blob: c55c6fed6686d9a94d39d8c5e12c012484cb111d [file] [log] [blame]
Chris Forbesaf4ed532018-12-06 18:33:27 -08001// Copyright 2018 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#ifndef sw_SpirvShader_hpp
16#define sw_SpirvShader_hpp
17
Chris Forbesd5aed492019-02-02 15:18:52 -080018#include "ShaderCore.hpp"
Nicolas Capens125dba02019-04-24 02:03:22 -040019#include "SamplerCore.hpp"
Ben Claytonab51bbf2019-02-20 14:36:27 +000020#include "SpirvID.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000021#include "System/Types.hpp"
22#include "Vulkan/VkDebug.hpp"
23#include "Vulkan/VkConfig.h"
Nicolas Capens09591b82019-04-08 22:51:08 -040024#include "Vulkan/VkDescriptorSet.hpp"
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040025#include "Common/Types.hpp"
Nicolas Capens86509d92019-03-21 13:23:50 -040026#include "Device/Config.hpp"
Nicolas Capens9e735102019-04-18 15:03:06 -040027#include "Device/Sampler.hpp"
Nicolas Capens86509d92019-03-21 13:23:50 -040028
29#include <spirv/unified1/spirv.hpp>
Chris Forbesaf4ed532018-12-06 18:33:27 -080030
Ben Clayton76e9bc02019-02-26 15:02:18 +000031#include <array>
Ben Clayton6fae32c2019-02-28 20:06:42 +000032#include <cstring>
Ben Clayton49d81582019-03-12 20:05:04 +000033#include <functional>
Chris Forbesaf4ed532018-12-06 18:33:27 -080034#include <string>
35#include <vector>
Ben Clayton64f78f52019-03-21 17:21:06 +000036#include <unordered_set>
Chris Forbesaf4ed532018-12-06 18:33:27 -080037#include <unordered_map>
38#include <cstdint>
Chris Forbesef4ab0f2019-01-18 08:11:03 -080039#include <type_traits>
Chris Forbesd5aed492019-02-02 15:18:52 -080040#include <memory>
Ben Clayton513ed1d2019-03-28 16:07:00 +000041#include <queue>
Chris Forbesaf4ed532018-12-06 18:33:27 -080042
Ben Clayton76e9bc02019-02-26 15:02:18 +000043namespace vk
44{
45 class PipelineLayout;
Ben Clayton96fbe082019-04-16 19:28:11 -040046 class ImageView;
47 class Sampler;
Chris Forbes24466042019-04-22 10:54:23 -070048 class RenderPass;
Chris Forbes45f9a932019-05-08 13:30:38 -070049 struct SampledImageDescriptor;
Ben Clayton76e9bc02019-02-26 15:02:18 +000050} // namespace vk
51
Chris Forbesaf4ed532018-12-06 18:33:27 -080052namespace sw
53{
Ben Clayton24ea5152019-02-26 11:02:42 +000054 // Forward declarations.
55 class SpirvRoutine;
Chris Forbes868ed902019-03-13 17:39:45 -070056 class GenericValue;
Ben Clayton24ea5152019-02-26 11:02:42 +000057
58 // SIMD contains types that represent multiple scalars packed into a single
59 // vector data type. Types in the SIMD namespace provide a semantic hint
60 // that the data should be treated as a per-execution-lane scalar instead of
61 // a typical euclidean-style vector type.
62 namespace SIMD
63 {
64 // Width is the number of per-lane scalars packed into each SIMD vector.
65 static constexpr int Width = 4;
66
67 using Float = rr::Float4;
68 using Int = rr::Int4;
Ben Claytondd1e37e2019-02-28 19:59:15 +000069 using UInt = rr::UInt4;
Ben Clayton3d497382019-04-08 16:16:12 -040070
71 struct Pointer
72 {
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040073 Pointer(rr::Pointer<Byte> base, rr::Int limit)
74 : base(base), limit(limit), dynamicOffsets(0), staticOffsets{}, hasDynamicOffsets(false) {}
75 Pointer(rr::Pointer<Byte> base, rr::Int limit, SIMD::Int offset)
76 : base(base), limit(limit), dynamicOffsets(offset), staticOffsets{}, hasDynamicOffsets(false) {}
Ben Clayton3d497382019-04-08 16:16:12 -040077
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040078 inline Pointer& operator += (Int i)
79 {
80 dynamicOffsets += i;
81 hasDynamicOffsets = true;
82 return *this;
83 }
84
85 inline Pointer& operator *= (Int i)
86 {
87 dynamicOffsets = offsets() * i;
88 staticOffsets = {};
89 hasDynamicOffsets = true;
90 return *this;
91 }
92
93 inline Pointer operator + (SIMD::Int i) { Pointer p = *this; p += i; return p; }
94 inline Pointer operator * (SIMD::Int i) { Pointer p = *this; p *= i; return p; }
95
96 inline Pointer& operator += (int i)
97 {
98 for (int el = 0; el < SIMD::Width; el++) { staticOffsets[el] += i; }
99 return *this;
100 }
101
102 inline Pointer& operator *= (int i)
103 {
104 for (int el = 0; el < SIMD::Width; el++) { staticOffsets[el] *= i; }
105 if (hasDynamicOffsets)
106 {
107 dynamicOffsets *= SIMD::Int(i);
108 }
109 return *this;
110 }
111
112 inline Pointer operator + (int i) { Pointer p = *this; p += i; return p; }
113 inline Pointer operator * (int i) { Pointer p = *this; p *= i; return p; }
114
115 inline SIMD::Int offsets() const
116 {
117 static_assert(SIMD::Width == 4, "Expects SIMD::Width to be 4");
118 return dynamicOffsets + SIMD::Int(staticOffsets[0], staticOffsets[1], staticOffsets[2], staticOffsets[3]);
119 }
120
121 // Returns true if all offsets are sequential (N+0, N+1, N+2, N+3)
122 inline rr::Bool hasSequentialOffsets() const
123 {
124 if (hasDynamicOffsets)
125 {
126 auto o = offsets();
127 static_assert(SIMD::Width == 4, "Expects SIMD::Width to be 4");
128 return rr::SignMask(~CmpEQ(o.yzww, o + SIMD::Int(1, 2, 3, 0))) == 0;
129 }
130 else
131 {
132 for (int i = 1; i < SIMD::Width; i++)
133 {
134 if (staticOffsets[i-1] + 1 != staticOffsets[i]) { return false; }
135 }
136 return true;
137 }
138 }
139
140 // Returns true if all offsets are equal (N, N, N, N)
141 inline rr::Bool hasEqualOffsets() const
142 {
143 if (hasDynamicOffsets)
144 {
145 auto o = offsets();
146 static_assert(SIMD::Width == 4, "Expects SIMD::Width to be 4");
147 return rr::SignMask(~CmpEQ(o, o.yzwx)) == 0;
148 }
149 else
150 {
151 for (int i = 1; i < SIMD::Width; i++)
152 {
153 if (staticOffsets[i-1] != staticOffsets[i]) { return false; }
154 }
155 return true;
156 }
157 }
Ben Clayton5f7e9112019-04-16 11:03:40 -0400158
Ben Clayton3d497382019-04-08 16:16:12 -0400159 // Base address for the pointer, common across all lanes.
Ben Clayton97035bd2019-04-16 11:35:38 -0400160 rr::Pointer<rr::Byte> base;
Ben Clayton3d497382019-04-08 16:16:12 -0400161
Ben Clayton9e4bc1b2019-04-16 16:52:02 -0400162 // Upper (non-inclusive) limit for offsets from base.
163 rr::Int limit;
Ben Clayton3d497382019-04-08 16:16:12 -0400164
Ben Clayton9e4bc1b2019-04-16 16:52:02 -0400165 // Per lane offsets from base.
166 SIMD::Int dynamicOffsets; // If hasDynamicOffsets is false, all dynamicOffsets are zero.
167 std::array<int32_t, SIMD::Width> staticOffsets;
168
169 // True if all dynamicOffsets are zero.
170 bool hasDynamicOffsets;
Ben Clayton3d497382019-04-08 16:16:12 -0400171 };
Ben Clayton9e4bc1b2019-04-16 16:52:02 -0400172
173 template <typename T> struct Element {};
174 template <> struct Element<Float> { using type = rr::Float; };
175 template <> struct Element<Int> { using type = rr::Int; };
176 template <> struct Element<UInt> { using type = rr::UInt; };
177
178 template<typename T>
179 void Store(Pointer ptr, T val, Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed);
180
181 template<typename T>
182 void Store(Pointer ptr, RValue<T> val, Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed)
183 {
184 Store(ptr, T(val), mask, atomic, order);
185 }
186
187 template<typename T>
188 T Load(Pointer ptr, Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed);
Ben Clayton24ea5152019-02-26 11:02:42 +0000189 }
190
Chris Forbese4ef5f72019-02-15 16:00:08 -0800191 // Incrementally constructed complex bundle of rvalues
192 // Effectively a restricted vector, supporting only:
193 // - allocation to a (runtime-known) fixed size
194 // - in-place construction of elements
195 // - const operator[]
196 class Intermediate
197 {
198 public:
Nicolas Capens5851ef42019-03-19 14:28:18 -0400199 Intermediate(uint32_t size) : scalar(new rr::Value*[size]), size(size) {
Nicolas Capens5851ef42019-03-19 14:28:18 -0400200 memset(scalar, 0, sizeof(rr::Value*) * size);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000201 }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800202
203 ~Intermediate()
204 {
Nicolas Capens5851ef42019-03-19 14:28:18 -0400205 delete[] scalar;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800206 }
207
Nicolas Capens80c796b2019-03-19 21:38:44 -0400208 void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value); }
209 void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value); }
210 void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value); }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800211
Nicolas Capens80c796b2019-03-19 21:38:44 -0400212 void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value); }
213 void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value); }
214 void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value); }
Ben Clayton093be462019-03-08 08:37:24 +0000215
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000216 // Value retrieval functions.
217 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbese4ef5f72019-02-15 16:00:08 -0800218 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000219 ASSERT(i < size);
Nicolas Capens5851ef42019-03-19 14:28:18 -0400220 ASSERT(scalar[i] != nullptr);
221 return As<SIMD::Float>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Float>(scalar)
Chris Forbese4ef5f72019-02-15 16:00:08 -0800222 }
Nicolas Capens5851ef42019-03-19 14:28:18 -0400223
224 RValue<SIMD::Int> Int(uint32_t i) const
225 {
226 ASSERT(i < size);
227 ASSERT(scalar[i] != nullptr);
228 return As<SIMD::Int>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Int>(scalar)
229 }
230
231 RValue<SIMD::UInt> UInt(uint32_t i) const
232 {
233 ASSERT(i < size);
234 ASSERT(scalar[i] != nullptr);
235 return As<SIMD::UInt>(scalar[i]); // TODO(b/128539387): RValue<SIMD::UInt>(scalar)
236 }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800237
238 // No copy/move construction or assignment
239 Intermediate(Intermediate const &) = delete;
240 Intermediate(Intermediate &&) = delete;
241 Intermediate & operator=(Intermediate const &) = delete;
242 Intermediate & operator=(Intermediate &&) = delete;
243
244 private:
Nicolas Capens5851ef42019-03-19 14:28:18 -0400245 void emplace(uint32_t i, rr::Value *value)
246 {
247 ASSERT(i < size);
248 ASSERT(scalar[i] == nullptr);
249 scalar[i] = value;
250 }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800251
Nicolas Capens5851ef42019-03-19 14:28:18 -0400252 rr::Value **const scalar;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800253 uint32_t size;
254 };
255
Chris Forbesaf4ed532018-12-06 18:33:27 -0800256 class SpirvShader
257 {
258 public:
259 using InsnStore = std::vector<uint32_t>;
260 InsnStore insns;
261
Nicolas Capens97da7822019-04-30 17:33:26 -0400262 using ImageSampler = void(void* texture, void *sampler, void* uvsIn, void* texelOut, void* constants);
Nicolas Capens125dba02019-04-24 02:03:22 -0400263 using GetImageSampler = ImageSampler*(const vk::ImageView *imageView, const vk::Sampler *sampler);
264
Ben Claytonecfeede2019-05-08 08:51:01 +0100265 enum class YieldResult
266 {
267 ControlBarrier,
268 };
269
Chris Forbesaf4ed532018-12-06 18:33:27 -0800270 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
271 class InsnIterator
272 {
273 InsnStore::const_iterator iter;
274
275 public:
276 spv::Op opcode() const
277 {
278 return static_cast<spv::Op>(*iter & spv::OpCodeMask);
279 }
280
281 uint32_t wordCount() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800282 {
283 return *iter >> spv::WordCountShift;
284 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800285
286 uint32_t word(uint32_t n) const
287 {
288 ASSERT(n < wordCount());
289 return iter[n];
290 }
291
Chris Forbes38f85b32019-02-12 20:10:05 +0000292 uint32_t const * wordPointer(uint32_t n) const
293 {
294 ASSERT(n < wordCount());
295 return &iter[n];
296 }
297
Ben Clayton60f15ec2019-05-09 17:50:01 +0100298 const char* string(uint32_t n) const
299 {
300 return reinterpret_cast<const char*>(wordPointer(n));
301 }
302
Ben Clayton9fd02e02019-03-21 18:47:15 +0000303 bool operator==(InsnIterator const &other) const
304 {
305 return iter == other.iter;
306 }
307
Chris Forbesaf4ed532018-12-06 18:33:27 -0800308 bool operator!=(InsnIterator const &other) const
309 {
310 return iter != other.iter;
311 }
312
313 InsnIterator operator*() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800314 {
315 return *this;
316 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800317
318 InsnIterator &operator++()
319 {
320 iter += wordCount();
321 return *this;
322 }
323
324 InsnIterator const operator++(int)
325 {
326 InsnIterator ret{*this};
327 iter += wordCount();
328 return ret;
329 }
330
331 InsnIterator(InsnIterator const &other) = default;
332
333 InsnIterator() = default;
334
335 explicit InsnIterator(InsnStore::const_iterator iter) : iter{iter}
Chris Forbes4a979dc2019-01-17 09:36:46 -0800336 {
337 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800338 };
339
340 /* range-based-for interface */
341 InsnIterator begin() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800342 {
343 return InsnIterator{insns.cbegin() + 5};
344 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800345
346 InsnIterator end() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800347 {
348 return InsnIterator{insns.cend()};
349 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800350
Ben Claytone205d342019-02-20 10:22:09 +0000351 class Type
352 {
353 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000354 using ID = SpirvID<Type>;
355
Nicolas Capens29090852019-03-19 16:22:35 -0400356 spv::Op opcode() const { return definition.opcode(); }
357
Ben Claytone205d342019-02-20 10:22:09 +0000358 InsnIterator definition;
Ben Clayton9a162482019-02-25 11:54:43 +0000359 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
Ben Claytone205d342019-02-20 10:22:09 +0000360 uint32_t sizeInComponents = 0;
361 bool isBuiltInBlock = false;
Ben Clayton9a162482019-02-25 11:54:43 +0000362
363 // Inner element type for pointers, arrays, vectors and matrices.
Ben Claytonaf973b62019-03-13 18:19:20 +0000364 ID element;
Ben Claytone205d342019-02-20 10:22:09 +0000365 };
366
Chris Forbes296aa252018-12-27 11:48:21 -0800367 class Object
368 {
369 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000370 using ID = SpirvID<Object>;
371
Nicolas Capens29090852019-03-19 16:22:35 -0400372 spv::Op opcode() const { return definition.opcode(); }
373
Chris Forbes296aa252018-12-27 11:48:21 -0800374 InsnIterator definition;
Ben Claytonaf973b62019-03-13 18:19:20 +0000375 Type::ID type;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800376 std::unique_ptr<uint32_t[]> constantValue = nullptr;
Chris Forbes296aa252018-12-27 11:48:21 -0800377
378 enum class Kind
379 {
Ben Clayton484e08e2019-04-05 12:11:39 +0100380 // Invalid default kind.
381 // If we get left with an object in this state, the module was
382 // broken.
383 Unknown,
384
385 // TODO: Better document this kind.
386 // A shader interface variable pointer.
387 // Pointer with uniform address across all lanes.
388 // Pointer held by SpirvRoutine::pointers
389 InterfaceVariable,
390
391 // Constant value held by Object::constantValue.
392 Constant,
393
394 // Value held by SpirvRoutine::intermediates.
395 Intermediate,
396
Ben Clayton5f7e9112019-04-16 11:03:40 -0400397 // Pointer held by SpirvRoutine::pointers
Ben Clayton1d514f32019-04-19 16:11:18 -0400398 Pointer,
Ben Clayton484e08e2019-04-05 12:11:39 +0100399
Ben Clayton6b511342019-04-05 12:12:30 +0100400 // A pointer to a vk::DescriptorSet*.
401 // Pointer held by SpirvRoutine::pointers.
402 DescriptorSet,
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400403 };
Ben Clayton6b511342019-04-05 12:12:30 +0100404
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400405 Kind kind = Kind::Unknown;
Chris Forbes296aa252018-12-27 11:48:21 -0800406 };
407
Ben Clayton9b156612019-03-13 19:48:31 +0000408 // Block is an interval of SPIR-V instructions, starting with the
409 // opening OpLabel, and ending with a termination instruction.
410 class Block
411 {
412 public:
413 using ID = SpirvID<Block>;
Ben Clayton64f78f52019-03-21 17:21:06 +0000414 using Set = std::unordered_set<ID>;
415
416 // Edge represents the graph edge between two blocks.
417 struct Edge
418 {
419 ID from;
420 ID to;
421
422 bool operator == (const Edge& other) const { return from == other.from && to == other.to; }
423
424 struct Hash
425 {
426 std::size_t operator()(const Edge& edge) const noexcept
427 {
428 return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value());
429 }
430 };
431 };
Ben Clayton9b156612019-03-13 19:48:31 +0000432
433 Block() = default;
434 Block(const Block& other) = default;
Ben Clayton64f78f52019-03-21 17:21:06 +0000435 explicit Block(InsnIterator begin, InsnIterator end);
Ben Clayton9b156612019-03-13 19:48:31 +0000436
437 /* range-based-for interface */
438 inline InsnIterator begin() const { return begin_; }
439 inline InsnIterator end() const { return end_; }
440
Ben Clayton64f78f52019-03-21 17:21:06 +0000441 enum Kind
442 {
443 Simple, // OpBranch or other simple terminator.
444 StructuredBranchConditional, // OpSelectionMerge + OpBranchConditional
445 UnstructuredBranchConditional, // OpBranchConditional
446 StructuredSwitch, // OpSelectionMerge + OpSwitch
447 UnstructuredSwitch, // OpSwitch
448 Loop, // OpLoopMerge + [OpBranchConditional | OpBranch]
449 };
450
451 Kind kind;
Ben Claytonfe3f0132019-03-26 11:10:16 +0000452 InsnIterator mergeInstruction; // Structured control flow merge instruction.
453 InsnIterator branchInstruction; // Branch instruction.
Ben Clayton64f78f52019-03-21 17:21:06 +0000454 ID mergeBlock; // Structured flow merge block.
455 ID continueTarget; // Loop continue block.
456 Set ins; // Blocks that branch into this block.
457 Set outs; // Blocks that this block branches to.
458
Ben Clayton9b156612019-03-13 19:48:31 +0000459 private:
460 InsnIterator begin_;
461 InsnIterator end_;
462 };
463
Ben Claytonab51bbf2019-02-20 14:36:27 +0000464 struct TypeOrObject {}; // Dummy struct to represent a Type or Object.
465
466 // TypeOrObjectID is an identifier that represents a Type or an Object,
Ben Claytonaf973b62019-03-13 18:19:20 +0000467 // and supports implicit casting to and from Type::ID or Object::ID.
Ben Claytonab51bbf2019-02-20 14:36:27 +0000468 class TypeOrObjectID : public SpirvID<TypeOrObject>
469 {
470 public:
471 using Hash = std::hash<SpirvID<TypeOrObject>>;
472
473 inline TypeOrObjectID(uint32_t id) : SpirvID(id) {}
Ben Claytonaf973b62019-03-13 18:19:20 +0000474 inline TypeOrObjectID(Type::ID id) : SpirvID(id.value()) {}
475 inline TypeOrObjectID(Object::ID id) : SpirvID(id.value()) {}
476 inline operator Type::ID() const { return Type::ID(value()); }
477 inline operator Object::ID() const { return Object::ID(value()); }
Ben Claytonab51bbf2019-02-20 14:36:27 +0000478 };
479
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400480 // OpImageSample variants
481 enum Variant
482 {
483 None,
484 Dref,
485 Proj,
486 ProjDref,
487 VARIANT_LAST = ProjDref
488 };
489
Nicolas Capens78896332019-04-29 16:41:50 -0400490 // Compact representation of image instruction parameters that is passed to the
491 // trampoline function for retrieving/generating the corresponding sampling routine.
492 struct ImageInstruction
493 {
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400494 ImageInstruction(Variant variant, SamplerMethod samplerMethod)
495 : parameters(0)
Nicolas Capens78896332019-04-29 16:41:50 -0400496 {
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400497 this->variant = variant;
498 this->samplerMethod = samplerMethod;
Nicolas Capens78896332019-04-29 16:41:50 -0400499 }
500
501 // Unmarshal from raw 32-bit data
502 ImageInstruction(uint32_t parameters) : parameters(parameters) {}
503
Nicolas Capens022bd572019-04-29 23:45:25 -0400504 SamplerFunction getSamplerFunction() const
Nicolas Capens78896332019-04-29 16:41:50 -0400505 {
Nicolas Capens022bd572019-04-29 23:45:25 -0400506 return { static_cast<SamplerMethod>(samplerMethod), static_cast<SamplerOption>(samplerOption) };
Nicolas Capens78896332019-04-29 16:41:50 -0400507 }
508
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400509 bool isDref() const
510 {
511 return (variant == Dref) || (variant == ProjDref);
512 }
513
514 bool isProj() const
515 {
516 return (variant == Proj) || (variant == ProjDref);
517 }
518
Nicolas Capens78896332019-04-29 16:41:50 -0400519 union
520 {
521 struct
522 {
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400523 uint32_t variant : BITS(VARIANT_LAST);
Nicolas Capens78896332019-04-29 16:41:50 -0400524 uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST);
Nicolas Capens022bd572019-04-29 23:45:25 -0400525 uint32_t samplerOption : BITS(SAMPLER_OPTION_LAST);
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400526
527 // Parameters are passed to the sampling routine in this order:
528 uint32_t coordinates : 3; // 1-4 (does not contain projection component)
Nicolas Capense2535df2019-05-06 10:37:50 -0400529 // uint32_t dref : 1; // Indicated by Variant::ProjDref|Dref
Nicolas Capens4bade2e2019-04-30 16:21:06 -0400530 // uint32_t lodOrBias : 1; // Indicated by SamplerMethod::Lod|Bias
Nicolas Capens022bd572019-04-29 23:45:25 -0400531 uint32_t gradComponents : 2; // 0-3 (for each of dx / dy)
532 uint32_t offsetComponents : 2; // 0-3
Nicolas Capens78896332019-04-29 16:41:50 -0400533 };
534
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400535 uint32_t parameters;
Nicolas Capens78896332019-04-29 16:41:50 -0400536 };
537 };
538
539 static_assert(sizeof(ImageInstruction) == 4, "ImageInstruction must be 32-bit");
540
Chris Forbesaf4ed532018-12-06 18:33:27 -0800541 int getSerialID() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800542 {
543 return serialID;
544 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800545
Ben Clayton60f15ec2019-05-09 17:50:01 +0100546 SpirvShader(VkPipelineShaderStageCreateInfo const *createInfo,
547 InsnStore const &insns,
548 vk::RenderPass *renderPass,
549 uint32_t subpassIndex);
Chris Forbesaf4ed532018-12-06 18:33:27 -0800550
551 struct Modes
552 {
553 bool EarlyFragmentTests : 1;
554 bool DepthReplacing : 1;
555 bool DepthGreater : 1;
556 bool DepthLess : 1;
557 bool DepthUnchanged : 1;
Chris Forbes8b0a2812019-01-17 10:10:09 -0800558 bool ContainsKill : 1;
Ben Claytonecfeede2019-05-08 08:51:01 +0100559 bool ContainsControlBarriers : 1;
Chris Forbes93f70b32019-02-10 21:26:27 +0000560 bool NeedsCentroid : 1;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800561
562 // Compute workgroup dimensions
Ben Clayton62758f52019-03-13 14:18:58 +0000563 int WorkgroupSizeX = 1, WorkgroupSizeY = 1, WorkgroupSizeZ = 1;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800564 };
565
566 Modes const &getModes() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800567 {
568 return modes;
569 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800570
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800571 enum AttribType : unsigned char
572 {
573 ATTRIBTYPE_FLOAT,
574 ATTRIBTYPE_INT,
575 ATTRIBTYPE_UINT,
Chris Forbesc25b8072018-12-10 15:10:39 -0800576 ATTRIBTYPE_UNUSED,
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800577
578 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
579 };
580
Chris Forbes8b0a2812019-01-17 10:10:09 -0800581 bool hasBuiltinInput(spv::BuiltIn b) const
582 {
583 return inputBuiltins.find(b) != inputBuiltins.end();
584 }
585
Chris Forbes71a1e012019-04-22 14:18:34 -0700586 bool hasBuiltinOutput(spv::BuiltIn b) const
587 {
588 return outputBuiltins.find(b) != outputBuiltins.end();
589 }
590
Chris Forbesc25b8072018-12-10 15:10:39 -0800591 struct Decorations
592 {
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400593 int32_t Location = -1;
594 int32_t Component = 0;
595 spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1);
596 int32_t Offset = -1;
597 int32_t ArrayStride = -1;
598 int32_t MatrixStride = 1;
599
Chris Forbesc25b8072018-12-10 15:10:39 -0800600 bool HasLocation : 1;
601 bool HasComponent : 1;
602 bool HasBuiltIn : 1;
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400603 bool HasOffset : 1;
604 bool HasArrayStride : 1;
605 bool HasMatrixStride : 1;
Chris Forbes1ba5ba72019-04-12 11:37:21 -0700606 bool HasRowMajor : 1; // whether RowMajor bit is valid.
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400607
Chris Forbesc25b8072018-12-10 15:10:39 -0800608 bool Flat : 1;
609 bool Centroid : 1;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800610 bool NoPerspective : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800611 bool Block : 1;
612 bool BufferBlock : 1;
Ben Clayton8448cc52019-04-09 16:24:31 -0400613 bool RelaxedPrecision : 1;
Chris Forbes1ba5ba72019-04-12 11:37:21 -0700614 bool RowMajor : 1; // RowMajor if true; ColMajor if false
Chris Forbes98e6b962019-04-12 11:58:58 -0700615 bool InsideMatrix : 1; // pseudo-decoration for whether we're inside a matrix.
Chris Forbesc25b8072018-12-10 15:10:39 -0800616
617 Decorations()
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400618 : Location{-1}, Component{0},
Ben Claytond073d8e2019-02-26 11:06:50 +0000619 BuiltIn{static_cast<spv::BuiltIn>(-1)},
Chris Forbes65321072019-03-07 16:13:56 -0800620 Offset{-1}, ArrayStride{-1}, MatrixStride{-1},
Ben Claytond073d8e2019-02-26 11:06:50 +0000621 HasLocation{false}, HasComponent{false},
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400622 HasBuiltIn{false}, HasOffset{false},
623 HasArrayStride{false}, HasMatrixStride{false},
Chris Forbes1ba5ba72019-04-12 11:37:21 -0700624 HasRowMajor{false},
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400625 Flat{false}, Centroid{false}, NoPerspective{false},
626 Block{false}, BufferBlock{false},
Chris Forbes98e6b962019-04-12 11:58:58 -0700627 RelaxedPrecision{false}, RowMajor{false},
628 InsideMatrix{false}
Chris Forbesc25b8072018-12-10 15:10:39 -0800629 {
630 }
631
632 Decorations(Decorations const &) = default;
633
634 void Apply(Decorations const &src);
635
636 void Apply(spv::Decoration decoration, uint32_t arg);
637 };
638
Ben Claytonab51bbf2019-02-20 14:36:27 +0000639 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
Ben Claytonaf973b62019-03-13 18:19:20 +0000640 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations;
Chris Forbesc25b8072018-12-10 15:10:39 -0800641
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400642 struct DescriptorDecorations
643 {
644 int32_t DescriptorSet = -1;
645 int32_t Binding = -1;
Chris Forbes24466042019-04-22 10:54:23 -0700646 int32_t InputAttachmentIndex = -1;
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400647
Chris Forbesb0d00ea2019-04-17 20:24:20 -0700648 void Apply(DescriptorDecorations const &src);
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400649 };
650
651 std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
Chris Forbes24466042019-04-22 10:54:23 -0700652 std::vector<VkFormat> inputAttachmentFormats;
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400653
Chris Forbes5839dcf2018-12-10 19:02:58 -0800654 struct InterfaceComponent
655 {
656 AttribType Type;
657 bool Flat : 1;
658 bool Centroid : 1;
659 bool NoPerspective : 1;
660
661 InterfaceComponent()
662 : Type{ATTRIBTYPE_UNUSED}, Flat{false}, Centroid{false}, NoPerspective{false}
663 {
664 }
665 };
666
Chris Forbesbde34082018-12-28 12:03:10 -0800667 struct BuiltinMapping
668 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000669 Object::ID Id;
Chris Forbesbde34082018-12-28 12:03:10 -0800670 uint32_t FirstComponent;
671 uint32_t SizeInComponents;
672 };
673
Ben Claytonecd38482019-04-19 17:11:08 -0400674 struct WorkgroupMemory
675 {
676 // allocates a new variable of size bytes with the given identifier.
677 inline void allocate(Object::ID id, uint32_t size)
678 {
679 uint32_t offset = totalSize;
680 auto it = offsets.emplace(id, offset);
681 ASSERT_MSG(it.second, "WorkgroupMemory already has an allocation for object %d", int(id.value()));
682 totalSize += size;
683 }
684 // returns the byte offset of the variable with the given identifier.
685 inline uint32_t offsetOf(Object::ID id) const
686 {
687 auto it = offsets.find(id);
688 ASSERT_MSG(it != offsets.end(), "WorkgroupMemory has no allocation for object %d", int(id.value()));
689 return it->second;
690 }
691 // returns the total allocated size in bytes.
692 inline uint32_t size() const { return totalSize; }
693 private:
694 uint32_t totalSize = 0; // in bytes
695 std::unordered_map<Object::ID, uint32_t> offsets; // in bytes
696 };
697
Chris Forbes5839dcf2018-12-10 19:02:58 -0800698 std::vector<InterfaceComponent> inputs;
699 std::vector<InterfaceComponent> outputs;
700
Chris Forbesc61271e2019-02-19 17:01:28 -0800701 void emitProlog(SpirvRoutine *routine) const;
Nicolas Capens09591b82019-04-08 22:51:08 -0400702 void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, const vk::DescriptorSet::Bindings &descriptorSets) const;
Chris Forbesc61271e2019-02-19 17:01:28 -0800703 void emitEpilog(SpirvRoutine *routine) const;
Chris Forbesef4ab0f2019-01-18 08:11:03 -0800704
705 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
706 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
707 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
Ben Claytonecd38482019-04-19 17:11:08 -0400708 WorkgroupMemory workgroupMemory;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800709
Ben Claytonaf973b62019-03-13 18:19:20 +0000710 Type const &getType(Type::ID id) const
Chris Forbes840809a2019-01-14 14:30:20 -0800711 {
712 auto it = types.find(id);
Ben Clayton00424c12019-03-17 17:29:30 +0000713 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value());
Chris Forbes840809a2019-01-14 14:30:20 -0800714 return it->second;
715 }
716
Ben Claytonaf973b62019-03-13 18:19:20 +0000717 Object const &getObject(Object::ID id) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800718 {
Chris Forbes1c658232019-02-01 17:12:25 -0800719 auto it = defs.find(id);
Ben Clayton00424c12019-03-17 17:29:30 +0000720 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value());
Chris Forbes1c658232019-02-01 17:12:25 -0800721 return it->second;
722 }
723
Ben Clayton9b156612019-03-13 19:48:31 +0000724 Block const &getBlock(Block::ID id) const
725 {
726 auto it = blocks.find(id);
Ben Claytonaf26cfe2019-03-21 17:32:44 +0000727 ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value());
Ben Clayton9b156612019-03-13 19:48:31 +0000728 return it->second;
729 }
730
Chris Forbesd5aed492019-02-02 15:18:52 -0800731 private:
732 const int serialID;
733 static volatile int serialCounter;
734 Modes modes;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000735 HandleMap<Type> types;
736 HandleMap<Object> defs;
Ben Clayton9b156612019-03-13 19:48:31 +0000737 HandleMap<Block> blocks;
Ben Clayton60f15ec2019-05-09 17:50:01 +0100738 Block::ID entryPointBlockId; // Block of the entry point function.
Ben Clayton9b156612019-03-13 19:48:31 +0000739
Ben Clayton513ed1d2019-03-28 16:07:00 +0000740 // Walks all reachable the blocks starting from id adding them to
741 // reachable.
742 void TraverseReachableBlocks(Block::ID id, Block::Set& reachable);
Ben Claytonfe3f0132019-03-26 11:10:16 +0000743
744 // Assigns Block::ins from Block::outs for every block.
745 void AssignBlockIns();
746
Ben Clayton0bb83b82019-02-26 11:41:07 +0000747 // DeclareType creates a Type for the given OpTypeX instruction, storing
748 // it into the types map. It is called from the analysis pass (constructor).
749 void DeclareType(InsnIterator insn);
750
Chris Forbesaf4ed532018-12-06 18:33:27 -0800751 void ProcessExecutionMode(InsnIterator it);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800752
753 uint32_t ComputeTypeSize(InsnIterator insn);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000754 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
Ben Claytonaf973b62019-03-13 18:19:20 +0000755 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const;
Chris Forbes3610ded2019-04-22 18:12:13 -0700756 void ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800757
Nicolas Capens82eb22e2019-04-10 01:15:43 -0400758 // Creates an Object for the instruction's result in 'defs'.
759 void DefineResult(const InsnIterator &insn);
760
Ben Clayton831db962019-02-27 14:57:18 +0000761 // Returns true if data in the given storage class is word-interleaved
Ben Claytonff1cede2019-03-08 08:23:34 +0000762 // by each SIMD vector lane, otherwise data is stored linerally.
Ben Clayton831db962019-02-27 14:57:18 +0000763 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000764 // Each lane addresses a single word, picked by a base pointer and an
765 // integer offset.
Ben Clayton831db962019-02-27 14:57:18 +0000766 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000767 // A word is currently 32 bits (single float, int32_t, uint32_t).
768 // A lane is a single element of a SIMD vector register.
Ben Clayton831db962019-02-27 14:57:18 +0000769 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000770 // Storage interleaved by lane - (IsStorageInterleavedByLane() == true):
771 // ---------------------------------------------------------------------
Ben Clayton831db962019-02-27 14:57:18 +0000772 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000773 // Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex)
Ben Clayton831db962019-02-27 14:57:18 +0000774 //
Ben Claytonff1cede2019-03-08 08:23:34 +0000775 // Assuming SIMD::Width == 4:
776 //
777 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
778 // ===========+===========+===========+==========
779 // LaneOffset=0: | Word[0] | Word[1] | Word[2] | Word[3]
780 // ---------------+-----------+-----------+-----------+----------
781 // LaneOffset=1: | Word[4] | Word[5] | Word[6] | Word[7]
782 // ---------------+-----------+-----------+-----------+----------
783 // LaneOffset=2: | Word[8] | Word[9] | Word[a] | Word[b]
784 // ---------------+-----------+-----------+-----------+----------
785 // LaneOffset=3: | Word[c] | Word[d] | Word[e] | Word[f]
786 //
787 //
788 // Linear storage - (IsStorageInterleavedByLane() == false):
789 // ---------------------------------------------------------
790 //
791 // Address = PtrBase + sizeof(Word) * LaneOffset
792 //
793 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
794 // ===========+===========+===========+==========
795 // LaneOffset=0: | Word[0] | Word[0] | Word[0] | Word[0]
796 // ---------------+-----------+-----------+-----------+----------
797 // LaneOffset=1: | Word[1] | Word[1] | Word[1] | Word[1]
798 // ---------------+-----------+-----------+-----------+----------
799 // LaneOffset=2: | Word[2] | Word[2] | Word[2] | Word[2]
800 // ---------------+-----------+-----------+-----------+----------
801 // LaneOffset=3: | Word[3] | Word[3] | Word[3] | Word[3]
Ben Clayton831db962019-02-27 14:57:18 +0000802 //
803 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
804
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800805 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000806 int VisitInterfaceInner(Type::ID id, Decorations d, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800807
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800808 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000809 void VisitInterface(Object::ID id, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800810
Chris Forbese6419ad2019-04-11 12:23:10 -0700811 template<typename F>
812 void VisitMemoryObject(Object::ID id, F f) const;
813
814 template<typename F>
815 void VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, F f) const;
816
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800817 Object& CreateConstant(InsnIterator it);
Chris Forbesbde34082018-12-28 12:03:10 -0800818
Chris Forbes049ff382019-02-02 15:16:43 -0800819 void ProcessInterfaceVariable(Object &object);
Chris Forbes38f85b32019-02-12 20:10:05 +0000820
Ben Clayton3d497382019-04-08 16:16:12 -0400821 // Returns a SIMD::Pointer to the underlying data for the given pointer
822 // object.
823 // Handles objects of the following kinds:
Ben Clayton6b511342019-04-05 12:12:30 +0100824 // • DescriptorSet
Ben Clayton484e08e2019-04-05 12:11:39 +0100825 // • DivergentPointer
826 // • InterfaceVariable
827 // • NonDivergentPointer
828 // Calling GetPointerToData with objects of any other kind will assert.
Ben Clayton3d497382019-04-08 16:16:12 -0400829 SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const;
Ben Clayton484e08e2019-04-05 12:11:39 +0100830
Ben Clayton3d497382019-04-08 16:16:12 -0400831 SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
Ben Clayton5f7e9112019-04-16 11:03:40 -0400832 SIMD::Pointer WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
Ben Clayton97035bd2019-04-16 11:35:38 -0400833
834 // Returns the *component* offset in the literal for the given access chain.
Ben Claytonaf973b62019-03-13 18:19:20 +0000835 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
Ben Claytond4e4c662019-02-26 11:54:34 +0000836
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000837 // EmitState holds control-flow state for the emit() pass.
838 class EmitState
839 {
840 public:
Nicolas Capens09591b82019-04-08 22:51:08 -0400841 EmitState(SpirvRoutine *routine, RValue<SIMD::Int> activeLaneMask, const vk::DescriptorSet::Bindings &descriptorSets)
842 : routine(routine),
843 activeLaneMaskValue(activeLaneMask.value),
844 descriptorSets(descriptorSets)
845 {
846 }
847
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000848 RValue<SIMD::Int> activeLaneMask() const
849 {
850 ASSERT(activeLaneMaskValue != nullptr);
851 return RValue<SIMD::Int>(activeLaneMaskValue);
852 }
853
854 void setActiveLaneMask(RValue<SIMD::Int> mask)
855 {
856 activeLaneMaskValue = mask.value;
857 }
858
859 // Add a new active lane mask edge from the current block to out.
860 // The edge mask value will be (mask AND activeLaneMaskValue).
861 // If multiple active lane masks are added for the same edge, then
862 // they will be ORed together.
863 void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask);
864
865 // Add a new active lane mask for the edge from -> to.
866 // If multiple active lane masks are added for the same edge, then
867 // they will be ORed together.
868 void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask);
869
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000870 SpirvRoutine *routine = nullptr; // The current routine being built.
871 rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask.
872 Block::ID currentBlock; // The current block being built.
873 Block::Set visited; // Blocks already built.
874 std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks;
Ben Clayton513ed1d2019-03-28 16:07:00 +0000875 std::queue<Block::ID> *pending;
Nicolas Capens09591b82019-04-08 22:51:08 -0400876
877 const vk::DescriptorSet::Bindings &descriptorSets;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000878 };
879
880 // EmitResult is an enumerator of result values from the Emit functions.
881 enum class EmitResult
882 {
883 Continue, // No termination instructions.
884 Terminator, // Reached a termination instruction.
885 };
886
Ben Claytone747b3c2019-03-21 19:35:15 +0000887 // existsPath returns true if there's a direct or indirect flow from
Ben Clayton513ed1d2019-03-28 16:07:00 +0000888 // the 'from' block to the 'to' block that does not pass through
889 // notPassingThrough.
890 bool existsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const;
Ben Claytone747b3c2019-03-21 19:35:15 +0000891
Ben Claytonfe3f0132019-03-26 11:10:16 +0000892 // Lookup the active lane mask for the edge from -> to.
893 // If from is unreachable, then a mask of all zeros is returned.
894 // Asserts if from is reachable and the edge does not exist.
895 RValue<SIMD::Int> GetActiveLaneMaskEdge(EmitState *state, Block::ID from, Block::ID to) const;
896
Ben Clayton513ed1d2019-03-28 16:07:00 +0000897 // Emit all the unvisited blocks (except for ignore) in BFS order,
898 // starting with id.
899 void EmitBlocks(Block::ID id, EmitState *state, Block::ID ignore = 0) const;
900 void EmitNonLoop(EmitState *state) const;
Ben Claytone747b3c2019-03-21 19:35:15 +0000901 void EmitLoop(EmitState *state) const;
Ben Clayton513ed1d2019-03-28 16:07:00 +0000902
903 void EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000904 EmitResult EmitInstruction(InsnIterator insn, EmitState *state) const;
905
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000906 // Emit pass instructions:
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000907 EmitResult EmitVariable(InsnIterator insn, EmitState *state) const;
908 EmitResult EmitLoad(InsnIterator insn, EmitState *state) const;
909 EmitResult EmitStore(InsnIterator insn, EmitState *state) const;
910 EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const;
911 EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const;
912 EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const;
913 EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const;
914 EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const;
915 EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const;
Chris Forbes06f4ed72019-03-28 09:53:20 +1300916 EmitResult EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const;
Chris Forbesa563dd82019-03-28 10:32:55 +1300917 EmitResult EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const;
Chris Forbes51562f12019-03-28 19:08:39 -0700918 EmitResult EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const;
Ben Clayton3ee52992019-04-08 11:01:23 -0400919 EmitResult EmitOuterProduct(InsnIterator insn, EmitState *state) const;
Ben Clayton620f7082019-04-08 11:12:08 -0400920 EmitResult EmitTranspose(InsnIterator insn, EmitState *state) const;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000921 EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
922 EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
923 EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;
924 EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const;
925 EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
926 EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
927 EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
928 EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
929 EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
930 EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000931 EmitResult EmitBranchConditional(InsnIterator insn, EmitState *state) const;
Ben Clayton213a8ce2019-03-21 18:57:23 +0000932 EmitResult EmitSwitch(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000933 EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const;
934 EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
Chris Forbes97e95892019-04-02 13:37:37 +1300935 EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
Ben Clayton9fd02e02019-03-21 18:47:15 +0000936 EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
Nicolas Capens5b09dd12019-04-30 01:05:28 -0400937 EmitResult EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
938 EmitResult EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
Chris Forbescd631592019-04-27 10:37:18 -0700939 EmitResult EmitImageFetch(InsnIterator insn, EmitState *state) const;
Nicolas Capens78896332019-04-29 16:41:50 -0400940 EmitResult EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const;
Chris Forbesb0d00ea2019-04-17 20:24:20 -0700941 EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
Ben Clayton0264d8e2019-05-08 15:39:40 +0100942 EmitResult EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const;
Ben Claytonb4001ed2019-05-10 10:21:00 +0100943 EmitResult EmitImageQueryLevels(InsnIterator insn, EmitState *state) const;
Ben Clayton2568cf72019-05-10 11:53:14 +0100944 EmitResult EmitImageQuerySamples(InsnIterator insn, EmitState *state) const;
Chris Forbes2f7f2ec2019-04-17 16:58:15 -0700945 EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
Chris Forbes179f0142019-04-17 20:24:44 -0700946 EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
Chris Forbesb51f2c12019-04-18 11:01:30 -0700947 EmitResult EmitImageTexelPointer(InsnIterator insn, EmitState *state) const;
Chris Forbes17813932019-04-18 11:45:54 -0700948 EmitResult EmitAtomicOp(InsnIterator insn, EmitState *state) const;
Chris Forbesa16238d2019-04-18 16:31:54 -0700949 EmitResult EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const;
Chris Forbesfa82c342019-04-26 16:42:38 -0700950 EmitResult EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const;
Ben Clayton78abf372019-05-09 15:11:58 +0100951 EmitResult EmitCopyObject(InsnIterator insn, EmitState *state) const;
Ben Claytonb5a45462019-04-30 19:21:29 +0100952 EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const;
Ben Claytonecfeede2019-05-08 08:51:01 +0100953 EmitResult EmitControlBarrier(InsnIterator insn, EmitState *state) const;
Ben Claytonb16c5862019-05-08 14:01:38 +0100954 EmitResult EmitMemoryBarrier(InsnIterator insn, EmitState *state) const;
Ben Clayton32d47972019-04-19 17:08:15 -0400955 EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
Ben Claytone4605da2019-05-09 16:24:01 +0100956 EmitResult EmitArrayLength(InsnIterator insn, EmitState *state) const;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000957
Ben Clayton0264d8e2019-05-08 15:39:40 +0100958 void GetImageDimensions(SpirvRoutine const *routine, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
959 SIMD::Pointer GetTexelAddress(SpirvRoutine const *routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const;
Ben Claytonb16c5862019-05-08 14:01:38 +0100960 uint32_t GetConstScalarInt(Object::ID id) const;
Chris Forbesea81ab72019-05-14 15:20:33 -0700961 void EvalSpecConstantOp(InsnIterator insn);
962 void EvalSpecConstantUnaryOp(InsnIterator insn);
963 void EvalSpecConstantBinaryOp(InsnIterator insn);
Ben Claytonb16c5862019-05-08 14:01:38 +0100964
Ben Clayton69c37492019-05-13 17:31:16 +0100965 // LoadPhi loads the phi values from the alloca storage and places the
966 // load values into the intermediate with the phi's result id.
967 void LoadPhi(InsnIterator insn, EmitState *state) const;
968
969 // StorePhi updates the phi's alloca storage value using the incoming
970 // values from blocks that are both in the OpPhi instruction and in
971 // filter.
972 void StorePhi(InsnIterator insn, EmitState *state, std::unordered_set<SpirvShader::Block::ID> const& filter) const;
973
Ben Claytonb16c5862019-05-08 14:01:38 +0100974 // Emits a rr::Fence for the given MemorySemanticsMask.
975 void Fence(spv::MemorySemanticsMask semantics) const;
Chris Forbes89c37a42019-04-17 18:28:33 -0700976
Ben Claytonecfeede2019-05-08 08:51:01 +0100977 // Helper for calling rr::Yield with res cast to an rr::Int.
978 void Yield(YieldResult res) const;
979
Nicolas Capens86509d92019-03-21 13:23:50 -0400980 // OpcodeName() returns the name of the opcode op.
981 // If NDEBUG is defined, then OpcodeName() will only return the numerical code.
Ben Claytond4e4c662019-02-26 11:54:34 +0000982 static std::string OpcodeName(spv::Op op);
Nicolas Capens86509d92019-03-21 13:23:50 -0400983 static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics);
Chris Forbes868ed902019-03-13 17:39:45 -0700984
985 // Helper as we often need to take dot products as part of doing other things.
986 SIMD::Float Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const;
Ben Claytonfc77af12019-04-09 10:48:00 -0400987
Chris Forbes50e64932019-04-08 17:49:27 -0700988 SIMD::UInt FloatToHalfBits(SIMD::UInt floatBits, bool storeInUpperBits) const;
Ben Claytonfc77af12019-04-09 10:48:00 -0400989
990 // Splits x into a floating-point significand in the range [0.5, 1.0)
991 // and an integral exponent of two, such that:
992 // x = significand * 2^exponent
993 // Returns the pair <significand, exponent>
994 std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const;
Ben Clayton96fbe082019-04-16 19:28:11 -0400995
Chris Forbes45f9a932019-05-08 13:30:38 -0700996 static ImageSampler *getImageSampler(uint32_t instruction, vk::SampledImageDescriptor const *imageDescriptor, const vk::Sampler *sampler);
Nicolas Capens1e7120e2019-04-30 17:33:26 -0400997 static ImageSampler *emitSamplerFunction(ImageInstruction instruction, const Sampler &samplerState);
Nicolas Capens9e735102019-04-18 15:03:06 -0400998
999 // TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly.
Nicolas Capensa47a5162019-04-24 02:41:27 -04001000 static sw::TextureType convertTextureType(VkImageViewType imageViewType);
Nicolas Capens9e735102019-04-18 15:03:06 -04001001 static sw::FilterType convertFilterMode(const vk::Sampler *sampler);
1002 static sw::MipmapType convertMipmapMode(const vk::Sampler *sampler);
Nicolas Capens6a12e092019-04-29 17:26:51 -04001003 static sw::AddressingMode convertAddressingMode(int coordinateIndex, VkSamplerAddressMode addressMode, VkImageViewType imageViewType);
Ben Clayton60f15ec2019-05-09 17:50:01 +01001004 static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model);
Chris Forbesaf4ed532018-12-06 18:33:27 -08001005 };
Ben Claytonab51bbf2019-02-20 14:36:27 +00001006
1007 class SpirvRoutine
1008 {
1009 public:
Ben Clayton76e9bc02019-02-26 15:02:18 +00001010 SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
1011
Ben Clayton47747612019-04-04 16:27:35 +01001012 using Variable = Array<SIMD::Float>;
Ben Clayton24ea5152019-02-26 11:02:42 +00001013
Ben Clayton76e9bc02019-02-26 15:02:18 +00001014 vk::PipelineLayout const * const pipelineLayout;
1015
Ben Clayton47747612019-04-04 16:27:35 +01001016 std::unordered_map<SpirvShader::Object::ID, Variable> variables;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001017
Ben Claytonaf973b62019-03-13 18:19:20 +00001018 std::unordered_map<SpirvShader::Object::ID, Intermediate> intermediates;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001019
Ben Clayton5f7e9112019-04-16 11:03:40 -04001020 std::unordered_map<SpirvShader::Object::ID, SIMD::Pointer> pointers;
Ben Clayton831db962019-02-27 14:57:18 +00001021
Ben Clayton69c37492019-05-13 17:31:16 +01001022 std::unordered_map<SpirvShader::Object::ID, Variable> phis;
1023
Ben Clayton47747612019-04-04 16:27:35 +01001024 Variable inputs = Variable{MAX_INTERFACE_COMPONENTS};
1025 Variable outputs = Variable{MAX_INTERFACE_COMPONENTS};
Ben Claytonab51bbf2019-02-20 14:36:27 +00001026
Ben Claytonecd38482019-04-19 17:11:08 -04001027 Pointer<Byte> workgroupMemory;
Ben Clayton225a1302019-04-02 12:28:22 +01001028 Pointer<Pointer<Byte>> descriptorSets;
1029 Pointer<Int> descriptorDynamicOffsets;
Chris Forbesa30de542019-03-18 18:51:55 -07001030 Pointer<Byte> pushConstants;
Chris Forbes548e3662019-04-25 10:00:06 -07001031 Pointer<Byte> constants;
Chris Forbes97e95892019-04-02 13:37:37 +13001032 Int killMask = Int{0};
Chris Forbes24466042019-04-22 10:54:23 -07001033 SIMD::Int windowSpacePosition[2];
Ben Clayton76e9bc02019-02-26 15:02:18 +00001034
Ben Clayton47747612019-04-04 16:27:35 +01001035 void createVariable(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +00001036 {
Ben Clayton47747612019-04-04 16:27:35 +01001037 bool added = variables.emplace(id, Variable(size)).second;
1038 ASSERT_MSG(added, "Variable %d created twice", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +00001039 }
1040
Ben Clayton5f7e9112019-04-16 11:03:40 -04001041 void createPointer(SpirvShader::Object::ID id, SIMD::Pointer ptr)
Ben Clayton484e08e2019-04-05 12:11:39 +01001042 {
Ben Clayton5f7e9112019-04-16 11:03:40 -04001043 bool added = pointers.emplace(id, ptr).second;
Ben Clayton484e08e2019-04-05 12:11:39 +01001044 ASSERT_MSG(added, "Pointer %d created twice", id.value());
1045 }
1046
Ben Claytonaf973b62019-03-13 18:19:20 +00001047 Intermediate& createIntermediate(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +00001048 {
Chris Forbes928dfee2019-02-26 21:22:32 -08001049 auto it = intermediates.emplace(std::piecewise_construct,
Ben Claytonab51bbf2019-02-20 14:36:27 +00001050 std::forward_as_tuple(id),
1051 std::forward_as_tuple(size));
Ben Clayton0e3d3282019-04-04 15:53:04 +01001052 ASSERT_MSG(it.second, "Intermediate %d created twice", id.value());
Chris Forbes928dfee2019-02-26 21:22:32 -08001053 return it.first->second;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001054 }
1055
Ben Clayton47747612019-04-04 16:27:35 +01001056 Variable& getVariable(SpirvShader::Object::ID id)
Ben Claytonab51bbf2019-02-20 14:36:27 +00001057 {
Ben Clayton47747612019-04-04 16:27:35 +01001058 auto it = variables.find(id);
1059 ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +00001060 return it->second;
1061 }
1062
Ben Claytonaf973b62019-03-13 18:19:20 +00001063 Intermediate const& getIntermediate(SpirvShader::Object::ID id) const
Ben Claytonab51bbf2019-02-20 14:36:27 +00001064 {
1065 auto it = intermediates.find(id);
Ben Claytonaf26cfe2019-03-21 17:32:44 +00001066 ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value());
Ben Claytonab51bbf2019-02-20 14:36:27 +00001067 return it->second;
1068 }
Ben Clayton831db962019-02-27 14:57:18 +00001069
Ben Clayton5f7e9112019-04-16 11:03:40 -04001070 SIMD::Pointer const& getPointer(SpirvShader::Object::ID id) const
Ben Clayton831db962019-02-27 14:57:18 +00001071 {
Ben Clayton484e08e2019-04-05 12:11:39 +01001072 auto it = pointers.find(id);
1073 ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());
Ben Clayton831db962019-02-27 14:57:18 +00001074 return it->second;
1075 }
Ben Claytonab51bbf2019-02-20 14:36:27 +00001076 };
1077
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001078 class GenericValue
1079 {
1080 // Generic wrapper over either per-lane intermediate value, or a constant.
1081 // Constants are transparently widened to per-lane values in operator[].
1082 // This is appropriate in most cases -- if we're not going to do something
1083 // significantly different based on whether the value is uniform across lanes.
1084
1085 SpirvShader::Object const &obj;
1086 Intermediate const *intermediate;
1087
1088 public:
Ben Claytonaf973b62019-03-13 18:19:20 +00001089 GenericValue(SpirvShader const *shader, SpirvRoutine const *routine, SpirvShader::Object::ID objId) :
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001090 obj(shader->getObject(objId)),
Ben Clayton16ab9e92019-04-08 10:57:35 -04001091 intermediate(obj.kind == SpirvShader::Object::Kind::Intermediate ? &routine->getIntermediate(objId) : nullptr),
1092 type(obj.type) {}
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001093
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001094 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001095 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001096 if (intermediate != nullptr)
1097 {
1098 return intermediate->Float(i);
1099 }
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001100 auto constantValue = reinterpret_cast<float *>(obj.constantValue.get());
Ben Clayton24ea5152019-02-26 11:02:42 +00001101 return RValue<SIMD::Float>(constantValue[i]);
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001102 }
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001103
1104 RValue<SIMD::Int> Int(uint32_t i) const
1105 {
1106 return As<SIMD::Int>(Float(i));
1107 }
1108
1109 RValue<SIMD::UInt> UInt(uint32_t i) const
1110 {
1111 return As<SIMD::UInt>(Float(i));
1112 }
Ben Clayton16ab9e92019-04-08 10:57:35 -04001113
1114 SpirvShader::Type::ID const type;
Chris Forbesd30b5ac2019-02-26 21:53:56 -08001115 };
1116
Chris Forbesaf4ed532018-12-06 18:33:27 -08001117}
1118
Chris Forbesc25b8072018-12-10 15:10:39 -08001119#endif // sw_SpirvShader_hpp