mirror of
				https://github.com/yuzu-emu/yuzu.git
				synced 2025-11-04 05:23:43 +00:00 
			
		
		
		
	Merge pull request #416 from bunnei/shader-ints-p3
gl_shader_decompiler: Implement MOV32I, partially implement I2I, I2F
This commit is contained in:
		
						commit
						6c464a2a4a
					
				@ -25,6 +25,13 @@ struct Register {
 | 
			
		||||
    /// Register 255 is special cased to always be 0
 | 
			
		||||
    static constexpr size_t ZeroIndex = 255;
 | 
			
		||||
 | 
			
		||||
    enum class Size : u64 {
 | 
			
		||||
        Byte = 0,
 | 
			
		||||
        Short = 1,
 | 
			
		||||
        Word = 2,
 | 
			
		||||
        Long = 3,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    constexpr Register() = default;
 | 
			
		||||
 | 
			
		||||
    constexpr Register(u64 value) : value(value) {}
 | 
			
		||||
@ -236,6 +243,15 @@ union Instruction {
 | 
			
		||||
        BitField<56, 1, u64> neg_imm;
 | 
			
		||||
    } fset;
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
        BitField<10, 2, Register::Size> size;
 | 
			
		||||
        BitField<13, 1, u64> is_signed;
 | 
			
		||||
        BitField<41, 2, u64> selector;
 | 
			
		||||
        BitField<45, 1, u64> negate_a;
 | 
			
		||||
        BitField<49, 1, u64> abs_a;
 | 
			
		||||
        BitField<50, 1, u64> saturate_a;
 | 
			
		||||
    } conversion;
 | 
			
		||||
 | 
			
		||||
    BitField<61, 1, u64> is_b_imm;
 | 
			
		||||
    BitField<60, 1, u64> is_b_gpr;
 | 
			
		||||
    BitField<59, 1, u64> is_c_gpr;
 | 
			
		||||
@ -290,7 +306,7 @@ public:
 | 
			
		||||
        MOV_C,
 | 
			
		||||
        MOV_R,
 | 
			
		||||
        MOV_IMM,
 | 
			
		||||
        MOV32I,
 | 
			
		||||
        MOV32_IMM,
 | 
			
		||||
        SHR_C,
 | 
			
		||||
        SHR_R,
 | 
			
		||||
        SHR_IMM,
 | 
			
		||||
@ -314,6 +330,7 @@ public:
 | 
			
		||||
        FloatSet,
 | 
			
		||||
        FloatSetPredicate,
 | 
			
		||||
        IntegerSetPredicate,
 | 
			
		||||
        Conversion,
 | 
			
		||||
        Unknown,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -435,20 +452,20 @@ private:
 | 
			
		||||
            INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
 | 
			
		||||
            INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
 | 
			
		||||
            INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
 | 
			
		||||
            INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
 | 
			
		||||
            INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
 | 
			
		||||
            INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
 | 
			
		||||
            INST("0100110011100---", Id::I2I_C, Type::Arithmetic, "I2I_C"),
 | 
			
		||||
            INST("0101110011100---", Id::I2I_R, Type::Arithmetic, "I2I_R"),
 | 
			
		||||
            INST("01110001-1000---", Id::I2I_IMM, Type::Arithmetic, "I2I_IMM"),
 | 
			
		||||
            INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
 | 
			
		||||
            INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
 | 
			
		||||
            INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
 | 
			
		||||
            INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
 | 
			
		||||
            INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
 | 
			
		||||
            INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"),
 | 
			
		||||
            INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
 | 
			
		||||
            INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
 | 
			
		||||
            INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
 | 
			
		||||
            INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
 | 
			
		||||
            INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
 | 
			
		||||
            INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
 | 
			
		||||
            INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
 | 
			
		||||
            INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
 | 
			
		||||
            INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),
 | 
			
		||||
            INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"),
 | 
			
		||||
            INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"),
 | 
			
		||||
            INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"),
 | 
			
		||||
 | 
			
		||||
@ -153,85 +153,61 @@ private:
 | 
			
		||||
 */
 | 
			
		||||
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)} {}
 | 
			
		||||
    enum class Type {
 | 
			
		||||
        Float,
 | 
			
		||||
        Integer,
 | 
			
		||||
        UnsignedInteger,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /// Returns a GLSL string representing the current state of the register
 | 
			
		||||
    const std::string& GetActiveString() {
 | 
			
		||||
        declr_type.insert(active_type);
 | 
			
		||||
    GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
 | 
			
		||||
 | 
			
		||||
        switch (active_type) {
 | 
			
		||||
    /// Gets the GLSL type string for a register
 | 
			
		||||
    static std::string GetTypeString(Type type) {
 | 
			
		||||
        switch (type) {
 | 
			
		||||
        case Type::Float:
 | 
			
		||||
            return float_str;
 | 
			
		||||
            return "float";
 | 
			
		||||
        case Type::Integer:
 | 
			
		||||
            return integer_str;
 | 
			
		||||
            return "int";
 | 
			
		||||
        case Type::UnsignedInteger:
 | 
			
		||||
            return "uint";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return float_str;
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns a GLSL string representing the register as a float
 | 
			
		||||
    const std::string& GetFloatString() const {
 | 
			
		||||
        ASSERT(IsFloatUsed());
 | 
			
		||||
        return float_str;
 | 
			
		||||
    /// Gets the GLSL register prefix string, used for declarations and referencing
 | 
			
		||||
    static std::string GetPrefixString(Type type) {
 | 
			
		||||
        return "reg_" + GetTypeString(type) + '_';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns a GLSL string representing the register as an integer
 | 
			
		||||
    const std::string& GetIntegerString() const {
 | 
			
		||||
        ASSERT(IsIntegerUsed());
 | 
			
		||||
        return integer_str;
 | 
			
		||||
    /// Returns a GLSL string representing the current state of the register
 | 
			
		||||
    const std::string GetActiveString() {
 | 
			
		||||
        declr_type.insert(active_type);
 | 
			
		||||
        return GetPrefixString(active_type) + std::to_string(index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the active type is float
 | 
			
		||||
    /// Returns true if the active type is a float
 | 
			
		||||
    bool IsFloat() const {
 | 
			
		||||
        return active_type == Type::Float;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the active type is integer
 | 
			
		||||
    /// Returns true if the active type is an integer
 | 
			
		||||
    bool IsInteger() const {
 | 
			
		||||
        return active_type == Type::Integer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    enum class Type {
 | 
			
		||||
        Float,
 | 
			
		||||
        Integer,
 | 
			
		||||
    };
 | 
			
		||||
    /// Returns the index of the register
 | 
			
		||||
    size_t GetIndex() const {
 | 
			
		||||
        return index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns a set of the declared types of the register
 | 
			
		||||
    const std::set<Type>& DeclaredTypes() const {
 | 
			
		||||
        return declr_type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const size_t index;
 | 
			
		||||
    const std::string float_str;
 | 
			
		||||
    const std::string integer_str;
 | 
			
		||||
@ -254,18 +230,35 @@ public:
 | 
			
		||||
        BuildRegisterList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Generates code representing a temporary (GPR) register.
 | 
			
		||||
    std::string GetRegister(const Register& reg, unsigned elem = 0) {
 | 
			
		||||
        if (reg == Register::ZeroIndex) {
 | 
			
		||||
            return "0";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a register as an float.
 | 
			
		||||
     * @param reg The register to get.
 | 
			
		||||
     * @param elem The element to use for the operation.
 | 
			
		||||
     * @returns GLSL string corresponding to the register as a float.
 | 
			
		||||
     */
 | 
			
		||||
    std::string GetRegisterAsFloat(const Register& reg, unsigned elem = 0) {
 | 
			
		||||
        ASSERT(regs[reg].IsFloat());
 | 
			
		||||
        return GetRegister(reg, elem);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes code that does a register assignment to float value operation. Should only be used
 | 
			
		||||
     * with shader instructions that deal with floats.
 | 
			
		||||
     * Gets a register as an integer.
 | 
			
		||||
     * @param reg The register to get.
 | 
			
		||||
     * @param elem The element to use for the operation.
 | 
			
		||||
     * @param is_signed Whether to get the register as a signed (or unsigned) integer.
 | 
			
		||||
     * @returns GLSL string corresponding to the register as an integer.
 | 
			
		||||
     */
 | 
			
		||||
    std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0,
 | 
			
		||||
                                     bool is_signed = true) {
 | 
			
		||||
        const std::string func = GetGLSLConversionFunc(
 | 
			
		||||
            GLSLRegister::Type::Float,
 | 
			
		||||
            is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger);
 | 
			
		||||
 | 
			
		||||
        return func + '(' + GetRegister(reg, elem) + ')';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes code that does a register assignment to float value operation.
 | 
			
		||||
     * @param reg The destination register to use.
 | 
			
		||||
     * @param elem The element to use for the operation.
 | 
			
		||||
     * @param value The code representing the value to assign.
 | 
			
		||||
@ -277,21 +270,28 @@ public:
 | 
			
		||||
    void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
 | 
			
		||||
                            u64 dest_num_components, u64 value_num_components, bool is_abs = false,
 | 
			
		||||
                            u64 dest_elem = 0) {
 | 
			
		||||
        ASSERT(regs[reg].IsFloat());
 | 
			
		||||
        SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        std::string dest = GetRegister(reg, dest_elem);
 | 
			
		||||
        if (dest_num_components > 1) {
 | 
			
		||||
            dest += GetSwizzle(elem);
 | 
			
		||||
        }
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes code that does a register assignment to integer value operation.
 | 
			
		||||
     * @param reg The destination register to use.
 | 
			
		||||
     * @param elem The element to use for the operation.
 | 
			
		||||
     * @param value The code representing the value to assign.
 | 
			
		||||
     * @param dest_num_components Number of components in the destination.
 | 
			
		||||
     * @param value_num_components Number of components in the value.
 | 
			
		||||
     * @param is_abs Optional, when True, applies absolute value to output.
 | 
			
		||||
     * @param dest_elem Optional, the destination element to use for the operation.
 | 
			
		||||
     */
 | 
			
		||||
    void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
 | 
			
		||||
                              const std::string& value, u64 dest_num_components,
 | 
			
		||||
                              u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) {
 | 
			
		||||
        const std::string func = GetGLSLConversionFunc(
 | 
			
		||||
            is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
 | 
			
		||||
            GLSLRegister::Type::Float);
 | 
			
		||||
 | 
			
		||||
        std::string src = '(' + value + ')';
 | 
			
		||||
        if (value_num_components > 1) {
 | 
			
		||||
            src += GetSwizzle(elem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        src = is_abs ? "abs(" + src + ')' : src;
 | 
			
		||||
 | 
			
		||||
        shader.AddLine(dest + " = " + src + ';');
 | 
			
		||||
        SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
 | 
			
		||||
                    is_abs, dest_elem);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -302,7 +302,7 @@ public:
 | 
			
		||||
     * @param attribute The input attibute to use as the source value.
 | 
			
		||||
     */
 | 
			
		||||
    void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
 | 
			
		||||
        std::string dest = GetRegister(reg);
 | 
			
		||||
        std::string dest = GetRegisterAsFloat(reg);
 | 
			
		||||
        std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
 | 
			
		||||
 | 
			
		||||
        if (regs[reg].IsFloat()) {
 | 
			
		||||
@ -323,7 +323,7 @@ public:
 | 
			
		||||
     */
 | 
			
		||||
    void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
 | 
			
		||||
        std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
 | 
			
		||||
        std::string src = GetRegister(reg);
 | 
			
		||||
        std::string src = GetRegisterAsFloat(reg);
 | 
			
		||||
        ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
 | 
			
		||||
        shader.AddLine(dest + " = " + src + ';');
 | 
			
		||||
    }
 | 
			
		||||
@ -347,11 +347,10 @@ public:
 | 
			
		||||
    /// Add declarations for registers
 | 
			
		||||
    void GenerateDeclarations() {
 | 
			
		||||
        for (const auto& reg : regs) {
 | 
			
		||||
            if (reg.IsFloatUsed()) {
 | 
			
		||||
                declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
 | 
			
		||||
            }
 | 
			
		||||
            if (reg.IsIntegerUsed()) {
 | 
			
		||||
                declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
 | 
			
		||||
            for (const auto& type : reg.DeclaredTypes()) {
 | 
			
		||||
                declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
 | 
			
		||||
                                     GLSLRegister::GetPrefixString(type) +
 | 
			
		||||
                                     std::to_string(reg.GetIndex()) + " = 0;");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        declarations.AddNewLine();
 | 
			
		||||
@ -395,6 +394,51 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc.
 | 
			
		||||
    const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const {
 | 
			
		||||
        const std::string src_type = GLSLRegister::GetTypeString(src);
 | 
			
		||||
        std::string dest_type = GLSLRegister::GetTypeString(dest);
 | 
			
		||||
        dest_type[0] = toupper(dest_type[0]);
 | 
			
		||||
        return src_type + "BitsTo" + dest_type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Generates code representing a temporary (GPR) register.
 | 
			
		||||
    std::string GetRegister(const Register& reg, unsigned elem) {
 | 
			
		||||
        if (reg == Register::ZeroIndex) {
 | 
			
		||||
            return "0";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Writes code that does a register assignment to value operation.
 | 
			
		||||
     * @param reg The destination register to use.
 | 
			
		||||
     * @param elem The element to use for the operation.
 | 
			
		||||
     * @param value The code representing the value to assign.
 | 
			
		||||
     * @param dest_num_components Number of components in the destination.
 | 
			
		||||
     * @param value_num_components Number of components in the value.
 | 
			
		||||
     * @param is_abs Optional, when True, applies absolute value to output.
 | 
			
		||||
     * @param dest_elem Optional, the destination element to use for the operation.
 | 
			
		||||
     */
 | 
			
		||||
    void SetRegister(const Register& reg, u64 elem, const std::string& value,
 | 
			
		||||
                     u64 dest_num_components, u64 value_num_components, bool is_abs,
 | 
			
		||||
                     u64 dest_elem) {
 | 
			
		||||
        std::string dest = GetRegister(reg, dest_elem);
 | 
			
		||||
        if (dest_num_components > 1) {
 | 
			
		||||
            dest += GetSwizzle(elem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        std::string src = '(' + value + ')';
 | 
			
		||||
        if (value_num_components > 1) {
 | 
			
		||||
            src += GetSwizzle(elem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        src = is_abs ? "abs(" + src + ')' : src;
 | 
			
		||||
 | 
			
		||||
        shader.AddLine(dest + " = " + src + ';');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Build the GLSL register list.
 | 
			
		||||
    void BuildRegisterList() {
 | 
			
		||||
        for (size_t index = 0; index < Register::NumRegisters; ++index) {
 | 
			
		||||
@ -598,7 +642,7 @@ private:
 | 
			
		||||
        switch (opcode->GetType()) {
 | 
			
		||||
        case OpCode::Type::Arithmetic: {
 | 
			
		||||
            std::string op_a = instr.alu.negate_a ? "-" : "";
 | 
			
		||||
            op_a += regs.GetRegister(instr.gpr8);
 | 
			
		||||
            op_a += regs.GetRegisterAsFloat(instr.gpr8);
 | 
			
		||||
            if (instr.alu.abs_a) {
 | 
			
		||||
                op_a = "abs(" + op_a + ')';
 | 
			
		||||
            }
 | 
			
		||||
@ -609,7 +653,7 @@ private:
 | 
			
		||||
                op_b += GetImmediate19(instr);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (instr.is_b_gpr) {
 | 
			
		||||
                    op_b += regs.GetRegister(instr.gpr20);
 | 
			
		||||
                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
 | 
			
		||||
                } else {
 | 
			
		||||
                    op_b += regs.GetUniform(instr.uniform, instr.gpr0);
 | 
			
		||||
                }
 | 
			
		||||
@ -620,6 +664,11 @@ private:
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (opcode->GetId()) {
 | 
			
		||||
            case OpCode::Id::MOV32_IMM: {
 | 
			
		||||
                // mov32i doesn't have abs or neg bits.
 | 
			
		||||
                regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::FMUL_C:
 | 
			
		||||
            case OpCode::Id::FMUL_R:
 | 
			
		||||
            case OpCode::Id::FMUL_IMM: {
 | 
			
		||||
@ -629,8 +678,8 @@ private:
 | 
			
		||||
            case OpCode::Id::FMUL32_IMM: {
 | 
			
		||||
                // fmul32i doesn't have abs or neg bits.
 | 
			
		||||
                regs.SetRegisterToFloat(
 | 
			
		||||
                    instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1,
 | 
			
		||||
                    1);
 | 
			
		||||
                    instr.gpr0, 0,
 | 
			
		||||
                    regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::FADD_C:
 | 
			
		||||
@ -687,29 +736,29 @@ private:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case OpCode::Type::Ffma: {
 | 
			
		||||
            std::string op_a = regs.GetRegister(instr.gpr8);
 | 
			
		||||
            std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
 | 
			
		||||
            std::string op_b = instr.ffma.negate_b ? "-" : "";
 | 
			
		||||
            std::string op_c = instr.ffma.negate_c ? "-" : "";
 | 
			
		||||
 | 
			
		||||
            switch (opcode->GetId()) {
 | 
			
		||||
            case OpCode::Id::FFMA_CR: {
 | 
			
		||||
                op_b += regs.GetUniform(instr.uniform, instr.gpr0);
 | 
			
		||||
                op_c += regs.GetRegister(instr.gpr39);
 | 
			
		||||
                op_c += regs.GetRegisterAsFloat(instr.gpr39);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::FFMA_RR: {
 | 
			
		||||
                op_b += regs.GetRegister(instr.gpr20);
 | 
			
		||||
                op_c += regs.GetRegister(instr.gpr39);
 | 
			
		||||
                op_b += regs.GetRegisterAsFloat(instr.gpr20);
 | 
			
		||||
                op_c += regs.GetRegisterAsFloat(instr.gpr39);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::FFMA_RC: {
 | 
			
		||||
                op_b += regs.GetRegister(instr.gpr39);
 | 
			
		||||
                op_b += regs.GetRegisterAsFloat(instr.gpr39);
 | 
			
		||||
                op_c += regs.GetUniform(instr.uniform, instr.gpr0);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::FFMA_IMM: {
 | 
			
		||||
                op_b += GetImmediate19(instr);
 | 
			
		||||
                op_c += regs.GetRegister(instr.gpr39);
 | 
			
		||||
                op_c += regs.GetRegisterAsFloat(instr.gpr39);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            default: {
 | 
			
		||||
@ -721,6 +770,32 @@ private:
 | 
			
		||||
            regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case OpCode::Type::Conversion: {
 | 
			
		||||
            ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
 | 
			
		||||
            ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
 | 
			
		||||
            ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
 | 
			
		||||
            ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
 | 
			
		||||
 | 
			
		||||
            switch (opcode->GetId()) {
 | 
			
		||||
            case OpCode::Id::I2I_R:
 | 
			
		||||
            case OpCode::Id::I2F_R: {
 | 
			
		||||
                std::string op_a =
 | 
			
		||||
                    regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
 | 
			
		||||
 | 
			
		||||
                if (instr.conversion.abs_a) {
 | 
			
		||||
                    op_a = "abs(" + op_a + ')';
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            default: {
 | 
			
		||||
                NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
 | 
			
		||||
                UNREACHABLE();
 | 
			
		||||
            }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case OpCode::Type::Memory: {
 | 
			
		||||
            const Attribute::Index attribute = instr.attribute.fmt20.index;
 | 
			
		||||
 | 
			
		||||
@ -739,8 +814,8 @@ private:
 | 
			
		||||
            }
 | 
			
		||||
            case OpCode::Id::TEXS: {
 | 
			
		||||
                ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
 | 
			
		||||
                const std::string op_a = regs.GetRegister(instr.gpr8);
 | 
			
		||||
                const std::string op_b = regs.GetRegister(instr.gpr20);
 | 
			
		||||
                const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
 | 
			
		||||
                const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
 | 
			
		||||
                const std::string sampler = GetSampler(instr.sampler);
 | 
			
		||||
                const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
 | 
			
		||||
                // Add an extra scope and declare the texture coords inside to prevent overwriting
 | 
			
		||||
@ -765,7 +840,7 @@ private:
 | 
			
		||||
        }
 | 
			
		||||
        case OpCode::Type::FloatSetPredicate: {
 | 
			
		||||
            std::string op_a = instr.fsetp.neg_a ? "-" : "";
 | 
			
		||||
            op_a += regs.GetRegister(instr.gpr8);
 | 
			
		||||
            op_a += regs.GetRegisterAsFloat(instr.gpr8);
 | 
			
		||||
 | 
			
		||||
            if (instr.fsetp.abs_a) {
 | 
			
		||||
                op_a = "abs(" + op_a + ')';
 | 
			
		||||
@ -781,7 +856,7 @@ private:
 | 
			
		||||
                op_b += '(' + GetImmediate19(instr) + ')';
 | 
			
		||||
            } else {
 | 
			
		||||
                if (instr.is_b_gpr) {
 | 
			
		||||
                    op_b += regs.GetRegister(instr.gpr20);
 | 
			
		||||
                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
 | 
			
		||||
                } else {
 | 
			
		||||
                    op_b += regs.GetUniform(instr.uniform, instr.gpr0);
 | 
			
		||||
                }
 | 
			
		||||
@ -816,7 +891,7 @@ private:
 | 
			
		||||
        }
 | 
			
		||||
        case OpCode::Type::FloatSet: {
 | 
			
		||||
            std::string op_a = instr.fset.neg_a ? "-" : "";
 | 
			
		||||
            op_a += regs.GetRegister(instr.gpr8);
 | 
			
		||||
            op_a += regs.GetRegisterAsFloat(instr.gpr8);
 | 
			
		||||
 | 
			
		||||
            if (instr.fset.abs_a) {
 | 
			
		||||
                op_a = "abs(" + op_a + ')';
 | 
			
		||||
@ -832,7 +907,7 @@ private:
 | 
			
		||||
                    op_b += imm;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (instr.is_b_gpr) {
 | 
			
		||||
                    op_b += regs.GetRegister(instr.gpr20);
 | 
			
		||||
                    op_b += regs.GetRegisterAsFloat(instr.gpr20);
 | 
			
		||||
                } else {
 | 
			
		||||
                    op_b += regs.GetUniform(instr.uniform, instr.gpr0);
 | 
			
		||||
                }
 | 
			
		||||
@ -877,10 +952,10 @@ private:
 | 
			
		||||
 | 
			
		||||
                // Final color output is currently hardcoded to GPR0-3 for fragment shaders
 | 
			
		||||
                if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
 | 
			
		||||
                    shader.AddLine("color.r = " + regs.GetRegister(0) + ';');
 | 
			
		||||
                    shader.AddLine("color.g = " + regs.GetRegister(1) + ';');
 | 
			
		||||
                    shader.AddLine("color.b = " + regs.GetRegister(2) + ';');
 | 
			
		||||
                    shader.AddLine("color.a = " + regs.GetRegister(3) + ';');
 | 
			
		||||
                    shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';');
 | 
			
		||||
                    shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';');
 | 
			
		||||
                    shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';');
 | 
			
		||||
                    shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';');
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                shader.AddLine("return true;");
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user