blob: e9876c714a6c0bd41d56e8659599293b70d46dcd [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
Nicolas Capens125dba02019-04-24 02:03:22 -040018#include "SamplerCore.hpp"
Ben Claytonbc1c067be2019-12-17 20:37:37 +000019#include "ShaderCore.hpp"
Ben Claytonab51bbf2019-02-20 14:36:27 +000020#include "SpirvID.hpp"
Nicolas Capens86509d92019-03-21 13:23:50 -040021#include "Device/Config.hpp"
Nicolas Capens9e735102019-04-18 15:03:06 -040022#include "Device/Sampler.hpp"
Ben Clayton25e06e02020-02-07 11:19:08 +000023#include "System/Debug.hpp"
Ben Claytonbc1c067be2019-12-17 20:37:37 +000024#include "System/Types.hpp"
25#include "Vulkan/VkConfig.h"
Ben Claytonbc1c067be2019-12-17 20:37:37 +000026#include "Vulkan/VkDescriptorSet.hpp"
Nicolas Capens86509d92019-03-21 13:23:50 -040027
28#include <spirv/unified1/spirv.hpp>
Chris Forbesaf4ed532018-12-06 18:33:27 -080029
Ben Clayton76e9bc02019-02-26 15:02:18 +000030#include <array>
Ben Claytonc42b2202019-05-22 11:18:14 +010031#include <atomic>
32#include <cstdint>
Ben Clayton6fae32c2019-02-28 20:06:42 +000033#include <cstring>
Ben Claytonbc1c067be2019-12-17 20:37:37 +000034#include <deque>
Ben Clayton49d81582019-03-12 20:05:04 +000035#include <functional>
Chris Forbesd5aed492019-02-02 15:18:52 -080036#include <memory>
Ben Claytonc42b2202019-05-22 11:18:14 +010037#include <string>
38#include <type_traits>
39#include <unordered_map>
40#include <unordered_set>
41#include <vector>
Chris Forbesaf4ed532018-12-06 18:33:27 -080042
Ben Claytonbc1c067be2019-12-17 20:37:37 +000043#undef Yield // b/127920555
Nicolas Capensd3545372019-08-09 13:59:18 -040044
Nicolas Capens157ba262019-12-10 17:49:14 -050045namespace vk {
Ben Clayton76e9bc02019-02-26 15:02:18 +000046
Nicolas Capens157ba262019-12-10 17:49:14 -050047class PipelineLayout;
48class ImageView;
49class Sampler;
50class RenderPass;
51struct SampledImageDescriptor;
Ben Clayton24ea5152019-02-26 11:02:42 +000052
Ben Clayton7d0ce412019-12-03 13:26:31 +000053namespace dbg {
54class Context;
55} // namespace dbg
56
Nicolas Capens157ba262019-12-10 17:49:14 -050057} // namespace vk
58
59namespace sw {
60
61// Forward declarations.
62class SpirvRoutine;
63
64// Incrementally constructed complex bundle of rvalues
65// Effectively a restricted vector, supporting only:
66// - allocation to a (runtime-known) fixed size
67// - in-place construction of elements
68// - const operator[]
69class Intermediate
70{
71public:
Ben Claytonbc1c067be2019-12-17 20:37:37 +000072 Intermediate(uint32_t size)
73 : scalar(new rr::Value *[size])
74 , size(size)
75 {
76 memset(scalar, 0, sizeof(rr::Value *) * size);
Nicolas Capens157ba262019-12-10 17:49:14 -050077 }
78
79 ~Intermediate()
80 {
81 delete[] scalar;
82 }
83
84 void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value); }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000085 void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value); }
86 void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value); }
Nicolas Capens157ba262019-12-10 17:49:14 -050087
88 void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value); }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000089 void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value); }
90 void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value); }
Nicolas Capens157ba262019-12-10 17:49:14 -050091
92 // Value retrieval functions.
93 RValue<SIMD::Float> Float(uint32_t i) const
94 {
95 ASSERT(i < size);
96 ASSERT(scalar[i] != nullptr);
97 return As<SIMD::Float>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Float>(scalar)
98 }
99
100 RValue<SIMD::Int> Int(uint32_t i) const
101 {
102 ASSERT(i < size);
103 ASSERT(scalar[i] != nullptr);
104 return As<SIMD::Int>(scalar[i]); // TODO(b/128539387): RValue<SIMD::Int>(scalar)
105 }
106
107 RValue<SIMD::UInt> UInt(uint32_t i) const
108 {
109 ASSERT(i < size);
110 ASSERT(scalar[i] != nullptr);
111 return As<SIMD::UInt>(scalar[i]); // TODO(b/128539387): RValue<SIMD::UInt>(scalar)
112 }
113
114 // No copy/move construction or assignment
115 Intermediate(Intermediate const &) = delete;
116 Intermediate(Intermediate &&) = delete;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000117 Intermediate &operator=(Intermediate const &) = delete;
118 Intermediate &operator=(Intermediate &&) = delete;
Nicolas Capens157ba262019-12-10 17:49:14 -0500119
120private:
121 void emplace(uint32_t i, rr::Value *value)
122 {
123 ASSERT(i < size);
124 ASSERT(scalar[i] == nullptr);
125 scalar[i] = value;
126 }
127
128 rr::Value **const scalar;
129 uint32_t size;
130};
131
132class SpirvShader
133{
134public:
135 using InsnStore = std::vector<uint32_t>;
136 InsnStore insns;
137
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000138 using ImageSampler = void(void *texture, void *sampler, void *uvsIn, void *texelOut, void *constants);
Nicolas Capens157ba262019-12-10 17:49:14 -0500139
140 enum class YieldResult
141 {
142 ControlBarrier,
143 };
144
145 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
146 class InsnIterator
147 {
148 InsnStore::const_iterator iter;
149
150 public:
151 spv::Op opcode() const
152 {
153 return static_cast<spv::Op>(*iter & spv::OpCodeMask);
154 }
155
156 uint32_t wordCount() const
157 {
158 return *iter >> spv::WordCountShift;
159 }
160
161 uint32_t word(uint32_t n) const
162 {
163 ASSERT(n < wordCount());
164 return iter[n];
165 }
166
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000167 uint32_t const *wordPointer(uint32_t n) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500168 {
169 ASSERT(n < wordCount());
170 return &iter[n];
171 }
172
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000173 const char *string(uint32_t n) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500174 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000175 return reinterpret_cast<const char *>(wordPointer(n));
Nicolas Capens157ba262019-12-10 17:49:14 -0500176 }
177
178 bool operator==(InsnIterator const &other) const
179 {
180 return iter == other.iter;
181 }
182
183 bool operator!=(InsnIterator const &other) const
184 {
185 return iter != other.iter;
186 }
187
188 InsnIterator operator*() const
189 {
190 return *this;
191 }
192
193 InsnIterator &operator++()
194 {
195 iter += wordCount();
196 return *this;
197 }
198
199 InsnIterator const operator++(int)
200 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000201 InsnIterator ret{ *this };
Nicolas Capens157ba262019-12-10 17:49:14 -0500202 iter += wordCount();
203 return ret;
204 }
205
206 InsnIterator(InsnIterator const &other) = default;
207
208 InsnIterator() = default;
209
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000210 explicit InsnIterator(InsnStore::const_iterator iter)
211 : iter{ iter }
Nicolas Capens157ba262019-12-10 17:49:14 -0500212 {
213 }
214 };
215
216 /* range-based-for interface */
217 InsnIterator begin() const
218 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000219 return InsnIterator{ insns.cbegin() + 5 };
Nicolas Capens157ba262019-12-10 17:49:14 -0500220 }
221
222 InsnIterator end() const
223 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000224 return InsnIterator{ insns.cend() };
Nicolas Capens157ba262019-12-10 17:49:14 -0500225 }
226
227 class Type
Chris Forbese4ef5f72019-02-15 16:00:08 -0800228 {
229 public:
Nicolas Capens157ba262019-12-10 17:49:14 -0500230 using ID = SpirvID<Type>;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800231
Nicolas Capens157ba262019-12-10 17:49:14 -0500232 spv::Op opcode() const { return definition.opcode(); }
233
234 InsnIterator definition;
235 spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
236 uint32_t sizeInComponents = 0;
237 bool isBuiltInBlock = false;
238
239 // Inner element type for pointers, arrays, vectors and matrices.
240 ID element;
241 };
242
243 class Object
244 {
245 public:
246 using ID = SpirvID<Object>;
247
248 spv::Op opcode() const { return definition.opcode(); }
249
250 InsnIterator definition;
251 Type::ID type;
252 std::unique_ptr<uint32_t[]> constantValue = nullptr;
253
254 enum class Kind
Chris Forbese4ef5f72019-02-15 16:00:08 -0800255 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500256 // Invalid default kind.
257 // If we get left with an object in this state, the module was
258 // broken.
259 Unknown,
260
261 // TODO: Better document this kind.
262 // A shader interface variable pointer.
263 // Pointer with uniform address across all lanes.
264 // Pointer held by SpirvRoutine::pointers
265 InterfaceVariable,
266
267 // Constant value held by Object::constantValue.
268 Constant,
269
270 // Value held by SpirvRoutine::intermediates.
271 Intermediate,
272
273 // Pointer held by SpirvRoutine::pointers
274 Pointer,
275
276 // A pointer to a vk::DescriptorSet*.
277 // Pointer held by SpirvRoutine::pointers.
278 DescriptorSet,
279 };
280
281 Kind kind = Kind::Unknown;
282 };
283
284 // Block is an interval of SPIR-V instructions, starting with the
285 // opening OpLabel, and ending with a termination instruction.
286 class Block
287 {
288 public:
289 using ID = SpirvID<Block>;
290 using Set = std::unordered_set<ID>;
291
292 // Edge represents the graph edge between two blocks.
293 struct Edge
294 {
295 ID from;
296 ID to;
297
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000298 bool operator==(const Edge &other) const { return from == other.from && to == other.to; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500299
300 struct Hash
301 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000302 std::size_t operator()(const Edge &edge) const noexcept
Nicolas Capens157ba262019-12-10 17:49:14 -0500303 {
304 return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value());
305 }
306 };
307 };
308
309 Block() = default;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000310 Block(const Block &other) = default;
Nicolas Capens157ba262019-12-10 17:49:14 -0500311 explicit Block(InsnIterator begin, InsnIterator end);
312
313 /* range-based-for interface */
314 inline InsnIterator begin() const { return begin_; }
315 inline InsnIterator end() const { return end_; }
316
317 enum Kind
318 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000319 Simple, // OpBranch or other simple terminator.
320 StructuredBranchConditional, // OpSelectionMerge + OpBranchConditional
321 UnstructuredBranchConditional, // OpBranchConditional
322 StructuredSwitch, // OpSelectionMerge + OpSwitch
323 UnstructuredSwitch, // OpSwitch
324 Loop, // OpLoopMerge + [OpBranchConditional | OpBranch]
Nicolas Capens157ba262019-12-10 17:49:14 -0500325 };
326
327 Kind kind = Simple;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000328 InsnIterator mergeInstruction; // Structured control flow merge instruction.
329 InsnIterator branchInstruction; // Branch instruction.
330 ID mergeBlock; // Structured flow merge block.
331 ID continueTarget; // Loop continue block.
332 Set ins; // Blocks that branch into this block.
333 Set outs; // Blocks that this block branches to.
Nicolas Capens157ba262019-12-10 17:49:14 -0500334 bool isLoopMerge = false;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000335
Nicolas Capens157ba262019-12-10 17:49:14 -0500336 private:
337 InsnIterator begin_;
338 InsnIterator end_;
339 };
340
341 class Function
342 {
343 public:
344 using ID = SpirvID<Function>;
345
346 // Walks all reachable the blocks starting from id adding them to
347 // reachable.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000348 void TraverseReachableBlocks(Block::ID id, Block::Set &reachable) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500349
350 // AssignBlockFields() performs the following for all reachable blocks:
351 // * Assigns Block::ins with the identifiers of all blocks that contain
352 // this block in their Block::outs.
353 // * Sets Block::isLoopMerge to true if the block is the merge of a
354 // another loop block.
355 void AssignBlockFields();
356
357 // ForeachBlockDependency calls f with each dependency of the given
358 // block. A dependency is an incoming block that is not a loop-back
359 // edge.
360 void ForeachBlockDependency(Block::ID blockId, std::function<void(Block::ID)> f) const;
361
362 // ExistsPath returns true if there's a direct or indirect flow from
363 // the 'from' block to the 'to' block that does not pass through
364 // notPassingThrough.
365 bool ExistsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const;
366
367 Block const &getBlock(Block::ID id) const
368 {
369 auto it = blocks.find(id);
370 ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value());
371 return it->second;
Chris Forbese4ef5f72019-02-15 16:00:08 -0800372 }
373
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000374 Block::ID entry; // function entry point block.
375 HandleMap<Block> blocks; // blocks belonging to this function.
376 Type::ID type; // type of the function.
377 Type::ID result; // return type.
Nicolas Capens157ba262019-12-10 17:49:14 -0500378 };
Chris Forbese4ef5f72019-02-15 16:00:08 -0800379
Ben Clayton9c8823a2020-01-08 12:07:30 +0000380 using String = std::string;
381 using StringID = SpirvID<std::string>;
382
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000383 class Extension
384 {
385 public:
386 using ID = SpirvID<Extension>;
387
388 enum Name
389 {
390 Unknown,
391 GLSLstd450,
Ben Claytoncd55f052020-01-14 11:56:00 +0000392 OpenCLDebugInfo100
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000393 };
394
395 Name name;
396 };
397
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000398 struct TypeOrObject
399 {}; // Dummy struct to represent a Type or Object.
Ben Clayton093be462019-03-08 08:37:24 +0000400
Nicolas Capens157ba262019-12-10 17:49:14 -0500401 // TypeOrObjectID is an identifier that represents a Type or an Object,
402 // and supports implicit casting to and from Type::ID or Object::ID.
403 class TypeOrObjectID : public SpirvID<TypeOrObject>
404 {
405 public:
406 using Hash = std::hash<SpirvID<TypeOrObject>>;
407
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000408 inline TypeOrObjectID(uint32_t id)
409 : SpirvID(id)
410 {}
411 inline TypeOrObjectID(Type::ID id)
412 : SpirvID(id.value())
413 {}
414 inline TypeOrObjectID(Object::ID id)
415 : SpirvID(id.value())
416 {}
Nicolas Capens157ba262019-12-10 17:49:14 -0500417 inline operator Type::ID() const { return Type::ID(value()); }
418 inline operator Object::ID() const { return Object::ID(value()); }
419 };
420
421 // OpImageSample variants
422 enum Variant
423 {
424 None, // No Dref or Proj. Also used by OpImageFetch and OpImageQueryLod.
425 Dref,
426 Proj,
427 ProjDref,
428 VARIANT_LAST = ProjDref
429 };
430
431 // Compact representation of image instruction parameters that is passed to the
432 // trampoline function for retrieving/generating the corresponding sampling routine.
433 struct ImageInstruction
434 {
435 ImageInstruction(Variant variant, SamplerMethod samplerMethod)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000436 : parameters(0)
Nicolas Capens157ba262019-12-10 17:49:14 -0500437 {
438 this->variant = variant;
439 this->samplerMethod = samplerMethod;
440 }
441
442 // Unmarshal from raw 32-bit data
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000443 ImageInstruction(uint32_t parameters)
444 : parameters(parameters)
445 {}
Nicolas Capens157ba262019-12-10 17:49:14 -0500446
447 SamplerFunction getSamplerFunction() const
448 {
449 return { static_cast<SamplerMethod>(samplerMethod), offset != 0, sample != 0 };
450 }
451
452 bool isDref() const
453 {
454 return (variant == Dref) || (variant == ProjDref);
455 }
456
457 bool isProj() const
458 {
459 return (variant == Proj) || (variant == ProjDref);
460 }
461
462 union
463 {
464 struct
465 {
466 uint32_t variant : BITS(VARIANT_LAST);
467 uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST);
468 uint32_t gatherComponent : 2;
469
470 // Parameters are passed to the sampling routine in this order:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000471 uint32_t coordinates : 3; // 1-4 (does not contain projection component)
472 // uint32_t dref : 1; // Indicated by Variant::ProjDref|Dref
473 // uint32_t lodOrBias : 1; // Indicated by SamplerMethod::Lod|Bias|Fetch
474 uint32_t grad : 2; // 0-3 components (for each of dx / dy)
475 uint32_t offset : 2; // 0-3 components
476 uint32_t sample : 1; // 0-1 scalar integer
Nicolas Capens157ba262019-12-10 17:49:14 -0500477 };
478
479 uint32_t parameters;
480 };
481 };
482
483 static_assert(sizeof(ImageInstruction) == sizeof(uint32_t), "ImageInstruction must be 32-bit");
484
485 // This method is for retrieving an ID that uniquely identifies the
486 // shader entry point represented by this object.
487 uint64_t getSerialID() const
488 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000489 return ((uint64_t)entryPoint.value() << 32) | codeSerialID;
Nicolas Capens157ba262019-12-10 17:49:14 -0500490 }
491
492 SpirvShader(uint32_t codeSerialID,
493 VkShaderStageFlagBits stage,
494 const char *entryPointName,
495 InsnStore const &insns,
496 const vk::RenderPass *renderPass,
497 uint32_t subpassIndex,
Ben Clayton7d0ce412019-12-03 13:26:31 +0000498 bool robustBufferAccess,
499 const std::shared_ptr<vk::dbg::Context> &dbgctx);
Nicolas Capens157ba262019-12-10 17:49:14 -0500500
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000501 ~SpirvShader();
502
Nicolas Capens157ba262019-12-10 17:49:14 -0500503 struct Modes
504 {
505 bool EarlyFragmentTests : 1;
506 bool DepthReplacing : 1;
507 bool DepthGreater : 1;
508 bool DepthLess : 1;
509 bool DepthUnchanged : 1;
510 bool ContainsKill : 1;
511 bool ContainsControlBarriers : 1;
512 bool NeedsCentroid : 1;
513
514 // Compute workgroup dimensions
515 int WorkgroupSizeX = 1, WorkgroupSizeY = 1, WorkgroupSizeZ = 1;
516 };
517
518 Modes const &getModes() const
519 {
520 return modes;
521 }
522
523 struct Capabilities
524 {
525 bool Matrix : 1;
526 bool Shader : 1;
527 bool ClipDistance : 1;
528 bool CullDistance : 1;
529 bool InputAttachment : 1;
530 bool Sampled1D : 1;
531 bool Image1D : 1;
532 bool ImageCubeArray : 1;
533 bool SampledBuffer : 1;
534 bool SampledCubeArray : 1;
535 bool ImageBuffer : 1;
536 bool StorageImageExtendedFormats : 1;
537 bool ImageQuery : 1;
538 bool DerivativeControl : 1;
539 bool GroupNonUniform : 1;
540 bool GroupNonUniformVote : 1;
541 bool GroupNonUniformBallot : 1;
542 bool GroupNonUniformShuffle : 1;
543 bool GroupNonUniformShuffleRelative : 1;
544 bool GroupNonUniformArithmetic : 1;
545 bool DeviceGroup : 1;
546 bool MultiView : 1;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500547 bool StencilExportEXT : 1;
Nicolas Capens157ba262019-12-10 17:49:14 -0500548 };
549
550 Capabilities const &getUsedCapabilities() const
551 {
552 return capabilities;
553 }
554
555 // getNumOutputClipDistances() returns the number of ClipDistances
556 // outputted by this shader.
557 unsigned int getNumOutputClipDistances() const
558 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500559 if(getUsedCapabilities().ClipDistance)
Nicolas Capens157ba262019-12-10 17:49:14 -0500560 {
561 auto it = outputBuiltins.find(spv::BuiltInClipDistance);
562 if(it != outputBuiltins.end())
563 {
564 return it->second.SizeInComponents;
565 }
566 }
567 return 0;
568 }
569
570 // getNumOutputCullDistances() returns the number of CullDistances
571 // outputted by this shader.
572 unsigned int getNumOutputCullDistances() const
573 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500574 if(getUsedCapabilities().CullDistance)
Nicolas Capens157ba262019-12-10 17:49:14 -0500575 {
576 auto it = outputBuiltins.find(spv::BuiltInCullDistance);
577 if(it != outputBuiltins.end())
578 {
579 return it->second.SizeInComponents;
580 }
581 }
582 return 0;
583 }
584
585 enum AttribType : unsigned char
586 {
587 ATTRIBTYPE_FLOAT,
588 ATTRIBTYPE_INT,
589 ATTRIBTYPE_UINT,
590 ATTRIBTYPE_UNUSED,
591
592 ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
593 };
594
595 bool hasBuiltinInput(spv::BuiltIn b) const
596 {
597 return inputBuiltins.find(b) != inputBuiltins.end();
598 }
599
600 bool hasBuiltinOutput(spv::BuiltIn b) const
601 {
602 return outputBuiltins.find(b) != outputBuiltins.end();
603 }
604
605 struct Decorations
606 {
607 int32_t Location = -1;
608 int32_t Component = 0;
609 spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1);
610 int32_t Offset = -1;
611 int32_t ArrayStride = -1;
612 int32_t MatrixStride = 1;
613
614 bool HasLocation : 1;
615 bool HasComponent : 1;
616 bool HasBuiltIn : 1;
617 bool HasOffset : 1;
618 bool HasArrayStride : 1;
619 bool HasMatrixStride : 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000620 bool HasRowMajor : 1; // whether RowMajor bit is valid.
Nicolas Capens157ba262019-12-10 17:49:14 -0500621
622 bool Flat : 1;
623 bool Centroid : 1;
624 bool NoPerspective : 1;
625 bool Block : 1;
626 bool BufferBlock : 1;
627 bool RelaxedPrecision : 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000628 bool RowMajor : 1; // RowMajor if true; ColMajor if false
629 bool InsideMatrix : 1; // pseudo-decoration for whether we're inside a matrix.
Nicolas Capens157ba262019-12-10 17:49:14 -0500630
631 Decorations()
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000632 : Location{ -1 }
633 , Component{ 0 }
634 , BuiltIn{ static_cast<spv::BuiltIn>(-1) }
635 , Offset{ -1 }
636 , ArrayStride{ -1 }
637 , MatrixStride{ -1 }
638 , HasLocation{ false }
639 , HasComponent{ false }
640 , HasBuiltIn{ false }
641 , HasOffset{ false }
642 , HasArrayStride{ false }
643 , HasMatrixStride{ false }
644 , HasRowMajor{ false }
645 , Flat{ false }
646 , Centroid{ false }
647 , NoPerspective{ false }
648 , Block{ false }
649 , BufferBlock{ false }
650 , RelaxedPrecision{ false }
651 , RowMajor{ false }
652 , InsideMatrix{ false }
Nicolas Capens157ba262019-12-10 17:49:14 -0500653 {
654 }
655
656 Decorations(Decorations const &) = default;
657
658 void Apply(Decorations const &src);
659
660 void Apply(spv::Decoration decoration, uint32_t arg);
661 };
662
663 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
664 std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations;
665
666 struct DescriptorDecorations
667 {
668 int32_t DescriptorSet = -1;
669 int32_t Binding = -1;
670 int32_t InputAttachmentIndex = -1;
671
672 void Apply(DescriptorDecorations const &src);
673 };
674
675 std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
676 std::vector<VkFormat> inputAttachmentFormats;
677
678 struct InterfaceComponent
679 {
680 AttribType Type;
681
682 union
683 {
684 struct
685 {
686 bool Flat : 1;
687 bool Centroid : 1;
688 bool NoPerspective : 1;
689 };
690
691 uint8_t DecorationBits;
692 };
693
694 InterfaceComponent()
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000695 : Type{ ATTRIBTYPE_UNUSED }
696 , DecorationBits{ 0 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500697 {
698 }
699 };
700
701 struct BuiltinMapping
702 {
703 Object::ID Id;
704 uint32_t FirstComponent;
705 uint32_t SizeInComponents;
706 };
707
708 struct WorkgroupMemory
709 {
710 // allocates a new variable of size bytes with the given identifier.
711 inline void allocate(Object::ID id, uint32_t size)
712 {
713 uint32_t offset = totalSize;
714 auto it = offsets.emplace(id, offset);
715 ASSERT_MSG(it.second, "WorkgroupMemory already has an allocation for object %d", int(id.value()));
716 totalSize += size;
717 }
718 // returns the byte offset of the variable with the given identifier.
719 inline uint32_t offsetOf(Object::ID id) const
720 {
721 auto it = offsets.find(id);
722 ASSERT_MSG(it != offsets.end(), "WorkgroupMemory has no allocation for object %d", int(id.value()));
723 return it->second;
724 }
725 // returns the total allocated size in bytes.
726 inline uint32_t size() const { return totalSize; }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000727
Nicolas Capens157ba262019-12-10 17:49:14 -0500728 private:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000729 uint32_t totalSize = 0; // in bytes
730 std::unordered_map<Object::ID, uint32_t> offsets; // in bytes
Nicolas Capens157ba262019-12-10 17:49:14 -0500731 };
732
733 std::vector<InterfaceComponent> inputs;
734 std::vector<InterfaceComponent> outputs;
735
736 void emitProlog(SpirvRoutine *routine) const;
737 void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets) const;
738 void emitEpilog(SpirvRoutine *routine) const;
739
740 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
741 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
742 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
743 WorkgroupMemory workgroupMemory;
744
745private:
746 const uint32_t codeSerialID;
747 Modes modes = {};
748 Capabilities capabilities = {};
749 HandleMap<Type> types;
750 HandleMap<Object> defs;
751 HandleMap<Function> functions;
Ben Clayton9c8823a2020-01-08 12:07:30 +0000752 std::unordered_map<StringID, String> strings;
Ben Clayton8842c8f2020-01-13 16:57:48 +0000753 HandleMap<Extension> extensionsByID;
754 std::unordered_set<Extension::Name> extensionsImported;
Nicolas Capens157ba262019-12-10 17:49:14 -0500755 Function::ID entryPoint;
756
757 const bool robustBufferAccess = true;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000758 spv::ExecutionModel executionModel = spv::ExecutionModelMax; // Invalid prior to OpEntryPoint parsing.
Nicolas Capens157ba262019-12-10 17:49:14 -0500759
760 // DeclareType creates a Type for the given OpTypeX instruction, storing
761 // it into the types map. It is called from the analysis pass (constructor).
762 void DeclareType(InsnIterator insn);
763
764 void ProcessExecutionMode(InsnIterator it);
765
766 uint32_t ComputeTypeSize(InsnIterator insn);
767 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
768 void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const;
769 void ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const;
770
771 // Creates an Object for the instruction's result in 'defs'.
772 void DefineResult(const InsnIterator &insn);
773
Ben Claytoncd55f052020-01-14 11:56:00 +0000774 // Processes the OpenCL.Debug.100 instruction for the initial definition
775 // pass of the SPIR-V.
776 void DefineOpenCLDebugInfo100(const InsnIterator &insn);
777
Nicolas Capens157ba262019-12-10 17:49:14 -0500778 // Returns true if data in the given storage class is word-interleaved
779 // by each SIMD vector lane, otherwise data is stored linerally.
780 //
781 // Each lane addresses a single word, picked by a base pointer and an
782 // integer offset.
783 //
784 // A word is currently 32 bits (single float, int32_t, uint32_t).
785 // A lane is a single element of a SIMD vector register.
786 //
787 // Storage interleaved by lane - (IsStorageInterleavedByLane() == true):
788 // ---------------------------------------------------------------------
789 //
790 // Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex)
791 //
792 // Assuming SIMD::Width == 4:
793 //
794 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
795 // ===========+===========+===========+==========
796 // LaneOffset=0: | Word[0] | Word[1] | Word[2] | Word[3]
797 // ---------------+-----------+-----------+-----------+----------
798 // LaneOffset=1: | Word[4] | Word[5] | Word[6] | Word[7]
799 // ---------------+-----------+-----------+-----------+----------
800 // LaneOffset=2: | Word[8] | Word[9] | Word[a] | Word[b]
801 // ---------------+-----------+-----------+-----------+----------
802 // LaneOffset=3: | Word[c] | Word[d] | Word[e] | Word[f]
803 //
804 //
805 // Linear storage - (IsStorageInterleavedByLane() == false):
806 // ---------------------------------------------------------
807 //
808 // Address = PtrBase + sizeof(Word) * LaneOffset
809 //
810 // Lane[0] | Lane[1] | Lane[2] | Lane[3]
811 // ===========+===========+===========+==========
812 // LaneOffset=0: | Word[0] | Word[0] | Word[0] | Word[0]
813 // ---------------+-----------+-----------+-----------+----------
814 // LaneOffset=1: | Word[1] | Word[1] | Word[1] | Word[1]
815 // ---------------+-----------+-----------+-----------+----------
816 // LaneOffset=2: | Word[2] | Word[2] | Word[2] | Word[2]
817 // ---------------+-----------+-----------+-----------+----------
818 // LaneOffset=3: | Word[3] | Word[3] | Word[3] | Word[3]
819 //
820 static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
821 static bool IsExplicitLayout(spv::StorageClass storageClass);
822
823 static sw::SIMD::Pointer InterleaveByLane(sw::SIMD::Pointer p);
824
825 // Output storage buffers and images should not be affected by helper invocations
826 static bool StoresInHelperInvocation(spv::StorageClass storageClass);
827
828 using InterfaceVisitor = std::function<void(Decorations const, AttribType)>;
829
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000830 void VisitInterface(Object::ID id, const InterfaceVisitor &v) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500831
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000832 int VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &v) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500833
834 // MemoryElement describes a scalar element within a structure, and is
835 // used by the callback function of VisitMemoryObject().
836 struct MemoryElement
837 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000838 uint32_t index; // index of the scalar element
839 uint32_t offset; // offset (in bytes) from the base of the object
840 const Type &type; // element type
Nicolas Capens157ba262019-12-10 17:49:14 -0500841 };
842
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000843 using MemoryVisitor = std::function<void(const MemoryElement &)>;
Nicolas Capens157ba262019-12-10 17:49:14 -0500844
845 // VisitMemoryObject() walks a type tree in an explicitly laid out
846 // storage class, calling the MemoryVisitor for each scalar element
847 // within the
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000848 void VisitMemoryObject(Object::ID id, const MemoryVisitor &v) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500849
850 // VisitMemoryObjectInner() is internally called by VisitMemoryObject()
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000851 void VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, const MemoryVisitor &v) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500852
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000853 Object &CreateConstant(InsnIterator it);
Nicolas Capens157ba262019-12-10 17:49:14 -0500854
855 void ProcessInterfaceVariable(Object &object);
856
857 // EmitState holds control-flow state for the emit() pass.
858 class EmitState
859 {
860 public:
861 EmitState(SpirvRoutine *routine,
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000862 Function::ID function,
863 RValue<SIMD::Int> activeLaneMask,
864 RValue<SIMD::Int> storesAndAtomicsMask,
865 const vk::DescriptorSet::Bindings &descriptorSets,
866 bool robustBufferAccess,
867 spv::ExecutionModel executionModel)
868 : routine(routine)
869 , function(function)
870 , activeLaneMaskValue(activeLaneMask.value)
871 , storesAndAtomicsMaskValue(storesAndAtomicsMask.value)
872 , descriptorSets(descriptorSets)
873 , robustBufferAccess(robustBufferAccess)
874 , executionModel(executionModel)
Nicolas Capens157ba262019-12-10 17:49:14 -0500875 {
876 ASSERT(executionModelToStage(executionModel) != VkShaderStageFlagBits(0)); // Must parse OpEntryPoint before emitting.
877 }
878
879 RValue<SIMD::Int> activeLaneMask() const
880 {
881 ASSERT(activeLaneMaskValue != nullptr);
882 return RValue<SIMD::Int>(activeLaneMaskValue);
883 }
884
885 RValue<SIMD::Int> storesAndAtomicsMask() const
886 {
887 ASSERT(storesAndAtomicsMaskValue != nullptr);
888 return RValue<SIMD::Int>(storesAndAtomicsMaskValue);
889 }
890
Nicolas Capens157ba262019-12-10 17:49:14 -0500891 // Add a new active lane mask edge from the current block to out.
892 // The edge mask value will be (mask AND activeLaneMaskValue).
893 // If multiple active lane masks are added for the same edge, then
894 // they will be ORed together.
895 void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask);
896
897 // Add a new active lane mask for the edge from -> to.
898 // If multiple active lane masks are added for the same edge, then
899 // they will be ORed together.
900 void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask);
901
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000902 SpirvRoutine *routine = nullptr; // The current routine being built.
903 Function::ID function; // The current function being built.
904 Block::ID block; // The current block being built.
905 rr::Value *activeLaneMaskValue = nullptr; // The current active lane mask.
906 rr::Value *storesAndAtomicsMaskValue = nullptr; // The current atomics mask.
907 Block::Set visited; // Blocks already built.
Nicolas Capens157ba262019-12-10 17:49:14 -0500908 std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks;
909 std::deque<Block::ID> *pending;
910
911 const vk::DescriptorSet::Bindings &descriptorSets;
912
913 OutOfBoundsBehavior getOutOfBoundsBehavior(spv::StorageClass storageClass) const;
914
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000915 Intermediate &createIntermediate(Object::ID id, uint32_t size)
Nicolas Capens157ba262019-12-10 17:49:14 -0500916 {
917 auto it = intermediates.emplace(std::piecewise_construct,
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000918 std::forward_as_tuple(id),
919 std::forward_as_tuple(size));
Nicolas Capens157ba262019-12-10 17:49:14 -0500920 ASSERT_MSG(it.second, "Intermediate %d created twice", id.value());
921 return it.first->second;
922 }
923
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000924 Intermediate const &getIntermediate(Object::ID id) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500925 {
926 auto it = intermediates.find(id);
927 ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value());
928 return it->second;
929 }
930
931 void createPointer(Object::ID id, SIMD::Pointer ptr)
932 {
933 bool added = pointers.emplace(id, ptr).second;
934 ASSERT_MSG(added, "Pointer %d created twice", id.value());
935 }
936
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000937 SIMD::Pointer const &getPointer(Object::ID id) const
Nicolas Capens157ba262019-12-10 17:49:14 -0500938 {
939 auto it = pointers.find(id);
940 ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());
941 return it->second;
942 }
943
944 private:
945 std::unordered_map<Object::ID, Intermediate> intermediates;
946 std::unordered_map<Object::ID, SIMD::Pointer> pointers;
947
948 const bool robustBufferAccess = true; // Emit robustBufferAccess safe code.
949 const spv::ExecutionModel executionModel = spv::ExecutionModelMax;
950 };
951
952 // EmitResult is an enumerator of result values from the Emit functions.
953 enum class EmitResult
954 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000955 Continue, // No termination instructions.
956 Terminator, // Reached a termination instruction.
Nicolas Capens157ba262019-12-10 17:49:14 -0500957 };
958
959 // Generic wrapper over either per-lane intermediate value, or a constant.
960 // Constants are transparently widened to per-lane values in operator[].
961 // This is appropriate in most cases -- if we're not going to do something
962 // significantly different based on whether the value is uniform across lanes.
963 class GenericValue
964 {
965 SpirvShader::Object const &obj;
966 Intermediate const *intermediate;
967
968 public:
969 GenericValue(SpirvShader const *shader, EmitState const *state, SpirvShader::Object::ID objId);
970
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000971 RValue<SIMD::Float> Float(uint32_t i) const
Chris Forbese4ef5f72019-02-15 16:00:08 -0800972 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500973 if(intermediate)
Nicolas Capens157ba262019-12-10 17:49:14 -0500974 {
975 return intermediate->Float(i);
976 }
977
978 // Constructing a constant SIMD::Float is not guaranteed to preserve the data's exact
979 // bit pattern, but SPIR-V provides 32-bit words representing "the bit pattern for the constant".
980 // Thus we must first construct an integer constant, and bitcast to float.
Chris Forbes10a900e2019-12-20 10:24:10 -0800981 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
Nicolas Capens157ba262019-12-10 17:49:14 -0500982 auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get());
983 return As<SIMD::Float>(SIMD::UInt(constantValue[i]));
Chris Forbese4ef5f72019-02-15 16:00:08 -0800984 }
Nicolas Capens5851ef42019-03-19 14:28:18 -0400985
986 RValue<SIMD::Int> Int(uint32_t i) const
987 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500988 if(intermediate)
Nicolas Capens157ba262019-12-10 17:49:14 -0500989 {
990 return intermediate->Int(i);
991 }
Chris Forbes10a900e2019-12-20 10:24:10 -0800992 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
Nicolas Capens157ba262019-12-10 17:49:14 -0500993 auto constantValue = reinterpret_cast<int *>(obj.constantValue.get());
994 return SIMD::Int(constantValue[i]);
Nicolas Capens5851ef42019-03-19 14:28:18 -0400995 }
996
997 RValue<SIMD::UInt> UInt(uint32_t i) const
998 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500999 if(intermediate)
Nicolas Capens157ba262019-12-10 17:49:14 -05001000 {
1001 return intermediate->UInt(i);
1002 }
Chris Forbes10a900e2019-12-20 10:24:10 -08001003 ASSERT(obj.kind == SpirvShader::Object::Kind::Constant);
Nicolas Capens157ba262019-12-10 17:49:14 -05001004 auto constantValue = reinterpret_cast<uint32_t *>(obj.constantValue.get());
1005 return SIMD::UInt(constantValue[i]);
Nicolas Capens5851ef42019-03-19 14:28:18 -04001006 }
Chris Forbese4ef5f72019-02-15 16:00:08 -08001007
Nicolas Capens157ba262019-12-10 17:49:14 -05001008 SpirvShader::Type::ID const type;
Chris Forbese4ef5f72019-02-15 16:00:08 -08001009 };
1010
Nicolas Capens157ba262019-12-10 17:49:14 -05001011 Type const &getType(Type::ID id) const
Chris Forbesaf4ed532018-12-06 18:33:27 -08001012 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001013 auto it = types.find(id);
1014 ASSERT_MSG(it != types.end(), "Unknown type %d", id.value());
1015 return it->second;
1016 }
Chris Forbesaf4ed532018-12-06 18:33:27 -08001017
Nicolas Capens157ba262019-12-10 17:49:14 -05001018 Object const &getObject(Object::ID id) const
Ben Claytonab51bbf2019-02-20 14:36:27 +00001019 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001020 auto it = defs.find(id);
1021 ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value());
1022 return it->second;
1023 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001024
Nicolas Capens157ba262019-12-10 17:49:14 -05001025 Function const &getFunction(Function::ID id) const
1026 {
1027 auto it = functions.find(id);
1028 ASSERT_MSG(it != functions.end(), "Unknown function %d", id.value());
1029 return it->second;
1030 }
Ben Clayton24ea5152019-02-26 11:02:42 +00001031
Ben Clayton9c8823a2020-01-08 12:07:30 +00001032 String const &getString(StringID id) const
1033 {
1034 auto it = strings.find(id);
1035 ASSERT_MSG(it != strings.end(), "Unknown string %d", id.value());
1036 return it->second;
1037 }
1038
Ben Claytonb36dbbe2020-01-08 12:18:43 +00001039 Extension const &getExtension(Extension::ID id) const
1040 {
Ben Clayton8842c8f2020-01-13 16:57:48 +00001041 auto it = extensionsByID.find(id);
1042 ASSERT_MSG(it != extensionsByID.end(), "Unknown extension %d", id.value());
Ben Claytonb36dbbe2020-01-08 12:18:43 +00001043 return it->second;
1044 }
1045
Nicolas Capens157ba262019-12-10 17:49:14 -05001046 // Returns a SIMD::Pointer to the underlying data for the given pointer
1047 // object.
1048 // Handles objects of the following kinds:
1049 // • DescriptorSet
1050 // • DivergentPointer
1051 // • InterfaceVariable
1052 // • NonDivergentPointer
1053 // Calling GetPointerToData with objects of any other kind will assert.
1054 SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, EmitState const *state) const;
Ben Clayton204a4102019-07-31 13:17:47 +01001055
Nicolas Capens157ba262019-12-10 17:49:14 -05001056 SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const;
1057 SIMD::Pointer WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const;
Ben Clayton76e9bc02019-02-26 15:02:18 +00001058
Nicolas Capens157ba262019-12-10 17:49:14 -05001059 // Returns the *component* offset in the literal for the given access chain.
1060 uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001061
Nicolas Capens157ba262019-12-10 17:49:14 -05001062 // Lookup the active lane mask for the edge from -> to.
1063 // If from is unreachable, then a mask of all zeros is returned.
1064 // Asserts if from is reachable and the edge does not exist.
1065 RValue<SIMD::Int> GetActiveLaneMaskEdge(EmitState *state, Block::ID from, Block::ID to) const;
Ben Clayton76e9bc02019-02-26 15:02:18 +00001066
Ben Clayton8a7067d2020-01-08 12:30:06 +00001067 // Updates the current active lane mask.
1068 void SetActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const;
1069
Nicolas Capens157ba262019-12-10 17:49:14 -05001070 // Emit all the unvisited blocks (except for ignore) in DFS order,
1071 // starting with id.
1072 void EmitBlocks(Block::ID id, EmitState *state, Block::ID ignore = 0) const;
1073 void EmitNonLoop(EmitState *state) const;
1074 void EmitLoop(EmitState *state) const;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001075
Nicolas Capens157ba262019-12-10 17:49:14 -05001076 void EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const;
1077 EmitResult EmitInstruction(InsnIterator insn, EmitState *state) const;
Ben Claytonea3cd1b2019-06-19 21:43:55 +01001078
Nicolas Capens157ba262019-12-10 17:49:14 -05001079 // Emit pass instructions:
1080 EmitResult EmitVariable(InsnIterator insn, EmitState *state) const;
1081 EmitResult EmitLoad(InsnIterator insn, EmitState *state) const;
1082 EmitResult EmitStore(InsnIterator insn, EmitState *state) const;
1083 EmitResult EmitAccessChain(InsnIterator insn, EmitState *state) const;
1084 EmitResult EmitCompositeConstruct(InsnIterator insn, EmitState *state) const;
1085 EmitResult EmitCompositeInsert(InsnIterator insn, EmitState *state) const;
1086 EmitResult EmitCompositeExtract(InsnIterator insn, EmitState *state) const;
1087 EmitResult EmitVectorShuffle(InsnIterator insn, EmitState *state) const;
1088 EmitResult EmitVectorTimesScalar(InsnIterator insn, EmitState *state) const;
1089 EmitResult EmitMatrixTimesVector(InsnIterator insn, EmitState *state) const;
1090 EmitResult EmitVectorTimesMatrix(InsnIterator insn, EmitState *state) const;
1091 EmitResult EmitMatrixTimesMatrix(InsnIterator insn, EmitState *state) const;
1092 EmitResult EmitOuterProduct(InsnIterator insn, EmitState *state) const;
1093 EmitResult EmitTranspose(InsnIterator insn, EmitState *state) const;
1094 EmitResult EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const;
1095 EmitResult EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const;
1096 EmitResult EmitUnaryOp(InsnIterator insn, EmitState *state) const;
1097 EmitResult EmitBinaryOp(InsnIterator insn, EmitState *state) const;
1098 EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
1099 EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
1100 EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
Ben Claytonb36dbbe2020-01-08 12:18:43 +00001101 EmitResult EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const;
Ben Claytoncd55f052020-01-14 11:56:00 +00001102 EmitResult EmitOpenCLDebugInfo100(InsnIterator insn, EmitState *state) const;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001103 EmitResult EmitLine(InsnIterator insn, EmitState *state) const;
Nicolas Capens157ba262019-12-10 17:49:14 -05001104 EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
1105 EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
1106 EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
1107 EmitResult EmitBranchConditional(InsnIterator insn, EmitState *state) const;
1108 EmitResult EmitSwitch(InsnIterator insn, EmitState *state) const;
1109 EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const;
1110 EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
1111 EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
1112 EmitResult EmitFunctionCall(InsnIterator insn, EmitState *state) const;
1113 EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
1114 EmitResult EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
1115 EmitResult EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
1116 EmitResult EmitImageGather(Variant variant, InsnIterator insn, EmitState *state) const;
1117 EmitResult EmitImageFetch(InsnIterator insn, EmitState *state) const;
1118 EmitResult EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const;
1119 EmitResult EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const;
1120 EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
1121 EmitResult EmitImageQueryLod(InsnIterator insn, EmitState *state) const;
1122 EmitResult EmitImageQueryLevels(InsnIterator insn, EmitState *state) const;
1123 EmitResult EmitImageQuerySamples(InsnIterator insn, EmitState *state) const;
1124 EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
1125 EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
1126 EmitResult EmitImageTexelPointer(InsnIterator insn, EmitState *state) const;
1127 EmitResult EmitAtomicOp(InsnIterator insn, EmitState *state) const;
1128 EmitResult EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const;
1129 EmitResult EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const;
1130 EmitResult EmitCopyObject(InsnIterator insn, EmitState *state) const;
1131 EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const;
1132 EmitResult EmitControlBarrier(InsnIterator insn, EmitState *state) const;
1133 EmitResult EmitMemoryBarrier(InsnIterator insn, EmitState *state) const;
1134 EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
1135 EmitResult EmitArrayLength(InsnIterator insn, EmitState *state) const;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001136
Nicolas Capens157ba262019-12-10 17:49:14 -05001137 void GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001138 SIMD::Pointer GetTexelAddress(EmitState const *state, SIMD::Pointer base, GenericValue const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const;
Nicolas Capens157ba262019-12-10 17:49:14 -05001139 uint32_t GetConstScalarInt(Object::ID id) const;
1140 void EvalSpecConstantOp(InsnIterator insn);
1141 void EvalSpecConstantUnaryOp(InsnIterator insn);
1142 void EvalSpecConstantBinaryOp(InsnIterator insn);
Ben Clayton30ee92e2019-08-13 14:21:44 +01001143
Nicolas Capens157ba262019-12-10 17:49:14 -05001144 // LoadPhi loads the phi values from the alloca storage and places the
1145 // load values into the intermediate with the phi's result id.
1146 void LoadPhi(InsnIterator insn, EmitState *state) const;
Ben Claytonea3cd1b2019-06-19 21:43:55 +01001147
Nicolas Capens157ba262019-12-10 17:49:14 -05001148 // StorePhi updates the phi's alloca storage value using the incoming
1149 // values from blocks that are both in the OpPhi instruction and in
1150 // filter.
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001151 void StorePhi(Block::ID blockID, InsnIterator insn, EmitState *state, std::unordered_set<SpirvShader::Block::ID> const &filter) const;
Ben Claytonea3cd1b2019-06-19 21:43:55 +01001152
Nicolas Capens157ba262019-12-10 17:49:14 -05001153 // Emits a rr::Fence for the given MemorySemanticsMask.
1154 void Fence(spv::MemorySemanticsMask semantics) const;
1155
1156 // Helper for calling rr::Yield with res cast to an rr::Int.
1157 void Yield(YieldResult res) const;
1158
1159 // OpcodeName() returns the name of the opcode op.
1160 // If NDEBUG is defined, then OpcodeName() will only return the numerical code.
1161 static std::string OpcodeName(spv::Op op);
1162 static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics);
1163
Ben Clayton54d16b82020-02-03 15:32:06 +00001164 // IsStatement() returns true if the given opcode actually performs
1165 // work (as opposed to declaring a type, defining a function start / end,
1166 // etc).
1167 static bool IsStatement(spv::Op op);
1168
Nicolas Capens157ba262019-12-10 17:49:14 -05001169 // Helper as we often need to take dot products as part of doing other things.
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001170 SIMD::Float Dot(unsigned numComponents, GenericValue const &x, GenericValue const &y) const;
Nicolas Capens157ba262019-12-10 17:49:14 -05001171
Nicolas Capens157ba262019-12-10 17:49:14 -05001172 // Splits x into a floating-point significand in the range [0.5, 1.0)
1173 // and an integral exponent of two, such that:
1174 // x = significand * 2^exponent
1175 // Returns the pair <significand, exponent>
1176 std::pair<SIMD::Float, SIMD::Int> Frexp(RValue<SIMD::Float> val) const;
1177
1178 static ImageSampler *getImageSampler(uint32_t instruction, vk::SampledImageDescriptor const *imageDescriptor, const vk::Sampler *sampler);
1179 static std::shared_ptr<rr::Routine> emitSamplerRoutine(ImageInstruction instruction, const Sampler &samplerState);
1180
1181 // TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly.
1182 static sw::FilterType convertFilterMode(const vk::Sampler *sampler);
1183 static sw::MipmapType convertMipmapMode(const vk::Sampler *sampler);
1184 static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::Sampler *sampler, VkImageViewType imageViewType);
1185
1186 // Returns 0 when invalid.
1187 static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model);
1188
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001189 // Debugger API functions. When ENABLE_VK_DEBUGGER is not defined, these
1190 // are all no-ops.
1191
1192 // dbgInit() initializes the debugger code generation.
1193 // All other dbgXXX() functions are no-op until this is called.
1194 void dbgInit(const std::shared_ptr<vk::dbg::Context> &dbgctx);
1195
1196 // dbgTerm() terminates the debugger code generation.
1197 void dbgTerm();
1198
1199 // dbgCreateFile() generates a synthetic file containing the disassembly
1200 // of the SPIR-V shader. This is the file displayed in the debug
1201 // session.
1202 void dbgCreateFile();
1203
1204 // dbgBeginEmit() sets up the debugging state for the shader.
1205 void dbgBeginEmit(EmitState *state) const;
1206
1207 // dbgEndEmit() tears down the debugging state for the shader.
1208 void dbgEndEmit(EmitState *state) const;
1209
1210 // dbgBeginEmitInstruction() updates the current debugger location for
1211 // the given instruction.
1212 void dbgBeginEmitInstruction(InsnIterator insn, EmitState *state) const;
1213
1214 // dbgEndEmitInstruction() creates any new debugger variables for the
1215 // instruction that just completed.
1216 void dbgEndEmitInstruction(InsnIterator insn, EmitState *state) const;
1217
1218 // dbgExposeIntermediate() exposes the intermediate with the given ID to
1219 // the debugger.
1220 void dbgExposeIntermediate(Object::ID id, EmitState *state) const;
1221
1222 // dbgUpdateActiveLaneMask() updates the active lane masks to the
1223 // debugger.
1224 void dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const;
1225
1226 // dbgDeclareResult() associates resultId as the result of the given
1227 // instruction.
1228 void dbgDeclareResult(const InsnIterator &insn, Object::ID resultId) const;
1229
1230 // Impl holds forward declaration structs and pointers to state for the
1231 // private implementations in the corresponding SpirvShaderXXX.cpp files.
Ben Clayton0771f9b2020-01-08 12:00:25 +00001232 // This allows access to the private members of the SpirvShader, without
1233 // littering the header with implementation details.
1234 struct Impl
1235 {
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001236 struct Debugger;
Ben Clayton0771f9b2020-01-08 12:00:25 +00001237 struct Group;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001238 Debugger *debugger = nullptr;
Ben Clayton0771f9b2020-01-08 12:00:25 +00001239 };
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001240 Impl impl;
Nicolas Capens157ba262019-12-10 17:49:14 -05001241};
1242
1243class SpirvRoutine
1244{
1245public:
1246 SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
1247
1248 using Variable = Array<SIMD::Float>;
1249
1250 struct SamplerCache
1251 {
1252 Pointer<Byte> imageDescriptor = nullptr;
1253 Pointer<Byte> sampler;
1254 Pointer<Byte> function;
Ben Claytonab51bbf2019-02-20 14:36:27 +00001255 };
1256
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001257 vk::PipelineLayout const *const pipelineLayout;
Nicolas Capens157ba262019-12-10 17:49:14 -05001258
1259 std::unordered_map<SpirvShader::Object::ID, Variable> variables;
1260 std::unordered_map<SpirvShader::Object::ID, SamplerCache> samplerCache;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001261 Variable inputs = Variable{ MAX_INTERFACE_COMPONENTS };
1262 Variable outputs = Variable{ MAX_INTERFACE_COMPONENTS };
Nicolas Capens157ba262019-12-10 17:49:14 -05001263
1264 Pointer<Byte> workgroupMemory;
1265 Pointer<Pointer<Byte>> descriptorSets;
1266 Pointer<Int> descriptorDynamicOffsets;
1267 Pointer<Byte> pushConstants;
1268 Pointer<Byte> constants;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001269 Int killMask = Int{ 0 };
Ben Clayton5beaef92019-12-03 12:23:35 +00001270
1271 // Shader invocation state.
1272 // Not all of these variables are used for every type of shader, and some
1273 // are only used when debugging. See b/146486064 for more information.
1274 // Give careful consideration to the runtime performance loss before adding
1275 // more state here.
Nicolas Capens157ba262019-12-10 17:49:14 -05001276 SIMD::Int windowSpacePosition[2];
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001277 Int viewID; // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex
Ben Clayton5beaef92019-12-03 12:23:35 +00001278 Int instanceID;
1279 SIMD::Int vertexIndex;
1280 std::array<SIMD::Float, 4> fragCoord;
1281 std::array<SIMD::Float, 4> pointCoord;
1282 SIMD::Int helperInvocation;
1283 Int4 numWorkgroups;
1284 Int4 workgroupID;
1285 Int4 workgroupSize;
1286 Int subgroupsPerWorkgroup;
1287 Int invocationsPerSubgroup;
1288 Int subgroupIndex;
1289 SIMD::Int localInvocationIndex;
1290 std::array<SIMD::Int, 3> localInvocationID;
1291 std::array<SIMD::Int, 3> globalInvocationID;
Nicolas Capens157ba262019-12-10 17:49:14 -05001292
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001293 Pointer<Byte> dbgState; // Pointer to a debugger state.
1294
Nicolas Capens157ba262019-12-10 17:49:14 -05001295 void createVariable(SpirvShader::Object::ID id, uint32_t size)
1296 {
1297 bool added = variables.emplace(id, Variable(size)).second;
1298 ASSERT_MSG(added, "Variable %d created twice", id.value());
1299 }
1300
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001301 Variable &getVariable(SpirvShader::Object::ID id)
Nicolas Capens157ba262019-12-10 17:49:14 -05001302 {
1303 auto it = variables.find(id);
1304 ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value());
1305 return it->second;
1306 }
1307
1308 // setImmutableInputBuiltins() sets all the immutable input builtins,
1309 // common for all shader types.
1310 void setImmutableInputBuiltins(SpirvShader const *shader);
1311
1312 // setInputBuiltin() calls f() with the builtin and value if the shader
1313 // uses the input builtin, otherwise the call is a no-op.
1314 // F is a function with the signature:
1315 // void(const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value)
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001316 template<typename F>
1317 inline void setInputBuiltin(SpirvShader const *shader, spv::BuiltIn id, F &&f)
Nicolas Capens157ba262019-12-10 17:49:14 -05001318 {
1319 auto it = shader->inputBuiltins.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001320 if(it != shader->inputBuiltins.end())
Nicolas Capens157ba262019-12-10 17:49:14 -05001321 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001322 const auto &builtin = it->second;
Nicolas Capens157ba262019-12-10 17:49:14 -05001323 f(builtin, getVariable(builtin.Id));
1324 }
1325 }
1326
1327private:
1328 // The phis are only accessible to SpirvShader as they are only used and
1329 // exist between calls to SpirvShader::emitProlog() and
1330 // SpirvShader::emitEpilog().
1331 friend class SpirvShader;
1332
1333 std::unordered_map<SpirvShader::Object::ID, Variable> phis;
Nicolas Capens157ba262019-12-10 17:49:14 -05001334};
1335
1336} // namespace sw
Chris Forbesaf4ed532018-12-06 18:33:27 -08001337
Chris Forbesc25b8072018-12-10 15:10:39 -08001338#endif // sw_SpirvShader_hpp