From 8ffcfc87bd9bcd8396cde82eec9daf2a250fd018 Mon Sep 17 00:00:00 2001 From: TheTurtle Date: Sun, 8 Jun 2025 22:46:34 +0300 Subject: [PATCH] shader_recompiler: Implement linear interpolation support (#3055) --- .../backend/spirv/spirv_emit_context.cpp | 23 +- .../backend/spirv/spirv_emit_context.h | 4 +- .../frontend/structured_control_flow.cpp | 12 +- .../frontend/translate/translate.cpp | 135 ++++---- .../frontend/translate/translate.h | 16 +- .../translate/vector_interpolation.cpp | 5 +- src/shader_recompiler/info.h | 4 + src/shader_recompiler/ir/attribute.h | 19 ++ src/shader_recompiler/ir/ir_emitter.cpp | 1 - src/shader_recompiler/ir/ir_emitter.h | 2 +- src/shader_recompiler/ir/reg.h | 2 +- src/video_core/amdgpu/pixel_format.h | 300 +++++++++++++++++- src/video_core/amdgpu/resource.h | 1 - src/video_core/amdgpu/types.h | 276 ---------------- 14 files changed, 425 insertions(+), 375 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index bd10fd3df..9e51f8e60 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -307,7 +307,9 @@ void EmitContext::DefineInterpolatedAttribs() { const Id p2{OpCompositeExtract(F32[4], p_array, 2U)}; const Id p10{OpFSub(F32[4], p1, p0)}; const Id p20{OpFSub(F32[4], p2, p0)}; - const Id bary_coord{OpLoad(F32[3], gl_bary_coord_id)}; + const Id bary_coord{OpLoad(F32[3], IsLinear(info.interp_qualifiers[i]) + ? bary_coord_linear_id + : bary_coord_persp_id)}; const Id bary_coord_y{OpCompositeExtract(F32[1], bary_coord, 1)}; const Id bary_coord_z{OpCompositeExtract(F32[1], bary_coord, 2)}; const Id p10_y{OpVectorTimesScalar(F32[4], p10, bary_coord_y)}; @@ -411,8 +413,14 @@ void EmitContext::DefineInputs() { DefineVariable(U1[1], spv::BuiltIn::FrontFacing, spv::StorageClass::Input); } if (profile.needs_manual_interpolation) { - gl_bary_coord_id = - DefineVariable(F32[3], spv::BuiltIn::BaryCoordKHR, spv::StorageClass::Input); + if (info.has_perspective_interp) { + bary_coord_persp_id = + DefineVariable(F32[3], spv::BuiltIn::BaryCoordKHR, spv::StorageClass::Input); + } + if (info.has_linear_interp) { + bary_coord_linear_id = DefineVariable(F32[3], spv::BuiltIn::BaryCoordNoPerspKHR, + spv::StorageClass::Input); + } } for (s32 i = 0; i < runtime_info.fs_info.num_inputs; i++) { const auto& input = runtime_info.fs_info.inputs[i]; @@ -435,9 +443,12 @@ void EmitContext::DefineInputs() { } else { attr_id = DefineInput(type, semantic); Name(attr_id, fmt::format("fs_in_attr{}", semantic)); - } - if (input.is_flat) { - Decorate(attr_id, spv::Decoration::Flat); + + if (input.is_flat) { + Decorate(attr_id, spv::Decoration::Flat); + } else if (IsLinear(info.interp_qualifiers[i])) { + Decorate(attr_id, spv::Decoration::NoPerspective); + } } input_params[semantic] = GetAttributeInfo(AmdGpu::NumberFormat::Float, attr_id, num_components, false); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index a2e0d2f47..20d936cf0 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -293,8 +293,8 @@ public: Id shared_memory_u32_type{}; - Id interpolate_func{}; - Id gl_bary_coord_id{}; + Id bary_coord_persp_id{}; + Id bary_coord_linear_id{}; struct TextureDefinition { const VectorIds* data_types; diff --git a/src/shader_recompiler/frontend/structured_control_flow.cpp b/src/shader_recompiler/frontend/structured_control_flow.cpp index 11b40d07c..1a7a43f4d 100644 --- a/src/shader_recompiler/frontend/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/structured_control_flow.cpp @@ -605,11 +605,12 @@ public: Info& info_, const RuntimeInfo& runtime_info_, const Profile& profile_) : stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_}, syntax_list{syntax_list_}, inst_list{inst_list_}, info{info_}, - runtime_info{runtime_info_}, profile{profile_} { + runtime_info{runtime_info_}, profile{profile_}, + translator{info_, runtime_info_, profile_} { Visit(root_stmt, nullptr, nullptr); - IR::Block& first_block{*syntax_list.front().data.block}; - Translator{&first_block, info, runtime_info, profile}.EmitPrologue(); + IR::Block* first_block = syntax_list.front().data.block; + translator.EmitPrologue(first_block); } private: @@ -637,8 +638,8 @@ private: current_block->has_multiple_predecessors = stmt.block->num_predecessors > 1; const u32 start = stmt.block->begin_index; const u32 size = stmt.block->end_index - start + 1; - Translate(current_block, stmt.block->begin, inst_list.subspan(start, size), - info, runtime_info, profile); + translator.Translate(current_block, stmt.block->begin, + inst_list.subspan(start, size)); } break; } @@ -820,6 +821,7 @@ private: Info& info; const RuntimeInfo& runtime_info; const Profile& profile; + Translator translator; }; } // Anonymous namespace diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 5675adf3c..5853f3e72 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -21,16 +21,60 @@ namespace Shader::Gcn { -static u32 next_vgpr_num; -static std::unordered_map vgpr_map; - -Translator::Translator(IR::Block* block_, Info& info_, const RuntimeInfo& runtime_info_, - const Profile& profile_) - : ir{*block_, block_->begin()}, info{info_}, runtime_info{runtime_info_}, profile{profile_} { - next_vgpr_num = vgpr_map.empty() ? runtime_info.num_allocated_vgprs : next_vgpr_num; +Translator::Translator(Info& info_, const RuntimeInfo& runtime_info_, const Profile& profile_) + : info{info_}, runtime_info{runtime_info_}, profile{profile_}, + next_vgpr_num{runtime_info.num_allocated_vgprs} { + if (info.l_stage == LogicalStage::Fragment) { + dst_frag_vreg = GatherInterpQualifiers(); + } } -void Translator::EmitPrologue() { +IR::VectorReg Translator::GatherInterpQualifiers() { + u32 dst_vreg{}; + if (runtime_info.fs_info.addr_flags.persp_sample_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveSample; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveSample; // J + info.has_perspective_interp = true; + } + if (runtime_info.fs_info.addr_flags.persp_center_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCenter; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCenter; // J + info.has_perspective_interp = true; + } + if (runtime_info.fs_info.addr_flags.persp_centroid_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCentroid; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCentroid; // J + info.has_perspective_interp = true; + } + if (runtime_info.fs_info.addr_flags.persp_pull_model_ena) { + ++dst_vreg; // I/W + ++dst_vreg; // J/W + ++dst_vreg; // 1/W + } + if (runtime_info.fs_info.addr_flags.linear_sample_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearSample; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearSample; // J + info.has_linear_interp = true; + } + if (runtime_info.fs_info.addr_flags.linear_center_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCenter; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCenter; // J + info.has_linear_interp = true; + } + if (runtime_info.fs_info.addr_flags.linear_centroid_ena) { + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCentroid; // I + vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCentroid; // J + info.has_linear_interp = true; + } + if (runtime_info.fs_info.addr_flags.line_stipple_tex_ena) { + ++dst_vreg; + } + return IR::VectorReg(dst_vreg); +} + +void Translator::EmitPrologue(IR::Block* first_block) { + ir = IR::IREmitter(*first_block, first_block->begin()); + ir.Prologue(); ir.SetExec(ir.Imm1(true)); @@ -60,39 +104,7 @@ void Translator::EmitPrologue() { } break; case LogicalStage::Fragment: - dst_vreg = IR::VectorReg::V0; - if (runtime_info.fs_info.addr_flags.persp_sample_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.persp_center_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.persp_centroid_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.persp_pull_model_ena) { - ++dst_vreg; // I/W - ++dst_vreg; // J/W - ++dst_vreg; // 1/W - } - if (runtime_info.fs_info.addr_flags.linear_sample_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.linear_center_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.linear_centroid_ena) { - ++dst_vreg; // I - ++dst_vreg; // J - } - if (runtime_info.fs_info.addr_flags.line_stipple_tex_ena) { - ++dst_vreg; - } + dst_vreg = dst_frag_vreg; if (runtime_info.fs_info.addr_flags.pos_x_float_ena) { if (runtime_info.fs_info.en_flags.pos_x_float_ena) { ir.SetVectorReg(dst_vreg++, ir.GetAttribute(IR::Attribute::FragCoord, 0)); @@ -543,6 +555,26 @@ void Translator::LogMissingOpcode(const GcnInst& inst) { info.translation_failed = true; } +void Translator::Translate(IR::Block* block, u32 pc, std::span inst_list) { + if (inst_list.empty()) { + return; + } + ir = IR::IREmitter{*block, block->begin()}; + for (const auto& inst : inst_list) { + pc += inst.length; + + // Special case for emitting fetch shader. + if (inst.opcode == Opcode::S_SWAPPC_B64) { + ASSERT(info.stage == Stage::Vertex || info.stage == Stage::Export || + info.stage == Stage::Local); + EmitFetch(inst); + continue; + } + + TranslateInstruction(inst, pc); + } +} + void Translator::TranslateInstruction(const GcnInst& inst, const u32 pc) { // Emit instructions for each category. switch (inst.category) { @@ -577,25 +609,4 @@ void Translator::TranslateInstruction(const GcnInst& inst, const u32 pc) { } } -void Translate(IR::Block* block, u32 pc, std::span inst_list, Info& info, - const RuntimeInfo& runtime_info, const Profile& profile) { - if (inst_list.empty()) { - return; - } - Translator translator{block, info, runtime_info, profile}; - for (const auto& inst : inst_list) { - pc += inst.length; - - // Special case for emitting fetch shader. - if (inst.opcode == Opcode::S_SWAPPC_B64) { - ASSERT(info.stage == Stage::Vertex || info.stage == Stage::Export || - info.stage == Stage::Local); - translator.EmitFetch(inst); - continue; - } - - translator.TranslateInstruction(inst, pc); - } -} - } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/translate/translate.h b/src/shader_recompiler/frontend/translate/translate.h index 15ba8c8d7..f8ffb9638 100644 --- a/src/shader_recompiler/frontend/translate/translate.h +++ b/src/shader_recompiler/frontend/translate/translate.h @@ -53,15 +53,17 @@ enum class NegateMode : u32 { Result, }; +static constexpr size_t MaxInterpVgpr = 16; + class Translator { public: - explicit Translator(IR::Block* block_, Info& info, const RuntimeInfo& runtime_info, - const Profile& profile); + explicit Translator(Info& info, const RuntimeInfo& runtime_info, const Profile& profile); + void Translate(IR::Block* block, u32 pc, std::span inst_list); void TranslateInstruction(const GcnInst& inst, u32 pc); // Instruction categories - void EmitPrologue(); + void EmitPrologue(IR::Block* first_block); void EmitFetch(const GcnInst& inst); void EmitExport(const GcnInst& inst); void EmitFlowControl(u32 pc, const GcnInst& inst); @@ -326,16 +328,18 @@ private: void LogMissingOpcode(const GcnInst& inst); IR::VectorReg GetScratchVgpr(u32 offset); + IR::VectorReg GatherInterpQualifiers(); private: IR::IREmitter ir; Info& info; const RuntimeInfo& runtime_info; const Profile& profile; + u32 next_vgpr_num; + std::unordered_map vgpr_map; + std::array vgpr_to_interp{}; + IR::VectorReg dst_frag_vreg{}; bool opcode_missing = false; }; -void Translate(IR::Block* block, u32 block_base, std::span inst_list, Info& info, - const RuntimeInfo& runtime_info, const Profile& profile); - } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/translate/vector_interpolation.cpp b/src/shader_recompiler/frontend/translate/vector_interpolation.cpp index 431cb2f04..2d7297c12 100644 --- a/src/shader_recompiler/frontend/translate/vector_interpolation.cpp +++ b/src/shader_recompiler/frontend/translate/vector_interpolation.cpp @@ -22,13 +22,14 @@ void Translator::EmitVectorInterpolation(const GcnInst& inst) { // VINTRP void Translator::V_INTERP_P2_F32(const GcnInst& inst) { - auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr); + const auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr); + info.interp_qualifiers[attr.param_index] = vgpr_to_interp[inst.src[0].code]; const IR::Attribute attrib{IR::Attribute::Param0 + attr.param_index}; SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan)); } void Translator::V_INTERP_MOV_F32(const GcnInst& inst) { - auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr); + const auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr); const IR::Attribute attrib{IR::Attribute::Param0 + attr.param_index}; SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan)); } diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index 24e0741c1..e14c7988d 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -193,6 +193,8 @@ struct Info { PersistentSrtInfo srt_info; std::vector flattened_ud_buf; + std::array interp_qualifiers{}; + IR::ScalarReg tess_consts_ptr_base = IR::ScalarReg::Max; s32 tess_consts_dword_offset = -1; @@ -206,6 +208,8 @@ struct Info { bool has_discard{}; bool has_image_gather{}; bool has_image_query{}; + bool has_perspective_interp{}; + bool has_linear_interp{}; bool uses_atomic_float_min_max{}; bool uses_lane_id{}; bool uses_group_quad{}; diff --git a/src/shader_recompiler/ir/attribute.h b/src/shader_recompiler/ir/attribute.h index 5117f5650..68472f052 100644 --- a/src/shader_recompiler/ir/attribute.h +++ b/src/shader_recompiler/ir/attribute.h @@ -83,6 +83,16 @@ enum class Attribute : u64 { Max, }; +enum class Interpolation { + Invalid = 0, + PerspectiveSample = 1, + PerspectiveCenter = 2, + PerspectiveCentroid = 3, + LinearSample = 4, + LinearCenter = 5, + LinearCentroid = 6, +}; + constexpr size_t NumAttributes = static_cast(Attribute::Max); constexpr size_t NumRenderTargets = 8; constexpr size_t NumParams = 32; @@ -104,6 +114,15 @@ constexpr bool IsMrt(Attribute attribute) noexcept { return attribute >= Attribute::RenderTarget0 && attribute <= Attribute::RenderTarget7; } +constexpr bool IsLinear(Interpolation interp) noexcept { + return interp >= Interpolation::LinearSample && interp <= Interpolation::LinearCentroid; +} + +constexpr bool IsPerspective(Interpolation interp) noexcept { + return interp >= Interpolation::PerspectiveSample && + interp <= Interpolation::PerspectiveCentroid; +} + [[nodiscard]] std::string NameOf(Attribute attribute); [[nodiscard]] constexpr Attribute operator+(Attribute attr, int num) { diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 07249edfe..e6cc32829 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include #include #include #include "common/assert.h" diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 7b9b81093..0e41f4b2d 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -6,7 +6,6 @@ #include #include -#include "shader_recompiler/info.h" #include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/basic_block.h" #include "shader_recompiler/ir/condition.h" @@ -17,6 +16,7 @@ namespace Shader::IR { class IREmitter { public: + explicit IREmitter() = default; explicit IREmitter(Block& block_) : block{&block_}, insertion_point{block->end()} {} explicit IREmitter(Block& block_, Block::iterator insertion_point_) : block{&block_}, insertion_point{insertion_point_} {} diff --git a/src/shader_recompiler/ir/reg.h b/src/shader_recompiler/ir/reg.h index 82aa436a7..c534eecd8 100644 --- a/src/shader_recompiler/ir/reg.h +++ b/src/shader_recompiler/ir/reg.h @@ -7,7 +7,7 @@ #include "common/bit_field.h" #include "common/enum.h" #include "common/types.h" -#include "video_core/amdgpu/types.h" +#include "video_core/amdgpu/pixel_format.h" namespace Shader::IR { diff --git a/src/video_core/amdgpu/pixel_format.h b/src/video_core/amdgpu/pixel_format.h index 38c81ba5f..faba8e285 100644 --- a/src/video_core/amdgpu/pixel_format.h +++ b/src/video_core/amdgpu/pixel_format.h @@ -5,34 +5,310 @@ #include #include +#include "common/assert.h" #include "common/types.h" -#include "video_core/amdgpu/types.h" namespace AmdGpu { -enum NumberClass { +// Table 8.13 Data and Image Formats [Sea Islands Series Instruction Set Architecture] +enum class DataFormat : u32 { + FormatInvalid = 0, + Format8 = 1, + Format16 = 2, + Format8_8 = 3, + Format32 = 4, + Format16_16 = 5, + Format10_11_11 = 6, + Format11_11_10 = 7, + Format10_10_10_2 = 8, + Format2_10_10_10 = 9, + Format8_8_8_8 = 10, + Format32_32 = 11, + Format16_16_16_16 = 12, + Format32_32_32 = 13, + Format32_32_32_32 = 14, + Format5_6_5 = 16, + Format1_5_5_5 = 17, + Format5_5_5_1 = 18, + Format4_4_4_4 = 19, + Format8_24 = 20, + Format24_8 = 21, + FormatX24_8_32 = 22, + FormatGB_GR = 32, + FormatBG_RG = 33, + Format5_9_9_9 = 34, + FormatBc1 = 35, + FormatBc2 = 36, + FormatBc3 = 37, + FormatBc4 = 38, + FormatBc5 = 39, + FormatBc6 = 40, + FormatBc7 = 41, + FormatFmask8_1 = 47, + FormatFmask8_2 = 48, + FormatFmask8_4 = 49, + FormatFmask16_1 = 50, + FormatFmask16_2 = 51, + FormatFmask32_2 = 52, + FormatFmask32_4 = 53, + FormatFmask32_8 = 54, + FormatFmask64_4 = 55, + FormatFmask64_8 = 56, + Format4_4 = 57, + Format6_5_5 = 58, + Format1 = 59, + Format1_Reversed = 60, + Format32_As_8 = 61, + Format32_As_8_8 = 62, + Format32_As_32_32_32_32 = 63, +}; + +enum class NumberFormat : u32 { + Unorm = 0, + Snorm = 1, + Uscaled = 2, + Sscaled = 3, + Uint = 4, + Sint = 5, + SnormNz = 6, + Float = 7, + Srgb = 9, + Ubnorm = 10, + UbnormNz = 11, + Ubint = 12, + Ubscaled = 13, +}; + +enum class NumberClass { Float, Sint, Uint, }; -[[nodiscard]] constexpr NumberClass GetNumberClass(const NumberFormat nfmt) { - switch (nfmt) { - case NumberFormat::Sint: - return Sint; - case NumberFormat::Uint: - return Uint; +enum class CompSwizzle : u8 { + Zero = 0, + One = 1, + Red = 4, + Green = 5, + Blue = 6, + Alpha = 7, +}; + +enum class NumberConversion : u32 { + None = 0, + UintToUscaled = 1, + SintToSscaled = 2, + UnormToUbnorm = 3, + Sint8ToSnormNz = 4, + Sint16ToSnormNz = 5, + Uint32ToUnorm = 6, +}; + +struct CompMapping { + CompSwizzle r; + CompSwizzle g; + CompSwizzle b; + CompSwizzle a; + + auto operator<=>(const CompMapping& other) const = default; + + template + [[nodiscard]] std::array Apply(const std::array& data) const { + return { + ApplySingle(data, r), + ApplySingle(data, g), + ApplySingle(data, b), + ApplySingle(data, a), + }; + } + + [[nodiscard]] CompMapping Inverse() const { + CompMapping result{}; + InverseSingle(result.r, CompSwizzle::Red); + InverseSingle(result.g, CompSwizzle::Green); + InverseSingle(result.b, CompSwizzle::Blue); + InverseSingle(result.a, CompSwizzle::Alpha); + return result; + } + +private: + template + T ApplySingle(const std::array& data, const CompSwizzle swizzle) const { + switch (swizzle) { + case CompSwizzle::Zero: + return T(0); + case CompSwizzle::One: + return T(1); + case CompSwizzle::Red: + return data[0]; + case CompSwizzle::Green: + return data[1]; + case CompSwizzle::Blue: + return data[2]; + case CompSwizzle::Alpha: + return data[3]; + default: + UNREACHABLE(); + } + } + + void InverseSingle(CompSwizzle& dst, const CompSwizzle target) const { + if (r == target) { + dst = CompSwizzle::Red; + } else if (g == target) { + dst = CompSwizzle::Green; + } else if (b == target) { + dst = CompSwizzle::Blue; + } else if (a == target) { + dst = CompSwizzle::Alpha; + } else { + dst = CompSwizzle::Zero; + } + } +}; + +static constexpr CompMapping IdentityMapping = { + .r = CompSwizzle::Red, + .g = CompSwizzle::Green, + .b = CompSwizzle::Blue, + .a = CompSwizzle::Alpha, +}; + +constexpr DataFormat RemapDataFormat(const DataFormat format) { + switch (format) { + case DataFormat::Format11_11_10: + return DataFormat::Format10_11_11; + case DataFormat::Format10_10_10_2: + return DataFormat::Format2_10_10_10; + case DataFormat::Format5_5_5_1: + return DataFormat::Format1_5_5_5; default: - return Float; + return format; } } -[[nodiscard]] constexpr bool IsInteger(const NumberFormat nfmt) { +constexpr NumberFormat RemapNumberFormat(const NumberFormat format, const DataFormat data_format) { + switch (format) { + case NumberFormat::Unorm: { + switch (data_format) { + case DataFormat::Format32: + case DataFormat::Format32_32: + case DataFormat::Format32_32_32: + case DataFormat::Format32_32_32_32: + return NumberFormat::Uint; + default: + return format; + } + } + case NumberFormat::Uscaled: + return NumberFormat::Uint; + case NumberFormat::Sscaled: + case NumberFormat::SnormNz: + return NumberFormat::Sint; + case NumberFormat::Ubnorm: + return NumberFormat::Unorm; + case NumberFormat::Float: + if (data_format == DataFormat::Format8) { + // Games may ask for 8-bit float when they want to access the stencil component + // of a depth-stencil image. Change to unsigned int to match the stencil format. + // This is also the closest approximation to pass the bits through unconverted. + return NumberFormat::Uint; + } + [[fallthrough]]; + default: + return format; + } +} + +constexpr CompMapping RemapSwizzle(const DataFormat format, const CompMapping swizzle) { + switch (format) { + case DataFormat::Format1_5_5_5: + case DataFormat::Format11_11_10: { + CompMapping result; + result.r = swizzle.b; + result.g = swizzle.g; + result.b = swizzle.r; + result.a = swizzle.a; + return result; + } + case DataFormat::Format10_10_10_2: { + CompMapping result; + result.r = swizzle.a; + result.g = swizzle.b; + result.b = swizzle.g; + result.a = swizzle.r; + return result; + } + case DataFormat::Format4_4_4_4: { + // Remap to a more supported component order. + CompMapping result; + result.r = swizzle.g; + result.g = swizzle.b; + result.b = swizzle.a; + result.a = swizzle.r; + return result; + } + default: + return swizzle; + } +} + +constexpr NumberConversion MapNumberConversion(const NumberFormat num_fmt, + const DataFormat data_fmt) { + switch (num_fmt) { + case NumberFormat::Unorm: { + switch (data_fmt) { + case DataFormat::Format32: + case DataFormat::Format32_32: + case DataFormat::Format32_32_32: + case DataFormat::Format32_32_32_32: + return NumberConversion::Uint32ToUnorm; + default: + return NumberConversion::None; + } + } + case NumberFormat::Uscaled: + return NumberConversion::UintToUscaled; + case NumberFormat::Sscaled: + return NumberConversion::SintToSscaled; + case NumberFormat::Ubnorm: + return NumberConversion::UnormToUbnorm; + case NumberFormat::SnormNz: { + switch (data_fmt) { + case DataFormat::Format8: + case DataFormat::Format8_8: + case DataFormat::Format8_8_8_8: + return NumberConversion::Sint8ToSnormNz; + case DataFormat::Format16: + case DataFormat::Format16_16: + case DataFormat::Format16_16_16_16: + return NumberConversion::Sint16ToSnormNz; + default: + UNREACHABLE_MSG("data_fmt = {}", u32(data_fmt)); + } + } + default: + return NumberConversion::None; + } +} + +constexpr NumberClass GetNumberClass(const NumberFormat nfmt) { + switch (nfmt) { + case NumberFormat::Sint: + return NumberClass::Sint; + case NumberFormat::Uint: + return NumberClass::Uint; + default: + return NumberClass::Float; + } +} + +constexpr bool IsInteger(const NumberFormat nfmt) { return nfmt == AmdGpu::NumberFormat::Sint || nfmt == AmdGpu::NumberFormat::Uint; } -[[nodiscard]] std::string_view NameOf(DataFormat fmt); -[[nodiscard]] std::string_view NameOf(NumberFormat fmt); +std::string_view NameOf(DataFormat fmt); +std::string_view NameOf(NumberFormat fmt); int NumComponents(DataFormat format); int NumBits(DataFormat format); diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index 89ac04f9a..5ede90200 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -6,7 +6,6 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/bit_field.h" -#include "common/types.h" #include "video_core/amdgpu/pixel_format.h" namespace AmdGpu { diff --git a/src/video_core/amdgpu/types.h b/src/video_core/amdgpu/types.h index f7536f7e2..009fbbbb2 100644 --- a/src/video_core/amdgpu/types.h +++ b/src/video_core/amdgpu/types.h @@ -5,7 +5,6 @@ #include #include -#include "common/assert.h" #include "common/types.h" namespace AmdGpu { @@ -114,281 +113,6 @@ enum class GsOutputPrimitiveType : u32 { TriangleStrip = 2, }; -// Table 8.13 Data and Image Formats [Sea Islands Series Instruction Set Architecture] -enum class DataFormat : u32 { - FormatInvalid = 0, - Format8 = 1, - Format16 = 2, - Format8_8 = 3, - Format32 = 4, - Format16_16 = 5, - Format10_11_11 = 6, - Format11_11_10 = 7, - Format10_10_10_2 = 8, - Format2_10_10_10 = 9, - Format8_8_8_8 = 10, - Format32_32 = 11, - Format16_16_16_16 = 12, - Format32_32_32 = 13, - Format32_32_32_32 = 14, - Format5_6_5 = 16, - Format1_5_5_5 = 17, - Format5_5_5_1 = 18, - Format4_4_4_4 = 19, - Format8_24 = 20, - Format24_8 = 21, - FormatX24_8_32 = 22, - FormatGB_GR = 32, - FormatBG_RG = 33, - Format5_9_9_9 = 34, - FormatBc1 = 35, - FormatBc2 = 36, - FormatBc3 = 37, - FormatBc4 = 38, - FormatBc5 = 39, - FormatBc6 = 40, - FormatBc7 = 41, - FormatFmask8_1 = 47, - FormatFmask8_2 = 48, - FormatFmask8_4 = 49, - FormatFmask16_1 = 50, - FormatFmask16_2 = 51, - FormatFmask32_2 = 52, - FormatFmask32_4 = 53, - FormatFmask32_8 = 54, - FormatFmask64_4 = 55, - FormatFmask64_8 = 56, - Format4_4 = 57, - Format6_5_5 = 58, - Format1 = 59, - Format1_Reversed = 60, - Format32_As_8 = 61, - Format32_As_8_8 = 62, - Format32_As_32_32_32_32 = 63, -}; - -enum class NumberFormat : u32 { - Unorm = 0, - Snorm = 1, - Uscaled = 2, - Sscaled = 3, - Uint = 4, - Sint = 5, - SnormNz = 6, - Float = 7, - Srgb = 9, - Ubnorm = 10, - UbnormNz = 11, - Ubint = 12, - Ubscaled = 13, -}; - -enum class CompSwizzle : u8 { - Zero = 0, - One = 1, - Red = 4, - Green = 5, - Blue = 6, - Alpha = 7, -}; - -enum class NumberConversion : u32 { - None = 0, - UintToUscaled = 1, - SintToSscaled = 2, - UnormToUbnorm = 3, - Sint8ToSnormNz = 4, - Sint16ToSnormNz = 5, - Uint32ToUnorm = 6, -}; - -struct CompMapping { - CompSwizzle r; - CompSwizzle g; - CompSwizzle b; - CompSwizzle a; - - auto operator<=>(const CompMapping& other) const = default; - - template - [[nodiscard]] std::array Apply(const std::array& data) const { - return { - ApplySingle(data, r), - ApplySingle(data, g), - ApplySingle(data, b), - ApplySingle(data, a), - }; - } - - [[nodiscard]] CompMapping Inverse() const { - CompMapping result{}; - InverseSingle(result.r, CompSwizzle::Red); - InverseSingle(result.g, CompSwizzle::Green); - InverseSingle(result.b, CompSwizzle::Blue); - InverseSingle(result.a, CompSwizzle::Alpha); - return result; - } - -private: - template - T ApplySingle(const std::array& data, const CompSwizzle swizzle) const { - switch (swizzle) { - case CompSwizzle::Zero: - return T(0); - case CompSwizzle::One: - return T(1); - case CompSwizzle::Red: - return data[0]; - case CompSwizzle::Green: - return data[1]; - case CompSwizzle::Blue: - return data[2]; - case CompSwizzle::Alpha: - return data[3]; - default: - UNREACHABLE(); - } - } - - void InverseSingle(CompSwizzle& dst, const CompSwizzle target) const { - if (r == target) { - dst = CompSwizzle::Red; - } else if (g == target) { - dst = CompSwizzle::Green; - } else if (b == target) { - dst = CompSwizzle::Blue; - } else if (a == target) { - dst = CompSwizzle::Alpha; - } else { - dst = CompSwizzle::Zero; - } - } -}; - -static constexpr CompMapping IdentityMapping = { - .r = CompSwizzle::Red, - .g = CompSwizzle::Green, - .b = CompSwizzle::Blue, - .a = CompSwizzle::Alpha, -}; - -inline DataFormat RemapDataFormat(const DataFormat format) { - switch (format) { - case DataFormat::Format11_11_10: - return DataFormat::Format10_11_11; - case DataFormat::Format10_10_10_2: - return DataFormat::Format2_10_10_10; - case DataFormat::Format5_5_5_1: - return DataFormat::Format1_5_5_5; - default: - return format; - } -} - -inline NumberFormat RemapNumberFormat(const NumberFormat format, const DataFormat data_format) { - switch (format) { - case NumberFormat::Unorm: { - switch (data_format) { - case DataFormat::Format32: - case DataFormat::Format32_32: - case DataFormat::Format32_32_32: - case DataFormat::Format32_32_32_32: - return NumberFormat::Uint; - default: - return format; - } - } - case NumberFormat::Uscaled: - return NumberFormat::Uint; - case NumberFormat::Sscaled: - case NumberFormat::SnormNz: - return NumberFormat::Sint; - case NumberFormat::Ubnorm: - return NumberFormat::Unorm; - case NumberFormat::Float: - if (data_format == DataFormat::Format8) { - // Games may ask for 8-bit float when they want to access the stencil component - // of a depth-stencil image. Change to unsigned int to match the stencil format. - // This is also the closest approximation to pass the bits through unconverted. - return NumberFormat::Uint; - } - [[fallthrough]]; - default: - return format; - } -} - -inline CompMapping RemapSwizzle(const DataFormat format, const CompMapping swizzle) { - switch (format) { - case DataFormat::Format1_5_5_5: - case DataFormat::Format11_11_10: { - CompMapping result; - result.r = swizzle.b; - result.g = swizzle.g; - result.b = swizzle.r; - result.a = swizzle.a; - return result; - } - case DataFormat::Format10_10_10_2: { - CompMapping result; - result.r = swizzle.a; - result.g = swizzle.b; - result.b = swizzle.g; - result.a = swizzle.r; - return result; - } - case DataFormat::Format4_4_4_4: { - // Remap to a more supported component order. - CompMapping result; - result.r = swizzle.g; - result.g = swizzle.b; - result.b = swizzle.a; - result.a = swizzle.r; - return result; - } - default: - return swizzle; - } -} - -inline NumberConversion MapNumberConversion(const NumberFormat num_fmt, const DataFormat data_fmt) { - switch (num_fmt) { - case NumberFormat::Unorm: { - switch (data_fmt) { - case DataFormat::Format32: - case DataFormat::Format32_32: - case DataFormat::Format32_32_32: - case DataFormat::Format32_32_32_32: - return NumberConversion::Uint32ToUnorm; - default: - return NumberConversion::None; - } - } - case NumberFormat::Uscaled: - return NumberConversion::UintToUscaled; - case NumberFormat::Sscaled: - return NumberConversion::SintToSscaled; - case NumberFormat::Ubnorm: - return NumberConversion::UnormToUbnorm; - case NumberFormat::SnormNz: { - switch (data_fmt) { - case DataFormat::Format8: - case DataFormat::Format8_8: - case DataFormat::Format8_8_8_8: - return NumberConversion::Sint8ToSnormNz; - case DataFormat::Format16: - case DataFormat::Format16_16: - case DataFormat::Format16_16_16_16: - return NumberConversion::Sint16ToSnormNz; - default: - UNREACHABLE_MSG("data_fmt = {}", u32(data_fmt)); - } - } - default: - return NumberConversion::None; - } -} - } // namespace AmdGpu template <>