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