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/decode/arithmetic.cpp33
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp94
-rw-r--r--src/video_core/shader/track.cpp20
3 files changed, 86 insertions, 61 deletions
diff --git a/src/video_core/shader/decode/arithmetic.cpp b/src/video_core/shader/decode/arithmetic.cpp
index 90240c765..478394682 100644
--- a/src/video_core/shader/decode/arithmetic.cpp
+++ b/src/video_core/shader/decode/arithmetic.cpp
@@ -53,29 +53,24 @@ u32 ShaderIR::DecodeArithmetic(NodeBlock& bb, u32 pc) {
op_b = GetOperandAbsNegFloat(op_b, false, instr.fmul.negate_b);
- // TODO(Rodrigo): Should precise be used when there's a postfactor?
- Node value = Operation(OperationCode::FMul, PRECISE, op_a, op_b);
+ static constexpr std::array FmulPostFactor = {
+ 1.000f, // None
+ 0.500f, // Divide 2
+ 0.250f, // Divide 4
+ 0.125f, // Divide 8
+ 8.000f, // Mul 8
+ 4.000f, // Mul 4
+ 2.000f, // Mul 2
+ };
if (instr.fmul.postfactor != 0) {
- auto postfactor = static_cast<s32>(instr.fmul.postfactor);
-
- // Postfactor encoded as 3-bit 1's complement in instruction, interpreted with below
- // logic.
- if (postfactor >= 4) {
- postfactor = 7 - postfactor;
- } else {
- postfactor = 0 - postfactor;
- }
-
- if (postfactor > 0) {
- value = Operation(OperationCode::FMul, NO_PRECISE, value,
- Immediate(static_cast<f32>(1 << postfactor)));
- } else {
- value = Operation(OperationCode::FDiv, NO_PRECISE, value,
- Immediate(static_cast<f32>(1 << -postfactor)));
- }
+ op_a = Operation(OperationCode::FMul, NO_PRECISE, op_a,
+ Immediate(FmulPostFactor[instr.fmul.postfactor]));
}
+ // TODO(Rodrigo): Should precise be used when there's a postfactor?
+ Node value = Operation(OperationCode::FMul, PRECISE, op_a, op_b);
+
value = GetSaturatedFloat(value, instr.alu.saturate_d);
SetInternalFlagsFromFloat(bb, value, instr.generates_cc);
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index 21366869d..2fe787d6f 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -293,44 +293,66 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
void ShaderIR::WriteLop3Instruction(NodeBlock& bb, Register dest, Node op_a, Node op_b, Node op_c,
Node imm_lut, bool sets_cc) {
- constexpr u32 lop_iterations = 32;
- const Node one = Immediate(1);
- const Node two = Immediate(2);
-
- Node value;
- for (u32 i = 0; i < lop_iterations; ++i) {
- const Node shift_amount = Immediate(i);
-
- const Node a = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_c, shift_amount);
- const Node pack_0 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, one);
-
- const Node b = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_b, shift_amount);
- const Node c = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, b, one);
- const Node pack_1 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, c, one);
-
- const Node d = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_a, shift_amount);
- const Node e = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, d, one);
- const Node pack_2 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, e, two);
-
- const Node pack_01 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_0, pack_1);
- const Node pack_012 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_01, pack_2);
-
- const Node shifted_bit =
- Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, imm_lut, pack_012);
- const Node bit = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, shifted_bit, one);
-
- const Node right =
- Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, bit, shift_amount);
-
- if (i > 0) {
- value = Operation(OperationCode::IBitwiseOr, NO_PRECISE, value, right);
- } else {
- value = right;
+ const Node lop3_fast = [&](const Node na, const Node nb, const Node nc, const Node ttbl) {
+ Node value = Immediate(0);
+ const ImmediateNode imm = std::get<ImmediateNode>(*ttbl);
+ if (imm.GetValue() & 0x01) {
+ const Node a = Operation(OperationCode::IBitwiseNot, na);
+ const Node b = Operation(OperationCode::IBitwiseNot, nb);
+ const Node c = Operation(OperationCode::IBitwiseNot, nc);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, b);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, c);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
}
- }
+ if (imm.GetValue() & 0x02) {
+ const Node a = Operation(OperationCode::IBitwiseNot, na);
+ const Node b = Operation(OperationCode::IBitwiseNot, nb);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, b);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, nc);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x04) {
+ const Node a = Operation(OperationCode::IBitwiseNot, na);
+ const Node c = Operation(OperationCode::IBitwiseNot, nc);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, nb);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, c);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x08) {
+ const Node a = Operation(OperationCode::IBitwiseNot, na);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, nb);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, nc);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x10) {
+ const Node b = Operation(OperationCode::IBitwiseNot, nb);
+ const Node c = Operation(OperationCode::IBitwiseNot, nc);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, na, b);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, c);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x20) {
+ const Node b = Operation(OperationCode::IBitwiseNot, nb);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, na, b);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, nc);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x40) {
+ const Node c = Operation(OperationCode::IBitwiseNot, nc);
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, na, nb);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, c);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ if (imm.GetValue() & 0x80) {
+ Node r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, na, nb);
+ r = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, r, nc);
+ value = Operation(OperationCode::IBitwiseOr, value, r);
+ }
+ return value;
+ }(op_a, op_b, op_c, imm_lut);
- SetInternalFlagsFromInteger(bb, value, sets_cc);
- SetRegister(bb, dest, value);
+ SetInternalFlagsFromInteger(bb, lop3_fast, sets_cc);
+ SetRegister(bb, dest, lop3_fast);
}
} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp
index face8c943..15e22b9fa 100644
--- a/src/video_core/shader/track.cpp
+++ b/src/video_core/shader/track.cpp
@@ -157,13 +157,21 @@ std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& co
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
return {};
}
- // Reduce the cursor in one to avoid infinite loops when the instruction sets the same
- // register that it uses as operand
- const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
- if (!source) {
- return {};
+ s64 current_cursor = cursor;
+ while (current_cursor > 0) {
+ // Reduce the cursor in one to avoid infinite loops when the instruction sets the same
+ // register that it uses as operand
+ const auto [source, new_cursor] = TrackRegister(gpr, code, current_cursor - 1);
+ current_cursor = new_cursor;
+ if (!source) {
+ continue;
+ }
+ const auto [base_address, index, offset] = TrackCbuf(source, code, current_cursor);
+ if (base_address != nullptr) {
+ return {base_address, index, offset};
+ }
}
- return TrackCbuf(source, code, new_cursor);
+ return {};
}
if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
for (std::size_t i = operation->GetOperandsCount(); i > 0; --i) {