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