mirror of https://github.com/yuzu-mirror/yuzu
shader: Implement VMAD, VMNMX, VSETP
parent
0e1b213fa7
commit
51475e21ba
@ -0,0 +1,30 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
|
||||
IR::U32 ExtractVideoOperandValue(IR::IREmitter& ir, const IR::U32& value, VideoWidth width,
|
||||
u32 selector, bool is_signed) {
|
||||
switch (width) {
|
||||
case VideoWidth::Byte:
|
||||
case VideoWidth::Unknown:
|
||||
return ir.BitFieldExtract(value, ir.Imm32(selector * 8), ir.Imm32(8), is_signed);
|
||||
case VideoWidth::Short:
|
||||
return ir.BitFieldExtract(value, ir.Imm32(selector * 16), ir.Imm32(16), is_signed);
|
||||
case VideoWidth::Word:
|
||||
return value;
|
||||
default:
|
||||
throw NotImplementedException("Unknown VideoWidth {}", width);
|
||||
}
|
||||
}
|
||||
|
||||
VideoWidth GetVideoSourceWidth(VideoWidth width, bool is_immediate) {
|
||||
// immediates must be 16-bit format.
|
||||
return is_immediate ? VideoWidth::Short : width;
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
@ -0,0 +1,23 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
enum class VideoWidth : u64 {
|
||||
Byte,
|
||||
Unknown,
|
||||
Short,
|
||||
Word,
|
||||
};
|
||||
|
||||
[[nodiscard]] IR::U32 ExtractVideoOperandValue(IR::IREmitter& ir, const IR::U32& value,
|
||||
VideoWidth width, u32 selector, bool is_signed);
|
||||
|
||||
[[nodiscard]] VideoWidth GetVideoSourceWidth(VideoWidth width, bool is_immediate);
|
||||
|
||||
} // namespace Shader::Maxwell
|
@ -0,0 +1,92 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class VideoMinMaxOps : u64 {
|
||||
MRG_16H,
|
||||
MRG_16L,
|
||||
MRG_8B0,
|
||||
MRG_8B2,
|
||||
ACC,
|
||||
MIN,
|
||||
MAX,
|
||||
};
|
||||
|
||||
[[nodiscard]] IR::U32 ApplyVideoMinMaxOp(IR::IREmitter& ir, const IR::U32& lhs, const IR::U32& rhs,
|
||||
VideoMinMaxOps op, bool is_signed) {
|
||||
switch (op) {
|
||||
case VideoMinMaxOps::MIN:
|
||||
return ir.IMin(lhs, rhs, is_signed);
|
||||
case VideoMinMaxOps::MAX:
|
||||
return ir.IMax(lhs, rhs, is_signed);
|
||||
default:
|
||||
throw NotImplementedException("VMNMX op {}", op);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::VMNMX(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<20, 16, u64> src_b_imm;
|
||||
BitField<28, 2, u64> src_b_selector;
|
||||
BitField<29, 2, VideoWidth> src_b_width;
|
||||
BitField<36, 2, u64> src_a_selector;
|
||||
BitField<37, 2, VideoWidth> src_a_width;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> src_a_sign;
|
||||
BitField<49, 1, u64> src_b_sign;
|
||||
BitField<50, 1, u64> is_src_b_reg;
|
||||
BitField<51, 3, VideoMinMaxOps> op;
|
||||
BitField<54, 1, u64> dest_sign;
|
||||
BitField<55, 1, u64> sat;
|
||||
BitField<56, 1, u64> mx;
|
||||
} const vmnmx{insn};
|
||||
|
||||
if (vmnmx.cc != 0) {
|
||||
throw NotImplementedException("VMNMX CC");
|
||||
}
|
||||
if (vmnmx.sat != 0) {
|
||||
throw NotImplementedException("VMNMX SAT");
|
||||
}
|
||||
// Selectors were shown to default to 2 in unit tests
|
||||
if (vmnmx.src_a_selector != 2) {
|
||||
throw NotImplementedException("VMNMX Selector {}", vmnmx.src_a_selector.Value());
|
||||
}
|
||||
if (vmnmx.src_b_selector != 2) {
|
||||
throw NotImplementedException("VMNMX Selector {}", vmnmx.src_b_selector.Value());
|
||||
}
|
||||
if (vmnmx.src_a_width != VideoWidth::Word) {
|
||||
throw NotImplementedException("VMNMX Source Width {}", vmnmx.src_a_width.Value());
|
||||
}
|
||||
|
||||
const bool is_b_imm{vmnmx.is_src_b_reg == 0};
|
||||
const IR::U32 src_a{GetReg8(insn)};
|
||||
const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vmnmx.src_b_imm)) : GetReg20(insn)};
|
||||
const IR::U32 src_c{GetReg39(insn)};
|
||||
|
||||
const VideoWidth a_width{vmnmx.src_a_width};
|
||||
const VideoWidth b_width{GetVideoSourceWidth(vmnmx.src_b_width, is_b_imm)};
|
||||
|
||||
const bool src_a_signed{vmnmx.src_a_sign != 0};
|
||||
const bool src_b_signed{vmnmx.src_b_sign != 0};
|
||||
const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, 0, src_a_signed)};
|
||||
const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, 0, src_b_signed)};
|
||||
|
||||
// First operation's sign is only dependent on operand b's sign
|
||||
const bool op_1_signed{src_b_signed};
|
||||
|
||||
const IR::U32 lhs{vmnmx.mx != 0 ? ir.IMax(op_a, op_b, op_1_signed)
|
||||
: ir.IMin(op_a, op_b, op_1_signed)};
|
||||
X(vmnmx.dest_reg, ApplyVideoMinMaxOp(ir, lhs, src_c, vmnmx.op, vmnmx.dest_sign != 0));
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
@ -0,0 +1,64 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
void TranslatorVisitor::VMAD(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<0, 8, IR::Reg> dest_reg;
|
||||
BitField<20, 16, u64> src_b_imm;
|
||||
BitField<28, 2, u64> src_b_selector;
|
||||
BitField<29, 2, VideoWidth> src_b_width;
|
||||
BitField<36, 2, u64> src_a_selector;
|
||||
BitField<37, 2, VideoWidth> src_a_width;
|
||||
BitField<47, 1, u64> cc;
|
||||
BitField<48, 1, u64> src_a_sign;
|
||||
BitField<49, 1, u64> src_b_sign;
|
||||
BitField<50, 1, u64> is_src_b_reg;
|
||||
BitField<51, 2, u64> scale;
|
||||
BitField<53, 1, u64> src_c_neg;
|
||||
BitField<54, 1, u64> src_a_neg;
|
||||
BitField<55, 1, u64> sat;
|
||||
} const vmad{insn};
|
||||
|
||||
if (vmad.cc != 0) {
|
||||
throw NotImplementedException("VMAD CC");
|
||||
}
|
||||
if (vmad.sat != 0) {
|
||||
throw NotImplementedException("VMAD SAT");
|
||||
}
|
||||
if (vmad.scale != 0) {
|
||||
throw NotImplementedException("VMAD SCALE");
|
||||
}
|
||||
if (vmad.src_a_neg != 0 && vmad.src_c_neg != 0) {
|
||||
throw NotImplementedException("VMAD PO");
|
||||
}
|
||||
if (vmad.src_a_neg != 0 || vmad.src_c_neg != 0) {
|
||||
throw NotImplementedException("VMAD NEG");
|
||||
}
|
||||
const bool is_b_imm{vmad.is_src_b_reg == 0};
|
||||
const IR::U32 src_a{GetReg8(insn)};
|
||||
const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vmad.src_b_imm)) : GetReg20(insn)};
|
||||
const IR::U32 src_c{GetReg39(insn)};
|
||||
|
||||
const u32 a_selector{static_cast<u32>(vmad.src_a_selector)};
|
||||
// Immediate values can't have a selector
|
||||
const u32 b_selector{is_b_imm ? 0U : static_cast<u32>(vmad.src_b_selector)};
|
||||
const VideoWidth a_width{vmad.src_a_width};
|
||||
const VideoWidth b_width{GetVideoSourceWidth(vmad.src_b_width, is_b_imm)};
|
||||
|
||||
const bool src_a_signed{vmad.src_a_sign != 0};
|
||||
const bool src_b_signed{vmad.src_b_sign != 0};
|
||||
const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, a_selector, src_a_signed)};
|
||||
const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, b_selector, src_b_signed)};
|
||||
|
||||
X(vmad.dest_reg, ir.IAdd(ir.IMul(op_a, op_b), src_c));
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
@ -0,0 +1,92 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/common_funcs.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
|
||||
#include "shader_recompiler/frontend/maxwell/translate/impl/video_helper.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
namespace {
|
||||
enum class VsetpCompareOp : u64 {
|
||||
False = 0,
|
||||
LessThan,
|
||||
Equal,
|
||||
LessThanEqual,
|
||||
GreaterThan = 16,
|
||||
NotEqual,
|
||||
GreaterThanEqual,
|
||||
True,
|
||||
};
|
||||
|
||||
CompareOp VsetpToShaderCompareOp(VsetpCompareOp op) {
|
||||
switch (op) {
|
||||
case VsetpCompareOp::False:
|
||||
return CompareOp::False;
|
||||
case VsetpCompareOp::LessThan:
|
||||
return CompareOp::LessThan;
|
||||
case VsetpCompareOp::Equal:
|
||||
return CompareOp::Equal;
|
||||
case VsetpCompareOp::LessThanEqual:
|
||||
return CompareOp::LessThanEqual;
|
||||
case VsetpCompareOp::GreaterThan:
|
||||
return CompareOp::GreaterThan;
|
||||
case VsetpCompareOp::NotEqual:
|
||||
return CompareOp::NotEqual;
|
||||
case VsetpCompareOp::GreaterThanEqual:
|
||||
return CompareOp::GreaterThanEqual;
|
||||
case VsetpCompareOp::True:
|
||||
return CompareOp::True;
|
||||
default:
|
||||
throw NotImplementedException("Invalid compare op {}", op);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::VSETP(u64 insn) {
|
||||
union {
|
||||
u64 raw;
|
||||
BitField<0, 3, IR::Pred> dest_pred_b;
|
||||
BitField<3, 3, IR::Pred> dest_pred_a;
|
||||
BitField<20, 16, u64> src_b_imm;
|
||||
BitField<28, 2, u64> src_b_selector;
|
||||
BitField<29, 2, VideoWidth> src_b_width;
|
||||
BitField<36, 2, u64> src_a_selector;
|
||||
BitField<37, 2, VideoWidth> src_a_width;
|
||||
BitField<39, 3, IR::Pred> bop_pred;
|
||||
BitField<42, 1, u64> neg_bop_pred;
|
||||
BitField<43, 5, VsetpCompareOp> compare_op;
|
||||
BitField<45, 2, BooleanOp> bop;
|
||||
BitField<48, 1, u64> src_a_sign;
|
||||
BitField<49, 1, u64> src_b_sign;
|
||||
BitField<50, 1, u64> is_src_b_reg;
|
||||
} const vsetp{insn};
|
||||
|
||||
const bool is_b_imm{vsetp.is_src_b_reg == 0};
|
||||
const IR::U32 src_a{GetReg8(insn)};
|
||||
const IR::U32 src_b{is_b_imm ? ir.Imm32(static_cast<u32>(vsetp.src_b_imm)) : GetReg20(insn)};
|
||||
|
||||
const u32 a_selector{static_cast<u32>(vsetp.src_a_selector)};
|
||||
const u32 b_selector{is_b_imm ? 0U : static_cast<u32>(vsetp.src_b_selector)};
|
||||
const VideoWidth a_width{vsetp.src_a_width};
|
||||
const VideoWidth b_width{GetVideoSourceWidth(vsetp.src_b_width, is_b_imm)};
|
||||
|
||||
const bool src_a_signed{vsetp.src_a_sign != 0};
|
||||
const bool src_b_signed{vsetp.src_b_sign != 0};
|
||||
const IR::U32 op_a{ExtractVideoOperandValue(ir, src_a, a_width, a_selector, src_a_signed)};
|
||||
const IR::U32 op_b{ExtractVideoOperandValue(ir, src_b, b_width, a_selector, src_b_signed)};
|
||||
|
||||
// Compare operation's sign is only dependent on operand b's sign
|
||||
const bool compare_signed{src_b_signed};
|
||||
const CompareOp compare_op{VsetpToShaderCompareOp(vsetp.compare_op)};
|
||||
const IR::U1 comparison{IntegerCompare(ir, op_a, op_b, compare_op, compare_signed)};
|
||||
const IR::U1 bop_pred{ir.GetPred(vsetp.bop_pred, vsetp.neg_bop_pred != 0)};
|
||||
const IR::U1 result_a{PredicateCombine(ir, comparison, bop_pred, vsetp.bop)};
|
||||
const IR::U1 result_b{PredicateCombine(ir, ir.LogicalNot(comparison), bop_pred, vsetp.bop)};
|
||||
ir.SetPred(vsetp.dest_pred_a, result_a);
|
||||
ir.SetPred(vsetp.dest_pred_b, result_b);
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
Loading…
Reference in New Issue