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"
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
49 // GPU fixed point math
50 #include "gpu_fixedpoint.h"
52 // Inner loop driver instantiation file
53 #include "gpu_inner.h"
55 // GPU internal image drawing functions
56 #include "gpu_raster_image.h"
58 // GPU internal line drawing functions
59 #include "gpu_raster_line.h"
61 // GPU internal polygon drawing functions
62 #include "gpu_raster_polygon.h"
64 // GPU internal sprite drawing functions
65 #include "gpu_raster_sprite.h"
67 // GPU command buffer execution/store
68 #include "gpu_command.h"
70 /////////////////////////////////////////////////////////////////////////////
72 #ifndef GPU_UNAI_NO_OLD
73 #define IS_OLD_RENDERER() gpu_unai.config.old_renderer
75 #define IS_OLD_RENDERER() false
78 #define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
80 INLINE void scale_640_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
84 const uint8_t* src8 = (const uint8_t *)src;
85 uint8_t* dst8 = (uint8_t *)dest;
94 const le16_t* src16 = src;
104 INLINE void scale_512_to_320(le16_t *dest, const le16_t *src, bool isRGB24) {
108 const uint8_t* src8 = (const uint8_t *)src;
109 uint8_t* dst8 = (uint8_t *)dest;
132 const le16_t* src16 = src;
133 le16_t* dst16 = dest;
148 static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
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;
155 // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
156 unsigned int fb_mask = 1024 * 512 - 1;
163 // Ensure start at a non-skipped line
164 while (*y & gpu_unai.inn.ilace_mask) ++*y;
167 unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
168 unsigned int fb_offset_dest = fb_offset_src;
170 if (*w == 512 || *w == 640) {
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;
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;
191 size_t size = isRGB24 ? *w * 3 : *w * 2;
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;
201 return (uint16_t *)gpu_unai.downscale_vram;
204 static void map_downscale_buffer(void)
206 if (gpu_unai.downscale_vram)
209 gpu_unai.downscale_vram = (le16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
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;
217 gpu.get_downscale_buffer = get_downscale_buffer;
221 static void unmap_downscale_buffer(void)
223 if (gpu_unai.downscale_vram == NULL)
226 gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
227 gpu_unai.downscale_vram = NULL;
228 gpu.get_downscale_buffer = NULL;
231 int renderer_init(void)
233 memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
234 gpu_unai.vram = (le16_t *)gpu.vram;
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);
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;
257 #if defined(GPU_UNAI_USE_INT_DIV_MULTINV) || (!defined(GPU_UNAI_NO_OLD) && !defined(GPU_UNAI_USE_FLOATMATH))
259 for(int i=1;i<=(1<<TABLE_BITS);++i)
261 double v = 1.0 / double(i);
262 #ifdef GPU_TABLE_10_BITS
263 v *= double(0xffffffff>>1);
265 v *= double(0x80000000);
267 s_invTable[i-1]=s32(v);
272 SetupDitheringConstants();
274 if (gpu_unai.config.scale_hires) {
275 map_downscale_buffer();
281 void renderer_finish(void)
283 unmap_downscale_buffer();
286 void renderer_notify_res_change(void)
288 gpu_unai.inn.ilace_mask = gpu_unai.config.ilace_force;
290 #ifndef HAVE_PRE_ARMV7 /* XXX */
291 if (gpu_unai.config.scale_hires)
294 gpu_unai.inn.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
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);
304 void renderer_notify_scanout_change(int x, int y)
309 // Handles GP0 draw settings commands 0xE1...0xE6
310 static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
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
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);
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
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];
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);
346 gpuSetTexture(gpu_unai.GPU_GP1);
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;
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;
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);
369 // GP0(E6h) - Mask Bit Setting
370 gpu_unai.Masking = (cmd_word & 0x2) << 1;
371 gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
377 #include "../gpulib/gpu_timing.h"
379 // Strip lower 3 bits of each color and determine if lighting should be used:
380 static inline bool need_lighting(u32 rgb_raw)
382 return (rgb_raw & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080);
385 static inline void textured_sprite(int &cpu_cycles_sum, int &cpu_cycles)
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);
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
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));
412 extern const unsigned char cmd_lengths[256];
414 int do_cmd_list(u32 *list_, int list_len,
415 int *cycles_sum_out, int *cycles_last, int *last_cmd)
417 int cpu_cycles_sum = 0, cpu_cycles = *cycles_last;
419 le32_t *list = (le32_t *)list_;
420 le32_t *list_start = list;
421 le32_t *list_end = list + list_len;
423 if (IS_OLD_RENDERER())
424 return oldunai_do_cmd_list(list_, list_len, cycles_sum_out, cycles_last, last_cmd);
426 for (; list < list_end; list += 1 + len)
428 cmd = le32_to_u32(*list) >> 24;
429 len = cmd_lengths[cmd];
430 if (list + 1 + len > list_end) {
436 gpu_unai.PacketBuffer.U4[0] = list[0];
437 for (i = 1; i <= len; i++)
438 gpu_unai.PacketBuffer.U4[i] = list[i];
440 PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
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));
453 case 0x23: { // Monochrome 3-pt poly
454 PP driver = gpuPolySpanDrivers[
455 //(gpu_unai.blit_mask?1024:0) |
457 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
459 gpuDrawPolyF(packet, driver, false);
460 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base());
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);
471 //(gpu_unai.blit_mask?1024:0) |
473 Blending_Mode | gpu_unai.TEXT_MODE |
474 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
476 if (!FastLightingEnabled()) {
477 driver_idx |= Lighting;
479 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
480 driver_idx |= Lighting;
483 PP driver = gpuPolySpanDrivers[driver_idx];
484 gpuDrawPolyFT(packet, driver, false);
485 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t());
491 case 0x2B: { // Monochrome 4-pt poly
492 PP driver = gpuPolySpanDrivers[
493 //(gpu_unai.blit_mask?1024:0) |
495 gpu_unai.Masking | Blending | gpu_unai.PixelMSB
497 gpuDrawPolyF(packet, driver, true); // is_quad = true
498 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base());
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)))
511 textured_sprite(cpu_cycles_sum, cpu_cycles);
512 if (++i >= simplified_count)
514 memcpy(&gpu_unai.PacketBuffer.U4[0], &gpu_unai.PacketBuffer.U4[i * 4], 16);
518 gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
521 //(gpu_unai.blit_mask?1024:0) |
523 Blending_Mode | gpu_unai.TEXT_MODE |
524 gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
526 if (!FastLightingEnabled()) {
527 driver_idx |= Lighting;
529 if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
530 driver_idx |= Lighting;
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());
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)
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)
552 PP driver = gpuPolySpanDrivers[
553 //(gpu_unai.blit_mask?1024:0) |
556 gpu_unai.Masking | Blending | gouraud | gpu_unai.PixelMSB
559 gpuDrawPolyG(packet, driver, false);
561 gpuDrawPolyF(packet, driver, false, POLYTYPE_G);
562 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g());
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;
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) {
579 if (!need_lighting(rgb0))
583 PP driver = gpuPolySpanDrivers[
584 //(gpu_unai.blit_mask?1024:0) |
586 Blending_Mode | gpu_unai.TEXT_MODE |
587 gpu_unai.Masking | Blending | gouraud | lighting | gpu_unai.PixelMSB
590 gpuDrawPolyGT(packet, driver, false); // is_quad = true
592 gpuDrawPolyFT(packet, driver, false, POLYTYPE_GT);
593 gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt());
599 case 0x3B: { // Gouraud-shaded 4-pt poly
600 // See notes regarding '129' for 0x30..0x33 further above -senquack
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)
607 PP driver = gpuPolySpanDrivers[
608 //(gpu_unai.blit_mask?1024:0) |
611 gpu_unai.Masking | Blending | gouraud | gpu_unai.PixelMSB
614 gpuDrawPolyG(packet, driver, true); // is_quad = true
616 gpuDrawPolyF(packet, driver, true, POLYTYPE_G);
617 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g());
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)))
630 textured_sprite(cpu_cycles_sum, cpu_cycles);
631 if (++i >= simplified_count)
633 memcpy(&gpu_unai.PacketBuffer.U4[0], &gpu_unai.PacketBuffer.U4[i * 4], 16);
637 gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
638 u8 lighting = Lighting;
639 u8 gouraud = lighting ? (1<<7) : 0;
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) {
646 if (!need_lighting(rgb0))
650 PP driver = gpuPolySpanDrivers[
651 //(gpu_unai.blit_mask?1024:0) |
653 Blending_Mode | gpu_unai.TEXT_MODE |
654 gpu_unai.Masking | Blending | gouraud | lighting | gpu_unai.PixelMSB
657 gpuDrawPolyGT(packet, driver, true); // is_quad = true
659 gpuDrawPolyFT(packet, driver, true, POLYTYPE_GT);
660 gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt());
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));
674 case 0x48 ... 0x4F: { // Monochrome line strip
675 u32 num_vertexes = 1;
676 le32_t *list_position = &list[2];
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);
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));
691 if(list_position >= list_end) {
695 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
699 len += (num_vertexes - 2);
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));
715 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
716 u32 num_vertexes = 1;
717 le32_t *list_position = &list[2];
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);
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));
736 if(list_position >= list_end) {
740 if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
744 len += (num_vertexes - 2) * 2;
750 case 0x63: { // Monochrome rectangle (variable size)
751 PT driver = gpuTileDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
753 gpuDrawT(packet, driver, &w, &h);
754 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
760 case 0x67: // Textured rectangle (variable size)
761 textured_sprite(cpu_cycles_sum, cpu_cycles);
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];
771 gpuDrawT(packet, driver, &w, &h);
772 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1));
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];
782 gpuDrawT(packet, driver, &w, &h);
783 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
789 case 0x77: { // Textured rectangle (8x8)
790 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
791 textured_sprite(cpu_cycles_sum, cpu_cycles);
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];
801 gpuDrawT(packet, driver, &w, &h);
802 gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
808 case 0x7F: { // Textured rectangle (16x16)
809 gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
810 textured_sprite(cpu_cycles_sum, cpu_cycles);
814 case 0x80: // vid -> vid
815 gpuMoveImage(packet);
818 case 0xA0: // sys -> vid
820 u32 load_width = list[2] & 0xffff;
821 u32 load_height = list[2] >> 16;
822 u32 load_size = load_width * load_height;
824 len += load_size / 2;
831 case 0x80 ... 0x9F: // vid -> vid
832 case 0xA0 ... 0xBF: // sys -> vid
833 case 0xC0 ... 0xDF: // vid -> sys
837 case 0xE1 ... 0xE6: { // Draw settings
838 gpuGP0Cmd_0xEx(gpu_unai, le32_to_u32(gpu_unai.PacketBuffer.U4[0]));
844 gpu.ex_regs[1] &= ~0x1ff;
845 gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
847 *cycles_sum_out += cpu_cycles_sum;
848 *cycles_last = cpu_cycles;
850 return list - list_start;
853 void renderer_sync_ecmds(u32 *ecmds)
855 if (!IS_OLD_RENDERER()) {
857 do_cmd_list(&ecmds[1], 6, &dummy, &dummy, &dummy);
860 oldunai_renderer_sync_ecmds(ecmds);
863 void renderer_update_caches(int x, int y, int w, int h, int state_changed)
867 void renderer_flush_queues(void)
871 void renderer_set_interlace(int enable, int is_odd)
873 renderer_notify_res_change();
876 #include "../../frontend/plugin_lib.h"
877 // Handle any gpulib settings applicable to gpu_unai:
878 void renderer_set_config(const struct rearmed_cbs *cbs)
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;
890 gpu.state.downscale_enable = gpu_unai.config.scale_hires;
891 if (gpu_unai.config.scale_hires) {
892 map_downscale_buffer();
894 unmap_downscale_buffer();
896 oldunai_renderer_set_config(cbs);
899 void renderer_sync(void)
903 void renderer_notify_update_lace(int updated)
907 // vim:shiftwidth=2:expandtab