diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 195 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 162 |
2 files changed, 329 insertions, 28 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 6e555ea03..7e1de0fa1 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -240,6 +240,41 @@ enum class FlowCondition : u64 { Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? }; +enum class ControlCode : u64 { + F = 0, + LT = 1, + EQ = 2, + LE = 3, + GT = 4, + NE = 5, + GE = 6, + Num = 7, + Nan = 8, + LTU = 9, + EQU = 10, + LEU = 11, + GTU = 12, + NEU = 13, + GEU = 14, + // + OFF = 16, + LO = 17, + SFF = 18, + LS = 19, + HI = 20, + SFT = 21, + HS = 22, + OFT = 23, + CSM_TA = 24, + CSM_TR = 25, + CSM_MX = 26, + FCSM_TA = 27, + FCSM_TR = 28, + FCSM_MX = 29, + RLE = 30, + RGT = 31, +}; + enum class PredicateResultMode : u64 { None = 0x0, NotZero = 0x3, @@ -271,6 +306,15 @@ enum class TextureProcessMode : u64 { LLA = 7 // Load LOD. The A is unknown, does not appear to differ with LL }; +enum class TextureMiscMode : u64 { + DC, + AOFFI, // Uses Offset + NDV, + NODEP, + MZ, + PTP, +}; + enum class IpaInterpMode : u64 { Linear = 0, Perspective = 1, Flat = 2, Sc = 3 }; enum class IpaSampleMode : u64 { Default = 0, Centroid = 1, Offset = 2 }; @@ -546,6 +590,15 @@ union Instruction { } pset; union { + BitField<0, 3, u64> pred0; + BitField<3, 3, u64> pred3; + BitField<8, 5, ControlCode> cc; // flag in cc + BitField<39, 3, u64> pred39; + BitField<42, 1, u64> neg_pred39; + BitField<45, 4, PredOperation> op; // op with pred39 + } csetp; + + union { BitField<39, 3, u64> pred39; BitField<42, 1, u64> neg_pred; BitField<43, 1, u64> neg_a; @@ -590,42 +643,127 @@ union Instruction { BitField<28, 1, u64> array; BitField<29, 2, TextureType> texture_type; BitField<31, 4, u64> component_mask; + BitField<49, 1, u64> nodep_flag; + BitField<50, 1, u64> dc_flag; + BitField<54, 1, u64> aoffi_flag; BitField<55, 3, TextureProcessMode> process_mode; bool IsComponentEnabled(std::size_t component) const { return ((1ull << component) & component_mask) != 0; } + + TextureProcessMode GetTextureProcessMode() const { + return process_mode; + } + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::DC: + return dc_flag != 0; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + case TextureMiscMode::AOFFI: + return aoffi_flag != 0; + default: + break; + } + return false; + } } tex; union { BitField<22, 6, TextureQueryType> query_type; BitField<31, 4, u64> component_mask; + BitField<49, 1, u64> nodep_flag; + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::NODEP: + return nodep_flag != 0; + default: + break; + } + return false; + } } txq; union { BitField<28, 1, u64> array; BitField<29, 2, TextureType> texture_type; BitField<31, 4, u64> component_mask; + BitField<35, 1, u64> ndv_flag; + BitField<49, 1, u64> nodep_flag; bool IsComponentEnabled(std::size_t component) const { return ((1ull << component) & component_mask) != 0; } + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::NDV: + return (ndv_flag != 0); + case TextureMiscMode::NODEP: + return (nodep_flag != 0); + default: + break; + } + return false; + } } tmml; union { BitField<28, 1, u64> array; BitField<29, 2, TextureType> texture_type; + BitField<35, 1, u64> ndv_flag; + BitField<49, 1, u64> nodep_flag; + BitField<50, 1, u64> dc_flag; + BitField<54, 2, u64> info; BitField<56, 2, u64> component; + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::NDV: + return ndv_flag != 0; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + case TextureMiscMode::DC: + return dc_flag != 0; + case TextureMiscMode::AOFFI: + return info == 1; + case TextureMiscMode::PTP: + return info == 2; + default: + break; + } + return false; + } } tld4; union { + BitField<49, 1, u64> nodep_flag; + BitField<50, 1, u64> dc_flag; + BitField<51, 1, u64> aoffi_flag; BitField<52, 2, u64> component; + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::DC: + return dc_flag != 0; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + case TextureMiscMode::AOFFI: + return aoffi_flag != 0; + default: + break; + } + return false; + } } tld4s; union { BitField<0, 8, Register> gpr0; BitField<28, 8, Register> gpr28; - BitField<49, 1, u64> nodep; + BitField<49, 1, u64> nodep_flag; BitField<50, 3, u64> component_mask_selector; BitField<53, 4, u64> texture_info; @@ -645,6 +783,37 @@ union Instruction { UNREACHABLE(); } + TextureProcessMode GetTextureProcessMode() const { + switch (texture_info) { + case 0: + case 2: + case 6: + case 8: + case 9: + case 11: + return TextureProcessMode::LZ; + case 3: + case 5: + case 13: + return TextureProcessMode::LL; + default: + break; + } + return TextureProcessMode::None; + } + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::DC: + return (texture_info >= 4 && texture_info <= 6) || texture_info == 9; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + default: + break; + } + return false; + } + bool IsArrayTexture() const { // TEXS only supports Texture2D arrays. return texture_info >= 7 && texture_info <= 9; @@ -673,6 +842,7 @@ union Instruction { } texs; union { + BitField<49, 1, u64> nodep_flag; BitField<53, 4, u64> texture_info; TextureType GetTextureType() const { @@ -693,6 +863,26 @@ union Instruction { UNREACHABLE(); } + TextureProcessMode GetTextureProcessMode() const { + if (texture_info == 1 || texture_info == 5 || texture_info == 12) + return TextureProcessMode::LL; + return TextureProcessMode::LZ; + } + + bool UsesMiscMode(TextureMiscMode mode) const { + switch (mode) { + case TextureMiscMode::AOFFI: + return texture_info == 12 || texture_info == 4; + case TextureMiscMode::MZ: + return texture_info == 5; + case TextureMiscMode::NODEP: + return nodep_flag != 0; + default: + break; + } + return false; + } + bool IsArrayTexture() const { // TEXS only supports Texture2D arrays. return texture_info == 8; @@ -735,6 +925,7 @@ union Instruction { BitField<36, 5, u64> index; } cbuf36; + BitField<47, 1, u64> generates_cc; BitField<61, 1, u64> is_b_imm; BitField<60, 1, u64> is_b_gpr; BitField<59, 1, u64> is_c_gpr; @@ -859,6 +1050,7 @@ public: ISET_IMM, PSETP, PSET, + CSETP, XMAD_IMM, XMAD_CR, XMAD_RC, @@ -1095,6 +1287,7 @@ private: INST("0011011-0101----", Id::ISET_IMM, Type::IntegerSet, "ISET_IMM"), INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), + INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index a1638c12e..b3e95187e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -236,6 +236,14 @@ private: const std::string& suffix; }; +enum class InternalFlag : u64 { + ZeroFlag = 0, + CarryFlag = 1, + OverflowFlag = 2, + NaNFlag = 3, + Amount +}; + /** * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state * of all registers (e.g. whether they are currently being used as Floats or Integers), and @@ -329,13 +337,19 @@ public: void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, const std::string& value, u64 dest_num_components, u64 value_num_components, bool is_saturated = false, - u64 dest_elem = 0, Register::Size size = Register::Size::Word) { + u64 dest_elem = 0, Register::Size size = Register::Size::Word, + bool sets_cc = false) { ASSERT_MSG(!is_saturated, "Unimplemented"); const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', dest_num_components, value_num_components, dest_elem); + + if (sets_cc) { + const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; + SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); + } } /** @@ -352,6 +366,26 @@ public: shader.AddLine(dest + " = " + src + ';'); } + std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { + switch (cc) { + case Tegra::Shader::ControlCode::NEU: + return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented Control Code {}", static_cast<u32>(cc)); + UNREACHABLE(); + return "false"; + } + } + + std::string GetInternalFlag(const InternalFlag ii) const { + const u32 code = static_cast<u32>(ii); + return "internalFlag_" + std::to_string(code) + suffix; + } + + void SetInternalFlag(const InternalFlag ii, const std::string& value) const { + shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); + } + /** * Writes code that does a output attribute assignment to register operation. Output attributes * are stored as floats, so this may require conversion. @@ -415,6 +449,12 @@ public: } declarations.AddNewLine(); + for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { + const InternalFlag code = static_cast<InternalFlag>(ii); + declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); + } + declarations.AddNewLine(); + for (const auto element : declr_input_attribute) { // TODO(bunnei): Use proper number of elements for these u32 idx = @@ -938,8 +978,6 @@ private: // TEXS has two destination registers and a swizzle. The first two elements in the swizzle // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 - ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented"); - std::size_t written_components = 0; for (u32 component = 0; component < 4; ++component) { if (!instr.texs.IsComponentEnabled(component)) { @@ -1622,7 +1660,8 @@ private: } regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, - 1, instr.alu.saturate_d, 0, instr.conversion.dest_size); + 1, instr.alu.saturate_d, 0, instr.conversion.dest_size, + instr.generates_cc.Value() != 0); break; } case OpCode::Id::I2F_R: @@ -1761,8 +1800,8 @@ private: Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective, Tegra::Shader::IpaSampleMode::Default}; - u32 next_element = instr.attribute.fmt20.element; - u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value()); + u64 next_element = instr.attribute.fmt20.element; + u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value()); const auto LoadNextElement = [&](u32 reg_offset) { regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element, @@ -1826,8 +1865,8 @@ private: ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0, "Unaligned attribute loads are not supported"); - u32 next_element = instr.attribute.fmt20.element; - u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value()); + u64 next_element = instr.attribute.fmt20.element; + u64 next_index = static_cast<u64>(instr.attribute.fmt20.index.Value()); const auto StoreNextElement = [&](u32 reg_offset) { regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index), @@ -1853,6 +1892,13 @@ private: Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; std::string coord; + ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), + "AOFFI is not implemented"); + ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), + "DC is not implemented"); + switch (texture_type) { case Tegra::Shader::TextureType::Texture1D: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); @@ -1935,6 +1981,11 @@ private: Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; bool is_array{instr.texs.IsArrayTexture()}; + ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), + "DC is not implemented"); + switch (texture_type) { case Tegra::Shader::TextureType::Texture2D: { if (is_array) { @@ -1971,6 +2022,13 @@ private: ASSERT(instr.tlds.IsArrayTexture() == false); std::string coord; + ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), + "AOFFI is not implemented"); + ASSERT_MSG(!instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ), + "MZ is not implemented"); + switch (instr.tlds.GetTextureType()) { case Tegra::Shader::TextureType::Texture2D: { if (instr.tlds.IsArrayTexture()) { @@ -1999,6 +2057,17 @@ private: ASSERT(instr.tld4.array == 0); std::string coord; + ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), + "AOFFI is not implemented"); + ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), + "DC is not implemented"); + ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), + "NDV is not implemented"); + ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), + "PTP is not implemented"); + switch (instr.tld4.texture_type) { case Tegra::Shader::TextureType::Texture2D: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); @@ -2036,6 +2105,13 @@ private: break; } case OpCode::Id::TLD4S: { + ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), + "AOFFI is not implemented"); + ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), + "DC is not implemented"); + const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. @@ -2048,6 +2124,9 @@ private: break; } case OpCode::Id::TXQ: { + ASSERT_MSG(!instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + // TODO: the new commits on the texture refactor, change the way samplers work. // Sadly, not all texture instructions specify the type of texture their sampler // uses. This must be fixed at a later instance. @@ -2068,6 +2147,11 @@ private: break; } case OpCode::Id::TMML: { + ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), + "NODEP is not implemented"); + ASSERT_MSG(!instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), + "NDV is not implemented"); + const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const bool is_array = instr.tmml.array != 0; @@ -2234,31 +2318,55 @@ private: break; } case OpCode::Type::PredicateSetPredicate: { - const std::string op_a = - GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); - const std::string op_b = - GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); + switch (opcode->GetId()) { + case OpCode::Id::PSETP: { + const std::string op_a = + GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); + const std::string op_b = + GetPredicateCondition(instr.psetp.pred29, instr.psetp.neg_pred29 != 0); - // We can't use the constant predicate as destination. - ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); + // We can't use the constant predicate as destination. + ASSERT(instr.psetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); - const std::string second_pred = - GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); + const std::string second_pred = + GetPredicateCondition(instr.psetp.pred39, instr.psetp.neg_pred39 != 0); - const std::string combiner = GetPredicateCombiner(instr.psetp.op); + const std::string combiner = GetPredicateCombiner(instr.psetp.op); - const std::string predicate = - '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; + const std::string predicate = + '(' + op_a + ") " + GetPredicateCombiner(instr.psetp.cond) + " (" + op_b + ')'; - // Set the primary predicate to the result of Predicate OP SecondPredicate - SetPredicate(instr.psetp.pred3, - '(' + predicate + ") " + combiner + " (" + second_pred + ')'); + // Set the primary predicate to the result of Predicate OP SecondPredicate + SetPredicate(instr.psetp.pred3, + '(' + predicate + ") " + combiner + " (" + second_pred + ')'); - if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { - // Set the secondary predicate to the result of !Predicate OP SecondPredicate, - // if enabled - SetPredicate(instr.psetp.pred0, - "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); + if (instr.psetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { + // Set the secondary predicate to the result of !Predicate OP SecondPredicate, + // if enabled + SetPredicate(instr.psetp.pred0, + "!(" + predicate + ") " + combiner + " (" + second_pred + ')'); + } + break; + } + case OpCode::Id::CSETP: { + const std::string pred = + GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); + const std::string combiner = GetPredicateCombiner(instr.csetp.op); + const std::string controlCode = regs.GetControlCode(instr.csetp.cc); + if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { + SetPredicate(instr.csetp.pred3, + '(' + controlCode + ") " + combiner + " (" + pred + ')'); + } + if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { + SetPredicate(instr.csetp.pred0, + "!(" + controlCode + ") " + combiner + " (" + pred + ')'); + } + break; + } + default: { + LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); + UNREACHABLE(); + } } break; } |