summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp416
1 files changed, 262 insertions, 154 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 3716bb782..8b235e252 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -41,7 +41,7 @@ enum class ExitMethod {
41struct Subroutine { 41struct Subroutine {
42 /// Generates a name suitable for GLSL source code. 42 /// Generates a name suitable for GLSL source code.
43 std::string GetName() const { 43 std::string GetName() const {
44 return "sub_" + std::to_string(begin) + "_" + std::to_string(end); 44 return "sub_" + std::to_string(begin) + '_' + std::to_string(end);
45 } 45 }
46 46
47 u32 begin; ///< Entry point of the subroutine. 47 u32 begin; ///< Entry point of the subroutine.
@@ -216,6 +216,16 @@ public:
216 return declr_type.find(Type::Integer) != declr_type.end(); 216 return declr_type.find(Type::Integer) != declr_type.end();
217 } 217 }
218 218
219 /// Returns true if the active type is float
220 bool IsFloat() const {
221 return active_type == Type::Float;
222 }
223
224 /// Returns true if the active type is integer
225 bool IsInteger() const {
226 return active_type == Type::Integer;
227 }
228
219private: 229private:
220 enum class Type { 230 enum class Type {
221 Float, 231 Float,
@@ -230,41 +240,168 @@ private:
230 std::set<Type> declr_type; 240 std::set<Type> declr_type;
231}; 241};
232 242
233class GLSLGenerator { 243/**
244 * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state
245 * of all registers (e.g. whether they are currently being used as Floats or Integers), and
246 * generates the necessary GLSL code to perform conversions as needed. This class is used for
247 * bookkeeping within the GLSL program.
248 */
249class GLSLRegisterManager {
234public: 250public:
235 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, 251 GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations,
236 u32 main_offset, Maxwell3D::Regs::ShaderStage stage) 252 const Maxwell3D::Regs::ShaderStage& stage)
237 : subroutines(subroutines), program_code(program_code), main_offset(main_offset), 253 : shader{shader}, declarations{declarations}, stage{stage} {
238 stage(stage) {
239
240 BuildRegisterList(); 254 BuildRegisterList();
241 Generate();
242 } 255 }
243 256
244 std::string GetShaderCode() { 257 /// Generates code representing a temporary (GPR) register.
245 return declarations.GetResult() + shader.GetResult(); 258 std::string GetRegister(const Register& reg, unsigned elem = 0) {
259 if (reg == Register::ZeroIndex) {
260 return "0";
261 }
262
263 return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
246 } 264 }
247 265
248 /// Returns entries in the shader that are useful for external functions 266 /**
249 ShaderEntries GetEntries() const { 267 * Writes code that does a register assignment to float value operation. Should only be used
250 return {GetConstBuffersDeclarations()}; 268 * with shader instructions that deal with floats.
269 * @param reg The destination register to use.
270 * @param elem The element to use for the operation.
271 * @param value The code representing the value to assign.
272 * @param dest_num_components Number of components in the destination.
273 * @param value_num_components Number of components in the value.
274 * @param is_abs Optional, when True, applies absolute value to output.
275 * @param dest_elem Optional, the destination element to use for the operation.
276 */
277 void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
278 u64 dest_num_components, u64 value_num_components, bool is_abs = false,
279 u64 dest_elem = 0) {
280 ASSERT(regs[reg].IsFloat());
281
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
294 shader.AddLine(dest + " = " + src + ';');
295 }
296
297 /**
298 * Writes code that does a register assignment to input attribute operation. Input attributes
299 * are stored as floats, so this may require conversion.
300 * @param reg The destination register to use.
301 * @param elem The element to use for the operation.
302 * @param attribute The input attibute to use as the source value.
303 */
304 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
305 std::string dest = GetRegister(reg);
306 std::string src = GetInputAttribute(attribute) + GetSwizzle(elem);
307
308 if (regs[reg].IsFloat()) {
309 shader.AddLine(dest + " = " + src + ';');
310 } else if (regs[reg].IsInteger()) {
311 shader.AddLine(dest + " = floatBitsToInt(" + src + ");");
312 } else {
313 UNREACHABLE();
314 }
315 }
316
317 /**
318 * Writes code that does a output attribute assignment to register operation. Output attributes
319 * are stored as floats, so this may require conversion.
320 * @param attribute The destination output attribute.
321 * @param elem The element to use for the operation.
322 * @param reg The register to use as the source value.
323 */
324 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
325 std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
326 std::string src = GetRegister(reg);
327 ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float");
328 shader.AddLine(dest + " = " + src + ';');
329 }
330
331 /// Generates code representing a uniform (C buffer) register.
332 std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
333 declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index),
334 static_cast<unsigned>(uniform.offset), stage);
335 std::string value =
336 'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']';
337
338 if (regs[dest_reg].IsFloat()) {
339 return value;
340 } else if (regs[dest_reg].IsInteger()) {
341 return "floatBitsToInt(" + value + ')';
342 } else {
343 UNREACHABLE();
344 }
345 }
346
347 /// Add declarations for registers
348 void GenerateDeclarations() {
349 for (const auto& reg : regs) {
350 if (reg.IsFloatUsed()) {
351 declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;");
352 }
353 if (reg.IsIntegerUsed()) {
354 declarations.AddLine("int " + reg.GetIntegerString() + " = 0;");
355 }
356 }
357 declarations.AddNewLine();
358
359 for (const auto& index : declr_input_attribute) {
360 // TODO(bunnei): Use proper number of elements for these
361 declarations.AddLine("layout(location = " +
362 std::to_string(static_cast<u32>(index) -
363 static_cast<u32>(Attribute::Index::Attribute_0)) +
364 ") in vec4 " + GetInputAttribute(index) + ';');
365 }
366 declarations.AddNewLine();
367
368 for (const auto& index : declr_output_attribute) {
369 // TODO(bunnei): Use proper number of elements for these
370 declarations.AddLine("layout(location = " +
371 std::to_string(static_cast<u32>(index) -
372 static_cast<u32>(Attribute::Index::Attribute_0)) +
373 ") out vec4 " + GetOutputAttribute(index) + ';');
374 }
375 declarations.AddNewLine();
376
377 unsigned const_buffer_layout = 0;
378 for (const auto& entry : GetConstBuffersDeclarations()) {
379 declarations.AddLine("layout(std430) buffer " + entry.GetName());
380 declarations.AddLine('{');
381 declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
382 declarations.AddLine("};");
383 declarations.AddNewLine();
384 ++const_buffer_layout;
385 }
386 declarations.AddNewLine();
387 }
388
389 /// Returns a list of constant buffer declarations
390 std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
391 std::vector<ConstBufferEntry> result;
392 std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
393 std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
394 return result;
251 } 395 }
252 396
253private: 397private:
254 /// Build the GLSL register list 398 /// Build the GLSL register list.
255 void BuildRegisterList() { 399 void BuildRegisterList() {
256 for (size_t index = 0; index < Register::NumRegisters; ++index) { 400 for (size_t index = 0; index < Register::NumRegisters; ++index) {
257 regs.emplace_back(index, shader); 401 regs.emplace_back(index, shader);
258 } 402 }
259 } 403 }
260 404
261 /// Gets the Subroutine object corresponding to the specified address.
262 const Subroutine& GetSubroutine(u32 begin, u32 end) const {
263 auto iter = subroutines.find(Subroutine{begin, end});
264 ASSERT(iter != subroutines.end());
265 return *iter;
266 }
267
268 /// Generates code representing an input attribute register. 405 /// Generates code representing an input attribute register.
269 std::string GetInputAttribute(Attribute::Index attribute) { 406 std::string GetInputAttribute(Attribute::Index attribute) {
270 switch (attribute) { 407 switch (attribute) {
@@ -301,6 +438,50 @@ private:
301 } 438 }
302 } 439 }
303 440
441 /// Generates code to use for a swizzle operation.
442 static std::string GetSwizzle(u64 elem) {
443 ASSERT(elem <= 3);
444 std::string swizzle = ".";
445 swizzle += "xyzw"[elem];
446 return swizzle;
447 }
448
449 ShaderWriter& shader;
450 ShaderWriter& declarations;
451 std::vector<GLSLRegister> regs;
452 std::set<Attribute::Index> declr_input_attribute;
453 std::set<Attribute::Index> declr_output_attribute;
454 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
455 const Maxwell3D::Regs::ShaderStage& stage;
456};
457
458class GLSLGenerator {
459public:
460 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
461 u32 main_offset, Maxwell3D::Regs::ShaderStage stage)
462 : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
463 stage(stage) {
464
465 Generate();
466 }
467
468 std::string GetShaderCode() {
469 return declarations.GetResult() + shader.GetResult();
470 }
471
472 /// Returns entries in the shader that are useful for external functions
473 ShaderEntries GetEntries() const {
474 return {regs.GetConstBuffersDeclarations()};
475 }
476
477private:
478 /// Gets the Subroutine object corresponding to the specified address.
479 const Subroutine& GetSubroutine(u32 begin, u32 end) const {
480 auto iter = subroutines.find(Subroutine{begin, end});
481 ASSERT(iter != subroutines.end());
482 return *iter;
483 }
484
304 /// Generates code representing a 19-bit immediate value 485 /// Generates code representing a 19-bit immediate value
305 static std::string GetImmediate19(const Instruction& instr) { 486 static std::string GetImmediate19(const Instruction& instr) {
306 return std::to_string(instr.alu.GetImm20_19()); 487 return std::to_string(instr.alu.GetImm20_19());
@@ -311,29 +492,13 @@ private:
311 return std::to_string(instr.alu.GetImm20_32()); 492 return std::to_string(instr.alu.GetImm20_32());
312 } 493 }
313 494
314 /// Generates code representing a temporary (GPR) register.
315 std::string GetRegister(const Register& reg, unsigned elem = 0) {
316 if (reg == Register::ZeroIndex) {
317 return "0";
318 }
319
320 return regs[reg.GetSwizzledIndex(elem)].GetActiveString();
321 }
322
323 /// Generates code representing a uniform (C buffer) register.
324 std::string GetUniform(const Uniform& reg) {
325 declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
326 static_cast<unsigned>(reg.offset), stage);
327 return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
328 }
329
330 /// Generates code representing a texture sampler. 495 /// Generates code representing a texture sampler.
331 std::string GetSampler(const Sampler& sampler) const { 496 std::string GetSampler(const Sampler& sampler) const {
332 // TODO(Subv): Support more than just texture sampler 0 497 // TODO(Subv): Support more than just texture sampler 0
333 ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported"); 498 ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
334 const unsigned index{static_cast<unsigned>(sampler.index.Value()) - 499 const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
335 static_cast<unsigned>(Sampler::Index::Sampler_0)}; 500 static_cast<unsigned>(Sampler::Index::Sampler_0)};
336 return "tex[" + std::to_string(index) + "]"; 501 return "tex[" + std::to_string(index) + ']';
337 } 502 }
338 503
339 /** 504 /**
@@ -351,23 +516,6 @@ private:
351 } 516 }
352 } 517 }
353 518
354 /**
355 * Writes code that does an assignment operation.
356 * @param reg the destination register code.
357 * @param value the code representing the value to assign.
358 */
359 void SetDest(u64 elem, const std::string& reg, const std::string& value,
360 u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
361 std::string swizzle = ".";
362 swizzle += "xyzw"[elem];
363
364 std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
365 std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
366 src = is_abs ? "abs(" + src + ")" : src;
367
368 shader.AddLine(dest + " = " + src + ";");
369 }
370
371 /* 519 /*
372 * Writes code that assigns a predicate boolean variable. 520 * Writes code that assigns a predicate boolean variable.
373 * @param pred The id of the predicate to write to. 521 * @param pred The id of the predicate to write to.
@@ -449,11 +597,10 @@ private:
449 597
450 switch (opcode->GetType()) { 598 switch (opcode->GetType()) {
451 case OpCode::Type::Arithmetic: { 599 case OpCode::Type::Arithmetic: {
452 std::string dest = GetRegister(instr.gpr0);
453 std::string op_a = instr.alu.negate_a ? "-" : ""; 600 std::string op_a = instr.alu.negate_a ? "-" : "";
454 op_a += GetRegister(instr.gpr8); 601 op_a += regs.GetRegister(instr.gpr8);
455 if (instr.alu.abs_a) { 602 if (instr.alu.abs_a) {
456 op_a = "abs(" + op_a + ")"; 603 op_a = "abs(" + op_a + ')';
457 } 604 }
458 605
459 std::string op_b = instr.alu.negate_b ? "-" : ""; 606 std::string op_b = instr.alu.negate_b ? "-" : "";
@@ -462,56 +609,64 @@ private:
462 op_b += GetImmediate19(instr); 609 op_b += GetImmediate19(instr);
463 } else { 610 } else {
464 if (instr.is_b_gpr) { 611 if (instr.is_b_gpr) {
465 op_b += GetRegister(instr.gpr20); 612 op_b += regs.GetRegister(instr.gpr20);
466 } else { 613 } else {
467 op_b += GetUniform(instr.uniform); 614 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
468 } 615 }
469 } 616 }
470 617
471 if (instr.alu.abs_b) { 618 if (instr.alu.abs_b) {
472 op_b = "abs(" + op_b + ")"; 619 op_b = "abs(" + op_b + ')';
473 } 620 }
474 621
475 switch (opcode->GetId()) { 622 switch (opcode->GetId()) {
476 case OpCode::Id::FMUL_C: 623 case OpCode::Id::FMUL_C:
477 case OpCode::Id::FMUL_R: 624 case OpCode::Id::FMUL_R:
478 case OpCode::Id::FMUL_IMM: { 625 case OpCode::Id::FMUL_IMM: {
479 SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d); 626 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
480 break; 627 break;
481 } 628 }
482 case OpCode::Id::FMUL32_IMM: { 629 case OpCode::Id::FMUL32_IMM: {
483 // fmul32i doesn't have abs or neg bits. 630 // fmul32i doesn't have abs or neg bits.
484 SetDest(0, dest, GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); 631 regs.SetRegisterToFloat(
632 instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1,
633 1);
485 break; 634 break;
486 } 635 }
487 case OpCode::Id::FADD_C: 636 case OpCode::Id::FADD_C:
488 case OpCode::Id::FADD_R: 637 case OpCode::Id::FADD_R:
489 case OpCode::Id::FADD_IMM: { 638 case OpCode::Id::FADD_IMM: {
490 SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d); 639 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
491 break; 640 break;
492 } 641 }
493 case OpCode::Id::MUFU: { 642 case OpCode::Id::MUFU: {
494 switch (instr.sub_op) { 643 switch (instr.sub_op) {
495 case SubOp::Cos: 644 case SubOp::Cos:
496 SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d); 645 regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1,
646 instr.alu.abs_d);
497 break; 647 break;
498 case SubOp::Sin: 648 case SubOp::Sin:
499 SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d); 649 regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1,
650 instr.alu.abs_d);
500 break; 651 break;
501 case SubOp::Ex2: 652 case SubOp::Ex2:
502 SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d); 653 regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1,
654 instr.alu.abs_d);
503 break; 655 break;
504 case SubOp::Lg2: 656 case SubOp::Lg2:
505 SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d); 657 regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1,
658 instr.alu.abs_d);
506 break; 659 break;
507 case SubOp::Rcp: 660 case SubOp::Rcp:
508 SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); 661 regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
509 break; 662 break;
510 case SubOp::Rsq: 663 case SubOp::Rsq:
511 SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d); 664 regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1,
665 instr.alu.abs_d);
512 break; 666 break;
513 case SubOp::Min: 667 case SubOp::Min:
514 SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d); 668 regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1,
669 instr.alu.abs_d);
515 break; 670 break;
516 default: 671 default:
517 NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", 672 NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
@@ -532,30 +687,29 @@ private:
532 break; 687 break;
533 } 688 }
534 case OpCode::Type::Ffma: { 689 case OpCode::Type::Ffma: {
535 std::string dest = GetRegister(instr.gpr0); 690 std::string op_a = regs.GetRegister(instr.gpr8);
536 std::string op_a = GetRegister(instr.gpr8);
537 std::string op_b = instr.ffma.negate_b ? "-" : ""; 691 std::string op_b = instr.ffma.negate_b ? "-" : "";
538 std::string op_c = instr.ffma.negate_c ? "-" : ""; 692 std::string op_c = instr.ffma.negate_c ? "-" : "";
539 693
540 switch (opcode->GetId()) { 694 switch (opcode->GetId()) {
541 case OpCode::Id::FFMA_CR: { 695 case OpCode::Id::FFMA_CR: {
542 op_b += GetUniform(instr.uniform); 696 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
543 op_c += GetRegister(instr.gpr39); 697 op_c += regs.GetRegister(instr.gpr39);
544 break; 698 break;
545 } 699 }
546 case OpCode::Id::FFMA_RR: { 700 case OpCode::Id::FFMA_RR: {
547 op_b += GetRegister(instr.gpr20); 701 op_b += regs.GetRegister(instr.gpr20);
548 op_c += GetRegister(instr.gpr39); 702 op_c += regs.GetRegister(instr.gpr39);
549 break; 703 break;
550 } 704 }
551 case OpCode::Id::FFMA_RC: { 705 case OpCode::Id::FFMA_RC: {
552 op_b += GetRegister(instr.gpr39); 706 op_b += regs.GetRegister(instr.gpr39);
553 op_c += GetUniform(instr.uniform); 707 op_c += regs.GetUniform(instr.uniform, instr.gpr0);
554 break; 708 break;
555 } 709 }
556 case OpCode::Id::FFMA_IMM: { 710 case OpCode::Id::FFMA_IMM: {
557 op_b += GetImmediate19(instr); 711 op_b += GetImmediate19(instr);
558 op_c += GetRegister(instr.gpr39); 712 op_c += regs.GetRegister(instr.gpr39);
559 break; 713 break;
560 } 714 }
561 default: { 715 default: {
@@ -564,28 +718,29 @@ private:
564 } 718 }
565 } 719 }
566 720
567 SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); 721 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1);
568 break; 722 break;
569 } 723 }
570 case OpCode::Type::Memory: { 724 case OpCode::Type::Memory: {
571 std::string gpr0 = GetRegister(instr.gpr0);
572 const Attribute::Index attribute = instr.attribute.fmt20.index; 725 const Attribute::Index attribute = instr.attribute.fmt20.index;
573 726
574 switch (opcode->GetId()) { 727 switch (opcode->GetId()) {
575 case OpCode::Id::LD_A: { 728 case OpCode::Id::LD_A: {
576 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 729 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
577 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); 730 regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element,
731 attribute);
578 break; 732 break;
579 } 733 }
580 case OpCode::Id::ST_A: { 734 case OpCode::Id::ST_A: {
581 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 735 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
582 SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); 736 regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element,
737 instr.gpr0);
583 break; 738 break;
584 } 739 }
585 case OpCode::Id::TEXS: { 740 case OpCode::Id::TEXS: {
586 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); 741 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
587 const std::string op_a = GetRegister(instr.gpr8); 742 const std::string op_a = regs.GetRegister(instr.gpr8);
588 const std::string op_b = GetRegister(instr.gpr20); 743 const std::string op_b = regs.GetRegister(instr.gpr20);
589 const std::string sampler = GetSampler(instr.sampler); 744 const std::string sampler = GetSampler(instr.sampler);
590 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 745 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
591 // Add an extra scope and declare the texture coords inside to prevent overwriting 746 // Add an extra scope and declare the texture coords inside to prevent overwriting
@@ -595,7 +750,7 @@ private:
595 shader.AddLine(coord); 750 shader.AddLine(coord);
596 const std::string texture = "texture(" + sampler + ", coords)"; 751 const std::string texture = "texture(" + sampler + ", coords)";
597 for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) { 752 for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
598 SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4); 753 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, elem);
599 } 754 }
600 --shader.scope; 755 --shader.scope;
601 shader.AddLine("}"); 756 shader.AddLine("}");
@@ -610,7 +765,7 @@ private:
610 } 765 }
611 case OpCode::Type::FloatSetPredicate: { 766 case OpCode::Type::FloatSetPredicate: {
612 std::string op_a = instr.fsetp.neg_a ? "-" : ""; 767 std::string op_a = instr.fsetp.neg_a ? "-" : "";
613 op_a += GetRegister(instr.gpr8); 768 op_a += regs.GetRegister(instr.gpr8);
614 769
615 if (instr.fsetp.abs_a) { 770 if (instr.fsetp.abs_a) {
616 op_a = "abs(" + op_a + ')'; 771 op_a = "abs(" + op_a + ')';
@@ -626,9 +781,9 @@ private:
626 op_b += '(' + GetImmediate19(instr) + ')'; 781 op_b += '(' + GetImmediate19(instr) + ')';
627 } else { 782 } else {
628 if (instr.is_b_gpr) { 783 if (instr.is_b_gpr) {
629 op_b += GetRegister(instr.gpr20); 784 op_b += regs.GetRegister(instr.gpr20);
630 } else { 785 } else {
631 op_b += GetUniform(instr.uniform); 786 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
632 } 787 }
633 } 788 }
634 789
@@ -660,9 +815,8 @@ private:
660 break; 815 break;
661 } 816 }
662 case OpCode::Type::FloatSet: { 817 case OpCode::Type::FloatSet: {
663 std::string dest = GetRegister(instr.gpr0);
664 std::string op_a = instr.fset.neg_a ? "-" : ""; 818 std::string op_a = instr.fset.neg_a ? "-" : "";
665 op_a += GetRegister(instr.gpr8); 819 op_a += regs.GetRegister(instr.gpr8);
666 820
667 if (instr.fset.abs_a) { 821 if (instr.fset.abs_a) {
668 op_a = "abs(" + op_a + ')'; 822 op_a = "abs(" + op_a + ')';
@@ -678,14 +832,14 @@ private:
678 op_b += imm; 832 op_b += imm;
679 } else { 833 } else {
680 if (instr.is_b_gpr) { 834 if (instr.is_b_gpr) {
681 op_b += GetRegister(instr.gpr20); 835 op_b += regs.GetRegister(instr.gpr20);
682 } else { 836 } else {
683 op_b += GetUniform(instr.uniform); 837 op_b += regs.GetUniform(instr.uniform, instr.gpr0);
684 } 838 }
685 } 839 }
686 840
687 if (instr.fset.abs_b) { 841 if (instr.fset.abs_b) {
688 op_b = "abs(" + op_b + ")"; 842 op_b = "abs(" + op_b + ')';
689 } 843 }
690 844
691 using Tegra::Shader::Pred; 845 using Tegra::Shader::Pred;
@@ -697,13 +851,16 @@ private:
697 using Tegra::Shader::PredCondition; 851 using Tegra::Shader::PredCondition;
698 switch (instr.fset.cond) { 852 switch (instr.fset.cond) {
699 case PredCondition::LessThan: 853 case PredCondition::LessThan:
700 SetDest(0, dest, "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1); 854 regs.SetRegisterToFloat(instr.gpr0, 0,
855 "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1);
701 break; 856 break;
702 case PredCondition::Equal: 857 case PredCondition::Equal:
703 SetDest(0, dest, "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1); 858 regs.SetRegisterToFloat(instr.gpr0, 0,
859 "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1);
704 break; 860 break;
705 case PredCondition::GreaterThan: 861 case PredCondition::GreaterThan:
706 SetDest(0, dest, "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1); 862 regs.SetRegisterToFloat(instr.gpr0, 0,
863 "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1);
707 break; 864 break;
708 default: 865 default:
709 NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", 866 NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
@@ -720,10 +877,10 @@ private:
720 877
721 // Final color output is currently hardcoded to GPR0-3 for fragment shaders 878 // Final color output is currently hardcoded to GPR0-3 for fragment shaders
722 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { 879 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
723 shader.AddLine("color.r = " + GetRegister(0) + ";"); 880 shader.AddLine("color.r = " + regs.GetRegister(0) + ';');
724 shader.AddLine("color.g = " + GetRegister(1) + ";"); 881 shader.AddLine("color.g = " + regs.GetRegister(1) + ';');
725 shader.AddLine("color.b = " + GetRegister(2) + ";"); 882 shader.AddLine("color.b = " + regs.GetRegister(2) + ';');
726 shader.AddLine("color.a = " + GetRegister(3) + ";"); 883 shader.AddLine("color.a = " + regs.GetRegister(3) + ';');
727 } 884 }
728 885
729 shader.AddLine("return true;"); 886 shader.AddLine("return true;");
@@ -736,8 +893,7 @@ private:
736 } 893 }
737 case OpCode::Id::IPA: { 894 case OpCode::Id::IPA: {
738 const auto& attribute = instr.attribute.fmt28; 895 const auto& attribute = instr.attribute.fmt28;
739 std::string dest = GetRegister(instr.gpr0); 896 regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index);
740 SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
741 break; 897 break;
742 } 898 }
743 default: { 899 default: {
@@ -843,55 +999,10 @@ private:
843 GenerateDeclarations(); 999 GenerateDeclarations();
844 } 1000 }
845 1001
846 /// Returns a list of constant buffer declarations
847 std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
848 std::vector<ConstBufferEntry> result;
849 std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
850 std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
851 return result;
852 }
853
854 /// Add declarations for registers 1002 /// Add declarations for registers
855 void GenerateDeclarations() { 1003 void GenerateDeclarations() {
856 for (const auto& reg : regs) { 1004 regs.GenerateDeclarations();
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 }
863 }
864 declarations.AddNewLine();
865 1005
866 for (const auto& index : declr_input_attribute) {
867 // TODO(bunnei): Use proper number of elements for these
868 declarations.AddLine("layout(location = " +
869 std::to_string(static_cast<u32>(index) -
870 static_cast<u32>(Attribute::Index::Attribute_0)) +
871 ") in vec4 " + GetInputAttribute(index) + ";");
872 }
873 declarations.AddNewLine();
874
875 for (const auto& index : declr_output_attribute) {
876 // TODO(bunnei): Use proper number of elements for these
877 declarations.AddLine("layout(location = " +
878 std::to_string(static_cast<u32>(index) -
879 static_cast<u32>(Attribute::Index::Attribute_0)) +
880 ") out vec4 " + GetOutputAttribute(index) + ";");
881 }
882 declarations.AddNewLine();
883
884 unsigned const_buffer_layout = 0;
885 for (const auto& entry : GetConstBuffersDeclarations()) {
886 declarations.AddLine("layout(std430) buffer " + entry.GetName());
887 declarations.AddLine('{');
888 declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
889 declarations.AddLine("};");
890 declarations.AddNewLine();
891 ++const_buffer_layout;
892 }
893
894 declarations.AddNewLine();
895 for (const auto& pred : declr_predicates) { 1006 for (const auto& pred : declr_predicates) {
896 declarations.AddLine("bool " + pred + " = false;"); 1007 declarations.AddLine("bool " + pred + " = false;");
897 } 1008 }
@@ -906,13 +1017,10 @@ private:
906 1017
907 ShaderWriter shader; 1018 ShaderWriter shader;
908 ShaderWriter declarations; 1019 ShaderWriter declarations;
909 std::vector<GLSLRegister> regs; 1020 GLSLRegisterManager regs{shader, declarations, stage};
910 1021
911 // Declarations 1022 // Declarations
912 std::set<std::string> declr_predicates; 1023 std::set<std::string> declr_predicates;
913 std::set<Attribute::Index> declr_input_attribute;
914 std::set<Attribute::Index> declr_output_attribute;
915 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
916}; // namespace Decompiler 1024}; // namespace Decompiler
917 1025
918std::string GetCommonDeclarations() { 1026std::string GetCommonDeclarations() {