summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-04-20 22:29:39 -0400
committerGravatar GitHub2018-04-20 22:29:39 -0400
commit8ac3a3f45e2102da5cc3b56e4be9b5e766f72358 (patch)
treec74be88544f6465fe3afad898654dced8d51f006 /src
parentMerge pull request #374 from lioncash/noexcept (diff)
parentShaderGen: Implemented the KIL instruction, which is equivalent to 'discard'. (diff)
downloadyuzu-8ac3a3f45e2102da5cc3b56e4be9b5e766f72358.tar.gz
yuzu-8ac3a3f45e2102da5cc3b56e4be9b5e766f72358.tar.xz
yuzu-8ac3a3f45e2102da5cc3b56e4be9b5e766f72358.zip
Merge pull request #369 from Subv/shader_instr2
ShaderGen: Implemented fsetp/kil and predicated instruction execution.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h52
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp131
2 files changed, 179 insertions, 4 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 7cd125f05..e6c2fd367 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -13,6 +13,9 @@ namespace Tegra {
13namespace Shader { 13namespace Shader {
14 14
15struct Register { 15struct Register {
16 // Register 255 is special cased to always be 0
17 static constexpr size_t ZeroIndex = 255;
18
16 constexpr Register() = default; 19 constexpr Register() = default;
17 20
18 constexpr Register(u64 value) : value(value) {} 21 constexpr Register(u64 value) : value(value) {}
@@ -106,6 +109,8 @@ union OpCode {
106 109
107 FSETP_R = 0x5BB, 110 FSETP_R = 0x5BB,
108 FSETP_C = 0x4BB, 111 FSETP_C = 0x4BB,
112 FSETP_IMM = 0x36B,
113 FSETP_NEG_IMM = 0x37B,
109 EXIT = 0xE30, 114 EXIT = 0xE30,
110 KIL = 0xE33, 115 KIL = 0xE33,
111 116
@@ -121,6 +126,7 @@ union OpCode {
121 Ffma, 126 Ffma,
122 Flow, 127 Flow,
123 Memory, 128 Memory,
129 FloatPredicate,
124 Unknown, 130 Unknown,
125 }; 131 };
126 132
@@ -161,6 +167,9 @@ union OpCode {
161 case Id::FSETP_C: 167 case Id::FSETP_C:
162 case Id::KIL: 168 case Id::KIL:
163 return op4; 169 return op4;
170 case Id::FSETP_IMM:
171 case Id::FSETP_NEG_IMM:
172 return Id::FSETP_IMM;
164 } 173 }
165 174
166 switch (op5) { 175 switch (op5) {
@@ -238,8 +247,9 @@ union OpCode {
238 info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"}; 247 info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"};
239 info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"}; 248 info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"};
240 info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"}; 249 info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"};
241 info_table[Id::FSETP_C] = {Type::Arithmetic, "fsetp_c"}; 250 info_table[Id::FSETP_C] = {Type::FloatPredicate, "fsetp_c"};
242 info_table[Id::FSETP_R] = {Type::Arithmetic, "fsetp_r"}; 251 info_table[Id::FSETP_R] = {Type::FloatPredicate, "fsetp_r"};
252 info_table[Id::FSETP_IMM] = {Type::FloatPredicate, "fsetp_imm"};
243 info_table[Id::EXIT] = {Type::Trivial, "exit"}; 253 info_table[Id::EXIT] = {Type::Trivial, "exit"};
244 info_table[Id::IPA] = {Type::Trivial, "ipa"}; 254 info_table[Id::IPA] = {Type::Trivial, "ipa"};
245 info_table[Id::KIL] = {Type::Flow, "kil"}; 255 info_table[Id::KIL] = {Type::Flow, "kil"};
@@ -283,7 +293,23 @@ namespace Shader {
283 293
284enum class Pred : u64 { 294enum class Pred : u64 {
285 UnusedIndex = 0x7, 295 UnusedIndex = 0x7,
286 NeverExecute = 0xf, 296 NeverExecute = 0xF,
297};
298
299enum class PredCondition : u64 {
300 LessThan = 1,
301 Equal = 2,
302 LessEqual = 3,
303 GreaterThan = 4,
304 NotEqual = 5,
305 GreaterEqual = 6,
306 // TODO(Subv): Other condition types
307};
308
309enum class PredOperation : u64 {
310 And = 0,
311 Or = 1,
312 Xor = 2,
287}; 313};
288 314
289enum class SubOp : u64 { 315enum class SubOp : u64 {
@@ -305,7 +331,11 @@ union Instruction {
305 OpCode opcode; 331 OpCode opcode;
306 BitField<0, 8, Register> gpr0; 332 BitField<0, 8, Register> gpr0;
307 BitField<8, 8, Register> gpr8; 333 BitField<8, 8, Register> gpr8;
308 BitField<16, 4, Pred> pred; 334 union {
335 BitField<16, 4, Pred> full_pred;
336 BitField<16, 3, u64> pred_index;
337 } pred;
338 BitField<19, 1, u64> negate_pred;
309 BitField<20, 8, Register> gpr20; 339 BitField<20, 8, Register> gpr20;
310 BitField<20, 7, SubOp> sub_op; 340 BitField<20, 7, SubOp> sub_op;
311 BitField<28, 8, Register> gpr28; 341 BitField<28, 8, Register> gpr28;
@@ -343,6 +373,20 @@ union Instruction {
343 BitField<49, 1, u64> negate_c; 373 BitField<49, 1, u64> negate_c;
344 } ffma; 374 } ffma;
345 375
376 union {
377 BitField<0, 3, u64> pred0;
378 BitField<3, 3, u64> pred3;
379 BitField<7, 1, u64> abs_a;
380 BitField<39, 3, u64> pred39;
381 BitField<42, 1, u64> neg_pred;
382 BitField<43, 1, u64> neg_a;
383 BitField<44, 1, u64> abs_b;
384 BitField<45, 2, PredOperation> op;
385 BitField<47, 1, u64> ftz;
386 BitField<48, 4, PredCondition> cond;
387 BitField<56, 1, u64> neg_b;
388 } fsetp;
389
346 BitField<61, 1, u64> is_b_imm; 390 BitField<61, 1, u64> is_b_imm;
347 BitField<60, 1, u64> is_b_gpr; 391 BitField<60, 1, u64> is_b_gpr;
348 BitField<59, 1, u64> is_c_gpr; 392 BitField<59, 1, u64> is_c_gpr;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index de137558d..2395945c3 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -220,6 +220,8 @@ private:
220 220
221 /// Generates code representing a temporary (GPR) register. 221 /// Generates code representing a temporary (GPR) register.
222 std::string GetRegister(const Register& reg, unsigned elem = 0) { 222 std::string GetRegister(const Register& reg, unsigned elem = 0) {
223 if (reg == Register::ZeroIndex)
224 return "0";
223 if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) { 225 if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
224 // GPRs 0-3 are output color for the fragment shader 226 // GPRs 0-3 are output color for the fragment shader
225 return std::string{"color."} + "rgba"[(reg + elem) & 3]; 227 return std::string{"color."} + "rgba"[(reg + elem) & 3];
@@ -276,6 +278,52 @@ private:
276 shader.AddLine(dest + " = " + src + ";"); 278 shader.AddLine(dest + " = " + src + ";");
277 } 279 }
278 280
281 /*
282 * Writes code that assigns a predicate boolean variable.
283 * @param pred The id of the predicate to write to.
284 * @param value The expression value to assign to the predicate.
285 */
286 void SetPredicate(u64 pred, const std::string& value) {
287 using Tegra::Shader::Pred;
288 // Can't assign to the constant predicate.
289 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
290
291 std::string variable = 'p' + std::to_string(pred);
292 shader.AddLine(variable + " = " + value + ';');
293 declr_predicates.insert(std::move(variable));
294 }
295
296 /*
297 * Returns the condition to use in the 'if' for a predicated instruction.
298 * @param instr Instruction to generate the if condition for.
299 * @returns string containing the predicate condition.
300 */
301 std::string GetPredicateCondition(Instruction instr) const {
302 using Tegra::Shader::Pred;
303 ASSERT(instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex));
304
305 std::string variable =
306 'p' + std::to_string(static_cast<u64>(instr.pred.pred_index.Value()));
307
308 if (instr.negate_pred) {
309 return "!(" + variable + ')';
310 }
311
312 return variable;
313 }
314
315 /*
316 * Returns whether the instruction at the specified offset is a 'sched' instruction.
317 * Sched instructions always appear before a sequence of 3 instructions.
318 */
319 bool IsSchedInstruction(u32 offset) const {
320 // sched instructions appear once every 4 instructions.
321 static constexpr size_t SchedPeriod = 4;
322 u32 absolute_offset = offset - main_offset;
323
324 return (absolute_offset % SchedPeriod) == 0;
325 }
326
279 /** 327 /**
280 * Compiles a single instruction from Tegra to GLSL. 328 * Compiles a single instruction from Tegra to GLSL.
281 * @param offset the offset of the Tegra shader instruction. 329 * @param offset the offset of the Tegra shader instruction.
@@ -283,10 +331,24 @@ private:
283 * + 1. If the current instruction always terminates the program, returns PROGRAM_END. 331 * + 1. If the current instruction always terminates the program, returns PROGRAM_END.
284 */ 332 */
285 u32 CompileInstr(u32 offset) { 333 u32 CompileInstr(u32 offset) {
334 // Ignore sched instructions when generating code.
335 if (IsSchedInstruction(offset))
336 return offset + 1;
337
286 const Instruction instr = {program_code[offset]}; 338 const Instruction instr = {program_code[offset]};
287 339
288 shader.AddLine("// " + std::to_string(offset) + ": " + OpCode::GetInfo(instr.opcode).name); 340 shader.AddLine("// " + std::to_string(offset) + ": " + OpCode::GetInfo(instr.opcode).name);
289 341
342 using Tegra::Shader::Pred;
343 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
344 "NeverExecute predicate not implemented");
345
346 if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
347 shader.AddLine("if (" + GetPredicateCondition(instr) + ')');
348 shader.AddLine('{');
349 ++shader.scope;
350 }
351
290 switch (OpCode::GetInfo(instr.opcode).type) { 352 switch (OpCode::GetInfo(instr.opcode).type) {
291 case OpCode::Type::Arithmetic: { 353 case OpCode::Type::Arithmetic: {
292 std::string dest = GetRegister(instr.gpr0); 354 std::string dest = GetRegister(instr.gpr0);
@@ -450,14 +512,70 @@ private:
450 } 512 }
451 break; 513 break;
452 } 514 }
515 case OpCode::Type::FloatPredicate: {
516 std::string op_a = instr.fsetp.neg_a ? "-" : "";
517 op_a += GetRegister(instr.gpr8);
518
519 if (instr.fsetp.abs_a) {
520 op_a = "abs(" + op_a + ')';
521 }
522
523 std::string op_b{};
524
525 if (instr.is_b_imm) {
526 if (instr.fsetp.neg_b) {
527 // Only the immediate version of fsetp has a neg_b bit.
528 op_b += '-';
529 }
530 op_b += '(' + GetImmediate19(instr) + ')';
531 } else {
532 if (instr.is_b_gpr) {
533 op_b += GetRegister(instr.gpr20);
534 } else {
535 op_b += GetUniform(instr.uniform);
536 }
537 }
453 538
539 if (instr.fsetp.abs_b) {
540 op_b = "abs(" + op_b + ')';
541 }
542
543 using Tegra::Shader::Pred;
544 ASSERT_MSG(instr.fsetp.pred0 == static_cast<u64>(Pred::UnusedIndex) &&
545 instr.fsetp.pred39 == static_cast<u64>(Pred::UnusedIndex),
546 "Compound predicates are not implemented");
547
548 // We can't use the constant predicate as destination.
549 ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
550
551 using Tegra::Shader::PredCondition;
552 switch (instr.fsetp.cond) {
553 case PredCondition::LessThan:
554 SetPredicate(instr.fsetp.pred3, '(' + op_a + ") < (" + op_b + ')');
555 break;
556 case PredCondition::Equal:
557 SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')');
558 break;
559 default:
560 NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
561 static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b);
562 UNREACHABLE();
563 }
564 break;
565 }
454 default: { 566 default: {
455 switch (instr.opcode.EffectiveOpCode()) { 567 switch (instr.opcode.EffectiveOpCode()) {
456 case OpCode::Id::EXIT: { 568 case OpCode::Id::EXIT: {
569 ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
570 "Predicated exits not implemented");
457 shader.AddLine("return true;"); 571 shader.AddLine("return true;");
458 offset = PROGRAM_END - 1; 572 offset = PROGRAM_END - 1;
459 break; 573 break;
460 } 574 }
575 case OpCode::Id::KIL: {
576 shader.AddLine("discard;");
577 break;
578 }
461 case OpCode::Id::IPA: { 579 case OpCode::Id::IPA: {
462 const auto& attribute = instr.attribute.fmt28; 580 const auto& attribute = instr.attribute.fmt28;
463 std::string dest = GetRegister(instr.gpr0); 581 std::string dest = GetRegister(instr.gpr0);
@@ -476,6 +594,12 @@ private:
476 } 594 }
477 } 595 }
478 596
597 // Close the predicate condition scope.
598 if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
599 --shader.scope;
600 shader.AddLine('}');
601 }
602
479 return offset + 1; 603 return offset + 1;
480 } 604 }
481 605
@@ -605,6 +729,12 @@ private:
605 declarations.AddNewLine(); 729 declarations.AddNewLine();
606 ++const_buffer_layout; 730 ++const_buffer_layout;
607 } 731 }
732
733 declarations.AddNewLine();
734 for (const auto& pred : declr_predicates) {
735 declarations.AddLine("bool " + pred + " = false;");
736 }
737 declarations.AddNewLine();
608 } 738 }
609 739
610private: 740private:
@@ -618,6 +748,7 @@ private:
618 748
619 // Declarations 749 // Declarations
620 std::set<std::string> declr_register; 750 std::set<std::string> declr_register;
751 std::set<std::string> declr_predicates;
621 std::set<Attribute::Index> declr_input_attribute; 752 std::set<Attribute::Index> declr_input_attribute;
622 std::set<Attribute::Index> declr_output_attribute; 753 std::set<Attribute::Index> declr_output_attribute;
623 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; 754 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;