From 4c6cff1116a5f58862240c3ae4c5829f81389da1 Mon Sep 17 00:00:00 2001 From: MarcelMediaDev Date: Thu, 23 Jul 2026 13:37:34 +0100 Subject: [PATCH] fix(agc): skip CB metadata draws for EliminateFastClear/Fmask/DCC (#553) CB_COLOR_CONTROL modes 2/5/6 are colour-buffer metadata ops; applying the bound shader as a normal colour draw corrupts subsequent composites. Decode MODE from bits [6:4] and return before translate. Co-authored-by: Cursor --- src/SharpEmu.Libs/Agc/AgcExports.cs | 53 +++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/SharpEmu.Libs/Agc/AgcExports.cs b/src/SharpEmu.Libs/Agc/AgcExports.cs index 58e3c181..a7d163fe 100644 --- a/src/SharpEmu.Libs/Agc/AgcExports.cs +++ b/src/SharpEmu.Libs/Agc/AgcExports.cs @@ -280,6 +280,7 @@ public static partial class AgcExports private static int _tracedVertexRangeCount; private static long _dcbWaitRegMemTraceCount; private static long _createShaderTraceCount; + private static long _cbMetadataSkipTraceCount; private static long _packetPayloadTraceCount; private static bool _tracedMissingPixelShaderBindings; private static long _unsatisfiedWaitTraceCount; @@ -5683,6 +5684,25 @@ public static partial class AgcExports } state.TranslatedDraw = null; state.GuestDrawKind = GuestDrawKind.None; + + // CB modes EliminateFastClear / FmaskDecompress / DccDecompress run + // colour-buffer metadata ops. The bound shader is only a vehicle and + // must not be applied as a normal colour draw. + if (TryGetCbColorControlMode(state.CxRegisters, out var cbMode) && + IsCbMetadataColorMode(cbMode)) + { + if (_traceAgcShader || ShouldTraceHotPath(ref _cbMetadataSkipTraceCount)) + { + TraceAgcShader( + $"agc.cb_metadata_skip seq={drawSequence} mode={cbMode} " + + $"es=0x{(hasExportShader ? exportShaderAddress : 0):X16} " + + $"ps=0x{(hasPixelShader ? pixelShaderAddress : 0):X16} " + + $"vertices={vertexCount}"); + } + + return; + } + foreach (var target in renderTargets) { state.KnownRenderTargets[target.Address] = target; @@ -7294,6 +7314,35 @@ public static partial class AgcExports return hash; } + private enum CbColorMode : byte + { + Disable = 0, + Normal = 1, + EliminateFastClear = 2, + Resolve = 3, + FmaskDecompress = 5, + DccDecompress = 6, + } + + private static bool TryGetCbColorControlMode( + IReadOnlyDictionary registers, + out uint mode) + { + mode = 0; + if (!registers.TryGetValue(CbColorControl, out var colorControl)) + { + return false; + } + + mode = (colorControl >> 4) & 0x7u; + return true; + } + + private static bool IsCbMetadataColorMode(uint mode) => + mode is (uint)CbColorMode.EliminateFastClear or + (uint)CbColorMode.FmaskDecompress or + (uint)CbColorMode.DccDecompress; + private static bool TryGetHardwareColorResolveTargets( IReadOnlyDictionary registers, out RenderTargetDescriptor source, @@ -7301,8 +7350,8 @@ public static partial class AgcExports { source = default; destination = default; - if (!registers.TryGetValue(CbColorControl, out var colorControl) || - ((colorControl >> 4) & 0x7u) != 3u) + if (!TryGetCbColorControlMode(registers, out var mode) || + mode != (uint)CbColorMode.Resolve) { return false; }