mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
Avoid inactive GPU and BIOS diagnostic recording
This commit is contained in:
+11
-1
@@ -263,6 +263,12 @@ if(BUILD_TESTING)
|
||||
set(PSX_GL_READBACK_COMPILER_BIN "${_gl_test_default_bin}" CACHE PATH "GCC/MinGW bin for GL fixture")
|
||||
find_package(Python3 QUIET COMPONENTS Interpreter)
|
||||
if(Python3_Interpreter_FOUND)
|
||||
# fixture_link uses GNU nm/linker diagnostics for its unrelated seams.
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
add_test(NAME bios_hle_recording_test COMMAND "${Python3_EXECUTABLE}"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/test_bios_hle_recording.py"
|
||||
--cc "${CMAKE_C_COMPILER}")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
add_test(NAME menu_video_snapshot_test COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_menu_video_snapshot.py
|
||||
@@ -1131,8 +1137,10 @@ if(BUILD_TESTING)
|
||||
src/ws_ui_group.c
|
||||
src/psx_video_timing.c
|
||||
src/gpu_timeline.c)
|
||||
add_executable(gpu_census_test tests/test_gpu_census.c
|
||||
src/psx_video_timing.c src/gpu_timeline.c)
|
||||
foreach(_anchor_test ws_view_anchor ws_view_anchor_gpu native_wide_projection
|
||||
gpu_render_pass_provenance)
|
||||
gpu_render_pass_provenance gpu_census)
|
||||
target_include_directories(${_anchor_test}_test PRIVATE include src)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${_anchor_test}_test PRIVATE -ffunction-sections -fdata-sections)
|
||||
@@ -1148,6 +1156,8 @@ if(BUILD_TESTING)
|
||||
add_test(NAME ws_view_anchor_gpu_test COMMAND ws_view_anchor_gpu_test)
|
||||
add_test(NAME native_wide_projection_test COMMAND native_wide_projection_test)
|
||||
add_test(NAME gpu_render_pass_provenance_test COMMAND gpu_render_pass_provenance_test)
|
||||
add_test(NAME gpu_census_test COMMAND gpu_census_test
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/gpu-census-test.csv")
|
||||
|
||||
add_executable(ws_repeat_rect_test tests/test_ws_repeat_rect.c)
|
||||
target_include_directories(ws_repeat_rect_test PRIVATE include)
|
||||
|
||||
@@ -110,8 +110,10 @@ typedef struct PsxHleCallEntry {
|
||||
|
||||
#define PSX_HLE_RING_CAP 16384 /* power of two */
|
||||
|
||||
/* Snapshot accessors: seq is the total number of records ever written; entry
|
||||
* i (seq-CAP .. seq-1 valid window) returns the ring slot for that sequence. */
|
||||
/* Debug builds only; PSX_NO_DEBUG_TOOLS returns an empty sequence/NULL and
|
||||
* performs no diagnostic guest reads. Snapshot accessors: seq is the total
|
||||
* number of records ever written; entry i (seq-CAP .. seq-1 valid window)
|
||||
* returns the ring slot for that sequence. */
|
||||
uint64_t psx_hle_ring_seq(void);
|
||||
const PsxHleCallEntry* psx_hle_ring_entry(uint64_t seq_index);
|
||||
|
||||
|
||||
@@ -739,7 +739,8 @@ void gpu_ws_set_margin_override(int v);
|
||||
* through the tagged sprite funnel). */
|
||||
void gpu_ws_set_nw_hud_tag_rects(int on);
|
||||
|
||||
/* Always-on draw-census ring: every drawn primitive records frame / source
|
||||
/* Explicit diagnostic draw-census ring: arm before the capture window.
|
||||
* Every drawn primitive records frame / source
|
||||
* addr / camera / first-vertex screen pos, so object spawn/despawn and edge
|
||||
* culls are observable in data. Dump frames [f0,f1] to a CSV file. */
|
||||
int gpu_ws_census_dump(uint32_t f0, uint32_t f1, const char *path);
|
||||
|
||||
+17
-1
@@ -87,8 +87,9 @@ static int s_shell_skipped = 0; /* boot skip already fired */
|
||||
* delivery gives the callback, reused here so the dispatch return contract
|
||||
* matches. 0 = unknown for this BIOS: callback delivery stays LLE. */
|
||||
|
||||
/* ── always-on ring ──────────────────────────────────────────────────────── */
|
||||
/* ── debug call-history ring ─────────────────────────────────────────────── */
|
||||
|
||||
#ifndef PSX_NO_DEBUG_TOOLS
|
||||
static PsxHleCallEntry s_ring[PSX_HLE_RING_CAP];
|
||||
static uint64_t s_ring_seq = 0;
|
||||
|
||||
@@ -153,6 +154,21 @@ const PsxHleCallEntry* psx_hle_ring_entry(uint64_t seq_index)
|
||||
if (s_ring_seq - seq_index > PSX_HLE_RING_CAP) return NULL; /* evicted */
|
||||
return &s_ring[seq_index & (PSX_HLE_RING_CAP - 1)];
|
||||
}
|
||||
#else
|
||||
/* The debug dump is the ring's only consumer. Keep functional BIOS handling
|
||||
* independent of forensic reads, repeat scans and storage in production. */
|
||||
static inline void hle_record(uint32_t vector, uint32_t fn, const CPUState* cpu,
|
||||
uint32_t v0, uint8_t route)
|
||||
{
|
||||
(void)vector; (void)fn; (void)cpu; (void)v0; (void)route;
|
||||
}
|
||||
uint64_t psx_hle_ring_seq(void) { return 0; }
|
||||
const PsxHleCallEntry* psx_hle_ring_entry(uint64_t seq_index)
|
||||
{
|
||||
(void)seq_index;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ── B0 event services (SCPH1001 kernel semantics, on real guest EvCBs) ──── */
|
||||
|
||||
|
||||
+9
-6
@@ -7299,7 +7299,7 @@ void gpu_set_gp0_source(uint32_t addr) {
|
||||
gp0_next_source_addr = addr;
|
||||
}
|
||||
|
||||
/* ---- Draw census ring (ALWAYS-ON) -----------------------------------------
|
||||
/* ---- Draw census ring (explicit diagnostic capture) -----------------------
|
||||
* Every drawn primitive (GP0 opcode 0x20-0x7F) records: frame, the prim's DMA
|
||||
* source address, the live camera (scratchpad camX/camY), and the prim's first
|
||||
* vertex in DRAWING space (pre draw_offset). Purpose: see object spawn/despawn
|
||||
@@ -7308,7 +7308,8 @@ void gpu_set_gp0_source(uint32_t addr) {
|
||||
* last recorded screen-x shows how far on-screen it still was — i.e. the
|
||||
* effective (4:3-sized) despawn margin, which the 16:9 view exceeds. A prim
|
||||
* present in the census but absent on screen would instead indict the renderer
|
||||
* gate. Query via TCP `ws_census` → CSV file (large dumps mustn't ride TCP). */
|
||||
* gate. Arm via TCP `ws_census action=on`, then dump to CSV (large dumps
|
||||
* mustn't ride TCP). No gameplay consumer depends on this forensic ring. */
|
||||
#define WS_CENSUS_CAP (1u << 21) /* 2,097,152 entries * 24B = 48 MiB */
|
||||
typedef struct {
|
||||
uint32_t frame;
|
||||
@@ -7322,7 +7323,7 @@ typedef struct {
|
||||
} WsCensusEntry;
|
||||
static WsCensusEntry *ws_census = NULL;
|
||||
static uint64_t ws_census_seq = 0;
|
||||
static int ws_census_on = 1; /* always-on; toggle via ws_census */
|
||||
static int ws_census_on = 0; /* arm only for a diagnostic window */
|
||||
extern uint16_t psx_read_half(uint32_t addr);
|
||||
|
||||
/* Screen-X extent (raw vertex coords = SX, pre-draw_offset) across a prim's
|
||||
@@ -7496,9 +7497,11 @@ static void gp0_execute_command(void) {
|
||||
|
||||
/* Draw-census: capture every drawing primitive's first vertex + camera. */
|
||||
if (opcode >= 0x20 && opcode <= 0x7F) {
|
||||
int32_t cvx, cvy;
|
||||
parse_vertex(gp0_cmd_buf[1], &cvx, &cvy);
|
||||
ws_census_record(opcode, cvx, cvy);
|
||||
if (ws_census_on) {
|
||||
int32_t cvx, cvy;
|
||||
parse_vertex(gp0_cmd_buf[1], &cvx, &cvy);
|
||||
ws_census_record(opcode, cvx, cvy);
|
||||
}
|
||||
ws_note_overhang(opcode); /* 2D-only-scene classifier world signal */
|
||||
ws_note_backdrop(opcode); /* ...and its finite-backdrop veto */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include "bios_hle.h"
|
||||
#include "cpu_state.h"
|
||||
#include "psx_bios_image.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
PsxBiosImageInfo psx_bios_image = {.shell_entry_phys=0x30000u};
|
||||
uint64_t psx_cycle_count=100;
|
||||
uint64_t psx_get_cycle_count(void) { return psx_cycle_count; }
|
||||
static unsigned reads;
|
||||
static uint32_t read_word(uint32_t address) {
|
||||
assert(address==0xA0000108u);
|
||||
++reads;
|
||||
return 0; /* no running PCB: only the first forensic attribution read */
|
||||
}
|
||||
int psx_get_in_exception(void) { return 0; }
|
||||
int fntrace_is_game_started(void) { return 1; }
|
||||
|
||||
int main(void) {
|
||||
CPUState cpu={0};
|
||||
cpu.read_word=read_word;
|
||||
cpu.gpr[9]=0x17u; cpu.gpr[31]=0x80012340u;
|
||||
CPUState before=cpu;
|
||||
psx_bios_hle_configure(0,1);
|
||||
assert(g_psx_bios_hle_hook);
|
||||
assert(!g_psx_bios_hle_hook(&cpu,0xA0u));
|
||||
assert(!g_psx_bios_hle_hook(&cpu,0xA0u));
|
||||
assert(!memcmp(&before,&cpu,sizeof(cpu)) && psx_cycle_count==100);
|
||||
#if EXPECT_RECORDING
|
||||
assert(reads==2 && psx_hle_ring_seq()==1);
|
||||
const PsxHleCallEntry *entry=psx_hle_ring_entry(0);
|
||||
assert(entry && entry->repeat==2 && entry->route==PSX_HLE_ROUTE_LLE);
|
||||
#else
|
||||
assert(!reads && !psx_hle_ring_seq() && !psx_hle_ring_entry(0));
|
||||
#endif
|
||||
psx_bios_hle_configure(0,0);
|
||||
assert(!g_psx_bios_hle_hook);
|
||||
puts("PASS BIOS recording: caller state/time preserved; diagnostic reads only in debug builds");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
"""Actual BIOS dispatch keeps diagnostic guest reads out of production."""
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
from fixture_link import build_and_run
|
||||
|
||||
if __name__=='__main__':
|
||||
parser=argparse.ArgumentParser();parser.add_argument('--cc',default='gcc')
|
||||
args=parser.parse_args();here=Path(__file__).resolve().parent
|
||||
for recording in (0,1):
|
||||
with tempfile.TemporaryDirectory(prefix='bios-recording-') as directory:
|
||||
work=Path(directory)
|
||||
(work/'fixture.c').write_text(f'#define EXPECT_RECORDING {recording}\n'+
|
||||
(here/'test_bios_hle_recording.c').read_text())
|
||||
build_and_run(args.cc,work,here.parent,'-O2',work,['bios_hle.c'],'fixture.c',
|
||||
defines=[] if recording else ['PSX_NO_DEBUG_TOOLS=1'])
|
||||
print('PASS: production dispatch records no forensic guest reads; debug repeats remain available')
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Exercise default-off and explicitly armed capture through real GP0 dispatch. */
|
||||
#define main gpu_dot_fixture_main
|
||||
#include "test_gpu_textured_dot_nw_shift_exec.c"
|
||||
#undef main
|
||||
|
||||
static void draw_dot(void) {
|
||||
set_dot_packet(0x10004u, 12, 34);
|
||||
gp0_execute_command();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
assert(argc == 2);
|
||||
reset_gpu_state_for_test();
|
||||
|
||||
draw_dot();
|
||||
assert(last_textured_rect.calls == 1);
|
||||
assert(last_textured_rect.x == 12 && last_textured_rect.y == 34);
|
||||
assert(gpu_ws_census_seq() == 0 && ws_census == NULL);
|
||||
|
||||
gpu_ws_census_set(1);
|
||||
draw_dot();
|
||||
assert(last_textured_rect.calls == 2 && gpu_ws_census_seq() == 1);
|
||||
assert(gpu_ws_census_dump(100, 100, argv[1]) == 1);
|
||||
FILE *csv = fopen(argv[1], "r");
|
||||
assert(csv);
|
||||
char line[256];
|
||||
assert(fgets(line, sizeof(line), csv));
|
||||
assert(strncmp(line, "frame,src_addr,", 15) == 0);
|
||||
assert(fgets(line, sizeof(line), csv));
|
||||
assert(strncmp(line, "100,0x00010004,", 15) == 0);
|
||||
assert(strstr(line, ",12,34,12,12,0,0x6C,0"));
|
||||
assert(fgets(line, sizeof(line), csv) == NULL);
|
||||
assert(fclose(csv) == 0);
|
||||
assert(remove(argv[1]) == 0);
|
||||
|
||||
gpu_ws_census_set(0);
|
||||
draw_dot();
|
||||
assert(last_textured_rect.calls == 3 && gpu_ws_census_seq() == 1);
|
||||
free(ws_census);
|
||||
ws_census = NULL;
|
||||
puts("PASS: drawing works without census allocation; armed capture exports and stops");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user