mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #399 from bunnei/shader-ints
Shader decompiler prep for integer instructions
This commit is contained in:
		
						commit
						bc43946140
					
				@ -19,7 +19,10 @@ namespace Tegra {
 | 
				
			|||||||
namespace Shader {
 | 
					namespace Shader {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Register {
 | 
					struct Register {
 | 
				
			||||||
    // Register 255 is special cased to always be 0
 | 
					    /// Number of registers
 | 
				
			||||||
 | 
					    static constexpr size_t NumRegisters = 256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Register 255 is special cased to always be 0
 | 
				
			||||||
    static constexpr size_t ZeroIndex = 255;
 | 
					    static constexpr size_t ZeroIndex = 255;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr Register() = default;
 | 
					    constexpr Register() = default;
 | 
				
			||||||
@ -48,6 +51,11 @@ struct Register {
 | 
				
			|||||||
        return ~value;
 | 
					        return ~value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u64 GetSwizzledIndex(u64 elem) const {
 | 
				
			||||||
 | 
					        elem = (value + elem) & 3;
 | 
				
			||||||
 | 
					        return (value & ~3) + elem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    u64 value{};
 | 
					    u64 value{};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -146,6 +146,90 @@ private:
 | 
				
			|||||||
    std::string shader_source;
 | 
					    std::string shader_source;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Represents an emulated shader register, used to track the state of that register for emulation
 | 
				
			||||||
 | 
					 * with GLSL. At this time, a register can be used as a float or an integer. This class is used for
 | 
				
			||||||
 | 
					 * bookkeeping within the GLSL program.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class GLSLRegister {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    GLSLRegister(size_t index, ShaderWriter& shader)
 | 
				
			||||||
 | 
					        : index{index}, shader{shader}, float_str{"freg_" + std::to_string(index)},
 | 
				
			||||||
 | 
					          integer_str{"ireg_" + std::to_string(index)} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns a GLSL string representing the current state of the register
 | 
				
			||||||
 | 
					    const std::string& GetActiveString() {
 | 
				
			||||||
 | 
					        declr_type.insert(active_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (active_type) {
 | 
				
			||||||
 | 
					        case Type::Float:
 | 
				
			||||||
 | 
					            return float_str;
 | 
				
			||||||
 | 
					        case Type::Integer:
 | 
				
			||||||
 | 
					            return integer_str;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UNREACHABLE();
 | 
				
			||||||
 | 
					        return float_str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns a GLSL string representing the register as a float
 | 
				
			||||||
 | 
					    const std::string& GetFloatString() const {
 | 
				
			||||||
 | 
					        ASSERT(IsFloatUsed());
 | 
				
			||||||
 | 
					        return float_str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns a GLSL string representing the register as an integer
 | 
				
			||||||
 | 
					    const std::string& GetIntegerString() const {
 | 
				
			||||||
 | 
					        ASSERT(IsIntegerUsed());
 | 
				
			||||||
 | 
					        return integer_str;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Convert the current register state from float to integer
 | 
				
			||||||
 | 
					    void FloatToInteger() {
 | 
				
			||||||
 | 
					        ASSERT(active_type == Type::Float);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const std::string src = GetActiveString();
 | 
				
			||||||
 | 
					        active_type = Type::Integer;
 | 
				
			||||||
 | 
					        const std::string dest = GetActiveString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        shader.AddLine(dest + " = floatBitsToInt(" + src + ");");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Convert the current register state from integer to float
 | 
				
			||||||
 | 
					    void IntegerToFloat() {
 | 
				
			||||||
 | 
					        ASSERT(active_type == Type::Integer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const std::string src = GetActiveString();
 | 
				
			||||||
 | 
					        active_type = Type::Float;
 | 
				
			||||||
 | 
					        const std::string dest = GetActiveString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        shader.AddLine(dest + " = intBitsToFloat(" + src + ");");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns true if the register was ever used as a float, used for register declarations
 | 
				
			||||||
 | 
					    bool IsFloatUsed() const {
 | 
				
			||||||
 | 
					        return declr_type.find(Type::Float) != declr_type.end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns true if the register was ever used as an integer, used for register declarations
 | 
				
			||||||
 | 
					    bool IsIntegerUsed() const {
 | 
				
			||||||
 | 
					        return declr_type.find(Type::Integer) != declr_type.end();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    enum class Type {
 | 
				
			||||||
 | 
					        Float,
 | 
				
			||||||
 | 
					        Integer,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const size_t index;
 | 
				
			||||||
 | 
					    const std::string float_str;
 | 
				
			||||||
 | 
					    const std::string integer_str;
 | 
				
			||||||
 | 
					    ShaderWriter& shader;
 | 
				
			||||||
 | 
					    Type active_type{Type::Float};
 | 
				
			||||||
 | 
					    std::set<Type> declr_type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GLSLGenerator {
 | 
					class GLSLGenerator {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
 | 
					    GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
 | 
				
			||||||
@ -153,6 +237,7 @@ public:
 | 
				
			|||||||
        : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
 | 
					        : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
 | 
				
			||||||
          stage(stage) {
 | 
					          stage(stage) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        BuildRegisterList();
 | 
				
			||||||
        Generate();
 | 
					        Generate();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -166,6 +251,13 @@ public:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					    /// Build the GLSL register list
 | 
				
			||||||
 | 
					    void BuildRegisterList() {
 | 
				
			||||||
 | 
					        for (size_t index = 0; index < Register::NumRegisters; ++index) {
 | 
				
			||||||
 | 
					            regs.emplace_back(index, shader);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Gets the Subroutine object corresponding to the specified address.
 | 
					    /// Gets the Subroutine object corresponding to the specified address.
 | 
				
			||||||
    const Subroutine& GetSubroutine(u32 begin, u32 end) const {
 | 
					    const Subroutine& GetSubroutine(u32 begin, u32 end) const {
 | 
				
			||||||
        auto iter = subroutines.find(Subroutine{begin, end});
 | 
					        auto iter = subroutines.find(Subroutine{begin, end});
 | 
				
			||||||
@ -221,14 +313,11 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Generates code representing a temporary (GPR) register.
 | 
					    /// Generates code representing a temporary (GPR) register.
 | 
				
			||||||
    std::string GetRegister(const Register& reg, unsigned elem = 0) {
 | 
					    std::string GetRegister(const Register& reg, unsigned elem = 0) {
 | 
				
			||||||
        if (reg == Register::ZeroIndex)
 | 
					        if (reg == Register::ZeroIndex) {
 | 
				
			||||||
            return "0";
 | 
					            return "0";
 | 
				
			||||||
        if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
 | 
					 | 
				
			||||||
            // GPRs 0-3 are output color for the fragment shader
 | 
					 | 
				
			||||||
            return std::string{"color."} + "rgba"[(reg + elem) & 3];
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
 | 
					        return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Generates code representing a uniform (C buffer) register.
 | 
					    /// Generates code representing a uniform (C buffer) register.
 | 
				
			||||||
@ -628,6 +717,15 @@ private:
 | 
				
			|||||||
            case OpCode::Id::EXIT: {
 | 
					            case OpCode::Id::EXIT: {
 | 
				
			||||||
                ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
 | 
					                ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
 | 
				
			||||||
                           "Predicated exits not implemented");
 | 
					                           "Predicated exits not implemented");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Final color output is currently hardcoded to GPR0-3 for fragment shaders
 | 
				
			||||||
 | 
					                if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
 | 
				
			||||||
 | 
					                    shader.AddLine("color.r = " + GetRegister(0) + ";");
 | 
				
			||||||
 | 
					                    shader.AddLine("color.g = " + GetRegister(1) + ";");
 | 
				
			||||||
 | 
					                    shader.AddLine("color.b = " + GetRegister(2) + ";");
 | 
				
			||||||
 | 
					                    shader.AddLine("color.a = " + GetRegister(3) + ";");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                shader.AddLine("return true;");
 | 
					                shader.AddLine("return true;");
 | 
				
			||||||
                offset = PROGRAM_END - 1;
 | 
					                offset = PROGRAM_END - 1;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
@ -755,8 +853,13 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Add declarations for registers
 | 
					    /// Add declarations for registers
 | 
				
			||||||
    void GenerateDeclarations() {
 | 
					    void GenerateDeclarations() {
 | 
				
			||||||
        for (const auto& reg : declr_register) {
 | 
					        for (const auto& reg : regs) {
 | 
				
			||||||
            declarations.AddLine("float " + reg + " = 0.0;");
 | 
					            if (reg.IsFloatUsed()) {
 | 
				
			||||||
 | 
					                declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (reg.IsIntegerUsed()) {
 | 
				
			||||||
 | 
					                declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        declarations.AddNewLine();
 | 
					        declarations.AddNewLine();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -803,9 +906,9 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ShaderWriter shader;
 | 
					    ShaderWriter shader;
 | 
				
			||||||
    ShaderWriter declarations;
 | 
					    ShaderWriter declarations;
 | 
				
			||||||
 | 
					    std::vector<GLSLRegister> regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Declarations
 | 
					    // Declarations
 | 
				
			||||||
    std::set<std::string> declr_register;
 | 
					 | 
				
			||||||
    std::set<std::string> declr_predicates;
 | 
					    std::set<std::string> declr_predicates;
 | 
				
			||||||
    std::set<Attribute::Index> declr_input_attribute;
 | 
					    std::set<Attribute::Index> declr_input_attribute;
 | 
				
			||||||
    std::set<Attribute::Index> declr_output_attribute;
 | 
					    std::set<Attribute::Index> declr_output_attribute;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user