summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp164
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
365private: 396private:
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;");