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 #include "gpu_senquack.h"
32 // GPU fixed point math
33 #include "gpu_fixedpoint.h"
35 // Inner loop driver instantiation file
36 #include "gpu_inner.h"
38 // GPU internal image drawing functions
39 #include "gpu_raster_image.h"
41 // GPU internal line drawing functions
42 #include "gpu_raster_line.h"
44 // GPU internal polygon drawing functions
45 #include "gpu_raster_polygon.h"
47 // GPU internal sprite drawing functions
48 #include "gpu_raster_sprite.h"
50 // GPU command buffer execution/store
51 #include "gpu_command.h"
53 /////////////////////////////////////////////////////////////////////////////
55 int renderer_init(void)
57 memset((void*)&gpu_senquack, 0, sizeof(gpu_senquack));
58 gpu_senquack.vram = (u16*)gpu.vram;
60 // Original standalone gpu_senquack initialized TextureWindow[]. I added the
61 // same behavior here, since it seems unsafe to leave [2],[3] unset when
62 // using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
63 gpu_senquack.TextureWindow[0] = 0;
64 gpu_senquack.TextureWindow[1] = 0;
65 gpu_senquack.TextureWindow[2] = 255;
66 gpu_senquack.TextureWindow[3] = 255;
67 //senquack - new vars must be updated whenever texture window is changed:
68 // (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
69 const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4
70 gpu_senquack.u_msk = (((u32)gpu_senquack.TextureWindow[2]) << fb) | ((1 << fb) - 1);
71 gpu_senquack.v_msk = (((u32)gpu_senquack.TextureWindow[3]) << fb) | ((1 << fb) - 1);
73 // Configuration options
74 gpu_senquack.config = gpu_senquack_config_ext;
75 //senquack - disabled, not sure this is needed and would require modifying
76 // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
77 // present in latest PCSX4ALL sources we were using.
78 //gpu_senquack.config.enableAbbeyHack = gpu_senquack_config_ext.abe_hack;
79 gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
81 #ifdef GPU_UNAI_USE_INT_DIV_MULTINV
83 for(int i=1;i<=(1<<TABLE_BITS);++i)
85 double v = 1.0 / double(i);
86 #ifdef GPU_TABLE_10_BITS
87 v *= double(0xffffffff>>1);
89 v *= double(0x80000000);
91 s_invTable[i-1]=s32(v);
96 SetupDitheringConstants();
101 void renderer_finish(void)
105 void renderer_notify_res_change(void)
107 if (PixelSkipEnabled()) {
108 // Set blit_mask for high horizontal resolutions. This allows skipping
109 // rendering pixels that would never get displayed on low-resolution
110 // platforms that use simple pixel-dropping scaler.
112 switch (gpu.screen.hres)
114 case 512: gpu_senquack.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
115 case 640: gpu_senquack.blit_mask = 0xaa; break; // GPU_BlitWS
116 default: gpu_senquack.blit_mask = 0; break;
119 gpu_senquack.blit_mask = 0;
122 if (LineSkipEnabled()) {
123 // Set rendering line-skip (only render every other line in high-res
124 // 480 vertical mode, or, optionally, force it for all video modes)
126 if (gpu.screen.vres == 480) {
127 if (gpu_senquack.config.ilace_force) {
128 gpu_senquack.ilace_mask = 3; // Only need 1/4 of lines
130 gpu_senquack.ilace_mask = 1; // Only need 1/2 of lines
133 // Vert resolution changed from 480 to lower one
134 gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
137 gpu_senquack.ilace_mask = 0;
141 printf("res change hres: %d vres: %d depth: %d ilace_mask: %d\n",
142 gpu.screen.hres, gpu.screen.vres, gpu.status.rgb24 ? 24 : 15,
143 gpu_senquack.ilace_mask);
148 // Handles GP0 draw settings commands 0xE1...0xE6
149 static void gpuGP0Cmd_0xEx(gpu_senquack_t &gpu_senquack, u32 cmd_word)
151 // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
152 u8 num = (cmd_word >> 24) & 7;
153 gpu.ex_regs[num] = cmd_word; // Update gpulib register
156 // GP0(E1h) - Draw Mode setting (aka "Texpage")
157 u32 cur_texpage = gpu_senquack.GPU_GP1 & 0x7FF;
158 u32 new_texpage = cmd_word & 0x7FF;
159 if (cur_texpage != new_texpage) {
160 gpu_senquack.GPU_GP1 = (gpu_senquack.GPU_GP1 & ~0x7FF) | new_texpage;
161 gpuSetTexture(gpu_senquack.GPU_GP1);
166 // GP0(E2h) - Texture Window setting
167 if (cmd_word != gpu_senquack.TextureWindowCur) {
168 static const u8 TextureMask[32] = {
169 255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
170 127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
172 gpu_senquack.TextureWindowCur = cmd_word;
173 gpu_senquack.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
174 gpu_senquack.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
175 gpu_senquack.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
176 gpu_senquack.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
177 gpu_senquack.TextureWindow[0] &= ~gpu_senquack.TextureWindow[2];
178 gpu_senquack.TextureWindow[1] &= ~gpu_senquack.TextureWindow[3];
180 // Inner loop vars must be updated whenever texture window is changed:
181 const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4
182 gpu_senquack.u_msk = (((u32)gpu_senquack.TextureWindow[2]) << fb) | ((1 << fb) - 1);
183 gpu_senquack.v_msk = (((u32)gpu_senquack.TextureWindow[3]) << fb) | ((1 << fb) - 1);
185 gpuSetTexture(gpu_senquack.GPU_GP1);
190 // GP0(E3h) - Set Drawing Area top left (X1,Y1)
191 gpu_senquack.DrawingArea[0] = cmd_word & 0x3FF;
192 gpu_senquack.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
196 // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
197 gpu_senquack.DrawingArea[2] = (cmd_word & 0x3FF) + 1;
198 gpu_senquack.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
202 // GP0(E5h) - Set Drawing Offset (X,Y)
203 gpu_senquack.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
204 gpu_senquack.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
208 // GP0(E6h) - Mask Bit Setting
209 gpu_senquack.Masking = (cmd_word & 0x2) << 1;
210 gpu_senquack.PixelMSB = (cmd_word & 0x1) << 8;
216 extern const unsigned char cmd_lengths[256];
218 int do_cmd_list(u32 *list, int list_len, int *last_cmd)
221 u32 *list_start = list;
222 u32 *list_end = list + list_len;
224 //TODO: set ilace_mask when resolution changes instead of every time,
225 // eliminate #ifdef below.
226 gpu_senquack.ilace_mask = gpu_senquack.config.ilace_force;
228 #ifdef HAVE_PRE_ARMV7 /* XXX */
229 gpu_senquack.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
231 if (gpu_senquack.config.scale_hires) {
232 gpu_senquack.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
235 for (; list < list_end; list += 1 + len)
238 len = cmd_lengths[cmd];
239 if (list + 1 + len > list_end) {
245 gpu_senquack.PacketBuffer.U4[0] = list[0];
246 for (i = 1; i <= len; i++)
247 gpu_senquack.PacketBuffer.U4[i] = list[i];
249 PtrUnion packet = { .ptr = (void*)&gpu_senquack.PacketBuffer };
254 gpuClearImage(packet);
260 case 0x23: { // Monochrome 3-pt poly
261 PP driver = gpuPolySpanDrivers[
262 (gpu_senquack.blit_mask?1024:0) |
264 gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
266 gpuDrawPolyF(packet, driver, false);
272 case 0x27: { // Textured 3-pt poly
273 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
274 gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
277 (gpu_senquack.blit_mask?1024:0) |
279 Blending_Mode | gpu_senquack.TEXT_MODE |
280 gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
282 if (!FastLightingEnabled()) {
283 driver_idx |= Lighting;
285 if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
286 driver_idx |= Lighting;
289 PP driver = gpuPolySpanDrivers[driver_idx];
290 gpuDrawPolyFT(packet, driver, false);
296 case 0x2B: { // Monochrome 4-pt poly
297 PP driver = gpuPolySpanDrivers[
298 (gpu_senquack.blit_mask?1024:0) |
300 gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB
302 gpuDrawPolyF(packet, driver, true); // is_quad = true
308 case 0x2F: { // Textured 4-pt poly
309 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
310 gpuSetTexture(gpu_senquack.PacketBuffer.U4[4] >> 16);
313 (gpu_senquack.blit_mask?1024:0) |
315 Blending_Mode | gpu_senquack.TEXT_MODE |
316 gpu_senquack.Masking | Blending | gpu_senquack.PixelMSB;
318 if (!FastLightingEnabled()) {
319 driver_idx |= Lighting;
321 if (!((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F)))
322 driver_idx |= Lighting;
325 PP driver = gpuPolySpanDrivers[driver_idx];
326 gpuDrawPolyFT(packet, driver, true); // is_quad = true
332 case 0x33: { // Gouraud-shaded 3-pt poly
333 //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
334 // this is an untextured poly, so CF_LIGHT (texture blend)
335 // shouldn't apply. Until the original array of template
336 // instantiation ptrs is fixed, we're stuck with this. (TODO)
337 PP driver = gpuPolySpanDrivers[
338 (gpu_senquack.blit_mask?1024:0) |
341 gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
343 gpuDrawPolyG(packet, driver, false);
349 case 0x37: { // Gouraud-shaded, textured 3-pt poly
350 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
351 gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
352 PP driver = gpuPolySpanDrivers[
353 (gpu_senquack.blit_mask?1024:0) |
355 Blending_Mode | gpu_senquack.TEXT_MODE |
356 gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
358 gpuDrawPolyGT(packet, driver, false);
364 case 0x3B: { // Gouraud-shaded 4-pt poly
365 // See notes regarding '129' for 0x30..0x33 further above -senquack
366 PP driver = gpuPolySpanDrivers[
367 (gpu_senquack.blit_mask?1024:0) |
370 gpu_senquack.Masking | Blending | 129 | gpu_senquack.PixelMSB
372 gpuDrawPolyG(packet, driver, true); // is_quad = true
378 case 0x3F: { // Gouraud-shaded, textured 4-pt poly
379 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
380 gpuSetTexture (gpu_senquack.PacketBuffer.U4[5] >> 16);
381 PP driver = gpuPolySpanDrivers[
382 (gpu_senquack.blit_mask?1024:0) |
384 Blending_Mode | gpu_senquack.TEXT_MODE |
385 gpu_senquack.Masking | Blending | ((Lighting)?129:0) | gpu_senquack.PixelMSB
387 gpuDrawPolyGT(packet, driver, true); // is_quad = true
393 case 0x43: { // Monochrome line
394 // Shift index right by one, as untextured prims don't use lighting
395 u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
396 PSD driver = gpuPixelSpanDrivers[driver_idx];
397 gpuDrawLineF(packet, driver);
400 case 0x48 ... 0x4F: { // Monochrome line strip
401 u32 num_vertexes = 1;
402 u32 *list_position = &(list[2]);
404 // Shift index right by one, as untextured prims don't use lighting
405 u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
406 PSD driver = gpuPixelSpanDrivers[driver_idx];
407 gpuDrawLineF(packet, driver);
411 gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[2];
412 gpu_senquack.PacketBuffer.U4[2] = *list_position++;
413 gpuDrawLineF(packet, driver);
416 if(list_position >= list_end) {
420 if((*list_position & 0xf000f000) == 0x50005000)
424 len += (num_vertexes - 2);
430 case 0x53: { // Gouraud-shaded line
431 // Shift index right by one, as untextured prims don't use lighting
432 u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
433 // Index MSB selects Gouraud-shaded PixelSpanDriver:
434 driver_idx |= (1 << 5);
435 PSD driver = gpuPixelSpanDrivers[driver_idx];
436 gpuDrawLineG(packet, driver);
439 case 0x58 ... 0x5F: { // Gouraud-shaded line strip
440 u32 num_vertexes = 1;
441 u32 *list_position = &(list[2]);
443 // Shift index right by one, as untextured prims don't use lighting
444 u32 driver_idx = (Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1;
445 // Index MSB selects Gouraud-shaded PixelSpanDriver:
446 driver_idx |= (1 << 5);
447 PSD driver = gpuPixelSpanDrivers[driver_idx];
448 gpuDrawLineG(packet, driver);
452 gpu_senquack.PacketBuffer.U4[0] = gpu_senquack.PacketBuffer.U4[2];
453 gpu_senquack.PacketBuffer.U4[1] = gpu_senquack.PacketBuffer.U4[3];
454 gpu_senquack.PacketBuffer.U4[2] = *list_position++;
455 gpu_senquack.PacketBuffer.U4[3] = *list_position++;
456 gpuDrawLineG(packet, driver);
459 if(list_position >= list_end) {
463 if((*list_position & 0xf000f000) == 0x50005000)
467 len += (num_vertexes - 2) * 2;
473 case 0x63: { // Monochrome rectangle (variable size)
474 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
475 gpuDrawT(packet, driver);
481 case 0x67: { // Textured rectangle (variable size)
482 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
483 u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
485 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
486 // This fixes Silent Hill running animation on loading screens:
487 // (On PSX, color values 0x00-0x7F darken the source texture's color,
488 // 0x81-FF lighten textures (ultimately clamped to 0x1F),
489 // 0x80 leaves source texture color unchanged, HOWEVER,
490 // gpu_senquack uses a simple lighting LUT whereby only the upper
491 // 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
494 // NOTE: I've changed all textured sprite draw commands here and
495 // elsewhere to use proper behavior, but left poly commands
496 // alone, I don't want to slow rendering down too much. (TODO)
497 //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
498 // Strip lower 3 bits of each color and determine if lighting should be used:
499 if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
500 driver_idx |= Lighting;
501 PS driver = gpuSpriteSpanDrivers[driver_idx];
502 gpuDrawS(packet, driver);
508 case 0x6B: { // Monochrome rectangle (1x1 dot)
509 gpu_senquack.PacketBuffer.U4[2] = 0x00010001;
510 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
511 gpuDrawT(packet, driver);
517 case 0x73: { // Monochrome rectangle (8x8)
518 gpu_senquack.PacketBuffer.U4[2] = 0x00080008;
519 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
520 gpuDrawT(packet, driver);
526 case 0x77: { // Textured rectangle (8x8)
527 gpu_senquack.PacketBuffer.U4[3] = 0x00080008;
528 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
529 u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
531 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
532 //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
533 // Strip lower 3 bits of each color and determine if lighting should be used:
534 if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
535 driver_idx |= Lighting;
536 PS driver = gpuSpriteSpanDrivers[driver_idx];
537 gpuDrawS(packet, driver);
543 case 0x7B: { // Monochrome rectangle (16x16)
544 gpu_senquack.PacketBuffer.U4[2] = 0x00100010;
545 PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>3)) >> 1];
546 gpuDrawT(packet, driver);
552 if ((gpu_senquack.GPU_GP1 & 0x180) == 0 && (gpu_senquack.Masking | gpu_senquack.PixelMSB) == 0)
554 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
561 case 0x7F: { // Textured rectangle (16x16)
562 gpu_senquack.PacketBuffer.U4[3] = 0x00100010;
563 gpuSetCLUT (gpu_senquack.PacketBuffer.U4[2] >> 16);
564 u32 driver_idx = Blending_Mode | gpu_senquack.TEXT_MODE | gpu_senquack.Masking | Blending | (gpu_senquack.PixelMSB>>1);
565 //senquack - Only color 808080h-878787h allows skipping lighting calculation:
566 //if ((gpu_senquack.PacketBuffer.U1[0]>0x5F) && (gpu_senquack.PacketBuffer.U1[1]>0x5F) && (gpu_senquack.PacketBuffer.U1[2]>0x5F))
567 // Strip lower 3 bits of each color and determine if lighting should be used:
568 if ((gpu_senquack.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
569 driver_idx |= Lighting;
570 PS driver = gpuSpriteSpanDrivers[driver_idx];
571 gpuDrawS(packet, driver);
574 case 0x80: // vid -> vid
575 gpuMoveImage(packet);
579 case 0xA0: // sys -> vid
581 u32 load_width = list[2] & 0xffff;
582 u32 load_height = list[2] >> 16;
583 u32 load_size = load_width * load_height;
585 len += load_size / 2;
591 case 0xA0: // sys ->vid
592 case 0xC0: // vid -> sys
596 case 0xE1 ... 0xE6: { // Draw settings
597 gpuGP0Cmd_0xEx(gpu_senquack, gpu_senquack.PacketBuffer.U4[0]);
603 gpu.ex_regs[1] &= ~0x1ff;
604 gpu.ex_regs[1] |= gpu_senquack.GPU_GP1 & 0x1ff;
607 return list - list_start;
610 void renderer_sync_ecmds(uint32_t *ecmds)
613 do_cmd_list(&ecmds[1], 6, &dummy);
616 void renderer_update_caches(int x, int y, int w, int h)
620 void renderer_flush_queues(void)
624 void renderer_set_interlace(int enable, int is_odd)
628 #include "../../frontend/plugin_lib.h"
629 // Handle any gpulib settings applicable to gpu_senquack:
630 void renderer_set_config(const struct rearmed_cbs *cbs)
632 gpu_senquack.vram = (u16*)gpu.vram;
633 gpu_senquack.config.ilace_force = cbs->gpu_senquack.ilace_force;
634 gpu_senquack.config.pixel_skip = cbs->gpu_senquack.pixel_skip;
635 gpu_senquack.config.lighting = cbs->gpu_senquack.lighting;
636 gpu_senquack.config.fast_lighting = cbs->gpu_senquack.fast_lighting;
637 gpu_senquack.config.blending = cbs->gpu_senquack.blending;
638 gpu_senquack.config.dithering = cbs->gpu_senquack.dithering;
639 gpu_senquack.config.scale_hires = cbs->gpu_senquack.scale_hires;
642 // vim:shiftwidth=2:expandtab