diff options
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 39 | 
2 files changed, 38 insertions, 8 deletions
| diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 3e409c2e1..6cb7bea1c 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -597,6 +597,13 @@ public:          Unknown,      }; +    /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be +    /// conditionally executed). +    static bool IsPredicatedInstruction(Id opcode) { +        // TODO(Subv): Add the rest of unpredicated instructions. +        return opcode != Id::SSY; +    } +      class Matcher {      public:          Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type) diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 32f06f409..8954deb81 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -141,6 +141,15 @@ private:                      ExitMethod jmp = Scan(target, end, labels);                      return exit_method = ParallelExit(no_jmp, jmp);                  } +                case OpCode::Id::SSY: { +                    // The SSY instruction uses a similar encoding as the BRA instruction. +                    ASSERT_MSG(instr.bra.constant_buffer == 0, +                               "Constant buffer SSY is not supported"); +                    u32 target = offset + instr.bra.GetBranchTarget(); +                    labels.insert(target); +                    // Continue scanning for an exit method. +                    break; +                }                  }              }          } @@ -828,7 +837,11 @@ private:          ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,                     "NeverExecute predicate not implemented"); -        if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { +        // Some instructions (like SSY) don't have a predicate field, they are always +        // unconditionally executed. +        bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId()); + +        if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {              shader.AddLine("if (" +                             GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +                             ')'); @@ -1668,16 +1681,25 @@ private:                  break;              }              case OpCode::Id::SSY: { -                // The SSY opcode tells the GPU where to re-converge divergent execution paths, we -                // can ignore this when generating GLSL code. +                // The SSY opcode tells the GPU where to re-converge divergent execution paths, it +                // sets the target of the jump that the SYNC instruction will make. The SSY opcode +                // has a similar structure to the BRA opcode. +                ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); + +                u32 target = offset + instr.bra.GetBranchTarget(); +                shader.AddLine("ssy_target = " + std::to_string(target) + "u;");                  break;              } -            case OpCode::Id::SYNC: +            case OpCode::Id::SYNC: { +                // The SYNC opcode jumps to the address previously set by the SSY opcode                  ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); +                shader.AddLine("{ jmp_to = ssy_target; break; }"); +                break; +            }              case OpCode::Id::DEPBAR: { -                // TODO(Subv): Find out if we actually have to care about these instructions or if +                // TODO(Subv): Find out if we actually have to care about this instruction or if                  // the GLSL compiler takes care of that for us. -                LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed"); +                LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");                  break;              }              default: { @@ -1691,7 +1713,7 @@ private:          }          // Close the predicate condition scope. -        if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { +        if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {              --shader.scope;              shader.AddLine('}');          } @@ -1742,6 +1764,7 @@ private:              } else {                  labels.insert(subroutine.begin);                  shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;"); +                shader.AddLine("uint ssy_target = 0u;");                  shader.AddLine("while (true) {");                  ++shader.scope; @@ -1757,7 +1780,7 @@ private:                      u32 compile_end = CompileRange(label, next_label);                      if (compile_end > next_label && compile_end != PROGRAM_END) {                          // This happens only when there is a label inside a IF/LOOP block -                        shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }"); +                        shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");                          labels.emplace(compile_end);                      } | 
