mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
graphics: preserve full tiled array backing in image-to-buffer copies
This commit is contained in:
+4
-6
@@ -1792,14 +1792,12 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uin
|
|||||||
const auto available = buffer.Size() - buf_offset;
|
const auto available = buffer.Size() - buf_offset;
|
||||||
uint32_t levels = 0;
|
uint32_t levels = 0;
|
||||||
uint64_t copy_size = 0;
|
uint64_t copy_size = 0;
|
||||||
if (image.info.IsVolume()) {
|
if (buffer.IsInBounds(image.info.data.address, image.info.data.size)) {
|
||||||
// Volume mips contain strided block slices, so a mip's linear span cannot prove that
|
|
||||||
// every retained slice fits. Keep volume synchronization whole-image only.
|
|
||||||
if (!buffer.IsInBounds(image.info.data.address, image.info.data.size)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
levels = image.info.resources.levels;
|
levels = image.info.resources.levels;
|
||||||
copy_size = image.info.data.size;
|
copy_size = image.info.data.size;
|
||||||
|
} else if (image.info.IsVolume() || image.info.resources.layers > 1) {
|
||||||
|
// Array and volume slices are strided across the full mip chain.
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
for (; levels < image.info.resources.levels; ++levels) {
|
for (; levels < image.info.resources.levels; ++levels) {
|
||||||
const auto& mip = image.info.mip_layout[levels];
|
const auto& mip = image.info.mip_layout[levels];
|
||||||
|
|||||||
@@ -5112,7 +5112,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 = 0x2c00000;
|
constexpr uint64_t allocation_size = 0x3000000;
|
||||||
constexpr uint64_t allocation_alignment = 0x200000;
|
constexpr uint64_t allocation_alignment = 0x200000;
|
||||||
EnsureRuntimeContext();
|
EnsureRuntimeContext();
|
||||||
RenderContext context(m_runtime_context);
|
RenderContext context(m_runtime_context);
|
||||||
@@ -5670,6 +5670,81 @@ public:
|
|||||||
"raw render-target copying overwrote the BC5 guest mip layout");
|
"raw render-target copying overwrote the BC5 guest mip layout");
|
||||||
DestroyBuffer(&bc5_readback);
|
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, ©);
|
||||||
|
}
|
||||||
|
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
|
// A formatted Buffer read must use the private
|
||||||
// Exercise the cache-native image-copy path. Use a request larger
|
// Exercise the cache-native image-copy path. Use a request larger
|
||||||
// than the stream shortcut and poison guest backing
|
// than the stream shortcut and poison guest backing
|
||||||
|
|||||||
Reference in New Issue
Block a user