diff --git a/src/graphics/host_gpu/renderer/imageInfo.h b/src/graphics/host_gpu/renderer/imageInfo.h index 5fcec1981..98c464eee 100644 --- a/src/graphics/host_gpu/renderer/imageInfo.h +++ b/src/graphics/host_gpu/renderer/imageInfo.h @@ -326,6 +326,7 @@ inline constexpr std::array 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) { diff --git a/src/graphics/host_gpu/renderer/imageView.h b/src/graphics/host_gpu/renderer/imageView.h index 728d10b37..99041fe4a 100644 --- a/src/graphics/host_gpu/renderer/imageView.h +++ b/src/graphics/host_gpu/renderer/imageView.h @@ -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); diff --git a/src/graphics/host_gpu/renderer/textureCache.cpp b/src/graphics/host_gpu/renderer/textureCache.cpp index 588615d0a..bad06fd7a 100644 --- a/src/graphics/host_gpu/renderer/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/textureCache.cpp @@ -2533,6 +2533,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G std::shared_ptr sampled_depth_source; std::shared_ptr native_depth_source; std::shared_ptr discarded_depth_source; + std::shared_ptr 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) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 8537b1e02..5131cd347 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -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();