diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index aee3cdc17..a863f98c9 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -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 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; diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.h b/src/graphics/host_gpu/renderer/cache/textureCache.h index addce65d2..e92dfd8f9 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.h +++ b/src/graphics/host_gpu/renderer/cache/textureCache.h @@ -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); diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 4665ecd7d..69ae2b182 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -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; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 383041392..7d7a2e4d1 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -219,7 +219,7 @@ struct TextureCacheTestAccess { const vk::ImageSubresourceRange &range, const vk::ClearValue &clear) { auto lock = Lock(cache); - cache.ClearImage(command, id, range, clear); + cache.ClearImage(command, id, cache.GetImage(id).backing.format, range, clear); } static void ConfigureGarbageCollection(TextureCache &cache, @@ -8568,10 +8568,12 @@ public: struct FillCase { uint32_t fill; std::array texel; + bool reuse_unorm = false; }; constexpr std::array cases{ FillCase{0x40404040u, {0, 0x3c000000u}}, FillCase{0x80808080u, {0x3c003c00u, 0x00003c00u}}, + FillCase{0x40404040u, {0, 0x3c000000u}, true}, }; EnsureRuntimeContext(); // Astro's generic metadata fill, through S_ENDPGM; trailing debug data is omitted. @@ -8658,6 +8660,21 @@ public: auto &texture_cache = resources.GetTextureCache(); auto &executor = context.GetRenderExecutor(); resources.MapMemory(base, allocation_size); + ImageId unorm_id{}; + if (fill_case.reuse_unorm) { + const auto float_info = registers.GetRenderTarget(0).info; + auto unorm_info = float_info; + unorm_info.dcc_compression_enable = false; + unorm_info.channel_type = Prospero::ChannelType::kUNorm; + registers.SetColorInfo(0, unorm_info); + RenderColorInfo unorm{}; + RenderExecutorTestAccess::ResolveRenderColorTarget( + executor, scheduler.Current(), unorm, 0); + unorm_id = unorm.image_id; + (void)texture_cache.FindRenderTarget(unorm_id, unorm.desc); + RenderExecutorTestAccess::ResetBindings(executor); + registers.SetColorInfo(0, float_info); + } const auto fill_metadata = [&](uint32_t count, bool raw = false) { const auto *shader = &native_fill; if (raw) { @@ -8687,6 +8704,13 @@ public: RenderDepthInfo no_depth{}; const auto rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &color, 1, no_depth); + if (fill_case.reuse_unorm) { + Require(name, "FLOAT clear reuses UNORM image", + color.image_id == unorm_id && + texture_cache.GetImage(unorm_id).backing.format == + vk::Format::eR16G16B16A16Unorm, + "the aliased clear did not reuse its existing UNORM allocation"); + } Require(name, "fixed clear on a float target", color.image_id && color.desc.info.metadata.kind == ImageMetadataKind::Dcc && @@ -8695,10 +8719,12 @@ public: !texture_cache.IsMeta(dcc_address), "a DCC fixed clear code was not materialised on an RGBA16F " "target"); + const auto cleared = ReadCachedTexel(name, context, color.image_id); Require(name, "GPU float clear value", - ReadCachedTexel(name, context, color.image_id) == + cleared == std::vector(fill_case.texel.begin(), fill_case.texel.end()), - "RGBA16F native image did not receive the fixed clear value"); + "expected " + Hex(fill_case.texel[0]) + ", " + Hex(fill_case.texel[1]) + + "; got " + Hex(cleared[0]) + ", " + Hex(cleared[1])); context.GetBufferCache().ReadMemory(dcc_address, metadata_size.size, false); std::vector expanded_metadata(metadata_size.size); Require(name, "expanded native metadata", @@ -8720,7 +8746,10 @@ public: texture_cache, scheduler.Current(), color.image_id, {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, clear); }; - const std::vector painted{0x00003c00u, 0x3c003c00u}; + std::vector painted{0x00003c00u, 0x3c003c00u}; + if (fill_case.reuse_unorm) { + painted = {0x0000ffffu, 0xffffffffu}; + } const auto retains_painted_texel = [&] { const auto texels = ReadCachedTexel(name, context, color.image_id, {}, {512, 256, 1}); for (size_t i = 0; i < texels.size(); i += 2) {