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