Handle stencil storage/depth transitions

This commit is contained in:
nmzik
2026-07-18 04:56:20 +02:00
parent df385a7aad
commit 78431dba4a
4 changed files with 81 additions and 6 deletions
@@ -326,6 +326,7 @@ inline constexpr std::array<VideoOutFormatPolicy, 6> VIDEO_OUT_FORMAT_POLICIES {
enum class DepthOverlap : uint8_t { enum class DepthOverlap : uint8_t {
None, None,
RetireSampled, RetireSampled,
RetireStorage,
ExpandTarget, ExpandTarget,
DiscardTarget, DiscardTarget,
Unsupported Unsupported
@@ -815,6 +816,23 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
return DepthOverlap::Unsupported; return DepthOverlap::Unsupported;
} }
// Mirrors storage -> depth-target binding transition. An inaccessible stencil aspect
// does not require the otherwise necessary image content copy.
[[nodiscard]] inline DepthOverlap ClassifyStorageDepthOverlap(const ImageInfo& storage,
const DepthTargetInfo& depth) {
const bool overlaps_depth = ImageRangeOverlaps(storage.address, storage.size, depth.address,
depth.size);
const bool overlaps_stencil = depth.stencil_address != 0 &&
ImageRangeOverlaps(storage.address, storage.size,
depth.stencil_address, depth.stencil_size);
if (!overlaps_depth && !overlaps_stencil) {
return DepthOverlap::None;
}
return !overlaps_depth && overlaps_stencil && !depth.stencil_access
? DepthOverlap::RetireStorage
: DepthOverlap::Unsupported;
}
[[nodiscard]] inline RenderTargetOverlap [[nodiscard]] inline RenderTargetOverlap
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context, ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context,
const RenderTargetInfo& target) { const RenderTargetInfo& target) {
+2 -2
View File
@@ -34,8 +34,8 @@ namespace Libs::Graphics {
uint32_t width, uint32_t height, uint32_t width, uint32_t height,
uint32_t depth) noexcept { uint32_t depth) noexcept {
return (format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) && return (format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) &&
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && width == 1 && type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && width != 0 &&
height == 1 && depth == 1) || height != 0 && depth == 1) ||
(format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) && (format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) &&
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && width != 0 && type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && width != 0 &&
height != 0 && depth == 1); height != 0 && depth == 1);
@@ -2533,6 +2533,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
std::shared_ptr<CachedImage> sampled_depth_source; std::shared_ptr<CachedImage> sampled_depth_source;
std::shared_ptr<CachedImage> native_depth_source; std::shared_ptr<CachedImage> native_depth_source;
std::shared_ptr<CachedImage> discarded_depth_source; std::shared_ptr<CachedImage> discarded_depth_source;
std::shared_ptr<CachedImage> retired_storage_source;
for (const auto& entry: m_images) { for (const auto& entry: m_images) {
auto& cached = *entry; auto& cached = *entry;
const bool overlaps = const bool overlaps =
@@ -2554,6 +2555,9 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
cached.buffer_modified, cached.ctx == ctx, info); cached.buffer_modified, cached.ctx == ctx, info);
break; break;
case CachedImage::Kind::StorageTexture: case CachedImage::Kind::StorageTexture:
overlap = cached.ctx == ctx ? ClassifyStorageDepthOverlap(cached.info, info)
: DepthOverlap::Unsupported;
break;
case CachedImage::Kind::RenderTarget: case CachedImage::Kind::RenderTarget:
case CachedImage::Kind::VideoOut: break; case CachedImage::Kind::VideoOut: break;
} }
@@ -2565,9 +2569,20 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
sampled_depth_source = entry; sampled_depth_source = entry;
} }
break; break;
case DepthOverlap::RetireStorage:
supported = cached.kind == CachedImage::Kind::StorageTexture &&
cached.gpu_modified && !cached.buffer_modified &&
!cached.info.IsCpuDirty() &&
retired_storage_source == nullptr && native_depth_source == nullptr &&
discarded_depth_source == nullptr;
if (supported) {
retired_storage_source = entry;
}
break;
case DepthOverlap::ExpandTarget: case DepthOverlap::ExpandTarget:
supported = supported =
cached.kind == CachedImage::Kind::DepthTarget && native_depth_source == nullptr; cached.kind == CachedImage::Kind::DepthTarget && native_depth_source == nullptr &&
retired_storage_source == nullptr;
if (supported) { if (supported) {
native_depth_source = entry; native_depth_source = entry;
} }
@@ -2575,6 +2590,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
case DepthOverlap::DiscardTarget: case DepthOverlap::DiscardTarget:
supported = cached.kind == CachedImage::Kind::DepthTarget && supported = cached.kind == CachedImage::Kind::DepthTarget &&
discarded_depth_source == nullptr && native_depth_source == nullptr; discarded_depth_source == nullptr && native_depth_source == nullptr;
supported = supported && retired_storage_source == nullptr;
if (supported) { if (supported) {
discarded_depth_source = entry; discarded_depth_source = entry;
} }
@@ -2591,8 +2607,17 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
retire.push_back(&cached); retire.push_back(&cached);
} }
RequireRetirementIsolation(retire, "depth target", info.address, info.size); RequireRetirementIsolation(retire, "depth target", info.address, info.size);
RetireImages(retire, native_depth_source != nullptr ? native_depth_source.get() if (retired_storage_source != nullptr) {
: discarded_depth_source.get()); m_memory_tracker.UnmarkRegionAsGpuModified(retired_storage_source->info.address,
retired_storage_source->info.size);
retired_storage_source->gpu_modified = false;
}
const auto* transition_source = native_depth_source != nullptr
? native_depth_source.get()
: (discarded_depth_source != nullptr
? discarded_depth_source.get()
: nullptr);
RetireImages(retire, transition_source);
const bool coherent_guest_stencil = const bool coherent_guest_stencil =
has_stencil && has_stencil &&
IsCoherentGuestImageSource(stencil_source, info.stencil_address, info.stencil_size); IsCoherentGuestImageSource(stencil_source, info.stencil_address, info.stencil_size);
@@ -2614,6 +2639,9 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
if (discarded_depth_source != nullptr) { if (discarded_depth_source != nullptr) {
command->RetainResourceUntilFence(discarded_depth_source); command->RetainResourceUntilFence(discarded_depth_source);
} }
if (retired_storage_source != nullptr) {
command->RetainResourceUntilFence(retired_storage_source);
}
if (native_depth_source != nullptr) { if (native_depth_source != nullptr) {
const auto& old = native_depth_source->depth; const auto& old = native_depth_source->depth;
if (old.layers >= info.layers || native_depth_source->image->layers != old.layers) { if (old.layers >= info.layers || native_depth_source->image->layers != old.layers) {
+30 -1
View File
@@ -9747,7 +9747,7 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() {
} else if (std::strcmp(kind, "depth-tile-extent") == 0) { } else if (std::strcmp(kind, "depth-tile-extent") == 0) {
resource = Ppsa14053DepthTileStorageTextureResource(); resource = Ppsa14053DepthTileStorageTextureResource();
descriptor = Ppsa14053DepthTileStorageTextureDescriptor(); descriptor = Ppsa14053DepthTileStorageTextureDescriptor();
descriptor.fields[2] |= 1u; descriptor.fields[4] |= 1u;
} else { } else {
std::_Exit(0x7e); std::_Exit(0x7e);
} }
@@ -10874,6 +10874,34 @@ void CheckStorageTextureSampledReuse() {
std::printf("[host] %-32s ok\n", "StorageTextureSampledReuse"); std::printf("[host] %-32s ok\n", "StorageTextureSampledReuse");
} }
void CheckStorageTextureDepthAlias() {
ImageInfo storage{};
storage.address = 0x201ae60000ull;
storage.size = 0x870000;
DepthTargetInfo depth{};
depth.address = 0x2046ca0000ull;
depth.size = 0x1fe0000;
depth.stencil_address = storage.address;
depth.stencil_size = storage.size;
Require("StorageTextureDepthAlias", "inactive stencil",
ClassifyStorageDepthOverlap(storage, depth) == DepthOverlap::RetireStorage,
"inactive stencil storage ownership was not retired");
depth.stencil_access = true;
Require("StorageTextureDepthAlias", "active stencil",
ClassifyStorageDepthOverlap(storage, depth) == DepthOverlap::Unsupported,
"active stencil storage contents were discarded");
depth.stencil_access = false;
storage.address = depth.address;
Require("StorageTextureDepthAlias", "depth aspect",
ClassifyStorageDepthOverlap(storage, depth) == DepthOverlap::Unsupported,
"depth-aspect storage contents were discarded");
storage.address = 0x2000000000ull;
Require("StorageTextureDepthAlias", "disjoint",
ClassifyStorageDepthOverlap(storage, depth) == DepthOverlap::None,
"disjoint storage image was classified as an alias");
std::printf("[host] %-32s ok\n", "StorageTextureDepthAlias");
}
[[noreturn]] void RunStorageTextureAccessDeathCase(const char *kind) { [[noreturn]] void RunStorageTextureAccessDeathCase(const char *kind) {
constexpr uintptr_t base = 0x0000000200300000ull; constexpr uintptr_t base = 0x0000000200300000ull;
constexpr uint64_t size = 0x10000; constexpr uint64_t size = 0x10000;
@@ -12900,6 +12928,7 @@ int main(int argc, char **argv) {
CheckStorageTextureVolumeUploadLayout(); CheckStorageTextureVolumeUploadLayout();
CheckStorageTextureGpuOwnedRebindState(); CheckStorageTextureGpuOwnedRebindState();
CheckStorageTextureSampledReuse(); CheckStorageTextureSampledReuse();
CheckStorageTextureDepthAlias();
CheckStorageTextureAccessPermissions(); CheckStorageTextureAccessPermissions();
CheckMetaOverlapDeaths(); CheckMetaOverlapDeaths();
CheckOverlappingMetadataViews(); CheckOverlappingMetadataViews();