diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 50d23fc96..d43ed4998 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -694,7 +694,9 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp requested.type == cached.info.type && requested.pitch == cached.info.pitch && !requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() && !cached.info.HasMetadata(); - // PPSA04264 + // PPSA04264, PPSA04288 + // A partial view retains the entire matching array layout. HTile belongs to + // the depth source, independently of the data slices copied into color storage. const bool retain_cached_layout = requested.samples == 1 && cached.info.samples == 1 && cached.backing.samples == 1 && requested.bytes_per_block == cached.info.bytes_per_block && @@ -713,7 +715,8 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp requested.data.size / requested.resources.layers == cached.info.data.size / cached.info.resources.layers && !requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() && - !cached.info.HasMetadata(); + (cached.info.metadata.kind == ImageMetadataKind::None || + cached.info.metadata.kind == ImageMetadataKind::Htile); bool recreate = cached.info.resources < requested.resources || requested.IsVolume() != cached.info.IsVolume(); switch (binding) { @@ -738,8 +741,6 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp info.data = cached.info.data; info.resources = cached.info.resources; info.mip_layout = cached.info.mip_layout; - } else { - info.resources = std::max(requested.resources, cached.info.resources); } info.htile_clear_mask = 0; const auto replacement_id = InsertImage(info); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index f9217f2b2..e5ddaddd7 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -5110,7 +5110,7 @@ public: void CheckUnifiedTextureCacheFlow() { constexpr const char *name = "UnifiedTextureCacheFlow"; constexpr uintptr_t base = 0x0000000200600000ull; - constexpr uint64_t allocation_size = 0x2800000; + constexpr uint64_t allocation_size = 0x2c00000; constexpr uint64_t allocation_alignment = 0x200000; EnsureRuntimeContext(); RenderContext context(m_runtime_context); @@ -6042,6 +6042,74 @@ public: "sampling"); DestroyBuffer(&layered_raw_d16_readback); + // RE2 converts a prefix of a 32-layer HTile depth array to R32F storage. + constexpr uint32_t htile_layers = 32; + constexpr uint64_t htile_slice_size = 0x10000; + auto htile_depth = MakeLinearDesc( + base + 0x2800000, htile_layers * htile_slice_size, + vk::Format::eD32Sfloat, Prospero::BufferFormat::k32Float, + Prospero::ImageType::kColor2D, {128, 128, 1}, htile_layers, 4, 1); + htile_depth.type = BindingType::DepthTarget; + htile_depth.info.tile_mode = Prospero::TileMode::kDepth; + htile_depth.info.metadata.kind = ImageMetadataKind::Htile; + htile_depth.info.metadata.range = {base + 0x2a00000, htile_layers * 0x8000}; + htile_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth; + htile_depth.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; + const auto htile_depth_image = texture_cache.FindImage(htile_depth); + vk::ClearValue htile_clear{}; + htile_clear.depthStencil.depth = 0.25f; + TextureCacheTestAccess::ClearImage( + texture_cache, scheduler.Current(), htile_depth_image, + {vk::ImageAspectFlagBits::eDepth, 0, 1, 0, htile_layers}, htile_clear); + + auto htile_storage = htile_depth; + htile_storage.type = BindingType::Storage; + htile_storage.info.pixel_format = vk::Format::eR32Sfloat; + htile_storage.info.metadata = {}; + htile_storage.view_info.format = vk::Format::eR32Sfloat; + htile_storage.view_info.aspect = vk::ImageAspectFlagBits::eColor; + htile_storage.view_info.usage = vk::ImageUsageFlagBits::eStorage; + ImageId htile_storage_image{}; + for (uint32_t layers : {1u, 2u}) { + htile_storage.info.data.size = layers * htile_slice_size; + htile_storage.info.resources.layers = layers; + htile_storage.info.mip_layout[0].size = htile_storage.info.data.size; + htile_storage.view_info.layer_count = layers; + const auto id = texture_cache.FindImage(htile_storage); + const auto &owner = texture_cache.GetImage(id); + Require(name, "HTile depth storage prefix layout", + id != htile_depth_image && + (!htile_storage_image || id == htile_storage_image) && + owner.info.data == htile_depth.info.data && + owner.info.resources == htile_depth.info.resources && + owner.info.mip_layout == htile_depth.info.mip_layout && + owner.backing.layers == htile_layers && + !owner.info.HasMetadata(), + "partial storage conversion separated array layers from their guest layout"); + Require(name, "HTile depth storage prefix view", + texture_cache.FindTexture(id, htile_storage) != nullptr, + "converted depth prefix has no storage view"); + htile_storage_image = id; + } + auto htile_readback = CreateHostBuffer( + name, htile_layers * sizeof(float), vk::BufferUsageFlagBits::eTransferDst, + std::vector(htile_layers)); + vk::BufferImageCopy htile_copy{}; + htile_copy.imageSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, htile_layers}; + htile_copy.imageExtent = {1, 1, 1}; + texture_cache.GetImage(htile_storage_image).Download( + std::span(&htile_copy, 1), htile_readback.buffer, + 0, htile_readback.size); + HostReadBarrier(htile_readback.buffer, htile_readback.size, + vk::PipelineStageFlagBits::eTransfer, + vk::AccessFlagBits::eTransferWrite); + scheduler.Finish(); + Require(name, "HTile depth storage array contents", + ReadBuffer(name, htile_readback, htile_layers) == + std::vector(htile_layers, std::bit_cast(0.25f)), + "partial storage conversion lost native depth data outside its view"); + DestroyBuffer(&htile_readback); + auto layered_stencil_desc = MakeLinearDesc( base + 0x27d4000, 6 * 4 * sizeof(float), vk::Format::eD32SfloatS8Uint, Prospero::BufferFormat::k32Float, @@ -7250,7 +7318,10 @@ public: auto layered_depth = layered_color; layered_depth.type = BindingType::DepthTarget; layered_depth.info.resources = {1, 4}; + layered_depth.info.mip_layout = {}; + layered_depth.info.mip_layout[0] = {0, layered_guest_size, 2, 2}; layered_depth.view_info.level_count = 1; + layered_depth.view_info.layer_count = 4; layered_depth.info.pixel_format = vk::Format::eD32Sfloat; layered_depth.view_info.format = vk::Format::eD32Sfloat; layered_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth; @@ -7260,13 +7331,13 @@ public: const auto &layered_native = texture_cache.GetImage(layered_depth_image); Require(name, "layered mipped depth alias", layered_depth_image != layered_color_image && - layered_native.backing.layers == 2 && - layered_native.backing.mip_levels == 2 && + layered_native.backing.layers == 4 && + layered_native.backing.mip_levels == 1 && layered_native.info.resources == - layered_color.info.resources && + layered_depth.info.resources && + layered_native.info.mip_layout == layered_depth.info.mip_layout && layered_native.IsGpuModified(), - "depth/color conversion did not use the lexicographic " - "resource maximum"); + "depth/color conversion mixed the source mip count with the requested layout"); const volatile auto layered_guest_byte = *reinterpret_cast(memory + layered_offset); (void)layered_guest_byte; @@ -7557,29 +7628,19 @@ public: vk::AccessFlagBits::eTransferWrite); auto layered_readback = CreateHostBuffer( - name, sizeof(layered_values), vk::BufferUsageFlagBits::eTransferDst, - std::vector(sizeof(layered_values) / sizeof(u32), 0)); + name, 8 * sizeof(float), vk::BufferUsageFlagBits::eTransferDst, + std::vector(8, 0)); auto &layered_depth_native = texture_cache.GetImage(layered_depth_image); layered_depth_native.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}, command.Handle()); - std::array layered_copies{}; - layered_copies[0].bufferOffset = 0; - layered_copies[0].imageSubresource.aspectMask = - vk::ImageAspectFlagBits::eDepth; - layered_copies[0].imageSubresource.mipLevel = 0; - layered_copies[0].imageSubresource.layerCount = 2; - layered_copies[0].imageExtent = {2, 2, 1}; - layered_copies[1].bufferOffset = 32; - layered_copies[1].imageSubresource.aspectMask = - vk::ImageAspectFlagBits::eDepth; - layered_copies[1].imageSubresource.mipLevel = 1; - layered_copies[1].imageSubresource.layerCount = 2; - layered_copies[1].imageExtent = {1, 1, 1}; + vk::BufferImageCopy layered_copy{}; + layered_copy.imageSubresource = {vk::ImageAspectFlagBits::eDepth, 0, 0, 2}; + layered_copy.imageExtent = {2, 2, 1}; command.Handle().copyImageToBuffer( layered_depth_native.backing.image, vk::ImageLayout::eTransferSrcOptimal, layered_readback.buffer, - static_cast(layered_copies.size()), layered_copies.data()); + 1, &layered_copy); HostReadBarrier(layered_readback.buffer, layered_readback.size, vk::PipelineStageFlagBits::eTransfer, vk::AccessFlagBits::eTransferWrite); @@ -7792,21 +7853,19 @@ public: std::vector{0x40004200u, 0x44003c00u}, "GPU BGRA16 swap did not publish RGBA half-word order"); scheduler.Finish(); - const auto layered_words = - ReadBuffer(name, layered_readback, layered_values.size()); - const std::array layered_expected{ + const auto layered_words = ReadBuffer(name, layered_readback, 8); + const std::array layered_expected{ layered_values[0], layered_values[1], layered_values[2], layered_values[3], layered_values[4], layered_values[5], - layered_values[6], layered_values[7], layered_values[8], - layered_values[9]}; + layered_values[6], layered_values[7]}; bool layered_content = layered_words.size() == layered_expected.size(); for (uint32_t index = 0; layered_content && index < layered_expected.size(); index++) { layered_content &= layered_words[index] == std::bit_cast(layered_expected[index]); } - Require(name, "layered mipped depth content", layered_content, - "depth/color conversion changed a mip or array-layer value"); + Require(name, "layered depth common-mip content", layered_content, + "depth/color conversion changed a shared array-layer value"); const std::array, 2> expected_ms_depth{{ {0x2000 / 65535.0f, 0xe000 / 65535.0f, 0.0f, 0.0f}, {0.0f, 0x4000 / 65535.0f, 0x8000 / 65535.0f, 1.0f},