Merge pull request #749 from pcercuei/lightrec-allow-mem-override
[pcsx_rearmed.git] / plugins / gpu_unai / gpulib_if.cpp
CommitLineData
6f2ee2be 1/***************************************************************************
2* Copyright (C) 2010 PCSX4ALL Team *
3* Copyright (C) 2010 Unai *
4* Copyright (C) 2011 notaz *
030d1121 5* Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com) *
6f2ee2be 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
030d1121 23#include <stddef.h>
6f2ee2be 24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
62d7fa95 27#include "../gpulib/gpu.h"
c765eb86
JW
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
030d1121 45//#include "port.h"
46#include "gpu_unai.h"
6f2ee2be 47
030d1121 48// GPU fixed point math
49#include "gpu_fixedpoint.h"
6f2ee2be 50
030d1121 51// Inner loop driver instantiation file
52#include "gpu_inner.h"
6f2ee2be 53
54// GPU internal image drawing functions
030d1121 55#include "gpu_raster_image.h"
6f2ee2be 56
57// GPU internal line drawing functions
030d1121 58#include "gpu_raster_line.h"
6f2ee2be 59
60// GPU internal polygon drawing functions
030d1121 61#include "gpu_raster_polygon.h"
6f2ee2be 62
63// GPU internal sprite drawing functions
030d1121 64#include "gpu_raster_sprite.h"
6f2ee2be 65
66// GPU command buffer execution/store
030d1121 67#include "gpu_command.h"
6f2ee2be 68
6f2ee2be 69/////////////////////////////////////////////////////////////////////////////
70
43047988
JW
71#define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
72
73INLINE void scale_640_to_320(uint16_t *dest, const uint16_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 uint16_t* src16 = src;
88 uint16_t* dst16 = dest;
89
90 do {
91 *dst16++ = *src16;
92 src16 += 2;
93 } while(--uCount);
94 }
95}
96
97INLINE void scale_512_to_320(uint16_t *dest, const uint16_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 uint16_t* src16 = src;
126 uint16_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 uint16_t *dest = gpu_unai.downscale_vram;
144 const uint16_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 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 = (uint16_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
6f2ee2be 223int renderer_init(void)
224{
030d1121 225 memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
226 gpu_unai.vram = (u16*)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
43047988
JW
266 if (gpu_unai.config.scale_hires) {
267 map_downscale_buffer();
268 }
269
030d1121 270 return 0;
6f2ee2be 271}
272
e929dec5 273void renderer_finish(void)
274{
43047988 275 unmap_downscale_buffer();
e929dec5 276}
277
278void renderer_notify_res_change(void)
279{
030d1121 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",
b9db55a9 315 gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
030d1121 316 gpu_unai.ilace_mask);
317 */
318}
319
12367ad0 320#ifdef USE_GPULIB
030d1121 321// Handles GP0 draw settings commands 0xE1...0xE6
322static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
323{
324 // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
325 u8 num = (cmd_word >> 24) & 7;
326 gpu.ex_regs[num] = cmd_word; // Update gpulib register
327 switch (num) {
328 case 1: {
329 // GP0(E1h) - Draw Mode setting (aka "Texpage")
330 u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
331 u32 new_texpage = cmd_word & 0x7FF;
332 if (cur_texpage != new_texpage) {
333 gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
334 gpuSetTexture(gpu_unai.GPU_GP1);
335 }
336 } break;
337
338 case 2: {
339 // GP0(E2h) - Texture Window setting
340 if (cmd_word != gpu_unai.TextureWindowCur) {
341 static const u8 TextureMask[32] = {
342 255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
343 127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
344 };
345 gpu_unai.TextureWindowCur = cmd_word;
346 gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
347 gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
348 gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
349 gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
350 gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
351 gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
352
353 // Inner loop vars must be updated whenever texture window is changed:
354 const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4
355 gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
356 gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
357
358 gpuSetTexture(gpu_unai.GPU_GP1);
359 }
360 } break;
361
362 case 3: {
363 // GP0(E3h) - Set Drawing Area top left (X1,Y1)
364 gpu_unai.DrawingArea[0] = cmd_word & 0x3FF;
365 gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
366 } break;
367
368 case 4: {
369 // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
370 gpu_unai.DrawingArea[2] = (cmd_word & 0x3FF) + 1;
371 gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
372 } break;
373
374 case 5: {
375 // GP0(E5h) - Set Drawing Offset (X,Y)
376 gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
377 gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
378 } break;
379
380 case 6: {
381 // GP0(E6h) - Mask Bit Setting
382 gpu_unai.Masking = (cmd_word & 0x2) << 1;
383 gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
384 } break;
385 }
e929dec5 386}
12367ad0 387#endif
e929dec5 388
6f2ee2be 389extern const unsigned char cmd_lengths[256];
390
5f315a8f 391int do_cmd_list(u32 *list, int list_len, int *last_cmd)
6f2ee2be 392{
5f315a8f 393 u32 cmd = 0, len, i;
394 u32 *list_start = list;
395 u32 *list_end = list + list_len;
6f2ee2be 396
030d1121 397 //TODO: set ilace_mask when resolution changes instead of every time,
398 // eliminate #ifdef below.
399 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
400
8f2bb0cb 401#ifdef HAVE_PRE_ARMV7 /* XXX */
b9db55a9 402 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
89c0de42 403#endif
43047988 404 if (gpu_unai.config.scale_hires) {
b9db55a9 405 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
43047988 406 }
89c0de42 407
6f2ee2be 408 for (; list < list_end; list += 1 + len)
409 {
6f2ee2be 410 cmd = *list >> 24;
411 len = cmd_lengths[cmd];
b243416b 412 if (list + 1 + len > list_end) {
413 cmd = -1;
414 break;
415 }
416
42a261f1 417 #define PRIM cmd
030d1121 418 gpu_unai.PacketBuffer.U4[0] = list[0];
42a261f1 419 for (i = 1; i <= len; i++)
030d1121 420 gpu_unai.PacketBuffer.U4[i] = list[i];
421
422 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
6f2ee2be 423
42a261f1 424 switch (cmd)
6f2ee2be 425 {
42a261f1 426 case 0x02:
030d1121 427 gpuClearImage(packet);
42a261f1 428 break;
429
430 case 0x20:
431 case 0x21:
432 case 0x22:
030d1121 433 case 0x23: { // Monochrome 3-pt poly
434 PP driver = gpuPolySpanDrivers[
435 (gpu_unai.blit_mask?1024:0) |
436 Blending_Mode |
437 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
438 ];
439 gpuDrawPolyF(packet, driver, false);
440 } break;
42a261f1 441
442 case 0x24:
443 case 0x25:
444 case 0x26:
030d1121 445 case 0x27: { // Textured 3-pt poly
446 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
447 gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
448
449 u32 driver_idx =
450 (gpu_unai.blit_mask?1024:0) |
451 Dithering |
452 Blending_Mode | gpu_unai.TEXT_MODE |
453 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
454
455 if (!FastLightingEnabled()) {
456 driver_idx |= Lighting;
457 } else {
458 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
459 driver_idx |= Lighting;
460 }
461
462 PP driver = gpuPolySpanDrivers[driver_idx];
463 gpuDrawPolyFT(packet, driver, false);
464 } break;
42a261f1 465
466 case 0x28:
467 case 0x29:
468 case 0x2A:
030d1121 469 case 0x2B: { // Monochrome 4-pt poly
470 PP driver = gpuPolySpanDrivers[
471 (gpu_unai.blit_mask?1024:0) |
472 Blending_Mode |
473 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
474 ];
475 gpuDrawPolyF(packet, driver, true); // is_quad = true
476 } break;
42a261f1 477
478 case 0x2C:
479 case 0x2D:
480 case 0x2E:
030d1121 481 case 0x2F: { // Textured 4-pt poly
482 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
483 gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
484
485 u32 driver_idx =
486 (gpu_unai.blit_mask?1024:0) |
487 Dithering |
488 Blending_Mode | gpu_unai.TEXT_MODE |
489 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
490
491 if (!FastLightingEnabled()) {
492 driver_idx |= Lighting;
493 } else {
494 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
495 driver_idx |= Lighting;
496 }
497
498 PP driver = gpuPolySpanDrivers[driver_idx];
499 gpuDrawPolyFT(packet, driver, true); // is_quad = true
500 } break;
42a261f1 501
502 case 0x30:
503 case 0x31:
504 case 0x32:
030d1121 505 case 0x33: { // Gouraud-shaded 3-pt poly
506 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
507 // this is an untextured poly, so CF_LIGHT (texture blend)
508 // shouldn't apply. Until the original array of template
509 // instantiation ptrs is fixed, we're stuck with this. (TODO)
510 PP driver = gpuPolySpanDrivers[
511 (gpu_unai.blit_mask?1024:0) |
512 Dithering |
513 Blending_Mode |
514 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
515 ];
516 gpuDrawPolyG(packet, driver, false);
517 } break;
42a261f1 518
519 case 0x34:
520 case 0x35:
521 case 0x36:
030d1121 522 case 0x37: { // Gouraud-shaded, textured 3-pt poly
523 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
524 gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
525 PP driver = gpuPolySpanDrivers[
526 (gpu_unai.blit_mask?1024:0) |
527 Dithering |
528 Blending_Mode | gpu_unai.TEXT_MODE |
529 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
530 ];
531 gpuDrawPolyGT(packet, driver, false);
532 } break;
42a261f1 533
534 case 0x38:
535 case 0x39:
536 case 0x3A:
030d1121 537 case 0x3B: { // Gouraud-shaded 4-pt poly
538 // See notes regarding '129' for 0x30..0x33 further above -senquack
539 PP driver = gpuPolySpanDrivers[
540 (gpu_unai.blit_mask?1024:0) |
541 Dithering |
542 Blending_Mode |
543 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
544 ];
545 gpuDrawPolyG(packet, driver, true); // is_quad = true
546 } break;
42a261f1 547
548 case 0x3C:
549 case 0x3D:
550 case 0x3E:
030d1121 551 case 0x3F: { // Gouraud-shaded, textured 4-pt poly
552 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
553 gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
554 PP driver = gpuPolySpanDrivers[
555 (gpu_unai.blit_mask?1024:0) |
556 Dithering |
557 Blending_Mode | gpu_unai.TEXT_MODE |
558 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
559 ];
560 gpuDrawPolyGT(packet, driver, true); // is_quad = true
561 } break;
42a261f1 562
563 case 0x40:
564 case 0x41:
565 case 0x42:
030d1121 566 case 0x43: { // Monochrome line
567 // Shift index right by one, as untextured prims don't use lighting
568 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
569 PSD driver = gpuPixelSpanDrivers[driver_idx];
570 gpuDrawLineF(packet, driver);
571 } break;
572
573 case 0x48 ... 0x4F: { // Monochrome line strip
6f2ee2be 574 u32 num_vertexes = 1;
5f315a8f 575 u32 *list_position = &(list[2]);
8aea5f5a 576
030d1121 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);
6f2ee2be 581
582 while(1)
583 {
030d1121 584 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
585 gpu_unai.PacketBuffer.U4[2] = *list_position++;
586 gpuDrawLineF(packet, driver);
8aea5f5a 587
6f2ee2be 588 num_vertexes++;
5f315a8f 589 if(list_position >= list_end) {
804789d7 590 cmd = -1;
591 goto breakloop;
592 }
593 if((*list_position & 0xf000f000) == 0x50005000)
b243416b 594 break;
6f2ee2be 595 }
596
b243416b 597 len += (num_vertexes - 2);
030d1121 598 } break;
6f2ee2be 599
42a261f1 600 case 0x50:
601 case 0x51:
602 case 0x52:
030d1121 603 case 0x53: { // Gouraud-shaded line
604 // Shift index right by one, as untextured prims don't use lighting
605 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
606 // Index MSB selects Gouraud-shaded PixelSpanDriver:
607 driver_idx |= (1 << 5);
608 PSD driver = gpuPixelSpanDrivers[driver_idx];
609 gpuDrawLineG(packet, driver);
610 } break;
611
612 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
6f2ee2be 613 u32 num_vertexes = 1;
5f315a8f 614 u32 *list_position = &(list[2]);
8aea5f5a 615
030d1121 616 // Shift index right by one, as untextured prims don't use lighting
617 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
618 // Index MSB selects Gouraud-shaded PixelSpanDriver:
619 driver_idx |= (1 << 5);
620 PSD driver = gpuPixelSpanDrivers[driver_idx];
621 gpuDrawLineG(packet, driver);
6f2ee2be 622
623 while(1)
624 {
030d1121 625 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
626 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
627 gpu_unai.PacketBuffer.U4[2] = *list_position++;
628 gpu_unai.PacketBuffer.U4[3] = *list_position++;
629 gpuDrawLineG(packet, driver);
8aea5f5a 630
6f2ee2be 631 num_vertexes++;
5f315a8f 632 if(list_position >= list_end) {
804789d7 633 cmd = -1;
634 goto breakloop;
635 }
636 if((*list_position & 0xf000f000) == 0x50005000)
b243416b 637 break;
6f2ee2be 638 }
639
b243416b 640 len += (num_vertexes - 2) * 2;
030d1121 641 } break;
6f2ee2be 642
42a261f1 643 case 0x60:
644 case 0x61:
645 case 0x62:
030d1121 646 case 0x63: { // Monochrome rectangle (variable size)
647 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
648 gpuDrawT(packet, driver);
649 } break;
42a261f1 650
651 case 0x64:
652 case 0x65:
653 case 0x66:
030d1121 654 case 0x67: { // Textured rectangle (variable size)
655 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
656 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
657
658 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
659 // This fixes Silent Hill running animation on loading screens:
660 // (On PSX, color values 0x00-0x7F darken the source texture's color,
661 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
662 // 0x80 leaves source texture color unchanged, HOWEVER,
663 // gpu_unai uses a simple lighting LUT whereby only the upper
664 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
665 // 0x80.
666 //
667 // NOTE: I've changed all textured sprite draw commands here and
668 // elsewhere to use proper behavior, but left poly commands
669 // alone, I don't want to slow rendering down too much. (TODO)
670 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
671 // Strip lower 3 bits of each color and determine if lighting should be used:
672 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
673 driver_idx |= Lighting;
674 PS driver = gpuSpriteSpanDrivers[driver_idx];
675 gpuDrawS(packet, driver);
676 } break;
42a261f1 677
678 case 0x68:
679 case 0x69:
680 case 0x6A:
030d1121 681 case 0x6B: { // Monochrome rectangle (1x1 dot)
682 gpu_unai.PacketBuffer.U4[2] = 0x00010001;
683 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
684 gpuDrawT(packet, driver);
685 } break;
42a261f1 686
687 case 0x70:
688 case 0x71:
689 case 0x72:
030d1121 690 case 0x73: { // Monochrome rectangle (8x8)
691 gpu_unai.PacketBuffer.U4[2] = 0x00080008;
692 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
693 gpuDrawT(packet, driver);
694 } break;
42a261f1 695
696 case 0x74:
697 case 0x75:
698 case 0x76:
030d1121 699 case 0x77: { // Textured rectangle (8x8)
700 gpu_unai.PacketBuffer.U4[3] = 0x00080008;
701 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
702 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
703
704 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
705 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
706 // Strip lower 3 bits of each color and determine if lighting should be used:
707 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
708 driver_idx |= Lighting;
709 PS driver = gpuSpriteSpanDrivers[driver_idx];
710 gpuDrawS(packet, driver);
711 } break;
42a261f1 712
713 case 0x78:
714 case 0x79:
715 case 0x7A:
030d1121 716 case 0x7B: { // Monochrome rectangle (16x16)
717 gpu_unai.PacketBuffer.U4[2] = 0x00100010;
718 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
719 gpuDrawT(packet, driver);
720 } break;
42a261f1 721
722 case 0x7C:
723 case 0x7D:
724#ifdef __arm__
030d1121 725 if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
42a261f1 726 {
030d1121 727 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
728 gpuDrawS16(packet);
42a261f1 729 break;
730 }
731 // fallthrough
732#endif
733 case 0x7E:
030d1121 734 case 0x7F: { // Textured rectangle (16x16)
735 gpu_unai.PacketBuffer.U4[3] = 0x00100010;
736 gpuSetCLUT (gpu_unai.PacketBuffer.U4[2] >> 16);
737 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
738 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
739 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
740 // Strip lower 3 bits of each color and determine if lighting should be used:
741 if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
742 driver_idx |= Lighting;
743 PS driver = gpuSpriteSpanDrivers[driver_idx];
744 gpuDrawS(packet, driver);
745 } break;
42a261f1 746
747 case 0x80: // vid -> vid
030d1121 748 gpuMoveImage(packet);
42a261f1 749 break;
030d1121 750
9a6e7816 751#ifdef TEST
752 case 0xA0: // sys -> vid
753 {
754 u32 load_width = list[2] & 0xffff;
755 u32 load_height = list[2] >> 16;
756 u32 load_size = load_width * load_height;
757
758 len += load_size / 2;
030d1121 759 } break;
760
42a261f1 761 case 0xC0:
762 break;
763#else
764 case 0xA0: // sys ->vid
765 case 0xC0: // vid -> sys
030d1121 766 // Handled by gpulib
42a261f1 767 goto breakloop;
9a6e7816 768#endif
030d1121 769 case 0xE1 ... 0xE6: { // Draw settings
770 gpuGP0Cmd_0xEx(gpu_unai, gpu_unai.PacketBuffer.U4[0]);
771 } break;
6f2ee2be 772 }
773 }
b243416b 774
42a261f1 775breakloop:
b243416b 776 gpu.ex_regs[1] &= ~0x1ff;
030d1121 777 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
b243416b 778
779 *last_cmd = cmd;
780 return list - list_start;
6f2ee2be 781}
782
783void renderer_sync_ecmds(uint32_t *ecmds)
784{
42a261f1 785 int dummy;
786 do_cmd_list(&ecmds[1], 6, &dummy);
6f2ee2be 787}
788
05740673 789void renderer_update_caches(int x, int y, int w, int h)
6f2ee2be 790{
791}
792
793void renderer_flush_queues(void)
794{
795}
914455e6 796
5440b88e 797void renderer_set_interlace(int enable, int is_odd)
798{
799}
800
914455e6 801#include "../../frontend/plugin_lib.h"
030d1121 802// Handle any gpulib settings applicable to gpu_unai:
914455e6 803void renderer_set_config(const struct rearmed_cbs *cbs)
804{
030d1121 805 gpu_unai.vram = (u16*)gpu.vram;
806 gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
807 gpu_unai.config.pixel_skip = cbs->gpu_unai.pixel_skip;
808 gpu_unai.config.lighting = cbs->gpu_unai.lighting;
809 gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
810 gpu_unai.config.blending = cbs->gpu_unai.blending;
811 gpu_unai.config.dithering = cbs->gpu_unai.dithering;
43047988
JW
812 gpu_unai.config.scale_hires = cbs->gpu_unai.scale_hires;
813
814 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
815 if (gpu_unai.config.scale_hires) {
816 map_downscale_buffer();
817 } else {
818 unmap_downscale_buffer();
819 }
914455e6 820}
9a6e7816 821
c765eb86
JW
822void renderer_sync(void)
823{
824}
825
826void renderer_notify_update_lace(int updated)
827{
828}
829
42a261f1 830// vim:shiftwidth=2:expandtab