mirror of
https://github.com/notaz/pcsx_rearmed.git
synced 2026-10-12 02:20:06 +00:00
727 lines
25 KiB
C++
727 lines
25 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2010 PCSX4ALL Team *
|
|
* Copyright (C) 2010 Unai *
|
|
* Copyright (C) 2011 notaz *
|
|
* Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com) *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
|
|
***************************************************************************/
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "arm_features.h"
|
|
#include "../gpulib/gpu.h"
|
|
#include "old/if.h"
|
|
|
|
//#include "port.h"
|
|
#include "gpu_unai.h"
|
|
|
|
// GPU fixed point math
|
|
#include "gpu_fixedpoint.h"
|
|
|
|
// Inner loop driver instantiation file
|
|
#include "gpu_inner.h"
|
|
|
|
// GPU internal image drawing functions
|
|
#include "gpu_raster_image.h"
|
|
|
|
// GPU internal line drawing functions
|
|
#include "gpu_raster_line.h"
|
|
|
|
// GPU internal polygon drawing functions
|
|
#include "gpu_raster_polygon.h"
|
|
|
|
// GPU internal sprite drawing functions
|
|
#include "gpu_raster_sprite.h"
|
|
|
|
// GPU command buffer execution/store
|
|
#include "gpu_command.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef GPU_UNAI_NO_OLD
|
|
#define IS_OLD_RENDERER() gpu_unai.config.old_renderer
|
|
#else
|
|
#define IS_OLD_RENDERER() false
|
|
#endif
|
|
|
|
int renderer_init(void)
|
|
{
|
|
memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
|
|
gpu_unai.vram = (le16_t *)gpu.vram;
|
|
|
|
// Original standalone gpu_unai initialized TextureWindow[]. I added the
|
|
// same behavior here, since it seems unsafe to leave [2],[3] unset when
|
|
// using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
|
|
gpu_unai.TextureWindow[0] = 0;
|
|
gpu_unai.TextureWindow[1] = 0;
|
|
gpu_unai.TextureWindow[2] = 255;
|
|
gpu_unai.TextureWindow[3] = 255;
|
|
//senquack - new vars must be updated whenever texture window is changed:
|
|
// (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
|
|
gpu_unai.inn.mask_v00u =
|
|
((u32)gpu_unai.TextureWindow[3] << 24) | gpu_unai.TextureWindow[2];
|
|
|
|
// Configuration options
|
|
gpu_unai.config = gpu_unai_config_ext;
|
|
//senquack - disabled, not sure this is needed and would require modifying
|
|
// sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
|
|
// present in latest PCSX4ALL sources we were using.
|
|
//gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
|
|
gpu_unai.inn.ilace_mask = gpu_unai.config.ilace_force;
|
|
|
|
#if defined(GPU_UNAI_USE_INT_DIV_MULTINV) || (!defined(GPU_UNAI_NO_OLD) && !defined(GPU_UNAI_USE_FLOATMATH))
|
|
// s_invTable
|
|
for(int i=1;i<=(1<<TABLE_BITS);++i)
|
|
{
|
|
double v = 1.0 / double(i);
|
|
#ifdef GPU_TABLE_10_BITS
|
|
v *= double(0xffffffff>>1);
|
|
#else
|
|
v *= double(0x80000000);
|
|
#endif
|
|
s_invTable[i-1]=s32(v);
|
|
}
|
|
#endif
|
|
|
|
SetupLightLUT();
|
|
SetupDitheringConstants();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void renderer_finish(void)
|
|
{
|
|
}
|
|
|
|
void renderer_notify_screen_change(const struct psx_gpu_screen *screen)
|
|
{
|
|
gpu_unai.inn.ilace_mask = gpu_unai.config.ilace_force;
|
|
|
|
if (gpu.state.downscale_enable)
|
|
{
|
|
gpu_unai.inn.ilace_mask |= !!(gpu.status & PSX_GPU_STATUS_INTERLACE);
|
|
}
|
|
|
|
/*
|
|
printf("res change hres: %d vres: %d depth: %d ilace_mask: %d\n",
|
|
gpu.screen.hres, gpu.screen.vres, (gpu.status & PSX_GPU_STATUS_RGB24) ? 24 : 15,
|
|
gpu_unai.ilace_mask);
|
|
*/
|
|
}
|
|
|
|
#ifdef USE_GPULIB
|
|
// Handles GP0 draw settings commands 0xE1...0xE6
|
|
static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
|
|
{
|
|
// Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
|
|
u8 num = (cmd_word >> 24) & 7;
|
|
switch (num) {
|
|
case 1: {
|
|
// GP0(E1h) - Draw Mode setting (aka "Texpage")
|
|
u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
|
|
u32 new_texpage = cmd_word & 0x7FF;
|
|
if (cur_texpage != new_texpage) {
|
|
gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
|
|
gpuSetTexture(gpu_unai.GPU_GP1);
|
|
}
|
|
} break;
|
|
|
|
case 2: {
|
|
// GP0(E2h) - Texture Window setting
|
|
if (cmd_word != gpu_unai.TextureWindowCur) {
|
|
static const u8 TextureMask[32] = {
|
|
255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
|
|
127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
|
|
};
|
|
gpu_unai.TextureWindowCur = cmd_word;
|
|
gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
|
|
gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
|
|
gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
|
|
gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
|
|
gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
|
|
gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
|
|
|
|
// Inner loop vars must be updated whenever texture window is changed:
|
|
gpu_unai.inn.mask_v00u =
|
|
((u32)gpu_unai.TextureWindow[3] << 24) | gpu_unai.TextureWindow[2];
|
|
|
|
gpuSetTexture(gpu_unai.GPU_GP1);
|
|
}
|
|
} break;
|
|
|
|
case 3: {
|
|
// GP0(E3h) - Set Drawing Area top left (X1,Y1)
|
|
gpu_unai.DrawingArea[0] = cmd_word & 0x3FF;
|
|
gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
|
|
} break;
|
|
|
|
case 4: {
|
|
// GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
|
|
gpu_unai.DrawingArea[2] = (cmd_word & 0x3FF) + 1;
|
|
gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
|
|
} break;
|
|
|
|
case 5: {
|
|
// GP0(E5h) - Set Drawing Offset (X,Y)
|
|
gpu_unai.DrawingOffset[0] = GPU_EXPANDSIGN(cmd_word);
|
|
gpu_unai.DrawingOffset[1] = GPU_EXPANDSIGN(cmd_word >> 11);
|
|
} break;
|
|
|
|
case 6: {
|
|
// GP0(E6h) - Mask Bit Setting
|
|
gpu_unai.Masking = (cmd_word & 0x2) << 1;
|
|
gpu_unai.PixelMSB = (cmd_word & 0x1) << 8;
|
|
} break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#include "../gpulib/gpu_timing.h"
|
|
|
|
// Strip lower 3 bits of each color and determine if lighting should be used:
|
|
static inline bool need_lighting(u32 rgb_raw)
|
|
{
|
|
return (rgb_raw & HTOLE32(0xF8F8F8)) != HTOLE32(0x808080);
|
|
}
|
|
|
|
static inline void textured_sprite(int &cpu_cycles_sum, int &cpu_cycles)
|
|
{
|
|
u32 PRIM = le32_to_u32(gpu_unai.PacketBuffer.U4[0]) >> 24;
|
|
gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
|
|
u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
|
|
s32 w = 0, h = 0;
|
|
|
|
//senquack - Only color 808080h-878787h allows skipping lighting calculation:
|
|
// This fixes Silent Hill running animation on loading screens:
|
|
// (On PSX, color values 0x00-0x7F darken the source texture's color,
|
|
// 0x81-FF lighten textures (ultimately clamped to 0x1F),
|
|
// 0x80 leaves source texture color unchanged, HOWEVER,
|
|
// gpu_unai uses a simple lighting LUT whereby only the upper
|
|
// 5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
|
|
// 0x80.
|
|
//
|
|
// NOTE: I've changed all textured sprite draw commands here and
|
|
// elsewhere to use proper behavior, but left poly commands
|
|
// alone, I don't want to slow rendering down too much. (TODO)
|
|
if (need_lighting(le32_raw(gpu_unai.PacketBuffer.U4[0])))
|
|
driver_idx |= Lighting;
|
|
PS driver = gpuSpriteDrivers[driver_idx];
|
|
PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
|
|
gpuDrawS(packet, driver, &w, &h);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
|
|
}
|
|
|
|
extern const unsigned char cmd_lengths[256];
|
|
|
|
int renderer_do_cmd_list(u32 *list_, int list_len, uint32_t *ex_regs,
|
|
int *cycles_sum_out, int *cycles_last, int *last_cmd)
|
|
{
|
|
int cpu_cycles_sum = 0, cpu_cycles = *cycles_last;
|
|
u32 cmd = 0, len, i;
|
|
le32_t *list = (le32_t *)list_;
|
|
le32_t *list_start = list;
|
|
le32_t *list_end = list + list_len;
|
|
|
|
if (IS_OLD_RENDERER()) {
|
|
return oldunai_do_cmd_list(list_, list_len, ex_regs,
|
|
cycles_sum_out, cycles_last, last_cmd);
|
|
}
|
|
|
|
for (; list < list_end; list += 1 + len)
|
|
{
|
|
cmd = le32_to_u32(*list) >> 24;
|
|
len = cmd_lengths[cmd];
|
|
if (list + 1 + len > list_end) {
|
|
cmd = -1;
|
|
break;
|
|
}
|
|
|
|
#define PRIM cmd
|
|
gpu_unai.PacketBuffer.U4[0] = list[0];
|
|
for (i = 1; i <= len; i++)
|
|
gpu_unai.PacketBuffer.U4[i] = list[i];
|
|
|
|
PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
|
|
|
|
switch (cmd)
|
|
{
|
|
case 0x02:
|
|
gpuClearImage(packet);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles,
|
|
gput_fill(le16_to_s16(packet.U2[4]) & 0x3ff, le16_to_s16(packet.U2[5]) & 0x1ff));
|
|
break;
|
|
|
|
case 0x20:
|
|
case 0x21:
|
|
case 0x22:
|
|
case 0x23: { // Monochrome 3-pt poly
|
|
PP driver = gpuPolySpanDrivers[
|
|
Blending_Mode |
|
|
gpu_unai.Masking | Blending | gpu_unai.PixelMSB
|
|
];
|
|
gpuDrawPolyF(packet, driver, false);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base());
|
|
} break;
|
|
|
|
case 0x24:
|
|
case 0x25:
|
|
case 0x26:
|
|
case 0x27: { // Textured 3-pt poly
|
|
gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
|
|
gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
|
|
|
|
u32 driver_idx =
|
|
Dithering |
|
|
Blending_Mode | gpu_unai.TEXT_MODE |
|
|
gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
|
|
|
|
if (!FastLightingEnabled()) {
|
|
driver_idx |= Lighting;
|
|
} else {
|
|
if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
|
|
driver_idx |= Lighting;
|
|
}
|
|
|
|
PP driver = gpuPolySpanDrivers[driver_idx];
|
|
gpuDrawPolyFT(packet, driver, false);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_t());
|
|
} break;
|
|
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2A:
|
|
case 0x2B: { // Monochrome 4-pt poly
|
|
PP driver = gpuPolySpanDrivers[
|
|
Blending_Mode |
|
|
gpu_unai.Masking | Blending | gpu_unai.PixelMSB
|
|
];
|
|
gpuDrawPolyF(packet, driver, true); // is_quad = true
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base());
|
|
} break;
|
|
|
|
case 0x2C:
|
|
case 0x2D:
|
|
case 0x2E:
|
|
case 0x2F: { // Textured 4-pt poly
|
|
u32 dithering = Dithering;
|
|
u32 simplified_count;
|
|
gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[4]) >> 16);
|
|
if (!dithering &&
|
|
(simplified_count = prim_try_simplify_quad_t(gpu_unai.PacketBuffer.U4,
|
|
gpu_unai.PacketBuffer.U4)))
|
|
{
|
|
for (i = 0;; ) {
|
|
textured_sprite(cpu_cycles_sum, cpu_cycles);
|
|
if (++i >= simplified_count)
|
|
break;
|
|
memcpy(&gpu_unai.PacketBuffer.U4[0], &gpu_unai.PacketBuffer.U4[i * 4], 16);
|
|
}
|
|
break;
|
|
}
|
|
gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
|
|
|
|
u32 driver_idx =
|
|
dithering |
|
|
Blending_Mode | gpu_unai.TEXT_MODE |
|
|
gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
|
|
|
|
if (!FastLightingEnabled()) {
|
|
driver_idx |= Lighting;
|
|
} else {
|
|
if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
|
|
driver_idx |= Lighting;
|
|
}
|
|
|
|
PP driver = gpuPolySpanDrivers[driver_idx];
|
|
gpuDrawPolyFT(packet, driver, true); // is_quad = true
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_t());
|
|
} break;
|
|
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33: { // Gouraud-shaded 3-pt poly
|
|
u32 dithering = Dithering;
|
|
//NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
|
|
// this is an untextured poly, so CF_LIGHT (texture blend)
|
|
// shouldn't apply. Until the original array of template
|
|
// instantiation ptrs is fixed, we're stuck with this. (TODO)
|
|
u8 gouraud = 129;
|
|
if (!dithering) {
|
|
u32 xor_ = 0, rgb0 = le32_raw(gpu_unai.PacketBuffer.U4[0]);
|
|
for (i = 1; i < 3; i++)
|
|
xor_ |= rgb0 ^ le32_raw(gpu_unai.PacketBuffer.U4[i * 2]);
|
|
if ((xor_ & HTOLE32(0xf8f8f8)) == 0)
|
|
gouraud = 0;
|
|
}
|
|
PP driver = gpuPolySpanDrivers[
|
|
dithering |
|
|
Blending_Mode |
|
|
gpu_unai.Masking | Blending | gouraud | gpu_unai.PixelMSB
|
|
];
|
|
if (gouraud)
|
|
gpuDrawPolyG(packet, driver, false);
|
|
else
|
|
gpuDrawPolyF(packet, driver, false, POLYTYPE_G);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_g());
|
|
} break;
|
|
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37: { // Gouraud-shaded, textured 3-pt poly
|
|
gpuSetCLUT (le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
|
|
gpuSetTexture (le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
|
|
u32 dithering = Dithering;
|
|
u8 lighting = Lighting;
|
|
u8 gouraud = lighting ? (1<<7) : 0;
|
|
if (lighting) {
|
|
u32 xor_ = 0, rgb0 = le32_raw(gpu_unai.PacketBuffer.U4[0]);
|
|
for (i = 1; i < 3; i++)
|
|
xor_ |= rgb0 ^ le32_raw(gpu_unai.PacketBuffer.U4[i * 3]);
|
|
if ((xor_ & HTOLE32(0xf8f8f8)) == 0) {
|
|
gouraud = 0;
|
|
if (!dithering && !need_lighting(rgb0))
|
|
lighting = 0;
|
|
}
|
|
}
|
|
PP driver = gpuPolySpanDrivers[
|
|
dithering |
|
|
Blending_Mode | gpu_unai.TEXT_MODE |
|
|
gpu_unai.Masking | Blending | gouraud | lighting | gpu_unai.PixelMSB
|
|
];
|
|
if (gouraud)
|
|
gpuDrawPolyGT(packet, driver, false); // is_quad = true
|
|
else
|
|
gpuDrawPolyFT(packet, driver, false, POLYTYPE_GT);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_poly_base_gt());
|
|
} break;
|
|
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3A:
|
|
case 0x3B: { // Gouraud-shaded 4-pt poly
|
|
u32 dithering = Dithering;
|
|
// See notes regarding '129' for 0x30..0x33 further above -senquack
|
|
u8 gouraud = 129;
|
|
if (!dithering) {
|
|
u32 xor_ = 0, rgb0 = le32_raw(gpu_unai.PacketBuffer.U4[0]);
|
|
for (i = 1; i < 4; i++)
|
|
xor_ |= rgb0 ^ le32_raw(gpu_unai.PacketBuffer.U4[i * 2]);
|
|
if ((xor_ & HTOLE32(0xf8f8f8)) == 0)
|
|
gouraud = 0;
|
|
}
|
|
PP driver = gpuPolySpanDrivers[
|
|
dithering |
|
|
Blending_Mode |
|
|
gpu_unai.Masking | Blending | gouraud | gpu_unai.PixelMSB
|
|
];
|
|
if (gouraud)
|
|
gpuDrawPolyG(packet, driver, true); // is_quad = true
|
|
else
|
|
gpuDrawPolyF(packet, driver, true, POLYTYPE_G);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_g());
|
|
} break;
|
|
|
|
case 0x3C:
|
|
case 0x3D:
|
|
case 0x3E:
|
|
case 0x3F: { // Gouraud-shaded, textured 4-pt poly
|
|
u32 dithering = Dithering;
|
|
u32 simplified_count;
|
|
gpuSetTexture(le32_to_u32(gpu_unai.PacketBuffer.U4[5]) >> 16);
|
|
if (!dithering &&
|
|
(simplified_count = prim_try_simplify_quad_gt(gpu_unai.PacketBuffer.U4,
|
|
gpu_unai.PacketBuffer.U4)))
|
|
{
|
|
for (i = 0;; ) {
|
|
textured_sprite(cpu_cycles_sum, cpu_cycles);
|
|
if (++i >= simplified_count)
|
|
break;
|
|
memcpy(&gpu_unai.PacketBuffer.U4[0], &gpu_unai.PacketBuffer.U4[i * 4], 16);
|
|
}
|
|
break;
|
|
}
|
|
gpuSetCLUT(le32_to_u32(gpu_unai.PacketBuffer.U4[2]) >> 16);
|
|
u8 lighting = Lighting;
|
|
u8 gouraud = lighting ? (1<<7) : 0;
|
|
if (lighting) {
|
|
u32 xor_ = 0, rgb0 = le32_raw(gpu_unai.PacketBuffer.U4[0]);
|
|
for (i = 1; i < 4; i++)
|
|
xor_ |= rgb0 ^ le32_raw(gpu_unai.PacketBuffer.U4[i * 3]);
|
|
if ((xor_ & HTOLE32(0xf8f8f8)) == 0) {
|
|
gouraud = 0;
|
|
if (!dithering && !need_lighting(rgb0))
|
|
lighting = 0;
|
|
}
|
|
}
|
|
PP driver = gpuPolySpanDrivers[
|
|
dithering |
|
|
Blending_Mode | gpu_unai.TEXT_MODE |
|
|
gpu_unai.Masking | Blending | gouraud | lighting | gpu_unai.PixelMSB
|
|
];
|
|
if (gouraud)
|
|
gpuDrawPolyGT(packet, driver, true); // is_quad = true
|
|
else
|
|
gpuDrawPolyFT(packet, driver, true, POLYTYPE_GT);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_quad_base_gt());
|
|
} break;
|
|
|
|
case 0x40:
|
|
case 0x41:
|
|
case 0x42:
|
|
case 0x43: { // Monochrome line
|
|
// Shift index right by one, as untextured prims don't use lighting
|
|
u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
|
|
PSD driver = gpuPixelSpanDrivers[driver_idx];
|
|
gpuDrawLineF(packet, driver);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
|
|
} break;
|
|
|
|
case 0x48 ... 0x4F: { // Monochrome line strip
|
|
u32 num_vertexes = 1;
|
|
le32_t *list_position = &list[2];
|
|
|
|
// Shift index right by one, as untextured prims don't use lighting
|
|
u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
|
|
PSD driver = gpuPixelSpanDrivers[driver_idx];
|
|
gpuDrawLineF(packet, driver);
|
|
|
|
while(1)
|
|
{
|
|
gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
|
|
gpu_unai.PacketBuffer.U4[2] = *list_position++;
|
|
gpuDrawLineF(packet, driver);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
|
|
|
|
num_vertexes++;
|
|
if(list_position >= list_end) {
|
|
cmd = -1;
|
|
goto breakloop;
|
|
}
|
|
if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
|
|
break;
|
|
}
|
|
|
|
len += (num_vertexes - 2);
|
|
} break;
|
|
|
|
case 0x50:
|
|
case 0x51:
|
|
case 0x52:
|
|
case 0x53: { // Gouraud-shaded line
|
|
// Shift index right by one, as untextured prims don't use lighting
|
|
u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
|
|
// Index MSB selects Gouraud-shaded PixelSpanDriver:
|
|
driver_idx |= (1 << 5);
|
|
PSD driver = gpuPixelSpanDrivers[driver_idx];
|
|
gpuDrawLineG(packet, driver);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
|
|
} break;
|
|
|
|
case 0x58 ... 0x5F: { // Gouraud-shaded line strip
|
|
u32 num_vertexes = 1;
|
|
le32_t *list_position = &list[2];
|
|
|
|
// Shift index right by one, as untextured prims don't use lighting
|
|
u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
|
|
// Index MSB selects Gouraud-shaded PixelSpanDriver:
|
|
driver_idx |= (1 << 5);
|
|
PSD driver = gpuPixelSpanDrivers[driver_idx];
|
|
gpuDrawLineG(packet, driver);
|
|
|
|
while(1)
|
|
{
|
|
gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
|
|
gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
|
|
gpu_unai.PacketBuffer.U4[2] = *list_position++;
|
|
gpu_unai.PacketBuffer.U4[3] = *list_position++;
|
|
gpuDrawLineG(packet, driver);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_line(0));
|
|
|
|
num_vertexes++;
|
|
if(list_position >= list_end) {
|
|
cmd = -1;
|
|
goto breakloop;
|
|
}
|
|
if((le32_raw(*list_position) & HTOLE32(0xf000f000)) == HTOLE32(0x50005000))
|
|
break;
|
|
}
|
|
|
|
len += (num_vertexes - 2) * 2;
|
|
} break;
|
|
|
|
case 0x60:
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63: { // Monochrome rectangle (variable size)
|
|
PT driver = gpuTileDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
|
|
s32 w = 0, h = 0;
|
|
gpuDrawT(packet, driver, &w, &h);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
|
|
} break;
|
|
|
|
case 0x64:
|
|
case 0x65:
|
|
case 0x66:
|
|
case 0x67: // Textured rectangle (variable size)
|
|
textured_sprite(cpu_cycles_sum, cpu_cycles);
|
|
break;
|
|
|
|
case 0x68:
|
|
case 0x69:
|
|
case 0x6A:
|
|
case 0x6B: { // Monochrome rectangle (1x1 dot)
|
|
gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00010001);
|
|
PT driver = gpuTileDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
|
|
s32 w = 0, h = 0;
|
|
gpuDrawT(packet, driver, &w, &h);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(1, 1));
|
|
} break;
|
|
|
|
case 0x70:
|
|
case 0x71:
|
|
case 0x72:
|
|
case 0x73: { // Monochrome rectangle (8x8)
|
|
gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00080008);
|
|
PT driver = gpuTileDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
|
|
s32 w = 0, h = 0;
|
|
gpuDrawT(packet, driver, &w, &h);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
|
|
} break;
|
|
|
|
case 0x74:
|
|
case 0x75:
|
|
case 0x76:
|
|
case 0x77: { // Textured rectangle (8x8)
|
|
gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00080008);
|
|
textured_sprite(cpu_cycles_sum, cpu_cycles);
|
|
} break;
|
|
|
|
case 0x78:
|
|
case 0x79:
|
|
case 0x7A:
|
|
case 0x7B: { // Monochrome rectangle (16x16)
|
|
gpu_unai.PacketBuffer.U4[2] = u32_to_le32(0x00100010);
|
|
PT driver = gpuTileDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
|
|
s32 w = 0, h = 0;
|
|
gpuDrawT(packet, driver, &w, &h);
|
|
gput_sum(cpu_cycles_sum, cpu_cycles, gput_sprite(w, h));
|
|
} break;
|
|
|
|
case 0x7C:
|
|
case 0x7D:
|
|
case 0x7E:
|
|
case 0x7F: { // Textured rectangle (16x16)
|
|
gpu_unai.PacketBuffer.U4[3] = u32_to_le32(0x00100010);
|
|
textured_sprite(cpu_cycles_sum, cpu_cycles);
|
|
} break;
|
|
|
|
#ifdef TEST
|
|
case 0x80: // vid -> vid
|
|
gpuMoveImage(packet);
|
|
break;
|
|
|
|
case 0xA0: // sys -> vid
|
|
{
|
|
u32 load_width = list[2] & 0xffff;
|
|
u32 load_height = list[2] >> 16;
|
|
u32 load_size = load_width * load_height;
|
|
|
|
len += load_size / 2;
|
|
} break;
|
|
|
|
case 0xC0:
|
|
break;
|
|
#else
|
|
case 0x1F: // irq?
|
|
case 0x80 ... 0x9F: // vid -> vid
|
|
case 0xA0 ... 0xBF: // sys -> vid
|
|
case 0xC0 ... 0xDF: // vid -> sys
|
|
// Handled by gpulib
|
|
goto breakloop;
|
|
#endif
|
|
case 0xE1 ... 0xE6: { // Draw settings
|
|
u32 cmd_word = le32_to_u32(gpu_unai.PacketBuffer.U4[0]);
|
|
ex_regs[(cmd_word >> 24) & 7] = cmd_word;
|
|
gpuGP0Cmd_0xEx(gpu_unai, cmd_word);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
breakloop:
|
|
ex_regs[1] &= ~0x1ff;
|
|
ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
|
|
|
|
*cycles_sum_out += cpu_cycles_sum;
|
|
*cycles_last = cpu_cycles;
|
|
*last_cmd = cmd;
|
|
return list - list_start;
|
|
}
|
|
|
|
void renderer_sync_ecmds(u32 *ecmds_)
|
|
{
|
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
// the funcs below expect LE
|
|
uint32_t i, ecmds[8];
|
|
for (i = 1; i <= 6; i++)
|
|
ecmds[i] = HTOLE32(ecmds_[i]);
|
|
#else
|
|
uint32_t *ecmds = ecmds_;
|
|
#endif
|
|
if (!IS_OLD_RENDERER()) {
|
|
int dummy;
|
|
renderer_do_cmd_list(&ecmds[1], 6, ecmds, &dummy, &dummy, &dummy);
|
|
}
|
|
else
|
|
oldunai_renderer_sync_ecmds(ecmds);
|
|
}
|
|
|
|
void renderer_update_caches(int x, int y, int w, int h, int state_changed)
|
|
{
|
|
}
|
|
|
|
void renderer_flush_queues(void)
|
|
{
|
|
}
|
|
|
|
void renderer_set_interlace(int enable, int is_odd)
|
|
{
|
|
renderer_notify_screen_change(&gpu.screen);
|
|
}
|
|
|
|
#include "../../frontend/plugin_lib.h"
|
|
// Handle any gpulib settings applicable to gpu_unai:
|
|
void renderer_set_config(const struct rearmed_cbs *cbs)
|
|
{
|
|
gpu_unai.vram = (le16_t *)gpu.vram;
|
|
gpu_unai.config.old_renderer = cbs->gpu_unai.old_renderer;
|
|
gpu_unai.config.ilace_force = cbs->gpu_unai.ilace_force;
|
|
gpu_unai.config.lighting = cbs->gpu_unai.lighting;
|
|
gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
|
|
gpu_unai.config.blending = cbs->gpu_unai.blending;
|
|
gpu_unai.config.dithering = cbs->dithering != 0;
|
|
gpu_unai.config.force_dithering = cbs->dithering >> 1;
|
|
|
|
renderer_notify_screen_change(&gpu.screen);
|
|
oldunai_renderer_set_config(cbs);
|
|
}
|
|
|
|
// vim:shiftwidth=2:expandtab
|