From e20f26963fbebd57209b8356ec6da0f27343e333 Mon Sep 17 00:00:00 2001 From: SaveEditors <119719171+SaveEditors@users.noreply.github.com> Date: Sat, 11 Jul 2026 05:50:13 -0400 Subject: [PATCH] [GPU] Initialize GPU registers to hardware reset defaults RegisterFile zeroes the whole register file at construction, but a real console comes up with non-zero values in several of the context registers. If a game reads one of those before writing it, it gets 0 under emulation and the real default on hardware. I read the reset values off a retail console (read-only) and checked them against the AMD R6xx register reference and the r600g defaults in Mesa, which set the same registers to the same values at context init. Where the hardware read matches the driver default it's a genuine power-on default, not leftover runtime state. Left the tessellation levels out on purpose: they reset to 1.0f too, but the backends do register + 1.0f, so seeding them here would change the effective reset factor. That needs its own change. --- src/xenia/gpu/register_file.cc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/xenia/gpu/register_file.cc b/src/xenia/gpu/register_file.cc index c10b433dc..c697852e4 100644 --- a/src/xenia/gpu/register_file.cc +++ b/src/xenia/gpu/register_file.cc @@ -15,7 +15,38 @@ namespace xe { namespace gpu { -RegisterFile::RegisterFile() { std::memset(values, 0, sizeof(values)); } +RegisterFile::RegisterFile() { + std::memset(values, 0, sizeof(values)); + + // Several context registers power up with non-zero values on real Xenos + // hardware, so a title that reads one of them before writing it would + // otherwise observe 0. These are the hardware reset defaults, corroborated by + // the AMD R6xx/R7xx 3D register reference and the Mesa r600g driver, which + // programs the same registers to the same values at context init. + values[XE_GPU_REG_VGT_MAX_VTX_INDX] = 0x0000FFFF; + values[XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX] = 0x0000FFFF; + values[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR] = 0x20002000; // 8192 x 8192 + values[XE_GPU_REG_RB_STENCILREFMASK_BF] = 0x00FFFF00; + values[XE_GPU_REG_PA_SU_POINT_SIZE] = 0x00080008; + values[XE_GPU_REG_PA_SU_POINT_MINMAX] = 0x04000010; + values[XE_GPU_REG_PA_SU_LINE_CNTL] = 0x00000008; + values[XE_GPU_REG_PA_SC_LINE_CNTL] = 0x00000400; + values[XE_GPU_REG_VGT_HOS_REUSE_DEPTH] = 0x0000000E; + values[XE_GPU_REG_VGT_VERTEX_REUSE_BLOCK_CNTL] = 0x0000000E; + values[XE_GPU_REG_VGT_OUT_DEALLOC_CNTL] = 0x00000010; + // Guard-band clip/discard adjust (2.0 clip, 1.0 discard); hardwired on + // hardware. + values[XE_GPU_REG_PA_CL_GB_VERT_CLIP_ADJ] = 0x40000000; // 2.0f + values[XE_GPU_REG_PA_CL_GB_VERT_DISC_ADJ] = 0x3F800000; // 1.0f + values[XE_GPU_REG_PA_CL_GB_HORZ_CLIP_ADJ] = 0x40000000; // 2.0f + values[XE_GPU_REG_PA_CL_GB_HORZ_DISC_ADJ] = 0x3F800000; // 1.0f + values[XE_GPU_REG_PA_SC_AA_MASK] = 0x0000FFFF; + // Tessellation levels also reset to 1.0f on hardware, but the backends apply + // the effective factor as (register + 1.0f), so initializing them here would + // change the effective reset factor; left out for separate review. + // values[XE_GPU_REG_VGT_HOS_MAX_TESS_LEVEL] = 0x3F800000; // 1.0f + // values[XE_GPU_REG_VGT_HOS_MIN_TESS_LEVEL] = 0x3F800000; // 1.0f +} constexpr unsigned int GetHighestRegisterNumber() { uint32_t highest = 0; #define XE_GPU_REGISTER(index, type, name) \