diff --git a/pcsx2-qt/Settings/GraphicsHardwareFixesSettingsTab.ui b/pcsx2-qt/Settings/GraphicsHardwareFixesSettingsTab.ui
index d59ac84e2b..8b3ea6f372 100644
--- a/pcsx2-qt/Settings/GraphicsHardwareFixesSettingsTab.ui
+++ b/pcsx2-qt/Settings/GraphicsHardwareFixesSettingsTab.ui
@@ -14,8 +14,31 @@
- -
-
+
-
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 0
+
+
+
+
+ -
+
+
+ Skip Draw Range:
+
+
+ skipDrawStart
+
+
+
+ -
+
-
Disabled (Default)
@@ -23,12 +46,12 @@
-
- Enabled (Sprites Only)
+ Inside Target
-
- Enabled (All Primitives)
+ Merge Targets
@@ -43,41 +66,6 @@
- -
-
-
- Skip Draw Range:
-
-
- skipDrawStart
-
-
-
- -
-
-
- 0 (Disabled)
-
-
- 0
-
-
-
-
- 0 (Disabled)
-
-
- -
-
- 1 (Normal)
-
-
- -
-
- 2 (Aggressive)
-
-
-
-
-
-
@@ -160,8 +148,36 @@
- -
-
+
-
+
+
+ Auto Flush:
+
+
+ hwAutoFlush
+
+
+
+ -
+
+
-
+
+
+ 10000
+
+
+
+ -
+
+
+ 10000
+
+
+
+
+
+ -
+
-
Disabled (Default)
@@ -169,12 +185,57 @@
-
- Inside Target
+ Enabled (Exact Match)
-
- Merge Targets
+ Enabled (Check Inside Target)
+
+
+
+
+ -
+
+
+ CPU Sprite Render Size:
+
+
+ cpuSpriteRenderBW
+
+
+
+ -
+
+
+ GPU Target CLUT:
+
+
+ gpuTargetCLUTMode
+
+
+
+ -
+
+
+ 0 (Disabled)
+
+
+ 0
+
+
-
+
+ 0 (Disabled)
+
+
+ -
+
+ 1 (Normal)
+
+
+ -
+
+ 2 (Aggressive)
@@ -189,7 +250,26 @@
- -
+
-
+
+
-
+
+ Disabled (Default)
+
+
+ -
+
+ Enabled (Sprites Only)
+
+
+ -
+
+ Enabled (All Primitives)
+
+
+
+
+ -
-
@@ -256,28 +336,8 @@
- -
-
-
- Auto Flush:
-
-
- hwAutoFlush
-
-
-
- -
-
-
- GPU Target CLUT:
-
-
- gpuTargetCLUTMode
-
-
-
- -
-
+
-
+
-
Disabled (Default)
@@ -285,57 +345,23 @@
-
- Enabled (Exact Match)
+ Prioritize Upper
-
- Enabled (Check Inside Target)
+ Prioritize Lower
- -
-
+
-
+
- CPU Sprite Render Size:
-
-
- cpuSpriteRenderBW
+ Limit 24 Bit Depth
- -
-
-
-
-
-
- 10000
-
-
-
- -
-
-
- 10000
-
-
-
-
-
- -
-
-
- Qt::Orientation::Vertical
-
-
-
- 20
- 0
-
-
-
-
diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
index cd99c8dcf8..83a7921f9e 100644
--- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
+++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp
@@ -147,6 +147,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
sif, m_fixes.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_fixes.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", static_cast(GSTextureInRtMode::Disabled));
+ SettingWidgetBinder::BindWidgetToIntSetting(
+ sif, m_fixes.limit24BitDepth, "EmuCore/GS", "UserHacks_Limit24BitDepth", static_cast(GSLimit24BitDepth::Disabled));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
@@ -624,6 +626,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_fixes.textureInsideRt, tr("Texture Inside RT"), tr("Disabled"),
tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."));
+ dialog()->registerWidgetHelp(m_fixes.limit24BitDepth, tr("Limit 24 Bit Depth"), tr("Disabled"),
+ tr("Eats your cheese."));
+
dialog()->registerWidgetHelp(m_fixes.readTCOnClose, tr("Read Targets When Closing"), tr("Unchecked"),
tr("Flushes all targets in the texture cache back to local memory when shutting down. Can prevent lost visuals when saving "
"state or switching graphics APIs, but can also cause graphical corruption."));
diff --git a/pcsx2/Config.h b/pcsx2/Config.h
index cdd49113f8..bfd741d85e 100644
--- a/pcsx2/Config.h
+++ b/pcsx2/Config.h
@@ -432,6 +432,13 @@ enum class GSTextureInRtMode : u8
MergeTargets,
};
+enum class GSLimit24BitDepth : u8
+{
+ Disabled,
+ PrioritizeUpper,
+ PrioritizeLower,
+};
+
enum class GSBilinearDirtyMode : u8
{
Automatic,
@@ -844,6 +851,7 @@ struct Pcsx2Config
u8 UserHacks_CPUCLUTRender = 0;
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled;
GSTextureInRtMode UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
+ GSLimit24BitDepth UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
GSBilinearDirtyMode UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
TriFiltering TriFilter = TriFiltering::Automatic;
s8 OverrideTextureBarriers = -1;
diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp
index 52c5e9bee4..0caf4e5038 100644
--- a/pcsx2/GS/GSState.cpp
+++ b/pcsx2/GS/GSState.cpp
@@ -4665,6 +4665,14 @@ __forceinline void GSState::VertexKick(u32 skip)
u32 next = m_vertex.next;
u32 xy_tail = m_vertex.xy_tail;
+ if (GSIsHardwareRenderer() && GSLocalMemory::m_psm[m_context->ZBUF.PSM].bpp == 32)
+ {
+ if (GSConfig.UserHacks_Limit24BitDepth == GSLimit24BitDepth::PrioritizeUpper)
+ m_v.XYZ.Z = ((m_v.XYZ.Z >> 8) & ~0xFF) | (m_v.XYZ.Z & 0xFF);
+ else if (GSConfig.UserHacks_Limit24BitDepth == GSLimit24BitDepth::PrioritizeLower)
+ m_v.XYZ.Z &= 0x00FFFFFF;
+ }
+
// callers should write XYZUVF to m_v.m[1] in one piece to have this load store-forwarded, either by the cpu or the compiler when this function is inlined
const GSVector4i new_v0(m_v.m[0]);
diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp
index 9a8bad41f4..dd6121e75a 100644
--- a/pcsx2/ImGui/ImGuiOverlays.cpp
+++ b/pcsx2/ImGui/ImGuiOverlays.cpp
@@ -619,6 +619,8 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
APPEND("SD={}/{} ", GSConfig.SkipDrawStart, GSConfig.SkipDrawEnd);
if (GSConfig.UserHacks_TextureInsideRt != GSTextureInRtMode::Disabled)
APPEND("TexRT={} ", static_cast(GSConfig.UserHacks_TextureInsideRt));
+ if (GSConfig.UserHacks_Limit24BitDepth != GSLimit24BitDepth::Disabled)
+ APPEND("TDR={} ", static_cast(GSConfig.UserHacks_Limit24BitDepth));
if (GSConfig.UserHacks_BilinearHack != GSBilinearDirtyMode::Automatic)
APPEND("BLU={} ", static_cast(GSConfig.UserHacks_BilinearHack));
if (GSConfig.UserHacks_ForceEvenSpritePosition)
diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp
index 51ec1f788d..cecf1a60eb 100644
--- a/pcsx2/Pcsx2Config.cpp
+++ b/pcsx2/Pcsx2Config.cpp
@@ -755,6 +755,7 @@ Pcsx2Config::GSOptions::GSOptions()
ManualUserHacks = false;
UserHacks_AlignSpriteX = false;
UserHacks_AutoFlush = GSHWAutoFlushLevel::Disabled;
+ UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
UserHacks_CPUFBConversion = false;
UserHacks_ReadTCOnClose = false;
UserHacks_DisableDepthSupport = false;
@@ -847,6 +848,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(UserHacks_CPUCLUTRender) &&
OpEqu(UserHacks_GPUTargetCLUTMode) &&
OpEqu(UserHacks_TextureInsideRt) &&
+ OpEqu(UserHacks_Limit24BitDepth) &&
OpEqu(UserHacks_BilinearHack) &&
OpEqu(OverrideTextureBarriers) &&
@@ -983,6 +985,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapIntEnumEx(UserHacks_BilinearHack, "UserHacks_BilinearHack");
SettingsWrapBitBoolEx(UserHacks_NativePaletteDraw, "UserHacks_NativePaletteDraw");
SettingsWrapIntEnumEx(UserHacks_TextureInsideRt, "UserHacks_TextureInsideRt");
+ SettingsWrapIntEnumEx(UserHacks_Limit24BitDepth, "UserHacks_Limit24BitDepth");
SettingsWrapBitBoolEx(UserHacks_EstimateTextureRegion, "UserHacks_EstimateTextureRegion");
SettingsWrapBitBoolEx(FXAA, "fxaa");
SettingsWrapBitBool(ShadeBoost);
@@ -1111,6 +1114,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
UserHacks_CPUFBConversion = false;
UserHacks_ReadTCOnClose = false;
UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
+ UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
UserHacks_EstimateTextureRegion = false;
UserHacks_TCOffsetX = 0;
UserHacks_TCOffsetY = 0;