mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 05:46:56 +01:00
textures: keep incompatible mip layouts separate
This commit is contained in:
+5
-1
@@ -728,7 +728,11 @@ TextureCache::OverlapResult TextureCache::ResolveOverlap(const ImageInfo& reques
|
|||||||
(requested.IsVolume() || cached.info.IsVolume())) {
|
(requested.IsVolume() || cached.info.IsVolume())) {
|
||||||
return {ExpandImage(requested, cached_id)};
|
return {ExpandImage(requested, cached_id)};
|
||||||
}
|
}
|
||||||
if (requested.tile_mode != cached.info.tile_mode) {
|
// Equal pitch does not imply equal mip placement: a changed extent can move
|
||||||
|
// a level into or out of the mip tail. These are separate guest layouts.
|
||||||
|
if (requested.tile_mode != cached.info.tile_mode ||
|
||||||
|
(requested.resources == cached.info.resources &&
|
||||||
|
requested.mip_layout != cached.info.mip_layout)) {
|
||||||
if (safe_to_delete) {
|
if (safe_to_delete) {
|
||||||
FreeImage(cached_id);
|
FreeImage(cached_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4511,6 +4511,95 @@ public:
|
|||||||
0, nullptr);
|
0, nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr uint64_t mip_layout_offset = 0x27f0000;
|
||||||
|
std::vector<u32> mip_guest(0x2000 / sizeof(u32));
|
||||||
|
std::iota(mip_guest.begin(), mip_guest.end(), 0x51000000u);
|
||||||
|
ImageId previous{};
|
||||||
|
for (const uint32_t width : {32u, 64u, 32u}) {
|
||||||
|
if (previous) {
|
||||||
|
Require(name, "mip-layout CPU overwrite",
|
||||||
|
resources.HandleFault(PageFaultAccess::Write,
|
||||||
|
base + mip_layout_offset),
|
||||||
|
"mip-layout guest overwrite did not invalidate the old texture");
|
||||||
|
}
|
||||||
|
std::memcpy(memory + mip_layout_offset, mip_guest.data(),
|
||||||
|
mip_guest.size() * sizeof(u32));
|
||||||
|
TileSurfaceLayout surface{};
|
||||||
|
Require(name, "mip-tail layout",
|
||||||
|
TileGetTiledTextureLayout(
|
||||||
|
{.format = Prospero::BufferFormat::kBc3Srgb,
|
||||||
|
.tile_mode = Prospero::TileMode::kStandard4KB,
|
||||||
|
.width = width, .height = 64, .levels = 7}, surface) &&
|
||||||
|
surface.first_tail_level == (width == 32 ? 0u : 1u) &&
|
||||||
|
surface.total_size == (width == 32 ? 0x1000u : 0x2000u),
|
||||||
|
"BC3 width change did not move mip zero into or out of the tail");
|
||||||
|
ImageDesc desc{};
|
||||||
|
desc.type = BindingType::Texture;
|
||||||
|
desc.info.data = {base + mip_layout_offset, surface.total_size};
|
||||||
|
desc.info.pixel_format = vk::Format::eBc3SrgbBlock;
|
||||||
|
desc.info.guest_format = Prospero::BufferFormat::kBc3Srgb;
|
||||||
|
desc.info.extent = {width, 64, 1};
|
||||||
|
desc.info.resources = {7, 1};
|
||||||
|
desc.info.pitch = 64;
|
||||||
|
desc.info.bytes_per_block = 16;
|
||||||
|
desc.info.tile_mode = Prospero::TileMode::kStandard4KB;
|
||||||
|
desc.view_info.format = desc.info.pixel_format;
|
||||||
|
desc.view_info.type = vk::ImageViewType::e2D;
|
||||||
|
desc.view_info.level_count = 7;
|
||||||
|
desc.view_info.aspect = vk::ImageAspectFlagBits::eColor;
|
||||||
|
desc.view_info.usage = vk::ImageUsageFlagBits::eSampled;
|
||||||
|
std::vector<vk::BufferImageCopy> copies;
|
||||||
|
std::vector<u32> expected;
|
||||||
|
for (uint32_t level = 0; level < 7; level++) {
|
||||||
|
const auto &layout = surface.mips[level];
|
||||||
|
desc.info.mip_layout[level] = {
|
||||||
|
layout.offset, layout.size, layout.padded_width * 4,
|
||||||
|
layout.padded_height * 4};
|
||||||
|
vk::BufferImageCopy copy{};
|
||||||
|
copy.bufferOffset = expected.size() * sizeof(u32);
|
||||||
|
copy.imageSubresource = {vk::ImageAspectFlagBits::eColor, level, 0, 1};
|
||||||
|
copy.imageExtent = {std::max(width >> level, 1u),
|
||||||
|
std::max(64u >> level, 1u), 1};
|
||||||
|
copies.push_back(copy);
|
||||||
|
for (uint32_t y = 0; y < layout.height; y++) {
|
||||||
|
for (uint32_t x = 0; x < layout.width; x++) {
|
||||||
|
uint32_t offset = 0;
|
||||||
|
Require(name, "mip-tail CPU address",
|
||||||
|
TileGetBlockOffset(
|
||||||
|
surface.texture.block, x + layout.tail_x,
|
||||||
|
y + layout.tail_y, 0, offset),
|
||||||
|
"BC3 mip-tail block address could not be computed");
|
||||||
|
const auto word = (layout.offset + offset) / sizeof(u32);
|
||||||
|
expected.insert(expected.end(), mip_guest.begin() + word,
|
||||||
|
mip_guest.begin() + word + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto id = texture_cache.FindImage(desc);
|
||||||
|
Require(name, "distinct mip-layout backing", id && id != previous,
|
||||||
|
"different guest mip layouts reused the same native image");
|
||||||
|
(void)texture_cache.FindTexture(id, desc);
|
||||||
|
auto readback = CreateHostBuffer(
|
||||||
|
name, expected.size() * sizeof(u32),
|
||||||
|
vk::BufferUsageFlagBits::eTransferDst,
|
||||||
|
std::vector<u32>(expected.size()));
|
||||||
|
texture_cache.GetImage(id).Download(copies, readback.buffer, 0,
|
||||||
|
readback.size);
|
||||||
|
HostReadBarrier(readback.buffer, readback.size,
|
||||||
|
vk::PipelineStageFlagBits::eTransfer,
|
||||||
|
vk::AccessFlagBits::eTransferWrite);
|
||||||
|
scheduler.Finish();
|
||||||
|
Require(name, "mip-layout GPU contents",
|
||||||
|
ReadBuffer(name, readback, expected.size()) == expected,
|
||||||
|
"cached native copying contaminated the requested guest mip layout");
|
||||||
|
DestroyBuffer(&readback);
|
||||||
|
if (width == 64) {
|
||||||
|
// Leave only the larger backing so shrinking must reject its layout.
|
||||||
|
TextureCacheTestAccess::DeleteImage(texture_cache, previous);
|
||||||
|
}
|
||||||
|
previous = id;
|
||||||
|
}
|
||||||
|
|
||||||
// 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