diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 119 |
2 files changed, 120 insertions, 9 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 { | |||
| 19 | namespace Shader { | 19 | namespace Shader { |
| 20 | 20 | ||
| 21 | struct Register { | 21 | struct Register { |
| 22 | // Register 255 is special cased to always be 0 | 22 | /// Number of registers |
| 23 | static constexpr size_t NumRegisters = 256; | ||
| 24 | |||
| 25 | /// Register 255 is special cased to always be 0 | ||
| 23 | static constexpr size_t ZeroIndex = 255; | 26 | static constexpr size_t ZeroIndex = 255; |
| 24 | 27 | ||
| 25 | constexpr Register() = default; | 28 | constexpr Register() = default; |
| @@ -48,6 +51,11 @@ struct Register { | |||
| 48 | return ~value; | 51 | return ~value; |
| 49 | } | 52 | } |
| 50 | 53 | ||
| 54 | u64 GetSwizzledIndex(u64 elem) const { | ||
| 55 | elem = (value + elem) & 3; | ||
| 56 | return (value & ~3) + elem; | ||
| 57 | } | ||
| 58 | |||
| 51 | private: | 59 | private: |
| 52 | u64 value{}; | 60 | u64 value{}; |
| 53 | }; | 61 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 3dffb205d..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: | |||
| 146 | std::string shader_source; | 146 | std::string shader_source; |
| 147 | }; | 147 | }; |
| 148 | 148 | ||
| 149 | /** | ||
| 150 | * Represents an emulated shader register, used to track the state of that register for emulation | ||
| 151 | * with GLSL. At this time, a register can be used as a float or an integer. This class is used for | ||
| 152 | * bookkeeping within the GLSL program. | ||
| 153 | */ | ||
| 154 | class GLSLRegister { | ||
| 155 | public: | ||
| 156 | GLSLRegister(size_t index, ShaderWriter& shader) | ||
| 157 | : index{index}, shader{shader}, float_str{"freg_" + std::to_string(index)}, | ||
| 158 | integer_str{"ireg_" + std::to_string(index)} {} | ||
| 159 | |||
| 160 | /// Returns a GLSL string representing the current state of the register | ||
| 161 | const std::string& GetActiveString() { | ||
| 162 | declr_type.insert(active_type); | ||
| 163 | |||
| 164 | switch (active_type) { | ||
| 165 | case Type::Float: | ||
| 166 | return float_str; | ||
| 167 | case Type::Integer: | ||
| 168 | return integer_str; | ||
| 169 | } | ||
| 170 | |||
| 171 | UNREACHABLE(); | ||
| 172 | return float_str; | ||
| 173 | } | ||
| 174 | |||
| 175 | /// Returns a GLSL string representing the register as a float | ||
| 176 | const std::string& GetFloatString() const { | ||
| 177 | ASSERT(IsFloatUsed()); | ||
| 178 | return float_str; | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Returns a GLSL string representing the register as an integer | ||
| 182 | const std::string& GetIntegerString() const { | ||
| 183 | ASSERT(IsIntegerUsed()); | ||
| 184 | return integer_str; | ||
| 185 | } | ||
| 186 | |||
| 187 | /// Convert the current register state from float to integer | ||
| 188 | void FloatToInteger() { | ||
| 189 | ASSERT(active_type == Type::Float); | ||
| 190 | |||
| 191 | const std::string src = GetActiveString(); | ||
| 192 | active_type = Type::Integer; | ||
| 193 | const std::string dest = GetActiveString(); | ||
| 194 | |||
| 195 | shader.AddLine(dest + " = floatBitsToInt(" + src + ");"); | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Convert the current register state from integer to float | ||
| 199 | void IntegerToFloat() { | ||
| 200 | ASSERT(active_type == Type::Integer); | ||
| 201 | |||
| 202 | const std::string src = GetActiveString(); | ||
| 203 | active_type = Type::Float; | ||
| 204 | const std::string dest = GetActiveString(); | ||
| 205 | |||
| 206 | shader.AddLine(dest + " = intBitsToFloat(" + src + ");"); | ||
| 207 | } | ||
| 208 | |||
| 209 | /// Returns true if the register was ever used as a float, used for register declarations | ||
| 210 | bool IsFloatUsed() const { | ||
| 211 | return declr_type.find(Type::Float) != declr_type.end(); | ||
| 212 | } | ||
| 213 | |||
| 214 | /// Returns true if the register was ever used as an integer, used for register declarations | ||
| 215 | bool IsIntegerUsed() const { | ||
| 216 | return declr_type.find(Type::Integer) != declr_type.end(); | ||
| 217 | } | ||
| 218 | |||
| 219 | private: | ||
| 220 | enum class Type { | ||
| 221 | Float, | ||
| 222 | Integer, | ||
| 223 | }; | ||
| 224 | |||
| 225 | const size_t index; | ||
| 226 | const std::string float_str; | ||
| 227 | const std::string integer_str; | ||
| 228 | ShaderWriter& shader; | ||
| 229 | Type active_type{Type::Float}; | ||
| 230 | std::set<Type> declr_type; | ||
| 231 | }; | ||
| 232 | |||
| 149 | class GLSLGenerator { | 233 | class GLSLGenerator { |
| 150 | public: | 234 | public: |
| 151 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, | 235 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, |
| @@ -153,6 +237,7 @@ public: | |||
| 153 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), | 237 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), |
| 154 | stage(stage) { | 238 | stage(stage) { |
| 155 | 239 | ||
| 240 | BuildRegisterList(); | ||
| 156 | Generate(); | 241 | Generate(); |
| 157 | } | 242 | } |
| 158 | 243 | ||
| @@ -166,6 +251,13 @@ public: | |||
| 166 | } | 251 | } |
| 167 | 252 | ||
| 168 | private: | 253 | private: |
| 254 | /// Build the GLSL register list | ||
| 255 | void BuildRegisterList() { | ||
| 256 | for (size_t index = 0; index < Register::NumRegisters; ++index) { | ||
| 257 | regs.emplace_back(index, shader); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 169 | /// Gets the Subroutine object corresponding to the specified address. | 261 | /// Gets the Subroutine object corresponding to the specified address. |
| 170 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { | 262 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { |
| 171 | auto iter = subroutines.find(Subroutine{begin, end}); | 263 | auto iter = subroutines.find(Subroutine{begin, end}); |
| @@ -221,14 +313,11 @@ private: | |||
| 221 | 313 | ||
| 222 | /// Generates code representing a temporary (GPR) register. | 314 | /// Generates code representing a temporary (GPR) register. |
| 223 | std::string GetRegister(const Register& reg, unsigned elem = 0) { | 315 | std::string GetRegister(const Register& reg, unsigned elem = 0) { |
| 224 | if (reg == Register::ZeroIndex) | 316 | if (reg == Register::ZeroIndex) { |
| 225 | return "0"; | 317 | return "0"; |
| 226 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) { | ||
| 227 | // GPRs 0-3 are output color for the fragment shader | ||
| 228 | return std::string{"color."} + "rgba"[(reg + elem) & 3]; | ||
| 229 | } | 318 | } |
| 230 | 319 | ||
| 231 | return *declr_register.insert("register_" + std::to_string(reg + elem)).first; | 320 | return regs[reg.GetSwizzledIndex(elem)].GetActiveString(); |
| 232 | } | 321 | } |
| 233 | 322 | ||
| 234 | /// Generates code representing a uniform (C buffer) register. | 323 | /// Generates code representing a uniform (C buffer) register. |
| @@ -628,6 +717,15 @@ private: | |||
| 628 | case OpCode::Id::EXIT: { | 717 | case OpCode::Id::EXIT: { |
| 629 | ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex), | 718 | ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex), |
| 630 | "Predicated exits not implemented"); | 719 | "Predicated exits not implemented"); |
| 720 | |||
| 721 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders | ||
| 722 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { | ||
| 723 | shader.AddLine("color.r = " + GetRegister(0) + ";"); | ||
| 724 | shader.AddLine("color.g = " + GetRegister(1) + ";"); | ||
| 725 | shader.AddLine("color.b = " + GetRegister(2) + ";"); | ||
| 726 | shader.AddLine("color.a = " + GetRegister(3) + ";"); | ||
| 727 | } | ||
| 728 | |||
| 631 | shader.AddLine("return true;"); | 729 | shader.AddLine("return true;"); |
| 632 | offset = PROGRAM_END - 1; | 730 | offset = PROGRAM_END - 1; |
| 633 | break; | 731 | break; |
| @@ -755,8 +853,13 @@ private: | |||
| 755 | 853 | ||
| 756 | /// Add declarations for registers | 854 | /// Add declarations for registers |
| 757 | void GenerateDeclarations() { | 855 | void GenerateDeclarations() { |
| 758 | for (const auto& reg : declr_register) { | 856 | for (const auto& reg : regs) { |
| 759 | declarations.AddLine("float " + reg + " = 0.0;"); | 857 | if (reg.IsFloatUsed()) { |
| 858 | declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;"); | ||
| 859 | } | ||
| 860 | if (reg.IsIntegerUsed()) { | ||
| 861 | declarations.AddLine("int " + reg.GetIntegerString() + " = 0;"); | ||
| 862 | } | ||
| 760 | } | 863 | } |
| 761 | declarations.AddNewLine(); | 864 | declarations.AddNewLine(); |
| 762 | 865 | ||
| @@ -803,9 +906,9 @@ private: | |||
| 803 | 906 | ||
| 804 | ShaderWriter shader; | 907 | ShaderWriter shader; |
| 805 | ShaderWriter declarations; | 908 | ShaderWriter declarations; |
| 909 | std::vector<GLSLRegister> regs; | ||
| 806 | 910 | ||
| 807 | // Declarations | 911 | // Declarations |
| 808 | std::set<std::string> declr_register; | ||
| 809 | std::set<std::string> declr_predicates; | 912 | std::set<std::string> declr_predicates; |
| 810 | std::set<Attribute::Index> declr_input_attribute; | 913 | std::set<Attribute::Index> declr_input_attribute; |
| 811 | std::set<Attribute::Index> declr_output_attribute; | 914 | std::set<Attribute::Index> declr_output_attribute; |