1
1
Fork 0
forked from suyu/suyu

gl_shader_decompiler: Boilerplate for handling integer instructions.

This commit is contained in:
bunnei 2018-04-25 23:55:21 -04:00
parent 37fa9a15cd
commit c9d7abe9c9
2 changed files with 111 additions and 6 deletions

View file

@ -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{};
}; };

View file

@ -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});
@ -224,8 +316,8 @@ private:
if (reg == Register::ZeroIndex) { if (reg == Register::ZeroIndex) {
return "0"; return "0";
} }
return *declr_register.insert("register_" + std::to_string(reg.GetSwizzledIndex(elem)))
.first; return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
} }
/// Generates code representing a uniform (C buffer) register. /// Generates code representing a uniform (C buffer) register.
@ -761,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();
@ -809,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;