cdrom: change pause timing again
[pcsx_rearmed.git] / plugins / gpu_senquack / 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 //#include "port.h"
30 #include "gpu_senquack.h"
31
32 // GPU fixed point math
33 #include "gpu_fixedpoint.h"
34
35 // Inner loop driver instantiation file
36 #include "gpu_inner.h"
37
38 // GPU internal image drawing functions
39 #include "gpu_raster_image.h"
40
41 // GPU internal line drawing functions
42 #include "gpu_raster_line.h"
43
44 // GPU internal polygon drawing functions
45 #include "gpu_raster_polygon.h"
46
47 // GPU internal sprite drawing functions
48 #include "gpu_raster_sprite.h"
49
50 // GPU command buffer execution/store
51 #include "gpu_command.h"
52
53 /////////////////////////////////////////////////////////////////////////////
54
55 int renderer_init(void)
56 {
57   memset((void*)&gpu_senquack, 0, sizeof(gpu_senquack));
58   gpu_senquack.vram = (u16*)gpu.vram;
59
60   // Original standalone gpu_senquack initialized TextureWindow[]. I added the
61   //  same behavior here, since it seems unsafe to leave [2],[3] unset when
62   //  using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
63   gpu_senquack.TextureWindow[0] = 0;
64   gpu_senquack.TextureWindow[1] = 0;
65   gpu_senquack.TextureWindow[2] = 255;
66   gpu_senquack.TextureWindow[3] = 255;
67   //senquack - new vars must be updated whenever texture window is changed:
68   //           (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
69   const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
70   gpu_senquack.u_msk = (((u32)gpu_senquack.TextureWindow[2]) << fb) | ((1 << fb) - 1);
71   gpu_senquack.v_msk = (((u32)gpu_senquack.TextureWindow[3]) << fb) | ((1 << fb) - 1);
72
73   // Configuration options
74   gpu_senquack.config = gpu_senquack_config_ext;
75   //senquack - disabled, not sure this is needed and would require modifying
76   // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
77   // present in latest PCSX4ALL sources we were using.
78   //gpu_senquack.config.enableAbbeyHack = gpu_senquack_config_ext.abe_hack;
79   gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
80
81 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
82   // s_invTable
83   for(int i=1;i<=(1<<TABLE_BITS);++i)
84   {
85     double v = 1.0 / double(i);
86 #ifdef GPU_TABLE_10_BITS
87     v *= double(0xffffffff>>1);
88 #else
89     v *= double(0x80000000);
90 #endif
91     s_invTable[i-1]=s32(v);
92   }
93 #endif
94
95   SetupLightLUT();
96   SetupDitheringConstants();
97
98   return 0;
99 }
100
101 void renderer_finish(void)
102 {
103 }
104
105 void renderer_notify_res_change(void)
106 {
107   if (PixelSkipEnabled()) {
108     // Set blit_mask for high horizontal resolutions. This allows skipping
109     //  rendering pixels that would never get displayed on low-resolution
110     //  platforms that use simple pixel-dropping scaler.
111
112     switch (gpu.screen.hres)
113     {
114       case 512: gpu_senquack.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
115       case 640: gpu_senquack.blit_mask = 0xaa; break; // GPU_BlitWS
116       default:  gpu_senquack.blit_mask = 0;    break;
117     }
118   } else {
119     gpu_senquack.blit_mask = 0;
120   }
121
122   if (LineSkipEnabled()) {
123     // Set rendering line-skip (only render every other line in high-res
124     //  480 vertical mode, or, optionally, force it for all video modes)
125
126     if (gpu.screen.vres == 480) {
127       if (gpu_senquack.config.ilace_force) {
128         gpu_senquack.ilace_mask = 3; // Only need 1/4 of lines
129       } else {
130         gpu_senquack.ilace_mask = 1; // Only need 1/2 of lines
131       }
132     } else {
133       // Vert resolution changed from 480 to lower one
134       gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
135     }
136   } else {
137     gpu_senquack.ilace_mask = 0;
138   }
139
140   /*
141   printf("res change hres: %d   vres: %d   depth: %d   ilace_mask: %d\n",
142       gpu.screen.hres, gpu.screen.vres, gpu.status.rgb24 ? 24 : 15,
143       gpu_senquack.ilace_mask);
144   */
145 }
146
147 #ifdef USE_GPULIB
148 // Handles GP0 draw settings commands 0xE1...0xE6
149 static void gpuGP0Cmd_0xEx(gpu_senquack_t &gpu_senquack, u32 cmd_word)
150 {
151   // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
152   u8 num = (cmd_word >> 24) & 7;
153   gpu.ex_regs[num] = cmd_word; // Update gpulib register
154   switch (num) {
155     case 1: {
156       // GP0(E1h) - Draw Mode setting (aka "Texpage")
157       u32 cur_texpage = gpu_senquack.GPU_GP1 & 0x7FF;
158       u32 new_texpage = cmd_word & 0x7FF;
159       if (cur_texpage != new_texpage) {
160         gpu_senquack.GPU_GP1 = (gpu_senquack.GPU_GP1 & ~0x7FF) | new_texpage;
161         gpuSetTexture(gpu_senquack.GPU_GP1);
162       }
163     } break;
164
165     case 2: {
166       // GP0(E2h) - Texture Window setting
167       if (cmd_word != gpu_senquack.TextureWindowCur) {
168         static const u8 TextureMask[32] = {
169           255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
170           127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
171         };
172         gpu_senquack.TextureWindowCur = cmd_word;
173         gpu_senquack.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
174         gpu_senquack.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
175         gpu_senquack.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
176         gpu_senquack.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
177         gpu_senquack.TextureWindow[0] &= ~gpu_senquack.TextureWindow[2];
178         gpu_senquack.TextureWindow[1] &= ~gpu_senquack.TextureWindow[3];
179
180         // Inner loop vars must be updated whenever texture window is changed:
181         const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
182         gpu_senquack.u_msk = (((u32)gpu_senquack.TextureWindow[2]) << fb) | ((1 << fb) - 1);
183         gpu_senquack.v_msk = (((u32)gpu_senquack.TextureWindow[3]) << fb) | ((1 << fb) - 1);
184
185         gpuSetTexture(gpu_senquack.GPU_GP1);
186       }
187     } break;
188
189     case 3: {
190       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
191       gpu_senquack.DrawingArea[0] = cmd_word         & 0x3FF;
192       gpu_senquack.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
193     } break;
194
195     case 4: {
196       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
197       gpu_senquack.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
198       gpu_senquack.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
199     } break;
200
201     case 5: {
202       // GP0(E5h) - Set Drawing Offset (X,Y)
203       gpu_senquack.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
204       gpu_senquack.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
205     } break;
206
207     case 6: {
208       // GP0(E6h) - Mask Bit Setting
209       gpu_senquack.Masking  = (cmd_word & 0x2) <<  1;
210       gpu_senquack.PixelMSB = (cmd_word & 0x1) <<  8;
211     } break;
212   }
213 }
214 #endif
215
216 extern const unsigned char cmd_lengths[256];
217
218 int do_cmd_list(u32 *list, int list_len, int *last_cmd)
219 {
220   u32 cmd = 0, len, i;
221   u32 *list_start = list;
222   u32 *list_end = list + list_len;
223
224   //TODO: set ilace_mask when resolution changes instead of every time,
225   // eliminate #ifdef below.
226   gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
227
228 #ifdef HAVE_PRE_ARMV7 /* XXX */
229   gpu_senquack.ilace_mask |= gpu.status.interlace;
230 #endif
231   if (gpu_senquack.config.scale_hires) {
232     gpu_senquack.ilace_mask |= gpu.status.interlace;
233   }
234
235   for (; list < list_end; list += 1 + len)
236   {
237     cmd = *list >> 24;
238     len = cmd_lengths[cmd];
239     if (list + 1 + len > list_end) {
240       cmd = -1;
241       break;
242     }
243
244     #define PRIM cmd
245     gpu_senquack.PacketBuffer.U4[0] = list[0];
246     for (i = 1; i <= len; i++)
247       gpu_senquack.PacketBuffer.U4[i] = list[i];
248
249     PtrUnion packet = { .ptr = (void*)&gpu_senquack.PacketBuffer };
250
251     switch (cmd)
252     {
253       case 0x02:
254         gpuClearImage(packet);
255         break;
256
257       case 0x20:
258       case 0x21:
259       case 0x22:
260       case 0x23: {          // Monochrome 3-pt poly
261         PP driver = gpuPolySpanDrivers[
262           (gpu_senquack.blit_mask?1024:0) |
263           Blending_Mode |
264           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
265         ];
266         gpuDrawPolyF(packet, driver, false);
267       } break;
268
269       case 0x24:
270       case 0x25:
271       case 0x26:
272       case 0x27: {          // Textured 3-pt poly
273         gpuSetCLUT   (gpu_senquack.PacketBuffer.U4[2] >> 16);
274         gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
275
276         u32 driver_idx =
277           (gpu_senquack.blit_mask?1024:0) |
278           Dithering |
279           Blending_Mode | gpu_senquack.TEXT_MODE |
280           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
281
282         if (!FastLightingEnabled()) {
283           driver_idx |= Lighting;
284         } else {
285           if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
286             driver_idx |= Lighting;
287         }
288
289         PP driver = gpuPolySpanDrivers[driver_idx];
290         gpuDrawPolyFT(packet, driver, false);
291       } break;
292
293       case 0x28:
294       case 0x29:
295       case 0x2A:
296       case 0x2B: {          // Monochrome 4-pt poly
297         PP driver = gpuPolySpanDrivers[
298           (gpu_senquack.blit_mask?1024:0) |
299           Blending_Mode |
300           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
301         ];
302         gpuDrawPolyF(packet, driver, true); // is_quad = true
303       } break;
304
305       case 0x2C:
306       case 0x2D:
307       case 0x2E:
308       case 0x2F: {          // Textured 4-pt poly
309         gpuSetCLUT   (gpu_senquack.PacketBuffer.U4[2] >> 16);
310         gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
311
312         u32 driver_idx =
313           (gpu_senquack.blit_mask?1024:0) |
314           Dithering |
315           Blending_Mode | gpu_senquack.TEXT_MODE |
316           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
317
318         if (!FastLightingEnabled()) {
319           driver_idx |= Lighting;
320         } else {
321           if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
322             driver_idx |= Lighting;
323         }
324
325         PP driver = gpuPolySpanDrivers[driver_idx];
326         gpuDrawPolyFT(packet, driver, true); // is_quad = true
327       } break;
328
329       case 0x30:
330       case 0x31:
331       case 0x32:
332       case 0x33: {          // Gouraud-shaded 3-pt poly
333         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
334         // this is an untextured poly, so CF_LIGHT (texture blend)
335         // shouldn't apply. Until the original array of template
336         // instantiation ptrs is fixed, we're stuck with this. (TODO)
337         PP driver = gpuPolySpanDrivers[
338           (gpu_senquack.blit_mask?1024:0) |
339           Dithering |
340           Blending_Mode |
341           gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
342         ];
343         gpuDrawPolyG(packet, driver, false);
344       } break;
345
346       case 0x34:
347       case 0x35:
348       case 0x36:
349       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
350         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
351         gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
352         PP driver = gpuPolySpanDrivers[
353           (gpu_senquack.blit_mask?1024:0) |
354           Dithering |
355           Blending_Mode | gpu_senquack.TEXT_MODE |
356           gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
357         ];
358         gpuDrawPolyGT(packet, driver, false);
359       } break;
360
361       case 0x38:
362       case 0x39:
363       case 0x3A:
364       case 0x3B: {          // Gouraud-shaded 4-pt poly
365         // See notes regarding '129' for 0x30..0x33 further above -senquack
366         PP driver = gpuPolySpanDrivers[
367           (gpu_senquack.blit_mask?1024:0) |
368           Dithering |
369           Blending_Mode |
370           gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
371         ];
372         gpuDrawPolyG(packet, driver, true); // is_quad = true
373       } break;
374
375       case 0x3C:
376       case 0x3D:
377       case 0x3E:
378       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
379         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
380         gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
381         PP driver = gpuPolySpanDrivers[
382           (gpu_senquack.blit_mask?1024:0) |
383           Dithering |
384           Blending_Mode | gpu_senquack.TEXT_MODE |
385           gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
386         ];
387         gpuDrawPolyGT(packet, driver, true); // is_quad = true
388       } break;
389
390       case 0x40:
391       case 0x41:
392       case 0x42:
393       case 0x43: {          // Monochrome line
394         // Shift index right by one, as untextured prims don't use lighting
395         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
396         PSD driver = gpuPixelSpanDrivers[driver_idx];
397         gpuDrawLineF(packet, driver);
398       } break;
399
400       case 0x48 ... 0x4F: { // Monochrome line strip
401         u32 num_vertexes = 1;
402         u32 *list_position = &(list[2]);
403
404         // Shift index right by one, as untextured prims don't use lighting
405         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
406         PSD driver = gpuPixelSpanDrivers[driver_idx];
407         gpuDrawLineF(packet, driver);
408
409         while(1)
410         {
411           gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[2];
412           gpu_senquack.PacketBuffer.U4[2] = *list_position++;
413           gpuDrawLineF(packet, driver);
414
415           num_vertexes++;
416           if(list_position >= list_end) {
417             cmd = -1;
418             goto breakloop;
419           }
420           if((*list_position & 0xf000f000) == 0x50005000)
421             break;
422         }
423
424         len += (num_vertexes - 2);
425       } break;
426
427       case 0x50:
428       case 0x51:
429       case 0x52:
430       case 0x53: {          // Gouraud-shaded line
431         // Shift index right by one, as untextured prims don't use lighting
432         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
433         // Index MSB selects Gouraud-shaded PixelSpanDriver:
434         driver_idx |= (1 << 5);
435         PSD driver = gpuPixelSpanDrivers[driver_idx];
436         gpuDrawLineG(packet, driver);
437       } break;
438
439       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
440         u32 num_vertexes = 1;
441         u32 *list_position = &(list[2]);
442
443         // Shift index right by one, as untextured prims don't use lighting
444         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
445         // Index MSB selects Gouraud-shaded PixelSpanDriver:
446         driver_idx |= (1 << 5);
447         PSD driver = gpuPixelSpanDrivers[driver_idx];
448         gpuDrawLineG(packet, driver);
449
450         while(1)
451         {
452           gpu_senquack.PacketBuffer.U4[0] = gpu_senquack.PacketBuffer.U4[2];
453           gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[3];
454           gpu_senquack.PacketBuffer.U4[2] = *list_position++;
455           gpu_senquack.PacketBuffer.U4[3] = *list_position++;
456           gpuDrawLineG(packet, driver);
457
458           num_vertexes++;
459           if(list_position >= list_end) {
460             cmd = -1;
461             goto breakloop;
462           }
463           if((*list_position & 0xf000f000) == 0x50005000)
464             break;
465         }
466
467         len += (num_vertexes - 2) * 2;
468       } break;
469
470       case 0x60:
471       case 0x61:
472       case 0x62:
473       case 0x63: {          // Monochrome rectangle (variable size)
474         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
475         gpuDrawT(packet, driver);
476       } break;
477
478       case 0x64:
479       case 0x65:
480       case 0x66:
481       case 0x67: {          // Textured rectangle (variable size)
482         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
483         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
484
485         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
486         // This fixes Silent Hill running animation on loading screens:
487         // (On PSX, color values 0x00-0x7F darken the source texture's color,
488         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
489         //  0x80 leaves source texture color unchanged, HOWEVER,
490         //   gpu_senquack uses a simple lighting LUT whereby only the upper
491         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
492         //   0x80.
493         // 
494         // NOTE: I've changed all textured sprite draw commands here and
495         //  elsewhere to use proper behavior, but left poly commands
496         //  alone, I don't want to slow rendering down too much. (TODO)
497         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
498         // Strip lower 3 bits of each color and determine if lighting should be used:
499         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
500           driver_idx |= Lighting;
501         PS driver = gpuSpriteSpanDrivers[driver_idx];
502         gpuDrawS(packet, driver);
503       } break;
504
505       case 0x68:
506       case 0x69:
507       case 0x6A:
508       case 0x6B: {          // Monochrome rectangle (1x1 dot)
509         gpu_senquack.PacketBuffer.U4[2] = 0x00010001;
510         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
511         gpuDrawT(packet, driver);
512       } break;
513
514       case 0x70:
515       case 0x71:
516       case 0x72:
517       case 0x73: {          // Monochrome rectangle (8x8)
518         gpu_senquack.PacketBuffer.U4[2] = 0x00080008;
519         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
520         gpuDrawT(packet, driver);
521       } break;
522
523       case 0x74:
524       case 0x75:
525       case 0x76:
526       case 0x77: {          // Textured rectangle (8x8)
527         gpu_senquack.PacketBuffer.U4[3] = 0x00080008;
528         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
529         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
530
531         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
532         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
533         // Strip lower 3 bits of each color and determine if lighting should be used:
534         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
535           driver_idx |= Lighting;
536         PS driver = gpuSpriteSpanDrivers[driver_idx];
537         gpuDrawS(packet, driver);
538       } break;
539
540       case 0x78:
541       case 0x79:
542       case 0x7A:
543       case 0x7B: {          // Monochrome rectangle (16x16)
544         gpu_senquack.PacketBuffer.U4[2] = 0x00100010;
545         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
546         gpuDrawT(packet, driver);
547       } break;
548
549       case 0x7C:
550       case 0x7D:
551 #ifdef __arm__
552         if ((gpu_senquack.GPU_GP1 & 0x180) == 0 && (gpu_senquack.Masking | gpu_senquack.PixelMSB) == 0)
553         {
554           gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
555           gpuDrawS16(packet);
556           break;
557         }
558         // fallthrough
559 #endif
560       case 0x7E:
561       case 0x7F: {          // Textured rectangle (16x16)
562         gpu_senquack.PacketBuffer.U4[3] = 0x00100010;
563         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
564         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
565         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
566         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
567         // Strip lower 3 bits of each color and determine if lighting should be used:
568         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
569           driver_idx |= Lighting;
570         PS driver = gpuSpriteSpanDrivers[driver_idx];
571         gpuDrawS(packet, driver);
572       } break;
573
574       case 0x80:          //  vid -> vid
575         gpuMoveImage(packet);
576         break;
577
578 #ifdef TEST
579       case 0xA0:          //  sys -> vid
580       {
581         u32 load_width = list[2] & 0xffff;
582         u32 load_height = list[2] >> 16;
583         u32 load_size = load_width * load_height;
584
585         len += load_size / 2;
586       } break;
587
588       case 0xC0:
589         break;
590 #else
591       case 0xA0:          //  sys ->vid
592       case 0xC0:          //  vid -> sys
593         // Handled by gpulib
594         goto breakloop;
595 #endif
596       case 0xE1 ... 0xE6: { // Draw settings
597         gpuGP0Cmd_0xEx(gpu_senquack, gpu_senquack.PacketBuffer.U4[0]);
598       } break;
599     }
600   }
601
602 breakloop:
603   gpu.ex_regs[1] &= ~0x1ff;
604   gpu.ex_regs[1] |= gpu_senquack.GPU_GP1 & 0x1ff;
605
606   *last_cmd = cmd;
607   return list - list_start;
608 }
609
610 void renderer_sync_ecmds(uint32_t *ecmds)
611 {
612   int dummy;
613   do_cmd_list(&ecmds[1], 6, &dummy);
614 }
615
616 void renderer_update_caches(int x, int y, int w, int h)
617 {
618 }
619
620 void renderer_flush_queues(void)
621 {
622 }
623
624 void renderer_set_interlace(int enable, int is_odd)
625 {
626 }
627
628 #include "../../frontend/plugin_lib.h"
629 // Handle any gpulib settings applicable to gpu_senquack:
630 void renderer_set_config(const struct rearmed_cbs *cbs)
631 {
632   gpu_senquack.vram = (u16*)gpu.vram;
633   gpu_senquack.config.ilace_force   = cbs->gpu_senquack.ilace_force;
634   gpu_senquack.config.pixel_skip    = cbs->gpu_senquack.pixel_skip;
635   gpu_senquack.config.lighting      = cbs->gpu_senquack.lighting;
636   gpu_senquack.config.fast_lighting = cbs->gpu_senquack.fast_lighting;
637   gpu_senquack.config.blending      = cbs->gpu_senquack.blending;
638   gpu_senquack.config.dithering     = cbs->gpu_senquack.dithering;
639   gpu_senquack.config.scale_hires   = cbs->gpu_senquack.scale_hires;
640 }
641
642 // vim:shiftwidth=2:expandtab