GS: let a player claim preload frame data and partial invalidation

Both are GameDB hardware fixes, so the database sets them per game and the
player's own value is discarded. The only way out was manual hack mode, which is
all or nothing: switching one fix off throws away every automatic fix that game
had. The pinning mechanism exists precisely for this, and already covers twelve
other fixes; these two were simply never added to it.

Append them to GSUserHackOverride after TextureOffsetY, so masks already written
to an INI keep meaning what they meant, and map the two GameDB fix ids onto them.
MaskUserHacks reset both unconditionally in the block below the keep() guards, so
move them up: a pinned value has to survive the mask as well as the database, and
only both together make the claim stick. MaskUserHacks(false) — the BIOS-boot
call that strips hacks for safety rather than preference — still resets them,
since the new guards take the same respect_claims parameter as the rest.

Verified on a Rogue Galaxy replay, which carries seven fixes including
disablePartialInvalidation. Pinning that one alone reports it skipped and still
applies the other six; pinning preload frame data behaves the same against a
temporary database row; pinning both skips both. The mask half shows up as
silence — with a fix pinned and its value on, the database finds the config
already agreeing and logs nothing, where the same run without the pin logs the
fix being applied over the wiped value.

No frontend exposes these yet. Pins are set by writing the override mask, and the
only frontend doing that today lists upscaling fixes only, which neither of these
is. AutoFlush and TextureInsideRt already sit in the enum with no frontend entry,
so the mapping is useful on its own and surfacing them is a separate decision per
frontend.
This commit is contained in:
Brian Degenhardt
2026-08-02 18:40:11 -07:00
parent 37d56169db
commit 7fee32e49f
3 changed files with 11 additions and 3 deletions
+3 -1
View File
@@ -551,8 +551,10 @@ enum class GSUserHackOverride : u8
AutoFlush,
TextureInsideRt,
// Appended rather than slotted in next to X, so a mask already written to an INI keeps
// meaning what it meant.
// meaning what it meant. Everything below follows the same rule: append only.
TextureOffsetY,
PreloadFrameData,
DisablePartialInvalidation,
MaxCount
};
+4
View File
@@ -510,6 +510,10 @@ static std::optional<GSUserHackOverride> UserHackOverrideForHWFix(GameDatabaseSc
return GSUserHackOverride::AutoFlush;
case GameDatabaseSchema::GSHWFixId::TextureInsideRT:
return GSUserHackOverride::TextureInsideRt;
case GameDatabaseSchema::GSHWFixId::PreloadFrameData:
return GSUserHackOverride::PreloadFrameData;
case GameDatabaseSchema::GSHWFixId::DisablePartialInvalidation:
return GSUserHackOverride::DisablePartialInvalidation;
default:
return std::nullopt;
}
+4 -2
View File
@@ -1257,12 +1257,14 @@ void Pcsx2Config::GSOptions::MaskUserHacks(bool respect_claims)
UserHacks_TCOffsetX = 0;
if (!keep(GSUserHackOverride::TextureOffsetY))
UserHacks_TCOffsetY = 0;
if (!keep(GSUserHackOverride::PreloadFrameData))
PreloadFrameWithGSData = false;
if (!keep(GSUserHackOverride::DisablePartialInvalidation))
UserHacks_DisablePartialInvalidation = false;
UserHacks_DisableSafeFeatures = false;
UserHacks_DisableRenderFixes = false;
GPUPaletteConversion = false;
PreloadFrameWithGSData = false;
UserHacks_DisablePartialInvalidation = false;
UserHacks_DisableDepthSupport = false;
UserHacks_CPUFBConversion = false;
UserHacks_ReadTCOnClose = false;