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(uint16_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;
88 uint16_t* dst16 = dest;
91 *dst16++ = le16_to_u16(*src16);
97 INLINE void scale_512_to_320(uint16_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 uint16_t* dst16 = dest;
129 *dst16++ = le16_to_u16(*src16++);
130 *dst16++ = le16_to_u16(*src16);
132 *dst16++ = le16_to_u16(*src16++);
133 *dst16++ = le16_to_u16(*src16);
135 *dst16++ = le16_to_u16(*src16);
141 static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
143 uint16_t *dest = gpu_unai.downscale_vram;
144 const le16_t *src = gpu_unai.vram;
145 bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
146 int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
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 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
188 for (unsigned int i; i < size; i += 2)
189 dest[fb_offset_dest + i] = le16_to_u16(src[fb_offset_src + i]);
191 memcpy(dest + fb_offset_dest, (u16 *)src + fb_offset_src, size);
193 fb_offset_src = (fb_offset_src + stride) & fb_mask;
194 fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
199 return gpu_unai.downscale_vram;
202 static void map_downscale_buffer(void)
204 if (gpu_unai.downscale_vram)
207 gpu_unai.downscale_vram = (uint16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
209 if (gpu_unai.downscale_vram == NULL) {
210 fprintf(stderr, "failed to map downscale buffer\n");
211 gpu.get_downscale_buffer = NULL;
214 gpu.get_downscale_buffer = get_downscale_buffer;
218 static void unmap_downscale_buffer(void)
220 if (gpu_unai.downscale_vram == NULL)
223 gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
224 gpu_unai.downscale_vram = NULL;
225 gpu.get_downscale_buffer = NULL;
228 int renderer_init(void)
230 memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
231 gpu_unai.vram = (le16_t *)gpu.vram;
233 // Original standalone gpu_unai initialized TextureWindow[]. I added the
234 // same behavior here, since it seems unsafe to leave [2],[3] unset when
235 // using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
236 gpu_unai.TextureWindow[0] = 0;
237 gpu_unai.TextureWindow[1] = 0;
238 gpu_unai.TextureWindow[2] = 255;
239 gpu_unai.TextureWindow[3] = 255;
240 //senquack - new vars must be updated whenever texture window is changed:
241 // (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
242 const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4
243 gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
244 gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
246 // Configuration options
247 gpu_unai.config = gpu_unai_config_ext;
248 //senquack - disabled, not sure this is needed and would require modifying
249 // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
250 // present in latest PCSX4ALL sources we were using.
251 //gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
252 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
254 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
256 for(int i=1;i<=(1<<TABLE_BITS);++i)
258 double v = 1.0 / double(i);
259 #ifdef GPU_TABLE_10_BITS
260 v *= double(0xffffffff>>1);
262 v *= double(0x80000000);
264 s_invTable[i-1]=s32(v);
269 SetupDitheringConstants();
271 if (gpu_unai.config.scale_hires) {
272 map_downscale_buffer();
278 void renderer_finish(void)
280 unmap_downscale_buffer();
283 void renderer_notify_res_change(void)
285 if (PixelSkipEnabled()) {
286 // Set blit_mask for high horizontal resolutions. This allows skipping
287 // rendering pixels that would never get displayed on low-resolution
288 // platforms that use simple pixel-dropping scaler.
290 switch (gpu.screen.hres)
292 case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
293 case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS
294 default: gpu_unai.blit_mask = 0; break;
297 gpu_unai.blit_mask = 0;
300 if (LineSkipEnabled()) {
301 // Set rendering line-skip (only render every other line in high-res
302 // 480 vertical mode, or, optionally, force it for all video modes)
304 if (gpu.screen.vres == 480) {
305 if (gpu_unai.config.ilace_force) {
306 gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
308 gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
311 // Vert resolution changed from 480 to lower one
312 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
315 gpu_unai.ilace_mask = 0;
319 printf("res change hres: %d vres: %d depth: %d ilace_mask: %d\n",
320 gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
321 gpu_unai.ilace_mask);
325 void renderer_notify_scanout_x_change(int x, int w)
330 // Handles GP0 draw settings commands 0xE1...0xE6
331 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
333 // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
334 u8 num = (cmd_word >> 24) & 7;
335 gpu.ex_regs[num] = cmd_word; // Update gpulib register
338 // GP0(E1h) - Draw Mode setting (aka "Texpage")
339 u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
340 u32 new_texpage = cmd_word & 0x7FF;
341 if (cur_texpage != new_texpage) {
342 gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
343 gpuSetTexture(gpu_unai.GPU_GP1);
348 // GP0(E2h) - Texture Window setting
349 if (cmd_word != gpu_unai.TextureWindowCur) {
350 static const u8 TextureMask[32] = {
351 255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
352 127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
354 gpu_unai.TextureWindowCur = cmd_word;
355 gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
356 gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
357 gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
358 gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
359 gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
360 gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
362 // Inner loop vars must be updated whenever texture window is changed:
363 const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4
364 gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
365 gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
367 gpuSetTexture(gpu_unai.GPU_GP1);
372 // GP0(E3h) - Set Drawing Area top left (X1,Y1)
373 gpu_unai.DrawingArea[0] = cmd_word & 0x3FF;
374 gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
378 // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
379 gpu_unai.DrawingArea[2] = (cmd_word & 0x3FF) + 1;
380 gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
384 // GP0(E5h) - Set Drawing Offset (X,Y)
385 gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
386 gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
390 // GP0(E6h) - Mask Bit Setting
391 gpu_unai.Masking = (cmd_word & 0x2) << 1;
392 gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
398 extern const unsigned char cmd_lengths[256];
400 int do_cmd_list(u32 *_list, int list_len, int *last_cmd)
403 le32_t *list = (le32_t *)_list;
404 le32_t *list_start = list;
405 le32_t *list_end = list + list_len;
407 //TODO: set ilace_mask when resolution changes instead of every time,
408 // eliminate #ifdef below.
409 gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
411 #ifdef HAVE_PRE_ARMV7 /* XXX */
412 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
414 if (gpu_unai.config.scale_hires) {
415 gpu_unai.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
418 for (; list < list_end; list += 1 + len)
420 cmd = le32_to_u32(*list) >> 24;
421 len = cmd_lengths[cmd];
422 if (list + 1 + len > list_end) {
428 gpu_unai.PacketBuffer.U4[0] = list[0];
429 for (i = 1; i <= len; i++)
430 gpu_unai.PacketBuffer.U4[i] = list[i];
432 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
437 gpuClearImage(packet);
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);
455 case 0x27: { // Textured 3-pt poly
456 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
457 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
460 (gpu_unai.blit_mask?1024:0) |
462 Blending_Mode | gpu_unai.TEXT_MODE |
463 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
465 if (!FastLightingEnabled()) {
466 driver_idx |= Lighting;
468 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
469 driver_idx |= Lighting;
472 PP driver = gpuPolySpanDrivers[driver_idx];
473 gpuDrawPolyFT(packet, driver, false);
479 case 0x2B: { // Monochrome 4-pt poly
480 PP driver = gpuPolySpanDrivers[
481 (gpu_unai.blit_mask?1024:0) |
483 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
485 gpuDrawPolyF(packet, driver, true); // is_quad = true
491 case 0x2F: { // Textured 4-pt poly
492 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
493 gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
496 (gpu_unai.blit_mask?1024:0) |
498 Blending_Mode | gpu_unai.TEXT_MODE |
499 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
501 if (!FastLightingEnabled()) {
502 driver_idx |= Lighting;
504 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
505 driver_idx |= Lighting;
508 PP driver = gpuPolySpanDrivers[driver_idx];
509 gpuDrawPolyFT(packet, driver, true); // is_quad = true
515 case 0x33: { // Gouraud-shaded 3-pt poly
516 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
517 // this is an untextured poly, so CF_LIGHT (texture blend)
518 // shouldn't apply. Until the original array of template
519 // instantiation ptrs is fixed, we're stuck with this. (TODO)
520 PP driver = gpuPolySpanDrivers[
521 (gpu_unai.blit_mask?1024:0) |
524 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
526 gpuDrawPolyG(packet, driver, false);
532 case 0x37: { // Gouraud-shaded, textured 3-pt poly
533 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
534 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
535 PP driver = gpuPolySpanDrivers[
536 (gpu_unai.blit_mask?1024:0) |
538 Blending_Mode | gpu_unai.TEXT_MODE |
539 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
541 gpuDrawPolyGT(packet, driver, false);
547 case 0x3B: { // Gouraud-shaded 4-pt poly
548 // See notes regarding '129' for 0x30..0x33 further above -senquack
549 PP driver = gpuPolySpanDrivers[
550 (gpu_unai.blit_mask?1024:0) |
553 gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
555 gpuDrawPolyG(packet, driver, true); // is_quad = true
561 case 0x3F: { // Gouraud-shaded, textured 4-pt poly
562 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
563 gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
564 PP driver = gpuPolySpanDrivers[
565 (gpu_unai.blit_mask?1024:0) |
567 Blending_Mode | gpu_unai.TEXT_MODE |
568 gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
570 gpuDrawPolyGT(packet, driver, true); // is_quad = true
576 case 0x43: { // Monochrome line
577 // Shift index right by one, as untextured prims don't use lighting
578 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
579 PSD driver = gpuPixelSpanDrivers[driver_idx];
580 gpuDrawLineF(packet, driver);
583 case 0x48 ... 0x4F: { // Monochrome line strip
584 u32 num_vertexes = 1;
585 le32_t *list_position = &list[2];
587 // Shift index right by one, as untextured prims don't use lighting
588 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
589 PSD driver = gpuPixelSpanDrivers[driver_idx];
590 gpuDrawLineF(packet, driver);
594 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
595 gpu_unai.PacketBuffer.U4[2] = *list_position++;
596 gpuDrawLineF(packet, driver);
599 if(list_position >= list_end) {
603 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
607 len += (num_vertexes - 2);
613 case 0x53: { // Gouraud-shaded line
614 // Shift index right by one, as untextured prims don't use lighting
615 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
616 // Index MSB selects Gouraud-shaded PixelSpanDriver:
617 driver_idx |= (1 << 5);
618 PSD driver = gpuPixelSpanDrivers[driver_idx];
619 gpuDrawLineG(packet, driver);
622 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
623 u32 num_vertexes = 1;
624 le32_t *list_position = &list[2];
626 // Shift index right by one, as untextured prims don't use lighting
627 u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
628 // Index MSB selects Gouraud-shaded PixelSpanDriver:
629 driver_idx |= (1 << 5);
630 PSD driver = gpuPixelSpanDrivers[driver_idx];
631 gpuDrawLineG(packet, driver);
635 gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
636 gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
637 gpu_unai.PacketBuffer.U4[2] = *list_position++;
638 gpu_unai.PacketBuffer.U4[3] = *list_position++;
639 gpuDrawLineG(packet, driver);
642 if(list_position >= list_end) {
646 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
650 len += (num_vertexes - 2) * 2;
656 case 0x63: { // Monochrome rectangle (variable size)
657 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
658 gpuDrawT(packet, driver);
664 case 0x67: { // Textured rectangle (variable size)
665 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
666 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
668 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
669 // This fixes Silent Hill running animation on loading screens:
670 // (On PSX, color values 0x00-0x7F darken the source texture's color,
671 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
672 // 0x80 leaves source texture color unchanged, HOWEVER,
673 // gpu_unai uses a simple lighting LUT whereby only the upper
674 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
677 // NOTE: I've changed all textured sprite draw commands here and
678 // elsewhere to use proper behavior, but left poly commands
679 // alone, I don't want to slow rendering down too much. (TODO)
680 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
681 // Strip lower 3 bits of each color and determine if lighting should be used:
682 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
683 driver_idx |= Lighting;
684 PS driver = gpuSpriteSpanDrivers[driver_idx];
685 gpuDrawS(packet, driver);
691 case 0x6B: { // Monochrome rectangle (1x1 dot)
692 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
693 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
694 gpuDrawT(packet, driver);
700 case 0x73: { // Monochrome rectangle (8x8)
701 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
702 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
703 gpuDrawT(packet, driver);
709 case 0x77: { // Textured rectangle (8x8)
710 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
711 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
712 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
714 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
715 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
716 // Strip lower 3 bits of each color and determine if lighting should be used:
717 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
718 driver_idx |= Lighting;
719 PS driver = gpuSpriteSpanDrivers[driver_idx];
720 gpuDrawS(packet, driver);
726 case 0x7B: { // Monochrome rectangle (16x16)
727 gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
728 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
729 gpuDrawT(packet, driver);
735 if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
737 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
744 case 0x7F: { // Textured rectangle (16x16)
745 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
746 gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
747 u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
748 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
749 //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
750 // Strip lower 3 bits of each color and determine if lighting should be used:
751 if ((le32_raw(gpu_unai.PacketBuffer.U4[0]) & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080))
752 driver_idx |= Lighting;
753 PS driver = gpuSpriteSpanDrivers[driver_idx];
754 gpuDrawS(packet, driver);
758 case 0x80: // vid -> vid
759 gpuMoveImage(packet);
762 case 0xA0: // sys -> vid
764 u32 load_width = list[2] & 0xffff;
765 u32 load_height = list[2] >> 16;
766 u32 load_size = load_width * load_height;
768 len += load_size / 2;
774 case 0x80 ... 0x9F: // vid -> vid
775 case 0xA0 ... 0xBF: // sys -> vid
776 case 0xC0 ... 0xDF: // vid -> sys
780 case 0xE1 ... 0xE6: { // Draw settings
781 gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
787 gpu.ex_regs[1] &= ~0x1ff;
788 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
791 return list - list_start;
794 void renderer_sync_ecmds(u32 *ecmds)
797 do_cmd_list(&ecmds[1], 6, &dummy);
800 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
804 void renderer_flush_queues(void)
808 void renderer_set_interlace(int enable, int is_odd)
812 #include "../../frontend/plugin_lib.h"
813 // Handle any gpulib settings applicable to gpu_unai:
814 void renderer_set_config(const struct rearmed_cbs *cbs)
816 gpu_unai.vram = (le16_t *)gpu.vram;
817 gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
818 gpu_unai.config.pixel_skip = cbs->gpu_unai.pixel_skip;
819 gpu_unai.config.lighting = cbs->gpu_unai.lighting;
820 gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
821 gpu_unai.config.blending = cbs->gpu_unai.blending;
822 gpu_unai.config.dithering = cbs->gpu_unai.dithering;
823 gpu_unai.config.scale_hires = cbs->gpu_unai.scale_hires;
825 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
826 if (gpu_unai.config.scale_hires) {
827 map_downscale_buffer();
829 unmap_downscale_buffer();
833 void renderer_sync(void)
837 void renderer_notify_update_lace(int updated)
841 // vim:shiftwidth=2:expandtab