gpulib: handle vram copy in gpulib
[pcsx_rearmed.git] / plugins / gpu_unai / gpulib_if.cpp
1 /***************************************************************************
2 *   Copyright (C) 2010 PCSX4ALL Team                                      *
3 *   Copyright (C) 2010 Unai                                               *
4 *   Copyright (C) 2011 notaz                                              *
5 *   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
6 *                                                                         *
7 *   This program is free software; you can redistribute it and/or modify  *
8 *   it under the terms of the GNU General Public License as published by  *
9 *   the Free Software Foundation; either version 2 of the License, or     *
10 *   (at your option) any later version.                                   *
11 *                                                                         *
12 *   This program is distributed in the hope that it will be useful,       *
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15 *   GNU General Public License for more details.                          *
16 *                                                                         *
17 *   You should have received a copy of the GNU General Public License     *
18 *   along with this program; if not, write to the                         *
19 *   Free Software Foundation, Inc.,                                       *
20 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
21 ***************************************************************************/
22
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "../gpulib/gpu.h"
28
29 #ifdef THREAD_RENDERING
30 #include "../gpulib/gpulib_thread_if.h"
31 #define do_cmd_list real_do_cmd_list
32 #define renderer_init real_renderer_init
33 #define renderer_finish real_renderer_finish
34 #define renderer_sync_ecmds real_renderer_sync_ecmds
35 #define renderer_update_caches real_renderer_update_caches
36 #define renderer_flush_queues real_renderer_flush_queues
37 #define renderer_set_interlace real_renderer_set_interlace
38 #define renderer_set_config real_renderer_set_config
39 #define renderer_notify_res_change real_renderer_notify_res_change
40 #define renderer_notify_update_lace real_renderer_notify_update_lace
41 #define renderer_sync real_renderer_sync
42 #define ex_regs scratch_ex_regs
43 #endif
44
45 //#include "port.h"
46 #include "gpu_unai.h"
47
48 // GPU fixed point math
49 #include "gpu_fixedpoint.h"
50
51 // Inner loop driver instantiation file
52 #include "gpu_inner.h"
53
54 // GPU internal image drawing functions
55 #include "gpu_raster_image.h"
56
57 // GPU internal line drawing functions
58 #include "gpu_raster_line.h"
59
60 // GPU internal polygon drawing functions
61 #include "gpu_raster_polygon.h"
62
63 // GPU internal sprite drawing functions
64 #include "gpu_raster_sprite.h"
65
66 // GPU command buffer execution/store
67 #include "gpu_command.h"
68
69 /////////////////////////////////////////////////////////////////////////////
70
71 #define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
72
73 INLINE void scale_640_to_320(uint16_t *dest, const le16_t *src, bool isRGB24) {
74   size_t uCount = 320;
75
76   if(isRGB24) {
77     const uint8_t* src8 = (const uint8_t *)src;
78     uint8_t* dst8 = (uint8_t *)dest;
79
80     do {
81       *dst8++ = *src8++;
82       *dst8++ = *src8++;
83       *dst8++ = *src8;
84       src8 += 4;
85     } while(--uCount);
86   } else {
87     const le16_t *src16 = src;
88     uint16_t* dst16 = dest;
89
90     do {
91       *dst16++ = le16_to_u16(*src16);
92       src16 += 2;
93     } while(--uCount);
94   }
95 }
96
97 INLINE void scale_512_to_320(uint16_t *dest, const le16_t *src, bool isRGB24) {
98   size_t uCount = 64;
99
100   if(isRGB24) {
101     const uint8_t* src8 = (const uint8_t *)src;
102     uint8_t* dst8 = (uint8_t *)dest;
103
104     do {
105       *dst8++ = *src8++;
106       *dst8++ = *src8++;
107       *dst8++ = *src8++;
108       *dst8++ = *src8++;
109       *dst8++ = *src8++;
110       *dst8++ = *src8;
111       src8 += 4;
112       *dst8++ = *src8++;
113       *dst8++ = *src8++;
114       *dst8++ = *src8++;
115       *dst8++ = *src8++;
116       *dst8++ = *src8++;
117       *dst8++ = *src8;
118       src8 += 4;
119       *dst8++ = *src8++;
120       *dst8++ = *src8++;
121       *dst8++ = *src8;
122       src8 += 4;
123     } while(--uCount);
124   } else {
125     const le16_t* src16 = src;
126     uint16_t* dst16 = dest;
127
128     do {
129       *dst16++ = le16_to_u16(*src16++);
130       *dst16++ = le16_to_u16(*src16);
131       src16 += 2;
132       *dst16++ = le16_to_u16(*src16++);
133       *dst16++ = le16_to_u16(*src16);
134       src16 += 2;
135       *dst16++ = le16_to_u16(*src16);
136       src16 += 2;
137     } while(--uCount);
138   }
139 }
140
141 static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
142 {
143   uint16_t *dest = gpu_unai.downscale_vram;
144   const le16_t *src = gpu_unai.vram;
145   bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
146   int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
147
148   // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
149   unsigned int fb_mask = 1024 * 512 - 1;
150
151   if (*h > 240) {
152     *h /= 2;
153     stride *= 2;
154     lines = *h;
155
156     // Ensure start at a non-skipped line
157     while (*y & gpu_unai.ilace_mask) ++*y;
158   }
159
160   unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
161   unsigned int fb_offset_dest = fb_offset_src;
162
163   if (*w == 512 || *w == 640) {
164     *w = 320;
165   }
166
167   switch(orig_w) {
168   case 640:
169     do {
170       scale_640_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
171       fb_offset_src = (fb_offset_src + stride) & fb_mask;
172       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
173     } while(--lines);
174
175     break;
176   case 512:
177     do {
178       scale_512_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
179       fb_offset_src = (fb_offset_src + stride) & fb_mask;
180       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
181     } while(--lines);
182     break;
183   default:
184     size_t size = isRGB24 ? *w * 3 : *w * 2;
185
186     do {
187 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
188       for (unsigned int i; i < size; i += 2)
189         dest[fb_offset_dest + i] = le16_to_u16(src[fb_offset_src + i]);
190 #else
191       memcpy(dest + fb_offset_dest, (u16 *)src + fb_offset_src, size);
192 #endif
193       fb_offset_src = (fb_offset_src + stride) & fb_mask;
194       fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
195     } while(--lines);
196     break;
197   }
198
199   return gpu_unai.downscale_vram;
200 }
201
202 static void map_downscale_buffer(void)
203 {
204   if (gpu_unai.downscale_vram)
205     return;
206
207   gpu_unai.downscale_vram = (uint16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
208
209   if (gpu_unai.downscale_vram == NULL) {
210     fprintf(stderr, "failed to map downscale buffer\n");
211     gpu.get_downscale_buffer = NULL;
212   }
213   else {
214     gpu.get_downscale_buffer = get_downscale_buffer;
215   }
216 }
217
218 static void unmap_downscale_buffer(void)
219 {
220   if (gpu_unai.downscale_vram == NULL)
221     return;
222
223   gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
224   gpu_unai.downscale_vram = NULL;
225   gpu.get_downscale_buffer = NULL;
226 }
227
228 int renderer_init(void)
229 {
230   memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
231   gpu_unai.vram = (le16_t *)gpu.vram;
232
233   // Original standalone gpu_unai initialized TextureWindow[]. I added the
234   //  same behavior here, since it seems unsafe to leave [2],[3] unset when
235   //  using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
236   gpu_unai.TextureWindow[0] = 0;
237   gpu_unai.TextureWindow[1] = 0;
238   gpu_unai.TextureWindow[2] = 255;
239   gpu_unai.TextureWindow[3] = 255;
240   //senquack - new vars must be updated whenever texture window is changed:
241   //           (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
242   const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
243   gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
244   gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
245
246   // Configuration options
247   gpu_unai.config = gpu_unai_config_ext;
248   //senquack - disabled, not sure this is needed and would require modifying
249   // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
250   // present in latest PCSX4ALL sources we were using.
251   //gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
252   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
253
254 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
255   // s_invTable
256   for(int i=1;i<=(1<<TABLE_BITS);++i)
257   {
258     double v = 1.0 / double(i);
259 #ifdef GPU_TABLE_10_BITS
260     v *= double(0xffffffff>>1);
261 #else
262     v *= double(0x80000000);
263 #endif
264     s_invTable[i-1]=s32(v);
265   }
266 #endif
267
268   SetupLightLUT();
269   SetupDitheringConstants();
270
271   if (gpu_unai.config.scale_hires) {
272     map_downscale_buffer();
273   }
274
275   return 0;
276 }
277
278 void renderer_finish(void)
279 {
280   unmap_downscale_buffer();
281 }
282
283 void renderer_notify_res_change(void)
284 {
285   if (PixelSkipEnabled()) {
286     // Set blit_mask for high horizontal resolutions. This allows skipping
287     //  rendering pixels that would never get displayed on low-resolution
288     //  platforms that use simple pixel-dropping scaler.
289
290     switch (gpu.screen.hres)
291     {
292       case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
293       case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS
294       default:  gpu_unai.blit_mask = 0;    break;
295     }
296   } else {
297     gpu_unai.blit_mask = 0;
298   }
299
300   if (LineSkipEnabled()) {
301     // Set rendering line-skip (only render every other line in high-res
302     //  480 vertical mode, or, optionally, force it for all video modes)
303
304     if (gpu.screen.vres == 480) {
305       if (gpu_unai.config.ilace_force) {
306         gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
307       } else {
308         gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
309       }
310     } else {
311       // Vert resolution changed from 480 to lower one
312       gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
313     }
314   } else {
315     gpu_unai.ilace_mask = 0;
316   }
317
318   /*
319   printf("res change hres: %d   vres: %d   depth: %d   ilace_mask: %d\n",
320       gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
321       gpu_unai.ilace_mask);
322   */
323 }
324
325 void renderer_notify_scanout_x_change(int x, int w)
326 {
327 }
328
329 #ifdef USE_GPULIB
330 // Handles GP0 draw settings commands 0xE1...0xE6
331 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
332 {
333   // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
334   u8 num = (cmd_word >> 24) & 7;
335   gpu.ex_regs[num] = cmd_word; // Update gpulib register
336   switch (num) {
337     case 1: {
338       // GP0(E1h) - Draw Mode setting (aka "Texpage")
339       u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
340       u32 new_texpage = cmd_word & 0x7FF;
341       if (cur_texpage != new_texpage) {
342         gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
343         gpuSetTexture(gpu_unai.GPU_GP1);
344       }
345     } break;
346
347     case 2: {
348       // GP0(E2h) - Texture Window setting
349       if (cmd_word != gpu_unai.TextureWindowCur) {
350         static const u8 TextureMask[32] = {
351           255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
352           127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
353         };
354         gpu_unai.TextureWindowCur = cmd_word;
355         gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
356         gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
357         gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
358         gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
359         gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
360         gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
361
362         // Inner loop vars must be updated whenever texture window is changed:
363         const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
364         gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
365         gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
366
367         gpuSetTexture(gpu_unai.GPU_GP1);
368       }
369     } break;
370
371     case 3: {
372       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
373       gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
374       gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
375     } break;
376
377     case 4: {
378       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
379       gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
380       gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
381     } break;
382
383     case 5: {
384       // GP0(E5h) - Set Drawing Offset (X,Y)
385       gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
386       gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
387     } break;
388
389     case 6: {
390       // GP0(E6h) - Mask Bit Setting
391       gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
392       gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
393     } break;
394   }
395 }
396 #endif
397
398 extern const unsigned char cmd_lengths[256];
399
400 int do_cmd_list(u32 *_list, int list_len, int *last_cmd)
401 {
402   u32 cmd = 0, len, i;
403   le32_t *list = (le32_t *)_list;
404   le32_t *list_start = list;
405   le32_t *list_end = list + list_len;
406
407   //TODO: set ilace_mask when resolution changes instead of every time,
408   // eliminate #ifdef below.
409   gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
410
411 #ifdef HAVE_PRE_ARMV7 /* XXX */
412   gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
413 #endif
414   if (gpu_unai.config.scale_hires) {
415     gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
416   }
417
418   for (; list < list_end; list += 1 + len)
419   {
420     cmd = le32_to_u32(*list) >> 24;
421     len = cmd_lengths[cmd];
422     if (list + 1 + len > list_end) {
423       cmd = -1;
424       break;
425     }
426
427     #define PRIM cmd
428     gpu_unai.PacketBuffer.U4[0] = list[0];
429     for (i = 1; i <= len; i++)
430       gpu_unai.PacketBuffer.U4[i] = list[i];
431
432     PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
433
434     switch (cmd)
435     {
436       case 0x02:
437         gpuClearImage(packet);
438         break;
439
440       case 0x20:
441       case 0x21:
442       case 0x22:
443       case 0x23: {          // Monochrome 3-pt poly
444         PP driver = gpuPolySpanDrivers[
445           (gpu_unai.blit_mask?1024:0) |
446           Blending_Mode |
447           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
448         ];
449         gpuDrawPolyF(packet, driver, false);
450       } break;
451
452       case 0x24:
453       case 0x25:
454       case 0x26:
455       case 0x27: {          // Textured 3-pt poly
456         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
457         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
458
459         u32 driver_idx =
460           (gpu_unai.blit_mask?1024:0) |
461           Dithering |
462           Blending_Mode | gpu_unai.TEXT_MODE |
463           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
464
465         if (!FastLightingEnabled()) {
466           driver_idx |= Lighting;
467         } else {
468           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
469             driver_idx |= Lighting;
470         }
471
472         PP driver = gpuPolySpanDrivers[driver_idx];
473         gpuDrawPolyFT(packet, driver, false);
474       } break;
475
476       case 0x28:
477       case 0x29:
478       case 0x2A:
479       case 0x2B: {          // Monochrome 4-pt poly
480         PP driver = gpuPolySpanDrivers[
481           (gpu_unai.blit_mask?1024:0) |
482           Blending_Mode |
483           gpu_unai.Masking | Blending | gpu_unai.PixelMSB
484         ];
485         gpuDrawPolyF(packet, driver, true); // is_quad = true
486       } break;
487
488       case 0x2C:
489       case 0x2D:
490       case 0x2E:
491       case 0x2F: {          // Textured 4-pt poly
492         gpuSetCLUT   (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
493         gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
494
495         u32 driver_idx =
496           (gpu_unai.blit_mask?1024:0) |
497           Dithering |
498           Blending_Mode | gpu_unai.TEXT_MODE |
499           gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
500
501         if (!FastLightingEnabled()) {
502           driver_idx |= Lighting;
503         } else {
504           if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
505             driver_idx |= Lighting;
506         }
507
508         PP driver = gpuPolySpanDrivers[driver_idx];
509         gpuDrawPolyFT(packet, driver, true); // is_quad = true
510       } break;
511
512       case 0x30:
513       case 0x31:
514       case 0x32:
515       case 0x33: {          // Gouraud-shaded 3-pt poly
516         //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
517         // this is an untextured poly, so CF_LIGHT (texture blend)
518         // shouldn't apply. Until the original array of template
519         // instantiation ptrs is fixed, we're stuck with this. (TODO)
520         PP driver = gpuPolySpanDrivers[
521           (gpu_unai.blit_mask?1024:0) |
522           Dithering |
523           Blending_Mode |
524           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
525         ];
526         gpuDrawPolyG(packet, driver, false);
527       } break;
528
529       case 0x34:
530       case 0x35:
531       case 0x36:
532       case 0x37: {          // Gouraud-shaded, textured 3-pt poly
533         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
534         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
535         PP driver = gpuPolySpanDrivers[
536           (gpu_unai.blit_mask?1024:0) |
537           Dithering |
538           Blending_Mode | gpu_unai.TEXT_MODE |
539           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
540         ];
541         gpuDrawPolyGT(packet, driver, false);
542       } break;
543
544       case 0x38:
545       case 0x39:
546       case 0x3A:
547       case 0x3B: {          // Gouraud-shaded 4-pt poly
548         // See notes regarding '129' for 0x30..0x33 further above -senquack
549         PP driver = gpuPolySpanDrivers[
550           (gpu_unai.blit_mask?1024:0) |
551           Dithering |
552           Blending_Mode |
553           gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
554         ];
555         gpuDrawPolyG(packet, driver, true); // is_quad = true
556       } break;
557
558       case 0x3C:
559       case 0x3D:
560       case 0x3E:
561       case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
562         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
563         gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
564         PP driver = gpuPolySpanDrivers[
565           (gpu_unai.blit_mask?1024:0) |
566           Dithering |
567           Blending_Mode | gpu_unai.TEXT_MODE |
568           gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
569         ];
570         gpuDrawPolyGT(packet, driver, true); // is_quad = true
571       } break;
572
573       case 0x40:
574       case 0x41:
575       case 0x42:
576       case 0x43: {          // Monochrome line
577         // Shift index right by one, as untextured prims don't use lighting
578         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
579         PSD driver = gpuPixelSpanDrivers[driver_idx];
580         gpuDrawLineF(packet, driver);
581       } break;
582
583       case 0x48 ... 0x4F: { // Monochrome line strip
584         u32 num_vertexes = 1;
585         le32_t *list_position = &list[2];
586
587         // Shift index right by one, as untextured prims don't use lighting
588         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
589         PSD driver = gpuPixelSpanDrivers[driver_idx];
590         gpuDrawLineF(packet, driver);
591
592         while(1)
593         {
594           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
595           gpu_unai.PacketBuffer.U4[2] = *list_position++;
596           gpuDrawLineF(packet, driver);
597
598           num_vertexes++;
599           if(list_position >= list_end) {
600             cmd = -1;
601             goto breakloop;
602           }
603           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
604             break;
605         }
606
607         len += (num_vertexes - 2);
608       } break;
609
610       case 0x50:
611       case 0x51:
612       case 0x52:
613       case 0x53: {          // Gouraud-shaded line
614         // Shift index right by one, as untextured prims don't use lighting
615         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
616         // Index MSB selects Gouraud-shaded PixelSpanDriver:
617         driver_idx |= (1 << 5);
618         PSD driver = gpuPixelSpanDrivers[driver_idx];
619         gpuDrawLineG(packet, driver);
620       } break;
621
622       case 0x58 ... 0x5F: { // Gouraud-shaded line strip
623         u32 num_vertexes = 1;
624         le32_t *list_position = &list[2];
625
626         // Shift index right by one, as untextured prims don't use lighting
627         u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
628         // Index MSB selects Gouraud-shaded PixelSpanDriver:
629         driver_idx |= (1 << 5);
630         PSD driver = gpuPixelSpanDrivers[driver_idx];
631         gpuDrawLineG(packet, driver);
632
633         while(1)
634         {
635           gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
636           gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
637           gpu_unai.PacketBuffer.U4[2] = *list_position++;
638           gpu_unai.PacketBuffer.U4[3] = *list_position++;
639           gpuDrawLineG(packet, driver);
640
641           num_vertexes++;
642           if(list_position >= list_end) {
643             cmd = -1;
644             goto breakloop;
645           }
646           if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
647             break;
648         }
649
650         len += (num_vertexes - 2) * 2;
651       } break;
652
653       case 0x60:
654       case 0x61:
655       case 0x62:
656       case 0x63: {          // Monochrome rectangle (variable size)
657         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
658         gpuDrawT(packet, driver);
659       } break;
660
661       case 0x64:
662       case 0x65:
663       case 0x66:
664       case 0x67: {          // Textured rectangle (variable size)
665         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
666         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
667
668         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
669         // This fixes Silent Hill running animation on loading screens:
670         // (On PSX, color values 0x00-0x7F darken the source texture's color,
671         //  0x81-FF lighten textures (ultimately clamped to 0x1F),
672         //  0x80 leaves source texture color unchanged, HOWEVER,
673         //   gpu_unai uses a simple lighting LUT whereby only the upper
674         //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
675         //   0x80.
676         // 
677         // NOTE: I've changed all textured sprite draw commands here and
678         //  elsewhere to use proper behavior, but left poly commands
679         //  alone, I don't want to slow rendering down too much. (TODO)
680         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
681         // Strip lower 3 bits of each color and determine if lighting should be used:
682         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
683           driver_idx |= Lighting;
684         PS driver = gpuSpriteSpanDrivers[driver_idx];
685         gpuDrawS(packet, driver);
686       } break;
687
688       case 0x68:
689       case 0x69:
690       case 0x6A:
691       case 0x6B: {          // Monochrome rectangle (1x1 dot)
692         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
693         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
694         gpuDrawT(packet, driver);
695       } break;
696
697       case 0x70:
698       case 0x71:
699       case 0x72:
700       case 0x73: {          // Monochrome rectangle (8x8)
701         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
702         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
703         gpuDrawT(packet, driver);
704       } break;
705
706       case 0x74:
707       case 0x75:
708       case 0x76:
709       case 0x77: {          // Textured rectangle (8x8)
710         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
711         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
712         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
713
714         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
715         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
716         // Strip lower 3 bits of each color and determine if lighting should be used:
717         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
718           driver_idx |= Lighting;
719         PS driver = gpuSpriteSpanDrivers[driver_idx];
720         gpuDrawS(packet, driver);
721       } break;
722
723       case 0x78:
724       case 0x79:
725       case 0x7A:
726       case 0x7B: {          // Monochrome rectangle (16x16)
727         gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
728         PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
729         gpuDrawT(packet, driver);
730       } break;
731
732       case 0x7C:
733       case 0x7D:
734 #ifdef __arm__
735         if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
736         {
737           gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
738           gpuDrawS16(packet);
739           break;
740         }
741         // fallthrough
742 #endif
743       case 0x7E:
744       case 0x7F: {          // Textured rectangle (16x16)
745         gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
746         gpuSetCLUT    (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
747         u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
748         //senquack - Only color 808080h-878787h allows skipping lighting calculation:
749         //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
750         // Strip lower 3 bits of each color and determine if lighting should be used:
751         if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
752           driver_idx |= Lighting;
753         PS driver = gpuSpriteSpanDrivers[driver_idx];
754         gpuDrawS(packet, driver);
755       } break;
756
757 #ifdef TEST
758       case 0x80:          //  vid -> vid
759         gpuMoveImage(packet);
760         break;
761
762       case 0xA0:          //  sys -> vid
763       {
764         u32 load_width = list[2] & 0xffff;
765         u32 load_height = list[2] >> 16;
766         u32 load_size = load_width * load_height;
767
768         len += load_size / 2;
769       } break;
770
771       case 0xC0:
772         break;
773 #else
774       case 0x80 ... 0x9F:          //  vid -> vid
775       case 0xA0 ... 0xBF:          //  sys -> vid
776       case 0xC0 ... 0xDF:          //  vid -> sys
777         // Handled by gpulib
778         goto breakloop;
779 #endif
780       case 0xE1 ... 0xE6: { // Draw settings
781         gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
782       } break;
783     }
784   }
785
786 breakloop:
787   gpu.ex_regs[1] &= ~0x1ff;
788   gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
789
790   *last_cmd = cmd;
791   return list - list_start;
792 }
793
794 void renderer_sync_ecmds(u32 *ecmds)
795 {
796   int dummy;
797   do_cmd_list(&ecmds[1], 6, &dummy);
798 }
799
800 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
801 {
802 }
803
804 void renderer_flush_queues(void)
805 {
806 }
807
808 void renderer_set_interlace(int enable, int is_odd)
809 {
810 }
811
812 #include "../../frontend/plugin_lib.h"
813 // Handle any gpulib settings applicable to gpu_unai:
814 void renderer_set_config(const struct rearmed_cbs *cbs)
815 {
816   gpu_unai.vram = (le16_t *)gpu.vram;
817   gpu_unai.config.ilace_force   = cbs->gpu_unai.ilace_force;
818   gpu_unai.config.pixel_skip    = cbs->gpu_unai.pixel_skip;
819   gpu_unai.config.lighting      = cbs->gpu_unai.lighting;
820   gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
821   gpu_unai.config.blending      = cbs->gpu_unai.blending;
822   gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
823   gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
824
825   gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
826   if (gpu_unai.config.scale_hires) {
827     map_downscale_buffer();
828   } else {
829     unmap_downscale_buffer();
830   }
831 }
832
833 void renderer_sync(void)
834 {
835 }
836
837 void renderer_notify_update_lace(int updated)
838 {
839 }
840
841 // vim:shiftwidth=2:expandtab