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 {
None,
RetireSampled,
RetireStorage,
ExpandTarget,
DiscardTarget,
Unsupported
@@ -815,6 +816,23 @@ ClassifyStorageBufferRebind(bool buffer_overlap, bool cached_gpu_modified,
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
ClassifyRenderTargetOverlap(const ImageInfo& sampled, bool sampled_gpu_modified, bool same_context,
const RenderTargetInfo& target) {
+2 -2
View File
@@ -34,8 +34,8 @@ namespace Libs::Graphics {
uint32_t width, uint32_t height,
uint32_t depth) noexcept {
return (format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) &&
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && width == 1 &&
height == 1 && depth == 1) ||
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && width != 0 &&
height != 0 && depth == 1) ||
(format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) &&
type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && width != 0 &&
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> native_depth_source;
std::shared_ptr<CachedImage> discarded_depth_source;
std::shared_ptr<CachedImage> retired_storage_source;
for (const auto& entry: m_images) {
auto& cached = *entry;
const bool overlaps =
@@ -2554,6 +2555,9 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
cached.buffer_modified, cached.ctx == ctx, info);
break;
case CachedImage::Kind::StorageTexture:
overlap = cached.ctx == ctx ? ClassifyStorageDepthOverlap(cached.info, info)
: DepthOverlap::Unsupported;
break;
case CachedImage::Kind::RenderTarget:
case CachedImage::Kind::VideoOut: break;
}
@@ -2565,9 +2569,20 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
sampled_depth_source = entry;
}
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:
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) {
native_depth_source = entry;
}
@@ -2575,6 +2590,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
case DepthOverlap::DiscardTarget:
supported = cached.kind == CachedImage::Kind::DepthTarget &&
discarded_depth_source == nullptr && native_depth_source == nullptr;
supported = supported && retired_storage_source == nullptr;
if (supported) {
discarded_depth_source = entry;
}
@@ -2591,8 +2607,17 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
retire.push_back(&cached);
}
RequireRetirementIsolation(retire, "depth target", info.address, info.size);
RetireImages(retire, native_depth_source != nullptr ? native_depth_source.get()
: discarded_depth_source.get());
if (retired_storage_source != nullptr) {
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 =
has_stencil &&
IsCoherentGuestImageSource(stencil_source, info.stencil_address, info.stencil_size);
@@ -2614,6 +2639,9 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
if (discarded_depth_source != nullptr) {
command->RetainResourceUntilFence(discarded_depth_source);
}
if (retired_storage_source != nullptr) {
command->RetainResourceUntilFence(retired_storage_source);
}
if (native_depth_source != nullptr) {
const auto& old = native_depth_source->depth;
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) {
resource = Ppsa14053DepthTileStorageTextureResource();
descriptor = Ppsa14053DepthTileStorageTextureDescriptor();
descriptor.fields[2] |= 1u;
descriptor.fields[4] |= 1u;
} else {
std::_Exit(0x7e);
}
@@ -10874,6 +10874,34 @@ void CheckStorageTextureSampledReuse() {
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) {
constexpr uintptr_t base = 0x0000000200300000ull;
constexpr uint64_t size = 0x10000;
@@ -12900,6 +12928,7 @@ int main(int argc, char **argv) {
CheckStorageTextureVolumeUploadLayout();
CheckStorageTextureGpuOwnedRebindState();
CheckStorageTextureSampledReuse();
CheckStorageTextureDepthAlias();
CheckStorageTextureAccessPermissions();
CheckMetaOverlapDeaths();
CheckOverlappingMetadataViews();