diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 77e7f9aa..fda47c1a 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -36,7 +36,9 @@ constexpr uint64_t NumFramesBeforeRemoval = 32; [[nodiscard]] bool DecodeColorClear(const TextureCache::ImageDesc& desc, uint8_t code, vk::ClearColorValue& clear) { const auto& metadata = desc.info.metadata; - const auto format = desc.view_info.format; + const auto format = desc.info.IsDepth() + ? TextureGetSurfaceFormatInfo(desc.info.guest_format).vk_format + : desc.view_info.format; const bool cmask = metadata.kind == ImageMetadataKind::Cmask; if (cmask ? code == 0 : code == 0x20) { // Register clears belong to the color buffer; the texture pipe cannot decode them. @@ -1059,8 +1061,15 @@ void TextureCache::MaterializeColorClear(ImageId id, const ImageDesc& desc, } { std::scoped_lock lock {m_lock}; - ClearImage(m_scheduler.Current(), id, view.format, - {vk::ImageAspectFlagBits::eColor, view.base_level, view.level_count, + const auto& image = m_slot_images[id]; + const bool depth = image.info.IsDepth(); + if (depth) { + const auto value = clear.color.float32[0]; + clear.depthStencil = {value, 0u}; + } + ClearImage(m_scheduler.Current(), id, depth ? image.backing.format : view.format, + {depth ? vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor, + view.base_level, view.level_count, image_first + slice, 1}, clear); } // Publish the conversion's expanded keys without treating them as guest writes diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 8b36ffc3..7683bfb3 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -179,7 +179,9 @@ static void ValidateSampledDepthBinding(const ShaderRecompiler::IR::ImageResourc const ShaderTextureResource& descriptor, const Image& image, vk::Format view_format, uint64_t size) { const bool resource_ok = IsSupportedSampledDepthResource(resource); - const bool encoding_ok = IsSupportedDepthTextureEncoding(descriptor, resource.r128); + // Comparison sampling changes the host format, not the guest metadata encoding. + const bool encoding_ok = descriptor.TileMode() != Prospero::TileMode::kDepth || + IsSupportedDepthTextureEncoding(descriptor, resource.r128); const bool view_ok = IsSupportedSampledDepthView(image.info.pixel_format, view_format, descriptor.DstSelXYZW()); if (resource_ok && encoding_ok && view_ok) { @@ -622,8 +624,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR if (storage) { ValidateStorageTexture(resource, descriptor, desc.info.data.size); } - if (!resource.r128 && descriptor.MetaCompress() && tile != Prospero::TileMode::kDepth && - !desc.info.IsDepth()) { + if (!resource.r128 && descriptor.MetaCompress() && tile != Prospero::TileMode::kDepth) { TileSizeAlign metadata_size {}; (void)TileGetDccSize(width, height, volume ? depth : image_layers, desc.info.bytes_per_block, physical_levels, tile, metadata_size, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 54f07631..34c58d40 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -11083,6 +11083,78 @@ public: context.ShutdownGpu(); LibKernel::Memory::InstallGpuResources(nullptr); } + { + // PPSA01593 samples a DCC R32 color surface through a comparison sampler. + constexpr uint64_t comparison_dcc = base + 0x10000; + std::memset(mapped, 0, 0x10000); + std::memset(reinterpret_cast(comparison_dcc), 0xff, 0x1000); + RenderContext context(m_runtime_context); + context.InitializeGpu(nullptr); + LibKernel::Memory::InstallGpuResources(&context); + auto &scheduler = context.GetCommandScheduler(); + HW::Context registers{}; + HW::UserConfig user_config{}; + HW::Shader shaders{}; + scheduler.Begin(registers, user_config, shaders); + context.MapMemory(base, allocation_size); + auto &cache = context.GetTextureCache(); + auto &executor = context.GetRenderExecutor(); + const ShaderTextureResource descriptor{{static_cast(base >> 8u), + 0xc1600000u, 0x000fc00fu, 0x91b00204u, 0, 0x00700000u, + 0x002b0000u | (static_cast(comparison_dcc >> 8u) << 24u), + static_cast(comparison_dcc >> 16u)}}; + ShaderRecompiler::IR::DescriptorValue value{}; + value.dword_count = 8; + std::copy_n(descriptor.fields, 8, value.dwords.begin()); + ShaderRecompiler::IR::ImageResource resource{}; + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage; + resource.numeric_class = Prospero::TextureNumericClass::Float; + resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; + resource.written = true; + const auto color = RenderExecutorTestAccess::ResolveTexture(executor, resource, value); + (void)cache.FindTexture(color.image_id, color.desc); + vk::ClearValue paint{}; + paint.color.float32 = std::array{0.375f, 0.f, 0.f, 0.f}; + TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), color.image_id, + {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, paint); + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled; + resource.written = false; + resource.read = true; + resource.depth_compare = true; + auto comparison = RenderExecutorTestAccess::ResolveTexture(executor, resource, value); + (void)cache.FindTexture(comparison.image_id, comparison.desc); + const auto &depth = cache.GetImage(comparison.image_id); + Require(name, "expanded DCC comparison alias", + comparison.image_id != color.image_id && + depth.info.pixel_format == vk::Format::eD32Sfloat && + depth.info.guest_format == Prospero::BufferFormat::k32Float && + depth.info.tile_mode == Prospero::TileMode::kRenderTarget && + depth.info.extent == vk::Extent3D{64, 64, 1} && + depth.info.metadata.kind == ImageMetadataKind::Dcc && + depth.info.metadata.range == GuestRange{comparison_dcc, 0x1000} && + ReadCachedTexel(name, context, comparison.image_id) == + std::vector{std::bit_cast(0.375f)}, + "comparison promotion lost native color data or guest DCC layout"); + for (const u32 code : {0x40404040u, 0x80808080u}) { + WriteMetadata(context, comparison_dcc, 0x1000, code); + comparison = RenderExecutorTestAccess::ResolveTexture(executor, resource, value); + (void)cache.FindTexture(comparison.image_id, comparison.desc); + Require(name, "DCC clear on a comparison backing", + ReadCachedTexel(name, context, comparison.image_id, {63, 63, 0}) == + std::vector{code == 0x40404040u ? 0u : 0x3f800000u}, + "DCC clear used the native depth format or color aspect"); + std::array metadata{}; + Require(name, "comparison clear expands metadata", + LibKernel::Memory::TryReadBacking(comparison_dcc, metadata.data(), + metadata.size()) && + std::ranges::all_of(metadata, [](uint8_t byte) { return byte == 0xff; }), + "comparison clear retained the native DCC clear key"); + } + context.UnmapMemory(base, allocation_size); + scheduler.Finish(); + context.ShutdownGpu(); + LibKernel::Memory::InstallGpuResources(nullptr); + } Require(name, "unmap", Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0, "captured scene mapping release failed");