Merge pull request #536 from gameblabla/cdrom_fixes
[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(uint16_t *dest, const uint16_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 uint16_t* src16 = src;
88     uint16_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(uint16_t *dest, const uint16_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 uint16_t* src16 = src;
126     uint16_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   uint16_t *dest = gpu_unai.downscale_vram;
144   const uint16_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 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 = (uint16_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 = (u16*)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.rgb24 ? 24 : 15,
316       gpu_unai.ilace_mask);
317   */
318 }
319
320 #ifdef USE_GPULIB
321 // Handles GP0 draw settings commands 0xE1...0xE6
322 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
323 {
324   // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
325   u8 num = (cmd_word >> 24) & 7;
326   gpu.ex_regs[num] = cmd_word; // Update gpulib register
327   switch (num) {
328     case 1: {
329       // GP0(E1h) - Draw Mode setting (aka "Texpage")
330       u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
331       u32 new_texpage = cmd_word & 0x7FF;
332       if (cur_texpage != new_texpage) {
333         gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
334         gpuSetTexture(gpu_unai.GPU_GP1);
335       }
336     } break;
337
338     case 2: {
339       // GP0(E2h) - Texture Window setting
340       if (cmd_word != gpu_unai.TextureWindowCur) {
341         static const u8 TextureMask[32] = {
342           255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
343           127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
344         };
345         gpu_unai.TextureWindowCur = cmd_word;
346         gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
347         gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
348         gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
349         gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
350         gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
351         gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
352
353         // Inner loop vars must be updated whenever texture window is changed:
354         const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
355         gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
356         gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
357
358         gpuSetTexture(gpu_unai.GPU_GP1);
359       }
360     } break;
361
362     case 3: {
363       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
364       gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
365       gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
366     } break;
367
368     case 4: {
369       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
370       gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
371       gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
372     } break;
373
374     case 5: {
375       // GP0(E5h) - Set Drawing Offset (X,Y)
376       gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
377       gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
378     } break;
379
380     case 6: {
381       // GP0(E6h) - Mask Bit Setting
382       gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
383       gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
384     } break;
385   }
386 }
387 #endif
388
389 extern const unsigned char cmd_lengths[256];
390
391 int do_cmd_list(u32 *list, int list_len, int *last_cmd)
392 {
393   u32 cmd = 0, len, i;
394   u32 *list_start = list;
395   u32 *list_end = list + list_len;
396
397   //TODO: set ilace_mask when resolution changes instead of every time,
398   // eliminate #ifdef below.
399   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
400
401 #ifdef HAVE_PRE_ARMV7 /* XXX */
402   gpu_unai.ilace_mask |= gpu.status.interlace;
403 #endif
404   if (gpu_unai.config.scale_hires) {
405     gpu_unai.ilace_mask |= gpu.status.interlace;
406   }
407
408   for (; list < list_end; list += 1 + len)
409   {
410     cmd = *list >> 24;
411     len = cmd_lengths[cmd];
412     if (list + 1 + len > list_end) {
413       cmd = -1;
414       break;
415     }
416
417     #define PRIM cmd
418     gpu_unai.PacketBuffer.U4[0] = list[0];
419     for (i = 1; i <= len; i++)
420       gpu_unai.PacketBuffer.U4[i] = list[i];
421
422     PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
423
424     switch (cmd)
425     {
426       case 0x02:
427         gpuClearImage(packet);
428         break;
429
430       case 0x20:
431       case 0x21:
432       case 0x22:
433       case 0x23: {          // Monochrome 3-pt poly
434         PP driver = gpuPolySpanDrivers[
435           (gpu_unai.blit_mask?1024:0) |
436           Blending_Mode |
437           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
438         ];
439         gpuDrawPolyF(packet, driver, false);
440       } break;
441
442       case 0x24:
443       case 0x25:
444       case 0x26:
445       case 0x27: {          // Textured 3-pt poly
446         gpuSetCLUT   (gpu_unai.PacketBuffer.U4[2] >> 16);
447         gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
448
449         u32 driver_idx =
450           (gpu_unai.blit_mask?1024:0) |
451           Dithering |
452           Blending_Mode | gpu_unai.TEXT_MODE |
453           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
454
455         if (!FastLightingEnabled()) {
456           driver_idx |= Lighting;
457         } else {
458           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
459             driver_idx |= Lighting;
460         }
461
462         PP driver = gpuPolySpanDrivers[driver_idx];
463         gpuDrawPolyFT(packet, driver, false);
464       } break;
465
466       case 0x28:
467       case 0x29:
468       case 0x2A:
469       case 0x2B: {          // Monochrome 4-pt poly
470         PP driver = gpuPolySpanDrivers[
471           (gpu_unai.blit_mask?1024:0) |
472           Blending_Mode |
473           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
474         ];
475         gpuDrawPolyF(packet, driver, true); // is_quad = true
476       } break;
477
478       case 0x2C:
479       case 0x2D:
480       case 0x2E:
481       case 0x2F: {          // Textured 4-pt poly
482         gpuSetCLUT   (gpu_unai.PacketBuffer.U4[2] >> 16);
483         gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
484
485         u32 driver_idx =
486           (gpu_unai.blit_mask?1024:0) |
487           Dithering |
488           Blending_Mode | gpu_unai.TEXT_MODE |
489           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
490
491         if (!FastLightingEnabled()) {
492           driver_idx |= Lighting;
493         } else {
494           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
495             driver_idx |= Lighting;
496         }
497
498         PP driver = gpuPolySpanDrivers[driver_idx];
499         gpuDrawPolyFT(packet, driver, true); // is_quad = true
500       } break;
501
502       case 0x30:
503       case 0x31:
504       case 0x32:
505       case 0x33: {          // Gouraud-shaded 3-pt poly
506         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
507         // this is an untextured poly, so CF_LIGHT (texture blend)
508         // shouldn't apply. Until the original array of template
509         // instantiation ptrs is fixed, we're stuck with this. (TODO)
510         PP driver = gpuPolySpanDrivers[
511           (gpu_unai.blit_mask?1024:0) |
512           Dithering |
513           Blending_Mode |
514           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
515         ];
516         gpuDrawPolyG(packet, driver, false);
517       } break;
518
519       case 0x34:
520       case 0x35:
521       case 0x36:
522       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
523         gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
524         gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
525         PP driver = gpuPolySpanDrivers[
526           (gpu_unai.blit_mask?1024:0) |
527           Dithering |
528           Blending_Mode | gpu_unai.TEXT_MODE |
529           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
530         ];
531         gpuDrawPolyGT(packet, driver, false);
532       } break;
533
534       case 0x38:
535       case 0x39:
536       case 0x3A:
537       case 0x3B: {          // Gouraud-shaded 4-pt poly
538         // See notes regarding '129' for 0x30..0x33 further above -senquack
539         PP driver = gpuPolySpanDrivers[
540           (gpu_unai.blit_mask?1024:0) |
541           Dithering |
542           Blending_Mode |
543           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
544         ];
545         gpuDrawPolyG(packet, driver, true); // is_quad = true
546       } break;
547
548       case 0x3C:
549       case 0x3D:
550       case 0x3E:
551       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
552         gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
553         gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
554         PP driver = gpuPolySpanDrivers[
555           (gpu_unai.blit_mask?1024:0) |
556           Dithering |
557           Blending_Mode | gpu_unai.TEXT_MODE |
558           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
559         ];
560         gpuDrawPolyGT(packet, driver, true); // is_quad = true
561       } break;
562
563       case 0x40:
564       case 0x41:
565       case 0x42:
566       case 0x43: {          // Monochrome line
567         // Shift index right by one, as untextured prims don't use lighting
568         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
569         PSD driver = gpuPixelSpanDrivers[driver_idx];
570         gpuDrawLineF(packet, driver);
571       } break;
572
573       case 0x48 ... 0x4F: { // Monochrome line strip
574         u32 num_vertexes = 1;
575         u32 *list_position = &(list[2]);
576
577         // Shift index right by one, as untextured prims don't use lighting
578         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
579         PSD driver = gpuPixelSpanDrivers[driver_idx];
580         gpuDrawLineF(packet, driver);
581
582         while(1)
583         {
584           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
585           gpu_unai.PacketBuffer.U4[2] = *list_position++;
586           gpuDrawLineF(packet, driver);
587
588           num_vertexes++;
589           if(list_position >= list_end) {
590             cmd = -1;
591             goto breakloop;
592           }
593           if((*list_position & 0xf000f000) == 0x50005000)
594             break;
595         }
596
597         len += (num_vertexes - 2);
598       } break;
599
600       case 0x50:
601       case 0x51:
602       case 0x52:
603       case 0x53: {          // Gouraud-shaded line
604         // Shift index right by one, as untextured prims don't use lighting
605         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
606         // Index MSB selects Gouraud-shaded PixelSpanDriver:
607         driver_idx |= (1 << 5);
608         PSD driver = gpuPixelSpanDrivers[driver_idx];
609         gpuDrawLineG(packet, driver);
610       } break;
611
612       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
613         u32 num_vertexes = 1;
614         u32 *list_position = &(list[2]);
615
616         // Shift index right by one, as untextured prims don't use lighting
617         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
618         // Index MSB selects Gouraud-shaded PixelSpanDriver:
619         driver_idx |= (1 << 5);
620         PSD driver = gpuPixelSpanDrivers[driver_idx];
621         gpuDrawLineG(packet, driver);
622
623         while(1)
624         {
625           gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
626           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
627           gpu_unai.PacketBuffer.U4[2] = *list_position++;
628           gpu_unai.PacketBuffer.U4[3] = *list_position++;
629           gpuDrawLineG(packet, driver);
630
631           num_vertexes++;
632           if(list_position >= list_end) {
633             cmd = -1;
634             goto breakloop;
635           }
636           if((*list_position & 0xf000f000) == 0x50005000)
637             break;
638         }
639
640         len += (num_vertexes - 2) * 2;
641       } break;
642
643       case 0x60:
644       case 0x61:
645       case 0x62:
646       case 0x63: {          // Monochrome rectangle (variable size)
647         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
648         gpuDrawT(packet, driver);
649       } break;
650
651       case 0x64:
652       case 0x65:
653       case 0x66:
654       case 0x67: {          // Textured rectangle (variable size)
655         gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
656         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
657
658         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
659         // This fixes Silent Hill running animation on loading screens:
660         // (On PSX, color values 0x00-0x7F darken the source texture's color,
661         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
662         //  0x80 leaves source texture color unchanged, HOWEVER,
663         //   gpu_unai uses a simple lighting LUT whereby only the upper
664         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
665         //   0x80.
666         // 
667         // NOTE: I've changed all textured sprite draw commands here and
668         //  elsewhere to use proper behavior, but left poly commands
669         //  alone, I don't want to slow rendering down too much. (TODO)
670         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
671         // Strip lower 3 bits of each color and determine if lighting should be used:
672         if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
673           driver_idx |= Lighting;
674         PS driver = gpuSpriteSpanDrivers[driver_idx];
675         gpuDrawS(packet, driver);
676       } break;
677
678       case 0x68:
679       case 0x69:
680       case 0x6A:
681       case 0x6B: {          // Monochrome rectangle (1x1 dot)
682         gpu_unai.PacketBuffer.U4[2] = 0x00010001;
683         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
684         gpuDrawT(packet, driver);
685       } break;
686
687       case 0x70:
688       case 0x71:
689       case 0x72:
690       case 0x73: {          // Monochrome rectangle (8x8)
691         gpu_unai.PacketBuffer.U4[2] = 0x00080008;
692         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
693         gpuDrawT(packet, driver);
694       } break;
695
696       case 0x74:
697       case 0x75:
698       case 0x76:
699       case 0x77: {          // Textured rectangle (8x8)
700         gpu_unai.PacketBuffer.U4[3] = 0x00080008;
701         gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
702         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
703
704         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
705         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
706         // Strip lower 3 bits of each color and determine if lighting should be used:
707         if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
708           driver_idx |= Lighting;
709         PS driver = gpuSpriteSpanDrivers[driver_idx];
710         gpuDrawS(packet, driver);
711       } break;
712
713       case 0x78:
714       case 0x79:
715       case 0x7A:
716       case 0x7B: {          // Monochrome rectangle (16x16)
717         gpu_unai.PacketBuffer.U4[2] = 0x00100010;
718         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
719         gpuDrawT(packet, driver);
720       } break;
721
722       case 0x7C:
723       case 0x7D:
724 #ifdef __arm__
725         if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
726         {
727           gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
728           gpuDrawS16(packet);
729           break;
730         }
731         // fallthrough
732 #endif
733       case 0x7E:
734       case 0x7F: {          // Textured rectangle (16x16)
735         gpu_unai.PacketBuffer.U4[3] = 0x00100010;
736         gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
737         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
738         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
739         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
740         // Strip lower 3 bits of each color and determine if lighting should be used:
741         if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
742           driver_idx |= Lighting;
743         PS driver = gpuSpriteSpanDrivers[driver_idx];
744         gpuDrawS(packet, driver);
745       } break;
746
747       case 0x80:          //  vid -> vid
748         gpuMoveImage(packet);
749         break;
750
751 #ifdef TEST
752       case 0xA0:          //  sys -> vid
753       {
754         u32 load_width = list[2] & 0xffff;
755         u32 load_height = list[2] >> 16;
756         u32 load_size = load_width * load_height;
757
758         len += load_size / 2;
759       } break;
760
761       case 0xC0:
762         break;
763 #else
764       case 0xA0:          //  sys ->vid
765       case 0xC0:          //  vid -> sys
766         // Handled by gpulib
767         goto breakloop;
768 #endif
769       case 0xE1 ... 0xE6: { // Draw settings
770         gpuGP0Cmd_0xEx(gpu_unai, gpu_unai.PacketBuffer.U4[0]);
771       } break;
772     }
773   }
774
775 breakloop:
776   gpu.ex_regs[1] &= ~0x1ff;
777   gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
778
779   *last_cmd = cmd;
780   return list - list_start;
781 }
782
783 void renderer_sync_ecmds(uint32_t *ecmds)
784 {
785   int dummy;
786   do_cmd_list(&ecmds[1], 6, &dummy);
787 }
788
789 void renderer_update_caches(int x, int y, int w, int h)
790 {
791 }
792
793 void renderer_flush_queues(void)
794 {
795 }
796
797 void renderer_set_interlace(int enable, int is_odd)
798 {
799 }
800
801 #include "../../frontend/plugin_lib.h"
802 // Handle any gpulib settings applicable to gpu_unai:
803 void renderer_set_config(const struct rearmed_cbs *cbs)
804 {
805   gpu_unai.vram = (u16*)gpu.vram;
806   gpu_unai.config.ilace_force   = cbs->gpu_unai.ilace_force;
807   gpu_unai.config.pixel_skip    = cbs->gpu_unai.pixel_skip;
808   gpu_unai.config.lighting      = cbs->gpu_unai.lighting;
809   gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
810   gpu_unai.config.blending      = cbs->gpu_unai.blending;
811   gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
812   gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
813
814   gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
815   if (gpu_unai.config.scale_hires) {
816     map_downscale_buffer();
817   } else {
818     unmap_downscale_buffer();
819   }
820 }
821
822 void renderer_sync(void)
823 {
824 }
825
826 void renderer_notify_update_lace(int updated)
827 {
828 }
829
830 // vim:shiftwidth=2:expandtab