summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/engines/shader_bytecode.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp31
-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
6 files changed, 119 insertions, 36 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 49dc5abe0..930b605af 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -231,18 +231,6 @@ enum class AtomicOp : u64 {
231 Or = 6, 231 Or = 6,
232 Xor = 7, 232 Xor = 7,
233 Exch = 8, 233 Exch = 8,
234};
235
236enum class GlobalAtomicOp : u64 {
237 Add = 0,
238 Min = 1,
239 Max = 2,
240 Inc = 3,
241 Dec = 4,
242 And = 5,
243 Or = 6,
244 Xor = 7,
245 Exch = 8,
246 SafeAdd = 10, 234 SafeAdd = 10,
247}; 235};
248 236
@@ -1001,7 +989,7 @@ union Instruction {
1001 } stg; 989 } stg;
1002 990
1003 union { 991 union {
1004 BitField<52, 4, GlobalAtomicOp> operation; 992 BitField<52, 4, AtomicOp> operation;
1005 BitField<49, 3, GlobalAtomicType> type; 993 BitField<49, 3, GlobalAtomicType> type;
1006 BitField<28, 20, s64> offset; 994 BitField<28, 20, s64> offset;
1007 } atom; 995 } atom;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8aa4a7ac9..c7d24cf14 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -2114,6 +2114,10 @@ private:
2114 2114
2115 template <const std::string_view& opname, Type type> 2115 template <const std::string_view& opname, Type type>
2116 Expression Atomic(Operation operation) { 2116 Expression Atomic(Operation operation) {
2117 if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) {
2118 UNIMPLEMENTED_MSG("Unimplemented Min & Max for atomic operations");
2119 return {};
2120 }
2117 return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), 2121 return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(),
2118 Visit(operation[1]).As(type)), 2122 Visit(operation[1]).As(type)),
2119 type}; 2123 type};
@@ -2307,6 +2311,8 @@ private:
2307 ~Func() = delete; 2311 ~Func() = delete;
2308 2312
2309 static constexpr std::string_view Add = "Add"; 2313 static constexpr std::string_view Add = "Add";
2314 static constexpr std::string_view Min = "Min";
2315 static constexpr std::string_view Max = "Max";
2310 static constexpr std::string_view And = "And"; 2316 static constexpr std::string_view And = "And";
2311 static constexpr std::string_view Or = "Or"; 2317 static constexpr std::string_view Or = "Or";
2312 static constexpr std::string_view Xor = "Xor"; 2318 static constexpr std::string_view Xor = "Xor";
@@ -2457,7 +2463,21 @@ private:
2457 &GLSLDecompiler::AtomicImage<Func::Xor>, 2463 &GLSLDecompiler::AtomicImage<Func::Xor>,
2458 &GLSLDecompiler::AtomicImage<Func::Exchange>, 2464 &GLSLDecompiler::AtomicImage<Func::Exchange>,
2459 2465
2466 &GLSLDecompiler::Atomic<Func::Exchange, Type::Uint>,
2460 &GLSLDecompiler::Atomic<Func::Add, Type::Uint>, 2467 &GLSLDecompiler::Atomic<Func::Add, Type::Uint>,
2468 &GLSLDecompiler::Atomic<Func::Min, Type::Uint>,
2469 &GLSLDecompiler::Atomic<Func::Max, Type::Uint>,
2470 &GLSLDecompiler::Atomic<Func::And, Type::Uint>,
2471 &GLSLDecompiler::Atomic<Func::Or, Type::Uint>,
2472 &GLSLDecompiler::Atomic<Func::Xor, Type::Uint>,
2473
2474 &GLSLDecompiler::Atomic<Func::Exchange, Type::Int>,
2475 &GLSLDecompiler::Atomic<Func::Add, Type::Int>,
2476 &GLSLDecompiler::Atomic<Func::Min, Type::Int>,
2477 &GLSLDecompiler::Atomic<Func::Max, Type::Int>,
2478 &GLSLDecompiler::Atomic<Func::And, Type::Int>,
2479 &GLSLDecompiler::Atomic<Func::Or, Type::Int>,
2480 &GLSLDecompiler::Atomic<Func::Xor, Type::Int>,
2461 2481
2462 &GLSLDecompiler::Branch, 2482 &GLSLDecompiler::Branch,
2463 &GLSLDecompiler::BranchIndirect, 2483 &GLSLDecompiler::BranchIndirect,
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 51ecb5567..d67f08cf9 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1941,7 +1941,11 @@ private:
1941 return {}; 1941 return {};
1942 } 1942 }
1943 1943
1944 Expression AtomicAdd(Operation operation) { 1944 template <Id (Module::*func)(Id, Id, Id, Id, Id), Type result_type,
1945 Type value_type = result_type>
1946 Expression Atomic(Operation operation) {
1947 const Id type_def = GetTypeDefinition(result_type);
1948
1945 Id pointer; 1949 Id pointer;
1946 if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { 1950 if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
1947 pointer = GetSharedMemoryPointer(*smem); 1951 pointer = GetSharedMemoryPointer(*smem);
@@ -1949,14 +1953,15 @@ private:
1949 pointer = GetGlobalMemoryPointer(*gmem); 1953 pointer = GetGlobalMemoryPointer(*gmem);
1950 } else { 1954 } else {
1951 UNREACHABLE(); 1955 UNREACHABLE();
1952 return {Constant(t_uint, 0), Type::Uint}; 1956 return {Constant(type_def, 0), result_type};
1953 } 1957 }
1954 1958
1959 const Id value = As(Visit(operation[1]), value_type);
1960
1955 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); 1961 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device));
1956 const Id semantics = Constant(t_uint, 0U); 1962 const Id semantics = Constant(type_def, 0);
1957 1963
1958 const Id value = AsUint(Visit(operation[1])); 1964 return {(this->*func)(type_def, pointer, scope, semantics, value), result_type};
1959 return {OpAtomicIAdd(t_uint, pointer, scope, semantics, value), Type::Uint};
1960 } 1965 }
1961 1966
1962 Expression Branch(Operation operation) { 1967 Expression Branch(Operation operation) {
@@ -2545,7 +2550,21 @@ private:
2545 &SPIRVDecompiler::AtomicImageXor, 2550 &SPIRVDecompiler::AtomicImageXor,
2546 &SPIRVDecompiler::AtomicImageExchange, 2551 &SPIRVDecompiler::AtomicImageExchange,
2547 2552
2548 &SPIRVDecompiler::AtomicAdd, 2553 &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Uint>,
2554 &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Uint>,
2555 &SPIRVDecompiler::Atomic<&Module::OpAtomicUMin, Type::Uint>,
2556 &SPIRVDecompiler::Atomic<&Module::OpAtomicUMax, Type::Uint>,
2557 &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Uint>,
2558 &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Uint>,
2559 &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Uint>,
2560
2561 &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Int>,
2562 &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Int>,
2563 &SPIRVDecompiler::Atomic<&Module::OpAtomicSMin, Type::Int>,
2564 &SPIRVDecompiler::Atomic<&Module::OpAtomicSMax, Type::Int>,
2565 &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Int>,
2566 &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Int>,
2567 &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Int>,
2549 2568
2550 &SPIRVDecompiler::Branch, 2569 &SPIRVDecompiler::Branch,
2551 &SPIRVDecompiler::BranchIndirect, 2570 &SPIRVDecompiler::BranchIndirect,
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 {
19using Tegra::Shader::AtomicOp; 19using Tegra::Shader::AtomicOp;
20using Tegra::Shader::AtomicType; 20using Tegra::Shader::AtomicType;
21using Tegra::Shader::Attribute; 21using Tegra::Shader::Attribute;
22using Tegra::Shader::GlobalAtomicOp;
23using Tegra::Shader::GlobalAtomicType; 22using Tegra::Shader::GlobalAtomicType;
24using Tegra::Shader::Instruction; 23using Tegra::Shader::Instruction;
25using Tegra::Shader::OpCode; 24using Tegra::Shader::OpCode;
@@ -28,6 +27,28 @@ using Tegra::Shader::StoreType;
28 27
29namespace { 28namespace {
30 29
30Node GetAtomOperation(AtomicOp op, bool is_signed, Node memory, Node data) {
31 const OperationCode operation_code = [op] {
32 switch (op) {
33 case AtomicOp::Add:
34 return OperationCode::AtomicIAdd;
35 case AtomicOp::Min:
36 return OperationCode::AtomicIMin;
37 case AtomicOp::Max:
38 return OperationCode::AtomicIMax;
39 case AtomicOp::And:
40 return OperationCode::AtomicIAnd;
41 case AtomicOp::Or:
42 return OperationCode::AtomicIOr;
43 case AtomicOp::Xor:
44 return OperationCode::AtomicIXor;
45 case AtomicOp::Exch:
46 return OperationCode::AtomicIExchange;
47 }
48 }();
49 return SignedOperation(operation_code, is_signed, std::move(memory), std::move(data));
50}
51
31bool IsUnaligned(Tegra::Shader::UniformType uniform_type) { 52bool IsUnaligned(Tegra::Shader::UniformType uniform_type) {
32 return uniform_type == Tegra::Shader::UniformType::UnsignedByte || 53 return uniform_type == Tegra::Shader::UniformType::UnsignedByte ||
33 uniform_type == Tegra::Shader::UniformType::UnsignedShort; 54 uniform_type == Tegra::Shader::UniformType::UnsignedShort;
@@ -363,10 +384,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
363 break; 384 break;
364 } 385 }
365 case OpCode::Id::ATOM: { 386 case OpCode::Id::ATOM: {
366 UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}", 387 UNIMPLEMENTED_IF_MSG(instr.atom.operation == AtomicOp::Inc ||
367 static_cast<int>(instr.atom.operation.Value())); 388 instr.atom.operation == AtomicOp::Dec ||
368 UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}", 389 instr.atom.operation == AtomicOp::SafeAdd,
369 static_cast<int>(instr.atom.type.Value())); 390 "operation={}", static_cast<int>(instr.atom.operation.Value()));
391 UNIMPLEMENTED_IF_MSG(instr.atom.type == GlobalAtomicType::S64 ||
392 instr.atom.type == GlobalAtomicType::U64,
393 "type={}", static_cast<int>(instr.atom.type.Value()));
370 394
371 const auto [real_address, base_address, descriptor] = 395 const auto [real_address, base_address, descriptor] =
372 TrackGlobalMemory(bb, instr, true, true); 396 TrackGlobalMemory(bb, instr, true, true);
@@ -375,25 +399,29 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
375 break; 399 break;
376 } 400 }
377 401
402 const bool is_signed =
403 instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
378 Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); 404 Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
379 Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20)); 405 Node value = GetAtomOperation(static_cast<AtomicOp>(instr.atom.operation), is_signed, gmem,
406 GetRegister(instr.gpr20));
380 SetRegister(bb, instr.gpr0, std::move(value)); 407 SetRegister(bb, instr.gpr0, std::move(value));
381 break; 408 break;
382 } 409 }
383 case OpCode::Id::ATOMS: { 410 case OpCode::Id::ATOMS: {
384 UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", 411 UNIMPLEMENTED_IF_MSG(instr.atoms.operation == AtomicOp::Inc ||
385 static_cast<int>(instr.atoms.operation.Value())); 412 instr.atoms.operation == AtomicOp::Dec,
386 UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}", 413 "operation={}", static_cast<int>(instr.atoms.operation.Value()));
387 static_cast<int>(instr.atoms.type.Value())); 414 UNIMPLEMENTED_IF_MSG(instr.atoms.type == AtomicType::S64 ||
388 415 instr.atoms.type == AtomicType::U64,
416 "type={}", static_cast<int>(instr.atoms.type.Value()));
417 const bool is_signed =
418 instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
389 const s32 offset = instr.atoms.GetImmediateOffset(); 419 const s32 offset = instr.atoms.GetImmediateOffset();
390 Node address = GetRegister(instr.gpr8); 420 Node address = GetRegister(instr.gpr8);
391 address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset)); 421 address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset));
392 422 Node value =
393 Node memory = GetSharedMemory(std::move(address)); 423 GetAtomOperation(static_cast<AtomicOp>(instr.atoms.operation), is_signed,
394 Node data = GetRegister(instr.gpr20); 424 GetSharedMemory(std::move(address)), GetRegister(instr.gpr20));
395
396 Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data));
397 SetRegister(bb, instr.gpr0, std::move(value)); 425 SetRegister(bb, instr.gpr0, std::move(value));
398 break; 426 break;
399 } 427 }
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 {
162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void 162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void
163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void 163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
164 164
165 AtomicAdd, /// (memory, {u}int) -> {u}int 165 AtomicUExchange, /// (memory, uint) -> uint
166 AtomicUAdd, /// (memory, uint) -> uint
167 AtomicUMin, /// (memory, uint) -> uint
168 AtomicUMax, /// (memory, uint) -> uint
169 AtomicUAnd, /// (memory, uint) -> uint
170 AtomicUOr, /// (memory, uint) -> uint
171 AtomicUXor, /// (memory, uint) -> uint
172
173 AtomicIExchange, /// (memory, int) -> int
174 AtomicIAdd, /// (memory, int) -> int
175 AtomicIMin, /// (memory, int) -> int
176 AtomicIMax, /// (memory, int) -> int
177 AtomicIAnd, /// (memory, int) -> int
178 AtomicIOr, /// (memory, int) -> int
179 AtomicIXor, /// (memory, int) -> int
166 180
167 Branch, /// (uint branch_target) -> void 181 Branch, /// (uint branch_target) -> void
168 BranchIndirect, /// (uint branch_target) -> void 182 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)
86 return OperationCode::LogicalUNotEqual; 86 return OperationCode::LogicalUNotEqual;
87 case OperationCode::LogicalIGreaterEqual: 87 case OperationCode::LogicalIGreaterEqual:
88 return OperationCode::LogicalUGreaterEqual; 88 return OperationCode::LogicalUGreaterEqual;
89 case OperationCode::AtomicIExchange:
90 return OperationCode::AtomicUExchange;
91 case OperationCode::AtomicIAdd:
92 return OperationCode::AtomicUAdd;
93 case OperationCode::AtomicIMin:
94 return OperationCode::AtomicUMin;
95 case OperationCode::AtomicIMax:
96 return OperationCode::AtomicUMax;
97 case OperationCode::AtomicIAnd:
98 return OperationCode::AtomicUAnd;
99 case OperationCode::AtomicIOr:
100 return OperationCode::AtomicUOr;
101 case OperationCode::AtomicIXor:
102 return OperationCode::AtomicUXor;
89 case OperationCode::INegate: 103 case OperationCode::INegate:
90 UNREACHABLE_MSG("Can't negate an unsigned integer"); 104 UNREACHABLE_MSG("Can't negate an unsigned integer");
91 return {}; 105 return {};