Shader: Implemented the predicate and mode arguments of LOP.
The mode can be used to set the predicate to true depending on the result of the logic operation. In some cases, this means discarding the result (writing it to register 0xFF (Zero)). This is used by Super Mario Odyssey.
This commit is contained in:
parent
6eba539f4a
commit
8335b2f115
@ -214,6 +214,11 @@ enum class FlowCondition : u64 {
|
|||||||
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PredicateResultMode : u64 {
|
||||||
|
None = 0x0,
|
||||||
|
NotZero = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
union Instruction {
|
union Instruction {
|
||||||
Instruction& operator=(const Instruction& instr) {
|
Instruction& operator=(const Instruction& instr) {
|
||||||
value = instr.value;
|
value = instr.value;
|
||||||
@ -254,7 +259,7 @@ union Instruction {
|
|||||||
BitField<39, 1, u64> invert_a;
|
BitField<39, 1, u64> invert_a;
|
||||||
BitField<40, 1, u64> invert_b;
|
BitField<40, 1, u64> invert_b;
|
||||||
BitField<41, 2, LogicOperation> operation;
|
BitField<41, 2, LogicOperation> operation;
|
||||||
BitField<44, 2, u64> unk44;
|
BitField<44, 2, PredicateResultMode> pred_result_mode;
|
||||||
BitField<48, 3, Pred> pred48;
|
BitField<48, 3, Pred> pred48;
|
||||||
} lop;
|
} lop;
|
||||||
|
|
||||||
|
@ -756,28 +756,51 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a,
|
void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a,
|
||||||
const std::string& op_b) {
|
const std::string& op_b,
|
||||||
|
Tegra::Shader::PredicateResultMode predicate_mode,
|
||||||
|
Tegra::Shader::Pred predicate) {
|
||||||
|
std::string result{};
|
||||||
switch (logic_op) {
|
switch (logic_op) {
|
||||||
case LogicOperation::And: {
|
case LogicOperation::And: {
|
||||||
regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " & " + op_b + ')', 1, 1);
|
result = '(' + op_a + " & " + op_b + ')';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LogicOperation::Or: {
|
case LogicOperation::Or: {
|
||||||
regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " | " + op_b + ')', 1, 1);
|
result = '(' + op_a + " | " + op_b + ')';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LogicOperation::Xor: {
|
case LogicOperation::Xor: {
|
||||||
regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " ^ " + op_b + ')', 1, 1);
|
result = '(' + op_a + " ^ " + op_b + ')';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LogicOperation::PassB: {
|
case LogicOperation::PassB: {
|
||||||
regs.SetRegisterToInteger(dest, true, 0, op_b, 1, 1);
|
result = op_b;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented logic operation: {}", static_cast<u32>(logic_op));
|
LOG_CRITICAL(HW_GPU, "Unimplemented logic operation: {}", static_cast<u32>(logic_op));
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dest != Tegra::Shader::Register::ZeroIndex) {
|
||||||
|
regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
using Tegra::Shader::PredicateResultMode;
|
||||||
|
// Write the predicate value depending on the predicate mode.
|
||||||
|
switch (predicate_mode) {
|
||||||
|
case PredicateResultMode::None:
|
||||||
|
// Do nothing.
|
||||||
|
return;
|
||||||
|
case PredicateResultMode::NotZero:
|
||||||
|
// Set the predicate to true if the result is not zero.
|
||||||
|
SetPredicate(static_cast<u64>(predicate), '(' + result + ") != 0");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(HW_GPU, "Unimplemented predicate result mode: {}",
|
||||||
|
static_cast<u32>(predicate_mode));
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteTexsInstruction(const Instruction& instr, const std::string& coord,
|
void WriteTexsInstruction(const Instruction& instr, const std::string& coord,
|
||||||
@ -1099,7 +1122,9 @@ private:
|
|||||||
if (instr.alu.lop32i.invert_b)
|
if (instr.alu.lop32i.invert_b)
|
||||||
op_b = "~(" + op_b + ')';
|
op_b = "~(" + op_b + ')';
|
||||||
|
|
||||||
WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b);
|
WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
|
||||||
|
Tegra::Shader::PredicateResultMode::None,
|
||||||
|
Tegra::Shader::Pred::UnusedIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -1165,16 +1190,14 @@ private:
|
|||||||
case OpCode::Id::LOP_C:
|
case OpCode::Id::LOP_C:
|
||||||
case OpCode::Id::LOP_R:
|
case OpCode::Id::LOP_R:
|
||||||
case OpCode::Id::LOP_IMM: {
|
case OpCode::Id::LOP_IMM: {
|
||||||
ASSERT_MSG(!instr.alu.lop.unk44, "Unimplemented");
|
|
||||||
ASSERT_MSG(instr.alu.lop.pred48 == Pred::UnusedIndex, "Unimplemented");
|
|
||||||
|
|
||||||
if (instr.alu.lop.invert_a)
|
if (instr.alu.lop.invert_a)
|
||||||
op_a = "~(" + op_a + ')';
|
op_a = "~(" + op_a + ')';
|
||||||
|
|
||||||
if (instr.alu.lop.invert_b)
|
if (instr.alu.lop.invert_b)
|
||||||
op_b = "~(" + op_b + ')';
|
op_b = "~(" + op_b + ')';
|
||||||
|
|
||||||
WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b);
|
WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
|
||||||
|
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::IMNMX_C:
|
case OpCode::Id::IMNMX_C:
|
||||||
|
Loading…
Reference in New Issue
Block a user