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