summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-01-25 21:03:02 -0300
committerGravatar ReinUsesLisp2020-01-26 01:54:24 -0300
commitd95d4ac84396973d76985dc96249d4714f58b6a2 (patch)
tree63083efff309ea993e1de84e4b93fd6d348dfce2 /src/video_core/renderer_vulkan
parentMerge pull request #3343 from FearlessTobi/ui-tab (diff)
downloadyuzu-d95d4ac84396973d76985dc96249d4714f58b6a2.tar.gz
yuzu-d95d4ac84396973d76985dc96249d4714f58b6a2.tar.xz
yuzu-d95d4ac84396973d76985dc96249d4714f58b6a2.zip
shader/memory: Implement ATOM.ADD
ATOM operates atomically on global memory. For now only add ATOM.ADD since that's what was found in commercial games. This asserts for ATOM.ADD.S32 (handling the others as unimplemented), although ATOM.ADD.U32 shouldn't be any different. This change forces us to change the default type on SPIR-V storage buffers from float to uint. We could also alias the buffers, but it's simpler for now to just use uint. While we are at it, abstract the code to avoid repetition.
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp66
1 files changed, 33 insertions, 33 deletions
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index b53078721..1ab22251e 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1123,15 +1123,7 @@ private:
1123 } 1123 }
1124 1124
1125 if (const auto gmem = std::get_if<GmemNode>(&*node)) { 1125 if (const auto gmem = std::get_if<GmemNode>(&*node)) {
1126 const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor()); 1126 return {OpLoad(t_uint, GetGlobalMemoryPointer(*gmem)), Type::Uint};
1127 const Id real = AsUint(Visit(gmem->GetRealAddress()));
1128 const Id base = AsUint(Visit(gmem->GetBaseAddress()));
1129
1130 Id offset = OpISub(t_uint, real, base);
1131 offset = OpUDiv(t_uint, offset, Constant(t_uint, 4U));
1132 return {OpLoad(t_float,
1133 OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0U), offset)),
1134 Type::Float};
1135 } 1127 }
1136 1128
1137 if (const auto lmem = std::get_if<LmemNode>(&*node)) { 1129 if (const auto lmem = std::get_if<LmemNode>(&*node)) {
@@ -1142,10 +1134,7 @@ private:
1142 } 1134 }
1143 1135
1144 if (const auto smem = std::get_if<SmemNode>(&*node)) { 1136 if (const auto smem = std::get_if<SmemNode>(&*node)) {
1145 Id address = AsUint(Visit(smem->GetAddress())); 1137 return {OpLoad(t_uint, GetSharedMemoryPointer(*smem)), Type::Uint};
1146 address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
1147 const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address);
1148 return {OpLoad(t_uint, pointer), Type::Uint};
1149 } 1138 }
1150 1139
1151 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { 1140 if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
@@ -1339,20 +1328,10 @@ private:
1339 target = {OpAccessChain(t_prv_float, local_memory, address), Type::Float}; 1328 target = {OpAccessChain(t_prv_float, local_memory, address), Type::Float};
1340 1329
1341 } else if (const auto smem = std::get_if<SmemNode>(&*dest)) { 1330 } else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
1342 ASSERT(stage == ShaderType::Compute); 1331 target = {GetSharedMemoryPointer(*smem), Type::Uint};
1343 Id address = AsUint(Visit(smem->GetAddress()));
1344 address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
1345 target = {OpAccessChain(t_smem_uint, shared_memory, address), Type::Uint};
1346 1332
1347 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { 1333 } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
1348 const Id real = AsUint(Visit(gmem->GetRealAddress())); 1334 target = {GetGlobalMemoryPointer(*gmem), Type::Uint};
1349 const Id base = AsUint(Visit(gmem->GetBaseAddress()));
1350 const Id diff = OpISub(t_uint, real, base);
1351 const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2));
1352
1353 const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor());
1354 target = {OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0), offset),
1355 Type::Float};
1356 1335
1357 } else { 1336 } else {
1358 UNIMPLEMENTED(); 1337 UNIMPLEMENTED();
@@ -1804,11 +1783,16 @@ private:
1804 return {}; 1783 return {};
1805 } 1784 }
1806 1785
1807 Expression UAtomicAdd(Operation operation) { 1786 Expression AtomicAdd(Operation operation) {
1808 const auto& smem = std::get<SmemNode>(*operation[0]); 1787 Id pointer;
1809 Id address = AsUint(Visit(smem.GetAddress())); 1788 if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
1810 address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); 1789 pointer = GetSharedMemoryPointer(*smem);
1811 const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address); 1790 } else if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) {
1791 pointer = GetGlobalMemoryPointer(*gmem);
1792 } else {
1793 UNREACHABLE();
1794 return {Constant(t_uint, 0), Type::Uint};
1795 }
1812 1796
1813 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); 1797 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device));
1814 const Id semantics = Constant(t_uint, 0U); 1798 const Id semantics = Constant(t_uint, 0U);
@@ -2243,6 +2227,22 @@ private:
2243 return {}; 2227 return {};
2244 } 2228 }
2245 2229
2230 Id GetGlobalMemoryPointer(const GmemNode& gmem) {
2231 const Id real = AsUint(Visit(gmem.GetRealAddress()));
2232 const Id base = AsUint(Visit(gmem.GetBaseAddress()));
2233 const Id diff = OpISub(t_uint, real, base);
2234 const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2));
2235 const Id buffer = global_buffers.at(gmem.GetDescriptor());
2236 return OpAccessChain(t_gmem_uint, buffer, Constant(t_uint, 0), offset);
2237 }
2238
2239 Id GetSharedMemoryPointer(const SmemNode& smem) {
2240 ASSERT(stage == ShaderType::Compute);
2241 Id address = AsUint(Visit(smem.GetAddress()));
2242 address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
2243 return OpAccessChain(t_smem_uint, shared_memory, address);
2244 }
2245
2246 static constexpr std::array operation_decompilers = { 2246 static constexpr std::array operation_decompilers = {
2247 &SPIRVDecompiler::Assign, 2247 &SPIRVDecompiler::Assign,
2248 2248
@@ -2389,7 +2389,7 @@ private:
2389 &SPIRVDecompiler::AtomicImageXor, 2389 &SPIRVDecompiler::AtomicImageXor,
2390 &SPIRVDecompiler::AtomicImageExchange, 2390 &SPIRVDecompiler::AtomicImageExchange,
2391 2391
2392 &SPIRVDecompiler::UAtomicAdd, 2392 &SPIRVDecompiler::AtomicAdd,
2393 2393
2394 &SPIRVDecompiler::Branch, 2394 &SPIRVDecompiler::Branch,
2395 &SPIRVDecompiler::BranchIndirect, 2395 &SPIRVDecompiler::BranchIndirect,
@@ -2485,9 +2485,9 @@ private:
2485 2485
2486 Id t_smem_uint{}; 2486 Id t_smem_uint{};
2487 2487
2488 const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float); 2488 const Id t_gmem_uint = TypePointer(spv::StorageClass::StorageBuffer, t_uint);
2489 const Id t_gmem_array = 2489 const Id t_gmem_array =
2490 Name(Decorate(TypeRuntimeArray(t_float), spv::Decoration::ArrayStride, 4U), "GmemArray"); 2490 Name(Decorate(TypeRuntimeArray(t_uint), spv::Decoration::ArrayStride, 4U), "GmemArray");
2491 const Id t_gmem_struct = MemberDecorate( 2491 const Id t_gmem_struct = MemberDecorate(
2492 Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); 2492 Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
2493 const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); 2493 const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct);