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) *
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. *
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. *
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 ***************************************************************************/
27 #include "../gpulib/gpu.h"
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
48 // GPU fixed point math
49 #include "gpu_fixedpoint.h"
51 // Inner loop driver instantiation file
52 #include "gpu_inner.h"
54 // GPU internal image drawing functions
55 #include "gpu_raster_image.h"
57 // GPU internal line drawing functions
58 #include "gpu_raster_line.h"
60 // GPU internal polygon drawing functions
61 #include "gpu_raster_polygon.h"
63 // GPU internal sprite drawing functions
64 #include "gpu_raster_sprite.h"
66 // GPU command buffer execution/store
67 #include "gpu_command.h"
69 /////////////////////////////////////////////////////////////////////////////
71 #define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
73 INLINE void scale_640_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
77 const uint8_t* src8 = (const uint8_t *)src;
78 uint8_t* dst8 = (uint8_t *)dest;
87 const le16_t* src16 = src;
97 INLINE void scale_512_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
101 const uint8_t* src8 = (const uint8_t *)src;
102 uint8_t* dst8 = (uint8_t *)dest;
125 const le16_t* src16 = src;
126 le16_t* dst16 = dest;
141 static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
143 le16_t *dest = gpu_unai.downscale_vram;
144 const le16_t *src = gpu_unai.vram;
145 bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
146 int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
148 // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
149 unsigned int fb_mask = 1024 * 512 - 1;
156 // Ensure start at a non-skipped line
157 while (*y & gpu_unai.ilace_mask) ++*y;
160 unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
161 unsigned int fb_offset_dest = fb_offset_src;
163 if (*w == 512 || *w == 640) {
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;
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;
184 size_t size = isRGB24 ? *w * 3 : *w * 2;
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;
194 return (uint16_t *)gpu_unai.downscale_vram;
197 static void map_downscale_buffer(void)
199 if (gpu_unai.downscale_vram)
202 gpu_unai.downscale_vram = (le16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
204 if (gpu_unai.downscale_vram == NULL) {
205 fprintf(stderr, "failed to map downscale buffer\n");
206 gpu.get_downscale_buffer = NULL;
209 gpu.get_downscale_buffer = get_downscale_buffer;
213 static void unmap_downscale_buffer(void)
215 if (gpu_unai.downscale_vram == NULL)
218 gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
219 gpu_unai.downscale_vram = NULL;
220 gpu.get_downscale_buffer = NULL;
223 int renderer_init(void)
225 memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
226 gpu_unai.vram = (le16_t *)gpu.vram;
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);
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;
249 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
251 for(int i=1;i<=(1<<TABLE_BITS);++i)
253 double v = 1.0 / double(i);
254 #ifdef GPU_TABLE_10_BITS
255 v *= double(0xffffffff>>1);
257 v *= double(0x80000000);
259 s_invTable[i-1]=s32(v);
264 SetupDitheringConstants();
266 if (gpu_unai.config.scale_hires) {
267 map_downscale_buffer();
273 void renderer_finish(void)
275 unmap_downscale_buffer();
278 void renderer_notify_res_change(void)
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.
285 switch (gpu.screen.hres)
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;
292 gpu_unai.blit_mask = 0;
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)
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
303 gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
306 // Vert resolution changed from 480 to lower one
307 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
310 gpu_unai.ilace_mask = 0;
314 printf("res change hres: %d vres: %d depth: %d ilace_mask: %d\n",
315 gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
316 gpu_unai.ilace_mask);
320 void renderer_notify_scanout_change(int x, int y)
325 // Handles GP0 draw settings commands 0xE1...0xE6
326 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
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
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);
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
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];
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);
362 gpuSetTexture(gpu_unai.GPU_GP1);
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;
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;
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);
385 // GP0(E6h) - Mask Bit Setting
386 gpu_unai.Masking = (cmd_word & 0x2) << 1;
387 gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
393 #include "../gpulib/gpu_timing.h"
394 extern const unsigned char cmd_lengths[256];
396 int do_cmd_list(u32 *list_, int list_len,
397 int *cycles_sum_out, int *cycles_last, int *last_cmd)
399 int cpu_cycles_sum = 0, cpu_cycles = *cycles_last;
401 le32_t *list = (le32_t *)list_;
402 le32_t *list_start = list;
403 le32_t *list_end = list + list_len;
405 //TODO: set ilace_mask when resolution changes instead of every time,
406 // eliminate #ifdef below.
407 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
409 #ifdef HAVE_PRE_ARMV7 /* XXX */
410 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
412 if (gpu_unai.config.scale_hires) {
413 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
416 for (; list < list_end; list += 1 + len)
418 cmd = le32_to_u32(*list) >> 24;
419 len = cmd_lengths[cmd];
420 if (list + 1 + len > list_end) {
426 gpu_unai.PacketBuffer.U4[0] = list[0];
427 for (i = 1; i <= len; i++)
428 gpu_unai.PacketBuffer.U4[i] = list[i];
430 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
435 gpuClearImage(packet);
436 gput_sum(cpu_cycles_sum, cpu_cycles,
437 gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff, le16_to_s16(packet.U2[5]) & 0x1ff));
443 case 0x23: { // Monochrome 3-pt poly
444 PP driver = gpuPolySpanDrivers[
445 (gpu_unai.blit_mask?1024:0) |
447 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
449 gpuDrawPolyF(packet, driver, false);
450 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base());
456 case 0x27: { // Textured 3-pt poly
457 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
458 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
461 (gpu_unai.blit_mask?1024:0) |
463 Blending_Mode | gpu_unai.TEXT_MODE |
464 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
466 if (!FastLightingEnabled()) {
467 driver_idx |= Lighting;
469 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
470 driver_idx |= Lighting;
473 PP driver = gpuPolySpanDrivers[driver_idx];
474 gpuDrawPolyFT(packet, driver, false);
475 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t());
481 case 0x2B: { // Monochrome 4-pt poly
482 PP driver = gpuPolySpanDrivers[
483 (gpu_unai.blit_mask?1024:0) |
485 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
487 gpuDrawPolyF(packet, driver, true); // is_quad = true
488 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base());
494 case 0x2F: { // Textured 4-pt poly
495 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
496 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
499 (gpu_unai.blit_mask?1024:0) |
501 Blending_Mode | gpu_unai.TEXT_MODE |
502 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
504 if (!FastLightingEnabled()) {
505 driver_idx |= Lighting;
507 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
508 driver_idx |= Lighting;
511 PP driver = gpuPolySpanDrivers[driver_idx];
512 gpuDrawPolyFT(packet, driver, true); // is_quad = true
513 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t());
519 case 0x33: { // Gouraud-shaded 3-pt poly
520 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
521 // this is an untextured poly, so CF_LIGHT (texture blend)
522 // shouldn't apply. Until the original array of template
523 // instantiation ptrs is fixed, we're stuck with this. (TODO)
524 PP driver = gpuPolySpanDrivers[
525 (gpu_unai.blit_mask?1024:0) |
528 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
530 gpuDrawPolyG(packet, driver, false);
531 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g());
537 case 0x37: { // Gouraud-shaded, textured 3-pt poly
538 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
539 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
540 PP driver = gpuPolySpanDrivers[
541 (gpu_unai.blit_mask?1024:0) |
543 Blending_Mode | gpu_unai.TEXT_MODE |
544 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
546 gpuDrawPolyGT(packet, driver, false);
547 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt());
553 case 0x3B: { // Gouraud-shaded 4-pt poly
554 // See notes regarding '129' for 0x30..0x33 further above -senquack
555 PP driver = gpuPolySpanDrivers[
556 (gpu_unai.blit_mask?1024:0) |
559 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
561 gpuDrawPolyG(packet, driver, true); // is_quad = true
562 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g());
568 case 0x3F: { // Gouraud-shaded, textured 4-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 PP driver = gpuPolySpanDrivers[
572 (gpu_unai.blit_mask?1024:0) |
574 Blending_Mode | gpu_unai.TEXT_MODE |
575 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
577 gpuDrawPolyGT(packet, driver, true); // is_quad = true
578 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt());
584 case 0x43: { // Monochrome line
585 // Shift index right by one, as untextured prims don't use lighting
586 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
587 PSD driver = gpuPixelSpanDrivers[driver_idx];
588 gpuDrawLineF(packet, driver);
589 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
592 case 0x48 ... 0x4F: { // Monochrome line strip
593 u32 num_vertexes = 1;
594 le32_t *list_position = &list[2];
596 // Shift index right by one, as untextured prims don't use lighting
597 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
598 PSD driver = gpuPixelSpanDrivers[driver_idx];
599 gpuDrawLineF(packet, driver);
603 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
604 gpu_unai.PacketBuffer.U4[2] = *list_position++;
605 gpuDrawLineF(packet, driver);
606 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
609 if(list_position >= list_end) {
613 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
617 len += (num_vertexes - 2);
623 case 0x53: { // Gouraud-shaded line
624 // Shift index right by one, as untextured prims don't use lighting
625 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
626 // Index MSB selects Gouraud-shaded PixelSpanDriver:
627 driver_idx |= (1 << 5);
628 PSD driver = gpuPixelSpanDrivers[driver_idx];
629 gpuDrawLineG(packet, driver);
630 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
633 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
634 u32 num_vertexes = 1;
635 le32_t *list_position = &list[2];
637 // Shift index right by one, as untextured prims don't use lighting
638 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
639 // Index MSB selects Gouraud-shaded PixelSpanDriver:
640 driver_idx |= (1 << 5);
641 PSD driver = gpuPixelSpanDrivers[driver_idx];
642 gpuDrawLineG(packet, driver);
646 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
647 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
648 gpu_unai.PacketBuffer.U4[2] = *list_position++;
649 gpu_unai.PacketBuffer.U4[3] = *list_position++;
650 gpuDrawLineG(packet, driver);
651 gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
654 if(list_position >= list_end) {
658 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
662 len += (num_vertexes - 2) * 2;
668 case 0x63: { // Monochrome rectangle (variable size)
669 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
671 gpuDrawT(packet, driver, &w, &h);
672 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
678 case 0x67: { // Textured rectangle (variable size)
679 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
680 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
683 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
684 // This fixes Silent Hill running animation on loading screens:
685 // (On PSX, color values 0x00-0x7F darken the source texture's color,
686 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
687 // 0x80 leaves source texture color unchanged, HOWEVER,
688 // gpu_unai uses a simple lighting LUT whereby only the upper
689 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
692 // NOTE: I've changed all textured sprite draw commands here and
693 // elsewhere to use proper behavior, but left poly commands
694 // alone, I don't want to slow rendering down too much. (TODO)
695 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
696 // Strip lower 3 bits of each color and determine if lighting should be used:
697 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
698 driver_idx |= Lighting;
699 PS driver = gpuSpriteSpanDrivers[driver_idx];
700 gpuDrawS(packet, driver, &w, &h);
701 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
707 case 0x6B: { // Monochrome rectangle (1x1 dot)
708 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
709 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
711 gpuDrawT(packet, driver, &w, &h);
712 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1));
718 case 0x73: { // Monochrome rectangle (8x8)
719 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
720 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
722 gpuDrawT(packet, driver, &w, &h);
723 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
729 case 0x77: { // Textured rectangle (8x8)
730 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
731 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
732 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
735 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
736 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
737 // Strip lower 3 bits of each color and determine if lighting should be used:
738 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
739 driver_idx |= Lighting;
740 PS driver = gpuSpriteSpanDrivers[driver_idx];
741 gpuDrawS(packet, driver, &w, &h);
742 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
748 case 0x7B: { // Monochrome rectangle (16x16)
749 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
750 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
752 gpuDrawT(packet, driver, &w, &h);
753 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
759 if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
762 gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
763 gpuDrawS16(packet, &w, &h);
764 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
770 case 0x7F: { // Textured rectangle (16x16)
771 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
772 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
773 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
775 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
776 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
777 // Strip lower 3 bits of each color and determine if lighting should be used:
778 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
779 driver_idx |= Lighting;
780 PS driver = gpuSpriteSpanDrivers[driver_idx];
781 gpuDrawS(packet, driver, &w, &h);
782 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
786 case 0x80: // vid -> vid
787 gpuMoveImage(packet);
790 case 0xA0: // sys -> vid
792 u32 load_width = list[2] & 0xffff;
793 u32 load_height = list[2] >> 16;
794 u32 load_size = load_width * load_height;
796 len += load_size / 2;
803 case 0x80 ... 0x9F: // vid -> vid
804 case 0xA0 ... 0xBF: // sys -> vid
805 case 0xC0 ... 0xDF: // vid -> sys
809 case 0xE1 ... 0xE6: { // Draw settings
810 gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
816 gpu.ex_regs[1] &= ~0x1ff;
817 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
819 *cycles_sum_out += cpu_cycles_sum;
820 *cycles_last = cpu_cycles;
822 return list - list_start;
825 void renderer_sync_ecmds(u32 *ecmds)
828 do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy);
831 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
835 void renderer_flush_queues(void)
839 void renderer_set_interlace(int enable, int is_odd)
843 #include "../../frontend/plugin_lib.h"
844 // Handle any gpulib settings applicable to gpu_unai:
845 void renderer_set_config(const struct rearmed_cbs *cbs)
847 gpu_unai.vram = (le16_t *)gpu.vram;
848 gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
849 gpu_unai.config.pixel_skip = cbs->gpu_unai.pixel_skip;
850 gpu_unai.config.lighting = cbs->gpu_unai.lighting;
851 gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
852 gpu_unai.config.blending = cbs->gpu_unai.blending;
853 gpu_unai.config.dithering = cbs->gpu_unai.dithering;
854 gpu_unai.config.scale_hires = cbs->gpu_unai.scale_hires;
856 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
857 if (gpu_unai.config.scale_hires) {
858 map_downscale_buffer();
860 unmap_downscale_buffer();
864 void renderer_sync(void)
868 void renderer_notify_update_lace(int updated)
872 // vim:shiftwidth=2:expandtab