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