graphics: preserve depth array layout during storage reinterpretation

This commit is contained in:
nmzik
2026-10-07 17:51:47 +04:00
parent d2413fc2eb
commit fbf6ae400c
2 changed files with 93 additions and 33 deletions
+5 -4
View File
@@ -694,7 +694,9 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp
requested.type == cached.info.type && requested.pitch == cached.info.pitch && requested.type == cached.info.type && requested.pitch == cached.info.pitch &&
!requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() && !requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() &&
!cached.info.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 = const bool retain_cached_layout =
requested.samples == 1 && cached.info.samples == 1 && cached.backing.samples == 1 && requested.samples == 1 && cached.info.samples == 1 && cached.backing.samples == 1 &&
requested.bytes_per_block == cached.info.bytes_per_block && 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 == requested.data.size / requested.resources.layers ==
cached.info.data.size / cached.info.resources.layers && cached.info.data.size / cached.info.resources.layers &&
!requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() && !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 || bool recreate = cached.info.resources < requested.resources ||
requested.IsVolume() != cached.info.IsVolume(); requested.IsVolume() != cached.info.IsVolume();
switch (binding) { switch (binding) {
@@ -738,8 +741,6 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp
info.data = cached.info.data; info.data = cached.info.data;
info.resources = cached.info.resources; info.resources = cached.info.resources;
info.mip_layout = cached.info.mip_layout; info.mip_layout = cached.info.mip_layout;
} else {
info.resources = std::max(requested.resources, cached.info.resources);
} }
info.htile_clear_mask = 0; info.htile_clear_mask = 0;
const auto replacement_id = InsertImage(info); const auto replacement_id = InsertImage(info);
+88 -29
View File
@@ -5110,7 +5110,7 @@ public:
void CheckUnifiedTextureCacheFlow() { void CheckUnifiedTextureCacheFlow() {
constexpr const char *name = "UnifiedTextureCacheFlow"; constexpr const char *name = "UnifiedTextureCacheFlow";
constexpr uintptr_t base = 0x0000000200600000ull; constexpr uintptr_t base = 0x0000000200600000ull;
constexpr uint64_t allocation_size = 0x2800000; constexpr uint64_t allocation_size = 0x2c00000;
constexpr uint64_t allocation_alignment = 0x200000; constexpr uint64_t allocation_alignment = 0x200000;
EnsureRuntimeContext(); EnsureRuntimeContext();
RenderContext context(m_runtime_context); RenderContext context(m_runtime_context);
@@ -6042,6 +6042,74 @@ public:
"sampling"); "sampling");
DestroyBuffer(&layered_raw_d16_readback); 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<u32>(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<const vk::BufferImageCopy>(&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<u32>(htile_layers, std::bit_cast<u32>(0.25f)),
"partial storage conversion lost native depth data outside its view");
DestroyBuffer(&htile_readback);
auto layered_stencil_desc = MakeLinearDesc( auto layered_stencil_desc = MakeLinearDesc(
base + 0x27d4000, 6 * 4 * sizeof(float), base + 0x27d4000, 6 * 4 * sizeof(float),
vk::Format::eD32SfloatS8Uint, Prospero::BufferFormat::k32Float, vk::Format::eD32SfloatS8Uint, Prospero::BufferFormat::k32Float,
@@ -7250,7 +7318,10 @@ public:
auto layered_depth = layered_color; auto layered_depth = layered_color;
layered_depth.type = BindingType::DepthTarget; layered_depth.type = BindingType::DepthTarget;
layered_depth.info.resources = {1, 4}; 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.level_count = 1;
layered_depth.view_info.layer_count = 4;
layered_depth.info.pixel_format = vk::Format::eD32Sfloat; layered_depth.info.pixel_format = vk::Format::eD32Sfloat;
layered_depth.view_info.format = vk::Format::eD32Sfloat; layered_depth.view_info.format = vk::Format::eD32Sfloat;
layered_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth; layered_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth;
@@ -7260,13 +7331,13 @@ public:
const auto &layered_native = texture_cache.GetImage(layered_depth_image); const auto &layered_native = texture_cache.GetImage(layered_depth_image);
Require(name, "layered mipped depth alias", Require(name, "layered mipped depth alias",
layered_depth_image != layered_color_image && layered_depth_image != layered_color_image &&
layered_native.backing.layers == 2 && layered_native.backing.layers == 4 &&
layered_native.backing.mip_levels == 2 && layered_native.backing.mip_levels == 1 &&
layered_native.info.resources == 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(), layered_native.IsGpuModified(),
"depth/color conversion did not use the lexicographic " "depth/color conversion mixed the source mip count with the requested layout");
"resource maximum");
const volatile auto layered_guest_byte = const volatile auto layered_guest_byte =
*reinterpret_cast<const volatile uint8_t *>(memory + layered_offset); *reinterpret_cast<const volatile uint8_t *>(memory + layered_offset);
(void)layered_guest_byte; (void)layered_guest_byte;
@@ -7557,29 +7628,19 @@ public:
vk::AccessFlagBits::eTransferWrite); vk::AccessFlagBits::eTransferWrite);
auto layered_readback = CreateHostBuffer( auto layered_readback = CreateHostBuffer(
name, sizeof(layered_values), vk::BufferUsageFlagBits::eTransferDst, name, 8 * sizeof(float), vk::BufferUsageFlagBits::eTransferDst,
std::vector<u32>(sizeof(layered_values) / sizeof(u32), 0)); std::vector<u32>(8, 0));
auto &layered_depth_native = texture_cache.GetImage(layered_depth_image); auto &layered_depth_native = texture_cache.GetImage(layered_depth_image);
layered_depth_native.Transit(vk::ImageLayout::eTransferSrcOptimal, layered_depth_native.Transit(vk::ImageLayout::eTransferSrcOptimal,
vk::AccessFlagBits2::eTransferRead, {}, vk::AccessFlagBits2::eTransferRead, {},
command.Handle()); command.Handle());
std::array<vk::BufferImageCopy, 2> layered_copies{}; vk::BufferImageCopy layered_copy{};
layered_copies[0].bufferOffset = 0; layered_copy.imageSubresource = {vk::ImageAspectFlagBits::eDepth, 0, 0, 2};
layered_copies[0].imageSubresource.aspectMask = layered_copy.imageExtent = {2, 2, 1};
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};
command.Handle().copyImageToBuffer( command.Handle().copyImageToBuffer(
layered_depth_native.backing.image, layered_depth_native.backing.image,
vk::ImageLayout::eTransferSrcOptimal, layered_readback.buffer, vk::ImageLayout::eTransferSrcOptimal, layered_readback.buffer,
static_cast<uint32_t>(layered_copies.size()), layered_copies.data()); 1, &layered_copy);
HostReadBarrier(layered_readback.buffer, layered_readback.size, HostReadBarrier(layered_readback.buffer, layered_readback.size,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::AccessFlagBits::eTransferWrite); vk::AccessFlagBits::eTransferWrite);
@@ -7792,21 +7853,19 @@ public:
std::vector<u32>{0x40004200u, 0x44003c00u}, std::vector<u32>{0x40004200u, 0x44003c00u},
"GPU BGRA16 swap did not publish RGBA half-word order"); "GPU BGRA16 swap did not publish RGBA half-word order");
scheduler.Finish(); scheduler.Finish();
const auto layered_words = const auto layered_words = ReadBuffer(name, layered_readback, 8);
ReadBuffer(name, layered_readback, layered_values.size()); const std::array<float, 8> layered_expected{
const std::array<float, 10> layered_expected{
layered_values[0], layered_values[1], layered_values[2], layered_values[0], layered_values[1], layered_values[2],
layered_values[3], layered_values[4], layered_values[5], layered_values[3], layered_values[4], layered_values[5],
layered_values[6], layered_values[7], layered_values[8], layered_values[6], layered_values[7]};
layered_values[9]};
bool layered_content = layered_words.size() == layered_expected.size(); bool layered_content = layered_words.size() == layered_expected.size();
for (uint32_t index = 0; for (uint32_t index = 0;
layered_content && index < layered_expected.size(); index++) { layered_content && index < layered_expected.size(); index++) {
layered_content &= layered_content &=
layered_words[index] == std::bit_cast<u32>(layered_expected[index]); layered_words[index] == std::bit_cast<u32>(layered_expected[index]);
} }
Require(name, "layered mipped depth content", layered_content, Require(name, "layered depth common-mip content", layered_content,
"depth/color conversion changed a mip or array-layer value"); "depth/color conversion changed a shared array-layer value");
const std::array<std::array<float, 4>, 2> expected_ms_depth{{ const std::array<std::array<float, 4>, 2> expected_ms_depth{{
{0x2000 / 65535.0f, 0xe000 / 65535.0f, 0.0f, 0.0f}, {0x2000 / 65535.0f, 0xe000 / 65535.0f, 0.0f, 0.0f},
{0.0f, 0x4000 / 65535.0f, 0x8000 / 65535.0f, 1.0f}, {0.0f, 0x4000 / 65535.0f, 0x8000 / 65535.0f, 1.0f},