[GPU] Track DCC metadata coverage for color targets and volume textures

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
This commit is contained in:
ParantezTech 2026-10-08 17:32:00 +03:00
parent 7be8a4b389
commit ef10b4a1d8
4 changed files with 73 additions and 15 deletions

View File

@ -43,24 +43,38 @@ public static partial class ImageRequestBuilders
public static uint SampleCount(uint encodedLog2) => encodedLog2 <= 3 ? 1u << (int)encodedLog2 : 0;
private static bool DccAlphaOnMsb(in ColorTargetWords words)
{
switch (words.Layout)
{
case ChannelLayout.Bits10_10_10_2:
case ChannelLayout.Bits10_10_10_2Float:
case ChannelLayout.Bits5_5_5_1:
return true;
case ChannelLayout.Bits2_10_10_10:
case ChannelLayout.Bits1_5_5_5:
return false;
}
var components = GuestPixelFormats.ResolveRenderTargetEncoding(words.Layout, words.NumberType).Components;
if (components == 1)
{
return words.Order != ChannelOrder.Standard;
}
return components == 3 || words.Order is ChannelOrder.Standard or ChannelOrder.Alternate;
}
// DCC clears use the target's packed clear word; the fixed-clear set is a format allow-list.
private static (bool Supported, bool FixedSupported, ClearColorValue Value) DccClearInfo(Format format, bool hasDcc, uint packedClear)
{
ClearColorValue value = default;
var supported = hasDcc && PackedClearValue.TryDecodeColor(format, packedClear, out value);
var fixedSupported = hasDcc && SupportsDccFixedClear(format);
var fixedSupported = hasDcc && PackedClearValue.SupportsDccFixedColor(format);
return (supported, fixedSupported, supported ? value : default);
}
public static bool SupportsDccFixedClear(Format format) => format switch
{
Format.R8Unorm or Format.R8G8Unorm or Format.R8G8B8A8Unorm or Format.R8G8B8A8Srgb or Format.B8G8R8A8Unorm or Format.B8G8R8A8Srgb or
Format.A2B10G10R10UnormPack32 or Format.A2R10G10B10UnormPack32 or Format.R5G6B5UnormPack16 or Format.A1R5G5B5UnormPack16 or
Format.R4G4B4A4UnormPack16 or Format.R16Unorm or Format.R16G16Unorm or Format.R16G16B16A16Unorm or Format.R16Sfloat or
Format.R16G16Sfloat or Format.R16G16B16A16Sfloat or Format.R32Sfloat or Format.R32G32Sfloat or Format.R32G32B32A32Sfloat or
Format.B10G11R11UfloatPack32 => true,
_ => false,
};
public static bool SupportsDccFixedClear(Format format) => PackedClearValue.SupportsDccFixedColor(format);
// Builds the request for a bound color target. Null when the slot carries no target.
public static ColorTargetResolution? ColorTarget(in ColorTargetWords words, uint targetMask, uint drawLayerOffset, bool ignoreTargetMask)
@ -324,8 +338,14 @@ public static partial class ImageRequestBuilders
if (hasDcc)
{
// DCC lives in its own allocation; the address lets the cache match fills seen before the target.
_ = TileGeometry.TryGetDccSize(
width, height, volume ? depth : view.ImageLayers, bytesPerElement, levels, tileMode,
out var metadataSize, words.FragmentsLog2);
description.Metadata.Kind = MetadataKind.Dcc;
description.Metadata.Range = new GuestSpan(words.DccAddress, 0);
description.Metadata.Range = new GuestSpan(words.DccAddress, metadataSize.Size);
description.Metadata.DccClearWord = words.ClearWord0;
description.Metadata.DccClearRegisterValid = true;
description.Metadata.DccAlphaMsb = DccAlphaOnMsb(words);
}
for (var level = 0; level < levels; level++)

View File

@ -300,12 +300,15 @@ public static partial class ImageRequestBuilders
description.BytesPerBlock = blockBytes != 0 ? blockBytes : GuestPixelFormats.BytesPerElement(format);
description.Samples = samples;
description.TileMode = tile;
var metadataAddress = descriptor.MetadataAddress << 8;
if (!storage && type == GuestImageType.Color2D && samples == 1 && levels == 1 && tile == GuestTileMode.RenderTarget && descriptor.MetadataCompress &&
metadataAddress != 0 && metadataAddress < TrackerLayout.SpaceBytes)
if (!shape.R128 && words.Length >= 8 && descriptor.MetadataCompress &&
tile != GuestTileMode.Depth && !description.IsDepth)
{
_ = TileGeometry.TryGetDccSize(
width, height, volume ? depth : imageLayers, description.BytesPerBlock, levels, tile,
out var metadataSize, (uint)System.Numerics.BitOperations.TrailingZeroCount(samples));
description.Metadata.Kind = MetadataKind.Dcc;
description.Metadata.Range = new GuestSpan(metadataAddress, 0);
description.Metadata.Range = new GuestSpan(descriptor.MetadataAddress << 8, metadataSize.Size);
description.Metadata.DccAlphaMsb = descriptor.DccAlphaMsb;
}
if (samples > 1)

View File

@ -78,6 +78,8 @@ public readonly struct TextureDescriptorWords
public bool MetadataCompress => ((Fields[6] >> 21) & 0x1) == 1;
public bool DccAlphaMsb => ((Fields[6] >> 22) & 0x1) == 1;
public ulong MetadataAddress => ((Fields[6] >> 24) & 0xFF) | ((ulong)Fields[7] << 8);
}

View File

@ -608,6 +608,39 @@ public static partial class TileGeometry
return true;
}
public static bool TryGetDccSize(
uint width,
uint height,
uint slices,
uint bytesPerElement,
uint levels,
GuestTileMode tile,
out TileSizeAndAlignment totalSize,
uint fragmentsLog2 = 0)
{
totalSize = default;
if (width == 0 || height == 0 || slices == 0 || levels != 1 || fragmentsLog2 != 0 ||
!BitOperations.IsPow2(bytesPerElement) || bytesPerElement > 16 ||
tile is not (GuestTileMode.RenderTarget or GuestTileMode.Depth))
{
return false;
}
var coverageBits = 20 - BitOperations.TrailingZeroCount(bytesPerElement);
var blockWidth = 1u << ((coverageBits + 1) / 2);
var blockHeight = 1u << (coverageBits / 2);
var blocksX = ((ulong)width + blockWidth - 1) / blockWidth;
var blocksY = ((ulong)height + blockHeight - 1) / blockHeight;
var blocks = blocksX * blocksY;
if (blocks == 0 || blocks > uint.MaxValue / 4096u / slices)
{
return false;
}
totalSize = new TileSizeAndAlignment((uint)(blocks * slices * 4096u), 4096);
return true;
}
public static bool TryGetRenderTargetMipLayout(uint width, uint height, uint pitch, uint bytesPerElement, uint levels, out TileSizeAndAlignment totalSize, TileLevelSpan[]? levelSpans, TilePaddedSize[]? paddedSizes)
{
totalSize = default;