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