cdrom: change pause timing again
[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 #include "../gpulib/gpu_timing.h"
394 extern const unsigned char cmd_lengths[256];
395
396 int do_cmd_list(u32 *list_, int list_len,
397  int *cycles_sum_out, int *cycles_last, int *last_cmd)
398 {
399   int cpu_cycles_sum = 0, cpu_cycles = *cycles_last;
400   u32 cmd = 0, len, i;
401   le32_t *list = (le32_t *)list_;
402   le32_t *list_start = list;
403   le32_t *list_end = list + list_len;
404
405   //TODO: set ilace_mask when resolution changes instead of every time,
406   // eliminate #ifdef below.
407   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
408
409 #ifdef HAVE_PRE_ARMV7 /* XXX */
410   gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
411 #endif
412   if (gpu_unai.config.scale_hires) {
413     gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
414   }
415
416   for (; list < list_end; list += 1 + len)
417   {
418     cmd = le32_to_u32(*list) >> 24;
419     len = cmd_lengths[cmd];
420     if (list + 1 + len > list_end) {
421       cmd = -1;
422       break;
423     }
424
425     #define PRIM cmd
426     gpu_unai.PacketBuffer.U4[0] = list[0];
427     for (i = 1; i <= len; i++)
428       gpu_unai.PacketBuffer.U4[i] = list[i];
429
430     PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
431
432     switch (cmd)
433     {
434       case 0x02:
435         gpuClearImage(packet);
436         gput_sum(cpu_cycles_sum, cpu_cycles,
437            gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff, le16_to_s16(packet.U2[5]) & 0x1ff));
438         break;
439
440       case 0x20:
441       case 0x21:
442       case 0x22:
443       case 0x23: {          // Monochrome 3-pt poly
444         PP driver = gpuPolySpanDrivers[
445           (gpu_unai.blit_mask?1024:0) |
446           Blending_Mode |
447           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
448         ];
449         gpuDrawPolyF(packet, driver, false);
450         gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base());
451       } break;
452
453       case 0x24:
454       case 0x25:
455       case 0x26:
456       case 0x27: {          // Textured 3-pt poly
457         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
458         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
459
460         u32 driver_idx =
461           (gpu_unai.blit_mask?1024:0) |
462           Dithering |
463           Blending_Mode | gpu_unai.TEXT_MODE |
464           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
465
466         if (!FastLightingEnabled()) {
467           driver_idx |= Lighting;
468         } else {
469           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
470             driver_idx |= Lighting;
471         }
472
473         PP driver = gpuPolySpanDrivers[driver_idx];
474         gpuDrawPolyFT(packet, driver, false);
475         gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t());
476       } break;
477
478       case 0x28:
479       case 0x29:
480       case 0x2A:
481       case 0x2B: {          // Monochrome 4-pt poly
482         PP driver = gpuPolySpanDrivers[
483           (gpu_unai.blit_mask?1024:0) |
484           Blending_Mode |
485           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
486         ];
487         gpuDrawPolyF(packet, driver, true); // is_quad = true
488         gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base());
489       } break;
490
491       case 0x2C:
492       case 0x2D:
493       case 0x2E:
494       case 0x2F: {          // Textured 4-pt poly
495         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
496         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
497
498         u32 driver_idx =
499           (gpu_unai.blit_mask?1024:0) |
500           Dithering |
501           Blending_Mode | gpu_unai.TEXT_MODE |
502           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
503
504         if (!FastLightingEnabled()) {
505           driver_idx |= Lighting;
506         } else {
507           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
508             driver_idx |= Lighting;
509         }
510
511         PP driver = gpuPolySpanDrivers[driver_idx];
512         gpuDrawPolyFT(packet, driver, true); // is_quad = true
513         gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t());
514       } break;
515
516       case 0x30:
517       case 0x31:
518       case 0x32:
519       case 0x33: {          // Gouraud-shaded 3-pt poly
520         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
521         // this is an untextured poly, so CF_LIGHT (texture blend)
522         // shouldn't apply. Until the original array of template
523         // instantiation ptrs is fixed, we're stuck with this. (TODO)
524         PP driver = gpuPolySpanDrivers[
525           (gpu_unai.blit_mask?1024:0) |
526           Dithering |
527           Blending_Mode |
528           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
529         ];
530         gpuDrawPolyG(packet, driver, false);
531         gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g());
532       } break;
533
534       case 0x34:
535       case 0x35:
536       case 0x36:
537       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
538         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
539         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
540         PP driver = gpuPolySpanDrivers[
541           (gpu_unai.blit_mask?1024:0) |
542           Dithering |
543           Blending_Mode | gpu_unai.TEXT_MODE |
544           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
545         ];
546         gpuDrawPolyGT(packet, driver, false);
547         gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt());
548       } break;
549
550       case 0x38:
551       case 0x39:
552       case 0x3A:
553       case 0x3B: {          // Gouraud-shaded 4-pt poly
554         // See notes regarding '129' for 0x30..0x33 further above -senquack
555         PP driver = gpuPolySpanDrivers[
556           (gpu_unai.blit_mask?1024:0) |
557           Dithering |
558           Blending_Mode |
559           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
560         ];
561         gpuDrawPolyG(packet, driver, true); // is_quad = true
562         gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g());
563       } break;
564
565       case 0x3C:
566       case 0x3D:
567       case 0x3E:
568       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
569         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
570         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
571         PP driver = gpuPolySpanDrivers[
572           (gpu_unai.blit_mask?1024:0) |
573           Dithering |
574           Blending_Mode | gpu_unai.TEXT_MODE |
575           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
576         ];
577         gpuDrawPolyGT(packet, driver, true); // is_quad = true
578         gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt());
579       } break;
580
581       case 0x40:
582       case 0x41:
583       case 0x42:
584       case 0x43: {          // Monochrome line
585         // Shift index right by one, as untextured prims don't use lighting
586         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
587         PSD driver = gpuPixelSpanDrivers[driver_idx];
588         gpuDrawLineF(packet, driver);
589         gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
590       } break;
591
592       case 0x48 ... 0x4F: { // Monochrome line strip
593         u32 num_vertexes = 1;
594         le32_t *list_position = &list[2];
595
596         // Shift index right by one, as untextured prims don't use lighting
597         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
598         PSD driver = gpuPixelSpanDrivers[driver_idx];
599         gpuDrawLineF(packet, driver);
600
601         while(1)
602         {
603           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
604           gpu_unai.PacketBuffer.U4[2] = *list_position++;
605           gpuDrawLineF(packet, driver);
606           gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
607
608           num_vertexes++;
609           if(list_position >= list_end) {
610             cmd = -1;
611             goto breakloop;
612           }
613           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
614             break;
615         }
616
617         len += (num_vertexes - 2);
618       } break;
619
620       case 0x50:
621       case 0x51:
622       case 0x52:
623       case 0x53: {          // Gouraud-shaded line
624         // Shift index right by one, as untextured prims don't use lighting
625         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
626         // Index MSB selects Gouraud-shaded PixelSpanDriver:
627         driver_idx |= (1 << 5);
628         PSD driver = gpuPixelSpanDrivers[driver_idx];
629         gpuDrawLineG(packet, driver);
630         gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
631       } break;
632
633       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
634         u32 num_vertexes = 1;
635         le32_t *list_position = &list[2];
636
637         // Shift index right by one, as untextured prims don't use lighting
638         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
639         // Index MSB selects Gouraud-shaded PixelSpanDriver:
640         driver_idx |= (1 << 5);
641         PSD driver = gpuPixelSpanDrivers[driver_idx];
642         gpuDrawLineG(packet, driver);
643
644         while(1)
645         {
646           gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
647           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
648           gpu_unai.PacketBuffer.U4[2] = *list_position++;
649           gpu_unai.PacketBuffer.U4[3] = *list_position++;
650           gpuDrawLineG(packet, driver);
651           gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
652
653           num_vertexes++;
654           if(list_position >= list_end) {
655             cmd = -1;
656             goto breakloop;
657           }
658           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
659             break;
660         }
661
662         len += (num_vertexes - 2) * 2;
663       } break;
664
665       case 0x60:
666       case 0x61:
667       case 0x62:
668       case 0x63: {          // Monochrome rectangle (variable size)
669         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
670         s32 w = 0, h = 0;
671         gpuDrawT(packet, driver, &w, &h);
672         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
673       } break;
674
675       case 0x64:
676       case 0x65:
677       case 0x66:
678       case 0x67: {          // Textured rectangle (variable size)
679         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
680         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
681         s32 w = 0, h = 0;
682
683         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
684         // This fixes Silent Hill running animation on loading screens:
685         // (On PSX, color values 0x00-0x7F darken the source texture's color,
686         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
687         //  0x80 leaves source texture color unchanged, HOWEVER,
688         //   gpu_unai uses a simple lighting LUT whereby only the upper
689         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
690         //   0x80.
691         // 
692         // NOTE: I've changed all textured sprite draw commands here and
693         //  elsewhere to use proper behavior, but left poly commands
694         //  alone, I don't want to slow rendering down too much. (TODO)
695         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
696         // Strip lower 3 bits of each color and determine if lighting should be used:
697         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
698           driver_idx |= Lighting;
699         PS driver = gpuSpriteSpanDrivers[driver_idx];
700         gpuDrawS(packet, driver, &w, &h);
701         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
702       } break;
703
704       case 0x68:
705       case 0x69:
706       case 0x6A:
707       case 0x6B: {          // Monochrome rectangle (1x1 dot)
708         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
709         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
710         s32 w = 0, h = 0;
711         gpuDrawT(packet, driver, &w, &h);
712         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1));
713       } break;
714
715       case 0x70:
716       case 0x71:
717       case 0x72:
718       case 0x73: {          // Monochrome rectangle (8x8)
719         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
720         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
721         s32 w = 0, h = 0;
722         gpuDrawT(packet, driver, &w, &h);
723         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
724       } break;
725
726       case 0x74:
727       case 0x75:
728       case 0x76:
729       case 0x77: {          // Textured rectangle (8x8)
730         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
731         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
732         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
733         s32 w = 0, h = 0;
734
735         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
736         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
737         // Strip lower 3 bits of each color and determine if lighting should be used:
738         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
739           driver_idx |= Lighting;
740         PS driver = gpuSpriteSpanDrivers[driver_idx];
741         gpuDrawS(packet, driver, &w, &h);
742         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
743       } break;
744
745       case 0x78:
746       case 0x79:
747       case 0x7A:
748       case 0x7B: {          // Monochrome rectangle (16x16)
749         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
750         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
751         s32 w = 0, h = 0;
752         gpuDrawT(packet, driver, &w, &h);
753         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
754       } break;
755
756       case 0x7C:
757       case 0x7D:
758 #ifdef __arm__
759         if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
760         {
761           s32 w = 0, h = 0;
762           gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
763           gpuDrawS16(packet, &w, &h);
764           gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
765           break;
766         }
767         // fallthrough
768 #endif
769       case 0x7E:
770       case 0x7F: {          // Textured rectangle (16x16)
771         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
772         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
773         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
774         s32 w = 0, h = 0;
775         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
776         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
777         // Strip lower 3 bits of each color and determine if lighting should be used:
778         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
779           driver_idx |= Lighting;
780         PS driver = gpuSpriteSpanDrivers[driver_idx];
781         gpuDrawS(packet, driver, &w, &h);
782         gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
783       } break;
784
785 #ifdef TEST
786       case 0x80:          //  vid -> vid
787         gpuMoveImage(packet);
788         break;
789
790       case 0xA0:          //  sys -> vid
791       {
792         u32 load_width = list[2] & 0xffff;
793         u32 load_height = list[2] >> 16;
794         u32 load_size = load_width * load_height;
795
796         len += load_size / 2;
797       } break;
798
799       case 0xC0:
800         break;
801 #else
802       case 0x1F:                   //  irq?
803       case 0x80 ... 0x9F:          //  vid -> vid
804       case 0xA0 ... 0xBF:          //  sys -> vid
805       case 0xC0 ... 0xDF:          //  vid -> sys
806         // Handled by gpulib
807         goto breakloop;
808 #endif
809       case 0xE1 ... 0xE6: { // Draw settings
810         gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
811       } break;
812     }
813   }
814
815 breakloop:
816   gpu.ex_regs[1] &= ~0x1ff;
817   gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
818
819   *cycles_sum_out += cpu_cycles_sum;
820   *cycles_last = cpu_cycles;
821   *last_cmd = cmd;
822   return list - list_start;
823 }
824
825 void renderer_sync_ecmds(u32 *ecmds)
826 {
827   int dummy;
828   do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy);
829 }
830
831 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
832 {
833 }
834
835 void renderer_flush_queues(void)
836 {
837 }
838
839 void renderer_set_interlace(int enable, int is_odd)
840 {
841 }
842
843 #include "../../frontend/plugin_lib.h"
844 // Handle any gpulib settings applicable to gpu_unai:
845 void renderer_set_config(const struct rearmed_cbs *cbs)
846 {
847   gpu_unai.vram = (le16_t *)gpu.vram;
848   gpu_unai.config.ilace_force   = cbs->gpu_unai.ilace_force;
849   gpu_unai.config.pixel_skip    = cbs->gpu_unai.pixel_skip;
850   gpu_unai.config.lighting      = cbs->gpu_unai.lighting;
851   gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
852   gpu_unai.config.blending      = cbs->gpu_unai.blending;
853   gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
854   gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
855
856   gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
857   if (gpu_unai.config.scale_hires) {
858     map_downscale_buffer();
859   } else {
860     unmap_downscale_buffer();
861   }
862 }
863
864 void renderer_sync(void)
865 {
866 }
867
868 void renderer_notify_update_lace(int updated)
869 {
870 }
871
872 // vim:shiftwidth=2:expandtab