cdrom: change pause timing again
[pcsx_rearmed.git] / plugins / gpu_unai / gpulib_if.cpp
CommitLineData
0bfe8d59 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
e223fa15 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
0bfe8d59 45//#include "port.h"
e223fa15 46#include "gpu_unai.h"
0bfe8d59 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
e223fa15 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
0bfe8d59 223int renderer_init(void)
224{
e223fa15 225 memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
226 gpu_unai.vram = (le16_t *)gpu.vram;
0bfe8d59 227
e223fa15 228 // Original standalone gpu_unai initialized TextureWindow[]. I added the
0bfe8d59 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
e223fa15 231 gpu_unai.TextureWindow[0] = 0;
232 gpu_unai.TextureWindow[1] = 0;
233 gpu_unai.TextureWindow[2] = 255;
234 gpu_unai.TextureWindow[3] = 255;
0bfe8d59 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
e223fa15 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);
0bfe8d59 240
241 // Configuration options
e223fa15 242 gpu_unai.config = gpu_unai_config_ext;
0bfe8d59 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.
e223fa15 246 //gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
247 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
0bfe8d59 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
e223fa15 266 if (gpu_unai.config.scale_hires) {
267 map_downscale_buffer();
268 }
269
0bfe8d59 270 return 0;
271}
272
273void renderer_finish(void)
274{
e223fa15 275 unmap_downscale_buffer();
0bfe8d59 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 {
e223fa15 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;
0bfe8d59 290 }
291 } else {
e223fa15 292 gpu_unai.blit_mask = 0;
0bfe8d59 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) {
e223fa15 300 if (gpu_unai.config.ilace_force) {
301 gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
0bfe8d59 302 } else {
e223fa15 303 gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
0bfe8d59 304 }
305 } else {
306 // Vert resolution changed from 480 to lower one
e223fa15 307 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
0bfe8d59 308 }
309 } else {
e223fa15 310 gpu_unai.ilace_mask = 0;
0bfe8d59 311 }
312
313 /*
314 printf("res change hres: %d vres: %d depth: %d ilace_mask: %d\n",
e223fa15 315 gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
316 gpu_unai.ilace_mask);
0bfe8d59 317 */
318}
319
2da2fc76 320void renderer_notify_scanout_change(int x, int y)
0b4038f8 321{
322}
323
0bfe8d59 324#ifdef USE_GPULIB
325// Handles GP0 draw settings commands 0xE1...0xE6
e223fa15 326static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
0bfe8d59 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")
e223fa15 334 u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
0bfe8d59 335 u32 new_texpage = cmd_word & 0x7FF;
336 if (cur_texpage != new_texpage) {
e223fa15 337 gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
338 gpuSetTexture(gpu_unai.GPU_GP1);
0bfe8d59 339 }
340 } break;
341
342 case 2: {
343 // GP0(E2h) - Texture Window setting
e223fa15 344 if (cmd_word != gpu_unai.TextureWindowCur) {
0bfe8d59 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 };
e223fa15 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];
0bfe8d59 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
e223fa15 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);
0bfe8d59 361
e223fa15 362 gpuSetTexture(gpu_unai.GPU_GP1);
0bfe8d59 363 }
364 } break;
365
366 case 3: {
367 // GP0(E3h) - Set Drawing Area top left (X1,Y1)
e223fa15 368 gpu_unai.DrawingArea[0] = cmd_word & 0x3FF;
369 gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
0bfe8d59 370 } break;
371
372 case 4: {
373 // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
e223fa15 374 gpu_unai.DrawingArea[2] = (cmd_word & 0x3FF) + 1;
375 gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
0bfe8d59 376 } break;
377
378 case 5: {
379 // GP0(E5h) - Set Drawing Offset (X,Y)
e223fa15 380 gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
381 gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
0bfe8d59 382 } break;
383
384 case 6: {
385 // GP0(E6h) - Mask Bit Setting
e223fa15 386 gpu_unai.Masking = (cmd_word & 0x2) << 1;
387 gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
0bfe8d59 388 } break;
389 }
390}
391#endif
392
90ac6fed 393#include "../gpulib/gpu_timing.h"
0bfe8d59 394extern const unsigned char cmd_lengths[256];
395
8412166f 396int do_cmd_list(u32 *list_, int list_len,
397 int *cycles_sum_out, int *cycles_last, int *last_cmd)
0bfe8d59 398{
8412166f 399 int cpu_cycles_sum = 0, cpu_cycles = *cycles_last;
0bfe8d59 400 u32 cmd = 0, len, i;
8412166f 401 le32_t *list = (le32_t *)list_;
e223fa15 402 le32_t *list_start = list;
403 le32_t *list_end = list + list_len;
0bfe8d59 404
405 //TODO: set ilace_mask when resolution changes instead of every time,
406 // eliminate #ifdef below.
e223fa15 407 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
0bfe8d59 408
409#ifdef HAVE_PRE_ARMV7 /* XXX */
e223fa15 410 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
0bfe8d59 411#endif
e223fa15 412 if (gpu_unai.config.scale_hires) {
413 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
0bfe8d59 414 }
415
416 for (; list < list_end; list += 1 + len)
417 {
e223fa15 418 cmd = le32_to_u32(*list) >> 24;
0bfe8d59 419 len = cmd_lengths[cmd];
420 if (list + 1 + len > list_end) {
421 cmd = -1;
422 break;
423 }
424
425 #define PRIM cmd
e223fa15 426 gpu_unai.PacketBuffer.U4[0] = list[0];
0bfe8d59 427 for (i = 1; i <= len; i++)
e223fa15 428 gpu_unai.PacketBuffer.U4[i] = list[i];
0bfe8d59 429
e223fa15 430 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
0bfe8d59 431
432 switch (cmd)
433 {
434 case 0x02:
435 gpuClearImage(packet);
8412166f 436 gput_sum(cpu_cycles_sum, cpu_cycles,
437 gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff, le16_to_s16(packet.U2[5]) & 0x1ff));
0bfe8d59 438 break;
439
440 case 0x20:
441 case 0x21:
442 case 0x22:
443 case 0x23: { // Monochrome 3-pt poly
444 PP driver = gpuPolySpanDrivers[
e223fa15 445 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 446 Blending_Mode |
e223fa15 447 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
0bfe8d59 448 ];
449 gpuDrawPolyF(packet, driver, false);
8412166f 450 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base());
0bfe8d59 451 } break;
452
453 case 0x24:
454 case 0x25:
455 case 0x26:
456 case 0x27: { // Textured 3-pt poly
e223fa15 457 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
458 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
0bfe8d59 459
460 u32 driver_idx =
e223fa15 461 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 462 Dithering |
e223fa15 463 Blending_Mode | gpu_unai.TEXT_MODE |
464 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
0bfe8d59 465
466 if (!FastLightingEnabled()) {
467 driver_idx |= Lighting;
468 } else {
e223fa15 469 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
0bfe8d59 470 driver_idx |= Lighting;
471 }
472
473 PP driver = gpuPolySpanDrivers[driver_idx];
474 gpuDrawPolyFT(packet, driver, false);
8412166f 475 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t());
0bfe8d59 476 } break;
477
478 case 0x28:
479 case 0x29:
480 case 0x2A:
481 case 0x2B: { // Monochrome 4-pt poly
482 PP driver = gpuPolySpanDrivers[
e223fa15 483 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 484 Blending_Mode |
e223fa15 485 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
0bfe8d59 486 ];
487 gpuDrawPolyF(packet, driver, true); // is_quad = true
8412166f 488 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base());
0bfe8d59 489 } break;
490
491 case 0x2C:
492 case 0x2D:
493 case 0x2E:
494 case 0x2F: { // Textured 4-pt poly
e223fa15 495 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
496 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
0bfe8d59 497
498 u32 driver_idx =
e223fa15 499 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 500 Dithering |
e223fa15 501 Blending_Mode | gpu_unai.TEXT_MODE |
502 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
0bfe8d59 503
504 if (!FastLightingEnabled()) {
505 driver_idx |= Lighting;
506 } else {
e223fa15 507 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
0bfe8d59 508 driver_idx |= Lighting;
509 }
510
511 PP driver = gpuPolySpanDrivers[driver_idx];
512 gpuDrawPolyFT(packet, driver, true); // is_quad = true
8412166f 513 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t());
0bfe8d59 514 } break;
515
516 case 0x30:
517 case 0x31:
518 case 0x32:
519 case 0x33: { // Gouraud-shaded 3-pt poly
520 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
521 // this is an untextured poly, so CF_LIGHT (texture blend)
522 // shouldn't apply. Until the original array of template
523 // instantiation ptrs is fixed, we're stuck with this. (TODO)
524 PP driver = gpuPolySpanDrivers[
e223fa15 525 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 526 Dithering |
527 Blending_Mode |
e223fa15 528 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
0bfe8d59 529 ];
530 gpuDrawPolyG(packet, driver, false);
8412166f 531 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g());
0bfe8d59 532 } break;
533
534 case 0x34:
535 case 0x35:
536 case 0x36:
537 case 0x37: { // Gouraud-shaded, textured 3-pt poly
e223fa15 538 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
539 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
0bfe8d59 540 PP driver = gpuPolySpanDrivers[
e223fa15 541 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 542 Dithering |
e223fa15 543 Blending_Mode | gpu_unai.TEXT_MODE |
544 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
0bfe8d59 545 ];
546 gpuDrawPolyGT(packet, driver, false);
8412166f 547 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt());
0bfe8d59 548 } break;
549
550 case 0x38:
551 case 0x39:
552 case 0x3A:
553 case 0x3B: { // Gouraud-shaded 4-pt poly
554 // See notes regarding '129' for 0x30..0x33 further above -senquack
555 PP driver = gpuPolySpanDrivers[
e223fa15 556 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 557 Dithering |
558 Blending_Mode |
e223fa15 559 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
0bfe8d59 560 ];
561 gpuDrawPolyG(packet, driver, true); // is_quad = true
8412166f 562 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g());
0bfe8d59 563 } break;
564
565 case 0x3C:
566 case 0x3D:
567 case 0x3E:
568 case 0x3F: { // Gouraud-shaded, textured 4-pt poly
e223fa15 569 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
570 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
0bfe8d59 571 PP driver = gpuPolySpanDrivers[
e223fa15 572 (gpu_unai.blit_mask?1024:0) |
0bfe8d59 573 Dithering |
e223fa15 574 Blending_Mode | gpu_unai.TEXT_MODE |
575 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
0bfe8d59 576 ];
577 gpuDrawPolyGT(packet, driver, true); // is_quad = true
8412166f 578 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt());
0bfe8d59 579 } break;
580
581 case 0x40:
582 case 0x41:
583 case 0x42:
584 case 0x43: { // Monochrome line
585 // Shift index right by one, as untextured prims don't use lighting
e223fa15 586 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
0bfe8d59 587 PSD driver = gpuPixelSpanDrivers[driver_idx];
588 gpuDrawLineF(packet, driver);
8412166f 589 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
0bfe8d59 590 } break;
591
592 case 0x48 ... 0x4F: { // Monochrome line strip
593 u32 num_vertexes = 1;
e223fa15 594 le32_t *list_position = &list[2];
0bfe8d59 595
596 // Shift index right by one, as untextured prims don't use lighting
e223fa15 597 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
0bfe8d59 598 PSD driver = gpuPixelSpanDrivers[driver_idx];
599 gpuDrawLineF(packet, driver);
600
601 while(1)
602 {
e223fa15 603 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
604 gpu_unai.PacketBuffer.U4[2] = *list_position++;
0bfe8d59 605 gpuDrawLineF(packet, driver);
8412166f 606 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
0bfe8d59 607
608 num_vertexes++;
609 if(list_position >= list_end) {
610 cmd = -1;
611 goto breakloop;
612 }
e223fa15 613 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
0bfe8d59 614 break;
615 }
616
617 len += (num_vertexes - 2);
618 } break;
619
620 case 0x50:
621 case 0x51:
622 case 0x52:
623 case 0x53: { // Gouraud-shaded line
624 // Shift index right by one, as untextured prims don't use lighting
e223fa15 625 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
0bfe8d59 626 // Index MSB selects Gouraud-shaded PixelSpanDriver:
627 driver_idx |= (1 << 5);
628 PSD driver = gpuPixelSpanDrivers[driver_idx];
629 gpuDrawLineG(packet, driver);
8412166f 630 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
0bfe8d59 631 } break;
632
633 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
634 u32 num_vertexes = 1;
e223fa15 635 le32_t *list_position = &list[2];
0bfe8d59 636
637 // Shift index right by one, as untextured prims don't use lighting
e223fa15 638 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
0bfe8d59 639 // Index MSB selects Gouraud-shaded PixelSpanDriver:
640 driver_idx |= (1 << 5);
641 PSD driver = gpuPixelSpanDrivers[driver_idx];
642 gpuDrawLineG(packet, driver);
643
644 while(1)
645 {
e223fa15 646 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
647 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
648 gpu_unai.PacketBuffer.U4[2] = *list_position++;
649 gpu_unai.PacketBuffer.U4[3] = *list_position++;
0bfe8d59 650 gpuDrawLineG(packet, driver);
8412166f 651 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
0bfe8d59 652
653 num_vertexes++;
654 if(list_position >= list_end) {
655 cmd = -1;
656 goto breakloop;
657 }
e223fa15 658 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
0bfe8d59 659 break;
660 }
661
662 len += (num_vertexes - 2) * 2;
663 } break;
664
665 case 0x60:
666 case 0x61:
667 case 0x62:
668 case 0x63: { // Monochrome rectangle (variable size)
e223fa15 669 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
1cec4719 670 s32 w = 0, h = 0;
671 gpuDrawT(packet, driver, &w, &h);
8412166f 672 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 673 } break;
674
675 case 0x64:
676 case 0x65:
677 case 0x66:
678 case 0x67: { // Textured rectangle (variable size)
e223fa15 679 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
680 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
1cec4719 681 s32 w = 0, h = 0;
0bfe8d59 682
683 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
684 // This fixes Silent Hill running animation on loading screens:
685 // (On PSX, color values 0x00-0x7F darken the source texture's color,
686 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
687 // 0x80 leaves source texture color unchanged, HOWEVER,
e223fa15 688 // gpu_unai uses a simple lighting LUT whereby only the upper
0bfe8d59 689 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
690 // 0x80.
691 //
692 // NOTE: I've changed all textured sprite draw commands here and
693 // elsewhere to use proper behavior, but left poly commands
694 // alone, I don't want to slow rendering down too much. (TODO)
e223fa15 695 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
0bfe8d59 696 // Strip lower 3 bits of each color and determine if lighting should be used:
e223fa15 697 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
0bfe8d59 698 driver_idx |= Lighting;
699 PS driver = gpuSpriteSpanDrivers[driver_idx];
1cec4719 700 gpuDrawS(packet, driver, &w, &h);
8412166f 701 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 702 } break;
703
704 case 0x68:
705 case 0x69:
706 case 0x6A:
707 case 0x6B: { // Monochrome rectangle (1x1 dot)
e223fa15 708 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
709 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
1cec4719 710 s32 w = 0, h = 0;
711 gpuDrawT(packet, driver, &w, &h);
8412166f 712 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1));
0bfe8d59 713 } break;
714
715 case 0x70:
716 case 0x71:
717 case 0x72:
718 case 0x73: { // Monochrome rectangle (8x8)
e223fa15 719 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
720 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
1cec4719 721 s32 w = 0, h = 0;
722 gpuDrawT(packet, driver, &w, &h);
8412166f 723 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 724 } break;
725
726 case 0x74:
727 case 0x75:
728 case 0x76:
729 case 0x77: { // Textured rectangle (8x8)
e223fa15 730 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
731 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
732 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
1cec4719 733 s32 w = 0, h = 0;
0bfe8d59 734
735 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
e223fa15 736 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
0bfe8d59 737 // Strip lower 3 bits of each color and determine if lighting should be used:
e223fa15 738 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
0bfe8d59 739 driver_idx |= Lighting;
740 PS driver = gpuSpriteSpanDrivers[driver_idx];
1cec4719 741 gpuDrawS(packet, driver, &w, &h);
8412166f 742 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 743 } break;
744
745 case 0x78:
746 case 0x79:
747 case 0x7A:
748 case 0x7B: { // Monochrome rectangle (16x16)
e223fa15 749 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
750 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
1cec4719 751 s32 w = 0, h = 0;
752 gpuDrawT(packet, driver, &w, &h);
8412166f 753 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 754 } break;
755
756 case 0x7C:
757 case 0x7D:
758#ifdef __arm__
e223fa15 759 if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
0bfe8d59 760 {
1cec4719 761 s32 w = 0, h = 0;
762 gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
763 gpuDrawS16(packet, &w, &h);
8412166f 764 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 765 break;
766 }
767 // fallthrough
768#endif
769 case 0x7E:
770 case 0x7F: { // Textured rectangle (16x16)
e223fa15 771 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
772 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
773 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
1cec4719 774 s32 w = 0, h = 0;
0bfe8d59 775 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
e223fa15 776 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
0bfe8d59 777 // Strip lower 3 bits of each color and determine if lighting should be used:
e223fa15 778 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
0bfe8d59 779 driver_idx |= Lighting;
780 PS driver = gpuSpriteSpanDrivers[driver_idx];
1cec4719 781 gpuDrawS(packet, driver, &w, &h);
8412166f 782 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
0bfe8d59 783 } break;
784
72583812 785#ifdef TEST
0bfe8d59 786 case 0x80: // vid -> vid
787 gpuMoveImage(packet);
788 break;
789
0bfe8d59 790 case 0xA0: // sys -> vid
791 {
792 u32 load_width = list[2] & 0xffff;
793 u32 load_height = list[2] >> 16;
794 u32 load_size = load_width * load_height;
795
796 len += load_size / 2;
797 } break;
798
799 case 0xC0:
800 break;
801#else
1cec4719 802 case 0x1F: // irq?
72583812 803 case 0x80 ... 0x9F: // vid -> vid
804 case 0xA0 ... 0xBF: // sys -> vid
805 case 0xC0 ... 0xDF: // vid -> sys
0bfe8d59 806 // Handled by gpulib
807 goto breakloop;
808#endif
809 case 0xE1 ... 0xE6: { // Draw settings
e223fa15 810 gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
0bfe8d59 811 } break;
812 }
813 }
814
815breakloop:
816 gpu.ex_regs[1] &= ~0x1ff;
e223fa15 817 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
0bfe8d59 818
8412166f 819 *cycles_sum_out += cpu_cycles_sum;
820 *cycles_last = cpu_cycles;
0bfe8d59 821 *last_cmd = cmd;
822 return list - list_start;
823}
824
e223fa15 825void renderer_sync_ecmds(u32 *ecmds)
0bfe8d59 826{
827 int dummy;
8412166f 828 do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy);
0bfe8d59 829}
830
0b4038f8 831void renderer_update_caches(int x, int y, int w, int h, int state_changed)
0bfe8d59 832{
833}
834
835void renderer_flush_queues(void)
836{
837}
838
839void renderer_set_interlace(int enable, int is_odd)
840{
841}
842
843#include "../../frontend/plugin_lib.h"
e223fa15 844// Handle any gpulib settings applicable to gpu_unai:
0bfe8d59 845void renderer_set_config(const struct rearmed_cbs *cbs)
846{
e223fa15 847 gpu_unai.vram = (le16_t *)gpu.vram;
848 gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
849 gpu_unai.config.pixel_skip = cbs->gpu_unai.pixel_skip;
850 gpu_unai.config.lighting = cbs->gpu_unai.lighting;
851 gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
852 gpu_unai.config.blending = cbs->gpu_unai.blending;
853 gpu_unai.config.dithering = cbs->gpu_unai.dithering;
854 gpu_unai.config.scale_hires = cbs->gpu_unai.scale_hires;
855
856 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
857 if (gpu_unai.config.scale_hires) {
858 map_downscale_buffer();
859 } else {
860 unmap_downscale_buffer();
861 }
862}
863
864void renderer_sync(void)
865{
866}
867
868void renderer_notify_update_lace(int updated)
869{
0bfe8d59 870}
871
872// vim:shiftwidth=2:expandtab