[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.
This commit is contained in:
SaveEditors
2026-07-11 05:50:13 -04:00
committed by Radosław Gliński
parent bad346717a
commit e20f26963f

View File

@@ -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) \