mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Cache display geometry within each GPU execution context
This commit is contained in:
@@ -2260,3 +2260,20 @@ common emulation/context regression work while retaining the bar, or explicitly
|
||||
revise load/bar. No further code changes or pushes; all code is committed.
|
||||
Receipts: R4 local brief5-worker-idle and brief5-loaded-profile-diff (including
|
||||
unprofiled-prefix-proof.json). Cadence, title ctest and both pushes remain pending.
|
||||
|
||||
2026-10-21 BRIEF-5 scope resumed: Claude authorizes the common-cost comparison.
|
||||
An exact da09fac/8130e6fd archive build with production options, loaded setting 0,
|
||||
frames 3450..4350, has 60.96% sampled source CPU and unprofiled-prefix p99 67.4%
|
||||
(32 windows >=60), versus current 59.39% / 65.9% (18). Native execution is
|
||||
positive with zero interpreted calls/misses; the historical 58.7% is not
|
||||
reproduced. Reuse the existing current profile rather than repeat it. The initial
|
||||
archive profile used netplay OFF and a wrong stop variable; exclude it.
|
||||
The paired profile shows gpu_get_display_info at 1.003% current wall samples
|
||||
versus zero separate old leaf samples. Cache the derived display geometry per
|
||||
execution context/reader until GP1, reset or snapshot restore changes registers;
|
||||
private invalidation does not touch live readers. The production GPU fixture
|
||||
checks all resolution modes, repeated queries, private/source separation,
|
||||
recapture, checkpoint and savestate restore, reset and power-on PAL. It passes.
|
||||
Continue failing loaded gate, cadence, title ctest and both pushes; quiet remains
|
||||
passed. No acceptance or current blocker. Receipts: R4 local
|
||||
brief5-stage2-regression/valid-* (first run explicitly INVALID).
|
||||
|
||||
+38
-1
@@ -50,6 +50,7 @@
|
||||
#include "ws_screen_mask.h"
|
||||
#include "ws_radial_screen_mask.h"
|
||||
#include <stdint.h>
|
||||
#include <stdatomic.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
@@ -69,14 +70,30 @@ extern uint32_t psx_read_word(uint32_t addr);
|
||||
/* ---- VRAM ---- */
|
||||
/* Default execution and render-thread queries keep the live objects. Only
|
||||
* a bound replay thread selects private regions; no live state is swapped. */
|
||||
typedef struct GpuDisplayCache {
|
||||
uint64_t epoch;
|
||||
GpuDisplayInfo info;
|
||||
} GpuDisplayCache;
|
||||
struct GpuExecutionSnapshot {
|
||||
uint64_t frame;
|
||||
int recent_mdec;
|
||||
void *slots[323];
|
||||
void *storage;
|
||||
int ready;
|
||||
uint64_t display_epoch;
|
||||
GpuDisplayCache display_cache;
|
||||
};
|
||||
static PSX_THREAD_LOCAL GpuExecutionSnapshot *s_gpu_execution;
|
||||
/* Display registers change at GP1/state boundaries, not per primitive. Keep
|
||||
* the derived view local to its reader; worker invalidation never touches the
|
||||
* source epoch. The epoch also invalidates other live readers' local caches. */
|
||||
static _Atomic uint64_t s_display_epoch = 1;
|
||||
static PSX_THREAD_LOCAL GpuDisplayCache t_display_cache;
|
||||
static void gpu_display_state_changed(void) {
|
||||
if (s_gpu_execution) ++s_gpu_execution->display_epoch;
|
||||
else atomic_fetch_add_explicit(&s_display_epoch, 1, memory_order_release);
|
||||
}
|
||||
|
||||
static uint16_t vram[1024 * 512];
|
||||
typedef uint16_t GpuContextType_vram[524288];
|
||||
static inline GpuContextType_vram *gpu_context_vram(void) {
|
||||
@@ -5265,6 +5282,7 @@ static inline GpuContextType_g_pollhack_vblank_count *gpu_context_g_pollhack_vbl
|
||||
/* ---- Initialization ---- */
|
||||
|
||||
static void gpu_reset_state(int clear_vram) {
|
||||
gpu_display_state_changed();
|
||||
ws_reset_scene_history();
|
||||
if (clear_vram) {
|
||||
memset((*gpu_context_vram()), 0, sizeof((*gpu_context_vram())));
|
||||
@@ -5365,12 +5383,15 @@ void gpu_init(void) {
|
||||
gpu_reset_state(1);
|
||||
(*gpu_context_video_mode()) = (*gpu_context_s_power_on_video_mode());
|
||||
(void)psx_video_timing_set_pal((int)(*gpu_context_video_mode()));
|
||||
gpu_display_state_changed();
|
||||
}
|
||||
|
||||
void gpu_set_power_on_video_mode(int pal) {
|
||||
gpu_display_state_changed();
|
||||
(*gpu_context_s_power_on_video_mode()) = pal ? 1u : 0u;
|
||||
(*gpu_context_video_mode()) = (*gpu_context_s_power_on_video_mode());
|
||||
(void)psx_video_timing_set_pal((int)(*gpu_context_video_mode()));
|
||||
gpu_display_state_changed();
|
||||
}
|
||||
|
||||
/* ---- GPUSTAT read (0x1F801814) ---- */
|
||||
@@ -5932,7 +5953,7 @@ int gpu_display_is_depth24(void) {
|
||||
return (int)((*gpu_context_display_depth()) & 1u);
|
||||
}
|
||||
|
||||
void gpu_get_display_info(GpuDisplayInfo* out) {
|
||||
static void gpu_build_display_info(GpuDisplayInfo* out) {
|
||||
out->display_x = (*gpu_context_display_area_x());
|
||||
out->display_y = (*gpu_context_display_area_y());
|
||||
out->depth24 = (int)((*gpu_context_display_depth()) & 1u);
|
||||
@@ -6012,6 +6033,18 @@ void gpu_get_display_info(GpuDisplayInfo* out) {
|
||||
if ((*gpu_context_vres())) out->screen_offset_y *= 2;
|
||||
}
|
||||
|
||||
void gpu_get_display_info(GpuDisplayInfo* out) {
|
||||
GpuExecutionSnapshot *execution = s_gpu_execution;
|
||||
uint64_t epoch = execution ? execution->display_epoch :
|
||||
atomic_load_explicit(&s_display_epoch, memory_order_acquire);
|
||||
GpuDisplayCache *cache = execution ? &execution->display_cache : &t_display_cache;
|
||||
if (cache->epoch != epoch) {
|
||||
gpu_build_display_info(&cache->info);
|
||||
cache->epoch = epoch;
|
||||
}
|
||||
*out = cache->info;
|
||||
}
|
||||
|
||||
/* Debug accessors for GP1 display-range / mode (TCP gpu_state). */
|
||||
void gpu_get_crtc_debug(uint32_t *x1, uint32_t *x2, uint32_t *y1, uint32_t *y2,
|
||||
uint32_t *hres1_out, uint32_t *hres2_out) {
|
||||
@@ -9421,6 +9454,7 @@ static inline GpuContextType_gpu_local_gpu_write_gp1_reason *gpu_context_gpu_loc
|
||||
return s_gpu_execution ? (GpuContextType_gpu_local_gpu_write_gp1_reason *)s_gpu_execution->slots[322] : &gpu_local_gpu_write_gp1_reason;
|
||||
}
|
||||
void gpu_write_gp1(uint32_t val) {
|
||||
gpu_display_state_changed();
|
||||
uint32_t cmd = (val >> 24) & 0x3F;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -9445,6 +9479,7 @@ void gpu_write_gp1(uint32_t val) {
|
||||
psx_fatal_halt((*gpu_context_gpu_local_gpu_write_gp1_reason()));
|
||||
}
|
||||
}
|
||||
gpu_display_state_changed();
|
||||
}
|
||||
|
||||
/* ---- boot snapshot: complete GPU register state (see boot_state.h) ---- */
|
||||
@@ -9526,6 +9561,7 @@ static int gpu_snap_emit(PstW *w) {
|
||||
return 1;
|
||||
}
|
||||
static int gpu_snap_parse(PstR *r) {
|
||||
gpu_display_state_changed();
|
||||
uint32_t u; int32_t i; uint16_t h;
|
||||
#define RU(f) do { if (!pst_r_u32(r, &u)) return 0; (f) = u; } while (0)
|
||||
#define RI(f) do { if (!pst_r_i32(r, &i)) return 0; (f) = i; } while (0)
|
||||
@@ -10225,6 +10261,7 @@ int gpu_execution_snapshot_capture(GpuExecutionSnapshot *snapshot) {
|
||||
ColorLut **lut = (ColorLut **)gpu_execution_region(snapshot, &s_screen_lut);
|
||||
if (*lut) color_lut_destroy(*lut);
|
||||
snapshot->ready = 0;
|
||||
++snapshot->display_epoch;
|
||||
snapshot->frame = s_frame_count;
|
||||
snapshot->recent_mdec = mdec_recently_active(WS_FMV_HYSTERESIS);
|
||||
for (size_t i = 0; i < sizeof s_gpu_execution_regions / sizeof s_gpu_execution_regions[0]; ++i) {
|
||||
|
||||
@@ -33,5 +33,65 @@ int main(void) {
|
||||
gpu_pass_checkpoint_restore();
|
||||
assert(gpu_execution_snapshot_capture(image));
|
||||
gpu_execution_snapshot_destroy(image);
|
||||
/* Derived display caches follow register writes, state restore and private
|
||||
* snapshot ownership. Compare each cached result with the uncached view. */
|
||||
gpu_init();
|
||||
GpuDisplayInfo actual, display_expected, source;
|
||||
const uint32_t modes[] = {0, 1, 2, 3, 0x40, 0x0C, 0x18};
|
||||
for (unsigned i = 0; i < sizeof modes / sizeof modes[0]; ++i) {
|
||||
gpu_write_gp1(0x08000000u | modes[i]);
|
||||
gpu_write_gp1(0x0500180Cu);
|
||||
gpu_write_gp1(0x060C0200u);
|
||||
gpu_write_gp1(0x07040010u);
|
||||
gpu_build_display_info(&display_expected);
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &display_expected, sizeof actual));
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &display_expected, sizeof actual));
|
||||
}
|
||||
source = actual;
|
||||
image = gpu_execution_snapshot_create();
|
||||
assert(image && gpu_execution_snapshot_capture(image));
|
||||
assert(gpu_execution_snapshot_bind(image));
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &source, sizeof actual));
|
||||
gpu_write_gp1(0x08000003u);
|
||||
gpu_write_gp1(0x05000029u);
|
||||
gpu_build_display_info(&display_expected);
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &display_expected, sizeof actual));
|
||||
assert(actual.display_x == 41);
|
||||
assert(gpu_pass_checkpoint_save());
|
||||
gpu_write_gp1(0);
|
||||
gpu_get_display_info(&actual);
|
||||
assert(actual.display_x == 0);
|
||||
gpu_pass_checkpoint_restore();
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &display_expected, sizeof actual));
|
||||
gpu_execution_snapshot_unbind();
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &source, sizeof actual));
|
||||
gpu_write_gp1(0x08000001u);
|
||||
assert(gpu_execution_snapshot_capture(image));
|
||||
gpu_get_display_info(&source);
|
||||
assert(gpu_execution_snapshot_bind(image));
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &source, sizeof actual));
|
||||
gpu_execution_snapshot_unbind();
|
||||
gpu_execution_snapshot_destroy(image);
|
||||
uint32_t bytes = gpu_snapshot_bytes();
|
||||
uint8_t *saved = malloc(bytes);
|
||||
assert(saved);
|
||||
gpu_snapshot_write(saved);
|
||||
gpu_write_gp1(0);
|
||||
gpu_get_display_info(&actual);
|
||||
assert(gpu_snapshot_read(saved, bytes));
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &source, sizeof actual));
|
||||
free(saved);
|
||||
gpu_set_power_on_video_mode(1);
|
||||
gpu_build_display_info(&display_expected);
|
||||
gpu_get_display_info(&actual);
|
||||
assert(!memcmp(&actual, &display_expected, sizeof actual));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user