graphics: preserve full tiled array backing in image-to-buffer copies

This commit is contained in:
Claxten
2026-10-07 20:03:59 +04:00
committed by nmzik
parent 743fdc6990
commit dd754065d8
2 changed files with 80 additions and 7 deletions
+76 -1
View File
@@ -5112,7 +5112,7 @@ public:
void CheckUnifiedTextureCacheFlow() {
constexpr const char *name = "UnifiedTextureCacheFlow";
constexpr uintptr_t base = 0x0000000200600000ull;
constexpr uint64_t allocation_size = 0x2c00000;
constexpr uint64_t allocation_size = 0x3000000;
constexpr uint64_t allocation_alignment = 0x200000;
EnsureRuntimeContext();
RenderContext context(m_runtime_context);
@@ -5670,6 +5670,81 @@ public:
"raw render-target copying overwrote the BC5 guest mip layout");
DestroyBuffer(&bc5_readback);
{
constexpr uint64_t tiled_array_offset = 0x2c00000;
constexpr uint32_t tiled_levels = 5, tiled_layers = 6;
TileSurfaceLayout surface{};
Require(name, "tiled array alias layout",
TileGetTiledTextureLayout(
{Prospero::BufferFormat::k32UInt, Prospero::TileMode::kStandard64KB,
TileSurfaceDimension::Dim2D, 256, 256, 1, tiled_levels, tiled_layers},
surface) && surface.total_size == 0x240000 &&
surface.block_slice_size == 0x60000 &&
surface.mips[0].offset + surface.mips[0].size * tiled_layers == 0x1a0000,
"fixture lost the gap between an array mip span and its full backing");
auto tiled_array = MakeLinearDesc(
base + tiled_array_offset, surface.total_size, vk::Format::eR32Uint,
Prospero::BufferFormat::k32UInt, Prospero::ImageType::kColor2D,
{256, 256, 1}, tiled_layers, sizeof(uint32_t), 1);
tiled_array.info.tile_mode = Prospero::TileMode::kStandard64KB;
tiled_array.info.resources.levels = tiled_levels;
tiled_array.view_info.level_count = tiled_levels;
for (uint32_t level = 0; level < tiled_levels; ++level) {
const auto &mip = surface.mips[level];
tiled_array.info.mip_layout[level] = {
mip.offset, mip.size * tiled_layers, mip.padded_width, mip.padded_height};
}
std::memset(memory + tiled_array_offset, 0, surface.total_size);
const auto tiled_array_id = texture_cache.FindImage(tiled_array);
(void)texture_cache.FindTexture(tiled_array_id, tiled_array);
constexpr uint32_t all_mips = 0x12345678u, last_mip = 0x89abcdefu;
vk::ClearValue clear{};
clear.color.uint32[0] = all_mips;
TextureCacheTestAccess::ClearImage(
texture_cache, scheduler.Current(), tiled_array_id,
{vk::ImageAspectFlagBits::eColor, 0, tiled_levels, 0, tiled_layers}, clear);
clear.color.uint32[0] = last_mip;
TextureCacheTestAccess::ClearImage(
texture_cache, scheduler.Current(), tiled_array_id,
{vk::ImageAspectFlagBits::eColor, tiled_levels - 1, 1, tiled_layers - 1, 1}, clear);
Libs::Graphics::Buffer full_array(
m_runtime_context, scheduler, MemoryUsage::DeviceLocal,
tiled_array.info.data.address, AllFlags, surface.total_size);
Libs::Graphics::Buffer partial_array(
m_runtime_context, scheduler, MemoryUsage::DeviceLocal,
tiled_array.info.data.address, AllFlags, 0x1a0000);
Require(name, "tiled array alias containment",
BufferCacheTestAccess::SynchronizeBufferFromImage(
resources.GetBufferCache(), full_array,
tiled_array.info.data.address, surface.total_size) &&
!BufferCacheTestAccess::SynchronizeBufferFromImage(
resources.GetBufferCache(), partial_array,
tiled_array.info.data.address, 0x1a0000),
"full array synchronization failed or accepted an incomplete slice chain");
auto readback = CreateHostBuffer(name, 2 * sizeof(uint32_t),
vk::BufferUsageFlagBits::eTransferDst, {0, 0});
TransferReadBarrier(full_array.Handle(), surface.total_size);
for (uint32_t probe = 0; probe < 2; ++probe) {
const auto &mip = surface.mips[probe == 0 ? 0 : tiled_levels - 1];
uint32_t within_block = 0;
Require(name, "tiled array probe address",
TileGetBlockOffset(surface.texture.block, mip.tail_x, mip.tail_y,
0, within_block),
"last-layer mip origin has no guest address");
const vk::BufferCopy copy{
(tiled_layers - 1) * surface.block_slice_size + mip.offset + within_block,
probe * sizeof(uint32_t), sizeof(uint32_t)};
command.Handle().copyBuffer(full_array.Handle(), readback.buffer, 1, &copy);
}
HostReadBarrier(readback.buffer, readback.size, vk::PipelineStageFlagBits::eTransfer,
vk::AccessFlagBits::eTransferWrite);
scheduler.Finish();
Require(name, "tiled array last-layer contents",
ReadBuffer(name, readback, 2) == std::vector<u32>{all_mips, last_mip},
"array synchronization lost GPU contents beyond the first mip span");
DestroyBuffer(&readback);
}
// A formatted Buffer read must use the private
// Exercise the cache-native image-copy path. Use a request larger
// than the stream shortcut and poison guest backing