mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-25 22:57:22 +00:00
Merge pull request #552 from bunnei/sat-fmul
gl_shader_decompiler: Implement saturate for float instructions.
This commit is contained in:
commit
2dc8b5c224
2 changed files with 32 additions and 39 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in a new issue