blob: e6905f8e01f3eff4dec94cddf0a803f52ecd7120 [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"
Ben Claytonab51bbf2019-02-20 14:36:27 +000019#include "SpirvID.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000020#include "System/Types.hpp"
21#include "Vulkan/VkDebug.hpp"
22#include "Vulkan/VkConfig.h"
Chris Forbesaf4ed532018-12-06 18:33:27 -080023
Ben Clayton76e9bc02019-02-26 15:02:18 +000024#include <array>
Ben Clayton6fae32c2019-02-28 20:06:42 +000025#include <cstring>
Ben Clayton49d81582019-03-12 20:05:04 +000026#include <functional>
Chris Forbesaf4ed532018-12-06 18:33:27 -080027#include <string>
28#include <vector>
29#include <unordered_map>
30#include <cstdint>
Chris Forbesef4ab0f2019-01-18 08:11:03 -080031#include <type_traits>
Chris Forbesd5aed492019-02-02 15:18:52 -080032#include <memory>
Chris Forbesaf4ed532018-12-06 18:33:27 -080033#include <spirv/unified1/spirv.hpp>
Chris Forbes7e6fff22019-02-10 20:18:50 +000034#include <Device/Config.hpp>
Chris Forbesaf4ed532018-12-06 18:33:27 -080035
Ben Clayton76e9bc02019-02-26 15:02:18 +000036namespace vk
37{
38 class PipelineLayout;
39} // namespace vk
40
Chris Forbesaf4ed532018-12-06 18:33:27 -080041namespace sw
42{
Ben Clayton24ea5152019-02-26 11:02:42 +000043 // Forward declarations.
44 class SpirvRoutine;
Chris Forbes868ed902019-03-13 17:39:45 -070045 class GenericValue;
Ben Clayton24ea5152019-02-26 11:02:42 +000046
47 // SIMD contains types that represent multiple scalars packed into a single
48 // vector data type. Types in the SIMD namespace provide a semantic hint
49 // that the data should be treated as a per-execution-lane scalar instead of
50 // a typical euclidean-style vector type.
51 namespace SIMD
52 {
53 // Width is the number of per-lane scalars packed into each SIMD vector.
54 static constexpr int Width = 4;
55
56 using Float = rr::Float4;
57 using Int = rr::Int4;
Ben Claytondd1e37e2019-02-28 19:59:15 +000058 using UInt = rr::UInt4;
Ben Clayton24ea5152019-02-26 11:02:42 +000059 }
60
Chris Forbese4ef5f72019-02-15 16:00:08 -080061 // Incrementally constructed complex bundle of rvalues
62 // Effectively a restricted vector, supporting only:
63 // - allocation to a (runtime-known) fixed size
64 // - in-place construction of elements
65 // - const operator[]
66 class Intermediate
67 {
68 public:
Ben Clayton24ea5152019-02-26 11:02:42 +000069 using Scalar = RValue<SIMD::Float>;
Chris Forbese4ef5f72019-02-15 16:00:08 -080070
Ben Clayton6fae32c2019-02-28 20:06:42 +000071 Intermediate(uint32_t size) : contents(new ContentsType[size]), size(size) {
72#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
Ben Clayton952d2732019-03-06 21:01:52 +000073 memset(contents, 0, sizeof(ContentsType) * size);
Ben Clayton6fae32c2019-02-28 20:06:42 +000074#endif
75 }
Chris Forbese4ef5f72019-02-15 16:00:08 -080076
77 ~Intermediate()
78 {
79 for (auto i = 0u; i < size; i++)
80 reinterpret_cast<Scalar *>(&contents[i])->~Scalar();
81 delete [] contents;
82 }
83
84 void emplace(uint32_t n, Scalar&& value)
85 {
Ben Clayton6fae32c2019-02-28 20:06:42 +000086 ASSERT(n < size);
87 ASSERT(reinterpret_cast<Scalar const *>(&contents[n])->value == nullptr);
Chris Forbese4ef5f72019-02-15 16:00:08 -080088 new (&contents[n]) Scalar(value);
89 }
90
Ben Clayton24ea5152019-02-26 11:02:42 +000091 void emplace(uint32_t n, const Scalar& value)
92 {
Ben Clayton6fae32c2019-02-28 20:06:42 +000093 ASSERT(n < size);
94 ASSERT(reinterpret_cast<Scalar const *>(&contents[n])->value == nullptr);
Ben Clayton24ea5152019-02-26 11:02:42 +000095 new (&contents[n]) Scalar(value);
96 }
97
Ben Clayton093be462019-03-08 08:37:24 +000098 // Emplace with cast helpers.
99 void emplace(uint32_t n, const RValue<SIMD::Int>& value) { emplace(n, As<SIMD::Float>(value)); }
100 void emplace(uint32_t n, const RValue<SIMD::UInt>& value) { emplace(n, As<SIMD::Float>(value)); }
101
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000102 // Value retrieval functions.
103 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbese4ef5f72019-02-15 16:00:08 -0800104 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000105 ASSERT(i < size);
106 auto scalar = reinterpret_cast<Scalar const *>(&contents[i]);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000107 ASSERT(scalar->value != nullptr);
108 return *scalar;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800109 }
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000110 RValue<SIMD::Int> Int(uint32_t i) const { return As<SIMD::Int>(Float(i)); }
111 RValue<SIMD::UInt> UInt(uint32_t i) const { return As<SIMD::UInt>(Float(i)); }
Chris Forbese4ef5f72019-02-15 16:00:08 -0800112
113 // No copy/move construction or assignment
114 Intermediate(Intermediate const &) = delete;
115 Intermediate(Intermediate &&) = delete;
116 Intermediate & operator=(Intermediate const &) = delete;
117 Intermediate & operator=(Intermediate &&) = delete;
118
119 private:
120 using ContentsType = std::aligned_storage<sizeof(Scalar), alignof(Scalar)>::type;
121
122 ContentsType *contents;
123 uint32_t size;
124 };
125
Chris Forbesaf4ed532018-12-06 18:33:27 -0800126 class SpirvShader
127 {
128 public:
129 using InsnStore = std::vector<uint32_t>;
130 InsnStore insns;
131
132 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
133 class InsnIterator
134 {
135 InsnStore::const_iterator iter;
136
137 public:
138 spv::Op opcode() const
139 {
140 return static_cast<spv::Op>(*iter & spv::OpCodeMask);
141 }
142
143 uint32_t wordCount() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800144 {
145 return *iter >> spv::WordCountShift;
146 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800147
148 uint32_t word(uint32_t n) const
149 {
150 ASSERT(n < wordCount());
151 return iter[n];
152 }
153
Chris Forbes38f85b32019-02-12 20:10:05 +0000154 uint32_t const * wordPointer(uint32_t n) const
155 {
156 ASSERT(n < wordCount());
157 return &iter[n];
158 }
159
Chris Forbesaf4ed532018-12-06 18:33:27 -0800160 bool operator!=(InsnIterator const &other) const
161 {
162 return iter != other.iter;
163 }
164
165 InsnIterator operator*() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800166 {
167 return *this;
168 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800169
170 InsnIterator &operator++()
171 {
172 iter += wordCount();
173 return *this;
174 }
175
176 InsnIterator const operator++(int)
177 {
178 InsnIterator ret{*this};
179 iter += wordCount();
180 return ret;
181 }
182
183 InsnIterator(InsnIterator const &other) = default;
184
185 InsnIterator() = default;
186
187 explicit InsnIterator(InsnStore::const_iterator iter) : iter{iter}
Chris Forbes4a979dc2019-01-17 09:36:46 -0800188 {
189 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800190 };
191
192 /* range-based-for interface */
193 InsnIterator begin() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800194 {
195 return InsnIterator{insns.cbegin() + 5};
196 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800197
198 InsnIterator end() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800199 {
200 return InsnIterator{insns.cend()};
201 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800202
Ben Claytone205d342019-02-20 10:22:09 +0000203 class Type
204 {
205 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000206 using ID = SpirvID<Type>;
207
Ben Claytone205d342019-02-20 10:22:09 +0000208 InsnIterator definition;
Ben Clayton9a162482019-02-25 11:54:43 +0000209 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
Ben Claytone205d342019-02-20 10:22:09 +0000210 uint32_t sizeInComponents = 0;
211 bool isBuiltInBlock = false;
Ben Clayton9a162482019-02-25 11:54:43 +0000212
213 // Inner element type for pointers, arrays, vectors and matrices.
Ben Claytonaf973b62019-03-13 18:19:20 +0000214 ID element;
Ben Claytone205d342019-02-20 10:22:09 +0000215 };
216
Chris Forbes296aa252018-12-27 11:48:21 -0800217 class Object
218 {
219 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000220 using ID = SpirvID<Object>;
221
Chris Forbes296aa252018-12-27 11:48:21 -0800222 InsnIterator definition;
Ben Claytonaf973b62019-03-13 18:19:20 +0000223 Type::ID type;
224 ID pointerBase;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800225 std::unique_ptr<uint32_t[]> constantValue = nullptr;
Chris Forbes296aa252018-12-27 11:48:21 -0800226
227 enum class Kind
228 {
229 Unknown, /* for paranoia -- if we get left with an object in this state, the module was broken */
Ben Clayton831db962019-02-27 14:57:18 +0000230 Variable, // TODO: Document
231 InterfaceVariable, // TODO: Document
232 Constant, // Values held by Object::constantValue
233 Value, // Values held by SpirvRoutine::intermediates
234 PhysicalPointer, // Pointer held by SpirvRoutine::physicalPointers
Chris Forbes296aa252018-12-27 11:48:21 -0800235 } kind = Kind::Unknown;
236 };
237
Ben Clayton9b156612019-03-13 19:48:31 +0000238 // Block is an interval of SPIR-V instructions, starting with the
239 // opening OpLabel, and ending with a termination instruction.
240 class Block
241 {
242 public:
243 using ID = SpirvID<Block>;
244
245 Block() = default;
246 Block(const Block& other) = default;
247 explicit Block(InsnIterator begin, InsnIterator end) : begin_(begin), end_(end) {}
248
249 /* range-based-for interface */
250 inline InsnIterator begin() const { return begin_; }
251 inline InsnIterator end() const { return end_; }
252
253 private:
254 InsnIterator begin_;
255 InsnIterator end_;
256 };
257
Ben Claytonab51bbf2019-02-20 14:36:27 +0000258 struct TypeOrObject {}; // Dummy struct to represent a Type or Object.
259
260 // TypeOrObjectID is an identifier that represents a Type or an Object,
Ben Claytonaf973b62019-03-13 18:19:20 +0000261 // and supports implicit casting to and from Type::ID or Object::ID.
Ben Claytonab51bbf2019-02-20 14:36:27 +0000262 class TypeOrObjectID : public SpirvID<TypeOrObject>
263 {
264 public:
265 using Hash = std::hash<SpirvID<TypeOrObject>>;
266
267 inline TypeOrObjectID(uint32_t id) : SpirvID(id) {}
Ben Claytonaf973b62019-03-13 18:19:20 +0000268 inline TypeOrObjectID(Type::ID id) : SpirvID(id.value()) {}
269 inline TypeOrObjectID(Object::ID id) : SpirvID(id.value()) {}
270 inline operator Type::ID() const { return Type::ID(value()); }
271 inline operator Object::ID() const { return Object::ID(value()); }
Ben Claytonab51bbf2019-02-20 14:36:27 +0000272 };
273
Chris Forbesaf4ed532018-12-06 18:33:27 -0800274 int getSerialID() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800275 {
276 return serialID;
277 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800278
279 explicit SpirvShader(InsnStore const &insns);
280
281 struct Modes
282 {
283 bool EarlyFragmentTests : 1;
284 bool DepthReplacing : 1;
285 bool DepthGreater : 1;
286 bool DepthLess : 1;
287 bool DepthUnchanged : 1;
Chris Forbes8b0a2812019-01-17 10:10:09 -0800288 bool ContainsKill : 1;
Chris Forbes93f70b32019-02-10 21:26:27 +0000289 bool NeedsCentroid : 1;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800290
291 // Compute workgroup dimensions
292 int LocalSizeX, LocalSizeY, LocalSizeZ;
293 };
294
295 Modes const &getModes() const
Chris Forbes4a979dc2019-01-17 09:36:46 -0800296 {
297 return modes;
298 }
Chris Forbesaf4ed532018-12-06 18:33:27 -0800299
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800300 enum AttribType : unsigned char
301 {
302 ATTRIBTYPE_FLOAT,
303 ATTRIBTYPE_INT,
304 ATTRIBTYPE_UINT,
Chris Forbesc25b8072018-12-10 15:10:39 -0800305 ATTRIBTYPE_UNUSED,
Chris Forbes2e7f35b2019-01-17 09:51:39 -0800306
307 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
308 };
309
Chris Forbes8b0a2812019-01-17 10:10:09 -0800310 bool hasBuiltinInput(spv::BuiltIn b) const
311 {
312 return inputBuiltins.find(b) != inputBuiltins.end();
313 }
314
Chris Forbesc25b8072018-12-10 15:10:39 -0800315 struct Decorations
316 {
317 int32_t Location;
318 int32_t Component;
Ben Claytond073d8e2019-02-26 11:06:50 +0000319 int32_t DescriptorSet;
320 int32_t Binding;
Chris Forbesc25b8072018-12-10 15:10:39 -0800321 spv::BuiltIn BuiltIn;
Chris Forbes65321072019-03-07 16:13:56 -0800322 int32_t Offset;
323 int32_t ArrayStride;
324 int32_t MatrixStride;
Chris Forbesc25b8072018-12-10 15:10:39 -0800325 bool HasLocation : 1;
326 bool HasComponent : 1;
Ben Claytond073d8e2019-02-26 11:06:50 +0000327 bool HasDescriptorSet : 1;
328 bool HasBinding : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800329 bool HasBuiltIn : 1;
330 bool Flat : 1;
331 bool Centroid : 1;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800332 bool NoPerspective : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800333 bool Block : 1;
334 bool BufferBlock : 1;
Chris Forbes65321072019-03-07 16:13:56 -0800335 bool HasOffset : 1;
336 bool HasArrayStride : 1;
337 bool HasMatrixStride : 1;
Chris Forbesc25b8072018-12-10 15:10:39 -0800338
339 Decorations()
Ben Claytond073d8e2019-02-26 11:06:50 +0000340 : Location{-1}, Component{0}, DescriptorSet{-1}, Binding{-1},
341 BuiltIn{static_cast<spv::BuiltIn>(-1)},
Chris Forbes65321072019-03-07 16:13:56 -0800342 Offset{-1}, ArrayStride{-1}, MatrixStride{-1},
Ben Claytond073d8e2019-02-26 11:06:50 +0000343 HasLocation{false}, HasComponent{false},
344 HasDescriptorSet{false}, HasBinding{false},
345 HasBuiltIn{false}, Flat{false}, Centroid{false},
Chris Forbes65321072019-03-07 16:13:56 -0800346 NoPerspective{false}, Block{false}, BufferBlock{false},
347 HasOffset{false}, HasArrayStride{false}, HasMatrixStride{false}
Chris Forbesc25b8072018-12-10 15:10:39 -0800348 {
349 }
350
351 Decorations(Decorations const &) = default;
352
353 void Apply(Decorations const &src);
354
355 void Apply(spv::Decoration decoration, uint32_t arg);
356 };
357
Ben Claytonab51bbf2019-02-20 14:36:27 +0000358 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
Ben Claytonaf973b62019-03-13 18:19:20 +0000359 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations;
Chris Forbesc25b8072018-12-10 15:10:39 -0800360
Chris Forbes5839dcf2018-12-10 19:02:58 -0800361 struct InterfaceComponent
362 {
363 AttribType Type;
364 bool Flat : 1;
365 bool Centroid : 1;
366 bool NoPerspective : 1;
367
368 InterfaceComponent()
369 : Type{ATTRIBTYPE_UNUSED}, Flat{false}, Centroid{false}, NoPerspective{false}
370 {
371 }
372 };
373
Chris Forbesbde34082018-12-28 12:03:10 -0800374 struct BuiltinMapping
375 {
Ben Claytonaf973b62019-03-13 18:19:20 +0000376 Object::ID Id;
Chris Forbesbde34082018-12-28 12:03:10 -0800377 uint32_t FirstComponent;
378 uint32_t SizeInComponents;
379 };
380
Chris Forbes5839dcf2018-12-10 19:02:58 -0800381 std::vector<InterfaceComponent> inputs;
382 std::vector<InterfaceComponent> outputs;
383
Chris Forbesc61271e2019-02-19 17:01:28 -0800384 void emitProlog(SpirvRoutine *routine) const;
Chris Forbesd5aed492019-02-02 15:18:52 -0800385 void emit(SpirvRoutine *routine) const;
Chris Forbesc61271e2019-02-19 17:01:28 -0800386 void emitEpilog(SpirvRoutine *routine) const;
Chris Forbesef4ab0f2019-01-18 08:11:03 -0800387
388 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
389 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
390 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800391
Ben Claytonaf973b62019-03-13 18:19:20 +0000392 Type const &getType(Type::ID id) const
Chris Forbes840809a2019-01-14 14:30:20 -0800393 {
394 auto it = types.find(id);
Ben Clayton36411212019-03-05 11:57:31 +0000395 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value());
Chris Forbes840809a2019-01-14 14:30:20 -0800396 return it->second;
397 }
398
Ben Claytonaf973b62019-03-13 18:19:20 +0000399 Object const &getObject(Object::ID id) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800400 {
Chris Forbes1c658232019-02-01 17:12:25 -0800401 auto it = defs.find(id);
Ben Clayton36411212019-03-05 11:57:31 +0000402 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value());
Chris Forbes1c658232019-02-01 17:12:25 -0800403 return it->second;
404 }
405
Ben Clayton9b156612019-03-13 19:48:31 +0000406 Block const &getBlock(Block::ID id) const
407 {
408 auto it = blocks.find(id);
409 ASSERT(it != blocks.end());
410 return it->second;
411 }
412
Chris Forbesd5aed492019-02-02 15:18:52 -0800413 private:
414 const int serialID;
415 static volatile int serialCounter;
416 Modes modes;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000417 HandleMap<Type> types;
418 HandleMap<Object> defs;
Ben Clayton9b156612019-03-13 19:48:31 +0000419 HandleMap<Block> blocks;
420 Block::ID mainBlockId; // Block of the entry point function.
421
422 void EmitBlock(SpirvRoutine *routine, Block const &block) const;
423 void EmitInstruction(SpirvRoutine *routine, InsnIterator insn) const;
Chris Forbesd5aed492019-02-02 15:18:52 -0800424
Ben Clayton0bb83b82019-02-26 11:41:07 +0000425 // DeclareType creates a Type for the given OpTypeX instruction, storing
426 // it into the types map. It is called from the analysis pass (constructor).
427 void DeclareType(InsnIterator insn);
428
Chris Forbesaf4ed532018-12-06 18:33:27 -0800429 void ProcessExecutionMode(InsnIterator it);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800430
431 uint32_t ComputeTypeSize(InsnIterator insn);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000432 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
Ben Claytonaf973b62019-03-13 18:19:20 +0000433 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800434
Ben Clayton831db962019-02-27 14:57:18 +0000435 // Returns true if data in the given storage class is word-interleaved
436 // by each SIMD vector lane, otherwise data is linerally stored.
437 //
438 // A 'lane' is a component of a SIMD vector register.
439 // Given 4 consecutive loads/stores of 4 SIMD vector registers:
440 //
441 // "StorageInterleavedByLane":
442 //
443 // Ptr+0:Reg0.x | Ptr+1:Reg0.y | Ptr+2:Reg0.z | Ptr+3:Reg0.w
444 // --------------+--------------+--------------+--------------
445 // Ptr+4:Reg1.x | Ptr+5:Reg1.y | Ptr+6:Reg1.z | Ptr+7:Reg1.w
446 // --------------+--------------+--------------+--------------
447 // Ptr+8:Reg2.x | Ptr+9:Reg2.y | Ptr+a:Reg2.z | Ptr+b:Reg2.w
448 // --------------+--------------+--------------+--------------
449 // Ptr+c:Reg3.x | Ptr+d:Reg3.y | Ptr+e:Reg3.z | Ptr+f:Reg3.w
450 //
451 // Not "StorageInterleavedByLane":
452 //
453 // Ptr+0:Reg0.x | Ptr+0:Reg0.y | Ptr+0:Reg0.z | Ptr+0:Reg0.w
454 // --------------+--------------+--------------+--------------
455 // Ptr+1:Reg1.x | Ptr+1:Reg1.y | Ptr+1:Reg1.z | Ptr+1:Reg1.w
456 // --------------+--------------+--------------+--------------
457 // Ptr+2:Reg2.x | Ptr+2:Reg2.y | Ptr+2:Reg2.z | Ptr+2:Reg2.w
458 // --------------+--------------+--------------+--------------
459 // Ptr+3:Reg3.x | Ptr+3:Reg3.y | Ptr+3:Reg3.z | Ptr+3:Reg3.w
460 //
461 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
462
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800463 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000464 int VisitInterfaceInner(Type::ID id, Decorations d, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800465
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800466 template<typename F>
Ben Claytonaf973b62019-03-13 18:19:20 +0000467 void VisitInterface(Object::ID id, F f) const;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800468
Ben Claytonaf973b62019-03-13 18:19:20 +0000469 uint32_t GetConstantInt(Object::ID id) const;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800470 Object& CreateConstant(InsnIterator it);
Chris Forbesbde34082018-12-28 12:03:10 -0800471
Chris Forbes049ff382019-02-02 15:16:43 -0800472 void ProcessInterfaceVariable(Object &object);
Chris Forbes38f85b32019-02-12 20:10:05 +0000473
Ben Claytonaf973b62019-03-13 18:19:20 +0000474 SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
475 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
Ben Claytond4e4c662019-02-26 11:54:34 +0000476
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000477 // Emit pass instructions:
478 void EmitVariable(InsnIterator insn, SpirvRoutine *routine) const;
479 void EmitLoad(InsnIterator insn, SpirvRoutine *routine) const;
480 void EmitStore(InsnIterator insn, SpirvRoutine *routine) const;
481 void EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const;
482 void EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const;
483 void EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const;
484 void EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const;
485 void EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const;
Chris Forbes856ebf82019-03-08 15:30:18 -0800486 void EmitVectorTimesScalar(InsnIterator insn, SpirvRoutine *routine) const;
Ben Claytondd1e37e2019-02-28 19:59:15 +0000487 void EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const;
488 void EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const;
Chris Forbes2b287cc2019-03-01 13:24:17 -0800489 void EmitDot(InsnIterator insn, SpirvRoutine *routine) const;
Ben Claytonbf943f62019-03-05 12:57:39 +0000490 void EmitSelect(InsnIterator insn, SpirvRoutine *routine) const;
Chris Forbes9667a5b2019-03-07 09:26:48 -0800491 void EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const;
Chris Forbes0785f692019-03-08 09:09:18 -0800492 void EmitAny(InsnIterator insn, SpirvRoutine *routine) const;
493 void EmitAll(InsnIterator insn, SpirvRoutine *routine) const;
Ben Claytone37ce612019-03-13 19:57:42 +0000494 void EmitBranch(InsnIterator insn, SpirvRoutine *routine) const;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000495
Ben Claytond4e4c662019-02-26 11:54:34 +0000496 // OpcodeName returns the name of the opcode op.
497 // If NDEBUG is defined, then OpcodeName will only return the numerical code.
498 static std::string OpcodeName(spv::Op op);
Chris Forbes868ed902019-03-13 17:39:45 -0700499
500 // Helper as we often need to take dot products as part of doing other things.
501 SIMD::Float Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const;
Chris Forbesaf4ed532018-12-06 18:33:27 -0800502 };
Ben Claytonab51bbf2019-02-20 14:36:27 +0000503
504 class SpirvRoutine
505 {
506 public:
Ben Clayton76e9bc02019-02-26 15:02:18 +0000507 SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
508
Ben Clayton24ea5152019-02-26 11:02:42 +0000509 using Value = Array<SIMD::Float>;
510
Ben Clayton76e9bc02019-02-26 15:02:18 +0000511 vk::PipelineLayout const * const pipelineLayout;
512
Ben Claytonaf973b62019-03-13 18:19:20 +0000513 std::unordered_map<SpirvShader::Object::ID, Value> lvalues;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000514
Ben Claytonaf973b62019-03-13 18:19:20 +0000515 std::unordered_map<SpirvShader::Object::ID, Intermediate> intermediates;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000516
Ben Claytonaf973b62019-03-13 18:19:20 +0000517 std::unordered_map<SpirvShader::Object::ID, Pointer<Byte> > physicalPointers;
Ben Clayton831db962019-02-27 14:57:18 +0000518
Ben Claytonab51bbf2019-02-20 14:36:27 +0000519 Value inputs = Value{MAX_INTERFACE_COMPONENTS};
520 Value outputs = Value{MAX_INTERFACE_COMPONENTS};
521
Ben Clayton49d81582019-03-12 20:05:04 +0000522 SIMD::Int activeLaneMask = SIMD::Int(0xFFFFFFFF);
523
Ben Clayton76e9bc02019-02-26 15:02:18 +0000524 std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets;
525
Ben Claytonaf973b62019-03-13 18:19:20 +0000526 void createLvalue(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000527 {
528 lvalues.emplace(id, Value(size));
529 }
530
Ben Claytonaf973b62019-03-13 18:19:20 +0000531 Intermediate& createIntermediate(SpirvShader::Object::ID id, uint32_t size)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000532 {
Chris Forbes928dfee2019-02-26 21:22:32 -0800533 auto it = intermediates.emplace(std::piecewise_construct,
Ben Claytonab51bbf2019-02-20 14:36:27 +0000534 std::forward_as_tuple(id),
535 std::forward_as_tuple(size));
Chris Forbes928dfee2019-02-26 21:22:32 -0800536 return it.first->second;
Ben Claytonab51bbf2019-02-20 14:36:27 +0000537 }
538
Ben Claytonaf973b62019-03-13 18:19:20 +0000539 Value& getValue(SpirvShader::Object::ID id)
Ben Claytonab51bbf2019-02-20 14:36:27 +0000540 {
541 auto it = lvalues.find(id);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000542 ASSERT(it != lvalues.end());
Ben Claytonab51bbf2019-02-20 14:36:27 +0000543 return it->second;
544 }
545
Ben Claytonaf973b62019-03-13 18:19:20 +0000546 Intermediate const& getIntermediate(SpirvShader::Object::ID id) const
Ben Claytonab51bbf2019-02-20 14:36:27 +0000547 {
548 auto it = intermediates.find(id);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000549 ASSERT(it != intermediates.end());
Ben Claytonab51bbf2019-02-20 14:36:27 +0000550 return it->second;
551 }
Ben Clayton831db962019-02-27 14:57:18 +0000552
Ben Claytonaf973b62019-03-13 18:19:20 +0000553 Pointer<Byte>& getPhysicalPointer(SpirvShader::Object::ID id)
Ben Clayton831db962019-02-27 14:57:18 +0000554 {
555 auto it = physicalPointers.find(id);
556 assert(it != physicalPointers.end());
557 return it->second;
558 }
Ben Claytonab51bbf2019-02-20 14:36:27 +0000559 };
560
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800561 class GenericValue
562 {
563 // Generic wrapper over either per-lane intermediate value, or a constant.
564 // Constants are transparently widened to per-lane values in operator[].
565 // This is appropriate in most cases -- if we're not going to do something
566 // significantly different based on whether the value is uniform across lanes.
567
568 SpirvShader::Object const &obj;
569 Intermediate const *intermediate;
570
571 public:
Ben Claytonaf973b62019-03-13 18:19:20 +0000572 GenericValue(SpirvShader const *shader, SpirvRoutine const *routine, SpirvShader::Object::ID objId) :
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800573 obj(shader->getObject(objId)),
574 intermediate(obj.kind == SpirvShader::Object::Kind::Value ? &routine->getIntermediate(objId) : nullptr) {}
575
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000576 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800577 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000578 if (intermediate != nullptr)
579 {
580 return intermediate->Float(i);
581 }
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800582 auto constantValue = reinterpret_cast<float *>(obj.constantValue.get());
Ben Clayton24ea5152019-02-26 11:02:42 +0000583 return RValue<SIMD::Float>(constantValue[i]);
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800584 }
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000585
586 RValue<SIMD::Int> Int(uint32_t i) const
587 {
588 return As<SIMD::Int>(Float(i));
589 }
590
591 RValue<SIMD::UInt> UInt(uint32_t i) const
592 {
593 return As<SIMD::UInt>(Float(i));
594 }
Chris Forbesd30b5ac2019-02-26 21:53:56 -0800595 };
596
Chris Forbesaf4ed532018-12-06 18:33:27 -0800597}
598
Chris Forbesc25b8072018-12-10 15:10:39 -0800599#endif // sw_SpirvShader_hpp