mirror of https://github.com/yuzu-mirror/yuzu
shader: Implement Int32 SUATOM/SURED
parent
d621e96d0d
commit
7ecc6de56a
@ -0,0 +1,182 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
|
||||
if (!index.IsImmediate()) {
|
||||
throw NotImplementedException("Indirect image indexing");
|
||||
}
|
||||
if (info.type == TextureType::Buffer) {
|
||||
const ImageBufferDefinition def{ctx.image_buffers.at(index.U32())};
|
||||
return def.id;
|
||||
} else {
|
||||
const ImageDefinition def{ctx.images.at(index.U32())};
|
||||
return def.id;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Id, Id> AtomicArgs(EmitContext& ctx) {
|
||||
const Id scope{ctx.Const(static_cast<u32>(spv::Scope::Device))};
|
||||
const Id semantics{ctx.u32_zero_value};
|
||||
return {scope, semantics};
|
||||
}
|
||||
|
||||
Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id value,
|
||||
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const Id image{Image(ctx, index, info)};
|
||||
const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, image, coords, ctx.Const(0U))};
|
||||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
||||
return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitImageAtomicIAdd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicIAdd);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicSMin);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicUMin);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicSMax);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicUMax);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicInc32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) {
|
||||
// TODO: This is not yet implemented
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitImageAtomicDec32(EmitContext&, IR::Inst*, const IR::Value&, Id, Id) {
|
||||
// TODO: This is not yet implemented
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicAnd);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicOr32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicOr);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicXor32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicXor);
|
||||
}
|
||||
|
||||
Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id value) {
|
||||
return ImageAtomicU32(ctx, inst, index, coords, value, &Sirit::Module::OpAtomicExchange);
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicIAdd32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicSMin32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicUMin32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicSMax32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicUMax32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicInc32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicDec32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicAnd32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicOr32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicXor32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBindlessImageAtomicExchange32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicIAdd32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicSMin32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicUMin32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicSMax32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicUMax32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicInc32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicDec32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicAnd32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicOr32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicXor32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
Id EmitBoundImageAtomicExchange32(EmitContext&) {
|
||||
throw NotImplementedException("SPIR-V Instruction");
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
@ -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
|
Loading…
Reference in New Issue