From 331ae6c2e59bc2832b228cbe9eea2f7fea6bb7a2 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Sat, 4 Jan 2025 05:48:55 -0800 Subject: [PATCH] video_core: Implement conversion for uncommon/unsupported number formats. --- .../frontend/translate/export.cpp | 9 ++- .../ir/passes/resource_tracking_pass.cpp | 18 ++++-- src/shader_recompiler/ir/reinterpret.h | 62 +++++++++++++++++++ src/shader_recompiler/runtime_info.h | 1 + src/video_core/amdgpu/liverpool.h | 4 ++ src/video_core/amdgpu/resource.h | 39 +++++++++++- .../renderer_vulkan/vk_graphics_pipeline.h | 1 + .../renderer_vulkan/vk_pipeline_cache.cpp | 3 + 8 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/shader_recompiler/frontend/translate/export.cpp b/src/shader_recompiler/frontend/translate/export.cpp index 83240e17f..38ff9ae14 100644 --- a/src/shader_recompiler/frontend/translate/export.cpp +++ b/src/shader_recompiler/frontend/translate/export.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "shader_recompiler/frontend/translate/translate.h" +#include "shader_recompiler/ir/reinterpret.h" #include "shader_recompiler/runtime_info.h" namespace Shader::Gcn { @@ -31,14 +32,16 @@ void Translator::EmitExport(const GcnInst& inst) { return; } const u32 index = u32(attrib) - u32(IR::Attribute::RenderTarget0); - const auto [r, g, b, a] = runtime_info.fs_info.color_buffers[index].swizzle; + const auto col_buf = runtime_info.fs_info.color_buffers[index]; + const auto converted = IR::ApplyWriteNumberConversion(ir, value, col_buf.num_conversion); + const auto [r, g, b, a] = col_buf.swizzle; const std::array swizzle_array = {r, g, b, a}; const auto swizzled_comp = swizzle_array[comp]; if (u32(swizzled_comp) < u32(AmdGpu::CompSwizzle::Red)) { - ir.SetAttribute(attrib, value, comp); + ir.SetAttribute(attrib, converted, comp); return; } - ir.SetAttribute(attrib, value, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red)); + ir.SetAttribute(attrib, converted, u32(swizzled_comp) - u32(AmdGpu::CompSwizzle::Red)); }; const auto unpack = [&](u32 idx) { diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 636752912..751b6f148 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -753,12 +753,17 @@ void PatchTextureBufferInterpretation(IR::Block& block, IR::Inst& inst, Info& in IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; if (inst.GetOpcode() == IR::Opcode::StoreBufferFormatF32) { - inst.SetArg(2, ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect())); + const auto swizzled = ApplySwizzle(ir, inst.Arg(2), buffer.DstSelect()); + const auto converted = + ApplyWriteNumberConversionVec4(ir, swizzled, buffer.GetNumberConversion()); + inst.SetArg(2, converted); } else if (inst.GetOpcode() == IR::Opcode::LoadBufferFormatF32) { const auto inst_info = inst.Flags(); const auto texel = ir.LoadBufferFormat(inst.Arg(0), inst.Arg(1), inst_info); const auto swizzled = ApplySwizzle(ir, texel, buffer.DstSelect()); - inst.ReplaceUsesWith(swizzled); + const auto converted = + ApplyReadNumberConversionVec4(ir, swizzled, buffer.GetNumberConversion()); + inst.ReplaceUsesWith(converted); } } @@ -773,7 +778,10 @@ void PatchImageInterpretation(IR::Block& block, IR::Inst& inst, Info& info) { IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; if (inst.GetOpcode() == IR::Opcode::ImageWrite) { - inst.SetArg(4, ApplySwizzle(ir, inst.Arg(4), image.DstSelect())); + const auto swizzled = ApplySwizzle(ir, inst.Arg(4), image.DstSelect()); + const auto converted = + ApplyWriteNumberConversionVec4(ir, swizzled, image.GetNumberConversion()); + inst.SetArg(4, converted); } else if (inst.GetOpcode() == IR::Opcode::ImageRead) { const auto inst_info = inst.Flags(); const auto lod = inst.Arg(2); @@ -782,7 +790,9 @@ void PatchImageInterpretation(IR::Block& block, IR::Inst& inst, Info& info) { ir.ImageRead(inst.Arg(0), inst.Arg(1), lod.IsEmpty() ? IR::U32{} : IR::U32{lod}, ms.IsEmpty() ? IR::U32{} : IR::U32{ms}, inst_info); const auto swizzled = ApplySwizzle(ir, texel, image.DstSelect()); - inst.ReplaceUsesWith(swizzled); + const auto converted = + ApplyReadNumberConversionVec4(ir, swizzled, image.GetNumberConversion()); + inst.ReplaceUsesWith(converted); } } diff --git a/src/shader_recompiler/ir/reinterpret.h b/src/shader_recompiler/ir/reinterpret.h index 73d587a56..74a7698db 100644 --- a/src/shader_recompiler/ir/reinterpret.h +++ b/src/shader_recompiler/ir/reinterpret.h @@ -21,4 +21,66 @@ inline Value ApplySwizzle(IREmitter& ir, const Value& vector, const AmdGpu::Comp return swizzled; } +/// Applies a number conversion in the read direction. +inline F32 ApplyReadNumberConversion(IREmitter& ir, const F32& value, + const AmdGpu::NumberConversion& conversion) { + switch (conversion) { + case AmdGpu::NumberConversion::None: + return value; + case AmdGpu::NumberConversion::UintToUscaled: + return ir.ConvertUToF(32, 32, value); + case AmdGpu::NumberConversion::SintToSscaled: + return ir.ConvertSToF(32, 32, value); + case AmdGpu::NumberConversion::UnormToUbnorm: + // Convert 0...1 to -1...1 + return ir.FPSub(ir.FPMul(value, ir.Imm32(2.f)), ir.Imm32(1.f)); + default: + UNREACHABLE(); + } +} + +inline Value ApplyReadNumberConversionVec4(IREmitter& ir, const Value& value, + const AmdGpu::NumberConversion& conversion) { + if (conversion == AmdGpu::NumberConversion::None) { + return value; + } + const auto x = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 0)}, conversion); + const auto y = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 1)}, conversion); + const auto z = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 2)}, conversion); + const auto w = ApplyReadNumberConversion(ir, F32{ir.CompositeExtract(value, 3)}, conversion); + return ir.CompositeConstruct(x, y, z, w); +} + +/// Applies a number conversion in the write direction. +inline F32 ApplyWriteNumberConversion(IREmitter& ir, const F32& value, + const AmdGpu::NumberConversion& conversion) { + switch (conversion) { + case AmdGpu::NumberConversion::None: + return value; + case AmdGpu::NumberConversion::UintToUscaled: + // Need to return float type to maintain IR semantics. + return ir.BitCast(U32{ir.ConvertFToU(32, value)}); + case AmdGpu::NumberConversion::SintToSscaled: + // Need to return float type to maintain IR semantics. + return ir.BitCast(U32{ir.ConvertFToS(32, value)}); + case AmdGpu::NumberConversion::UnormToUbnorm: + // Convert -1...1 to 0...1 + return ir.FPDiv(ir.FPAdd(value, ir.Imm32(1.f)), ir.Imm32(2.f)); + default: + UNREACHABLE(); + } +} + +inline Value ApplyWriteNumberConversionVec4(IREmitter& ir, const Value& value, + const AmdGpu::NumberConversion& conversion) { + if (conversion == AmdGpu::NumberConversion::None) { + return value; + } + const auto x = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 0)}, conversion); + const auto y = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 1)}, conversion); + const auto z = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 2)}, conversion); + const auto w = ApplyWriteNumberConversion(ir, F32{ir.CompositeExtract(value, 3)}, conversion); + return ir.CompositeConstruct(x, y, z, w); +} + } // namespace Shader::IR diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 781a0b14a..cf49b0879 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -180,6 +180,7 @@ struct FragmentRuntimeInfo { std::array inputs; struct PsColorBuffer { AmdGpu::NumberFormat num_format; + AmdGpu::NumberConversion num_conversion; AmdGpu::CompMapping swizzle; auto operator<=>(const PsColorBuffer&) const noexcept = default; diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 0f1783057..de72a41b2 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -902,6 +902,10 @@ struct Liverpool { : info.number_type.Value()); } + [[nodiscard]] NumberConversion GetNumberConversion() const { + return MapNumberConversion(info.number_type); + } + [[nodiscard]] CompMapping Swizzle() const { // clang-format off static constexpr std::array, 4> mrt_swizzles{{ diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index 1d9673850..43fa2d0cf 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -74,7 +74,16 @@ inline DataFormat RemapDataFormat(const DataFormat format) { } inline NumberFormat RemapNumberFormat(const NumberFormat format) { - return format; + switch (format) { + case NumberFormat::Uscaled: + return NumberFormat::Uint; + case NumberFormat::Sscaled: + return NumberFormat::Sint; + case NumberFormat::Ubnorm: + return NumberFormat::Unorm; + default: + return format; + } } inline CompMapping RemapComponents(const DataFormat format, const CompMapping components) { @@ -101,6 +110,26 @@ inline CompMapping RemapComponents(const DataFormat format, const CompMapping co } } +enum NumberConversion { + None, + UintToUscaled, + SintToSscaled, + UnormToUbnorm, +}; + +inline NumberConversion MapNumberConversion(const NumberFormat format) { + switch (format) { + case NumberFormat::Uscaled: + return UintToUscaled; + case NumberFormat::Sscaled: + return SintToSscaled; + case NumberFormat::Ubnorm: + return UnormToUbnorm; + default: + return None; + } +} + // Table 8.5 Buffer Resource Descriptor [Sea Islands Series Instruction Set Architecture] struct Buffer { u64 base_address : 44; @@ -151,6 +180,10 @@ struct Buffer { return RemapDataFormat(DataFormat(data_format)); } + NumberConversion GetNumberConversion() const noexcept { + return MapNumberConversion(NumberFormat(num_format)); + } + u32 GetStride() const noexcept { return stride; } @@ -354,6 +387,10 @@ struct Image { return RemapNumberFormat(NumberFormat(num_format)); } + NumberConversion GetNumberConversion() const noexcept { + return MapNumberConversion(NumberFormat(num_format)); + } + TilingMode GetTilingMode() const { if (tiling_index >= 0 && tiling_index <= 7) { return tiling_index == 5 ? TilingMode::Texture_MicroTiled diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index c8f4999b1..fa10831a0 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -32,6 +32,7 @@ struct GraphicsPipelineKey { u32 num_color_attachments; std::array color_formats; std::array color_num_formats; + std::array color_num_conversions; std::array color_swizzles; vk::Format depth_format; vk::Format stencil_format; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ba069dae1..9cfc7c277 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -168,6 +168,7 @@ const Shader::RuntimeInfo& PipelineCache::BuildRuntimeInfo(Stage stage, LogicalS for (u32 i = 0; i < Shader::MaxColorBuffers; i++) { info.fs_info.color_buffers[i] = { .num_format = graphics_key.color_num_formats[i], + .num_conversion = graphics_key.color_num_conversions[i], .swizzle = graphics_key.color_swizzles[i], }; } @@ -302,6 +303,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.num_color_attachments = 0; key.color_formats.fill(vk::Format::eUndefined); key.color_num_formats.fill(AmdGpu::NumberFormat::Unorm); + key.color_num_conversions.fill(AmdGpu::NumberConversion::None); key.blend_controls.fill({}); key.write_masks.fill({}); key.color_swizzles.fill({}); @@ -330,6 +332,7 @@ bool PipelineCache::RefreshGraphicsKey() { key.color_formats[remapped_cb] = LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt()); key.color_num_formats[remapped_cb] = col_buf.GetNumberFmt(); + key.color_num_conversions[remapped_cb] = col_buf.GetNumberConversion(); key.color_swizzles[remapped_cb] = col_buf.Swizzle(); }