summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/decode/memory.cpp60
-rw-r--r--src/video_core/shader/node.h16
-rw-r--r--src/video_core/shader/node_helper.cpp14
3 files changed, 73 insertions, 17 deletions
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index b5fbc4d58..28a49addd 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -19,7 +19,6 @@ namespace VideoCommon::Shader {
using Tegra::Shader::AtomicOp;
using Tegra::Shader::AtomicType;
using Tegra::Shader::Attribute;
-using Tegra::Shader::GlobalAtomicOp;
using Tegra::Shader::GlobalAtomicType;
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
@@ -28,6 +27,28 @@ using Tegra::Shader::StoreType;
namespace {
+Node GetAtomOperation(AtomicOp op, bool is_signed, Node memory, Node data) {
+ const OperationCode operation_code = [op] {
+ switch (op) {
+ case AtomicOp::Add:
+ return OperationCode::AtomicIAdd;
+ case AtomicOp::Min:
+ return OperationCode::AtomicIMin;
+ case AtomicOp::Max:
+ return OperationCode::AtomicIMax;
+ case AtomicOp::And:
+ return OperationCode::AtomicIAnd;
+ case AtomicOp::Or:
+ return OperationCode::AtomicIOr;
+ case AtomicOp::Xor:
+ return OperationCode::AtomicIXor;
+ case AtomicOp::Exch:
+ return OperationCode::AtomicIExchange;
+ }
+ }();
+ return SignedOperation(operation_code, is_signed, std::move(memory), std::move(data));
+}
+
bool IsUnaligned(Tegra::Shader::UniformType uniform_type) {
return uniform_type == Tegra::Shader::UniformType::UnsignedByte ||
uniform_type == Tegra::Shader::UniformType::UnsignedShort;
@@ -363,10 +384,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::ATOM: {
- UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}",
- static_cast<int>(instr.atom.operation.Value()));
- UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}",
- static_cast<int>(instr.atom.type.Value()));
+ UNIMPLEMENTED_IF_MSG(instr.atom.operation == AtomicOp::Inc ||
+ instr.atom.operation == AtomicOp::Dec ||
+ instr.atom.operation == AtomicOp::SafeAdd,
+ "operation={}", static_cast<int>(instr.atom.operation.Value()));
+ UNIMPLEMENTED_IF_MSG(instr.atom.type == GlobalAtomicType::S64 ||
+ instr.atom.type == GlobalAtomicType::U64,
+ "type={}", static_cast<int>(instr.atom.type.Value()));
const auto [real_address, base_address, descriptor] =
TrackGlobalMemory(bb, instr, true, true);
@@ -375,25 +399,29 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
break;
}
+ const bool is_signed =
+ instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
- Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20));
+ Node value = GetAtomOperation(static_cast<AtomicOp>(instr.atom.operation), is_signed, gmem,
+ GetRegister(instr.gpr20));
SetRegister(bb, instr.gpr0, std::move(value));
break;
}
case OpCode::Id::ATOMS: {
- UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}",
- static_cast<int>(instr.atoms.operation.Value()));
- UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}",
- static_cast<int>(instr.atoms.type.Value()));
-
+ UNIMPLEMENTED_IF_MSG(instr.atoms.operation == AtomicOp::Inc ||
+ instr.atoms.operation == AtomicOp::Dec,
+ "operation={}", static_cast<int>(instr.atoms.operation.Value()));
+ UNIMPLEMENTED_IF_MSG(instr.atoms.type == AtomicType::S64 ||
+ instr.atoms.type == AtomicType::U64,
+ "type={}", static_cast<int>(instr.atoms.type.Value()));
+ const bool is_signed =
+ instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
const s32 offset = instr.atoms.GetImmediateOffset();
Node address = GetRegister(instr.gpr8);
address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset));
-
- Node memory = GetSharedMemory(std::move(address));
- Node data = GetRegister(instr.gpr20);
-
- Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data));
+ Node value =
+ GetAtomOperation(static_cast<AtomicOp>(instr.atoms.operation), is_signed,
+ GetSharedMemory(std::move(address)), GetRegister(instr.gpr20));
SetRegister(bb, instr.gpr0, std::move(value));
break;
}
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index a1828546e..5fcc9da60 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -162,7 +162,21 @@ enum class OperationCode {
AtomicImageXor, /// (MetaImage, int[N] coords) -> void
AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
- AtomicAdd, /// (memory, {u}int) -> {u}int
+ AtomicUExchange, /// (memory, uint) -> uint
+ AtomicUAdd, /// (memory, uint) -> uint
+ AtomicUMin, /// (memory, uint) -> uint
+ AtomicUMax, /// (memory, uint) -> uint
+ AtomicUAnd, /// (memory, uint) -> uint
+ AtomicUOr, /// (memory, uint) -> uint
+ AtomicUXor, /// (memory, uint) -> uint
+
+ AtomicIExchange, /// (memory, int) -> int
+ AtomicIAdd, /// (memory, int) -> int
+ AtomicIMin, /// (memory, int) -> int
+ AtomicIMax, /// (memory, int) -> int
+ AtomicIAnd, /// (memory, int) -> int
+ AtomicIOr, /// (memory, int) -> int
+ AtomicIXor, /// (memory, int) -> int
Branch, /// (uint branch_target) -> void
BranchIndirect, /// (uint branch_target) -> void
diff --git a/src/video_core/shader/node_helper.cpp b/src/video_core/shader/node_helper.cpp
index 76c56abb5..7bf4ff387 100644
--- a/src/video_core/shader/node_helper.cpp
+++ b/src/video_core/shader/node_helper.cpp
@@ -86,6 +86,20 @@ OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed)
return OperationCode::LogicalUNotEqual;
case OperationCode::LogicalIGreaterEqual:
return OperationCode::LogicalUGreaterEqual;
+ case OperationCode::AtomicIExchange:
+ return OperationCode::AtomicUExchange;
+ case OperationCode::AtomicIAdd:
+ return OperationCode::AtomicUAdd;
+ case OperationCode::AtomicIMin:
+ return OperationCode::AtomicUMin;
+ case OperationCode::AtomicIMax:
+ return OperationCode::AtomicUMax;
+ case OperationCode::AtomicIAnd:
+ return OperationCode::AtomicUAnd;
+ case OperationCode::AtomicIOr:
+ return OperationCode::AtomicUOr;
+ case OperationCode::AtomicIXor:
+ return OperationCode::AtomicUXor;
case OperationCode::INegate:
UNREACHABLE_MSG("Can't negate an unsigned integer");
return {};