From 2d22264db43b32e2f89fc0afca38ea64150230da Mon Sep 17 00:00:00 2001 From: moonpower Date: Tue, 7 Apr 2026 22:20:58 +0200 Subject: [PATCH] Add hardware debug tracing for GPU comparison --- Makefile | 6 + frontend/gpu_hw.c | 4 + psx/dev/gpu.c | 271 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 218 insertions(+), 63 deletions(-) diff --git a/Makefile b/Makefile index c98443b..0272351 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ SDL_LIBS_STATIC ?= $(shell $(SDL_CONFIG) --static-libs 2>/dev/null || $(SDL_CONF SDL_STATIC ?= 1 WASM_LDFLAGS ?= USE_HARDWARE ?= 0 +HW_DEBUG ?= 0 PLATFORM := $(shell uname -s) ifeq ($(WASM_TARGET),wasm) @@ -99,6 +100,11 @@ ifeq ($(USE_HARDWARE),1) BASE_CXXFLAGS += -DUSE_HARDWARE endif +ifeq ($(HW_DEBUG),1) + BASE_CFLAGS += -DHW_DEBUG + BASE_CXXFLAGS += -DHW_DEBUG +endif + ifeq ($(UWP_TARGET),1) BASE_CFLAGS += -DUWP_TARGET BASE_CXXFLAGS += -DUWP_TARGET diff --git a/frontend/gpu_hw.c b/frontend/gpu_hw.c index a232a60..d936d41 100644 --- a/frontend/gpu_hw.c +++ b/frontend/gpu_hw.c @@ -10,12 +10,16 @@ static int g_hw_trace_mode = -1; static bool hw_trace_enabled(void) { +#if !defined(HW_DEBUG) + return false; +#else if (g_hw_trace_mode < 0) { const char* env = getenv("ARMSX_HW_TRACE"); g_hw_trace_mode = (env && env[0] && env[0] != '0') ? 1 : 0; } return g_hw_trace_mode != 0; +#endif } static void hw_tracef(const char* fmt, ...) { diff --git a/psx/dev/gpu.c b/psx/dev/gpu.c index be2d326..8be50e3 100644 --- a/psx/dev/gpu.c +++ b/psx/dev/gpu.c @@ -3,10 +3,16 @@ #include #include -#include "gpu.h" -#include "../log.h" - -#define SE10(v) ((int16_t)((v) << 5) >> 5) +#include "gpu.h" +#include "../log.h" + +#define SE10(v) ((int16_t)((v) << 5) >> 5) + +#if defined(HW_DEBUG) +#define GPU_HW_DEBUG(...) psxe_diag_logf("gpu", __VA_ARGS__) +#else +#define GPU_HW_DEBUG(...) do { } while (0) +#endif int g_psx_gpu_dither_kernel[] = { -4, +0, -3, +1, @@ -652,16 +658,29 @@ void gpu_render_flat_line(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, uint32_t col plotLine(gpu, v0.x, v0.y, v1.x, v1.y, color); } -void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t color) { - /* Offset coordinates */ - v.x += gpu->off_x; - v.y += gpu->off_y; +void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint32_t color) { + /* Offset coordinates */ + v.x += gpu->off_x; + v.y += gpu->off_y; /* Calculate bounding box */ int xmin = max(v.x, gpu->draw_x1); int ymin = max(v.y, gpu->draw_y1); - int xmax = min(xmin + w, gpu->draw_x2); - int ymax = min(ymin + h, gpu->draw_y2); + int xmax = min(xmin + w, gpu->draw_x2); + int ymax = min(ymin + h, gpu->draw_y2); + + GPU_HW_DEBUG( + "soft-flat-rect color=%08x origin=(%d,%d) size=%ux%u bounds=(%d,%d)-(%d,%d)", + color, + v.x, + v.y, + w, + h, + xmin, + ymin, + xmax, + ymax + ); for (uint32_t y = ymin; y < ymax; y++) { for (uint32_t x = xmin; x < xmax; x++) { @@ -676,7 +695,7 @@ void gpu_render_flat_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t } } -void gpu_render_textured_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint16_t clutx, uint16_t cluty, uint32_t color) { +void gpu_render_textured_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint32_t h, uint16_t clutx, uint16_t cluty, uint32_t color) { vertex_t a = v; a.x += gpu->off_x; @@ -685,9 +704,26 @@ void gpu_render_textured_rectangle(psx_gpu_t* gpu, vertex_t v, uint32_t w, uint3 int xmin = max(a.x, gpu->draw_x1); int ymin = max(a.y, gpu->draw_y1); int xmax = min(xmin + w, gpu->draw_x2); - int ymax = min(ymin + h, gpu->draw_y2); - - uint32_t xc = 0, yc = 0; + int ymax = min(ymin + h, gpu->draw_y2); + + uint32_t xc = 0, yc = 0; + + GPU_HW_DEBUG( + "soft-textured-rect color=%08x origin=(%d,%d) size=%ux%u page=(%u,%u) clut=(%u,%u) bounds=(%d,%d)-(%d,%d)", + color, + v.x, + v.y, + w, + h, + gpu->texp_x, + gpu->texp_y, + clutx, + cluty, + xmin, + ymin, + xmax, + ymax + ); for (int y = ymin; y < ymax; y++) { for (int x = xmin; x < xmax; x++) { @@ -731,10 +767,25 @@ void gpu_render_flat_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t c.x += gpu->off_x; c.y += gpu->off_y; - int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); - int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); - int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); - int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); + int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); + int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); + int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + + GPU_HW_DEBUG( + "soft-flat-tri color=%08x bounds=(%d,%d)-(%d,%d) vertices=(%d,%d)-(%d,%d)-(%d,%d)", + color, + xmin, + ymin, + xmax, + ymax, + a.x, + a.y, + b.x, + b.y, + c.x, + c.y + ); for (int y = ymin; y < ymax; y++) { for (int x = xmin; x < xmax; x++) { @@ -770,12 +821,30 @@ void gpu_render_shaded_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex c.x += gpu->off_x; c.y += gpu->off_y; - int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); - int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); - int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); - int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); - - int area = EDGE(a, b, c); + int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); + int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); + int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); + int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + + int area = EDGE(a, b, c); + + GPU_HW_DEBUG( + "soft-shaded-tri bounds=(%d,%d)-(%d,%d) area=%d v0=(%d,%d c=%08x) v1=(%d,%d c=%08x) v2=(%d,%d c=%08x)", + xmin, + ymin, + xmax, + ymax, + area, + a.x, + a.y, + a.c, + b.x, + b.y, + b.c, + c.x, + c.y, + c.c + ); for (int y = ymin; y < ymax; y++) { for (int x = xmin; x < xmax; x++) { @@ -845,10 +914,39 @@ void gpu_render_textured_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vert int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); - int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); - int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); - - uint32_t area = EDGE(a, b, c); + int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); + int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + + uint32_t area = EDGE(a, b, c); + + GPU_HW_DEBUG( + "soft-textured-tri page=(%u,%u) clut=(%u,%u) depth=%d bounds=(%d,%d)-(%d,%d) area=%u v0=(%d,%d c=%08x tx=%u ty=%u) v1=(%d,%d c=%08x tx=%u ty=%u) v2=(%d,%d c=%08x tx=%u ty=%u)", + tpx, + tpy, + clutx, + cluty, + depth, + xmin, + ymin, + xmax, + ymax, + area, + a.x, + a.y, + a.c, + a.tx, + a.ty, + b.x, + b.y, + b.c, + b.tx, + b.ty, + c.x, + c.y, + c.c, + c.tx, + c.ty + ); for (int y = ymin; y < ymax; y++) { for (int x = xmin; x < xmax; x++) { @@ -885,14 +983,22 @@ void gpu_render_textured_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vert void gpu_rect(psx_gpu_t* gpu) { switch (gpu->state) { - case GPU_STATE_RECV_CMD: { - gpu->state = GPU_STATE_RECV_ARGS; - - int size = (gpu->buf[0] >> 27) & 3; - int textured = (gpu->buf[0] & 0x04000000) != 0; - - gpu->cmd_args_remaining = 1 + (size == RS_VARIABLE) + textured; - } break; + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + + int size = (gpu->buf[0] >> 27) & 3; + int textured = (gpu->buf[0] & 0x04000000) != 0; + + GPU_HW_DEBUG( + "rect-cmd raw=0x%08x attrib=0x%02x size=%d textured=%s", + gpu->buf[0], + gpu->buf[0] >> 24, + size, + textured ? "true" : "false" + ); + + gpu->cmd_args_remaining = 1 + (size == RS_VARIABLE) + textured; + } break; case GPU_STATE_RECV_ARGS: { if (!gpu->cmd_args_remaining) { @@ -915,10 +1021,25 @@ void gpu_rect(psx_gpu_t* gpu) { rect.width = gpu->buf[size_offset] & 0xffff; rect.height = gpu->buf[size_offset] >> 16; - if (textured && raw) - rect.v0.c = 0x808080; - - gpu_render_rect(gpu, rect); + if (textured && raw) + rect.v0.c = 0x808080; + + GPU_HW_DEBUG( + "rect-dispatch attrib=0x%02x v0=(%d,%d c=%08x tx=%u ty=%u) clut=0x%04x size=%ux%u raw=%s textured=%s", + rect.attrib, + rect.v0.x, + rect.v0.y, + rect.v0.c, + rect.v0.tx, + rect.v0.ty, + rect.clut, + rect.width, + rect.height, + raw ? "true" : "false", + textured ? "true" : "false" + ); + + gpu_render_rect(gpu, rect); gpu->state = GPU_STATE_RECV_CMD; } @@ -928,15 +1049,23 @@ void gpu_rect(psx_gpu_t* gpu) { void gpu_poly(psx_gpu_t* gpu) { switch (gpu->state) { - case GPU_STATE_RECV_CMD: { - gpu->state = GPU_STATE_RECV_ARGS; - - int shaded = (gpu->buf[0] & 0x10000000) != 0; - int quad = (gpu->buf[0] & 0x08000000) != 0; - int textured = (gpu->buf[0] & 0x04000000) != 0; - - int fields_per_vertex = 1 + shaded + textured; - int vertices = 3 + quad; + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + + int shaded = (gpu->buf[0] & 0x10000000) != 0; + int quad = (gpu->buf[0] & 0x08000000) != 0; + int textured = (gpu->buf[0] & 0x04000000) != 0; + + GPU_HW_DEBUG( + "poly-cmd raw=0x%08x shaded=%s quad=%s textured=%s", + gpu->buf[0], + shaded ? "true" : "false", + quad ? "true" : "false", + textured ? "true" : "false" + ); + + int fields_per_vertex = 1 + shaded + textured; + int vertices = 3 + quad; gpu->cmd_args_remaining = (fields_per_vertex * vertices) - shaded; } break; @@ -956,20 +1085,36 @@ void gpu_poly(psx_gpu_t* gpu) { int texc_offset = textured * (2 + shaded); int texp_offset = textured * (4 + shaded); - poly.clut = gpu->buf[2] >> 16; - poly.texp = gpu->buf[texp_offset] >> 16; - - // Undocumented behavior? - // Fixes Mortal Kombat II, Bubble Bobble, Driver 1 & 2 - if (textured) { - gpu->texp_x = (poly.texp & 0xf) << 6; - gpu->texp_y = (poly.texp & 0x10) << 4; - gpu->texp_d = (poly.texp >> 7) & 0x3; - gpu->gpustat &= 0xfffffe00; - gpu->gpustat |= poly.texp & 0x1ff; - } - - poly.v[0].c = gpu->buf[0+0*color_offset] & 0xffffff; + poly.clut = gpu->buf[2] >> 16; + poly.texp = gpu->buf[texp_offset] >> 16; + const bool poly_quad = (poly.attrib & PA_QUAD) != 0; + + // Undocumented behavior? + // Fixes Mortal Kombat II, Bubble Bobble, Driver 1 & 2 + if (textured) { + gpu->texp_x = (poly.texp & 0xf) << 6; + gpu->texp_y = (poly.texp & 0x10) << 4; + gpu->texp_d = (poly.texp >> 7) & 0x3; + gpu->gpustat &= 0xfffffe00; + gpu->gpustat |= poly.texp & 0x1ff; + } + + GPU_HW_DEBUG( + "poly-dispatch attrib=0x%02x shaded=%s quad=%s textured=%s clut=0x%04x texp=0x%04x " + "v0=(%d,%d c=%08x tx=%u ty=%u) v1=(%d,%d c=%08x tx=%u ty=%u) v2=(%d,%d c=%08x tx=%u ty=%u) v3=(%d,%d c=%08x tx=%u ty=%u)", + poly.attrib, + shaded ? "true" : "false", + poly_quad ? "true" : "false", + textured ? "true" : "false", + poly.clut, + poly.texp, + poly.v[0].x, poly.v[0].y, poly.v[0].c, poly.v[0].tx, poly.v[0].ty, + poly.v[1].x, poly.v[1].y, poly.v[1].c, poly.v[1].tx, poly.v[1].ty, + poly.v[2].x, poly.v[2].y, poly.v[2].c, poly.v[2].tx, poly.v[2].ty, + poly.v[3].x, poly.v[3].y, poly.v[3].c, poly.v[3].tx, poly.v[3].ty + ); + + poly.v[0].c = gpu->buf[0+0*color_offset] & 0xffffff; poly.v[1].c = gpu->buf[0+1*color_offset] & 0xffffff; poly.v[2].c = gpu->buf[0+2*color_offset] & 0xffffff; poly.v[3].c = gpu->buf[0+3*color_offset] & 0xffffff;