gl_shader_decompiler: Implement saturate for float instructions.

This commit is contained in:
bunnei 2018-06-09 02:36:33 -04:00
parent 09b8a16414
commit 5f3d6c85db
2 changed files with 32 additions and 39 deletions

View File

@ -213,7 +213,6 @@ union Instruction {
BitField<28, 8, Register> gpr28; BitField<28, 8, Register> gpr28;
BitField<39, 8, Register> gpr39; BitField<39, 8, Register> gpr39;
BitField<48, 16, u64> opcode; BitField<48, 16, u64> opcode;
BitField<50, 1, u64> saturate_a;
union { union {
BitField<20, 19, u64> imm20_19; BitField<20, 19, u64> imm20_19;
@ -222,7 +221,7 @@ union Instruction {
BitField<46, 1, u64> abs_a; BitField<46, 1, u64> abs_a;
BitField<48, 1, u64> negate_a; BitField<48, 1, u64> negate_a;
BitField<49, 1, u64> abs_b; BitField<49, 1, u64> abs_b;
BitField<50, 1, u64> abs_d; BitField<50, 1, u64> saturate_d;
BitField<56, 1, u64> negate_imm; BitField<56, 1, u64> negate_imm;
union { union {

View File

@ -299,13 +299,15 @@ public:
* @param value The code representing the value to assign. * @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination. * @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value. * @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output. * @param is_saturated Optional, when True, saturates the provided value.
* @param dest_elem Optional, the destination element to use for the operation. * @param dest_elem Optional, the destination element to use for the operation.
*/ */
void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
u64 dest_num_components, u64 value_num_components, bool is_abs = false, u64 dest_num_components, u64 value_num_components,
u64 dest_elem = 0) { bool is_saturated = false, u64 dest_elem = 0) {
SetRegister(reg, elem, value, dest_num_components, value_num_components, is_abs, dest_elem);
SetRegister(reg, elem, is_saturated ? "clamp(" + value + ", 0.0, 1.0)" : value,
dest_num_components, value_num_components, dest_elem);
} }
/** /**
@ -315,18 +317,21 @@ public:
* @param value The code representing the value to assign. * @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination. * @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value. * @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output. * @param is_saturated Optional, when True, saturates the provided value.
* @param dest_elem Optional, the destination element to use for the operation. * @param dest_elem Optional, the destination element to use for the operation.
*/ */
void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
const std::string& value, u64 dest_num_components, const std::string& value, u64 dest_num_components,
u64 value_num_components, bool is_abs = false, u64 dest_elem = 0) { u64 value_num_components, bool is_saturated = false,
u64 dest_elem = 0) {
ASSERT_MSG(!is_saturated, "Unimplemented");
const std::string func = GetGLSLConversionFunc( const std::string func = GetGLSLConversionFunc(
is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger, is_signed ? GLSLRegister::Type::Integer : GLSLRegister::Type::UnsignedInteger,
GLSLRegister::Type::Float); GLSLRegister::Type::Float);
SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components, SetRegister(reg, elem, func + '(' + value + ')', dest_num_components, value_num_components,
is_abs, dest_elem); dest_elem);
} }
/** /**
@ -500,12 +505,10 @@ private:
* @param value The code representing the value to assign. * @param value The code representing the value to assign.
* @param dest_num_components Number of components in the destination. * @param dest_num_components Number of components in the destination.
* @param value_num_components Number of components in the value. * @param value_num_components Number of components in the value.
* @param is_abs Optional, when True, applies absolute value to output.
* @param dest_elem Optional, the destination element to use for the operation. * @param dest_elem Optional, the destination element to use for the operation.
*/ */
void SetRegister(const Register& reg, u64 elem, const std::string& value, void SetRegister(const Register& reg, u64 elem, const std::string& value,
u64 dest_num_components, u64 value_num_components, bool is_abs, u64 dest_num_components, u64 value_num_components, u64 dest_elem) {
u64 dest_elem) {
std::string dest = GetRegister(reg, dest_elem); std::string dest = GetRegister(reg, dest_elem);
if (dest_num_components > 1) { if (dest_num_components > 1) {
dest += GetSwizzle(elem); dest += GetSwizzle(elem);
@ -516,8 +519,6 @@ private:
src += GetSwizzle(elem); src += GetSwizzle(elem);
} }
src = is_abs ? "abs(" + src + ')' : src;
shader.AddLine(dest + " = " + src + ';'); shader.AddLine(dest + " = " + src + ';');
} }
@ -808,9 +809,8 @@ private:
case OpCode::Id::FMUL_C: case OpCode::Id::FMUL_C:
case OpCode::Id::FMUL_R: case OpCode::Id::FMUL_R:
case OpCode::Id::FMUL_IMM: { case OpCode::Id::FMUL_IMM: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented"); regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
instr.alu.saturate_d);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
break; break;
} }
case OpCode::Id::FMUL32_IMM: { case OpCode::Id::FMUL32_IMM: {
@ -823,41 +823,39 @@ private:
case OpCode::Id::FADD_C: case OpCode::Id::FADD_C:
case OpCode::Id::FADD_R: case OpCode::Id::FADD_R:
case OpCode::Id::FADD_IMM: { case OpCode::Id::FADD_IMM: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented"); regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
instr.alu.saturate_d);
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
break; break;
} }
case OpCode::Id::MUFU: { case OpCode::Id::MUFU: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented");
switch (instr.sub_op) { switch (instr.sub_op) {
case SubOp::Cos: case SubOp::Cos:
regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
case SubOp::Sin: case SubOp::Sin:
regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
case SubOp::Ex2: case SubOp::Ex2:
regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
case SubOp::Lg2: case SubOp::Lg2:
regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
case SubOp::Rcp: case SubOp::Rcp:
regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1,
instr.alu.saturate_d);
break; break;
case SubOp::Rsq: case SubOp::Rsq:
regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
case SubOp::Min: case SubOp::Min:
regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1, regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1,
instr.alu.abs_d); instr.alu.saturate_d);
break; break;
default: default:
NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
@ -1028,8 +1026,8 @@ private:
case OpCode::Id::IADD_C: case OpCode::Id::IADD_C:
case OpCode::Id::IADD_R: case OpCode::Id::IADD_R:
case OpCode::Id::IADD_IMM: { case OpCode::Id::IADD_IMM: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented"); regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1); instr.alu.saturate_d);
break; break;
} }
case OpCode::Id::ISCADD_C: case OpCode::Id::ISCADD_C:
@ -1051,8 +1049,6 @@ private:
break; break;
} }
case OpCode::Type::Ffma: { case OpCode::Type::Ffma: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
std::string op_b = instr.ffma.negate_b ? "-" : ""; std::string op_b = instr.ffma.negate_b ? "-" : "";
std::string op_c = instr.ffma.negate_c ? "-" : ""; std::string op_c = instr.ffma.negate_c ? "-" : "";
@ -1086,13 +1082,13 @@ private:
} }
} }
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1); regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1,
instr.alu.saturate_d);
break; break;
} }
case OpCode::Type::Conversion: { case OpCode::Type::Conversion: {
ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented"); ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented"); ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
ASSERT_MSG(!instr.saturate_a, "Unimplemented");
switch (opcode->GetId()) { switch (opcode->GetId()) {
case OpCode::Id::I2I_R: { case OpCode::Id::I2I_R: {
@ -1106,7 +1102,7 @@ private:
} }
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
1); 1, instr.alu.saturate_d);
break; break;
} }
case OpCode::Id::I2F_R: { case OpCode::Id::I2F_R: {
@ -1122,8 +1118,6 @@ private:
break; break;
} }
case OpCode::Id::F2F_R: { case OpCode::Id::F2F_R: {
ASSERT_MSG(!instr.saturate_a, "Unimplemented");
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
switch (instr.conversion.f2f.rounding) { switch (instr.conversion.f2f.rounding) {
@ -1149,7 +1143,7 @@ private:
op_a = "abs(" + op_a + ')'; op_a = "abs(" + op_a + ')';
} }
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
break; break;
} }
case OpCode::Id::F2I_R: { case OpCode::Id::F2I_R: {