summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/control_flow.cpp3
-rw-r--r--src/video_core/shader/decode/other.cpp42
-rw-r--r--src/video_core/shader/node.h1
3 files changed, 42 insertions, 4 deletions
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index fcf22c7f2..a9de8f814 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -284,6 +284,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
state.pbk_labels.emplace(offset, target);
break;
}
+ case OpCode::Id::BRX: {
+ return ParseResult::AbnormalFlow;
+ }
default:
break;
}
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index d46a8ab82..ed3c63781 100644
--- a/src/video_core/shader/decode/other.cpp
+++ b/src/video_core/shader/decode/other.cpp
@@ -91,11 +91,45 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::BRA: {
- UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
- "BRA with constant buffers are not implemented");
+ Node branch;
+ if (instr.bra.constant_buffer == 0) {
+ const u32 target = pc + instr.bra.GetBranchTarget();
+ branch = Operation(OperationCode::Branch, Immediate(target));
+ } else {
+ const u32 target = pc + 1;
+ const Node op_a = GetConstBuffer(instr.cbuf36.index, instr.cbuf36.GetOffset());
+ const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
+ true, PRECISE, op_a, Immediate(3));
+ const Node operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
+ branch = Operation(OperationCode::BranchIndirect, convert);
+ }
- const u32 target = pc + instr.bra.GetBranchTarget();
- const Node branch = Operation(OperationCode::Branch, Immediate(target));
+ const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
+ if (cc != Tegra::Shader::ConditionCode::T) {
+ bb.push_back(Conditional(GetConditionCode(cc), {branch}));
+ } else {
+ bb.push_back(branch);
+ }
+ break;
+ }
+ case OpCode::Id::BRX: {
+ Node operand;
+ if (instr.brx.constant_buffer != 0) {
+ const s32 target = pc + 1;
+ const Node index = GetRegister(instr.gpr8);
+ const Node op_a =
+ GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 0, index);
+ const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
+ true, PRECISE, op_a, Immediate(3));
+ operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
+ } else {
+ const s32 target = pc + instr.brx.GetBranchExtend();
+ const Node op_a = GetRegister(instr.gpr8);
+ const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
+ true, PRECISE, op_a, Immediate(3));
+ operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
+ }
+ const Node branch = Operation(OperationCode::BranchIndirect, operand);
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
if (cc != Tegra::Shader::ConditionCode::T) {
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 0ac83fcf0..e468758a6 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -149,6 +149,7 @@ enum class OperationCode {
ImageStore, /// (MetaImage, float[N] coords) -> void
Branch, /// (uint branch_target) -> void
+ BranchIndirect,/// (uint branch_target) -> void
PushFlowStack, /// (uint branch_target) -> void
PopFlowStack, /// () -> void
Exit, /// () -> void