From 7307518e4411776ecd855bfb8dc28f4d8490a1f9 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 5 Jul 2026 23:47:22 -0400 Subject: [PATCH] [vulkan] Re-wiring older ASTC decoding path + new helper function on wider ASTC textures --- src/video_core/host_shaders/astc_decoder.comp | 18 ++---------- .../renderer_vulkan/vk_compute_pass.cpp | 6 ++-- .../renderer_vulkan/vk_texture_cache.cpp | 28 +++++++++---------- .../renderer_vulkan/vk_texture_cache.h | 2 +- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/video_core/host_shaders/astc_decoder.comp b/src/video_core/host_shaders/astc_decoder.comp index b6270fd067..ba201d328d 100644 --- a/src/video_core/host_shaders/astc_decoder.comp +++ b/src/video_core/host_shaders/astc_decoder.comp @@ -44,7 +44,7 @@ layout(binding = BINDING_INPUT_BUFFER, std430) readonly restrict buffer InputBuf }; #ifdef VULKAN -layout(binding = BINDING_OUTPUT_IMAGE, rgba32f) uniform writeonly restrict image2DArray dest_image; +layout(binding = BINDING_OUTPUT_IMAGE) uniform writeonly restrict image2DArray dest_image; #else layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly restrict image2DArray dest_image; #endif @@ -137,17 +137,6 @@ uvec4 ReplicateByteTo16(uvec4 value) { return value * 0x101; } -// sRGB EOTF (decode: encoded value -> linear). Only used on the Vulkan path, where the -// destination image is a linear float format with no format-level sRGB tag of its own. -// Vectorized (single vec3 overload, no per-component scalar ternary) to match the style -// already used elsewhere in this file (see the HDR Mt piecewise selection) rather than the -// float/vec3 overload pair this replaces. -vec3 SRGBToLinear(vec3 c) { - const vec3 lo = c / 12.92; - const vec3 hi = pow(max((c + 0.055) / 1.055, vec3(0.0)), vec3(2.4)); - return mix(hi, lo, lessThanEqual(c, vec3(0.04045))); -} - uint ReplicateBitTo7(uint value) { return value * 127; } @@ -1405,9 +1394,6 @@ void DecompressBlock(ivec3 coord) { const vec4 Cf = vec4((C0 * (uvec4(64) - weight_vec) + C1 * weight_vec + uvec4(32)) / 64); p = Cf / 65535.0f; -#ifdef VULKAN - p.yzw = mix(p.yzw, SRGBToLinear(p.yzw), bvec3((block_height_mask & 0x80000000u) != 0u)); -#endif } #ifdef VULKAN @@ -1436,7 +1422,7 @@ void main() { uint offset = 0; offset += pos.z * layer_stride; offset += (block_y >> block_height) * block_size; - offset += (block_y & (block_height_mask & 0x7FFFFFFFu)) << GOB_SIZE_SHIFT; + offset += (block_y & block_height_mask) << GOB_SIZE_SHIFT; offset += (pos.x >> GOB_SIZE_X_SHIFT) << x_shift; offset += swizzle; diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index a6ec98d224..f361c34f44 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -564,7 +564,6 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, VideoCore::Surface::DefaultBlockWidth(image.info.format), VideoCore::Surface::DefaultBlockHeight(image.info.format), }; - const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image.info.format); scheduler.RequestOutsideRenderPassOperationContext(); const VkPipeline vk_pipeline = *pipeline; const VkImageAspectFlags aspect_mask = image.AspectMask(); @@ -614,15 +613,14 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map, ASSERT(params.destination == (std::array{0, 0, 0})); ASSERT(params.bytes_per_block_log2 == 4); scheduler.Record([this, num_dispatches_x, num_dispatches_y, num_dispatches_z, block_dims, - params, descriptor_data, is_srgb](vk::CommandBuffer cmdbuf) { + params, descriptor_data](vk::CommandBuffer cmdbuf) { const AstcPushConstants uniforms{ .blocks_dims = block_dims, .layer_stride = params.layer_stride, .block_size = params.block_size, .x_shift = params.x_shift, .block_height = params.block_height, - .block_height_mask = - params.block_height_mask | (is_srgb ? 0x8000'0000u : 0u), + .block_height_mask = params.block_height_mask, }; const VkDescriptorSet set = descriptor_allocator.Commit(); device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 29ec1a5127..f789c989d8 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -129,11 +129,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { return usage; } -// Whether an ASTC texture will be decoded via the GPU compute pass (ASTCDecoderPass / -// astc_decoder.comp) rather than the CPU ConvertImage path. Must stay the single source of -// truth for this decision: both the destination image's real format (below) and the -// AcceleratedUpload flag (Image::Image()) key off of it, and they must never disagree -- -// the compute shader's declared storage image format has to match what was actually allocated. [[nodiscard]] bool WillUseAcceleratedAstcDecode(const Device& device, const ImageInfo& info) { if (!IsPixelFormatASTC(info.format) || device.IsOptimalAstcSupported()) { return false; @@ -146,13 +141,16 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { info.size.depth == 1; } +[[nodiscard]] bool WillUseWidenedAstcFormat(const Device& device, const ImageInfo& info) { + return WillUseAcceleratedAstcDecode(device, info) && + !VideoCore::Surface::IsPixelFormatSRGB(info.format); +} + [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info, std::optional format_override = {}) { auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, info.format); if (format_override) { - // Accelerated ASTC HDR decode target: real (unclamped) values need a linear float - // format, not whatever the guest ASTC pixel format would normally map to. format_info.format = *format_override; format_info.attachable = false; format_info.storage = true; @@ -1586,10 +1584,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, runtime{&runtime_}, original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info, - WillUseAcceleratedAstcDecode(runtime_.device, info) + WillUseWidenedAstcFormat(runtime_.device, info) ? std::span{} : runtime->ViewFormats(info.format), - WillUseAcceleratedAstcDecode(runtime_.device, info) + WillUseWidenedAstcFormat(runtime_.device, info) ? std::make_optional(VK_FORMAT_R32G32B32A32_SFLOAT) : std::nullopt)), aspect_mask(ImageAspectMask(info.format)) { @@ -1622,7 +1620,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Uncompressed) { const auto& device = runtime->device.GetLogical(); - const VkFormat storage_format = WillUseAcceleratedAstcDecode(runtime->device, info) + const VkFormat storage_format = WillUseWidenedAstcFormat(runtime->device, info) ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_A8B8G8R8_UNORM_PACK32; for (s32 level = 0; level < info.resources.levels; ++level) { @@ -1979,7 +1977,9 @@ VkImageView Image::StorageImageView(s32 level) noexcept { auto format_info = MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format); if (WillUseAcceleratedAstcDecode(runtime->device, info)) { - format_info.format = VK_FORMAT_R32G32B32A32_SFLOAT; + format_info.format = WillUseWidenedAstcFormat(runtime->device, info) + ? VK_FORMAT_R32G32B32A32_SFLOAT + : VK_FORMAT_A8B8G8R8_UNORM_PACK32; } view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image), format_info.format); @@ -2147,9 +2147,9 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI SanitizeDepthStencilSwizzle(swizzle, device->SupportsDepthStencilSwizzleOne()); } } - uses_accelerated_astc_decode = WillUseAcceleratedAstcDecode(*device, image.info); + uses_widened_astc_format = WillUseWidenedAstcFormat(*device, image.info); auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); - if (uses_accelerated_astc_decode) { + if (uses_widened_astc_format) { format_info.format = VK_FORMAT_R32G32B32A32_SFLOAT; } const VkImageUsageFlags requested_view_usage = ImageUsageFlags(format_info, format); @@ -2287,7 +2287,7 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, if (image_format == Shader::ImageFormat::Typeless) { if (!typeless_storage_view) { auto info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); - if (uses_accelerated_astc_decode) { + if (uses_widened_astc_format) { info.format = VK_FORMAT_R32G32B32A32_SFLOAT; } typeless_storage_view = MakeView(info.format, VK_IMAGE_ASPECT_COLOR_BIT); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 0d11c71a42..027143fdbc 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -387,7 +387,7 @@ private: VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; u32 buffer_size = 0; - bool uses_accelerated_astc_decode = false; + bool uses_widened_astc_format = false; }; class ImageAlloc : public VideoCommon::ImageAllocBase {};