graphics: preserve HTILE metadata across native image replacement

This commit is contained in:
nmzik
2026-10-17 17:31:25 +02:00
parent 6aa3846fb2
commit d8c4a9af38
2 changed files with 24 additions and 10 deletions
+1 -9
View File
@@ -263,15 +263,6 @@ void TextureCache::DeleteImage(ImageId id) {
EXIT("TextureCache: deleting a GPU-modified image without resolving its contents\n"); EXIT("TextureCache: deleting a GPU-modified image without resolving its contents\n");
} }
m_download_images.erase(id); m_download_images.erase(id);
if (image->info.HasMetadata()) {
const auto metadata = m_surface_metas.find(image->info.metadata.range.address);
if (metadata != m_surface_metas.end() &&
image->info.metadata.kind == ImageMetadataKind::Htile &&
metadata->second.type == MetaDataInfo::Type::HTile) {
// A later binding may have reused this address for another metadata type.
m_surface_metas.erase(metadata);
}
}
UnregisterImage(id); UnregisterImage(id);
if (m_scheduler.Active()) { if (m_scheduler.Active()) {
m_scheduler.DeferOperation([this, id] { m_slot_images.erase(id); }); m_scheduler.DeferOperation([this, id] { m_slot_images.erase(id); });
@@ -1885,6 +1876,7 @@ void TextureCache::UnmapMemory(uint64_t address, uint64_t size) {
EXIT("TextureCache: invalid unmap range\n"); EXIT("TextureCache: invalid unmap range\n");
} }
std::scoped_lock lock {m_lock}; std::scoped_lock lock {m_lock};
// HTILE belongs to guest memory, independently of native image replacements.
for (auto metadata = m_surface_metas.begin(); metadata != m_surface_metas.end();) { for (auto metadata = m_surface_metas.begin(); metadata != m_surface_metas.end();) {
const auto base = metadata->first; const auto base = metadata->first;
if (base >= address && base < address + size) { if (base >= address && base < address + size) {
+23 -1
View File
@@ -6572,6 +6572,11 @@ public:
htile_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth; htile_depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth;
htile_depth.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; htile_depth.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
const auto htile_depth_image = texture_cache.FindImage(htile_depth); const auto htile_depth_image = texture_cache.FindImage(htile_depth);
(void)texture_cache.FindDepthTarget(htile_depth_image, htile_depth);
Require(name, "HTile depth metadata registration",
texture_cache.ClearMeta(htile_depth.info.metadata.range.address) &&
texture_cache.TouchMeta(htile_depth.info.metadata.range.address, 0, false),
"depth target did not register independent slice clear state");
vk::ClearValue htile_clear{}; vk::ClearValue htile_clear{};
htile_clear.depthStencil.depth = 0.25f; htile_clear.depthStencil.depth = 0.25f;
TextureCacheTestAccess::ClearImage( TextureCacheTestAccess::ClearImage(
@@ -6605,6 +6610,11 @@ public:
Require(name, "HTile depth storage prefix view", Require(name, "HTile depth storage prefix view",
texture_cache.FindTexture(id, htile_storage) != nullptr, texture_cache.FindTexture(id, htile_storage) != nullptr,
"converted depth prefix has no storage view"); "converted depth prefix has no storage view");
Require(name, "HTile metadata survives native depth replacement",
texture_cache.IsMeta(htile_depth.info.metadata.range.address) &&
!texture_cache.IsMetaCleared(htile_depth.info.metadata.range.address, 0) &&
texture_cache.IsMetaCleared(htile_depth.info.metadata.range.address, 1),
"storage conversion discarded guest metadata or its slice clear state");
htile_storage_image = id; htile_storage_image = id;
} }
auto htile_readback = CreateHostBuffer( auto htile_readback = CreateHostBuffer(
@@ -6625,6 +6635,11 @@ public:
std::vector<u32>(htile_layers, std::bit_cast<u32>(0.25f)), std::vector<u32>(htile_layers, std::bit_cast<u32>(0.25f)),
"partial storage conversion lost native depth data outside its view"); "partial storage conversion lost native depth data outside its view");
DestroyBuffer(&htile_readback); DestroyBuffer(&htile_readback);
texture_cache.UnmapMemory(htile_depth.info.metadata.range.address,
htile_depth.info.metadata.range.size);
Require(name, "HTile metadata allocation unmap",
!texture_cache.IsMeta(htile_depth.info.metadata.range.address),
"unmapped guest metadata retained its registration");
auto layered_stencil_desc = MakeLinearDesc( auto layered_stencil_desc = MakeLinearDesc(
base + 0x27d4000, 6 * 4 * sizeof(float), base + 0x27d4000, 6 * 4 * sizeof(float),
@@ -7898,9 +7913,16 @@ public:
"retiring the old DCC image erased the live HTile slice state"); "retiring the old DCC image erased the live HTile slice state");
texture_cache.UnmapMemory(reused_depth.info.data.address, texture_cache.UnmapMemory(reused_depth.info.data.address,
reused_depth.info.data.size); reused_depth.info.data.size);
Require(name, "HTile allocation outlives native depth retirement",
texture_cache.IsMeta(base + 0x28000) &&
!texture_cache.IsMetaCleared(base + 0x28000, 0) &&
texture_cache.IsMetaCleared(base + 0x28000, 1),
"retiring depth data erased an independent metadata allocation");
texture_cache.UnmapMemory(reused_depth.info.metadata.range.address,
reused_depth.info.metadata.range.size);
Require(name, "reused metadata final retirement", Require(name, "reused metadata final retirement",
!texture_cache.IsMeta(base + 0x28000), !texture_cache.IsMeta(base + 0x28000),
"retiring the HTile image left its metadata registered"); "unmapping the HTile allocation left its metadata registered");
constexpr uint64_t partial_unmap_image_offset = 0x2700000; constexpr uint64_t partial_unmap_image_offset = 0x2700000;
auto partial_unmap_image = auto partial_unmap_image =