mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-29 14:57:41 -05:00
Merge pull request #399 from bunnei/shader-ints
Shader decompiler prep for integer instructions
This commit is contained in:
commit
bc43946140
2 changed files with 120 additions and 9 deletions
|
@ -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 a new issue