Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 1 | // Copyright 2019 The SwiftShader Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #include "SpirvShader.hpp" |
Ben Clayton | fc951cd | 2019-05-15 17:16:56 +0100 | [diff] [blame] | 16 | #include "SpirvShaderDebug.hpp" |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 17 | |
| 18 | #include "ShaderCore.hpp" |
Nicolas Capens | 9e727fa | 2021-11-22 12:06:33 -0500 | [diff] [blame] | 19 | #include "Reactor/Assert.hpp" |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 20 | #include "Vulkan/VkPipelineLayout.hpp" |
| 21 | |
| 22 | #include <spirv/unified1/spirv.hpp> |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 23 | |
| 24 | namespace sw { |
| 25 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 26 | void SpirvEmitter::EmitLoad(InsnIterator insn) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 27 | { |
| 28 | bool atomic = (insn.opcode() == spv::OpAtomicLoad); |
| 29 | Object::ID resultId = insn.word(2); |
| 30 | Object::ID pointerId = insn.word(3); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 31 | auto &result = shader.getObject(resultId); |
| 32 | auto &resultTy = shader.getType(result); |
| 33 | auto &pointer = shader.getObject(pointerId); |
| 34 | auto &pointerTy = shader.getType(pointer); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 35 | std::memory_order memoryOrder = std::memory_order_relaxed; |
| 36 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 37 | ASSERT(shader.getType(pointer).element == result.typeId()); |
Nicolas Capens | 72f089c | 2020-04-08 23:37:08 -0400 | [diff] [blame] | 38 | ASSERT(Type::ID(insn.word(1)) == result.typeId()); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 39 | ASSERT(!atomic || shader.getType(shader.getType(pointer).element).opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer." |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 40 | |
| 41 | if(pointerTy.storageClass == spv::StorageClassUniformConstant) |
| 42 | { |
| 43 | // Just propagate the pointer. |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 44 | auto &ptr = getPointer(pointerId); |
| 45 | createPointer(resultId, ptr); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | if(atomic) |
| 49 | { |
| 50 | Object::ID semanticsId = insn.word(5); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 51 | auto memorySemantics = static_cast<spv::MemorySemanticsMask>(shader.getObject(semanticsId).constantValue[0]); |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 52 | memoryOrder = shader.MemoryOrder(memorySemantics); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 53 | } |
| 54 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 55 | auto ptr = GetPointerToData(pointerId, 0, false); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 56 | auto robustness = shader.getOutOfBoundsBehavior(pointerId, routine->pipelineLayout); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 57 | |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 58 | if(result.kind == Object::Kind::Pointer) |
| 59 | { |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 60 | shader.VisitMemoryObject(pointerId, true, [&](const Spirv::MemoryElement &el) { |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 61 | ASSERT(el.index == 0); |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 62 | auto p = GetElementPointer(ptr, el.offset, pointerTy.storageClass); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 63 | createPointer(resultId, p.Load<SIMD::Pointer>(robustness, activeLaneMask(), atomic, memoryOrder, sizeof(void *))); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 64 | }); |
Alexis Hetu | ec31f54 | 2022-06-22 16:47:48 -0400 | [diff] [blame] | 65 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 66 | SPIRV_SHADER_DBG("Load(atomic: {0}, order: {1}, ptr: {2}, mask: {3})", atomic, int(memoryOrder), ptr, activeLaneMask()); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 67 | } |
| 68 | else |
| 69 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 70 | auto &dst = createIntermediate(resultId, resultTy.componentCount); |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 71 | shader.VisitMemoryObject(pointerId, false, [&](const Spirv::MemoryElement &el) { |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 72 | auto p = GetElementPointer(ptr, el.offset, pointerTy.storageClass); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 73 | dst.move(el.index, p.Load<SIMD::Float>(robustness, activeLaneMask(), atomic, memoryOrder)); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 74 | }); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 75 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 76 | SPIRV_SHADER_DBG("Load(atomic: {0}, order: {1}, ptr: {2}, val: {3}, mask: {4})", atomic, int(memoryOrder), ptr, dst, activeLaneMask()); |
Alexis Hetu | ec31f54 | 2022-06-22 16:47:48 -0400 | [diff] [blame] | 77 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 78 | } |
| 79 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 80 | void SpirvEmitter::EmitStore(InsnIterator insn) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 81 | { |
| 82 | bool atomic = (insn.opcode() == spv::OpAtomicStore); |
| 83 | Object::ID pointerId = insn.word(1); |
| 84 | Object::ID objectId = insn.word(atomic ? 4 : 2); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 85 | std::memory_order memoryOrder = std::memory_order_relaxed; |
| 86 | |
| 87 | if(atomic) |
| 88 | { |
| 89 | Object::ID semanticsId = insn.word(3); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 90 | auto memorySemantics = static_cast<spv::MemorySemanticsMask>(shader.getObject(semanticsId).constantValue[0]); |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 91 | memoryOrder = shader.MemoryOrder(memorySemantics); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 92 | } |
| 93 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 94 | const auto &value = Operand(shader, *this, objectId); |
Nicolas Capens | 0b77aa5 | 2020-04-09 02:48:16 -0400 | [diff] [blame] | 95 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 96 | Store(pointerId, value, atomic, memoryOrder); |
Nicolas Capens | 0b77aa5 | 2020-04-09 02:48:16 -0400 | [diff] [blame] | 97 | } |
| 98 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 99 | void SpirvEmitter::Store(Object::ID pointerId, const Operand &value, bool atomic, std::memory_order memoryOrder) const |
Nicolas Capens | 0b77aa5 | 2020-04-09 02:48:16 -0400 | [diff] [blame] | 100 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 101 | auto &pointer = shader.getObject(pointerId); |
| 102 | auto &pointerTy = shader.getType(pointer); |
| 103 | auto &elementTy = shader.getType(pointerTy.element); |
Nicolas Capens | 0b77aa5 | 2020-04-09 02:48:16 -0400 | [diff] [blame] | 104 | |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 105 | ASSERT(!atomic || elementTy.opcode() == spv::OpTypeInt); // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer." |
| 106 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 107 | auto ptr = GetPointerToData(pointerId, 0, false); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 108 | auto robustness = shader.getOutOfBoundsBehavior(pointerId, routine->pipelineLayout); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 109 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 110 | SIMD::Int mask = activeLaneMask(); |
Nicolas Capens | 3a82d57 | 2022-10-22 21:50:25 -0400 | [diff] [blame] | 111 | if(shader.StoresInHelperInvocationsHaveNoEffect(pointerTy.storageClass)) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 112 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 113 | mask = mask & storesAndAtomicsMask(); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 114 | } |
| 115 | |
Ben Clayton | fc951cd | 2019-05-15 17:16:56 +0100 | [diff] [blame] | 116 | SPIRV_SHADER_DBG("Store(atomic: {0}, order: {1}, ptr: {2}, val: {3}, mask: {4}", atomic, int(memoryOrder), ptr, value, mask); |
| 117 | |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 118 | if(value.isPointer()) |
| 119 | { |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 120 | shader.VisitMemoryObject(pointerId, true, [&](const Spirv::MemoryElement &el) { |
Nicolas Capens | 08dfcbb | 2022-09-02 14:32:12 -0400 | [diff] [blame] | 121 | ASSERT(el.index == 0); |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 122 | auto p = GetElementPointer(ptr, el.offset, pointerTy.storageClass); |
Nicolas Capens | 08dfcbb | 2022-09-02 14:32:12 -0400 | [diff] [blame] | 123 | p.Store(value.Pointer(), robustness, mask, atomic, memoryOrder); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 124 | }); |
| 125 | } |
| 126 | else |
| 127 | { |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 128 | shader.VisitMemoryObject(pointerId, false, [&](const Spirv::MemoryElement &el) { |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 129 | auto p = GetElementPointer(ptr, el.offset, pointerTy.storageClass); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 130 | p.Store(value.Float(el.index), robustness, mask, atomic, memoryOrder); |
| 131 | }); |
| 132 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 133 | } |
| 134 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 135 | void SpirvEmitter::EmitVariable(InsnIterator insn) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 136 | { |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 137 | Object::ID resultId = insn.word(2); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 138 | auto &object = shader.getObject(resultId); |
| 139 | auto &objectTy = shader.getType(object); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 140 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 141 | switch(objectTy.storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 142 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 143 | case spv::StorageClassOutput: |
| 144 | case spv::StorageClassPrivate: |
| 145 | case spv::StorageClassFunction: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 146 | { |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 147 | ASSERT(objectTy.opcode() == spv::OpTypePointer); |
| 148 | auto base = &routine->getVariable(resultId)[0]; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 149 | auto elementTy = shader.getType(objectTy.element); |
Nicolas Capens | ff9f9b5 | 2020-04-14 00:46:38 -0400 | [diff] [blame] | 150 | auto size = elementTy.componentCount * static_cast<uint32_t>(sizeof(float)) * SIMD::Width; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 151 | createPointer(resultId, SIMD::Pointer(base, size)); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 152 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 153 | break; |
| 154 | case spv::StorageClassWorkgroup: |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 155 | { |
| 156 | ASSERT(objectTy.opcode() == spv::OpTypePointer); |
| 157 | auto base = &routine->workgroupMemory[0]; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 158 | auto size = shader.workgroupMemory.size(); |
| 159 | createPointer(resultId, SIMD::Pointer(base, size, shader.workgroupMemory.offsetOf(resultId))); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 160 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 161 | break; |
| 162 | case spv::StorageClassInput: |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 163 | { |
| 164 | if(object.kind == Object::Kind::InterfaceVariable) |
| 165 | { |
| 166 | auto &dst = routine->getVariable(resultId); |
| 167 | int offset = 0; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 168 | shader.VisitInterface(resultId, |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 169 | [&](const Decorations &d, Spirv::AttribType type) { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 170 | auto scalarSlot = d.Location << 2 | d.Component; |
| 171 | dst[offset++] = routine->inputs[scalarSlot]; |
| 172 | }); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 173 | } |
| 174 | ASSERT(objectTy.opcode() == spv::OpTypePointer); |
| 175 | auto base = &routine->getVariable(resultId)[0]; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 176 | auto elementTy = shader.getType(objectTy.element); |
Nicolas Capens | ff9f9b5 | 2020-04-14 00:46:38 -0400 | [diff] [blame] | 177 | auto size = elementTy.componentCount * static_cast<uint32_t>(sizeof(float)) * SIMD::Width; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 178 | createPointer(resultId, SIMD::Pointer(base, size)); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 179 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 180 | break; |
| 181 | case spv::StorageClassUniformConstant: |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 182 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 183 | const auto &d = shader.descriptorDecorations.at(resultId); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 184 | ASSERT(d.DescriptorSet >= 0); |
| 185 | ASSERT(d.Binding >= 0); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 186 | |
Nicolas Capens | c7d5ec3 | 2020-04-22 01:11:37 -0400 | [diff] [blame] | 187 | uint32_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding); |
Nicolas Capens | ca9de96 | 2020-04-23 00:42:39 -0400 | [diff] [blame] | 188 | Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet* |
| 189 | Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // vk::SampledImageDescriptor* |
| 190 | auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write. |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 191 | createPointer(resultId, SIMD::Pointer(binding, size)); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 192 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 193 | break; |
| 194 | case spv::StorageClassUniform: |
| 195 | case spv::StorageClassStorageBuffer: |
Alexis Hetu | 71ec98e | 2022-06-14 16:58:44 -0400 | [diff] [blame] | 196 | case spv::StorageClassPhysicalStorageBuffer: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 197 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 198 | const auto &d = shader.descriptorDecorations.at(resultId); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 199 | ASSERT(d.DescriptorSet >= 0); |
| 200 | auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write. |
| 201 | // Note: the module may contain descriptor set references that are not suitable for this implementation -- using a set index higher than the number |
| 202 | // of descriptor set binding points we support. As long as the selected entrypoint doesn't actually touch the out of range binding points, this |
| 203 | // is valid. In this case make the value nullptr to make it easier to diagnose an attempt to dereference it. |
Nicolas Capens | b7b7cb7 | 2021-09-29 14:02:53 -0400 | [diff] [blame] | 204 | if(static_cast<uint32_t>(d.DescriptorSet) < vk::MAX_BOUND_DESCRIPTOR_SETS) |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 205 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 206 | createPointer(resultId, SIMD::Pointer(routine->descriptorSets[d.DescriptorSet], size)); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 207 | } |
| 208 | else |
| 209 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 210 | createPointer(resultId, SIMD::Pointer(nullptr, 0)); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 211 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 212 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 213 | break; |
| 214 | case spv::StorageClassPushConstant: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 215 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 216 | createPointer(resultId, SIMD::Pointer(routine->pushConstants, vk::MAX_PUSH_CONSTANT_SIZE)); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 217 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 218 | break; |
| 219 | default: |
| 220 | UNREACHABLE("Storage class %d", objectTy.storageClass); |
| 221 | break; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 222 | } |
| 223 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 224 | if(insn.wordCount() > 4) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 225 | { |
| 226 | Object::ID initializerId = insn.word(4); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 227 | if(shader.getObject(initializerId).kind != Object::Kind::Constant) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 228 | { |
Nicolas Capens | dd0e600 | 2020-01-24 01:21:47 -0500 | [diff] [blame] | 229 | UNIMPLEMENTED("b/148241854: Non-constant initializers not yet implemented"); // FIXME(b/148241854) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 230 | } |
Nicolas Capens | 44bd43a | 2020-01-22 03:07:14 -0500 | [diff] [blame] | 231 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 232 | switch(objectTy.storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 233 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 234 | case spv::StorageClassOutput: |
| 235 | case spv::StorageClassPrivate: |
| 236 | case spv::StorageClassFunction: |
Alexis Hetu | 7021c48 | 2021-10-27 18:29:54 -0400 | [diff] [blame] | 237 | case spv::StorageClassWorkgroup: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 238 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 239 | auto ptr = GetPointerToData(resultId, 0, false); |
| 240 | Operand initialValue(shader, *this, initializerId); |
| 241 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 242 | shader.VisitMemoryObject(resultId, false, [&](const Spirv::MemoryElement &el) { |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 243 | auto p = GetElementPointer(ptr, el.offset, objectTy.storageClass); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 244 | auto robustness = OutOfBoundsBehavior::UndefinedBehavior; // Local variables are always within bounds. |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 245 | p.Store(initialValue.Float(el.index), robustness, activeLaneMask()); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 246 | }); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 247 | |
Alexis Hetu | 7021c48 | 2021-10-27 18:29:54 -0400 | [diff] [blame] | 248 | if(objectTy.storageClass == spv::StorageClassWorkgroup) |
| 249 | { |
| 250 | // Initialization of workgroup memory is done by each subgroup and requires waiting on a barrier. |
| 251 | // TODO(b/221242292): Initialize just once per workgroup and eliminate the barrier. |
| 252 | Yield(YieldResult::ControlBarrier); |
| 253 | } |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 254 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 255 | break; |
| 256 | default: |
| 257 | ASSERT_MSG(initializerId == 0, "Vulkan does not permit variables of storage class %d to have initializers", int(objectTy.storageClass)); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 258 | } |
| 259 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 260 | } |
| 261 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 262 | void SpirvEmitter::EmitCopyMemory(InsnIterator insn) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 263 | { |
| 264 | Object::ID dstPtrId = insn.word(1); |
| 265 | Object::ID srcPtrId = insn.word(2); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 266 | auto &dstPtrTy = shader.getObjectType(dstPtrId); |
| 267 | auto &srcPtrTy = shader.getObjectType(srcPtrId); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 268 | ASSERT(dstPtrTy.element == srcPtrTy.element); |
| 269 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 270 | auto dstPtr = GetPointerToData(dstPtrId, 0, false); |
| 271 | auto srcPtr = GetPointerToData(srcPtrId, 0, false); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 272 | |
| 273 | std::unordered_map<uint32_t, uint32_t> srcOffsets; |
| 274 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 275 | shader.VisitMemoryObject(srcPtrId, false, [&](const Spirv::MemoryElement &el) { srcOffsets[el.index] = el.offset; }); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 276 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 277 | shader.VisitMemoryObject(dstPtrId, false, [&](const Spirv::MemoryElement &el) { |
Ben Clayton | 18c6a78 | 2019-12-03 12:08:16 +0000 | [diff] [blame] | 278 | auto it = srcOffsets.find(el.index); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 279 | ASSERT(it != srcOffsets.end()); |
| 280 | auto srcOffset = it->second; |
Ben Clayton | 18c6a78 | 2019-12-03 12:08:16 +0000 | [diff] [blame] | 281 | auto dstOffset = el.offset; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 282 | |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 283 | auto dst = GetElementPointer(dstPtr, dstOffset, dstPtrTy.storageClass); |
| 284 | auto src = GetElementPointer(srcPtr, srcOffset, srcPtrTy.storageClass); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 285 | |
| 286 | // TODO(b/131224163): Optimize based on src/dst storage classes. |
| 287 | auto robustness = OutOfBoundsBehavior::RobustBufferAccess; |
| 288 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 289 | auto value = src.Load<SIMD::Float>(robustness, activeLaneMask()); |
| 290 | dst.Store(value, robustness, activeLaneMask()); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 291 | }); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 292 | } |
| 293 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 294 | void SpirvEmitter::EmitMemoryBarrier(InsnIterator insn) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 295 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 296 | auto semantics = spv::MemorySemanticsMask(shader.GetConstScalarInt(insn.word(2))); |
Nicolas Capens | 4c62980 | 2021-12-08 02:05:19 -0500 | [diff] [blame] | 297 | // TODO(b/176819536): We probably want to consider the memory scope here. |
| 298 | // For now, just always emit the full fence. |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 299 | Fence(semantics); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 300 | } |
| 301 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 302 | void Spirv::VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, bool resultIsPointer, const MemoryVisitor &f) const |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 303 | { |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 304 | ApplyDecorationsForId(&d, id); |
Shahbaz Youssefi | 4dbbcd0 | 2022-09-13 22:23:30 -0400 | [diff] [blame] | 305 | const auto &type = getType(id); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 306 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 307 | if(d.HasOffset) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 308 | { |
| 309 | offset += d.Offset; |
| 310 | d.HasOffset = false; |
| 311 | } |
| 312 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 313 | switch(type.opcode()) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 314 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 315 | case spv::OpTypePointer: |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 316 | if(resultIsPointer) |
| 317 | { |
| 318 | // Load/Store the pointer itself, rather than the structure pointed to by the pointer |
| 319 | f(MemoryElement{ index++, offset, type }); |
| 320 | } |
| 321 | else |
| 322 | { |
| 323 | VisitMemoryObjectInner(type.definition.word(3), d, index, offset, resultIsPointer, f); |
| 324 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 325 | break; |
| 326 | case spv::OpTypeInt: |
| 327 | case spv::OpTypeFloat: |
| 328 | case spv::OpTypeRuntimeArray: |
| 329 | f(MemoryElement{ index++, offset, type }); |
| 330 | break; |
| 331 | case spv::OpTypeVector: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 332 | { |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 333 | auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float)); |
| 334 | for(auto i = 0u; i < type.definition.word(3); i++) |
| 335 | { |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 336 | VisitMemoryObjectInner(type.definition.word(2), d, index, offset + elemStride * i, resultIsPointer, f); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 337 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 338 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 339 | break; |
| 340 | case spv::OpTypeMatrix: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 341 | { |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 342 | auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride; |
| 343 | d.InsideMatrix = true; |
| 344 | for(auto i = 0u; i < type.definition.word(3); i++) |
| 345 | { |
| 346 | ASSERT(d.HasMatrixStride); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 347 | VisitMemoryObjectInner(type.definition.word(2), d, index, offset + columnStride * i, resultIsPointer, f); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 348 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 349 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 350 | break; |
| 351 | case spv::OpTypeStruct: |
| 352 | for(auto i = 0u; i < type.definition.wordCount() - 2; i++) |
| 353 | { |
| 354 | ApplyDecorationsForIdMember(&d, id, i); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 355 | VisitMemoryObjectInner(type.definition.word(i + 2), d, index, offset, resultIsPointer, f); |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 356 | } |
| 357 | break; |
| 358 | case spv::OpTypeArray: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 359 | { |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 360 | auto arraySize = GetConstScalarInt(type.definition.word(3)); |
| 361 | for(auto i = 0u; i < arraySize; i++) |
| 362 | { |
| 363 | ASSERT(d.HasArrayStride); |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 364 | VisitMemoryObjectInner(type.definition.word(2), d, index, offset + i * d.ArrayStride, resultIsPointer, f); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 365 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 366 | } |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 367 | break; |
| 368 | default: |
| 369 | UNREACHABLE("%s", OpcodeName(type.opcode())); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 370 | } |
| 371 | } |
| 372 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 373 | void Spirv::VisitMemoryObject(Object::ID id, bool resultIsPointer, const MemoryVisitor &f) const |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 374 | { |
Nicolas Capens | 72f089c | 2020-04-08 23:37:08 -0400 | [diff] [blame] | 375 | auto typeId = getObject(id).typeId(); |
Shahbaz Youssefi | 4dbbcd0 | 2022-09-13 22:23:30 -0400 | [diff] [blame] | 376 | const auto &type = getType(typeId); |
Nicolas Capens | 72f089c | 2020-04-08 23:37:08 -0400 | [diff] [blame] | 377 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 378 | if(IsExplicitLayout(type.storageClass)) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 379 | { |
Nicolas Capens | d6806b3 | 2022-03-02 10:16:31 -0500 | [diff] [blame] | 380 | Decorations d = GetDecorationsForId(id); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 381 | uint32_t index = 0; |
Alexis Hetu | da978d8 | 2022-06-14 17:51:58 -0400 | [diff] [blame] | 382 | VisitMemoryObjectInner(typeId, d, index, 0, resultIsPointer, f); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 383 | } |
| 384 | else |
| 385 | { |
| 386 | // Objects without explicit layout are tightly packed. |
Ben Clayton | 18c6a78 | 2019-12-03 12:08:16 +0000 | [diff] [blame] | 387 | auto &elType = getType(type.element); |
Nicolas Capens | ff9f9b5 | 2020-04-14 00:46:38 -0400 | [diff] [blame] | 388 | for(auto index = 0u; index < elType.componentCount; index++) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 389 | { |
Ben Clayton | 18c6a78 | 2019-12-03 12:08:16 +0000 | [diff] [blame] | 390 | auto offset = static_cast<uint32_t>(index * sizeof(float)); |
Ben Clayton | bc1c067be | 2019-12-17 20:37:37 +0000 | [diff] [blame] | 391 | f({ index, offset, elType }); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 392 | } |
| 393 | } |
| 394 | } |
| 395 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 396 | SIMD::Pointer SpirvEmitter::GetPointerToData(Object::ID id, SIMD::Int arrayIndices, bool nonUniform) const |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 397 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 398 | auto &object = shader.getObject(id); |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 399 | switch(object.kind) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 400 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 401 | case Object::Kind::Pointer: |
| 402 | case Object::Kind::InterfaceVariable: |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 403 | return getPointer(id); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 404 | |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 405 | case Object::Kind::DescriptorSet: |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 406 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 407 | const auto &d = shader.descriptorDecorations.at(id); |
Nicolas Capens | b7b7cb7 | 2021-09-29 14:02:53 -0400 | [diff] [blame] | 408 | ASSERT(d.DescriptorSet >= 0 && static_cast<uint32_t>(d.DescriptorSet) < vk::MAX_BOUND_DESCRIPTOR_SETS); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 409 | ASSERT(d.Binding >= 0); |
Nicolas Capens | eb68244 | 2020-06-01 15:24:52 -0400 | [diff] [blame] | 410 | ASSERT(routine->pipelineLayout->getDescriptorCount(d.DescriptorSet, d.Binding) != 0); // "If descriptorCount is zero this binding entry is reserved and the resource must not be accessed from any stage via this binding within any pipeline using the set layout." |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 411 | |
Nicolas Capens | c7d5ec3 | 2020-04-22 01:11:37 -0400 | [diff] [blame] | 412 | uint32_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding); |
| 413 | uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding); |
Nicolas Capens | c7d5ec3 | 2020-04-22 01:11:37 -0400 | [diff] [blame] | 414 | |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 415 | auto set = getPointer(id); |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 416 | if(nonUniform) |
| 417 | { |
| 418 | SIMD::Int descriptorOffset = bindingOffset + descriptorSize * arrayIndices; |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 419 | auto robustness = shader.getOutOfBoundsBehavior(id, routine->pipelineLayout); |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 420 | ASSERT(routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding) != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT); |
Nicolas Capens | c7d5ec3 | 2020-04-22 01:11:37 -0400 | [diff] [blame] | 421 | |
Nicolas Capens | 942c639 | 2022-06-30 00:20:40 -0400 | [diff] [blame] | 422 | std::vector<Pointer<Byte>> pointers(SIMD::Width); |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 423 | for(int i = 0; i < SIMD::Width; i++) |
| 424 | { |
| 425 | pointers[i] = *Pointer<Pointer<Byte>>(set.getPointerForLane(i) + Extract(descriptorOffset, i) + OFFSET(vk::BufferDescriptor, ptr)); |
| 426 | } |
| 427 | |
| 428 | SIMD::Pointer ptr(pointers); |
Alexis Hetu | 8941bde | 2021-11-17 17:45:40 -0500 | [diff] [blame] | 429 | |
| 430 | if(routine->pipelineLayout->isDescriptorDynamic(d.DescriptorSet, d.Binding)) |
| 431 | { |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 432 | SIMD::Int dynamicOffsetIndex = SIMD::Int(routine->pipelineLayout->getDynamicOffsetIndex(d.DescriptorSet, d.Binding) + arrayIndices); |
| 433 | SIMD::Pointer routineDynamicOffsets = SIMD::Pointer(routine->descriptorDynamicOffsets, 0, sizeof(int) * dynamicOffsetIndex); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 434 | SIMD::Int dynamicOffsets = routineDynamicOffsets.Load<SIMD::Int>(robustness, activeLaneMask()); |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 435 | ptr += dynamicOffsets; |
| 436 | } |
| 437 | return ptr; |
| 438 | } |
| 439 | else |
| 440 | { |
| 441 | rr::Int arrayIdx = Extract(arrayIndices, 0); |
| 442 | rr::Int descriptorOffset = bindingOffset + descriptorSize * arrayIdx; |
| 443 | Pointer<Byte> descriptor = set.getUniformPointer() + descriptorOffset; // BufferDescriptor* or inline uniform block |
Alexis Hetu | 8941bde | 2021-11-17 17:45:40 -0500 | [diff] [blame] | 444 | |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 445 | auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding); |
| 446 | if(descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) |
| 447 | { |
| 448 | // Note: there is no bounds checking for inline uniform blocks. |
| 449 | // MAX_INLINE_UNIFORM_BLOCK_SIZE represents the maximum size of |
| 450 | // an inline uniform block, but this value should remain unused. |
| 451 | return SIMD::Pointer(descriptor, vk::MAX_INLINE_UNIFORM_BLOCK_SIZE); |
Alexis Hetu | 8941bde | 2021-11-17 17:45:40 -0500 | [diff] [blame] | 452 | } |
| 453 | else |
| 454 | { |
Sean Risser | da08cb2 | 2022-04-08 20:49:06 -0400 | [diff] [blame] | 455 | Pointer<Byte> data = *Pointer<Pointer<Byte>>(descriptor + OFFSET(vk::BufferDescriptor, ptr)); // void* |
| 456 | rr::Int size = *Pointer<Int>(descriptor + OFFSET(vk::BufferDescriptor, sizeInBytes)); |
| 457 | |
| 458 | if(routine->pipelineLayout->isDescriptorDynamic(d.DescriptorSet, d.Binding)) |
| 459 | { |
| 460 | rr::Int dynamicOffsetIndex = |
| 461 | routine->pipelineLayout->getDynamicOffsetIndex(d.DescriptorSet, d.Binding) + |
| 462 | arrayIdx; |
| 463 | rr::Int offset = routine->descriptorDynamicOffsets[dynamicOffsetIndex]; |
| 464 | rr::Int robustnessSize = *Pointer<rr::Int>(descriptor + OFFSET(vk::BufferDescriptor, robustnessSize)); |
| 465 | |
| 466 | return SIMD::Pointer(data + offset, Min(size, robustnessSize - offset)); |
| 467 | } |
| 468 | else |
| 469 | { |
| 470 | return SIMD::Pointer(data, size); |
| 471 | } |
Alexis Hetu | 8941bde | 2021-11-17 17:45:40 -0500 | [diff] [blame] | 472 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 473 | } |
| 474 | } |
| 475 | |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 476 | default: |
| 477 | UNREACHABLE("Invalid pointer kind %d", int(object.kind)); |
| 478 | return SIMD::Pointer(Pointer<Byte>(), 0); |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 479 | } |
| 480 | } |
| 481 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 482 | void SpirvEmitter::OffsetToElement(SIMD::Pointer &ptr, Object::ID elementId, int32_t arrayStride) const |
Alexis Hetu | 47c2246 | 2022-06-06 18:00:16 -0400 | [diff] [blame] | 483 | { |
| 484 | if(elementId != 0 && arrayStride != 0) |
| 485 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 486 | auto &elementObject = shader.getObject(elementId); |
Alexis Hetu | 47c2246 | 2022-06-06 18:00:16 -0400 | [diff] [blame] | 487 | ASSERT(elementObject.kind == Object::Kind::Constant || elementObject.kind == Object::Kind::Intermediate); |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 488 | |
Alexis Hetu | 47c2246 | 2022-06-06 18:00:16 -0400 | [diff] [blame] | 489 | if(elementObject.kind == Object::Kind::Constant) |
| 490 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 491 | ptr += shader.GetConstScalarInt(elementId) * arrayStride; |
Alexis Hetu | 47c2246 | 2022-06-06 18:00:16 -0400 | [diff] [blame] | 492 | } |
| 493 | else |
| 494 | { |
Nicolas Capens | e1b8cbd | 2022-09-12 09:13:06 -0400 | [diff] [blame] | 495 | ptr += getIntermediate(elementId).Int(0) * arrayStride; |
Alexis Hetu | 47c2246 | 2022-06-06 18:00:16 -0400 | [diff] [blame] | 496 | } |
| 497 | } |
| 498 | } |
| 499 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 500 | void SpirvEmitter::Fence(spv::MemorySemanticsMask semantics) const |
Nicolas Capens | 4c62980 | 2021-12-08 02:05:19 -0500 | [diff] [blame] | 501 | { |
| 502 | if(semantics != spv::MemorySemanticsMaskNone) |
| 503 | { |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 504 | rr::Fence(shader.MemoryOrder(semantics)); |
Nicolas Capens | 4c62980 | 2021-12-08 02:05:19 -0500 | [diff] [blame] | 505 | } |
| 506 | } |
| 507 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 508 | std::memory_order Spirv::MemoryOrder(spv::MemorySemanticsMask memorySemantics) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 509 | { |
Nicolas Capens | 4c62980 | 2021-12-08 02:05:19 -0500 | [diff] [blame] | 510 | uint32_t control = static_cast<uint32_t>(memorySemantics) & static_cast<uint32_t>( |
| 511 | spv::MemorySemanticsAcquireMask | |
| 512 | spv::MemorySemanticsReleaseMask | |
| 513 | spv::MemorySemanticsAcquireReleaseMask | |
| 514 | spv::MemorySemanticsSequentiallyConsistentMask); |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 515 | switch(control) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 516 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 517 | case spv::MemorySemanticsMaskNone: return std::memory_order_relaxed; |
| 518 | case spv::MemorySemanticsAcquireMask: return std::memory_order_acquire; |
| 519 | case spv::MemorySemanticsReleaseMask: return std::memory_order_release; |
| 520 | case spv::MemorySemanticsAcquireReleaseMask: return std::memory_order_acq_rel; |
| 521 | case spv::MemorySemanticsSequentiallyConsistentMask: return std::memory_order_acq_rel; // Vulkan 1.1: "SequentiallyConsistent is treated as AcquireRelease" |
| 522 | default: |
| 523 | // "it is invalid for more than one of these four bits to be set: |
Nicolas Capens | 4c62980 | 2021-12-08 02:05:19 -0500 | [diff] [blame] | 524 | // Acquire, Release, AcquireRelease, or SequentiallyConsistent." |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 525 | UNREACHABLE("MemorySemanticsMask: %x", int(control)); |
| 526 | return std::memory_order_acq_rel; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 527 | } |
| 528 | } |
| 529 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 530 | bool Spirv::StoresInHelperInvocationsHaveNoEffect(spv::StorageClass storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 531 | { |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 532 | switch(storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 533 | { |
Nicolas Capens | 3a82d57 | 2022-10-22 21:50:25 -0400 | [diff] [blame] | 534 | // "Stores and atomics performed by helper invocations must not have any effect on memory..." |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 535 | default: |
| 536 | return true; |
Nicolas Capens | bb5d3bd | 2022-11-23 14:03:20 -0500 | [diff] [blame] | 537 | // "...except for the Function, Private and Output storage classes". |
Nicolas Capens | 3a82d57 | 2022-10-22 21:50:25 -0400 | [diff] [blame] | 538 | case spv::StorageClassFunction: |
| 539 | case spv::StorageClassPrivate: |
Nicolas Capens | bb5d3bd | 2022-11-23 14:03:20 -0500 | [diff] [blame] | 540 | case spv::StorageClassOutput: |
Nicolas Capens | 3a82d57 | 2022-10-22 21:50:25 -0400 | [diff] [blame] | 541 | return false; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 542 | } |
| 543 | } |
| 544 | |
Nicolas Capens | 7113474 | 2022-10-12 12:44:16 -0400 | [diff] [blame] | 545 | bool Spirv::IsExplicitLayout(spv::StorageClass storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 546 | { |
Alexis Hetu | 71ec98e | 2022-06-14 16:58:44 -0400 | [diff] [blame] | 547 | // From the Vulkan spec: |
| 548 | // "Composite objects in the StorageBuffer, PhysicalStorageBuffer, Uniform, |
| 549 | // and PushConstant Storage Classes must be explicitly laid out." |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 550 | switch(storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 551 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 552 | case spv::StorageClassUniform: |
| 553 | case spv::StorageClassStorageBuffer: |
Alexis Hetu | 71ec98e | 2022-06-14 16:58:44 -0400 | [diff] [blame] | 554 | case spv::StorageClassPhysicalStorageBuffer: |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 555 | case spv::StorageClassPushConstant: |
| 556 | return true; |
| 557 | default: |
| 558 | return false; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 559 | } |
| 560 | } |
| 561 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 562 | sw::SIMD::Pointer SpirvEmitter::GetElementPointer(sw::SIMD::Pointer structure, uint32_t offset, spv::StorageClass storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 563 | { |
Nicolas Capens | fdf4147 | 2022-09-26 00:40:11 -0400 | [diff] [blame] | 564 | if(IsStorageInterleavedByLane(storageClass)) |
Nicolas Capens | 94c7362 | 2022-06-06 13:05:38 -0400 | [diff] [blame] | 565 | { |
Nicolas Capens | afdb512 | 2022-06-30 11:31:35 -0400 | [diff] [blame] | 566 | for(int i = 0; i < SIMD::Width; i++) |
| 567 | { |
| 568 | structure.staticOffsets[i] += i * sizeof(float); |
| 569 | } |
Nicolas Capens | 94c7362 | 2022-06-06 13:05:38 -0400 | [diff] [blame] | 570 | |
| 571 | return structure + offset * sw::SIMD::Width; |
| 572 | } |
| 573 | else |
| 574 | { |
| 575 | return structure + offset; |
| 576 | } |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 577 | } |
| 578 | |
Nicolas Capens | 1ab775a | 2022-10-12 15:27:02 -0400 | [diff] [blame] | 579 | bool SpirvEmitter::IsStorageInterleavedByLane(spv::StorageClass storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 580 | { |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 581 | switch(storageClass) |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 582 | { |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 583 | case spv::StorageClassUniform: |
| 584 | case spv::StorageClassStorageBuffer: |
Alexis Hetu | 71ec98e | 2022-06-14 16:58:44 -0400 | [diff] [blame] | 585 | case spv::StorageClassPhysicalStorageBuffer: |
Nicolas Capens | 112faf4 | 2019-12-13 17:32:26 -0500 | [diff] [blame] | 586 | case spv::StorageClassPushConstant: |
| 587 | case spv::StorageClassWorkgroup: |
| 588 | case spv::StorageClassImage: |
| 589 | return false; |
| 590 | default: |
| 591 | return true; |
Ben Clayton | f3e2cc2 | 2019-11-28 12:02:15 +0000 | [diff] [blame] | 592 | } |
| 593 | } |
| 594 | |
| 595 | } // namespace sw |