Fix DCC clears through aliased image formats

Clear DCC images using the requested view format.
UNORM alpha 0xffff reads as NaN in a FLOAT view.
This commit is contained in:
nmzik
2026-09-15 05:25:30 +04:00
parent 18a1e0fadc
commit ea092a9472
4 changed files with 46 additions and 17 deletions
+10 -10
View File
@@ -33,8 +33,8 @@ namespace {
constexpr uint64_t NumFramesBeforeRemoval = 32;
[[nodiscard]] bool DecodeDccClear(const TextureCache::ImageDesc& desc, vk::Format format,
uint8_t code, vk::ClearColorValue& clear) {
[[nodiscard]] bool DecodeDccClear(const TextureCache::ImageDesc& desc, uint8_t code,
vk::ClearColorValue& clear) {
switch (code) {
case 0x00:
case 0x20:
@@ -44,6 +44,7 @@ constexpr uint64_t NumFramesBeforeRemoval = 32;
default: return false;
}
const auto& metadata = desc.info.metadata;
const auto format = desc.view_info.format;
if (code == 0x20) {
// Clear-to-register is a color-buffer operation; the texture pipe cannot decode it.
return desc.type == TextureCache::BindingType::RenderTarget &&
@@ -1129,7 +1130,6 @@ void TextureCache::MaterializeDccClear(ImageId id, const ImageDesc& desc,
return;
}
const auto range = desc.info.metadata.range;
vk::Format format;
{
std::scoped_lock lock {m_lock};
auto& image = m_slot_images[id];
@@ -1139,7 +1139,6 @@ void TextureCache::MaterializeDccClear(ImageId id, const ImageDesc& desc,
if (range.size == 0 || desc.info.resources.levels != 1 || image.info.resources.levels != 1) {
return;
}
format = image.backing.format;
}
const auto layers = desc.info.TransferLayers();
// These one-mip surfaces use complete 4 KiB DCC metadata blocks.
@@ -1169,7 +1168,7 @@ void TextureCache::MaterializeDccClear(ImageId id, const ImageDesc& desc,
EXIT("TextureCache: failed to read DCC metadata backing\n");
}
vk::ClearValue clear {};
if (!DecodeDccClear(desc, format, code, clear.color)) {
if (!DecodeDccClear(desc, code, clear.color)) {
continue;
}
std::vector<uint8_t> bytes(slice_size);
@@ -1181,7 +1180,7 @@ void TextureCache::MaterializeDccClear(ImageId id, const ImageDesc& desc,
}
{
std::scoped_lock lock {m_lock};
ClearImage(m_scheduler.Current(), id,
ClearImage(m_scheduler.Current(), id, view.format,
{vk::ImageAspectFlagBits::eColor, view.base_level, view.level_count,
image_first + slice, 1}, clear);
}
@@ -1526,12 +1525,12 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address
}
clear.depthStencil.stencil = stencil_clear;
}
ClearImage(command, selected,
ClearImage(command, selected, image.backing.format,
{aspect, 0, image.info.resources.levels, 0, image.info.TransferLayers()}, clear);
return true;
}
void TextureCache::ClearImage(CommandBuffer& command, ImageId id,
void TextureCache::ClearImage(CommandBuffer& command, ImageId id, vk::Format format,
const vk::ImageSubresourceRange& range, const vk::ClearValue& clear) {
auto& image = m_slot_images[id];
const auto aspects = image.info.IsDepth() ? ImageViewOps::DepthAspectMask(image.backing.format)
@@ -1556,11 +1555,12 @@ void TextureCache::ClearImage(CommandBuffer& command, ImageId id,
}
}
command.EndRendering();
if (image.info.IsVolume() && !full_image) {
// Transfer clears use the backing format; aliased clears must encode through their view.
if (format != image.backing.format || (image.info.IsVolume() && !full_image)) {
EXIT_NOT_IMPLEMENTED(range.aspectMask != vk::ImageAspectFlagBits::eColor ||
range.levelCount != 1);
ImageViewInfo view {};
view.format = image.backing.format;
view.format = format;
view.type = range.layerCount == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray;
view.base_level = range.baseMipLevel;
view.base_layer = range.baseArrayLayer;
+2 -2
View File
@@ -151,8 +151,8 @@ private:
void DownloadDepth(Image& image, Buffer& destination, uint64_t destination_offset);
void CommitGpuWrite(Image& image);
// Caller holds m_lock. Volume layer ranges select depth slices.
void ClearImage(CommandBuffer& command, ImageId id, const vk::ImageSubresourceRange& range,
const vk::ClearValue& clear);
void ClearImage(CommandBuffer& command, ImageId id, vk::Format format,
const vk::ImageSubresourceRange& range, const vk::ClearValue& clear);
void PrepareImageCopy(Image& image);
void RefreshCopySource(ImageId id);
[[nodiscard]] bool CopyD16(Image& destination, Image& source);
@@ -172,7 +172,7 @@ bool RenderExecutor::TryConsumeComputeImageClear(const ShaderComputeInputInfo& i
1, view.base_layer, view.layer_count};
vk::ClearValue clear {};
clear.depthStencil = vk::ClearDepthStencilValue {0.0f, fill.value};
cache.ClearImage(command, binding.image_id, range, clear);
cache.ClearImage(command, binding.image_id, image.backing.format, range, clear);
return true;
}
ShaderBufferResource descriptor;