gpu_unai: sync with libretro
[pcsx_rearmed.git] / plugins / gpu_unai / gpulib_if.cpp
1 /***************************************************************************
2 *   Copyright (C) 2010 PCSX4ALL Team                                      *
3 *   Copyright (C) 2010 Unai                                               *
4 *   Copyright (C) 2011 notaz                                              *
5 *   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
6 *                                                                         *
7 *   This program is free software; you can redistribute it and/or modify  *
8 *   it under the terms of the GNU General Public License as published by  *
9 *   the Free Software Foundation; either version 2 of the License, or     *
10 *   (at your option) any later version.                                   *
11 *                                                                         *
12 *   This program is distributed in the hope that it will be useful,       *
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15 *   GNU General Public License for more details.                          *
16 *                                                                         *
17 *   You should have received a copy of the GNU General Public License     *
18 *   along with this program; if not, write to the                         *
19 *   Free Software Foundation, Inc.,                                       *
20 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
21 ***************************************************************************/
22
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "../gpulib/gpu.h"
28
29 #ifdef THREAD_RENDERING
30 #include "../gpulib/gpulib_thread_if.h"
31 #define do_cmd_list real_do_cmd_list
32 #define renderer_init real_renderer_init
33 #define renderer_finish real_renderer_finish
34 #define renderer_sync_ecmds real_renderer_sync_ecmds
35 #define renderer_update_caches real_renderer_update_caches
36 #define renderer_flush_queues real_renderer_flush_queues
37 #define renderer_set_interlace real_renderer_set_interlace
38 #define renderer_set_config real_renderer_set_config
39 #define renderer_notify_res_change real_renderer_notify_res_change
40 #define renderer_notify_update_lace real_renderer_notify_update_lace
41 #define renderer_sync real_renderer_sync
42 #define ex_regs scratch_ex_regs
43 #endif
44
45 //#include "port.h"
46 #include "gpu_unai.h"
47
48 // GPU fixed point math
49 #include "gpu_fixedpoint.h"
50
51 // Inner loop driver instantiation file
52 #include "gpu_inner.h"
53
54 // GPU internal image drawing functions
55 #include "gpu_raster_image.h"
56
57 // GPU internal line drawing functions
58 #include "gpu_raster_line.h"
59
60 // GPU internal polygon drawing functions
61 #include "gpu_raster_polygon.h"
62
63 // GPU internal sprite drawing functions
64 #include "gpu_raster_sprite.h"
65
66 // GPU command buffer execution/store
67 #include "gpu_command.h"
68
69 /////////////////////////////////////////////////////////////////////////////
70
71 #define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
72
73 INLINE void scale_640_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
74   size_t uCount = 320;
75
76   if(isRGB24) {
77     const uint8_t* src8 = (const uint8_t *)src;
78     uint8_t* dst8 = (uint8_t *)dest;
79
80     do {
81       *dst8++ = *src8++;
82       *dst8++ = *src8++;
83       *dst8++ = *src8;
84       src8 += 4;
85     } while(--uCount);
86   } else {
87     const le16_t* src16 = src;
88     le16_t* dst16 = dest;
89
90     do {
91       *dst16++ = *src16;
92       src16 += 2;
93     } while(--uCount);
94   }
95 }
96
97 INLINE void scale_512_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
98   size_t uCount = 64;
99
100   if(isRGB24) {
101     const uint8_t* src8 = (const uint8_t *)src;
102     uint8_t* dst8 = (uint8_t *)dest;
103
104     do {
105       *dst8++ = *src8++;
106       *dst8++ = *src8++;
107       *dst8++ = *src8++;
108       *dst8++ = *src8++;
109       *dst8++ = *src8++;
110       *dst8++ = *src8;
111       src8 += 4;
112       *dst8++ = *src8++;
113       *dst8++ = *src8++;
114       *dst8++ = *src8++;
115       *dst8++ = *src8++;
116       *dst8++ = *src8++;
117       *dst8++ = *src8;
118       src8 += 4;
119       *dst8++ = *src8++;
120       *dst8++ = *src8++;
121       *dst8++ = *src8;
122       src8 += 4;
123     } while(--uCount);
124   } else {
125     const le16_t* src16 = src;
126     le16_t* dst16 = dest;
127
128     do {
129       *dst16++ = *src16++;
130       *dst16++ = *src16;
131       src16 += 2;
132       *dst16++ = *src16++;
133       *dst16++ = *src16;
134       src16 += 2;
135       *dst16++ = *src16;
136       src16 += 2;
137     } while(--uCount);
138   }
139 }
140
141 static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
142 {
143   le16_t *dest = gpu_unai.downscale_vram;
144   const le16_t *src = gpu_unai.vram;
145   bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
146   int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
147
148   // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
149   unsigned int fb_mask = 1024 * 512 - 1;
150
151   if (*h > 240) {
152     *h /= 2;
153     stride *= 2;
154     lines = *h;
155
156     // Ensure start at a non-skipped line
157     while (*y & gpu_unai.ilace_mask) ++*y;
158   }
159
160   unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
161   unsigned int fb_offset_dest = fb_offset_src;
162
163   if (*w == 512 || *w == 640) {
164     *w = 320;
165   }
166
167   switch(orig_w) {
168   case 640:
169     do {
170       scale_640_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
171       fb_offset_src = (fb_offset_src + stride) & fb_mask;
172       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
173     } while(--lines);
174
175     break;
176   case 512:
177     do {
178       scale_512_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
179       fb_offset_src = (fb_offset_src + stride) & fb_mask;
180       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
181     } while(--lines);
182     break;
183   default:
184     size_t size = isRGB24 ? *w * 3 : *w * 2;
185
186     do {
187       memcpy(dest + fb_offset_dest, src + fb_offset_src, size);
188       fb_offset_src = (fb_offset_src + stride) & fb_mask;
189       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
190     } while(--lines);
191     break;
192   }
193
194   return (uint16_t *)gpu_unai.downscale_vram;
195 }
196
197 static void map_downscale_buffer(void)
198 {
199   if (gpu_unai.downscale_vram)
200     return;
201
202   gpu_unai.downscale_vram = (le16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
203
204   if (gpu_unai.downscale_vram == NULL) {
205     fprintf(stderr, "failed to map downscale buffer\n");
206     gpu.get_downscale_buffer = NULL;
207   }
208   else {
209     gpu.get_downscale_buffer = get_downscale_buffer;
210   }
211 }
212
213 static void unmap_downscale_buffer(void)
214 {
215   if (gpu_unai.downscale_vram == NULL)
216     return;
217
218   gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
219   gpu_unai.downscale_vram = NULL;
220   gpu.get_downscale_buffer = NULL;
221 }
222
223 int renderer_init(void)
224 {
225   memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
226   gpu_unai.vram = (le16_t *)gpu.vram;
227
228   // Original standalone gpu_unai initialized TextureWindow[]. I added the
229   //  same behavior here, since it seems unsafe to leave [2],[3] unset when
230   //  using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
231   gpu_unai.TextureWindow[0] = 0;
232   gpu_unai.TextureWindow[1] = 0;
233   gpu_unai.TextureWindow[2] = 255;
234   gpu_unai.TextureWindow[3] = 255;
235   //senquack - new vars must be updated whenever texture window is changed:
236   //           (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
237   const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
238   gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
239   gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
240
241   // Configuration options
242   gpu_unai.config = gpu_unai_config_ext;
243   //senquack - disabled, not sure this is needed and would require modifying
244   // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
245   // present in latest PCSX4ALL sources we were using.
246   //gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
247   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
248
249 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
250   // s_invTable
251   for(int i=1;i<=(1<<TABLE_BITS);++i)
252   {
253     double v = 1.0 / double(i);
254 #ifdef GPU_TABLE_10_BITS
255     v *= double(0xffffffff>>1);
256 #else
257     v *= double(0x80000000);
258 #endif
259     s_invTable[i-1]=s32(v);
260   }
261 #endif
262
263   SetupLightLUT();
264   SetupDitheringConstants();
265
266   if (gpu_unai.config.scale_hires) {
267     map_downscale_buffer();
268   }
269
270   return 0;
271 }
272
273 void renderer_finish(void)
274 {
275   unmap_downscale_buffer();
276 }
277
278 void renderer_notify_res_change(void)
279 {
280   if (PixelSkipEnabled()) {
281     // Set blit_mask for high horizontal resolutions. This allows skipping
282     //  rendering pixels that would never get displayed on low-resolution
283     //  platforms that use simple pixel-dropping scaler.
284
285     switch (gpu.screen.hres)
286     {
287       case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
288       case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS
289       default:  gpu_unai.blit_mask = 0;    break;
290     }
291   } else {
292     gpu_unai.blit_mask = 0;
293   }
294
295   if (LineSkipEnabled()) {
296     // Set rendering line-skip (only render every other line in high-res
297     //  480 vertical mode, or, optionally, force it for all video modes)
298
299     if (gpu.screen.vres == 480) {
300       if (gpu_unai.config.ilace_force) {
301         gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
302       } else {
303         gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
304       }
305     } else {
306       // Vert resolution changed from 480 to lower one
307       gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
308     }
309   } else {
310     gpu_unai.ilace_mask = 0;
311   }
312
313   /*
314   printf("res change hres: %d   vres: %d   depth: %d   ilace_mask: %d\n",
315       gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
316       gpu_unai.ilace_mask);
317   */
318 }
319
320 void renderer_notify_scanout_change(int x, int y)
321 {
322 }
323
324 #ifdef USE_GPULIB
325 // Handles GP0 draw settings commands 0xE1...0xE6
326 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
327 {
328   // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
329   u8 num = (cmd_word >> 24) & 7;
330   gpu.ex_regs[num] = cmd_word; // Update gpulib register
331   switch (num) {
332     case 1: {
333       // GP0(E1h) - Draw Mode setting (aka "Texpage")
334       u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
335       u32 new_texpage = cmd_word & 0x7FF;
336       if (cur_texpage != new_texpage) {
337         gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
338         gpuSetTexture(gpu_unai.GPU_GP1);
339       }
340     } break;
341
342     case 2: {
343       // GP0(E2h) - Texture Window setting
344       if (cmd_word != gpu_unai.TextureWindowCur) {
345         static const u8 TextureMask[32] = {
346           255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
347           127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
348         };
349         gpu_unai.TextureWindowCur = cmd_word;
350         gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
351         gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
352         gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
353         gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
354         gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
355         gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
356
357         // Inner loop vars must be updated whenever texture window is changed:
358         const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
359         gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
360         gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
361
362         gpuSetTexture(gpu_unai.GPU_GP1);
363       }
364     } break;
365
366     case 3: {
367       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
368       gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
369       gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
370     } break;
371
372     case 4: {
373       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
374       gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
375       gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
376     } break;
377
378     case 5: {
379       // GP0(E5h) - Set Drawing Offset (X,Y)
380       gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
381       gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
382     } break;
383
384     case 6: {
385       // GP0(E6h) - Mask Bit Setting
386       gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
387       gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
388     } break;
389   }
390 }
391 #endif
392
393 extern const unsigned char cmd_lengths[256];
394
395 int do_cmd_list(u32 *_list, int list_len, int *last_cmd)
396 {
397   u32 cmd = 0, len, i;
398   le32_t *list = (le32_t *)_list;
399   le32_t *list_start = list;
400   le32_t *list_end = list + list_len;
401
402   //TODO: set ilace_mask when resolution changes instead of every time,
403   // eliminate #ifdef below.
404   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
405
406 #ifdef HAVE_PRE_ARMV7 /* XXX */
407   gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
408 #endif
409   if (gpu_unai.config.scale_hires) {
410     gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
411   }
412
413   for (; list < list_end; list += 1 + len)
414   {
415     cmd = le32_to_u32(*list) >> 24;
416     len = cmd_lengths[cmd];
417     if (list + 1 + len > list_end) {
418       cmd = -1;
419       break;
420     }
421
422     #define PRIM cmd
423     gpu_unai.PacketBuffer.U4[0] = list[0];
424     for (i = 1; i <= len; i++)
425       gpu_unai.PacketBuffer.U4[i] = list[i];
426
427     PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
428
429     switch (cmd)
430     {
431       case 0x02:
432         gpuClearImage(packet);
433         break;
434
435       case 0x20:
436       case 0x21:
437       case 0x22:
438       case 0x23: {          // Monochrome 3-pt poly
439         PP driver = gpuPolySpanDrivers[
440           (gpu_unai.blit_mask?1024:0) |
441           Blending_Mode |
442           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
443         ];
444         gpuDrawPolyF(packet, driver, false);
445       } break;
446
447       case 0x24:
448       case 0x25:
449       case 0x26:
450       case 0x27: {          // Textured 3-pt poly
451         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
452         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
453
454         u32 driver_idx =
455           (gpu_unai.blit_mask?1024:0) |
456           Dithering |
457           Blending_Mode | gpu_unai.TEXT_MODE |
458           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
459
460         if (!FastLightingEnabled()) {
461           driver_idx |= Lighting;
462         } else {
463           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
464             driver_idx |= Lighting;
465         }
466
467         PP driver = gpuPolySpanDrivers[driver_idx];
468         gpuDrawPolyFT(packet, driver, false);
469       } break;
470
471       case 0x28:
472       case 0x29:
473       case 0x2A:
474       case 0x2B: {          // Monochrome 4-pt poly
475         PP driver = gpuPolySpanDrivers[
476           (gpu_unai.blit_mask?1024:0) |
477           Blending_Mode |
478           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
479         ];
480         gpuDrawPolyF(packet, driver, true); // is_quad = true
481       } break;
482
483       case 0x2C:
484       case 0x2D:
485       case 0x2E:
486       case 0x2F: {          // Textured 4-pt poly
487         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
488         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
489
490         u32 driver_idx =
491           (gpu_unai.blit_mask?1024:0) |
492           Dithering |
493           Blending_Mode | gpu_unai.TEXT_MODE |
494           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
495
496         if (!FastLightingEnabled()) {
497           driver_idx |= Lighting;
498         } else {
499           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
500             driver_idx |= Lighting;
501         }
502
503         PP driver = gpuPolySpanDrivers[driver_idx];
504         gpuDrawPolyFT(packet, driver, true); // is_quad = true
505       } break;
506
507       case 0x30:
508       case 0x31:
509       case 0x32:
510       case 0x33: {          // Gouraud-shaded 3-pt poly
511         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
512         // this is an untextured poly, so CF_LIGHT (texture blend)
513         // shouldn't apply. Until the original array of template
514         // instantiation ptrs is fixed, we're stuck with this. (TODO)
515         PP driver = gpuPolySpanDrivers[
516           (gpu_unai.blit_mask?1024:0) |
517           Dithering |
518           Blending_Mode |
519           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
520         ];
521         gpuDrawPolyG(packet, driver, false);
522       } break;
523
524       case 0x34:
525       case 0x35:
526       case 0x36:
527       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
528         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
529         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
530         PP driver = gpuPolySpanDrivers[
531           (gpu_unai.blit_mask?1024:0) |
532           Dithering |
533           Blending_Mode | gpu_unai.TEXT_MODE |
534           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
535         ];
536         gpuDrawPolyGT(packet, driver, false);
537       } break;
538
539       case 0x38:
540       case 0x39:
541       case 0x3A:
542       case 0x3B: {          // Gouraud-shaded 4-pt poly
543         // See notes regarding '129' for 0x30..0x33 further above -senquack
544         PP driver = gpuPolySpanDrivers[
545           (gpu_unai.blit_mask?1024:0) |
546           Dithering |
547           Blending_Mode |
548           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
549         ];
550         gpuDrawPolyG(packet, driver, true); // is_quad = true
551       } break;
552
553       case 0x3C:
554       case 0x3D:
555       case 0x3E:
556       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
557         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
558         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
559         PP driver = gpuPolySpanDrivers[
560           (gpu_unai.blit_mask?1024:0) |
561           Dithering |
562           Blending_Mode | gpu_unai.TEXT_MODE |
563           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
564         ];
565         gpuDrawPolyGT(packet, driver, true); // is_quad = true
566       } break;
567
568       case 0x40:
569       case 0x41:
570       case 0x42:
571       case 0x43: {          // Monochrome line
572         // Shift index right by one, as untextured prims don't use lighting
573         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
574         PSD driver = gpuPixelSpanDrivers[driver_idx];
575         gpuDrawLineF(packet, driver);
576       } break;
577
578       case 0x48 ... 0x4F: { // Monochrome line strip
579         u32 num_vertexes = 1;
580         le32_t *list_position = &list[2];
581
582         // Shift index right by one, as untextured prims don't use lighting
583         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
584         PSD driver = gpuPixelSpanDrivers[driver_idx];
585         gpuDrawLineF(packet, driver);
586
587         while(1)
588         {
589           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
590           gpu_unai.PacketBuffer.U4[2] = *list_position++;
591           gpuDrawLineF(packet, driver);
592
593           num_vertexes++;
594           if(list_position >= list_end) {
595             cmd = -1;
596             goto breakloop;
597           }
598           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
599             break;
600         }
601
602         len += (num_vertexes - 2);
603       } break;
604
605       case 0x50:
606       case 0x51:
607       case 0x52:
608       case 0x53: {          // Gouraud-shaded line
609         // Shift index right by one, as untextured prims don't use lighting
610         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
611         // Index MSB selects Gouraud-shaded PixelSpanDriver:
612         driver_idx |= (1 << 5);
613         PSD driver = gpuPixelSpanDrivers[driver_idx];
614         gpuDrawLineG(packet, driver);
615       } break;
616
617       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
618         u32 num_vertexes = 1;
619         le32_t *list_position = &list[2];
620
621         // Shift index right by one, as untextured prims don't use lighting
622         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
623         // Index MSB selects Gouraud-shaded PixelSpanDriver:
624         driver_idx |= (1 << 5);
625         PSD driver = gpuPixelSpanDrivers[driver_idx];
626         gpuDrawLineG(packet, driver);
627
628         while(1)
629         {
630           gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
631           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
632           gpu_unai.PacketBuffer.U4[2] = *list_position++;
633           gpu_unai.PacketBuffer.U4[3] = *list_position++;
634           gpuDrawLineG(packet, driver);
635
636           num_vertexes++;
637           if(list_position >= list_end) {
638             cmd = -1;
639             goto breakloop;
640           }
641           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
642             break;
643         }
644
645         len += (num_vertexes - 2) * 2;
646       } break;
647
648       case 0x60:
649       case 0x61:
650       case 0x62:
651       case 0x63: {          // Monochrome rectangle (variable size)
652         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
653         gpuDrawT(packet, driver);
654       } break;
655
656       case 0x64:
657       case 0x65:
658       case 0x66:
659       case 0x67: {          // Textured rectangle (variable size)
660         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
661         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
662
663         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
664         // This fixes Silent Hill running animation on loading screens:
665         // (On PSX, color values 0x00-0x7F darken the source texture's color,
666         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
667         //  0x80 leaves source texture color unchanged, HOWEVER,
668         //   gpu_unai uses a simple lighting LUT whereby only the upper
669         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
670         //   0x80.
671         // 
672         // NOTE: I've changed all textured sprite draw commands here and
673         //  elsewhere to use proper behavior, but left poly commands
674         //  alone, I don't want to slow rendering down too much. (TODO)
675         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
676         // Strip lower 3 bits of each color and determine if lighting should be used:
677         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
678           driver_idx |= Lighting;
679         PS driver = gpuSpriteSpanDrivers[driver_idx];
680         gpuDrawS(packet, driver);
681       } break;
682
683       case 0x68:
684       case 0x69:
685       case 0x6A:
686       case 0x6B: {          // Monochrome rectangle (1x1 dot)
687         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
688         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
689         gpuDrawT(packet, driver);
690       } break;
691
692       case 0x70:
693       case 0x71:
694       case 0x72:
695       case 0x73: {          // Monochrome rectangle (8x8)
696         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
697         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
698         gpuDrawT(packet, driver);
699       } break;
700
701       case 0x74:
702       case 0x75:
703       case 0x76:
704       case 0x77: {          // Textured rectangle (8x8)
705         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
706         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
707         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
708
709         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
710         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
711         // Strip lower 3 bits of each color and determine if lighting should be used:
712         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
713           driver_idx |= Lighting;
714         PS driver = gpuSpriteSpanDrivers[driver_idx];
715         gpuDrawS(packet, driver);
716       } break;
717
718       case 0x78:
719       case 0x79:
720       case 0x7A:
721       case 0x7B: {          // Monochrome rectangle (16x16)
722         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
723         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
724         gpuDrawT(packet, driver);
725       } break;
726
727       case 0x7C:
728       case 0x7D:
729 #ifdef __arm__
730         if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
731         {
732           gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
733           gpuDrawS16(packet);
734           break;
735         }
736         // fallthrough
737 #endif
738       case 0x7E:
739       case 0x7F: {          // Textured rectangle (16x16)
740         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
741         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
742         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
743         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
744         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
745         // Strip lower 3 bits of each color and determine if lighting should be used:
746         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
747           driver_idx |= Lighting;
748         PS driver = gpuSpriteSpanDrivers[driver_idx];
749         gpuDrawS(packet, driver);
750       } break;
751
752 #ifdef TEST
753       case 0x80:          //  vid -> vid
754         gpuMoveImage(packet);
755         break;
756
757       case 0xA0:          //  sys -> vid
758       {
759         u32 load_width = list[2] & 0xffff;
760         u32 load_height = list[2] >> 16;
761         u32 load_size = load_width * load_height;
762
763         len += load_size / 2;
764       } break;
765
766       case 0xC0:
767         break;
768 #else
769       case 0x80 ... 0x9F:          //  vid -> vid
770       case 0xA0 ... 0xBF:          //  sys -> vid
771       case 0xC0 ... 0xDF:          //  vid -> sys
772         // Handled by gpulib
773         goto breakloop;
774 #endif
775       case 0xE1 ... 0xE6: { // Draw settings
776         gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
777       } break;
778     }
779   }
780
781 breakloop:
782   gpu.ex_regs[1] &= ~0x1ff;
783   gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
784
785   *last_cmd = cmd;
786   return list - list_start;
787 }
788
789 void renderer_sync_ecmds(u32 *ecmds)
790 {
791   int dummy;
792   do_cmd_list(&ecmds[1], 6, &dummy);
793 }
794
795 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
796 {
797 }
798
799 void renderer_flush_queues(void)
800 {
801 }
802
803 void renderer_set_interlace(int enable, int is_odd)
804 {
805 }
806
807 #include "../../frontend/plugin_lib.h"
808 // Handle any gpulib settings applicable to gpu_unai:
809 void renderer_set_config(const struct rearmed_cbs *cbs)
810 {
811   gpu_unai.vram = (le16_t *)gpu.vram;
812   gpu_unai.config.ilace_force   = cbs->gpu_unai.ilace_force;
813   gpu_unai.config.pixel_skip    = cbs->gpu_unai.pixel_skip;
814   gpu_unai.config.lighting      = cbs->gpu_unai.lighting;
815   gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
816   gpu_unai.config.blending      = cbs->gpu_unai.blending;
817   gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
818   gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
819
820   gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
821   if (gpu_unai.config.scale_hires) {
822     map_downscale_buffer();
823   } else {
824     unmap_downscale_buffer();
825   }
826 }
827
828 void renderer_sync(void)
829 {
830 }
831
832 void renderer_notify_update_lace(int updated)
833 {
834 }
835
836 // vim:shiftwidth=2:expandtab