From 20c4e070492632341cf61daf27514bc0bbd48c1f Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Tue, 8 Apr 2025 13:14:30 +0200 Subject: [PATCH] Implement MinTri, MaxTri, MedTri --- .../asm_x64/emit_x64_floating_point.cpp | 28 +++ .../backend/asm_x64/emit_x64_instructions.h | 9 + .../backend/asm_x64/emit_x64_integer.cpp | 72 +++++++ .../ir/compute_value/do_float_operations.cpp | 21 ++ .../ir/compute_value/do_float_operations.h | 6 + .../compute_value/do_integer_operations.cpp | 36 ++++ .../ir/compute_value/do_integer_operations.h | 6 + .../ir/compute_value/imm_value.cpp | 196 ++++++++++++++++++ .../ir/compute_value/imm_value.h | 9 + 9 files changed, 383 insertions(+) diff --git a/src/shader_recompiler/backend/asm_x64/emit_x64_floating_point.cpp b/src/shader_recompiler/backend/asm_x64/emit_x64_floating_point.cpp index 2a048dbcb..2630538fe 100644 --- a/src/shader_recompiler/backend/asm_x64/emit_x64_floating_point.cpp +++ b/src/shader_recompiler/backend/asm_x64/emit_x64_floating_point.cpp @@ -146,6 +146,34 @@ void EmitFPMin64(EmitContext& ctx, const Operands& dest, const Operands& op1, co MovDouble(ctx, dest[0], tmp); } +void EmitFPMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm(); + MovFloat(ctx, tmp, op1[0]); + ctx.Code().minss(tmp, op2[0].Op()); + ctx.Code().minss(tmp, op3[0].Op()); + MovFloat(ctx, dest[0], tmp); +} + +void EmitFPMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm(); + MovFloat(ctx, tmp, op1[0]); + ctx.Code().maxss(tmp, op2[0].Op()); + ctx.Code().maxss(tmp, op3[0].Op()); + MovFloat(ctx, dest[0], tmp); +} + +void EmitFPMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Xmm tmp = dest[0].IsMem() ? ctx.TempXmmReg() : dest[0].Xmm(); + Xmm tmp2 = ctx.TempXmmReg(); + MovFloat(ctx, tmp2, op1[0]); + ctx.Code().maxss(tmp2, op2[0].Op()); + ctx.Code().minss(tmp2, op3[0].Op()); + MovFloat(ctx, tmp, op1[0]); + ctx.Code().minss(tmp, op2[0].Op()); + ctx.Code().maxss(tmp, tmp2); + MovFloat(ctx, dest[0], tmp); +} + void EmitFPMul16(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2) { Xmm tmp1 = ctx.TempXmmReg(); Xmm tmp2 = ctx.TempXmmReg(); diff --git a/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h b/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h index c85da6890..d4a1c961c 100644 --- a/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h +++ b/src/shader_recompiler/backend/asm_x64/emit_x64_instructions.h @@ -237,6 +237,9 @@ void EmitFPMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, co void EmitFPMax64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitFPMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, bool is_legacy = false); void EmitFPMin64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); +void EmitFPMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitFPMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitFPMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); void EmitFPMul16(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitFPMul32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitFPMul64(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); @@ -362,6 +365,12 @@ void EmitSMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, con void EmitUMin32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitSMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); void EmitUMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2); +void EmitSMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitUMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitSMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitUMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitSMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); +void EmitUMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3); void EmitSClamp32(EmitContext& ctx, const Operands& dest, const Operands& op, const Operands& min, const Operands& max); void EmitUClamp32(EmitContext& ctx, const Operands& dest, const Operands& op, const Operands& min, const Operands& max); void EmitSLessThan32(EmitContext& ctx, const Operands& dest, const Operands& lhs, const Operands& rhs); diff --git a/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp b/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp index 6251a174a..5c9d1c4e9 100644 --- a/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp +++ b/src/shader_recompiler/backend/asm_x64/emit_x64_integer.cpp @@ -377,6 +377,78 @@ void EmitUMax32(EmitContext& ctx, const Operands& dest, const Operands& op1, con MovGP(ctx, dest[0], tmp); } +void EmitSMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmovg(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, op3[0].Op()); + ctx.Code().cmovg(tmp, op3[0].Op()); + MovGP(ctx, dest[0], tmp); +} + +void EmitUMinTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmova(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, op3[0].Op()); + ctx.Code().cmova(tmp, op3[0].Op()); + MovGP(ctx, dest[0], tmp); +} + +void EmitSMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmovl(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, op3[0].Op()); + ctx.Code().cmovl(tmp, op3[0].Op()); + MovGP(ctx, dest[0], tmp); +} + +void EmitUMaxTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmovb(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, op3[0].Op()); + ctx.Code().cmovb(tmp, op3[0].Op()); + MovGP(ctx, dest[0], tmp); +} + +void EmitSMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + Reg tmp2 = ctx.TempGPReg().cvt32(); + MovGP(ctx, tmp2, op1[0]); + ctx.Code().cmp(tmp2, op2[0].Op()); + ctx.Code().cmovl(tmp2, op2[0].Op()); + ctx.Code().cmp(tmp2, op3[0].Op()); + ctx.Code().cmovg(tmp2, op3[0].Op()); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmovg(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, tmp); + ctx.Code().cmovl(tmp, tmp2); + MovGP(ctx, dest[0], tmp); +} + +void EmitUMedTri32(EmitContext& ctx, const Operands& dest, const Operands& op1, const Operands& op2, const Operands& op3) { + Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); + Reg tmp2 = ctx.TempGPReg().cvt32(); + MovGP(ctx, tmp, op1[0]); + ctx.Code().cmp(tmp, op2[0].Op()); + ctx.Code().cmova(tmp, op2[0].Op()); + ctx.Code().cmp(tmp, op3[0].Op()); + ctx.Code().cmovb(tmp, op3[0].Op()); + MovGP(ctx, tmp2, op1[0]); + ctx.Code().cmp(tmp2, op2[0].Op()); + ctx.Code().cmovb(tmp2, op2[0].Op()); + ctx.Code().cmp(tmp2, tmp); + ctx.Code().cmova(tmp2, tmp); + MovGP(ctx, dest[0], tmp2); +} + void EmitSClamp32(EmitContext& ctx, const Operands& dest, const Operands& value, const Operands& min, const Operands& max) { Reg tmp = dest[0].IsMem() ? ctx.TempGPReg().cvt32() : dest[0].Reg(); MovGP(ctx, tmp, value[0]); diff --git a/src/shader_recompiler/ir/compute_value/do_float_operations.cpp b/src/shader_recompiler/ir/compute_value/do_float_operations.cpp index dd4175eac..1071d252d 100644 --- a/src/shader_recompiler/ir/compute_value/do_float_operations.cpp +++ b/src/shader_recompiler/ir/compute_value/do_float_operations.cpp @@ -85,6 +85,27 @@ void DoFPMin64(ImmValueList& inst_values, const ImmValueList& args0, const ImmVa std::insert_iterator(inst_values, inst_values.begin()), args0, args1); } +void DoFPMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MaxTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, + args2); +} + +void DoFPMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MinTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, + args2); +} + +void DoFPMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MedTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, + args2); +} + void DoFPMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1) { Common::CartesianInvoke(ImmValue::Mul, std::insert_iterator(inst_values, inst_values.begin()), args0, args1); diff --git a/src/shader_recompiler/ir/compute_value/do_float_operations.h b/src/shader_recompiler/ir/compute_value/do_float_operations.h index ffc8040d1..170201f33 100644 --- a/src/shader_recompiler/ir/compute_value/do_float_operations.h +++ b/src/shader_recompiler/ir/compute_value/do_float_operations.h @@ -22,6 +22,12 @@ void DoFPMax64(ImmValueList& inst_values, const ImmValueList& args0, const ImmVa void DoFPMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args_legacy); void DoFPMin64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoFPMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2); +void DoFPMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2); +void DoFPMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2); void DoFPMul32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); void DoFPMul64(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); void DoFPDiv32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); diff --git a/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp b/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp index dacdaae14..92ce82fa9 100644 --- a/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp +++ b/src/shader_recompiler/ir/compute_value/do_integer_operations.cpp @@ -219,6 +219,42 @@ void DoUMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmVal std::insert_iterator(inst_values, inst_values.begin()), args0, args1); } +void DoSMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MinTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + +void DoUMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MinTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + +void DoSMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MaxTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + +void DoUMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MaxTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + +void DoSMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MedTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + +void DoUMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, + const ImmValueList& args2) { + Common::CartesianInvoke(ImmValue::MedTri, + std::insert_iterator(inst_values, inst_values.begin()), args0, args1, args2); +} + void DoSClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, const ImmValueList& max) { Common::CartesianInvoke(ImmValue::Clamp, diff --git a/src/shader_recompiler/ir/compute_value/do_integer_operations.h b/src/shader_recompiler/ir/compute_value/do_integer_operations.h index e698f2b12..aa06ee36b 100644 --- a/src/shader_recompiler/ir/compute_value/do_integer_operations.h +++ b/src/shader_recompiler/ir/compute_value/do_integer_operations.h @@ -62,6 +62,12 @@ void DoSMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmVal void DoUMin32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); void DoSMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); void DoUMax32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1); +void DoSMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); +void DoUMinTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); +void DoSMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); +void DoUMaxTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); +void DoSMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); +void DoUMedTri32(ImmValueList& inst_values, const ImmValueList& args0, const ImmValueList& args1, const ImmValueList& args2); void DoSClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, const ImmValueList& max); void DoUClamp32(ImmValueList& inst_values, const ImmValueList& value, const ImmValueList& min, diff --git a/src/shader_recompiler/ir/compute_value/imm_value.cpp b/src/shader_recompiler/ir/compute_value/imm_value.cpp index 2000bdfba..86586a25a 100644 --- a/src/shader_recompiler/ir/compute_value/imm_value.cpp +++ b/src/shader_recompiler/ir/compute_value/imm_value.cpp @@ -1127,6 +1127,202 @@ ImmValue ImmValue::Max(const ImmValue& a, const ImmValue& b) no return ImmValue(std::max(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64)); } +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8), + c.imm_values[0].imm_u8)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8), + c.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16), + c.imm_values[0].imm_u16)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16), + c.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32), + c.imm_values[0].imm_u32)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32), + c.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64), + c.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64), + c.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32), + c.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::min(std::min(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64), + c.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8), + c.imm_values[0].imm_u8)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8), + c.imm_values[0].imm_s8)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16), + c.imm_values[0].imm_u16)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16), + c.imm_values[0].imm_s16)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32), + c.imm_values[0].imm_u32)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32), + c.imm_values[0].imm_s32)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64), + c.imm_values[0].imm_u64)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_s64, b.imm_values[0].imm_s64), + c.imm_values[0].imm_s64)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32), + c.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64), + c.imm_values[0].imm_f64)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + u8 mmx = std::min(std::max(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8), + c.imm_values[0].imm_u8); + return ImmValue(std::max(std::min(a.imm_values[0].imm_u8, b.imm_values[0].imm_u8), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + s8 mmx = std::min(std::max(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8), + c.imm_values[0].imm_s8); + return ImmValue(std::max(std::min(a.imm_values[0].imm_s8, b.imm_values[0].imm_s8), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + u16 mmx = std::min(std::max(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16), + c.imm_values[0].imm_u16); + return ImmValue(std::max(std::min(a.imm_values[0].imm_u16, b.imm_values[0].imm_u16), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + s16 mmx = std::min(std::max(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16), + c.imm_values[0].imm_s16); + return ImmValue(std::max(std::min(a.imm_values[0].imm_s16, b.imm_values[0].imm_s16), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + u32 mmx = std::min(std::max(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32), + c.imm_values[0].imm_u32); + return ImmValue(std::max(std::min(a.imm_values[0].imm_u32, b.imm_values[0].imm_u32), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + s32 mmx = std::min(std::max(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32), + c.imm_values[0].imm_s32); + return ImmValue(std::max(std::min(a.imm_values[0].imm_s32, b.imm_values[0].imm_s32), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + u64 mmx = std::min(std::max(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64), + c.imm_values[0].imm_u64); + return ImmValue(std::max(std::min(a.imm_values[0].imm_u64, b.imm_values[0].imm_u64), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + s64 mmx = std::min(std::max(a.imm_values[0].imm_s64, b.imm_values[0].imm_s64), + c.imm_values[0].imm_s64); + return ImmValue(std::max(std::min(a.imm_values[0].imm_s64, b.imm_values[0].imm_s64), + mmx)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_f32, b.imm_values[0].imm_f32), + c.imm_values[0].imm_f32)); +} + +template <> +ImmValue ImmValue::MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept { + return ImmValue(std::max(std::max(a.imm_values[0].imm_f64, b.imm_values[0].imm_f64), + c.imm_values[0].imm_f64)); +} + template <> ImmValue ImmValue::Clamp(const ImmValue& in, const ImmValue& min, const ImmValue& max) noexcept { diff --git a/src/shader_recompiler/ir/compute_value/imm_value.h b/src/shader_recompiler/ir/compute_value/imm_value.h index 800ee4b16..513e36db0 100644 --- a/src/shader_recompiler/ir/compute_value/imm_value.h +++ b/src/shader_recompiler/ir/compute_value/imm_value.h @@ -166,6 +166,15 @@ public: template [[nodiscard]] static ImmValue Max(const ImmValue& a, const ImmValue& b) noexcept; + template + [[nodiscard]] static ImmValue MinTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept; + + template + [[nodiscard]] static ImmValue MaxTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept; + + template + [[nodiscard]] static ImmValue MedTri(const ImmValue& a, const ImmValue& b, const ImmValue& c) noexcept; + template [[nodiscard]] static ImmValue Clamp(const ImmValue& in, const ImmValue& min, const ImmValue& max) noexcept;