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