summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-04-29 12:56:16 -0400
committerGravatar GitHub2018-04-29 12:56:16 -0400
commit6c464a2a4a50ec531cd2c5c20fa03f1579eced88 (patch)
tree49eb4e1010af58ab7c14fe906aba1b0bcf842bfe
parentMerge pull request #417 from bunnei/lang-codes (diff)
parentgl_shader_decompiler: Partially implement I2I_R, and I2F_R. (diff)
downloadyuzu-6c464a2a4a50ec531cd2c5c20fa03f1579eced88.tar.gz
yuzu-6c464a2a4a50ec531cd2c5c20fa03f1579eced88.tar.xz
yuzu-6c464a2a4a50ec531cd2c5c20fa03f1579eced88.zip
Merge pull request #416 from bunnei/shader-ints-p3
gl_shader_decompiler: Implement MOV32I, partially implement I2I, I2F
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/shader_bytecode.h33
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp287
2 files changed, 206 insertions, 114 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index f3ca30cfa..f20c2cd41 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -25,6 +25,13 @@ struct Register {
25 /// Register 255 is special cased to always be 0 25 /// Register 255 is special cased to always be 0
26 static constexpr size_t ZeroIndex = 255; 26 static constexpr size_t ZeroIndex = 255;
27 27
28 enum class Size : u64 {
29 Byte = 0,
30 Short = 1,
31 Word = 2,
32 Long = 3,
33 };
34
28 constexpr Register() = default; 35 constexpr Register() = default;
29 36
30 constexpr Register(u64 value) : value(value) {} 37 constexpr Register(u64 value) : value(value) {}
@@ -236,6 +243,15 @@ union Instruction {
236 BitField<56, 1, u64> neg_imm; 243 BitField<56, 1, u64> neg_imm;
237 } fset; 244 } fset;
238 245
246 union {
247 BitField<10, 2, Register::Size> size;
248 BitField<13, 1, u64> is_signed;
249 BitField<41, 2, u64> selector;
250 BitField<45, 1, u64> negate_a;
251 BitField<49, 1, u64> abs_a;
252 BitField<50, 1, u64> saturate_a;
253 } conversion;
254
239 BitField<61, 1, u64> is_b_imm; 255 BitField<61, 1, u64> is_b_imm;
240 BitField<60, 1, u64> is_b_gpr; 256 BitField<60, 1, u64> is_b_gpr;
241 BitField<59, 1, u64> is_c_gpr; 257 BitField<59, 1, u64> is_c_gpr;
@@ -290,7 +306,7 @@ public:
290 MOV_C, 306 MOV_C,
291 MOV_R, 307 MOV_R,
292 MOV_IMM, 308 MOV_IMM,
293 MOV32I, 309 MOV32_IMM,
294 SHR_C, 310 SHR_C,
295 SHR_R, 311 SHR_R,
296 SHR_IMM, 312 SHR_IMM,
@@ -314,6 +330,7 @@ public:
314 FloatSet, 330 FloatSet,
315 FloatSetPredicate, 331 FloatSetPredicate,
316 IntegerSetPredicate, 332 IntegerSetPredicate,
333 Conversion,
317 Unknown, 334 Unknown,
318 }; 335 };
319 336
@@ -435,20 +452,20 @@ private:
435 INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"), 452 INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
436 INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"), 453 INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
437 INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"), 454 INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
438 INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
439 INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
440 INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
441 INST("0100110011100---", Id::I2I_C, Type::Arithmetic, "I2I_C"),
442 INST("0101110011100---", Id::I2I_R, Type::Arithmetic, "I2I_R"),
443 INST("01110001-1000---", Id::I2I_IMM, Type::Arithmetic, "I2I_IMM"),
444 INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"), 455 INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
445 INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), 456 INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
446 INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), 457 INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
447 INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), 458 INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
448 INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"), 459 INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"),
449 INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"), 460 INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
450 INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"), 461 INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
451 INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"), 462 INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
463 INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
464 INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
465 INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
466 INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
467 INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
468 INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),
452 INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"), 469 INST("01011000--------", Id::FSET_R, Type::FloatSet, "FSET_R"),
453 INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"), 470 INST("0100100---------", Id::FSET_C, Type::FloatSet, "FSET_C"),
454 INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"), 471 INST("0011000---------", Id::FSET_IMM, Type::FloatSet, "FSET_IMM"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8b235e252..27190cc45 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -153,85 +153,61 @@ private:
153 */ 153 */
154class GLSLRegister { 154class GLSLRegister {
155public: 155public:
156 GLSLRegister(size_t index, ShaderWriter& shader) 156 enum class Type {
157 : index{index}, shader{shader}, float_str{"freg_" + std::to_string(index)}, 157 Float,
158 integer_str{"ireg_" + std::to_string(index)} {} 158 Integer,
159 UnsignedInteger,
160 };
159 161
160 /// Returns a GLSL string representing the current state of the register 162 GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {}
161 const std::string& GetActiveString() {
162 declr_type.insert(active_type);
163 163
164 switch (active_type) { 164 /// Gets the GLSL type string for a register
165 static std::string GetTypeString(Type type) {
166 switch (type) {
165 case Type::Float: 167 case Type::Float:
166 return float_str; 168 return "float";
167 case Type::Integer: 169 case Type::Integer:
168 return integer_str; 170 return "int";
171 case Type::UnsignedInteger:
172 return "uint";
169 } 173 }
170 174
171 UNREACHABLE(); 175 UNREACHABLE();
172 return float_str; 176 return {};
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 } 177 }
208 178
209 /// Returns true if the register was ever used as a float, used for register declarations 179 /// Gets the GLSL register prefix string, used for declarations and referencing
210 bool IsFloatUsed() const { 180 static std::string GetPrefixString(Type type) {
211 return declr_type.find(Type::Float) != declr_type.end(); 181 return "reg_" + GetTypeString(type) + '_';
212 } 182 }
213 183
214 /// Returns true if the register was ever used as an integer, used for register declarations 184 /// Returns a GLSL string representing the current state of the register
215 bool IsIntegerUsed() const { 185 const std::string GetActiveString() {
216 return declr_type.find(Type::Integer) != declr_type.end(); 186 declr_type.insert(active_type);
187 return GetPrefixString(active_type) + std::to_string(index);
217 } 188 }
218 189
219 /// Returns true if the active type is float 190 /// Returns true if the active type is a float
220 bool IsFloat() const { 191 bool IsFloat() const {
221 return active_type == Type::Float; 192 return active_type == Type::Float;
222 } 193 }
223 194
224 /// Returns true if the active type is integer 195 /// Returns true if the active type is an integer
225 bool IsInteger() const { 196 bool IsInteger() const {
226 return active_type == Type::Integer; 197 return active_type == Type::Integer;
227 } 198 }
228 199
229private: 200 /// Returns the index of the register
230 enum class Type { 201 size_t GetIndex() const {
231 Float, 202 return index;
232 Integer, 203 }
233 };
234 204
205 /// Returns a set of the declared types of the register
206 const std::set<Type>& DeclaredTypes() const {
207 return declr_type;
208 }
209
210private:
235 const size_t index; 211 const size_t index;
236 const std::string float_str; 212 const std::string float_str;
237 const std::string integer_str; 213 const std::string integer_str;
@@ -254,18 +230,35 @@ public:
254 BuildRegisterList(); 230 BuildRegisterList();
255 } 231 }
256 232
257 /// Generates code representing a temporary (GPR) register. 233 /**
258 std::string GetRegister(const Register& reg, unsigned elem = 0) { 234 * Gets a register as an float.
259 if (reg == Register::ZeroIndex) { 235 * @param reg The register to get.
260 return "0"; 236 * @param elem The element to use for the operation.
261 } 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 }
262 243
263 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) + ')';
264 } 258 }
265 259
266 /** 260 /**
267 * 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.
268 * with shader instructions that deal with floats.
269 * @param reg The destination register to use. 262 * @param reg The destination register to use.
270 * @param elem The element to use for the operation. 263 * @param elem The element to use for the operation.
271 * @param value The code representing the value to assign. 264 * @param value The code representing the value to assign.
@@ -277,21 +270,28 @@ public:
277 void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, 270 void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
278 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,
279 u64 dest_elem = 0) { 272 u64 dest_elem = 0) {
280 ASSERT(regs[reg].IsFloat()); 273 SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
281 274 }
282 std::string dest = GetRegister(reg, dest_elem);
283 if (dest_num_components > 1) {
284 dest += GetSwizzle(elem);
285 }
286
287 std::string src = '(' + value + ')';
288 if (value_num_components > 1) {
289 src += GetSwizzle(elem);
290 }
291
292 src = is_abs ? "abs(" + src + ')' : src;
293 275
294 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);
295 } 295 }
296 296
297 /** 297 /**
@@ -302,7 +302,7 @@ public:
302 * @param attribute The input attibute to use as the source value. 302 * @param attribute The input attibute to use as the source value.
303 */ 303 */
304 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) { 304 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
305 std::string dest = GetRegister(reg); 305 std::string dest = GetRegisterAsFloat(reg);
306 std::string src = GetInputAttribute(attribute) + GetSwizzle(elem); 306 std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
307 307
308 if (regs[reg].IsFloat()) { 308 if (regs[reg].IsFloat()) {
@@ -323,7 +323,7 @@ public:
323 */ 323 */
324 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { 324 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
325 std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); 325 std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
326 std::string src = GetRegister(reg); 326 std::string src = GetRegisterAsFloat(reg);
327 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");
328 shader.AddLine(dest + " = " + src + ';'); 328 shader.AddLine(dest + " = " + src + ';');
329 } 329 }
@@ -347,11 +347,10 @@ public:
347 /// Add declarations for registers 347 /// Add declarations for registers
348 void GenerateDeclarations() { 348 void GenerateDeclarations() {
349 for (const auto& reg : regs) { 349 for (const auto& reg : regs) {
350 if (reg.IsFloatUsed()) { 350 for (const auto& type : reg.DeclaredTypes()) {
351 declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;"); 351 declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
352 } 352 GLSLRegister::GetPrefixString(type) +
353 if (reg.IsIntegerUsed()) { 353 std::to_string(reg.GetIndex()) + " = 0;");
354 declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
355 } 354 }
356 } 355 }
357 declarations.AddNewLine(); 356 declarations.AddNewLine();
@@ -395,6 +394,51 @@ public:
395 } 394 }
396 395
397private: 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
398 /// Build the GLSL register list. 442 /// Build the GLSL register list.
399 void BuildRegisterList() { 443 void BuildRegisterList() {
400 for (size_t index = 0; index < Register::NumRegisters; ++index) { 444 for (size_t index = 0; index < Register::NumRegisters; ++index) {
@@ -598,7 +642,7 @@ private:
598 switch (opcode->GetType()) { 642 switch (opcode->GetType()) {
599 case OpCode::Type::Arithmetic: { 643 case OpCode::Type::Arithmetic: {
600 std::string op_a = instr.alu.negate_a ? "-" : ""; 644 std::string op_a = instr.alu.negate_a ? "-" : "";
601 op_a += regs.GetRegister(instr.gpr8); 645 op_a += regs.GetRegisterAsFloat(instr.gpr8);
602 if (instr.alu.abs_a) { 646 if (instr.alu.abs_a) {
603 op_a = "abs(" + op_a + ')'; 647 op_a = "abs(" + op_a + ')';
604 } 648 }
@@ -609,7 +653,7 @@ private:
609 op_b += GetImmediate19(instr); 653 op_b += GetImmediate19(instr);
610 } else { 654 } else {
611 if (instr.is_b_gpr) { 655 if (instr.is_b_gpr) {
612 op_b += regs.GetRegister(instr.gpr20); 656 op_b += regs.GetRegisterAsFloat(instr.gpr20);
613 } else { 657 } else {
614 op_b += regs.GetUniform(instr.uniform, instr.gpr0); 658 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
615 } 659 }
@@ -620,6 +664,11 @@ private:
620 } 664 }
621 665
622 switch (opcode->GetId()) { 666 switch (opcode->GetId()) {
667 case OpCode::Id::MOV32_IMM: {
668 // mov32i doesn't have abs or neg bits.
669 regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
670 break;
671 }
623 case OpCode::Id::FMUL_C: 672 case OpCode::Id::FMUL_C:
624 case OpCode::Id::FMUL_R: 673 case OpCode::Id::FMUL_R:
625 case OpCode::Id::FMUL_IMM: { 674 case OpCode::Id::FMUL_IMM: {
@@ -629,8 +678,8 @@ private:
629 case OpCode::Id::FMUL32_IMM: { 678 case OpCode::Id::FMUL32_IMM: {
630 // fmul32i doesn't have abs or neg bits. 679 // fmul32i doesn't have abs or neg bits.
631 regs.SetRegisterToFloat( 680 regs.SetRegisterToFloat(
632 instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 681 instr.gpr0, 0,
633 1); 682 regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1);
634 break; 683 break;
635 } 684 }
636 case OpCode::Id::FADD_C: 685 case OpCode::Id::FADD_C:
@@ -687,29 +736,29 @@ private:
687 break; 736 break;
688 } 737 }
689 case OpCode::Type::Ffma: { 738 case OpCode::Type::Ffma: {
690 std::string op_a = regs.GetRegister(instr.gpr8); 739 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
691 std::string op_b = instr.ffma.negate_b ? "-" : ""; 740 std::string op_b = instr.ffma.negate_b ? "-" : "";
692 std::string op_c = instr.ffma.negate_c ? "-" : ""; 741 std::string op_c = instr.ffma.negate_c ? "-" : "";
693 742
694 switch (opcode->GetId()) { 743 switch (opcode->GetId()) {
695 case OpCode::Id::FFMA_CR: { 744 case OpCode::Id::FFMA_CR: {
696 op_b += regs.GetUniform(instr.uniform, instr.gpr0); 745 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
697 op_c += regs.GetRegister(instr.gpr39); 746 op_c += regs.GetRegisterAsFloat(instr.gpr39);
698 break; 747 break;
699 } 748 }
700 case OpCode::Id::FFMA_RR: { 749 case OpCode::Id::FFMA_RR: {
701 op_b += regs.GetRegister(instr.gpr20); 750 op_b += regs.GetRegisterAsFloat(instr.gpr20);
702 op_c += regs.GetRegister(instr.gpr39); 751 op_c += regs.GetRegisterAsFloat(instr.gpr39);
703 break; 752 break;
704 } 753 }
705 case OpCode::Id::FFMA_RC: { 754 case OpCode::Id::FFMA_RC: {
706 op_b += regs.GetRegister(instr.gpr39); 755 op_b += regs.GetRegisterAsFloat(instr.gpr39);
707 op_c += regs.GetUniform(instr.uniform, instr.gpr0); 756 op_c += regs.GetUniform(instr.uniform, instr.gpr0);
708 break; 757 break;
709 } 758 }
710 case OpCode::Id::FFMA_IMM: { 759 case OpCode::Id::FFMA_IMM: {
711 op_b += GetImmediate19(instr); 760 op_b += GetImmediate19(instr);
712 op_c += regs.GetRegister(instr.gpr39); 761 op_c += regs.GetRegisterAsFloat(instr.gpr39);
713 break; 762 break;
714 } 763 }
715 default: { 764 default: {
@@ -721,6 +770,32 @@ private:
721 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1); 770 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
722 break; 771 break;
723 } 772 }
773 case OpCode::Type::Conversion: {
774 ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
775 ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
776 ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
777 ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
778
779 switch (opcode->GetId()) {
780 case OpCode::Id::I2I_R:
781 case OpCode::Id::I2F_R: {
782 std::string op_a =
783 regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
784
785 if (instr.conversion.abs_a) {
786 op_a = "abs(" + op_a + ')';
787 }
788
789 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
790 break;
791 }
792 default: {
793 NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
794 UNREACHABLE();
795 }
796 }
797 break;
798 }
724 case OpCode::Type::Memory: { 799 case OpCode::Type::Memory: {
725 const Attribute::Index attribute = instr.attribute.fmt20.index; 800 const Attribute::Index attribute = instr.attribute.fmt20.index;
726 801
@@ -739,8 +814,8 @@ private:
739 } 814 }
740 case OpCode::Id::TEXS: { 815 case OpCode::Id::TEXS: {
741 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); 816 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
742 const std::string op_a = regs.GetRegister(instr.gpr8); 817 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
743 const std::string op_b = regs.GetRegister(instr.gpr20); 818 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
744 const std::string sampler = GetSampler(instr.sampler); 819 const std::string sampler = GetSampler(instr.sampler);
745 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 820 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
746 // Add an extra scope and declare the texture coords inside to prevent overwriting 821 // Add an extra scope and declare the texture coords inside to prevent overwriting
@@ -765,7 +840,7 @@ private:
765 } 840 }
766 case OpCode::Type::FloatSetPredicate: { 841 case OpCode::Type::FloatSetPredicate: {
767 std::string op_a = instr.fsetp.neg_a ? "-" : ""; 842 std::string op_a = instr.fsetp.neg_a ? "-" : "";
768 op_a += regs.GetRegister(instr.gpr8); 843 op_a += regs.GetRegisterAsFloat(instr.gpr8);
769 844
770 if (instr.fsetp.abs_a) { 845 if (instr.fsetp.abs_a) {
771 op_a = "abs(" + op_a + ')'; 846 op_a = "abs(" + op_a + ')';
@@ -781,7 +856,7 @@ private:
781 op_b += '(' + GetImmediate19(instr) + ')'; 856 op_b += '(' + GetImmediate19(instr) + ')';
782 } else { 857 } else {
783 if (instr.is_b_gpr) { 858 if (instr.is_b_gpr) {
784 op_b += regs.GetRegister(instr.gpr20); 859 op_b += regs.GetRegisterAsFloat(instr.gpr20);
785 } else { 860 } else {
786 op_b += regs.GetUniform(instr.uniform, instr.gpr0); 861 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
787 } 862 }
@@ -816,7 +891,7 @@ private:
816 } 891 }
817 case OpCode::Type::FloatSet: { 892 case OpCode::Type::FloatSet: {
818 std::string op_a = instr.fset.neg_a ? "-" : ""; 893 std::string op_a = instr.fset.neg_a ? "-" : "";
819 op_a += regs.GetRegister(instr.gpr8); 894 op_a += regs.GetRegisterAsFloat(instr.gpr8);
820 895
821 if (instr.fset.abs_a) { 896 if (instr.fset.abs_a) {
822 op_a = "abs(" + op_a + ')'; 897 op_a = "abs(" + op_a + ')';
@@ -832,7 +907,7 @@ private:
832 op_b += imm; 907 op_b += imm;
833 } else { 908 } else {
834 if (instr.is_b_gpr) { 909 if (instr.is_b_gpr) {
835 op_b += regs.GetRegister(instr.gpr20); 910 op_b += regs.GetRegisterAsFloat(instr.gpr20);
836 } else { 911 } else {
837 op_b += regs.GetUniform(instr.uniform, instr.gpr0); 912 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
838 } 913 }
@@ -877,10 +952,10 @@ private:
877 952
878 // Final color output is currently hardcoded to GPR0-3 for fragment shaders 953 // Final color output is currently hardcoded to GPR0-3 for fragment shaders
879 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { 954 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
880 shader.AddLine("color.r = " + regs.GetRegister(0) + ';'); 955 shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';');
881 shader.AddLine("color.g = " + regs.GetRegister(1) + ';'); 956 shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';');
882 shader.AddLine("color.b = " + regs.GetRegister(2) + ';'); 957 shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';');
883 shader.AddLine("color.a = " + regs.GetRegister(3) + ';'); 958 shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';');
884 } 959 }
885 960
886 shader.AddLine("return true;"); 961 shader.AddLine("return true;");