diff options
author | bunnei <bunneidev@gmail.com> | 2018-04-26 05:55:21 +0200 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2018-04-26 20:38:42 +0200 |
commit | c9d7abe9c9be3e3654b47623602770c9be9ee88f (patch) | |
tree | 81a6cda909f1fe18f6a5ff31321369418bd3337b | |
parent | gl_shader_decompiler: Move color output to EXIT instruction. (diff) | |
download | yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.gz yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.bz2 yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.lz yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.xz yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.tar.zst yuzu-c9d7abe9c9be3e3654b47623602770c9be9ee88f.zip |
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 10 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 107 |
2 files changed, 111 insertions, 6 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index f4d11fa5d..f3ca30cfa 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -19,7 +19,10 @@ namespace Tegra { namespace Shader { 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; constexpr Register() = default; @@ -48,6 +51,11 @@ struct Register { return ~value; } + u64 GetSwizzledIndex(u64 elem) const { + elem = (value + elem) & 3; + return (value & ~3) + elem; + } + private: u64 value{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 82fd7a0de..3716bb782 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -146,6 +146,90 @@ private: 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 { public: 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), stage(stage) { + BuildRegisterList(); Generate(); } @@ -166,6 +251,13 @@ public: } 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. const Subroutine& GetSubroutine(u32 begin, u32 end) const { auto iter = subroutines.find(Subroutine{begin, end}); @@ -224,8 +316,8 @@ private: if (reg == Register::ZeroIndex) { 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. @@ -761,8 +853,13 @@ private: /// Add declarations for registers void GenerateDeclarations() { - for (const auto& reg : declr_register) { - declarations.AddLine("float " + reg + " = 0.0;"); + for (const auto& reg : regs) { + if (reg.IsFloatUsed()) { + declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;"); + } + if (reg.IsIntegerUsed()) { + declarations.AddLine("int " + reg.GetIntegerString() + " = 0;"); + } } declarations.AddNewLine(); @@ -809,9 +906,9 @@ private: ShaderWriter shader; ShaderWriter declarations; + std::vector<GLSLRegister> regs; // Declarations - std::set<std::string> declr_register; std::set<std::string> declr_predicates; std::set<Attribute::Index> declr_input_attribute; std::set<Attribute::Index> declr_output_attribute; |