mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-26 08:42:45 +01:00
Merge pull request #1018 from Subv/ssy_sync
GPU/Shader: Implemented SSY and SYNC as a set_target/jump pair.
This commit is contained in:
commit
670a2c1f80
2 changed files with 38 additions and 8 deletions
|
@ -597,6 +597,13 @@ public:
|
||||||
Unknown,
|
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 {
|
class Matcher {
|
||||||
public:
|
public:
|
||||||
Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
|
Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
|
||||||
|
|
|
@ -141,6 +141,15 @@ private:
|
||||||
ExitMethod jmp = Scan(target, end, labels);
|
ExitMethod jmp = Scan(target, end, labels);
|
||||||
return exit_method = ParallelExit(no_jmp, jmp);
|
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,
|
ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
|
||||||
"NeverExecute predicate not implemented");
|
"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 (" +
|
shader.AddLine("if (" +
|
||||||
GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
|
GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
|
||||||
')');
|
')');
|
||||||
|
@ -1668,16 +1681,25 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::SSY: {
|
case OpCode::Id::SSY: {
|
||||||
// The SSY opcode tells the GPU where to re-converge divergent execution paths, we
|
// The SSY opcode tells the GPU where to re-converge divergent execution paths, it
|
||||||
// can ignore this when generating GLSL code.
|
// 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;
|
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);
|
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
||||||
|
shader.AddLine("{ jmp_to = ssy_target; break; }");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OpCode::Id::DEPBAR: {
|
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.
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -1691,7 +1713,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the predicate condition scope.
|
// 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.scope;
|
||||||
shader.AddLine('}');
|
shader.AddLine('}');
|
||||||
}
|
}
|
||||||
|
@ -1742,6 +1764,7 @@ private:
|
||||||
} else {
|
} else {
|
||||||
labels.insert(subroutine.begin);
|
labels.insert(subroutine.begin);
|
||||||
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
|
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
|
||||||
|
shader.AddLine("uint ssy_target = 0u;");
|
||||||
shader.AddLine("while (true) {");
|
shader.AddLine("while (true) {");
|
||||||
++shader.scope;
|
++shader.scope;
|
||||||
|
|
||||||
|
@ -1757,7 +1780,7 @@ private:
|
||||||
u32 compile_end = CompileRange(label, next_label);
|
u32 compile_end = CompileRange(label, next_label);
|
||||||
if (compile_end > next_label && compile_end != PROGRAM_END) {
|
if (compile_end > next_label && compile_end != PROGRAM_END) {
|
||||||
// This happens only when there is a label inside a IF/LOOP block
|
// 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);
|
labels.emplace(compile_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue