shader: FMUL, select, RRO, and MUFU fixes
This commit is contained in:
parent
18a766b362
commit
e44752ddc8
18 changed files with 507 additions and 119 deletions
|
@ -46,7 +46,8 @@ inline IR::FmzMode CastFmzMode(FmzMode fmz_mode) {
|
|||
case FmzMode::FTZ:
|
||||
return IR::FmzMode::FTZ;
|
||||
case FmzMode::FMZ:
|
||||
return IR::FmzMode::FMZ;
|
||||
// FMZ is manually handled in the instruction
|
||||
return IR::FmzMode::FTZ;
|
||||
case FmzMode::INVALIDFMZ3:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ void FADD(TranslatorVisitor& v, u64 insn, const IR::F32& src_b) {
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::FADD_reg(u64 insn) {
|
||||
FADD(*this, insn, GetRegFloat20(insn));
|
||||
FADD(*this, insn, GetFloatReg20(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FADD_cbuf(u64 insn) {
|
||||
|
|
|
@ -51,7 +51,7 @@ void FFMA(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, const IR::F32& s
|
|||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::FFMA_reg(u64 insn) {
|
||||
FFMA(*this, insn, GetRegFloat20(insn), GetRegFloat39(insn));
|
||||
FFMA(*this, insn, GetFloatReg20(insn), GetFloatReg39(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FFMA_rc(u64) {
|
||||
|
@ -59,7 +59,7 @@ void TranslatorVisitor::FFMA_rc(u64) {
|
|||
}
|
||||
|
||||
void TranslatorVisitor::FFMA_cr(u64 insn) {
|
||||
FFMA(*this, insn, GetFloatCbuf(insn), GetRegFloat39(insn));
|
||||
FFMA(*this, insn, GetFloatCbuf(insn), GetFloatReg39(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FFMA_imm(u64) {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Operation {
|
||||
enum class Operation : u64 {
|
||||
Cos = 0,
|
||||
Sin = 1,
|
||||
Ex2 = 2, // Base 2 exponent
|
||||
|
@ -39,11 +39,11 @@ void TranslatorVisitor::MUFU(u64 insn) {
|
|||
IR::F32 value{[&]() -> IR::F32 {
|
||||
switch (mufu.operation) {
|
||||
case Operation::Cos:
|
||||
return ir.FPCosNotReduced(op_a);
|
||||
return ir.FPCos(op_a);
|
||||
case Operation::Sin:
|
||||
return ir.FPSinNotReduced(op_a);
|
||||
return ir.FPSin(op_a);
|
||||
case Operation::Ex2:
|
||||
return ir.FPExp2NotReduced(op_a);
|
||||
return ir.FPExp2(op_a);
|
||||
case Operation::Lg2:
|
||||
return ir.FPLog2(op_a);
|
||||
case Operation::Rcp:
|
||||
|
|
|
@ -55,9 +55,6 @@ void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, FmzMode fmz_mode
|
|||
if (cc) {
|
||||
throw NotImplementedException("FMUL CC");
|
||||
}
|
||||
if (sat) {
|
||||
throw NotImplementedException("FMUL SAT");
|
||||
}
|
||||
IR::F32 op_a{v.F(fmul.src_a)};
|
||||
if (scale != Scale::None) {
|
||||
if (fmz_mode != FmzMode::FTZ || fp_rounding != FpRounding::RN) {
|
||||
|
@ -71,7 +68,20 @@ void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b, FmzMode fmz_mode
|
|||
.rounding{CastFpRounding(fp_rounding)},
|
||||
.fmz_mode{CastFmzMode(fmz_mode)},
|
||||
};
|
||||
v.F(fmul.dest_reg, v.ir.FPMul(op_a, op_b, fp_control));
|
||||
IR::F32 value{v.ir.FPMul(op_a, op_b, fp_control)};
|
||||
if (fmz_mode == FmzMode::FMZ && !sat) {
|
||||
// Do not implement FMZ if SAT is enabled, as it does the logic for us.
|
||||
// On D3D9 mode, anything * 0 is zero, even NAN and infinity
|
||||
const IR::F32 zero{v.ir.Imm32(0.0f)};
|
||||
const IR::U1 zero_a{v.ir.FPEqual(op_a, zero)};
|
||||
const IR::U1 zero_b{v.ir.FPEqual(op_b, zero)};
|
||||
const IR::U1 any_zero{v.ir.LogicalOr(zero_a, zero_b)};
|
||||
value = IR::F32{v.ir.Select(any_zero, zero, value)};
|
||||
}
|
||||
if (sat) {
|
||||
value = v.ir.FPSaturate(value);
|
||||
}
|
||||
v.F(fmul.dest_reg, value);
|
||||
}
|
||||
|
||||
void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b) {
|
||||
|
@ -83,27 +93,33 @@ void FMUL(TranslatorVisitor& v, u64 insn, const IR::F32& src_b) {
|
|||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> neg_b;
|
||||
BitField<50, 1, u64> sat;
|
||||
} fmul{insn};
|
||||
|
||||
} const fmul{insn};
|
||||
FMUL(v, insn, src_b, fmul.fmz, fmul.fp_rounding, fmul.scale, fmul.sat != 0, fmul.cc != 0,
|
||||
fmul.neg_b != 0);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::FMUL_reg(u64 insn) {
|
||||
return FMUL(*this, insn, GetRegFloat20(insn));
|
||||
return FMUL(*this, insn, GetFloatReg20(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FMUL_cbuf(u64) {
|
||||
throw NotImplementedException("FMUL (cbuf)");
|
||||
void TranslatorVisitor::FMUL_cbuf(u64 insn) {
|
||||
return FMUL(*this, insn, GetFloatCbuf(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FMUL_imm(u64) {
|
||||
throw NotImplementedException("FMUL (imm)");
|
||||
void TranslatorVisitor::FMUL_imm(u64 insn) {
|
||||
return FMUL(*this, insn, GetFloatImm20(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::FMUL32I(u64) {
|
||||
throw NotImplementedException("FMUL32I");
|
||||
void TranslatorVisitor::FMUL32I(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<52, 1, u64> cc;
|
||||
BitField<53, 2, FmzMode> fmz;
|
||||
BitField<55, 1, u64> sat;
|
||||
} const fmul32i{insn};
|
||||
FMUL(*this, insn, GetFloatImm32(insn), fmul32i.fmz, FpRounding::RN, Scale::None,
|
||||
fmul32i.sat != 0, fmul32i.cc != 0, false);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class Mode : u64 {
|
||||
SINCOS,
|
||||
EX2,
|
||||
};
|
||||
|
||||
void RRO(TranslatorVisitor& v, u64 insn, const IR::F32& src) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<39, 1, Mode> mode;
|
||||
BitField<45, 1, u64> neg;
|
||||
BitField<49, 1, u64> abs;
|
||||
} const rro{insn};
|
||||
|
||||
v.F(rro.dest_reg, v.ir.FPAbsNeg(src, rro.abs != 0, rro.neg != 0));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::RRO_reg(u64 insn) {
|
||||
RRO(*this, insn, GetFloatReg20(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RRO_cbuf(u64 insn) {
|
||||
RRO(*this, insn, GetFloatCbuf(insn));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RRO_imm(u64) {
|
||||
throw NotImplementedException("RRO (imm)");
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
|
@ -48,11 +48,11 @@ IR::U32 TranslatorVisitor::GetReg39(u64 insn) {
|
|||
return X(reg.index);
|
||||
}
|
||||
|
||||
IR::F32 TranslatorVisitor::GetRegFloat20(u64 insn) {
|
||||
IR::F32 TranslatorVisitor::GetFloatReg20(u64 insn) {
|
||||
return ir.BitCast<IR::F32>(GetReg20(insn));
|
||||
}
|
||||
|
||||
IR::F32 TranslatorVisitor::GetRegFloat39(u64 insn) {
|
||||
IR::F32 TranslatorVisitor::GetFloatReg39(u64 insn) {
|
||||
return ir.BitCast<IR::F32>(GetReg39(insn));
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,14 @@ IR::U32 TranslatorVisitor::GetImm32(u64 insn) {
|
|||
return ir.Imm32(static_cast<u32>(imm.value));
|
||||
}
|
||||
|
||||
IR::F32 TranslatorVisitor::GetFloatImm32(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<20, 32, u64> value;
|
||||
} const imm{insn};
|
||||
return ir.Imm32(Common::BitCast<f32>(static_cast<u32>(imm.value)));
|
||||
}
|
||||
|
||||
void TranslatorVisitor::SetZFlag(const IR::U1& value) {
|
||||
ir.SetZFlag(value);
|
||||
}
|
||||
|
|
|
@ -304,8 +304,8 @@ public:
|
|||
[[nodiscard]] IR::U32 GetReg8(u64 insn);
|
||||
[[nodiscard]] IR::U32 GetReg20(u64 insn);
|
||||
[[nodiscard]] IR::U32 GetReg39(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetRegFloat20(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetRegFloat39(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatReg20(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatReg39(u64 insn);
|
||||
|
||||
[[nodiscard]] IR::U32 GetCbuf(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatCbuf(u64 insn);
|
||||
|
@ -314,6 +314,7 @@ public:
|
|||
[[nodiscard]] IR::F32 GetFloatImm20(u64 insn);
|
||||
|
||||
[[nodiscard]] IR::U32 GetImm32(u64 insn);
|
||||
[[nodiscard]] IR::F32 GetFloatImm32(u64 insn);
|
||||
|
||||
void SetZFlag(const IR::U1& value);
|
||||
void SetSFlag(const IR::U1& value);
|
||||
|
|
|
@ -50,7 +50,7 @@ void SHL(TranslatorVisitor& v, u64 insn, const IR::U32& unsafe_shift) {
|
|||
//
|
||||
const IR::U1 is_safe{v.ir.ILessThan(unsafe_shift, v.ir.Imm32(32), false)};
|
||||
const IR::U32 unsafe_result{v.ir.ShiftLeftLogical(base, unsafe_shift)};
|
||||
result = v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0));
|
||||
result = IR::U32{v.ir.Select(is_safe, unsafe_result, v.ir.Imm32(0))};
|
||||
}
|
||||
v.X(shl.dest_reg, result);
|
||||
}
|
||||
|
|
|
@ -721,18 +721,6 @@ void TranslatorVisitor::RET(u64) {
|
|||
ThrowNotImplemented(Opcode::RET);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RRO_reg(u64) {
|
||||
ThrowNotImplemented(Opcode::RRO_reg);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RRO_cbuf(u64) {
|
||||
ThrowNotImplemented(Opcode::RRO_cbuf);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RRO_imm(u64) {
|
||||
ThrowNotImplemented(Opcode::RRO_imm);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::RTT(u64) {
|
||||
ThrowNotImplemented(Opcode::RTT);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue