From 0ce19357f615f42d5f0a6eff5e9dd44f8ab08922 Mon Sep 17 00:00:00 2001 From: nmzik Date: Fri, 4 Sep 2026 00:54:59 +0200 Subject: [PATCH] graphics: create depth images for comparison textures --- .../host_gpu/renderer/cache/textureCache.cpp | 5 +- .../renderer/pipeline/descriptors.cpp | 20 +++- tests/ShaderRecompilerComputeTests.cpp | 110 ++++++++++++++++++ 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index ca121548f..b5bf548dd 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -939,7 +939,7 @@ void TextureCache::UploadImage(Image& image, const ImageDesc& desc, Buffer& sour image.Upload(copies, linear.buffer, linear.offset, linear.size); }; - if (desc.type != BindingType::DepthTarget) { + if (!info.IsDepth()) { auto plan = BuildColorTransfer(image, desc.type, TransferDirection::Upload); if (!plan.valid) { EXIT("TextureCache: invalid color upload: binding=%u addr=0x%016" PRIx64 @@ -963,7 +963,8 @@ void TextureCache::UploadImage(Image& image, const ImageDesc& desc, Buffer& sour return; } - if (desc.type != BindingType::DepthTarget || info.samples != 1 || image.backing.samples != 1 || + if ((desc.type != BindingType::Texture && desc.type != BindingType::DepthTarget) || + info.samples != 1 || image.backing.samples != 1 || info.resources.layers == 0 || info.data.size % info.resources.layers != 0 || Prospero::NumBytesPerElement(info.guest_format) != info.bytes_per_block) { EXIT("TextureCache: invalid depth upload\n"); diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index ba81551e0..d5d14f38f 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -512,6 +512,20 @@ struct NullImageSpec { Prospero::BufferFormat guest_format; }; +static vk::Format TextureBackingFormat(const ShaderRecompiler::IR::ImageResource& resource, + Prospero::BufferFormat guest_format, + vk::Format view_format) { + if (!resource.depth_compare) { + return view_format; + } + const auto* policy = FindGuestDepthFormatPolicy(guest_format); + if (!IsSupportedSampledDepthResource(resource) || policy == nullptr) { + EXIT("unsupported comparison-sampled texture: format=%u\n", + static_cast(guest_format)); + } + return policy->depth_attachment_format; +} + static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) { switch (resource.numeric_class) { case Prospero::TextureNumericClass::Float: @@ -529,7 +543,7 @@ static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::Image TextureCache::BindingType binding) { const auto spec = NullTextureSpec(resource); TextureCache::ImageDesc desc {}; - desc.info.pixel_format = spec.format; + desc.info.pixel_format = TextureBackingFormat(resource, spec.guest_format, spec.format); desc.info.guest_format = spec.guest_format; desc.info.type = Prospero::ImageType::kColor2D; desc.info.extent = {1, 1, 1}; @@ -537,7 +551,7 @@ static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::Image desc.info.bytes_per_block = 4; desc.info.samples = 1; desc.info.mip_layout[0] = {0, 0, 1, 1}; - desc.view_info.format = desc.info.pixel_format; + desc.view_info.format = spec.format; desc.view_info.type = vk::ImageViewType::e2D; desc.view_info.aspect = vk::ImageAspectFlagBits::eColor; desc.view_info.usage = binding == TextureCache::BindingType::Storage @@ -753,7 +767,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); TextureCache::ImageDesc desc {}; desc.info.data = {address, size.size}; - desc.info.pixel_format = pixel_format; + desc.info.pixel_format = TextureBackingFormat(resource, format, pixel_format); desc.info.guest_format = format; desc.info.type = TextureBaseType(type); desc.info.extent = {width, height, volume ? depth : 1u}; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index e8ccaf86e..f0966232d 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -9328,6 +9328,114 @@ public: std::printf("[host] %-32s ok\n", name); } + void CheckSampledDepthTextureDiscovery() { + constexpr const char *name = "SampledDepthTextureDiscovery"; + constexpr uintptr_t base = 0x0000000204200000ull; + constexpr uint64_t allocation_size = 0x200000; + constexpr uint32_t width = 64; + constexpr uint32_t height = 64; + constexpr auto format = Prospero::BufferFormat::k32Float; + constexpr auto tile = Prospero::TileMode::kDepth; + EnsureRuntimeContext(); + + int64_t direct_offset = -1; + Require(name, "direct allocation", + Libs::LibKernel::Memory::KernelAllocateDirectMemory( + 0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(), + allocation_size, allocation_size, 0, &direct_offset) == 0, + "sampled-depth direct-memory allocation failed"); + void *mapped = reinterpret_cast(base); + Require(name, "direct mapping", + Libs::LibKernel::Memory::KernelMapDirectMemory( + &mapped, allocation_size, 0x3, 0x10, direct_offset, + allocation_size) == 0 && + mapped == reinterpret_cast(base), + "sampled-depth fixed mapping failed"); + std::memset(mapped, 0, allocation_size); + + { + RenderContext context(m_runtime_context); + auto &scheduler = context.GetCommandScheduler(); + HW::Context registers{}; + HW::UserConfig user_config{}; + HW::Shader shaders{}; + scheduler.Begin(registers, user_config, shaders); + auto &resources = context.GetGpuResources(); + auto &cache = resources.GetTextureCache(); + auto &executor = context.GetRenderExecutor(); + resources.MapMemory(base, allocation_size); + + const auto encoded_address = base >> 8u; + ShaderTextureResource descriptor{}; + descriptor.fields[0] = static_cast(encoded_address); + descriptor.fields[1] = + static_cast(encoded_address >> 32u) | + (static_cast(format) << 20u) | (((width - 1u) & 3u) << 30u); + descriptor.fields[2] = ((width - 1u) >> 2u) | ((height - 1u) << 14u); + descriptor.fields[3] = + DstSel(4, 4, 4, 4) | (static_cast(tile) << 20u) | + (static_cast(Prospero::ImageType::kColor2D) << 28u); + descriptor.fields[5] = 0x00700000u; + ShaderRecompiler::IR::DescriptorValue value{}; + std::copy(std::begin(descriptor.fields), std::end(descriptor.fields), + value.dwords.begin()); + value.dword_count = 8; + ShaderRecompiler::IR::ImageResource resource{}; + resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + resource.numeric_class = Prospero::TextureNumericClass::Float; + resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; + resource.read = true; + resource.depth_compare = true; + + auto binding = + RenderExecutorTestAccess::ResolveTexture(executor, resource, value); + const auto view = cache.FindTexture(binding.image_id, binding.desc); + const auto &image = cache.GetImage(binding.image_id); + const bool depth_view = std::ranges::any_of(image.views, [&](const auto &cached) { + return cached.view == view && cached.info.format == vk::Format::eD32Sfloat && + cached.info.aspect == vk::ImageAspectFlagBits::eDepth; + }); + Require(name, "uncached comparison image", + binding.desc.info.pixel_format == vk::Format::eD32Sfloat && + binding.desc.view_info.format == vk::Format::eR32Sfloat && + image.backing.format == vk::Format::eD32Sfloat && view != nullptr && + depth_view, + "comparison texture cache miss did not create a sampled D32 image"); + + ShaderRecompiler::IR::DescriptorValue null_value{}; + null_value.dword_count = 8; + auto null_binding = + RenderExecutorTestAccess::ResolveTexture(executor, resource, null_value); + const auto null_view = + cache.FindTexture(null_binding.image_id, null_binding.desc); + const auto &null_image = cache.GetImage(null_binding.image_id); + const bool null_depth_view = + std::ranges::any_of(null_image.views, [&](const auto &cached) { + return cached.view == null_view && + cached.info.format == vk::Format::eD32Sfloat && + cached.info.aspect == vk::ImageAspectFlagBits::eDepth; + }); + Require(name, "null comparison image", + null_binding.image_id != binding.image_id && null_image.info.data.Empty() && + null_image.backing.format == vk::Format::eD32Sfloat && + null_view != nullptr && null_depth_view, + "null comparison texture did not use a sampled D32 image"); + + resources.UnmapMemory(base, allocation_size); + scheduler.Finish(); + } + + Require(name, "unmap direct backing", + Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0, + "sampled-depth direct mapping release failed"); + Require(name, "release direct backing", + Libs::LibKernel::Memory::KernelReleaseDirectMemory( + direct_offset, allocation_size) == 0, + "sampled-depth direct-memory allocation release failed"); + std::printf("[gpu] %-32s ok\n", name); + } + Buffer CreateStorageBuffer(const char *shader_name, const std::vector &initial, size_t dword_count, bool device_address = false) { @@ -26097,6 +26205,7 @@ int main(int argc, char **argv) { VulkanHarness vulkan; CheckSampledDepthResource(); CheckSampledDepthDescriptor(vulkan.RuntimeRenderer()); + vulkan.CheckSampledDepthTextureDiscovery(); CheckDepthComparisonBindings(); RunCase(nullptr, ImageSampleOpcodeAliasUsesNormalCoords()); RunCase(nullptr, ImageSampleA16CompareBiasRdna2AddressOrder()); @@ -26213,6 +26322,7 @@ int main(int argc, char **argv) { vulkan.CheckRenderExecutorDccFixedClearFloat(); vulkan.CheckRenderExecutorColorStandardTileDiscovery(); vulkan.CheckRenderExecutorColorDepthTileDiscovery(); + vulkan.CheckSampledDepthTextureDiscovery(); vulkan.CheckRenderExecutorStencilBindingDiscovery(); vulkan.CheckUnifiedTextureCacheFlow(); vulkan.CheckBgra16Readback();