diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 164 |
1 files changed, 120 insertions, 44 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 555aa8cc7..f90f74a48 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -156,20 +156,27 @@ public: | |||
| 156 | enum class Type { | 156 | enum class Type { |
| 157 | Float, | 157 | Float, |
| 158 | Integer, | 158 | Integer, |
| 159 | UnsignedInteger, | ||
| 159 | }; | 160 | }; |
| 160 | 161 | ||
| 161 | GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {} | 162 | GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {} |
| 162 | 163 | ||
| 164 | /// Gets the GLSL type string for a register | ||
| 163 | static std::string GetTypeString(Type type) { | 165 | static std::string GetTypeString(Type type) { |
| 164 | switch (type) { | 166 | switch (type) { |
| 165 | case Type::Float: | 167 | case Type::Float: |
| 166 | return "float"; | 168 | return "float"; |
| 169 | case Type::Integer: | ||
| 170 | return "int"; | ||
| 171 | case Type::UnsignedInteger: | ||
| 172 | return "uint"; | ||
| 167 | } | 173 | } |
| 168 | 174 | ||
| 169 | UNREACHABLE(); | 175 | UNREACHABLE(); |
| 170 | return {}; | 176 | return {}; |
| 171 | } | 177 | } |
| 172 | 178 | ||
| 179 | /// Gets the GLSL register prefix string, used for declarations and referencing | ||
| 173 | static std::string GetPrefixString(Type type) { | 180 | static std::string GetPrefixString(Type type) { |
| 174 | return "reg_" + GetTypeString(type) + '_'; | 181 | return "reg_" + GetTypeString(type) + '_'; |
| 175 | } | 182 | } |
| @@ -223,18 +230,35 @@ public: | |||
| 223 | BuildRegisterList(); | 230 | BuildRegisterList(); |
| 224 | } | 231 | } |
| 225 | 232 | ||
| 226 | /// Generates code representing a temporary (GPR) register. | 233 | /** |
| 227 | std::string GetRegister(const Register& reg, unsigned elem = 0) { | 234 | * Gets a register as an float. |
| 228 | if (reg == Register::ZeroIndex) { | 235 | * @param reg The register to get. |
| 229 | return "0"; | 236 | * @param elem The element to use for the operation. |
| 230 | } | 237 | * @returns GLSL string corresponding to the register as a float. |
| 238 | */ | ||
| 239 | std::string GetRegisterAsFloat(const Register& reg, unsigned elem = 0) { | ||
| 240 | ASSERT(regs[reg].IsFloat()); | ||
| 241 | return GetRegister(reg, elem); | ||
| 242 | } | ||
| 231 | 243 | ||
| 232 | return regs[reg.GetSwizzledIndex(elem)].GetActiveString(); | 244 | /** |
| 245 | * Gets a register as an integer. | ||
| 246 | * @param reg The register to get. | ||
| 247 | * @param elem The element to use for the operation. | ||
| 248 | * @param is_signed Whether to get the register as a signed (or unsigned) integer. | ||
| 249 | * @returns GLSL string corresponding to the register as an integer. | ||
| 250 | */ | ||
| 251 | std::string GetRegisterAsInteger(const Register& reg, unsigned elem = 0, | ||
| 252 | bool is_signed = true) { | ||
| 253 | const std::string func = GetGLSLConversionFunc( | ||
| 254 | GLSLRegister::Type::Float, | ||
| 255 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger); | ||
| 256 | |||
| 257 | return func + '(' + GetRegister(reg, elem) + ')'; | ||
| 233 | } | 258 | } |
| 234 | 259 | ||
| 235 | /** | 260 | /** |
| 236 | * Writes code that does a register assignment to float value operation. Should only be used | 261 | * Writes code that does a register assignment to float value operation. |
| 237 | * with shader instructions that deal with floats. | ||
| 238 | * @param reg The destination register to use. | 262 | * @param reg The destination register to use. |
| 239 | * @param elem The element to use for the operation. | 263 | * @param elem The element to use for the operation. |
| 240 | * @param value The code representing the value to assign. | 264 | * @param value The code representing the value to assign. |
| @@ -246,21 +270,28 @@ public: | |||
| 246 | void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, | 270 | void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, |
| 247 | u64 dest_num_components, u64 value_num_components, bool is_abs = false, | 271 | u64 dest_num_components, u64 value_num_components, bool is_abs = false, |
| 248 | u64 dest_elem = 0) { | 272 | u64 dest_elem = 0) { |
| 249 | ASSERT(regs[reg].IsFloat()); | 273 | SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem); |
| 250 | 274 | } | |
| 251 | std::string dest = GetRegister(reg, dest_elem); | ||
| 252 | if (dest_num_components > 1) { | ||
| 253 | dest += GetSwizzle(elem); | ||
| 254 | } | ||
| 255 | |||
| 256 | std::string src = '(' + value + ')'; | ||
| 257 | if (value_num_components > 1) { | ||
| 258 | src += GetSwizzle(elem); | ||
| 259 | } | ||
| 260 | |||
| 261 | src = is_abs ? "abs(" + src + ')' : src; | ||
| 262 | 275 | ||
| 263 | shader.AddLine(dest + " = " + src + ';'); | 276 | /** |
| 277 | * Writes code that does a register assignment to integer value operation. | ||
| 278 | * @param reg The destination register to use. | ||
| 279 | * @param elem The element to use for the operation. | ||
| 280 | * @param value The code representing the value to assign. | ||
| 281 | * @param dest_num_components Number of components in the destination. | ||
| 282 | * @param value_num_components Number of components in the value. | ||
| 283 | * @param is_abs Optional, when True, applies absolute value to output. | ||
| 284 | * @param dest_elem Optional, the destination element to use for the operation. | ||
| 285 | */ | ||
| 286 | void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, | ||
| 287 | const std::string& value, u64 dest_num_components, | ||
| 288 | u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) { | ||
| 289 | const std::string func = GetGLSLConversionFunc( | ||
| 290 | is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger, | ||
| 291 | GLSLRegister::Type::Float); | ||
| 292 | |||
| 293 | SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components, | ||
| 294 | is_abs, dest_elem); | ||
| 264 | } | 295 | } |
| 265 | 296 | ||
| 266 | /** | 297 | /** |
| @@ -271,7 +302,7 @@ public: | |||
| 271 | * @param attribute The input attibute to use as the source value. | 302 | * @param attribute The input attibute to use as the source value. |
| 272 | */ | 303 | */ |
| 273 | void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) { | 304 | void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) { |
| 274 | std::string dest = GetRegister(reg); | 305 | std::string dest = GetRegisterAsFloat(reg); |
| 275 | std::string src = GetInputAttribute(attribute) + GetSwizzle(elem); | 306 | std::string src = GetInputAttribute(attribute) + GetSwizzle(elem); |
| 276 | 307 | ||
| 277 | if (regs[reg].IsFloat()) { | 308 | if (regs[reg].IsFloat()) { |
| @@ -292,7 +323,7 @@ public: | |||
| 292 | */ | 323 | */ |
| 293 | void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { | 324 | void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { |
| 294 | std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); | 325 | std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); |
| 295 | std::string src = GetRegister(reg); | 326 | std::string src = GetRegisterAsFloat(reg); |
| 296 | ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float"); | 327 | ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float"); |
| 297 | shader.AddLine(dest + " = " + src + ';'); | 328 | shader.AddLine(dest + " = " + src + ';'); |
| 298 | } | 329 | } |
| @@ -363,6 +394,51 @@ public: | |||
| 363 | } | 394 | } |
| 364 | 395 | ||
| 365 | private: | 396 | private: |
| 397 | /// Build GLSL conversion function, e.g. floatBitsToInt, intBitsToFloat, etc. | ||
| 398 | const std::string GetGLSLConversionFunc(GLSLRegister::Type src, GLSLRegister::Type dest) const { | ||
| 399 | const std::string src_type = GLSLRegister::GetTypeString(src); | ||
| 400 | std::string dest_type = GLSLRegister::GetTypeString(dest); | ||
| 401 | dest_type[0] = toupper(dest_type[0]); | ||
| 402 | return src_type + "BitsTo" + dest_type; | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Generates code representing a temporary (GPR) register. | ||
| 406 | std::string GetRegister(const Register& reg, unsigned elem) { | ||
| 407 | if (reg == Register::ZeroIndex) { | ||
| 408 | return "0"; | ||
| 409 | } | ||
| 410 | |||
| 411 | return regs[reg.GetSwizzledIndex(elem)].GetActiveString(); | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * Writes code that does a register assignment to value operation. | ||
| 416 | * @param reg The destination register to use. | ||
| 417 | * @param elem The element to use for the operation. | ||
| 418 | * @param value The code representing the value to assign. | ||
| 419 | * @param dest_num_components Number of components in the destination. | ||
| 420 | * @param value_num_components Number of components in the value. | ||
| 421 | * @param is_abs Optional, when True, applies absolute value to output. | ||
| 422 | * @param dest_elem Optional, the destination element to use for the operation. | ||
| 423 | */ | ||
| 424 | void SetRegister(const Register& reg, u64 elem, const std::string& value, | ||
| 425 | u64 dest_num_components, u64 value_num_components, bool is_abs, | ||
| 426 | u64 dest_elem) { | ||
| 427 | std::string dest = GetRegister(reg, dest_elem); | ||
| 428 | if (dest_num_components > 1) { | ||
| 429 | dest += GetSwizzle(elem); | ||
| 430 | } | ||
| 431 | |||
| 432 | std::string src = '(' + value + ')'; | ||
| 433 | if (value_num_components > 1) { | ||
| 434 | src += GetSwizzle(elem); | ||
| 435 | } | ||
| 436 | |||
| 437 | src = is_abs ? "abs(" + src + ')' : src; | ||
| 438 | |||
| 439 | shader.AddLine(dest + " = " + src + ';'); | ||
| 440 | } | ||
| 441 | |||
| 366 | /// Build the GLSL register list. | 442 | /// Build the GLSL register list. |
| 367 | void BuildRegisterList() { | 443 | void BuildRegisterList() { |
| 368 | for (size_t index = 0; index < Register::NumRegisters; ++index) { | 444 | for (size_t index = 0; index < Register::NumRegisters; ++index) { |
| @@ -566,7 +642,7 @@ private: | |||
| 566 | switch (opcode->GetType()) { | 642 | switch (opcode->GetType()) { |
| 567 | case OpCode::Type::Arithmetic: { | 643 | case OpCode::Type::Arithmetic: { |
| 568 | std::string op_a = instr.alu.negate_a ? "-" : ""; | 644 | std::string op_a = instr.alu.negate_a ? "-" : ""; |
| 569 | op_a += regs.GetRegister(instr.gpr8); | 645 | op_a += regs.GetRegisterAsFloat(instr.gpr8); |
| 570 | if (instr.alu.abs_a) { | 646 | if (instr.alu.abs_a) { |
| 571 | op_a = "abs(" + op_a + ')'; | 647 | op_a = "abs(" + op_a + ')'; |
| 572 | } | 648 | } |
| @@ -577,7 +653,7 @@ private: | |||
| 577 | op_b += GetImmediate19(instr); | 653 | op_b += GetImmediate19(instr); |
| 578 | } else { | 654 | } else { |
| 579 | if (instr.is_b_gpr) { | 655 | if (instr.is_b_gpr) { |
| 580 | op_b += regs.GetRegister(instr.gpr20); | 656 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 581 | } else { | 657 | } else { |
| 582 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 658 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 583 | } | 659 | } |
| @@ -602,8 +678,8 @@ private: | |||
| 602 | case OpCode::Id::FMUL32_IMM: { | 678 | case OpCode::Id::FMUL32_IMM: { |
| 603 | // fmul32i doesn't have abs or neg bits. | 679 | // fmul32i doesn't have abs or neg bits. |
| 604 | regs.SetRegisterToFloat( | 680 | regs.SetRegisterToFloat( |
| 605 | instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, | 681 | instr.gpr0, 0, |
| 606 | 1); | 682 | regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); |
| 607 | break; | 683 | break; |
| 608 | } | 684 | } |
| 609 | case OpCode::Id::FADD_C: | 685 | case OpCode::Id::FADD_C: |
| @@ -660,29 +736,29 @@ private: | |||
| 660 | break; | 736 | break; |
| 661 | } | 737 | } |
| 662 | case OpCode::Type::Ffma: { | 738 | case OpCode::Type::Ffma: { |
| 663 | std::string op_a = regs.GetRegister(instr.gpr8); | 739 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 664 | std::string op_b = instr.ffma.negate_b ? "-" : ""; | 740 | std::string op_b = instr.ffma.negate_b ? "-" : ""; |
| 665 | std::string op_c = instr.ffma.negate_c ? "-" : ""; | 741 | std::string op_c = instr.ffma.negate_c ? "-" : ""; |
| 666 | 742 | ||
| 667 | switch (opcode->GetId()) { | 743 | switch (opcode->GetId()) { |
| 668 | case OpCode::Id::FFMA_CR: { | 744 | case OpCode::Id::FFMA_CR: { |
| 669 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 745 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 670 | op_c += regs.GetRegister(instr.gpr39); | 746 | op_c += regs.GetRegisterAsFloat(instr.gpr39); |
| 671 | break; | 747 | break; |
| 672 | } | 748 | } |
| 673 | case OpCode::Id::FFMA_RR: { | 749 | case OpCode::Id::FFMA_RR: { |
| 674 | op_b += regs.GetRegister(instr.gpr20); | 750 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 675 | op_c += regs.GetRegister(instr.gpr39); | 751 | op_c += regs.GetRegisterAsFloat(instr.gpr39); |
| 676 | break; | 752 | break; |
| 677 | } | 753 | } |
| 678 | case OpCode::Id::FFMA_RC: { | 754 | case OpCode::Id::FFMA_RC: { |
| 679 | op_b += regs.GetRegister(instr.gpr39); | 755 | op_b += regs.GetRegisterAsFloat(instr.gpr39); |
| 680 | op_c += regs.GetUniform(instr.uniform, instr.gpr0); | 756 | op_c += regs.GetUniform(instr.uniform, instr.gpr0); |
| 681 | break; | 757 | break; |
| 682 | } | 758 | } |
| 683 | case OpCode::Id::FFMA_IMM: { | 759 | case OpCode::Id::FFMA_IMM: { |
| 684 | op_b += GetImmediate19(instr); | 760 | op_b += GetImmediate19(instr); |
| 685 | op_c += regs.GetRegister(instr.gpr39); | 761 | op_c += regs.GetRegisterAsFloat(instr.gpr39); |
| 686 | break; | 762 | break; |
| 687 | } | 763 | } |
| 688 | default: { | 764 | default: { |
| @@ -712,8 +788,8 @@ private: | |||
| 712 | } | 788 | } |
| 713 | case OpCode::Id::TEXS: { | 789 | case OpCode::Id::TEXS: { |
| 714 | ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); | 790 | ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); |
| 715 | const std::string op_a = regs.GetRegister(instr.gpr8); | 791 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 716 | const std::string op_b = regs.GetRegister(instr.gpr20); | 792 | const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); |
| 717 | const std::string sampler = GetSampler(instr.sampler); | 793 | const std::string sampler = GetSampler(instr.sampler); |
| 718 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 794 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; |
| 719 | // Add an extra scope and declare the texture coords inside to prevent overwriting | 795 | // Add an extra scope and declare the texture coords inside to prevent overwriting |
| @@ -738,7 +814,7 @@ private: | |||
| 738 | } | 814 | } |
| 739 | case OpCode::Type::FloatSetPredicate: { | 815 | case OpCode::Type::FloatSetPredicate: { |
| 740 | std::string op_a = instr.fsetp.neg_a ? "-" : ""; | 816 | std::string op_a = instr.fsetp.neg_a ? "-" : ""; |
| 741 | op_a += regs.GetRegister(instr.gpr8); | 817 | op_a += regs.GetRegisterAsFloat(instr.gpr8); |
| 742 | 818 | ||
| 743 | if (instr.fsetp.abs_a) { | 819 | if (instr.fsetp.abs_a) { |
| 744 | op_a = "abs(" + op_a + ')'; | 820 | op_a = "abs(" + op_a + ')'; |
| @@ -754,7 +830,7 @@ private: | |||
| 754 | op_b += '(' + GetImmediate19(instr) + ')'; | 830 | op_b += '(' + GetImmediate19(instr) + ')'; |
| 755 | } else { | 831 | } else { |
| 756 | if (instr.is_b_gpr) { | 832 | if (instr.is_b_gpr) { |
| 757 | op_b += regs.GetRegister(instr.gpr20); | 833 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 758 | } else { | 834 | } else { |
| 759 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 835 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 760 | } | 836 | } |
| @@ -789,7 +865,7 @@ private: | |||
| 789 | } | 865 | } |
| 790 | case OpCode::Type::FloatSet: { | 866 | case OpCode::Type::FloatSet: { |
| 791 | std::string op_a = instr.fset.neg_a ? "-" : ""; | 867 | std::string op_a = instr.fset.neg_a ? "-" : ""; |
| 792 | op_a += regs.GetRegister(instr.gpr8); | 868 | op_a += regs.GetRegisterAsFloat(instr.gpr8); |
| 793 | 869 | ||
| 794 | if (instr.fset.abs_a) { | 870 | if (instr.fset.abs_a) { |
| 795 | op_a = "abs(" + op_a + ')'; | 871 | op_a = "abs(" + op_a + ')'; |
| @@ -805,7 +881,7 @@ private: | |||
| 805 | op_b += imm; | 881 | op_b += imm; |
| 806 | } else { | 882 | } else { |
| 807 | if (instr.is_b_gpr) { | 883 | if (instr.is_b_gpr) { |
| 808 | op_b += regs.GetRegister(instr.gpr20); | 884 | op_b += regs.GetRegisterAsFloat(instr.gpr20); |
| 809 | } else { | 885 | } else { |
| 810 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); | 886 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 811 | } | 887 | } |
| @@ -850,10 +926,10 @@ private: | |||
| 850 | 926 | ||
| 851 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders | 927 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders |
| 852 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { | 928 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { |
| 853 | shader.AddLine("color.r = " + regs.GetRegister(0) + ';'); | 929 | shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';'); |
| 854 | shader.AddLine("color.g = " + regs.GetRegister(1) + ';'); | 930 | shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';'); |
| 855 | shader.AddLine("color.b = " + regs.GetRegister(2) + ';'); | 931 | shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';'); |
| 856 | shader.AddLine("color.a = " + regs.GetRegister(3) + ';'); | 932 | shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';'); |
| 857 | } | 933 | } |
| 858 | 934 | ||
| 859 | shader.AddLine("return true;"); | 935 | shader.AddLine("return true;"); |