shader: Implement Int32 SUATOM/SURED

This commit is contained in:
ameerj 2021-04-23 17:47:54 -04:00
parent d621e96d0d
commit 7ecc6de56a
17 changed files with 733 additions and 6 deletions

View file

@ -1869,6 +1869,95 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value
Inst(op, Flags{info}, handle, coords, color);
}
Value IREmitter::ImageAtomicIAdd(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicIAdd32
: Opcode::BindlessImageAtomicIAdd32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicSMin(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicSMin32
: Opcode::BindlessImageAtomicSMin32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicUMin(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicUMin32
: Opcode::BindlessImageAtomicUMin32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicIMin(const Value& handle, const Value& coords, const Value& value,
bool is_signed, TextureInstInfo info) {
return is_signed ? ImageAtomicSMin(handle, coords, value, info)
: ImageAtomicUMin(handle, coords, value, info);
}
Value IREmitter::ImageAtomicSMax(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicSMax32
: Opcode::BindlessImageAtomicSMax32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicUMax(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicUMax32
: Opcode::BindlessImageAtomicUMax32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicIMax(const Value& handle, const Value& coords, const Value& value,
bool is_signed, TextureInstInfo info) {
return is_signed ? ImageAtomicSMax(handle, coords, value, info)
: ImageAtomicUMax(handle, coords, value, info);
}
Value IREmitter::ImageAtomicInc(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicInc32
: Opcode::BindlessImageAtomicInc32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicDec(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicDec32
: Opcode::BindlessImageAtomicDec32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicAnd(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicAnd32
: Opcode::BindlessImageAtomicAnd32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicOr(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicOr32
: Opcode::BindlessImageAtomicOr32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicXor(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicXor32
: Opcode::BindlessImageAtomicXor32};
return Inst(op, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicExchange(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageAtomicExchange32
: Opcode::BindlessImageAtomicExchange32};
return Inst(op, Flags{info}, handle, coords, value);
}
U1 IREmitter::VoteAll(const U1& value) {
return Inst<U1>(Opcode::VoteAll, value);
}

View file

@ -334,6 +334,32 @@ public:
[[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicSMin(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicUMin(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicIMin(const Value& handle, const Value& coords,
const Value& value, bool is_signed, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicSMax(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicUMax(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicIMax(const Value& handle, const Value& coords,
const Value& value, bool is_signed, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicInc(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicDec(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicAnd(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicOr(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicXor(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicExchange(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] U1 VoteAll(const U1& value);
[[nodiscard]] U1 VoteAny(const U1& value);
[[nodiscard]] U1 VoteEqual(const U1& value);

View file

@ -166,6 +166,39 @@ bool Inst::MayHaveSideEffects() const noexcept {
case Opcode::BindlessImageWrite:
case Opcode::BoundImageWrite:
case Opcode::ImageWrite:
case IR::Opcode::BindlessImageAtomicIAdd32:
case IR::Opcode::BindlessImageAtomicSMin32:
case IR::Opcode::BindlessImageAtomicUMin32:
case IR::Opcode::BindlessImageAtomicSMax32:
case IR::Opcode::BindlessImageAtomicUMax32:
case IR::Opcode::BindlessImageAtomicInc32:
case IR::Opcode::BindlessImageAtomicDec32:
case IR::Opcode::BindlessImageAtomicAnd32:
case IR::Opcode::BindlessImageAtomicOr32:
case IR::Opcode::BindlessImageAtomicXor32:
case IR::Opcode::BindlessImageAtomicExchange32:
case IR::Opcode::BoundImageAtomicIAdd32:
case IR::Opcode::BoundImageAtomicSMin32:
case IR::Opcode::BoundImageAtomicUMin32:
case IR::Opcode::BoundImageAtomicSMax32:
case IR::Opcode::BoundImageAtomicUMax32:
case IR::Opcode::BoundImageAtomicInc32:
case IR::Opcode::BoundImageAtomicDec32:
case IR::Opcode::BoundImageAtomicAnd32:
case IR::Opcode::BoundImageAtomicOr32:
case IR::Opcode::BoundImageAtomicXor32:
case IR::Opcode::BoundImageAtomicExchange32:
case IR::Opcode::ImageAtomicIAdd32:
case IR::Opcode::ImageAtomicSMin32:
case IR::Opcode::ImageAtomicUMin32:
case IR::Opcode::ImageAtomicSMax32:
case IR::Opcode::ImageAtomicUMax32:
case IR::Opcode::ImageAtomicInc32:
case IR::Opcode::ImageAtomicDec32:
case IR::Opcode::ImageAtomicAnd32:
case IR::Opcode::ImageAtomicOr32:
case IR::Opcode::ImageAtomicXor32:
case IR::Opcode::ImageAtomicExchange32:
return true;
default:
return false;

View file

@ -496,6 +496,44 @@ OPCODE(ImageGradient, F32x4, Opaq
OPCODE(ImageRead, U32x4, Opaque, Opaque, )
OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, )
// Atomic Image operations
OPCODE(BindlessImageAtomicIAdd32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicSMin32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicUMin32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicSMax32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicUMax32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicInc32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicDec32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicAnd32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicOr32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicXor32, U32, U32, Opaque, U32, )
OPCODE(BindlessImageAtomicExchange32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicIAdd32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicSMin32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicUMin32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicSMax32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicUMax32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicInc32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicDec32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicAnd32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicOr32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicXor32, U32, U32, Opaque, U32, )
OPCODE(BoundImageAtomicExchange32, U32, U32, Opaque, U32, )
OPCODE(ImageAtomicIAdd32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicSMin32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicUMin32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicSMax32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicUMax32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicInc32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicDec32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicAnd32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicOr32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicXor32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicExchange32, U32, Opaque, Opaque, U32, )
// Warp operations
OPCODE(LaneId, U32, )
OPCODE(VoteAll, U1, U1, )

View file

@ -244,7 +244,8 @@ INST(STG, "STG", "1110 1110 1101 1---")
INST(STL, "STL", "1110 1111 0101 0---")
INST(STP, "STP", "1110 1110 1010 0---")
INST(STS, "STS", "1110 1111 0101 1---")
INST(SUATOM_cas, "SUATOM", "1110 1010 ---- ----")
INST(SUATOM, "SUATOM", "1110 1010 0--- ----")
INST(SUATOM_cas, "SUATOM_cas", "1110 1010 1--- ----")
INST(SULD, "SULD", "1110 1011 000- ----")
INST(SURED, "SURED", "1110 1011 010- ----")
INST(SUST, "SUST", "1110 1011 001- ----")

View file

@ -303,6 +303,7 @@ public:
void STL(u64 insn);
void STP(u64 insn);
void STS(u64 insn);
void SUATOM(u64 insn);
void SUATOM_cas(u64 insn);
void SULD(u64 insn);
void SURED(u64 insn);

View file

@ -249,10 +249,6 @@ void TranslatorVisitor::SUATOM_cas(u64) {
ThrowNotImplemented(Opcode::SUATOM_cas);
}
void TranslatorVisitor::SURED(u64) {
ThrowNotImplemented(Opcode::SURED);
}
void TranslatorVisitor::SYNC(u64) {
ThrowNotImplemented(Opcode::SYNC);
}

View file

@ -0,0 +1,204 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <bit>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "shader_recompiler/frontend/ir/modifiers.h"
#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
namespace Shader::Maxwell {
namespace {
enum class Type : u64 {
_1D,
BUFFER_1D,
ARRAY_1D,
_2D,
ARRAY_2D,
_3D,
};
enum class Size : u64 {
U32,
S32,
U64,
S64,
F32FTZRN,
F16x2FTZRN,
SD32,
SD64,
};
enum class AtomicOp : u64 {
ADD,
MIN,
MAX,
INC,
DEC,
AND,
OR,
XOR,
EXCH,
};
enum class Clamp : u64 {
IGN,
Default,
TRAP,
};
TextureType GetType(Type type) {
switch (type) {
case Type::_1D:
return TextureType::Color1D;
case Type::BUFFER_1D:
return TextureType::Buffer;
case Type::ARRAY_1D:
return TextureType::ColorArray1D;
case Type::_2D:
return TextureType::Color2D;
case Type::ARRAY_2D:
return TextureType::ColorArray2D;
case Type::_3D:
return TextureType::Color3D;
}
throw NotImplementedException("Invalid type {}", type);
}
IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) {
const auto array{[&](int index) {
return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16));
}};
switch (type) {
case Type::_1D:
case Type::BUFFER_1D:
return v.X(reg);
default:
break;
}
throw NotImplementedException("Invalid type {}", type);
}
IR::Value ApplyAtomicOp(IR::IREmitter& ir, const IR::U32& handle, const IR::Value& coords,
const IR::Value& op_b, IR::TextureInstInfo info, AtomicOp op,
bool is_signed) {
switch (op) {
case AtomicOp::ADD:
return ir.ImageAtomicIAdd(handle, coords, op_b, info);
case AtomicOp::MIN:
return ir.ImageAtomicIMin(handle, coords, op_b, is_signed, info);
case AtomicOp::MAX:
return ir.ImageAtomicIMax(handle, coords, op_b, is_signed, info);
case AtomicOp::INC:
return ir.ImageAtomicInc(handle, coords, op_b, info);
case AtomicOp::DEC:
return ir.ImageAtomicDec(handle, coords, op_b, info);
case AtomicOp::AND:
return ir.ImageAtomicAnd(handle, coords, op_b, info);
case AtomicOp::OR:
return ir.ImageAtomicOr(handle, coords, op_b, info);
case AtomicOp::XOR:
return ir.ImageAtomicXor(handle, coords, op_b, info);
case AtomicOp::EXCH:
return ir.ImageAtomicExchange(handle, coords, op_b, info);
default:
throw NotImplementedException("Atomic Operation {}", op);
}
}
ImageFormat Format(Size size) {
switch (size) {
case Size::U32:
case Size::S32:
case Size::SD32:
return ImageFormat::R32_UINT;
default:
break;
}
throw NotImplementedException("Invalid size {}", size);
}
bool IsSizeInt32(Size size) {
switch (size) {
case Size::U32:
case Size::S32:
case Size::SD32:
return true;
default:
return false;
}
}
void ImageAtomOp(TranslatorVisitor& v, IR::Reg dest_reg, IR::Reg operand_reg, IR::Reg coord_reg,
IR::Reg bindless_reg, AtomicOp op, Clamp clamp, Size size, Type type,
u64 bound_offset, bool is_bindless, bool write_result) {
if (clamp != Clamp::IGN) {
throw NotImplementedException("Clamp {}", clamp);
}
if (!IsSizeInt32(size)) {
throw NotImplementedException("Size {}", size);
}
const bool is_signed{size == Size::S32};
const ImageFormat format{Format(size)};
const TextureType tex_type{GetType(type)};
const IR::Value coords{MakeCoords(v, coord_reg, type)};
const IR::U32 handle{is_bindless != 0 ? v.X(bindless_reg)
: v.ir.Imm32(static_cast<u32>(bound_offset * 4))};
IR::TextureInstInfo info{};
info.type.Assign(tex_type);
info.image_format.Assign(format);
// TODO: float/64-bit operand
const IR::Value op_b{v.X(operand_reg)};
const IR::Value color{ApplyAtomicOp(v.ir, handle, coords, op_b, info, op, is_signed)};
if (write_result) {
v.X(dest_reg, IR::U32{color});
}
}
} // Anonymous namespace
void TranslatorVisitor::SUATOM(u64 insn) {
union {
u64 raw;
BitField<54, 1, u64> is_bindless;
BitField<29, 4, AtomicOp> op;
BitField<33, 3, Type> type;
BitField<51, 3, Size> size;
BitField<49, 2, Clamp> clamp;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 8, IR::Reg> coord_reg;
BitField<20, 8, IR::Reg> operand_reg;
BitField<36, 13, u64> bound_offset; // !is_bindless
BitField<39, 8, IR::Reg> bindless_reg; // is_bindless
} const suatom{insn};
ImageAtomOp(*this, suatom.dest_reg, suatom.operand_reg, suatom.coord_reg, suatom.bindless_reg,
suatom.op, suatom.clamp, suatom.size, suatom.type, suatom.bound_offset,
suatom.is_bindless != 0, true);
}
void TranslatorVisitor::SURED(u64 insn) {
// TODO: confirm offsets
union {
u64 raw;
BitField<51, 1, u64> is_bound;
BitField<21, 3, AtomicOp> op;
BitField<33, 3, Type> type;
BitField<20, 3, Size> size;
BitField<49, 2, Clamp> clamp;
BitField<0, 8, IR::Reg> operand_reg;
BitField<8, 8, IR::Reg> coord_reg;
BitField<36, 13, u64> bound_offset; // is_bound
BitField<39, 8, IR::Reg> bindless_reg; // !is_bound
} const sured{insn};
ImageAtomOp(*this, IR::Reg::RZ, sured.operand_reg, sured.coord_reg, sured.bindless_reg,
sured.op, sured.clamp, sured.size, sured.type, sured.bound_offset,
sured.is_bound == 0, false);
}
} // namespace Shader::Maxwell