gpu_neon: rework buffer selection
[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 void renderer_notify_scanout_x_change(int x, int w)
148 {
149 }
150
151 #ifdef USE_GPULIB
152 // Handles GP0 draw settings commands 0xE1...0xE6
153 static void gpuGP0Cmd_0xEx(gpu_senquack_t &gpu_senquack, u32 cmd_word)
154 {
155   // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
156   u8 num = (cmd_word >> 24) & 7;
157   gpu.ex_regs[num] = cmd_word; // Update gpulib register
158   switch (num) {
159     case 1: {
160       // GP0(E1h) - Draw Mode setting (aka "Texpage")
161       u32 cur_texpage = gpu_senquack.GPU_GP1 & 0x7FF;
162       u32 new_texpage = cmd_word & 0x7FF;
163       if (cur_texpage != new_texpage) {
164         gpu_senquack.GPU_GP1 = (gpu_senquack.GPU_GP1 & ~0x7FF) | new_texpage;
165         gpuSetTexture(gpu_senquack.GPU_GP1);
166       }
167     } break;
168
169     case 2: {
170       // GP0(E2h) - Texture Window setting
171       if (cmd_word != gpu_senquack.TextureWindowCur) {
172         static const u8 TextureMask[32] = {
173           255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
174           127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
175         };
176         gpu_senquack.TextureWindowCur = cmd_word;
177         gpu_senquack.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
178         gpu_senquack.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
179         gpu_senquack.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
180         gpu_senquack.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
181         gpu_senquack.TextureWindow[0] &= ~gpu_senquack.TextureWindow[2];
182         gpu_senquack.TextureWindow[1] &= ~gpu_senquack.TextureWindow[3];
183
184         // Inner loop vars must be updated whenever texture window is changed:
185         const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
186         gpu_senquack.u_msk = (((u32)gpu_senquack.TextureWindow[2]) << fb) | ((1 << fb) - 1);
187         gpu_senquack.v_msk = (((u32)gpu_senquack.TextureWindow[3]) << fb) | ((1 << fb) - 1);
188
189         gpuSetTexture(gpu_senquack.GPU_GP1);
190       }
191     } break;
192
193     case 3: {
194       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
195       gpu_senquack.DrawingArea[0] = cmd_word         & 0x3FF;
196       gpu_senquack.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
197     } break;
198
199     case 4: {
200       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
201       gpu_senquack.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
202       gpu_senquack.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
203     } break;
204
205     case 5: {
206       // GP0(E5h) - Set Drawing Offset (X,Y)
207       gpu_senquack.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
208       gpu_senquack.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
209     } break;
210
211     case 6: {
212       // GP0(E6h) - Mask Bit Setting
213       gpu_senquack.Masking  = (cmd_word & 0x2) <<  1;
214       gpu_senquack.PixelMSB = (cmd_word & 0x1) <<  8;
215     } break;
216   }
217 }
218 #endif
219
220 extern const unsigned char cmd_lengths[256];
221
222 int do_cmd_list(u32 *list, int list_len, int *last_cmd)
223 {
224   u32 cmd = 0, len, i;
225   u32 *list_start = list;
226   u32 *list_end = list + list_len;
227
228   //TODO: set ilace_mask when resolution changes instead of every time,
229   // eliminate #ifdef below.
230   gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
231
232 #ifdef HAVE_PRE_ARMV7 /* XXX */
233   gpu_senquack.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
234 #endif
235   if (gpu_senquack.config.scale_hires) {
236     gpu_senquack.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
237   }
238
239   for (; list < list_end; list += 1 + len)
240   {
241     cmd = *list >> 24;
242     len = cmd_lengths[cmd];
243     if (list + 1 + len > list_end) {
244       cmd = -1;
245       break;
246     }
247
248     #define PRIM cmd
249     gpu_senquack.PacketBuffer.U4[0] = list[0];
250     for (i = 1; i <= len; i++)
251       gpu_senquack.PacketBuffer.U4[i] = list[i];
252
253     PtrUnion packet = { .ptr = (void*)&gpu_senquack.PacketBuffer };
254
255     switch (cmd)
256     {
257       case 0x02:
258         gpuClearImage(packet);
259         break;
260
261       case 0x20:
262       case 0x21:
263       case 0x22:
264       case 0x23: {          // Monochrome 3-pt poly
265         PP driver = gpuPolySpanDrivers[
266           (gpu_senquack.blit_mask?1024:0) |
267           Blending_Mode |
268           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
269         ];
270         gpuDrawPolyF(packet, driver, false);
271       } break;
272
273       case 0x24:
274       case 0x25:
275       case 0x26:
276       case 0x27: {          // Textured 3-pt poly
277         gpuSetCLUT   (gpu_senquack.PacketBuffer.U4[2] >> 16);
278         gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
279
280         u32 driver_idx =
281           (gpu_senquack.blit_mask?1024:0) |
282           Dithering |
283           Blending_Mode | gpu_senquack.TEXT_MODE |
284           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
285
286         if (!FastLightingEnabled()) {
287           driver_idx |= Lighting;
288         } else {
289           if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
290             driver_idx |= Lighting;
291         }
292
293         PP driver = gpuPolySpanDrivers[driver_idx];
294         gpuDrawPolyFT(packet, driver, false);
295       } break;
296
297       case 0x28:
298       case 0x29:
299       case 0x2A:
300       case 0x2B: {          // Monochrome 4-pt poly
301         PP driver = gpuPolySpanDrivers[
302           (gpu_senquack.blit_mask?1024:0) |
303           Blending_Mode |
304           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
305         ];
306         gpuDrawPolyF(packet, driver, true); // is_quad = true
307       } break;
308
309       case 0x2C:
310       case 0x2D:
311       case 0x2E:
312       case 0x2F: {          // Textured 4-pt poly
313         gpuSetCLUT   (gpu_senquack.PacketBuffer.U4[2] >> 16);
314         gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
315
316         u32 driver_idx =
317           (gpu_senquack.blit_mask?1024:0) |
318           Dithering |
319           Blending_Mode | gpu_senquack.TEXT_MODE |
320           gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
321
322         if (!FastLightingEnabled()) {
323           driver_idx |= Lighting;
324         } else {
325           if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
326             driver_idx |= Lighting;
327         }
328
329         PP driver = gpuPolySpanDrivers[driver_idx];
330         gpuDrawPolyFT(packet, driver, true); // is_quad = true
331       } break;
332
333       case 0x30:
334       case 0x31:
335       case 0x32:
336       case 0x33: {          // Gouraud-shaded 3-pt poly
337         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
338         // this is an untextured poly, so CF_LIGHT (texture blend)
339         // shouldn't apply. Until the original array of template
340         // instantiation ptrs is fixed, we're stuck with this. (TODO)
341         PP driver = gpuPolySpanDrivers[
342           (gpu_senquack.blit_mask?1024:0) |
343           Dithering |
344           Blending_Mode |
345           gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
346         ];
347         gpuDrawPolyG(packet, driver, false);
348       } break;
349
350       case 0x34:
351       case 0x35:
352       case 0x36:
353       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
354         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
355         gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
356         PP driver = gpuPolySpanDrivers[
357           (gpu_senquack.blit_mask?1024:0) |
358           Dithering |
359           Blending_Mode | gpu_senquack.TEXT_MODE |
360           gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
361         ];
362         gpuDrawPolyGT(packet, driver, false);
363       } break;
364
365       case 0x38:
366       case 0x39:
367       case 0x3A:
368       case 0x3B: {          // Gouraud-shaded 4-pt poly
369         // See notes regarding '129' for 0x30..0x33 further above -senquack
370         PP driver = gpuPolySpanDrivers[
371           (gpu_senquack.blit_mask?1024:0) |
372           Dithering |
373           Blending_Mode |
374           gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
375         ];
376         gpuDrawPolyG(packet, driver, true); // is_quad = true
377       } break;
378
379       case 0x3C:
380       case 0x3D:
381       case 0x3E:
382       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
383         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
384         gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
385         PP driver = gpuPolySpanDrivers[
386           (gpu_senquack.blit_mask?1024:0) |
387           Dithering |
388           Blending_Mode | gpu_senquack.TEXT_MODE |
389           gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
390         ];
391         gpuDrawPolyGT(packet, driver, true); // is_quad = true
392       } break;
393
394       case 0x40:
395       case 0x41:
396       case 0x42:
397       case 0x43: {          // Monochrome line
398         // Shift index right by one, as untextured prims don't use lighting
399         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
400         PSD driver = gpuPixelSpanDrivers[driver_idx];
401         gpuDrawLineF(packet, driver);
402       } break;
403
404       case 0x48 ... 0x4F: { // Monochrome line strip
405         u32 num_vertexes = 1;
406         u32 *list_position = &(list[2]);
407
408         // Shift index right by one, as untextured prims don't use lighting
409         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
410         PSD driver = gpuPixelSpanDrivers[driver_idx];
411         gpuDrawLineF(packet, driver);
412
413         while(1)
414         {
415           gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[2];
416           gpu_senquack.PacketBuffer.U4[2] = *list_position++;
417           gpuDrawLineF(packet, driver);
418
419           num_vertexes++;
420           if(list_position >= list_end) {
421             cmd = -1;
422             goto breakloop;
423           }
424           if((*list_position & 0xf000f000) == 0x50005000)
425             break;
426         }
427
428         len += (num_vertexes - 2);
429       } break;
430
431       case 0x50:
432       case 0x51:
433       case 0x52:
434       case 0x53: {          // Gouraud-shaded line
435         // Shift index right by one, as untextured prims don't use lighting
436         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
437         // Index MSB selects Gouraud-shaded PixelSpanDriver:
438         driver_idx |= (1 << 5);
439         PSD driver = gpuPixelSpanDrivers[driver_idx];
440         gpuDrawLineG(packet, driver);
441       } break;
442
443       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
444         u32 num_vertexes = 1;
445         u32 *list_position = &(list[2]);
446
447         // Shift index right by one, as untextured prims don't use lighting
448         u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
449         // Index MSB selects Gouraud-shaded PixelSpanDriver:
450         driver_idx |= (1 << 5);
451         PSD driver = gpuPixelSpanDrivers[driver_idx];
452         gpuDrawLineG(packet, driver);
453
454         while(1)
455         {
456           gpu_senquack.PacketBuffer.U4[0] = gpu_senquack.PacketBuffer.U4[2];
457           gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[3];
458           gpu_senquack.PacketBuffer.U4[2] = *list_position++;
459           gpu_senquack.PacketBuffer.U4[3] = *list_position++;
460           gpuDrawLineG(packet, driver);
461
462           num_vertexes++;
463           if(list_position >= list_end) {
464             cmd = -1;
465             goto breakloop;
466           }
467           if((*list_position & 0xf000f000) == 0x50005000)
468             break;
469         }
470
471         len += (num_vertexes - 2) * 2;
472       } break;
473
474       case 0x60:
475       case 0x61:
476       case 0x62:
477       case 0x63: {          // Monochrome rectangle (variable size)
478         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
479         gpuDrawT(packet, driver);
480       } break;
481
482       case 0x64:
483       case 0x65:
484       case 0x66:
485       case 0x67: {          // Textured rectangle (variable size)
486         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
487         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
488
489         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
490         // This fixes Silent Hill running animation on loading screens:
491         // (On PSX, color values 0x00-0x7F darken the source texture's color,
492         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
493         //  0x80 leaves source texture color unchanged, HOWEVER,
494         //   gpu_senquack uses a simple lighting LUT whereby only the upper
495         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
496         //   0x80.
497         // 
498         // NOTE: I've changed all textured sprite draw commands here and
499         //  elsewhere to use proper behavior, but left poly commands
500         //  alone, I don't want to slow rendering down too much. (TODO)
501         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
502         // Strip lower 3 bits of each color and determine if lighting should be used:
503         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
504           driver_idx |= Lighting;
505         PS driver = gpuSpriteSpanDrivers[driver_idx];
506         gpuDrawS(packet, driver);
507       } break;
508
509       case 0x68:
510       case 0x69:
511       case 0x6A:
512       case 0x6B: {          // Monochrome rectangle (1x1 dot)
513         gpu_senquack.PacketBuffer.U4[2] = 0x00010001;
514         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
515         gpuDrawT(packet, driver);
516       } break;
517
518       case 0x70:
519       case 0x71:
520       case 0x72:
521       case 0x73: {          // Monochrome rectangle (8x8)
522         gpu_senquack.PacketBuffer.U4[2] = 0x00080008;
523         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
524         gpuDrawT(packet, driver);
525       } break;
526
527       case 0x74:
528       case 0x75:
529       case 0x76:
530       case 0x77: {          // Textured rectangle (8x8)
531         gpu_senquack.PacketBuffer.U4[3] = 0x00080008;
532         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
533         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
534
535         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
536         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
537         // Strip lower 3 bits of each color and determine if lighting should be used:
538         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
539           driver_idx |= Lighting;
540         PS driver = gpuSpriteSpanDrivers[driver_idx];
541         gpuDrawS(packet, driver);
542       } break;
543
544       case 0x78:
545       case 0x79:
546       case 0x7A:
547       case 0x7B: {          // Monochrome rectangle (16x16)
548         gpu_senquack.PacketBuffer.U4[2] = 0x00100010;
549         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
550         gpuDrawT(packet, driver);
551       } break;
552
553       case 0x7C:
554       case 0x7D:
555 #ifdef __arm__
556         if ((gpu_senquack.GPU_GP1 & 0x180) == 0 && (gpu_senquack.Masking | gpu_senquack.PixelMSB) == 0)
557         {
558           gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
559           gpuDrawS16(packet);
560           break;
561         }
562         // fallthrough
563 #endif
564       case 0x7E:
565       case 0x7F: {          // Textured rectangle (16x16)
566         gpu_senquack.PacketBuffer.U4[3] = 0x00100010;
567         gpuSetCLUT    (gpu_senquack.PacketBuffer.U4[2] >> 16);
568         u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
569         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
570         //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
571         // Strip lower 3 bits of each color and determine if lighting should be used:
572         if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
573           driver_idx |= Lighting;
574         PS driver = gpuSpriteSpanDrivers[driver_idx];
575         gpuDrawS(packet, driver);
576       } break;
577
578       case 0x80:          //  vid -> vid
579         gpuMoveImage(packet);
580         break;
581
582 #ifdef TEST
583       case 0xA0:          //  sys -> vid
584       {
585         u32 load_width = list[2] & 0xffff;
586         u32 load_height = list[2] >> 16;
587         u32 load_size = load_width * load_height;
588
589         len += load_size / 2;
590       } break;
591
592       case 0xC0:
593         break;
594 #else
595       case 0xA0:          //  sys ->vid
596       case 0xC0:          //  vid -> sys
597         // Handled by gpulib
598         goto breakloop;
599 #endif
600       case 0xE1 ... 0xE6: { // Draw settings
601         gpuGP0Cmd_0xEx(gpu_senquack, gpu_senquack.PacketBuffer.U4[0]);
602       } break;
603     }
604   }
605
606 breakloop:
607   gpu.ex_regs[1] &= ~0x1ff;
608   gpu.ex_regs[1] |= gpu_senquack.GPU_GP1 & 0x1ff;
609
610   *last_cmd = cmd;
611   return list - list_start;
612 }
613
614 void renderer_sync_ecmds(uint32_t *ecmds)
615 {
616   int dummy;
617   do_cmd_list(&ecmds[1], 6, &dummy);
618 }
619
620 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
621 {
622 }
623
624 void renderer_flush_queues(void)
625 {
626 }
627
628 void renderer_set_interlace(int enable, int is_odd)
629 {
630 }
631
632 #include "../../frontend/plugin_lib.h"
633 // Handle any gpulib settings applicable to gpu_senquack:
634 void renderer_set_config(const struct rearmed_cbs *cbs)
635 {
636   gpu_senquack.vram = (u16*)gpu.vram;
637   gpu_senquack.config.ilace_force   = cbs->gpu_senquack.ilace_force;
638   gpu_senquack.config.pixel_skip    = cbs->gpu_senquack.pixel_skip;
639   gpu_senquack.config.lighting      = cbs->gpu_senquack.lighting;
640   gpu_senquack.config.fast_lighting = cbs->gpu_senquack.fast_lighting;
641   gpu_senquack.config.blending      = cbs->gpu_senquack.blending;
642   gpu_senquack.config.dithering     = cbs->gpu_senquack.dithering;
643   gpu_senquack.config.scale_hires   = cbs->gpu_senquack.scale_hires;
644 }
645
646 // vim:shiftwidth=2:expandtab