From 7be8a4b38964a724fb0d4d719b11ed4780cfd6a3 Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:31:58 +0300 Subject: [PATCH] [GPU] Decode DCC fixed and register clear values Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com> --- .../Gpu/Images/ImageDescription.cs | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/SharpEmu.Libs/Gpu/Images/ImageDescription.cs b/src/SharpEmu.Libs/Gpu/Images/ImageDescription.cs index 67201de..7c772e6 100644 --- a/src/SharpEmu.Libs/Gpu/Images/ImageDescription.cs +++ b/src/SharpEmu.Libs/Gpu/Images/ImageDescription.cs @@ -28,8 +28,11 @@ public struct MetadataDescription public GuestSpan Range; public MetadataKind Kind; public uint Control; + public uint DccClearWord; public DisplayCompression Compression; public bool StencilCompressed; + public bool DccClearRegisterValid; + public bool DccAlphaMsb; } public readonly record struct SubresourceCount(uint Levels, uint Layers) : IComparable @@ -366,7 +369,8 @@ public struct ImageDescription { case MetadataKind.None: if (!IsEmptyRange(Metadata.Range) || Metadata.Control != 0 || - Metadata.Compression != DisplayCompression.Uncompressed || Metadata.StencilCompressed) + Metadata.DccClearWord != 0 || Metadata.Compression != DisplayCompression.Uncompressed || Metadata.StencilCompressed || + Metadata.DccClearRegisterValid || Metadata.DccAlphaMsb) { throw SubmissionScheduler.Fatal("An image without metadata carries metadata state."); } @@ -378,6 +382,11 @@ public struct ImageDescription throw SubmissionScheduler.Fatal($"The HTile metadata is invalid: address=0x{Metadata.Range.Address:X16} size=0x{Metadata.Range.Size:X16}."); } + if (Metadata.DccClearWord != 0 || Metadata.DccClearRegisterValid || Metadata.DccAlphaMsb) + { + throw SubmissionScheduler.Fatal("HTile metadata carries DCC clear state."); + } + break; case MetadataKind.Dcc: if (Metadata.Range.Address == 0 || Metadata.Range.Address >= TrackerLayout.SpaceBytes || @@ -507,6 +516,87 @@ public static class DisplayFormatRule // Decoders for the packed 32-bit clear values guest compute fills carry. public static class PackedClearValue { + public static bool SupportsDccFixedColor(Format format) => DccComponentCount(format) != 0; + + public static bool TryDecodeDccColor( + Format format, + uint metadataFill, + in MetadataDescription metadata, + bool allowClearToRegister, + out ClearColorValue clear) + { + clear = default; + var code = (byte)metadataFill; + if (metadataFill != code * 0x01010101u) + { + return false; + } + + if (code == 0x20) + { + return allowClearToRegister && metadata.DccClearRegisterValid && + TryDecodeColor(format, metadata.DccClearWord, out clear); + } + + if (code == 0x00) + { + return true; + } + + var components = DccComponentCount(format); + if (components == 0 || code is not (0x40 or 0x80 or 0xc0)) + { + return false; + } + + var rgb = (code & 0x80) != 0 ? 1.0f : 0.0f; + var alpha = (code & 0x40) != 0 ? 1.0f : 0.0f; + Span channels = stackalloc float[4] { rgb, rgb, rgb, alpha }; + if (!metadata.DccAlphaMsb) + { + (channels[0], channels[3]) = (channels[3], channels[0]); + } + + if (components == 1) + { + channels[0] = channels[3]; + } + else if (components == 2) + { + channels[1] = channels[3]; + } + + switch (format) + { + case Format.B8G8R8A8Unorm: + case Format.B8G8R8A8Srgb: + case Format.A2R10G10B10UnormPack32: + case Format.A1R5G5B5UnormPack16: + case Format.R5G6B5UnormPack16: + (channels[0], channels[2]) = (channels[2], channels[0]); + break; + case Format.R4G4B4A4UnormPack16: + (channels[0], channels[3]) = (channels[3], channels[0]); + (channels[1], channels[2]) = (channels[2], channels[1]); + break; + } + + clear = new ClearColorValue(channels[0], channels[1], channels[2], channels[3]); + return true; + } + + private static uint DccComponentCount(Format format) => format switch + { + Format.R8Unorm or Format.R16Unorm or Format.R16Sfloat or Format.R32Sfloat => 1, + Format.R8G8Unorm or Format.R16G16Unorm or Format.R16G16Sfloat or Format.R32G32Sfloat => 2, + Format.R5G6B5UnormPack16 or Format.B10G11R11UfloatPack32 => 3, + Format.R8G8B8A8Unorm or Format.R8G8B8A8Srgb or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb or + Format.A2B10G10R10UnormPack32 or Format.A2R10G10B10UnormPack32 or Format.A1R5G5B5UnormPack16 or + Format.R4G4B4A4UnormPack16 or Format.R16G16B16A16Unorm or Format.R16G16B16A16Sfloat or + Format.R32G32B32A32Sfloat => 4, + _ => 0, + }; + public static bool TryDecodeColor(Format format, uint packed, out ClearColorValue clear) { static float Unorm8(uint value) => (value & 0xff) / 255.0f;