gpu: improve timings of clipped sprites
[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
8999ff50 73INLINE void scale_640_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
43047988
JW
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 {
8999ff50
PC
87 const le16_t* src16 = src;
88 le16_t* dst16 = dest;
43047988
JW
89
90 do {
8999ff50 91 *dst16++ = *src16;
43047988
JW
92 src16 += 2;
93 } while(--uCount);
94 }
95}
96
8999ff50 97INLINE void scale_512_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
43047988
JW
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 {
4949d4ff 125 const le16_t* src16 = src;
8999ff50 126 le16_t* dst16 = dest;
43047988
JW
127
128 do {
8999ff50
PC
129 *dst16++ = *src16++;
130 *dst16++ = *src16;
43047988 131 src16 += 2;
8999ff50
PC
132 *dst16++ = *src16++;
133 *dst16++ = *src16;
43047988 134 src16 += 2;
8999ff50 135 *dst16++ = *src16;
43047988
JW
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{
8999ff50 143 le16_t *dest = gpu_unai.downscale_vram;
4949d4ff 144 const le16_t *src = gpu_unai.vram;
43047988
JW
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 {
8999ff50 187 memcpy(dest + fb_offset_dest, src + fb_offset_src, size);
43047988
JW
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
8999ff50 194 return (uint16_t *)gpu_unai.downscale_vram;
43047988
JW
195}
196
197static void map_downscale_buffer(void)
198{
199 if (gpu_unai.downscale_vram)
200 return;
201
8999ff50 202 gpu_unai.downscale_vram = (le16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
43047988
JW
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));
4949d4ff 226 gpu_unai.vram = (le16_t *)gpu.vram;
030d1121 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
9a864a8f 320void renderer_notify_scanout_change(int x, int y)
3b7b0065 321{
322}
323
12367ad0 324#ifdef USE_GPULIB
030d1121 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 }
e929dec5 390}
12367ad0 391#endif
e929dec5 392
f99193c2 393#include "../gpulib/gpu_timing.h"
6f2ee2be 394extern const unsigned char cmd_lengths[256];
395
f99193c2 396int do_cmd_list(u32 *_list, int list_len, int *cpu_cycles_out, int *last_cmd)
6f2ee2be 397{
5f315a8f 398 u32 cmd = 0, len, i;
4949d4ff
PC
399 le32_t *list = (le32_t *)_list;
400 le32_t *list_start = list;
401 le32_t *list_end = list + list_len;
f99193c2 402 u32 cpu_cycles = 0;
6f2ee2be 403
030d1121 404 //TODO: set ilace_mask when resolution changes instead of every time,
405 // eliminate #ifdef below.
406 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
407
8f2bb0cb 408#ifdef HAVE_PRE_ARMV7 /* XXX */
b9db55a9 409 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
89c0de42 410#endif
43047988 411 if (gpu_unai.config.scale_hires) {
b9db55a9 412 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
43047988 413 }
89c0de42 414
6f2ee2be 415 for (; list < list_end; list += 1 + len)
416 {
4949d4ff 417 cmd = le32_to_u32(*list) >> 24;
6f2ee2be 418 len = cmd_lengths[cmd];
b243416b 419 if (list + 1 + len > list_end) {
420 cmd = -1;
421 break;
422 }
423
42a261f1 424 #define PRIM cmd
030d1121 425 gpu_unai.PacketBuffer.U4[0] = list[0];
42a261f1 426 for (i = 1; i <= len; i++)
030d1121 427 gpu_unai.PacketBuffer.U4[i] = list[i];
428
429 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
6f2ee2be 430
42a261f1 431 switch (cmd)
6f2ee2be 432 {
42a261f1 433 case 0x02:
030d1121 434 gpuClearImage(packet);
f99193c2 435 cpu_cycles += gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff,
436 le16_to_s16(packet.U2[5]) & 0x1ff);
42a261f1 437 break;
438
439 case 0x20:
440 case 0x21:
441 case 0x22:
030d1121 442 case 0x23: { // Monochrome 3-pt poly
443 PP driver = gpuPolySpanDrivers[
444 (gpu_unai.blit_mask?1024:0) |
445 Blending_Mode |
446 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
447 ];
448 gpuDrawPolyF(packet, driver, false);
f99193c2 449 cpu_cycles += gput_poly_base();
030d1121 450 } break;
42a261f1 451
452 case 0x24:
453 case 0x25:
454 case 0x26:
030d1121 455 case 0x27: { // Textured 3-pt poly
4949d4ff
PC
456 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
457 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
030d1121 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);
f99193c2 474 cpu_cycles += gput_poly_base_t();
030d1121 475 } break;
42a261f1 476
477 case 0x28:
478 case 0x29:
479 case 0x2A:
030d1121 480 case 0x2B: { // Monochrome 4-pt poly
481 PP driver = gpuPolySpanDrivers[
482 (gpu_unai.blit_mask?1024:0) |
483 Blending_Mode |
484 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
485 ];
486 gpuDrawPolyF(packet, driver, true); // is_quad = true
f99193c2 487 cpu_cycles += gput_quad_base();
030d1121 488 } break;
42a261f1 489
490 case 0x2C:
491 case 0x2D:
492 case 0x2E:
030d1121 493 case 0x2F: { // Textured 4-pt poly
4949d4ff
PC
494 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
495 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
030d1121 496
497 u32 driver_idx =
498 (gpu_unai.blit_mask?1024:0) |
499 Dithering |
500 Blending_Mode | gpu_unai.TEXT_MODE |
501 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
502
503 if (!FastLightingEnabled()) {
504 driver_idx |= Lighting;
505 } else {
506 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
507 driver_idx |= Lighting;
508 }
509
510 PP driver = gpuPolySpanDrivers[driver_idx];
511 gpuDrawPolyFT(packet, driver, true); // is_quad = true
f99193c2 512 cpu_cycles += gput_quad_base_t();
030d1121 513 } break;
42a261f1 514
515 case 0x30:
516 case 0x31:
517 case 0x32:
030d1121 518 case 0x33: { // Gouraud-shaded 3-pt poly
519 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
520 // this is an untextured poly, so CF_LIGHT (texture blend)
521 // shouldn't apply. Until the original array of template
522 // instantiation ptrs is fixed, we're stuck with this. (TODO)
523 PP driver = gpuPolySpanDrivers[
524 (gpu_unai.blit_mask?1024:0) |
525 Dithering |
526 Blending_Mode |
527 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
528 ];
529 gpuDrawPolyG(packet, driver, false);
f99193c2 530 cpu_cycles += gput_poly_base_g();
030d1121 531 } break;
42a261f1 532
533 case 0x34:
534 case 0x35:
535 case 0x36:
030d1121 536 case 0x37: { // Gouraud-shaded, textured 3-pt poly
4949d4ff
PC
537 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
538 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
030d1121 539 PP driver = gpuPolySpanDrivers[
540 (gpu_unai.blit_mask?1024:0) |
541 Dithering |
542 Blending_Mode | gpu_unai.TEXT_MODE |
543 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
544 ];
545 gpuDrawPolyGT(packet, driver, false);
f99193c2 546 cpu_cycles += gput_poly_base_gt();
030d1121 547 } break;
42a261f1 548
549 case 0x38:
550 case 0x39:
551 case 0x3A:
030d1121 552 case 0x3B: { // Gouraud-shaded 4-pt poly
553 // See notes regarding '129' for 0x30..0x33 further above -senquack
554 PP driver = gpuPolySpanDrivers[
555 (gpu_unai.blit_mask?1024:0) |
556 Dithering |
557 Blending_Mode |
558 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
559 ];
560 gpuDrawPolyG(packet, driver, true); // is_quad = true
f99193c2 561 cpu_cycles += gput_quad_base_g();
030d1121 562 } break;
42a261f1 563
564 case 0x3C:
565 case 0x3D:
566 case 0x3E:
030d1121 567 case 0x3F: { // Gouraud-shaded, textured 4-pt poly
4949d4ff
PC
568 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
569 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
030d1121 570 PP driver = gpuPolySpanDrivers[
571 (gpu_unai.blit_mask?1024:0) |
572 Dithering |
573 Blending_Mode | gpu_unai.TEXT_MODE |
574 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
575 ];
576 gpuDrawPolyGT(packet, driver, true); // is_quad = true
f99193c2 577 cpu_cycles += gput_quad_base_gt();
030d1121 578 } break;
42a261f1 579
580 case 0x40:
581 case 0x41:
582 case 0x42:
030d1121 583 case 0x43: { // Monochrome line
584 // Shift index right by one, as untextured prims don't use lighting
585 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
586 PSD driver = gpuPixelSpanDrivers[driver_idx];
587 gpuDrawLineF(packet, driver);
f99193c2 588 cpu_cycles += gput_line(0);
030d1121 589 } break;
590
591 case 0x48 ... 0x4F: { // Monochrome line strip
6f2ee2be 592 u32 num_vertexes = 1;
4949d4ff 593 le32_t *list_position = &list[2];
8aea5f5a 594
030d1121 595 // Shift index right by one, as untextured prims don't use lighting
596 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
597 PSD driver = gpuPixelSpanDrivers[driver_idx];
598 gpuDrawLineF(packet, driver);
6f2ee2be 599
600 while(1)
601 {
030d1121 602 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
603 gpu_unai.PacketBuffer.U4[2] = *list_position++;
604 gpuDrawLineF(packet, driver);
f99193c2 605 cpu_cycles += gput_line(0);
8aea5f5a 606
6f2ee2be 607 num_vertexes++;
5f315a8f 608 if(list_position >= list_end) {
804789d7 609 cmd = -1;
610 goto breakloop;
611 }
4949d4ff 612 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
b243416b 613 break;
6f2ee2be 614 }
615
b243416b 616 len += (num_vertexes - 2);
030d1121 617 } break;
6f2ee2be 618
42a261f1 619 case 0x50:
620 case 0x51:
621 case 0x52:
030d1121 622 case 0x53: { // Gouraud-shaded line
623 // Shift index right by one, as untextured prims don't use lighting
624 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
625 // Index MSB selects Gouraud-shaded PixelSpanDriver:
626 driver_idx |= (1 << 5);
627 PSD driver = gpuPixelSpanDrivers[driver_idx];
628 gpuDrawLineG(packet, driver);
f99193c2 629 cpu_cycles += gput_line(0);
030d1121 630 } break;
631
632 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
6f2ee2be 633 u32 num_vertexes = 1;
4949d4ff 634 le32_t *list_position = &list[2];
8aea5f5a 635
030d1121 636 // Shift index right by one, as untextured prims don't use lighting
637 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
638 // Index MSB selects Gouraud-shaded PixelSpanDriver:
639 driver_idx |= (1 << 5);
640 PSD driver = gpuPixelSpanDrivers[driver_idx];
641 gpuDrawLineG(packet, driver);
6f2ee2be 642
643 while(1)
644 {
030d1121 645 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
646 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
647 gpu_unai.PacketBuffer.U4[2] = *list_position++;
648 gpu_unai.PacketBuffer.U4[3] = *list_position++;
649 gpuDrawLineG(packet, driver);
f99193c2 650 cpu_cycles += gput_line(0);
8aea5f5a 651
6f2ee2be 652 num_vertexes++;
5f315a8f 653 if(list_position >= list_end) {
804789d7 654 cmd = -1;
655 goto breakloop;
656 }
4949d4ff 657 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
b243416b 658 break;
6f2ee2be 659 }
660
b243416b 661 len += (num_vertexes - 2) * 2;
030d1121 662 } break;
6f2ee2be 663
42a261f1 664 case 0x60:
665 case 0x61:
666 case 0x62:
030d1121 667 case 0x63: { // Monochrome rectangle (variable size)
668 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
c296224f 669 s32 w = 0, h = 0;
670 gpuDrawT(packet, driver, &w, &h);
671 cpu_cycles += gput_sprite(w, h);
030d1121 672 } break;
42a261f1 673
674 case 0x64:
675 case 0x65:
676 case 0x66:
030d1121 677 case 0x67: { // Textured rectangle (variable size)
4949d4ff 678 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
030d1121 679 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
c296224f 680 s32 w = 0, h = 0;
030d1121 681
682 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
683 // This fixes Silent Hill running animation on loading screens:
684 // (On PSX, color values 0x00-0x7F darken the source texture's color,
685 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
686 // 0x80 leaves source texture color unchanged, HOWEVER,
687 // gpu_unai uses a simple lighting LUT whereby only the upper
688 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
689 // 0x80.
690 //
691 // NOTE: I've changed all textured sprite draw commands here and
692 // elsewhere to use proper behavior, but left poly commands
693 // alone, I don't want to slow rendering down too much. (TODO)
694 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
695 // Strip lower 3 bits of each color and determine if lighting should be used:
4949d4ff 696 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
030d1121 697 driver_idx |= Lighting;
698 PS driver = gpuSpriteSpanDrivers[driver_idx];
c296224f 699 gpuDrawS(packet, driver, &w, &h);
700 cpu_cycles += gput_sprite(w, h);
030d1121 701 } break;
42a261f1 702
703 case 0x68:
704 case 0x69:
705 case 0x6A:
030d1121 706 case 0x6B: { // Monochrome rectangle (1x1 dot)
4949d4ff 707 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
030d1121 708 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
c296224f 709 s32 w = 0, h = 0;
710 gpuDrawT(packet, driver, &w, &h);
f99193c2 711 cpu_cycles += gput_sprite(1, 1);
030d1121 712 } break;
42a261f1 713
714 case 0x70:
715 case 0x71:
716 case 0x72:
030d1121 717 case 0x73: { // Monochrome rectangle (8x8)
4949d4ff 718 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
030d1121 719 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
c296224f 720 s32 w = 0, h = 0;
721 gpuDrawT(packet, driver, &w, &h);
722 cpu_cycles += gput_sprite(w, h);
030d1121 723 } break;
42a261f1 724
725 case 0x74:
726 case 0x75:
727 case 0x76:
030d1121 728 case 0x77: { // Textured rectangle (8x8)
4949d4ff
PC
729 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
730 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
030d1121 731 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
c296224f 732 s32 w = 0, h = 0;
030d1121 733
734 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
735 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
736 // Strip lower 3 bits of each color and determine if lighting should be used:
4949d4ff 737 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
030d1121 738 driver_idx |= Lighting;
739 PS driver = gpuSpriteSpanDrivers[driver_idx];
c296224f 740 gpuDrawS(packet, driver, &w, &h);
741 cpu_cycles += gput_sprite(w, h);
030d1121 742 } break;
42a261f1 743
744 case 0x78:
745 case 0x79:
746 case 0x7A:
030d1121 747 case 0x7B: { // Monochrome rectangle (16x16)
4949d4ff 748 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
030d1121 749 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
c296224f 750 s32 w = 0, h = 0;
751 gpuDrawT(packet, driver, &w, &h);
752 cpu_cycles += gput_sprite(w, h);
030d1121 753 } break;
42a261f1 754
755 case 0x7C:
756 case 0x7D:
757#ifdef __arm__
030d1121 758 if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
42a261f1 759 {
c296224f 760 s32 w = 0, h = 0;
761 gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
762 gpuDrawS16(packet, &w, &h);
763 cpu_cycles += gput_sprite(w, h);
42a261f1 764 break;
765 }
766 // fallthrough
767#endif
768 case 0x7E:
030d1121 769 case 0x7F: { // Textured rectangle (16x16)
4949d4ff
PC
770 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
771 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
030d1121 772 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
c296224f 773 s32 w = 0, h = 0;
030d1121 774 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
775 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
776 // Strip lower 3 bits of each color and determine if lighting should be used:
4949d4ff 777 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
030d1121 778 driver_idx |= Lighting;
779 PS driver = gpuSpriteSpanDrivers[driver_idx];
c296224f 780 gpuDrawS(packet, driver, &w, &h);
781 cpu_cycles += gput_sprite(w, h);
030d1121 782 } break;
42a261f1 783
36da9c13 784#ifdef TEST
42a261f1 785 case 0x80: // vid -> vid
030d1121 786 gpuMoveImage(packet);
42a261f1 787 break;
030d1121 788
9a6e7816 789 case 0xA0: // sys -> vid
790 {
791 u32 load_width = list[2] & 0xffff;
792 u32 load_height = list[2] >> 16;
793 u32 load_size = load_width * load_height;
794
795 len += load_size / 2;
030d1121 796 } break;
797
42a261f1 798 case 0xC0:
799 break;
800#else
c296224f 801 case 0x1F: // irq?
36da9c13 802 case 0x80 ... 0x9F: // vid -> vid
803 case 0xA0 ... 0xBF: // sys -> vid
804 case 0xC0 ... 0xDF: // vid -> sys
030d1121 805 // Handled by gpulib
42a261f1 806 goto breakloop;
9a6e7816 807#endif
030d1121 808 case 0xE1 ... 0xE6: { // Draw settings
4949d4ff 809 gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
030d1121 810 } break;
6f2ee2be 811 }
812 }
b243416b 813
42a261f1 814breakloop:
b243416b 815 gpu.ex_regs[1] &= ~0x1ff;
030d1121 816 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
b243416b 817
f99193c2 818 *cpu_cycles_out += cpu_cycles;
b243416b 819 *last_cmd = cmd;
820 return list - list_start;
6f2ee2be 821}
822
4949d4ff 823void renderer_sync_ecmds(u32 *ecmds)
6f2ee2be 824{
42a261f1 825 int dummy;
f99193c2 826 do_cmd_list(&ecmds[1], 6, &dummy, &dummy);
6f2ee2be 827}
828
3b7b0065 829void renderer_update_caches(int x, int y, int w, int h, int state_changed)
6f2ee2be 830{
831}
832
833void renderer_flush_queues(void)
834{
835}
914455e6 836
5440b88e 837void renderer_set_interlace(int enable, int is_odd)
838{
839}
840
914455e6 841#include "../../frontend/plugin_lib.h"
030d1121 842// Handle any gpulib settings applicable to gpu_unai:
914455e6 843void renderer_set_config(const struct rearmed_cbs *cbs)
844{
4949d4ff 845 gpu_unai.vram = (le16_t *)gpu.vram;
030d1121 846 gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
847 gpu_unai.config.pixel_skip = cbs->gpu_unai.pixel_skip;
848 gpu_unai.config.lighting = cbs->gpu_unai.lighting;
849 gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
850 gpu_unai.config.blending = cbs->gpu_unai.blending;
851 gpu_unai.config.dithering = cbs->gpu_unai.dithering;
43047988
JW
852 gpu_unai.config.scale_hires = cbs->gpu_unai.scale_hires;
853
854 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
855 if (gpu_unai.config.scale_hires) {
856 map_downscale_buffer();
857 } else {
858 unmap_downscale_buffer();
859 }
914455e6 860}
9a6e7816 861
c765eb86
JW
862void renderer_sync(void)
863{
864}
865
866void renderer_notify_update_lace(int updated)
867{
868}
869
42a261f1 870// vim:shiftwidth=2:expandtab