diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index ac7505556..a9da58c6e 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -130,10 +130,11 @@ bool TextureCache::SameBacking(const ImageInfo& cached, const ImageInfo& request TextureCache::BindingType TextureCache::UploadBinding(const Image& image) { if (image.info.IsDepth()) { - return image.info.tile_mode == Prospero::TileMode::kDepth || - image.info.tile_mode == Prospero::TileMode::kLinear - ? BindingType::DepthTarget - : BindingType::Texture; + if (image.info.tile_mode == Prospero::TileMode::kDepth || + image.info.tile_mode == Prospero::TileMode::kLinear) { + return BindingType::DepthTarget; + } + return BindingType::Texture; } if (image.usage.render_target) { return BindingType::RenderTarget; @@ -823,7 +824,6 @@ struct TextureCache::TextureTransferPlan { std::vector regions; std::vector tiles; uint64_t linear_size = 0; - bool tiled = false; bool swap_bgra16 = false; bool valid = false; }; @@ -846,52 +846,44 @@ TextureCache::TextureTransferPlan TextureCache::BuildTextureTransfer(const Image& image, BindingType binding, TransferDirection direction) const { const auto& info = image.info; + const bool upload = direction == TransferDirection::Upload; + const bool render_target = binding == BindingType::RenderTarget; + const bool video_out = binding == BindingType::VideoOut; auto format = info.guest_format; uint32_t layers = info.TransferLayers(); bool volume = info.IsVolume(); - bool allow_depth_tile = direction == TransferDirection::Upload; - const char* owner = - direction == TransferDirection::Upload ? "TextureCache" : "TextureCache readback"; + bool allow_depth_tile = upload; + const char* owner = "TextureCache readback"; TextureTransferPlan plan; - if (direction == TransferDirection::Upload) { - switch (binding) { - case BindingType::Texture: break; - case BindingType::Storage: owner = "StorageTextureCache"; break; - case BindingType::RenderTarget: - if (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 || - info.samples != 1 || image.backing.samples != 1) { - EXIT("TextureCache: invalid color-attachment upload\n"); - } - format = ImageOps::RenderTargetTransferFormat(info.bytes_per_block); - allow_depth_tile = true; - plan.swap_bgra16 = info.bgra16; - owner = "RenderTarget"; - break; - case BindingType::VideoOut: - if (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 || - info.samples != 1 || image.backing.samples != 1 || - info.metadata.compression != VideoOutCompression::Uncompressed) { - EXIT("TextureCache: invalid color-attachment upload\n"); - } - format = info.guest_format; - layers = info.resources.layers; - volume = false; - allow_depth_tile = false; - plan.swap_bgra16 = info.bgra16; - owner = "VideoOut"; - break; - case BindingType::DepthTarget: return plan; + plan.swap_bgra16 = info.bgra16 && (!upload || render_target || video_out); + if (render_target) { + format = ImageOps::RenderTargetTransferFormat(info.bytes_per_block); + } + if (video_out) { + allow_depth_tile = false; + } else if (render_target || binding == BindingType::Storage) { + allow_depth_tile = true; + } + if (upload) { + if ((render_target || video_out) && + (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 || + info.samples != 1 || image.backing.samples != 1)) { + EXIT("TextureCache: invalid color-attachment upload\n"); } - } else { - if (binding == BindingType::DepthTarget) { - return plan; + owner = "TextureCache"; + if (render_target) { + owner = "RenderTarget"; + } else if (binding == BindingType::Storage) { + owner = "StorageTextureCache"; + } else if (video_out) { + if (info.metadata.compression != VideoOutCompression::Uncompressed) { + EXIT("TextureCache: invalid color-attachment upload\n"); + } + layers = info.resources.layers; + volume = false; + owner = "VideoOut"; } - format = binding == BindingType::RenderTarget - ? ImageOps::RenderTargetTransferFormat(info.bytes_per_block) - : info.guest_format; - allow_depth_tile = binding == BindingType::Storage || binding == BindingType::RenderTarget; - plan.swap_bgra16 = info.bgra16; } plan.layout = TextureCalcUploadLayout(format, info.extent.width, info.extent.height, @@ -903,8 +895,7 @@ TextureCache::BuildTextureTransfer(const Image& image, BindingType binding, region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eDepth; } } - plan.tiled = plan.layout.surface.description.tile_mode != Prospero::TileMode::kLinear; - if (plan.tiled) { + if (plan.layout.surface.description.tile_mode != Prospero::TileMode::kLinear) { if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout, info.resources.levels, plan.tiles)) { return plan; @@ -959,7 +950,7 @@ void TextureCache::UploadImage(Image& image, Buffer& source, uint64_t source_off info.resources.layers, info.samples); } TileManager::Result linear {source.Handle(), source_offset, info.data.size}; - if (plan.tiled) { + if (!plan.tiles.empty()) { linear = m_tiler.Detile(source.Handle(), source_offset, info.data.size, plan.linear_size, plan.tiles); } @@ -1568,7 +1559,7 @@ void TextureCache::DownloadImageData(Image& image, Buffer& destination, uint64_t auto& texture = plan.texture; const auto transform = texture.swap_bgra16 ? TileManager::ColorTransform::SwapBgra16 : TileManager::ColorTransform::None; - if (!texture.tiled) { + if (texture.tiles.empty()) { if (transform == TileManager::ColorTransform::SwapBgra16) { auto linear = m_tiler.GetScratchBuffer(destination_size); image.Download(texture.regions, linear.buffer, 0, linear.size); @@ -1666,7 +1657,7 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uin if (texture.regions.empty()) { return false; } - if (texture.tiled) { + if (!texture.tiles.empty()) { texture.tiles.clear(); if (!TextureBuildGpuTileInfos(copy_size, texture.regions, texture.layout, levels, texture.tiles)) { diff --git a/src/graphics/host_gpu/renderer/image/imageView.h b/src/graphics/host_gpu/renderer/image/imageView.h index a77322595..1e8772550 100644 --- a/src/graphics/host_gpu/renderer/image/imageView.h +++ b/src/graphics/host_gpu/renderer/image/imageView.h @@ -92,15 +92,6 @@ SelectSampledColorView(vk::Format image_format, vk::Format view_format, uint32_t } } -[[nodiscard]] inline uint32_t -SelectSampledDepthView(vk::Format image_format, vk::Format view_format, uint32_t swizzle) noexcept { - if (IsSupportedSampledDepthView(image_format, view_format, swizzle)) { - return swizzle; - } - EXIT("unsupported sampled depth image view: image_format=%d view_format=%d swizzle=0x%03x\n", - static_cast(image_format), static_cast(view_format), swizzle); -} - [[nodiscard]] inline bool IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept { if (resource.resource_class != ShaderRecompiler::IR::ImageResourceClass::Sampled) { diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 4ced2bb11..ff376809a 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -335,40 +335,36 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co } static void ValidateSampledDepthBinding(const ShaderRecompiler::IR::ImageResource& resource, - const ShaderTextureResource& descriptor, const Image* image, - vk::Format view_format, uint64_t size) { - const bool resource_ok = IsSupportedSampledDepthResource(resource); - const bool descriptor_ok = - image != nullptr && IsSupportedSampledDepthDescriptor(descriptor, *image, resource.r128); - const bool encoding_ok = - image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image, resource.r128); - const bool format_ok = - image != nullptr && IsSupportedSampledDepthFormat(image->info.pixel_format, view_format); - if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) { + const ShaderTextureResource& descriptor, const Image& image, + vk::Format view_format, uint64_t size) { + const bool resource_ok = IsSupportedSampledDepthResource(resource); + const bool descriptor_ok = IsSupportedSampledDepthDescriptor(descriptor, image, resource.r128); + const bool encoding_ok = IsSupportedDepthTextureEncoding(descriptor, image, resource.r128); + const bool view_ok = + IsSupportedSampledDepthView(image.info.pixel_format, view_format, descriptor.DstSelXYZW()); + if (resource_ok && descriptor_ok && encoding_ok && view_ok) { return; } const auto descriptor_pitch = TileGetTexturePitch(descriptor.Format(), static_cast(descriptor.Width5()) + 1u, descriptor.TileMode()); - EXIT("unsupported sampled depth image: resource=%d descriptor=%d encoding=%d format=%d " + EXIT("unsupported sampled depth image: resource=%d descriptor=%d encoding=%d view=%d " "class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d " "guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u " "descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 " dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n", - resource_ok, descriptor_ok, encoding_ok, format_ok, + resource_ok, descriptor_ok, encoding_ok, view_ok, static_cast(resource.resource_class), static_cast(resource.numeric_class), static_cast(resource.dimension), static_cast(resource.mip_mode), resource.read, resource.written, resource.atomic, resource.depth_compare, static_cast(descriptor.Format()), - descriptor.DstSelXYZW(), - image == nullptr ? static_cast(vk::Format::eUndefined) - : static_cast(image->info.pixel_format), - static_cast(view_format), image == nullptr ? 0u : image->info.resources.layers, + descriptor.DstSelXYZW(), static_cast(image.info.pixel_format), + static_cast(view_format), image.info.resources.layers, static_cast(descriptor.Type()), descriptor.BaseArray5(), descriptor.Depth(), - descriptor_pitch, image == nullptr ? 0u : image->info.pitch, descriptor.Base40(), size, - descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3], - descriptor.fields[4], descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]); + descriptor_pitch, image.info.pitch, descriptor.Base40(), size, descriptor.fields[0], + descriptor.fields[1], descriptor.fields[2], descriptor.fields[3], descriptor.fields[4], + descriptor.fields[5], descriptor.fields[6], descriptor.fields[7]); } static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::ImageResource& resource, @@ -747,10 +743,12 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR ValidateStorageTexture(resource, descriptor, size.size); } - const auto* depth_format = resource.depth_compare ? FindGuestDepthFormatPolicy(format) : nullptr; - EXIT_NOT_IMPLEMENTED(resource.depth_compare && depth_format == nullptr); - const auto pixel_format = - depth_format != nullptr ? depth_format->depth_attachment_format : surface_format.vk_format; + auto pixel_format = surface_format.vk_format; + if (resource.depth_compare) { + const auto* depth_format = FindGuestDepthFormatPolicy(format); + EXIT_NOT_IMPLEMENTED(depth_format == nullptr); + pixel_format = depth_format->depth_attachment_format; + } const auto storage_view_format = storage && format == Prospero::BufferFormat::k32SInt ? vk::Format::eR32Uint : SrgbStorageViewFormat(pixel_format); @@ -789,9 +787,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR if (storage) { EXIT("depth target cannot be bound as a storage image\n"); } - ValidateSampledDepthBinding(resource, descriptor, image, pixel_format, size.size); - (void)SelectSampledDepthView(image->info.pixel_format, pixel_format, - descriptor.DstSelXYZW()); + ValidateSampledDepthBinding(resource, descriptor, *image, pixel_format, size.size); } else if (storage) { ValidateStorageColorView(image->info.pixel_format, view_format, descriptor.DstSelXYZW()); } else { diff --git a/src/graphics/host_gpu/renderer/render.h b/src/graphics/host_gpu/renderer/render.h index 81a12d30d..92d196a6f 100644 --- a/src/graphics/host_gpu/renderer/render.h +++ b/src/graphics/host_gpu/renderer/render.h @@ -219,7 +219,7 @@ private: friend struct RenderExecutorTestAccess; }; -[[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x, +[[nodiscard]] bool ResolveComputeBufferFill(const ShaderComputeInputInfo& input, uint32_t group_x, uint32_t group_y, uint32_t group_z, uint32_t mode, ShaderBufferResource& descriptor, uint32_t& packed_clear, uint64_t& size); diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 5a08f2295..6550feda3 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -39,9 +39,6 @@ namespace Libs::Graphics { static uint64_t BufferDescriptorSize(const ShaderBufferResource& descriptor) { const uint64_t records = descriptor.NumRecords(); const uint64_t stride = descriptor.Stride(); - if (stride != 0 && records > UINT64_MAX / stride) { - EXIT("compute buffer descriptor footprint overflow\n"); - } return stride == 0 ? records : records * stride; } @@ -51,9 +48,8 @@ static bool FillSourcesDisjoint(std::span(sources[i]); const auto bytes = BufferDescriptorSize(source); - if (source.Base48() > UINT64_MAX - bytes || - (source.Base48() < destination.End() && - destination.address < source.Base48() + bytes)) return false; + if (source.Base48() < destination.End() && destination.address < source.Base48() + bytes) + return false; } return true; } @@ -91,30 +87,23 @@ bool RenderExecutor::TryConsumeComputeMetaClear(const ShaderComputeInputInfo& in return false; } -bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x, +bool ResolveComputeBufferFill(const ShaderComputeInputInfo& input, uint32_t group_x, uint32_t group_y, uint32_t group_z, uint32_t mode, ShaderBufferResource& resolved_descriptor, uint32_t& resolved_clear, uint64_t& resolved_size) { - const auto& program = *input.stage.program; const auto& resources = input.stage.resources; const auto& fill = resources.uniform_fill; - if (fill.kind != ShaderRecompiler::IR::UniformFillKind::Buffer || fill.words == 0 || - fill.words > 4 || fill.resource >= resources.buffers.size() || - resources.buffers.size() != program.info.buffers.size()) { + if (fill.kind != ShaderRecompiler::IR::UniformFillKind::Buffer) { return false; } - const auto element_size = fill.words * sizeof(uint32_t); - const auto& resource = program.info.buffers[fill.resource]; - const auto& raw = resources.buffers[fill.resource]; - const auto descriptor = DecodeNativeDescriptor(raw); + const auto element_size = fill.words * sizeof(uint32_t); + const auto descriptor = + DecodeNativeDescriptor(resources.buffers[fill.resource]); constexpr std::array formats { Prospero::BufferFormat::k32UInt, Prospero::BufferFormat::k32_32UInt, Prospero::BufferFormat::k32_32_32UInt, Prospero::BufferFormat::k32_32_32_32UInt}; - if (!resource.formatted || !resource.written || resource.read || resource.atomic || - resource.scalar || descriptor.Stride() != element_size || - descriptor.Format() != formats[fill.words - 1] || descriptor.SwizzleEnabled() || - descriptor.IndexStride() != 0 || descriptor.AddTid() || - resource.packed_stride != descriptor.PackedStride() || raw.dword_count != 4 || + if (descriptor.Stride() != element_size || descriptor.Format() != formats[fill.words - 1] || + descriptor.SwizzleEnabled() || descriptor.IndexStride() != 0 || descriptor.AddTid() || descriptor.Base48() == 0) { return false; } @@ -128,7 +117,6 @@ bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t grou : static_cast(group_x) * input.threads_num[0]; const auto size = BufferDescriptorSize(descriptor); if (invocations != descriptor.NumRecords() || size == 0 || size > UINT32_MAX || - descriptor.Base48() > UINT64_MAX - size || (input.dispatch_thread_dimensions && (group_x % input.threads_num[0] != 0 || input.dispatch_threads_num[0] != group_x || input.dispatch_threads_num[1] != 1 || input.dispatch_threads_num[2] != 1))) { @@ -150,23 +138,17 @@ bool RenderExecutor::TryConsumeComputeImageClear(const ShaderComputeInputInfo& i const auto& fill = resources.uniform_fill; auto& cache = command.GetContext().GetTextureCache(); if (fill.kind == ShaderRecompiler::IR::UniformFillKind::Image) { - if (mode != 0x41u || input.dispatch_thread_dimensions || fill.words != 1 || fill.value > 255 || - resources.images.size() != 1 || program.info.images.size() != 1 || fill.resource != 0 || - resources.images[0].dword_count != 8 || input.threads_num[2] != 1 || - fill.group_stride[2] != 1) return false; + if (mode != 0x41u || input.dispatch_thread_dimensions || fill.value > 255 || + input.threads_num[2] != 1) + return false; const auto descriptor = DecodeNativeDescriptor(resources.images[0]); const auto& resource = program.info.images[0]; if (descriptor.IsNull() || descriptor.Format() != Prospero::BufferFormat::k8UInt || - descriptor.Type() != Prospero::ImageType::kColor2DArray || - descriptor.MetaCompress() || descriptor.WriteCompress() || - descriptor.BaseLevel() > descriptor.LastLevel() || + descriptor.Type() != Prospero::ImageType::kColor2DArray || descriptor.MetaCompress() || + descriptor.WriteCompress() || descriptor.BaseLevel() > descriptor.LastLevel() || descriptor.BaseLevel() > descriptor.MaxMip() || - descriptor.BaseArray5() > descriptor.Depth() || - descriptor.DstSelX() != 4 || (resource.shader_swizzle & 7u) != 4 || - resource.numeric_class != Prospero::TextureNumericClass::Uint || - resource.dimension != ShaderRecompiler::Decoder::ImageDimension::Dim2DArray || - resource.read || resource.atomic || !resource.written || - resource.mip_mode != ShaderRecompiler::IR::ImageMipMode::None) return false; + descriptor.BaseArray5() > descriptor.Depth() || descriptor.DstSelX() != 4) + return false; const std::array extents { std::max(1u, (descriptor.Width5() + 1u) >> descriptor.BaseLevel()), std::max(1u, (descriptor.Height5() + 1u) >> descriptor.BaseLevel()), @@ -202,7 +184,7 @@ bool RenderExecutor::TryConsumeComputeImageClear(const ShaderComputeInputInfo& i ShaderBufferResource descriptor; uint32_t packed_clear = 0; uint64_t size = 0; - if (!ResolveComputeImageClear(input, group_x, group_y, group_z, mode, descriptor, packed_clear, + if (!ResolveComputeBufferFill(input, group_x, group_y, group_z, mode, descriptor, packed_clear, size)) { return false; } @@ -219,10 +201,7 @@ bool RenderExecutor::TryConsumeComputeImageClear(const ShaderComputeInputInfo& i registered_metadata ? "tracked" : "deferred", input.stage.program->shader_hash, descriptor.Base48(), size, packed_clear); } - if (registered_metadata) { - return true; - } - return false; + return registered_metadata; } static std::atomic logged_clears {0}; if (logged_clears.fetch_add(1, std::memory_order_relaxed) < 32) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index bc4502af9..17a5324f0 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -5398,11 +5398,15 @@ public: const auto count = copy.imageExtent.width * copy.imageExtent.height; const auto *bytes = stencil_bytes + copy.bufferOffset; const bool depth = sub.aspectMask == vk::ImageAspectFlagBits::eDepth; + uint32_t expected = 0x91u; + if (depth) { + expected = std::bit_cast(0.75f); + } else if (sub.mipLevel == 1 && sub.baseArrayLayer == 1) { + expected = 0x35u; + } for (uint32_t pixel = 0; pixel < count; pixel++) { uint32_t actual = bytes[pixel]; if (depth) std::memcpy(&actual, bytes + pixel * 4, 4); - const uint32_t expected = depth ? std::bit_cast(0.75f) - : sub.mipLevel == 1 && sub.baseArrayLayer == 1 ? 0x35u : 0x91u; Require(name, "stencil clear preserves depth and neighbors", actual == expected, "selected stencil clear changed depth, another mip, or another layer"); } @@ -22760,29 +22764,18 @@ void CheckPs5GameExampleImageClearRuntimeShape() { auto result = ShaderRecompiler::CompileProgram( std::move(translated), options, specialization); ValidateSpirv("Ps5GameExampleImageClear", result.spirv); - return CompiledShader{std::move(result.spirv), std::move(result.program), - std::move(resources), {}}; + return resources; }; const auto code = MakeCode(); auto positive = Compile(code); - ShaderRecompiler::IR::CompiledShaderInfo program{}; - program.stage = positive.program.stage; - program.shader_hash = positive.program.shader_hash; - program.wave_size = positive.program.wave_size; - program.user_data_base = positive.program.user_data_base; - program.user_data_count = positive.program.user_data_count; - program.scratch_dwords = positive.program.scratch_dwords; - program.info = std::move(positive.program.info); - program.bindings = std::move(positive.program.bindings); - compute.stage.program = &program; - compute.stage.resources = positive.resources; + compute.stage.resources = positive; ShaderBufferResource descriptor{}; u32 packed_clear = 0; uint64_t size = 0; Require("Ps5GameExampleImageClear", "runtime shape", - ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, descriptor, + ResolveComputeBufferFill(compute, 64, 1, 1, 0x61u, descriptor, packed_clear, size) && descriptor.Base48() == 0x10000u && size == 64u * 16u && packed_clear == 0xff000000u, @@ -22790,22 +22783,22 @@ void CheckPs5GameExampleImageClearRuntimeShape() { auto wrong_index = code; wrong_index[0] = (wrong_index[0] & ~(0x3ffu << 16u)) | (0x347u << 16u); - compute.stage.resources = Compile(wrong_index).resources; + compute.stage.resources = Compile(wrong_index); Require("Ps5GameExampleImageClear", "add-before-shift address", - !ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, descriptor, + !ResolveComputeBufferFill(compute, 64, 1, 1, 0x61u, descriptor, packed_clear, size), "V_ADD_LSHL was mistaken for V_LSHL_ADD contiguous coverage"); user_data[7] ^= 1u; - compute.stage.resources = Compile(code).resources; + compute.stage.resources = Compile(code); Require("Ps5GameExampleImageClear", "non-repeated clear", - !ResolveComputeImageClear(compute, 64, 1, 1, 0x61u, descriptor, + !ResolveComputeBufferFill(compute, 64, 1, 1, 0x61u, descriptor, packed_clear, size), "non-uniform uint4 data was replaced with a color clear"); - compute.stage.resources = positive.resources; + compute.stage.resources = positive; compute.dispatch_threads_num[0] = 32; Require("Ps5GameExampleImageClear", "partial dispatch", - !ResolveComputeImageClear(compute, 32, 1, 1, 0x61u, descriptor, + !ResolveComputeBufferFill(compute, 32, 1, 1, 0x61u, descriptor, packed_clear, size), "partial buffer coverage was classified as a complete clear"); @@ -22821,46 +22814,43 @@ void CheckPs5GameExampleImageClearRuntimeShape() { scalar_code.push_back(EncodeMubuf1(1, 0, 0)); AppendEnd(&scalar_code); auto scalar = Compile(scalar_code); - program.info = scalar.program.info; - compute.stage.resources = scalar.resources; + compute.stage.resources = scalar; Require("Ps5GameExampleImageClear", "inline scalar fill", - ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size) && descriptor.Base48() == 0x200000u && size == 256u && packed_clear == 0u, "GTA3's actual scalar store was not recognized from IR"); Require("Ps5GameExampleImageClear", "excess dispatch", - !ResolveComputeImageClear(compute, 2, 1, 1, 0x41u, descriptor, + !ResolveComputeBufferFill(compute, 2, 1, 1, 0x41u, descriptor, packed_clear, size), "excess invocation coverage was accepted as a fill"); - auto alias = scalar.resources.buffers.front(); + auto alias = scalar.buffers.front(); compute.stage.resources.buffers.push_back(alias); - program.info.buffers.push_back({.read = true, .scalar = true}); Require("Ps5GameExampleImageClear", "aliased scalar input", - !ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + !ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size), "a scalar read aliasing the destination was accepted as uniform"); - program.info = scalar.program.info; - compute.stage.resources = scalar.resources; + compute.stage.resources = scalar; compute.stage.resources.buffers[0].dwords[3] = (static_cast(Prospero::BufferFormat::k32Float) << 12u) | 0x204u; Require("Ps5GameExampleImageClear", "wrong store format", - !ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + !ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size), "a format that changes the stored value was accepted as a uint fill"); // A body change preserving every descriptor and dispatch field must change // the result. scalar_code[2] = EncodeVop1(0x01u, 1, InlineU32(7)); - compute.stage.resources = Compile(scalar_code).resources; + compute.stage.resources = Compile(scalar_code); Require("Ps5GameExampleImageClear", "changed store value", - ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size) && packed_clear == 7u, "clear recognition ignored the shader's actual stored value"); scalar_code[2] = EncodeVop1(0x01u, 1, Vgpr(0)); - compute.stage.resources = Compile(scalar_code).resources; + compute.stage.resources = Compile(scalar_code); Require("Ps5GameExampleImageClear", "varying store value", - !ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + !ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size), "a varying store with identical resources was treated as a fill"); @@ -22880,17 +22870,16 @@ void CheckPs5GameExampleImageClearRuntimeShape() { AppendEnd(&scalar_code); clean_scalar = true; auto loaded = Compile(scalar_code); - program.info = loaded.program.info; - compute.stage.resources = loaded.resources; + compute.stage.resources = loaded; Require("Ps5GameExampleImageClear", "scalar-loaded fill", - ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size) && packed_clear == scalar_clear && descriptor.Base48() == 0x200000u, "GTA3's scalar input was confused with its destination"); clean_scalar = false; - compute.stage.resources = Compile(scalar_code).resources; + compute.stage.resources = Compile(scalar_code); Require("Ps5GameExampleImageClear", "unavailable clean scalar", - !ResolveComputeImageClear(compute, 1, 1, 1, 0x41u, descriptor, + !ResolveComputeBufferFill(compute, 1, 1, 1, 0x41u, descriptor, packed_clear, size), "a scalar without a clean reader was replaced by a fill"); std::printf("[host] %-32s ok\n", "Ps5GameExampleImageClear"); @@ -23178,12 +23167,6 @@ void CheckRenderTargetFormatContract() { (void)SelectSampledColorView(vk::Format::eR8G8B8A8Unorm, vk::Format::eR8G8B8A8Unorm, DstSel(7, 6, 5, 3)); - } else if (std::strcmp(kind, "sampled-depth-format") == 0) { - (void)SelectSampledDepthView(vk::Format::eD24UnormS8Uint, - vk::Format::eR8Unorm, DstSel(4, 4, 4, 4)); - } else if (std::strcmp(kind, "sampled-depth-swizzle") == 0) { - (void)SelectSampledDepthView(vk::Format::eD32SfloatS8Uint, - vk::Format::eR32Sfloat, DstSel(4, 5, 6, 7)); } else if (std::strcmp(kind, "storage-incompatible-format") == 0) { ValidateStorageColorView(vk::Format::eR8G8B8A8Srgb, vk::Format::eR16G16B16A16Unorm, @@ -23397,34 +23380,44 @@ void CheckSampledColorViews() { vk::Format::eR8G8B8A8Unorm, DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7), "compatible integer render-target sampled view was rejected"); + Require("SampledColorViews", "invalid depth format", + !IsSupportedSampledDepthView(vk::Format::eD24UnormS8Uint, + vk::Format::eR8Unorm, + DstSel(4, 4, 4, 4)), + "incompatible sampled depth format was accepted"); + Require("SampledColorViews", "invalid depth swizzle", + !IsSupportedSampledDepthView(vk::Format::eD32SfloatS8Uint, + vk::Format::eR32Sfloat, + DstSel(4, 5, 6, 7)), + "incompatible sampled depth swizzle was accepted"); Require("SampledColorViews", "D32 depth target", - SelectSampledDepthView(vk::Format::eD32SfloatS8Uint, - vk::Format::eR32Sfloat, - DstSel(4, 4, 4, 4)) == DstSel(4, 4, 4, 4), + IsSupportedSampledDepthView(vk::Format::eD32SfloatS8Uint, + vk::Format::eR32Sfloat, + DstSel(4, 4, 4, 4)), "D32 depth target did not select its depth-aspect view"); Require("SampledColorViews", "D16 R000 depth target", - SelectSampledDepthView(vk::Format::eD16Unorm, vk::Format::eR16Unorm, - DstSel(4, 0, 0, 0)) == DstSel(4, 0, 0, 0), + IsSupportedSampledDepthView( + vk::Format::eD16Unorm, vk::Format::eR16Unorm, DstSel(4, 0, 0, 0)), "D16 depth target did not select its R000 depth-aspect view"); Require("SampledColorViews", "D16S8 R001 depth target", - SelectSampledDepthView(vk::Format::eD16UnormS8Uint, - vk::Format::eR16Unorm, - DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), + IsSupportedSampledDepthView(vk::Format::eD16UnormS8Uint, + vk::Format::eR16Unorm, + DstSel(4, 0, 0, 1)), "D16S8 depth target did not select its R001 depth-aspect view"); Require("SampledColorViews", "promoted D24S8 R001 depth target", - SelectSampledDepthView(vk::Format::eD24UnormS8Uint, - vk::Format::eR16Unorm, - DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), + IsSupportedSampledDepthView(vk::Format::eD24UnormS8Uint, + vk::Format::eR16Unorm, + DstSel(4, 0, 0, 1)), "D24S8 host fallback did not preserve the guest R16 depth view"); Require("SampledColorViews", "promoted D32S8 R001 depth target", - SelectSampledDepthView(vk::Format::eD32SfloatS8Uint, - vk::Format::eR16Unorm, - DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), + IsSupportedSampledDepthView(vk::Format::eD32SfloatS8Uint, + vk::Format::eR16Unorm, + DstSel(4, 0, 0, 1)), "D32S8 host fallback did not preserve the guest R16 depth view"); Require("SampledColorViews", "D32S8 R001 depth target", - SelectSampledDepthView(vk::Format::eD32SfloatS8Uint, - vk::Format::eR32Sfloat, - DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), + IsSupportedSampledDepthView(vk::Format::eD32SfloatS8Uint, + vk::Format::eR32Sfloat, + DstSel(4, 0, 0, 1)), "D32S8 depth target did not select its R001 depth-aspect view"); ShaderRecompiler::IR::ImageResource storage_resource{}; storage_resource.resource_class = @@ -23470,10 +23463,9 @@ void CheckSampledColorViews() { "GetModuleFileName failed"); for (const char *kind : {"sampled-invalid-selector", "sampled-incompatible-format", - "sampled-invalid-high", "sampled-depth-format", "sampled-depth-swizzle", - "storage-incompatible-format", "storage-kind", "storage-no-write", - "storage-nonuint-atomic", "storage-compare", "storage-dimension", - "volume-mip-count", "volume-slice-range"}) { + "sampled-invalid-high", "storage-incompatible-format", "storage-kind", + "storage-no-write", "storage-nonuint-atomic", "storage-compare", + "storage-dimension", "volume-mip-count", "volume-slice-range"}) { std::string command = std::string("\"") + path + "\" --image-view-death " + kind; std::vector mutable_command(command.begin(), command.end());