summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/shader_bytecode.h51
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp153
2 files changed, 190 insertions, 14 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index a57b90632..8d4ea3401 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -156,6 +156,13 @@ enum class PredOperation : u64 {
Xor = 2,
};
+enum class LogicOperation : u64 {
+ And = 0,
+ Or = 1,
+ Xor = 2,
+ PassB = 3,
+};
+
enum class SubOp : u64 {
Cos = 0x0,
Sin = 0x1,
@@ -202,6 +209,12 @@ union Instruction {
BitField<42, 1, u64> negate_pred;
} fmnmx;
+ union {
+ BitField<53, 2, LogicOperation> operation;
+ BitField<55, 1, u64> invert_a;
+ BitField<56, 1, u64> invert_b;
+ } lop;
+
float GetImm20_19() const {
float result{};
u32 imm{static_cast<u32>(imm20_19)};
@@ -220,6 +233,22 @@ union Instruction {
} alu;
union {
+ BitField<39, 5, u64> shift_amount;
+ BitField<20, 19, u64> immediate_low;
+ BitField<56, 1, u64> immediate_high;
+ BitField<48, 1, u64> negate_b;
+ BitField<49, 1, u64> negate_a;
+
+ s32 GetImmediate() const {
+ u32 immediate = static_cast<u32>(immediate_low | (immediate_high << 19));
+ // Sign extend the 20-bit value.
+ u32 mask = 1U << (20 - 1);
+ return static_cast<s32>((immediate ^ mask) - mask);
+ }
+
+ } iscadd;
+
+ union {
BitField<48, 1, u64> negate_b;
BitField<49, 1, u64> negate_c;
} ffma;
@@ -239,15 +268,25 @@ union Instruction {
} fsetp;
union {
+ BitField<0, 3, u64> pred0;
+ BitField<3, 3, u64> pred3;
+ BitField<39, 3, u64> pred39;
+ BitField<42, 1, u64> neg_pred;
+ BitField<45, 2, PredOperation> op;
+ BitField<48, 1, u64> is_signed;
+ BitField<49, 3, PredCondition> cond;
+ } isetp;
+
+ union {
BitField<39, 3, u64> pred39;
BitField<42, 1, u64> neg_pred;
BitField<43, 1, u64> neg_a;
BitField<44, 1, u64> abs_b;
BitField<45, 2, PredOperation> op;
BitField<48, 4, PredCondition> cond;
+ BitField<52, 1, u64> bf;
BitField<53, 1, u64> neg_b;
BitField<54, 1, u64> abs_a;
- BitField<52, 1, u64> bf;
BitField<55, 1, u64> ftz;
BitField<56, 1, u64> neg_imm;
} fset;
@@ -339,6 +378,9 @@ public:
FMUL_R,
FMUL_IMM,
FMUL32_IMM,
+ ISCADD_C, // Scale and Add
+ ISCADD_R,
+ ISCADD_IMM,
MUFU, // Multi-Function Operator
RRO_C, // Range Reduction Operator
RRO_R,
@@ -381,6 +423,8 @@ public:
enum class Type {
Trivial,
Arithmetic,
+ Logic,
+ ScaledAdd,
Ffma,
Flow,
Memory,
@@ -504,6 +548,9 @@ private:
INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"),
INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"),
INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"),
+ INST("0100110000011---", Id::ISCADD_C, Type::ScaledAdd, "ISCADD_C"),
+ INST("0101110000011---", Id::ISCADD_R, Type::ScaledAdd, "ISCADD_R"),
+ INST("0011100-00011---", Id::ISCADD_IMM, Type::ScaledAdd, "ISCADD_IMM"),
INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
@@ -514,7 +561,6 @@ private:
INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
- INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
@@ -525,6 +571,7 @@ private:
INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"),
INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"),
INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"),
+ INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"),
INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 6391f1ad4..eb8d37c9b 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -228,6 +228,11 @@ public:
return active_type == Type::Integer;
}
+ /// Returns the current active type of the register
+ Type GetActiveType() const {
+ return active_type;
+ }
+
/// Returns the index of the register
size_t GetIndex() const {
return index;
@@ -359,22 +364,28 @@ public:
shader.AddLine(dest + " = " + src + ';');
}
- /// Generates code representing a uniform (C buffer) register.
- std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
+ /// Generates code representing a uniform (C buffer) register, interpreted as the input type.
+ std::string GetUniform(const Uniform& uniform, GLSLRegister::Type type) {
declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index),
static_cast<unsigned>(uniform.offset), stage);
std::string value =
'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']';
- if (regs[dest_reg].IsFloat()) {
+ if (type == GLSLRegister::Type::Float) {
return value;
- } else if (regs[dest_reg].IsInteger()) {
+ } else if (type == GLSLRegister::Type::Integer) {
return "floatBitsToInt(" + value + ')';
} else {
UNREACHABLE();
}
}
+ /// Generates code representing a uniform (C buffer) register, interpreted as the type of the
+ /// destination register.
+ std::string GetUniform(const Uniform& uniform, const Register& dest_reg) {
+ return GetUniform(uniform, regs[dest_reg].GetActiveType());
+ }
+
/// Add declarations for registers
void GenerateDeclarations() {
for (const auto& reg : regs) {
@@ -643,9 +654,9 @@ private:
std::string GetPredicateComparison(Tegra::Shader::PredCondition condition) const {
using Tegra::Shader::PredCondition;
static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
- {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
- {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
- {PredCondition::GreaterEqual, ">="},
+ {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="},
+ {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"},
+ {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="},
};
auto comparison = PredicateComparisonStrings.find(condition);
@@ -839,6 +850,73 @@ private:
}
break;
}
+ case OpCode::Type::Logic: {
+ std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, false);
+
+ if (instr.alu.lop.invert_a)
+ op_a = "~(" + op_a + ')';
+
+ switch (opcode->GetId()) {
+ case OpCode::Id::LOP32I: {
+ u32 imm = static_cast<u32>(instr.alu.imm20_32.Value());
+
+ if (instr.alu.lop.invert_b)
+ imm = ~imm;
+
+ switch (instr.alu.lop.operation) {
+ case Tegra::Shader::LogicOperation::And: {
+ regs.SetRegisterToInteger(instr.gpr0, false, 0,
+ '(' + op_a + " & " + std::to_string(imm) + ')', 1, 1);
+ break;
+ }
+ case Tegra::Shader::LogicOperation::Or: {
+ regs.SetRegisterToInteger(instr.gpr0, false, 0,
+ '(' + op_a + " | " + std::to_string(imm) + ')', 1, 1);
+ break;
+ }
+ case Tegra::Shader::LogicOperation::Xor: {
+ regs.SetRegisterToInteger(instr.gpr0, false, 0,
+ '(' + op_a + " ^ " + std::to_string(imm) + ')', 1, 1);
+ break;
+ }
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unimplemented lop32i operation: {}",
+ static_cast<u32>(instr.alu.lop.operation.Value()));
+ UNREACHABLE();
+ }
+ break;
+ }
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled logic instruction: {}", opcode->GetName());
+ UNREACHABLE();
+ }
+ }
+ break;
+ }
+ case OpCode::Type::ScaledAdd: {
+ std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
+
+ if (instr.iscadd.negate_a)
+ op_a = '-' + op_a;
+
+ std::string op_b = instr.iscadd.negate_b ? "-" : "";
+
+ if (instr.is_b_imm) {
+ op_b += '(' + std::to_string(instr.iscadd.GetImmediate()) + ')';
+ } else {
+ if (instr.is_b_gpr) {
+ op_b += regs.GetRegisterAsInteger(instr.gpr20);
+ } else {
+ op_b += regs.GetUniform(instr.uniform, instr.gpr0);
+ }
+ }
+
+ std::string shift = std::to_string(instr.iscadd.shift_amount.Value());
+
+ regs.SetRegisterToInteger(instr.gpr0, true, 0,
+ "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
+ break;
+ }
case OpCode::Type::Ffma: {
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b = instr.ffma.negate_b ? "-" : "";
@@ -880,8 +958,7 @@ private:
ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
switch (opcode->GetId()) {
- case OpCode::Id::I2I_R:
- case OpCode::Id::I2F_R: {
+ case OpCode::Id::I2I_R: {
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
std::string op_a =
@@ -894,6 +971,17 @@ private:
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
break;
}
+ case OpCode::Id::I2F_R: {
+ std::string op_a =
+ regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
+
+ if (instr.conversion.abs_a) {
+ op_a = "abs(" + op_a + ')';
+ }
+
+ regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
+ break;
+ }
case OpCode::Id::F2F_R: {
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
@@ -1017,7 +1105,7 @@ private:
if (instr.is_b_gpr) {
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
- op_b += regs.GetUniform(instr.uniform, instr.gpr0);
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float);
}
}
@@ -1048,6 +1136,42 @@ private:
}
break;
}
+ case OpCode::Type::IntegerSetPredicate: {
+ std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed);
+
+ std::string op_b{};
+
+ ASSERT_MSG(!instr.is_b_imm, "ISETP_IMM not implemented");
+
+ if (instr.is_b_gpr) {
+ op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed);
+ } else {
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer);
+ }
+
+ using Tegra::Shader::Pred;
+ // We can't use the constant predicate as destination.
+ ASSERT(instr.isetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
+
+ std::string second_pred =
+ GetPredicateCondition(instr.isetp.pred39, instr.isetp.neg_pred != 0);
+
+ std::string comparator = GetPredicateComparison(instr.isetp.cond);
+ std::string combiner = GetPredicateCombiner(instr.isetp.op);
+
+ std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')';
+ // Set the primary predicate to the result of Predicate OP SecondPredicate
+ SetPredicate(instr.isetp.pred3,
+ '(' + predicate + ") " + combiner + " (" + second_pred + ')');
+
+ if (instr.isetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
+ // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
+ // if enabled
+ SetPredicate(instr.isetp.pred0,
+ "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
+ }
+ break;
+ }
case OpCode::Type::FloatSet: {
std::string op_a = instr.fset.neg_a ? "-" : "";
op_a += regs.GetRegisterAsFloat(instr.gpr8);
@@ -1068,7 +1192,7 @@ private:
if (instr.is_b_gpr) {
op_b += regs.GetRegisterAsFloat(instr.gpr20);
} else {
- op_b += regs.GetUniform(instr.uniform, instr.gpr0);
+ op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Float);
}
}
@@ -1087,7 +1211,12 @@ private:
std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " +
combiner + " (" + second_pred + "))";
- regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
+ if (instr.fset.bf) {
+ regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
+ } else {
+ regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1,
+ 1);
+ }
break;
}
default: {