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