• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
18 #include "SamplerCore.hpp"
19 #include "ShaderCore.hpp"
20 #include "SpirvBinary.hpp"
21 #include "SpirvID.hpp"
22 #include "Device/Config.hpp"
23 #include "Device/Sampler.hpp"
24 #include "System/Debug.hpp"
25 #include "System/Math.hpp"
26 #include "System/Types.hpp"
27 #include "Vulkan/VkConfig.hpp"
28 #include "Vulkan/VkDescriptorSet.hpp"
29 
30 #define SPV_ENABLE_UTILITY_CODE
31 #include <spirv/unified1/spirv.hpp>
32 
33 #include <array>
34 #include <atomic>
35 #include <cstdint>
36 #include <cstring>
37 #include <deque>
38 #include <functional>
39 #include <memory>
40 #include <string>
41 #include <type_traits>
42 #include <unordered_map>
43 #include <unordered_set>
44 #include <vector>
45 
46 #undef Yield  // b/127920555
47 
48 namespace vk {
49 
50 class Device;
51 class PipelineLayout;
52 class ImageView;
53 class Sampler;
54 class RenderPass;
55 struct SampledImageDescriptor;
56 struct SamplerState;
57 
58 }  // namespace vk
59 
60 namespace sw {
61 
62 // Forward declarations.
63 class SpirvRoutine;
64 
65 // Incrementally constructed complex bundle of rvalues
66 // Effectively a restricted vector, supporting only:
67 // - allocation to a (runtime-known) fixed component count
68 // - in-place construction of elements
69 // - const operator[]
70 class Intermediate
71 {
72 public:
Intermediate(uint32_t componentCount)73 	Intermediate(uint32_t componentCount)
74 	    : componentCount(componentCount)
75 	    , scalar(new rr::Value *[componentCount])
76 	{
77 		for(auto i = 0u; i < componentCount; i++) { scalar[i] = nullptr; }
78 	}
79 
~Intermediate()80 	~Intermediate()
81 	{
82 		delete[] scalar;
83 	}
84 
85 	// TypeHint is used as a hint for rr::PrintValue::Ty<sw::Intermediate> to
86 	// decide the format used to print the intermediate data.
87 	enum class TypeHint
88 	{
89 		Float,
90 		Int,
91 		UInt
92 	};
93 
move(uint32_t i,RValue<SIMD::Float> && scalar)94 	void move(uint32_t i, RValue<SIMD::Float> &&scalar) { emplace(i, scalar.value(), TypeHint::Float); }
move(uint32_t i,RValue<SIMD::Int> && scalar)95 	void move(uint32_t i, RValue<SIMD::Int> &&scalar) { emplace(i, scalar.value(), TypeHint::Int); }
move(uint32_t i,RValue<SIMD::UInt> && scalar)96 	void move(uint32_t i, RValue<SIMD::UInt> &&scalar) { emplace(i, scalar.value(), TypeHint::UInt); }
97 
move(uint32_t i,const RValue<SIMD::Float> & scalar)98 	void move(uint32_t i, const RValue<SIMD::Float> &scalar) { emplace(i, scalar.value(), TypeHint::Float); }
move(uint32_t i,const RValue<SIMD::Int> & scalar)99 	void move(uint32_t i, const RValue<SIMD::Int> &scalar) { emplace(i, scalar.value(), TypeHint::Int); }
move(uint32_t i,const RValue<SIMD::UInt> & scalar)100 	void move(uint32_t i, const RValue<SIMD::UInt> &scalar) { emplace(i, scalar.value(), TypeHint::UInt); }
101 
102 	// Value retrieval functions.
Float(uint32_t i) const103 	RValue<SIMD::Float> Float(uint32_t i) const
104 	{
105 		ASSERT(i < componentCount);
106 		ASSERT(scalar[i] != nullptr);
107 		RR_PRINT_ONLY(typeHint = TypeHint::Float;)
108 		return As<SIMD::Float>(scalar[i]);  // TODO(b/128539387): RValue<SIMD::Float>(scalar)
109 	}
110 
Int(uint32_t i) const111 	RValue<SIMD::Int> Int(uint32_t i) const
112 	{
113 		ASSERT(i < componentCount);
114 		ASSERT(scalar[i] != nullptr);
115 		RR_PRINT_ONLY(typeHint = TypeHint::Int;)
116 		return As<SIMD::Int>(scalar[i]);  // TODO(b/128539387): RValue<SIMD::Int>(scalar)
117 	}
118 
UInt(uint32_t i) const119 	RValue<SIMD::UInt> UInt(uint32_t i) const
120 	{
121 		ASSERT(i < componentCount);
122 		ASSERT(scalar[i] != nullptr);
123 		RR_PRINT_ONLY(typeHint = TypeHint::UInt;)
124 		return As<SIMD::UInt>(scalar[i]);  // TODO(b/128539387): RValue<SIMD::UInt>(scalar)
125 	}
126 
127 	// No copy/move construction or assignment
128 	Intermediate(const Intermediate &) = delete;
129 	Intermediate(Intermediate &&) = delete;
130 	Intermediate &operator=(const Intermediate &) = delete;
131 	Intermediate &operator=(Intermediate &&) = delete;
132 
133 	const uint32_t componentCount;
134 
135 private:
emplace(uint32_t i,rr::Value * value,TypeHint type)136 	void emplace(uint32_t i, rr::Value *value, TypeHint type)
137 	{
138 		ASSERT(i < componentCount);
139 		ASSERT(scalar[i] == nullptr);
140 		scalar[i] = value;
141 		RR_PRINT_ONLY(typeHint = type;)
142 	}
143 
144 	rr::Value **const scalar;
145 
146 #ifdef ENABLE_RR_PRINT
147 	friend struct rr::PrintValue::Ty<sw::Intermediate>;
148 	mutable TypeHint typeHint = TypeHint::Float;
149 #endif  // ENABLE_RR_PRINT
150 };
151 
152 // The Spirv class parses a SPIR-V binary and provides utilities for retrieving
153 // information about instructions, objects, types, etc.
154 class Spirv
155 {
156 public:
157 	Spirv(VkShaderStageFlagBits stage,
158 	      const char *entryPointName,
159 	      const SpirvBinary &insns);
160 
161 	~Spirv();
162 
163 	SpirvBinary insns;
164 
165 	class Type;
166 	class Object;
167 
168 	// Pseudo-iterator over SPIR-V instructions, designed to support range-based-for.
169 	class InsnIterator
170 	{
171 	public:
172 		InsnIterator() = default;
173 		InsnIterator(const InsnIterator &other) = default;
174 		InsnIterator &operator=(const InsnIterator &other) = default;
175 
InsnIterator(SpirvBinary::const_iterator iter)176 		explicit InsnIterator(SpirvBinary::const_iterator iter)
177 		    : iter{ iter }
178 		{
179 		}
180 
opcode() const181 		spv::Op opcode() const
182 		{
183 			return static_cast<spv::Op>(*iter & spv::OpCodeMask);
184 		}
185 
wordCount() const186 		uint32_t wordCount() const
187 		{
188 			return *iter >> spv::WordCountShift;
189 		}
190 
word(uint32_t n) const191 		uint32_t word(uint32_t n) const
192 		{
193 			ASSERT(n < wordCount());
194 			return iter[n];
195 		}
196 
data() const197 		const uint32_t *data() const
198 		{
199 			return &iter[0];
200 		}
201 
string(uint32_t n) const202 		const char *string(uint32_t n) const
203 		{
204 			return reinterpret_cast<const char *>(&iter[n]);
205 		}
206 
207 		// Returns the number of whole-words that a string literal starting at
208 		// word n consumes. If the end of the intruction is reached before the
209 		// null-terminator is found, then the function DABORT()s and 0 is
210 		// returned.
stringSizeInWords(uint32_t n) const211 		uint32_t stringSizeInWords(uint32_t n) const
212 		{
213 			uint32_t c = wordCount();
214 			for(uint32_t i = n; n < c; i++)
215 			{
216 				const char *s = string(i);
217 				// SPIR-V spec 2.2.1. Instructions:
218 				// A string is interpreted as a nul-terminated stream of
219 				// characters. The character set is Unicode in the UTF-8
220 				// encoding scheme. The UTF-8 octets (8-bit bytes) are packed
221 				// four per word, following the little-endian convention (i.e.,
222 				// the first octet is in the lowest-order 8 bits of the word).
223 				// The final word contains the string's nul-termination
224 				// character (0), and all contents past the end of the string in
225 				// the final word are padded with 0.
226 				if(s[3] == 0)
227 				{
228 					return 1 + i - n;
229 				}
230 			}
231 			DABORT("SPIR-V string literal was not null-terminated");
232 			return 0;
233 		}
234 
hasResultAndType() const235 		bool hasResultAndType() const
236 		{
237 			bool hasResult = false, hasResultType = false;
238 			spv::HasResultAndType(opcode(), &hasResult, &hasResultType);
239 
240 			return hasResultType;
241 		}
242 
resultTypeId() const243 		SpirvID<Type> resultTypeId() const
244 		{
245 			ASSERT(hasResultAndType());
246 			return word(1);
247 		}
248 
resultId() const249 		SpirvID<Object> resultId() const
250 		{
251 			ASSERT(hasResultAndType());
252 			return word(2);
253 		}
254 
distanceFrom(const InsnIterator & other) const255 		uint32_t distanceFrom(const InsnIterator &other) const
256 		{
257 			return static_cast<uint32_t>(iter - other.iter);
258 		}
259 
operator ==(const InsnIterator & other) const260 		bool operator==(const InsnIterator &other) const
261 		{
262 			return iter == other.iter;
263 		}
264 
operator !=(const InsnIterator & other) const265 		bool operator!=(const InsnIterator &other) const
266 		{
267 			return iter != other.iter;
268 		}
269 
operator *() const270 		InsnIterator operator*() const
271 		{
272 			return *this;
273 		}
274 
operator ++()275 		InsnIterator &operator++()
276 		{
277 			iter += wordCount();
278 			return *this;
279 		}
280 
operator ++(int)281 		InsnIterator const operator++(int)
282 		{
283 			InsnIterator ret{ *this };
284 			iter += wordCount();
285 			return ret;
286 		}
287 
288 	private:
289 		SpirvBinary::const_iterator iter;
290 	};
291 
292 	// Range-based-for interface
begin() const293 	InsnIterator begin() const
294 	{
295 		// Skip over the header words
296 		return InsnIterator{ insns.cbegin() + 5 };
297 	}
298 
end() const299 	InsnIterator end() const
300 	{
301 		return InsnIterator{ insns.cend() };
302 	}
303 
304 	// A range of contiguous instruction words.
305 	struct Span
306 	{
Spansw::Spirv::Span307 		Span(const InsnIterator &insn, uint32_t offset, uint32_t size)
308 		    : insn(insn)
309 		    , offset(offset)
310 		    , wordCount(size)
311 		{}
312 
operator []sw::Spirv::Span313 		uint32_t operator[](uint32_t index) const
314 		{
315 			ASSERT(index < wordCount);
316 			return insn.word(offset + index);
317 		}
318 
sizesw::Spirv::Span319 		uint32_t size() const
320 		{
321 			return wordCount;
322 		}
323 
324 	private:
325 		const InsnIterator &insn;
326 		const uint32_t offset;
327 		const uint32_t wordCount;
328 	};
329 
330 	class Type
331 	{
332 	public:
333 		using ID = SpirvID<Type>;
334 
opcode() const335 		spv::Op opcode() const { return definition.opcode(); }
336 
337 		InsnIterator definition;
338 		spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
339 		uint32_t componentCount = 0;
340 		bool isBuiltInBlock = false;
341 
342 		// Inner element type for pointers, arrays, vectors and matrices.
343 		ID element;
344 	};
345 
346 	class Object
347 	{
348 	public:
349 		using ID = SpirvID<Object>;
350 
opcode() const351 		spv::Op opcode() const { return definition.opcode(); }
typeId() const352 		Type::ID typeId() const { return definition.resultTypeId(); }
id() const353 		Object::ID id() const { return definition.resultId(); }
354 
355 		bool isConstantZero() const;
356 
357 		InsnIterator definition;
358 		std::vector<uint32_t> constantValue;
359 
360 		enum class Kind
361 		{
362 			// Invalid default kind.
363 			// If we get left with an object in this state, the module was
364 			// broken.
365 			Unknown,
366 
367 			// TODO: Better document this kind.
368 			// A shader interface variable pointer.
369 			// Pointer with uniform address across all lanes.
370 			// Pointer held by SpirvRoutine::pointers
371 			InterfaceVariable,
372 
373 			// Constant value held by Object::constantValue.
374 			Constant,
375 
376 			// Value held by SpirvRoutine::intermediates.
377 			Intermediate,
378 
379 			// Pointer held by SpirvRoutine::pointers
380 			Pointer,
381 
382 			// Combination of an image pointer and a sampler ID
383 			SampledImage,
384 
385 			// A pointer to a vk::DescriptorSet*.
386 			// Pointer held by SpirvRoutine::pointers.
387 			DescriptorSet,
388 		};
389 
390 		Kind kind = Kind::Unknown;
391 	};
392 
393 	// Block is an interval of SPIR-V instructions, starting with the
394 	// opening OpLabel, and ending with a termination instruction.
395 	class Block
396 	{
397 	public:
398 		using ID = SpirvID<Block>;
399 		using Set = std::unordered_set<ID>;
400 
401 		// Edge represents the graph edge between two blocks.
402 		struct Edge
403 		{
404 			ID from;
405 			ID to;
406 
operator ==sw::Spirv::Block::Edge407 			bool operator==(const Edge &other) const { return from == other.from && to == other.to; }
408 
409 			struct Hash
410 			{
operator ()sw::Spirv::Block::Edge::Hash411 				std::size_t operator()(const Edge &edge) const noexcept
412 				{
413 					return std::hash<uint32_t>()(edge.from.value() * 31 + edge.to.value());
414 				}
415 			};
416 		};
417 
418 		Block() = default;
419 		Block(const Block &other) = default;
420 		Block &operator=(const Block &other) = default;
421 		explicit Block(InsnIterator begin, InsnIterator end);
422 
423 		/* range-based-for interface */
begin() const424 		inline InsnIterator begin() const { return begin_; }
end() const425 		inline InsnIterator end() const { return end_; }
426 
427 		enum Kind
428 		{
429 			Simple,                         // OpBranch or other simple terminator.
430 			StructuredBranchConditional,    // OpSelectionMerge + OpBranchConditional
431 			UnstructuredBranchConditional,  // OpBranchConditional
432 			StructuredSwitch,               // OpSelectionMerge + OpSwitch
433 			UnstructuredSwitch,             // OpSwitch
434 			Loop,                           // OpLoopMerge + [OpBranchConditional | OpBranch]
435 		};
436 
437 		Kind kind = Simple;
438 		InsnIterator mergeInstruction;   // Structured control flow merge instruction.
439 		InsnIterator branchInstruction;  // Branch instruction.
440 		ID mergeBlock;                   // Structured flow merge block.
441 		ID continueTarget;               // Loop continue block.
442 		Set ins;                         // Blocks that branch into this block.
443 		Set outs;                        // Blocks that this block branches to.
444 		bool isLoopMerge = false;
445 
446 	private:
447 		InsnIterator begin_;
448 		InsnIterator end_;
449 	};
450 
451 	class Function
452 	{
453 	public:
454 		using ID = SpirvID<Function>;
455 
456 		// Walks all reachable the blocks starting from id adding them to
457 		// reachable.
458 		void TraverseReachableBlocks(Block::ID id, Block::Set &reachable) const;
459 
460 		// AssignBlockFields() performs the following for all reachable blocks:
461 		// * Assigns Block::ins with the identifiers of all blocks that contain
462 		//   this block in their Block::outs.
463 		// * Sets Block::isLoopMerge to true if the block is the merge of a
464 		//   another loop block.
465 		void AssignBlockFields();
466 
467 		// ForeachBlockDependency calls f with each dependency of the given
468 		// block. A dependency is an incoming block that is not a loop-back
469 		// edge.
470 		void ForeachBlockDependency(Block::ID blockId, std::function<void(Block::ID)> f) const;
471 
472 		// ExistsPath returns true if there's a direct or indirect flow from
473 		// the 'from' block to the 'to' block that does not pass through
474 		// notPassingThrough.
475 		bool ExistsPath(Block::ID from, Block::ID to, Block::ID notPassingThrough) const;
476 
getBlock(Block::ID id) const477 		const Block &getBlock(Block::ID id) const
478 		{
479 			auto it = blocks.find(id);
480 			ASSERT_MSG(it != blocks.end(), "Unknown block %d", id.value());
481 			return it->second;
482 		}
483 
484 		Block::ID entry;          // function entry point block.
485 		HandleMap<Block> blocks;  // blocks belonging to this function.
486 		Type::ID type;            // type of the function.
487 		Type::ID result;          // return type.
488 	};
489 
490 	using String = std::string;
491 	using StringID = SpirvID<std::string>;
492 
493 	class Extension
494 	{
495 	public:
496 		using ID = SpirvID<Extension>;
497 
498 		enum Name
499 		{
500 			Unknown,
501 			GLSLstd450,
502 			OpenCLDebugInfo100,
503 			NonSemanticInfo,
504 		};
505 
506 		Name name;
507 	};
508 
509 	struct TypeOrObject
510 	{};
511 
512 	// TypeOrObjectID is an identifier that represents a Type or an Object,
513 	// and supports implicit casting to and from Type::ID or Object::ID.
514 	class TypeOrObjectID : public SpirvID<TypeOrObject>
515 	{
516 	public:
517 		using Hash = std::hash<SpirvID<TypeOrObject>>;
518 
TypeOrObjectID(uint32_t id)519 		inline TypeOrObjectID(uint32_t id)
520 		    : SpirvID(id)
521 		{}
TypeOrObjectID(Type::ID id)522 		inline TypeOrObjectID(Type::ID id)
523 		    : SpirvID(id.value())
524 		{}
TypeOrObjectID(Object::ID id)525 		inline TypeOrObjectID(Object::ID id)
526 		    : SpirvID(id.value())
527 		{}
operator Type::ID() const528 		inline operator Type::ID() const { return Type::ID(value()); }
operator Object::ID() const529 		inline operator Object::ID() const { return Object::ID(value()); }
530 	};
531 
532 	// This method is for retrieving an ID that uniquely identifies the
533 	// shader entry point represented by this object.
getIdentifier() const534 	uint64_t getIdentifier() const
535 	{
536 		return ((uint64_t)entryPoint.value() << 32) | insns.getIdentifier();
537 	}
538 
539 	struct ExecutionModes
540 	{
541 		bool EarlyFragmentTests : 1;
542 		bool DepthReplacing : 1;
543 		bool DepthGreater : 1;
544 		bool DepthLess : 1;
545 		bool DepthUnchanged : 1;
546 		bool StencilRefReplacing : 1;
547 
548 		// Compute workgroup dimensions
549 		Object::ID WorkgroupSizeX = 1;
550 		Object::ID WorkgroupSizeY = 1;
551 		Object::ID WorkgroupSizeZ = 1;
552 		bool useWorkgroupSizeId = false;
553 	};
554 
getExecutionModes() const555 	const ExecutionModes &getExecutionModes() const
556 	{
557 		return executionModes;
558 	}
559 
560 	struct Analysis
561 	{
562 		bool ContainsDiscard : 1;  // OpKill, OpTerminateInvocation, or OpDemoteToHelperInvocation
563 		bool ContainsControlBarriers : 1;
564 		bool NeedsCentroid : 1;
565 		bool ContainsSampleQualifier : 1;
566 		bool ContainsImageWrite : 1;
567 	};
568 
getAnalysis() const569 	const Analysis &getAnalysis() const { return analysis; }
containsImageWrite() const570 	bool containsImageWrite() const { return analysis.ContainsImageWrite; }
571 
coverageModified() const572 	bool coverageModified() const
573 	{
574 		return analysis.ContainsDiscard ||
575 		       (outputBuiltins.find(spv::BuiltInSampleMask) != outputBuiltins.end());
576 	}
577 
578 	struct Capabilities
579 	{
580 		bool Matrix : 1;
581 		bool Shader : 1;
582 		bool StorageImageMultisample : 1;
583 		bool ClipDistance : 1;
584 		bool CullDistance : 1;
585 		bool ImageCubeArray : 1;
586 		bool SampleRateShading : 1;
587 		bool InputAttachment : 1;
588 		bool Sampled1D : 1;
589 		bool Image1D : 1;
590 		bool SampledBuffer : 1;
591 		bool SampledCubeArray : 1;
592 		bool ImageBuffer : 1;
593 		bool ImageMSArray : 1;
594 		bool StorageImageExtendedFormats : 1;
595 		bool ImageQuery : 1;
596 		bool DerivativeControl : 1;
597 		bool DotProductInputAll : 1;
598 		bool DotProductInput4x8Bit : 1;
599 		bool DotProductInput4x8BitPacked : 1;
600 		bool DotProduct : 1;
601 		bool InterpolationFunction : 1;
602 		bool StorageImageWriteWithoutFormat : 1;
603 		bool GroupNonUniform : 1;
604 		bool GroupNonUniformVote : 1;
605 		bool GroupNonUniformBallot : 1;
606 		bool GroupNonUniformShuffle : 1;
607 		bool GroupNonUniformShuffleRelative : 1;
608 		bool GroupNonUniformArithmetic : 1;
609 		bool GroupNonUniformQuad : 1;
610 		bool DeviceGroup : 1;
611 		bool MultiView : 1;
612 		bool SignedZeroInfNanPreserve : 1;
613 		bool DemoteToHelperInvocation : 1;
614 		bool StencilExportEXT : 1;
615 		bool VulkanMemoryModel : 1;
616 		bool VulkanMemoryModelDeviceScope : 1;
617 		bool ShaderNonUniform : 1;
618 		bool RuntimeDescriptorArray : 1;
619 		bool StorageBufferArrayNonUniformIndexing : 1;
620 		bool StorageTexelBufferArrayNonUniformIndexing : 1;
621 		bool StorageTexelBufferArrayDynamicIndexing : 1;
622 		bool UniformTexelBufferArrayNonUniformIndexing : 1;
623 		bool UniformTexelBufferArrayDynamicIndexing : 1;
624 		bool UniformBufferArrayNonUniformIndex : 1;
625 		bool SampledImageArrayNonUniformIndexing : 1;
626 		bool StorageImageArrayNonUniformIndexing : 1;
627 		bool PhysicalStorageBufferAddresses : 1;
628 	};
629 
getUsedCapabilities() const630 	const Capabilities &getUsedCapabilities() const
631 	{
632 		return capabilities;
633 	}
634 
635 	// getNumOutputClipDistances() returns the number of ClipDistances
636 	// outputted by this shader.
getNumOutputClipDistances() const637 	unsigned int getNumOutputClipDistances() const
638 	{
639 		if(getUsedCapabilities().ClipDistance)
640 		{
641 			auto it = outputBuiltins.find(spv::BuiltInClipDistance);
642 			if(it != outputBuiltins.end())
643 			{
644 				return it->second.SizeInComponents;
645 			}
646 		}
647 		return 0;
648 	}
649 
650 	// getNumOutputCullDistances() returns the number of CullDistances
651 	// outputted by this shader.
getNumOutputCullDistances() const652 	unsigned int getNumOutputCullDistances() const
653 	{
654 		if(getUsedCapabilities().CullDistance)
655 		{
656 			auto it = outputBuiltins.find(spv::BuiltInCullDistance);
657 			if(it != outputBuiltins.end())
658 			{
659 				return it->second.SizeInComponents;
660 			}
661 		}
662 		return 0;
663 	}
664 
665 	enum AttribType : unsigned char
666 	{
667 		ATTRIBTYPE_FLOAT,
668 		ATTRIBTYPE_INT,
669 		ATTRIBTYPE_UINT,
670 		ATTRIBTYPE_UNUSED,
671 
672 		ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
673 	};
674 
hasBuiltinInput(spv::BuiltIn b) const675 	bool hasBuiltinInput(spv::BuiltIn b) const
676 	{
677 		return inputBuiltins.find(b) != inputBuiltins.end();
678 	}
679 
hasBuiltinOutput(spv::BuiltIn b) const680 	bool hasBuiltinOutput(spv::BuiltIn b) const
681 	{
682 		return outputBuiltins.find(b) != outputBuiltins.end();
683 	}
684 
685 	struct Decorations
686 	{
687 		int32_t Location = -1;
688 		int32_t Component = 0;
689 		spv::BuiltIn BuiltIn = static_cast<spv::BuiltIn>(-1);
690 		int32_t Offset = -1;
691 		int32_t ArrayStride = -1;
692 		int32_t MatrixStride = 1;
693 
694 		bool HasLocation : 1;
695 		bool HasComponent : 1;
696 		bool HasBuiltIn : 1;
697 		bool HasOffset : 1;
698 		bool HasArrayStride : 1;
699 		bool HasMatrixStride : 1;
700 		bool HasRowMajor : 1;  // whether RowMajor bit is valid.
701 
702 		bool Flat : 1;
703 		bool Centroid : 1;
704 		bool NoPerspective : 1;
705 		bool Block : 1;
706 		bool BufferBlock : 1;
707 		bool RelaxedPrecision : 1;
708 		bool RowMajor : 1;      // RowMajor if true; ColMajor if false
709 		bool InsideMatrix : 1;  // pseudo-decoration for whether we're inside a matrix.
710 		bool NonUniform : 1;
711 
Decorationssw::Spirv::Decorations712 		Decorations()
713 		    : Location{ -1 }
714 		    , Component{ 0 }
715 		    , BuiltIn{ static_cast<spv::BuiltIn>(-1) }
716 		    , Offset{ -1 }
717 		    , ArrayStride{ -1 }
718 		    , MatrixStride{ -1 }
719 		    , HasLocation{ false }
720 		    , HasComponent{ false }
721 		    , HasBuiltIn{ false }
722 		    , HasOffset{ false }
723 		    , HasArrayStride{ false }
724 		    , HasMatrixStride{ false }
725 		    , HasRowMajor{ false }
726 		    , Flat{ false }
727 		    , Centroid{ false }
728 		    , NoPerspective{ false }
729 		    , Block{ false }
730 		    , BufferBlock{ false }
731 		    , RelaxedPrecision{ false }
732 		    , RowMajor{ false }
733 		    , InsideMatrix{ false }
734 		    , NonUniform{ false }
735 		{
736 		}
737 
738 		Decorations(const Decorations &) = default;
739 		Decorations& operator= (const Decorations &) = default;
740 
741 		void Apply(const Decorations &src);
742 
743 		void Apply(spv::Decoration decoration, uint32_t arg);
744 	};
745 
746 	std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
747 	std::unordered_map<Type::ID, std::vector<Decorations>> memberDecorations;
748 
749 	struct DescriptorDecorations
750 	{
751 		int32_t DescriptorSet = -1;
752 		int32_t Binding = -1;
753 		int32_t InputAttachmentIndex = -1;
754 
755 		void Apply(const DescriptorDecorations &src);
756 	};
757 
758 	std::unordered_map<Object::ID, DescriptorDecorations> descriptorDecorations;
759 
760 	struct InterfaceComponent
761 	{
762 		AttribType Type;
763 
764 		union
765 		{
766 			struct
767 			{
768 				bool Flat : 1;
769 				bool Centroid : 1;
770 				bool NoPerspective : 1;
771 			};
772 
773 			uint8_t DecorationBits;
774 		};
775 
InterfaceComponentsw::Spirv::InterfaceComponent776 		InterfaceComponent()
777 		    : Type{ ATTRIBTYPE_UNUSED }
778 		    , DecorationBits{ 0 }
779 		{
780 		}
781 	};
782 
783 	struct BuiltinMapping
784 	{
785 		Object::ID Id;
786 		uint32_t FirstComponent;
787 		uint32_t SizeInComponents;
788 	};
789 
790 	struct WorkgroupMemory
791 	{
792 		// allocates a new variable of size bytes with the given identifier.
allocatesw::Spirv::WorkgroupMemory793 		inline void allocate(Object::ID id, uint32_t size)
794 		{
795 			uint32_t offset = totalSize;
796 			auto it = offsets.emplace(id, offset);
797 			ASSERT_MSG(it.second, "WorkgroupMemory already has an allocation for object %d", int(id.value()));
798 			totalSize += size;
799 		}
800 		// returns the byte offset of the variable with the given identifier.
offsetOfsw::Spirv::WorkgroupMemory801 		inline uint32_t offsetOf(Object::ID id) const
802 		{
803 			auto it = offsets.find(id);
804 			ASSERT_MSG(it != offsets.end(), "WorkgroupMemory has no allocation for object %d", int(id.value()));
805 			return it->second;
806 		}
807 		// returns the total allocated size in bytes.
sizesw::Spirv::WorkgroupMemory808 		inline uint32_t size() const { return totalSize; }
809 
810 	private:
811 		uint32_t totalSize = 0;                            // in bytes
812 		std::unordered_map<Object::ID, uint32_t> offsets;  // in bytes
813 	};
814 
815 	std::vector<InterfaceComponent> inputs;
816 	std::vector<InterfaceComponent> outputs;
817 
818 	uint32_t getWorkgroupSizeX() const;
819 	uint32_t getWorkgroupSizeY() const;
820 	uint32_t getWorkgroupSizeZ() const;
821 
822 	using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
823 	std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
824 	std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
825 	WorkgroupMemory workgroupMemory;
826 
827 	Function::ID entryPoint;
828 	spv::ExecutionModel executionModel = spv::ExecutionModelMax;  // Invalid prior to OpEntryPoint parsing.
829 	ExecutionModes executionModes = {};
830 	Capabilities capabilities = {};
831 	spv::AddressingModel addressingModel = spv::AddressingModelLogical;
832 	spv::MemoryModel memoryModel = spv::MemoryModelSimple;
833 	HandleMap<Extension> extensionsByID;
834 	std::unordered_set<uint32_t> extensionsImported;
835 
836 	Analysis analysis = {};
837 
838 	HandleMap<Type> types;
839 	HandleMap<Object> defs;
840 
841 	// TODO(b/247020580): Encapsulate
842 public:
843 	HandleMap<Function> functions;
844 	std::unordered_map<StringID, String> strings;
845 
846 	// DeclareType creates a Type for the given OpTypeX instruction, storing
847 	// it into the types map. It is called from the analysis pass (constructor).
848 	void DeclareType(InsnIterator insn);
849 
850 	void ProcessExecutionMode(InsnIterator it);
851 
852 	uint32_t ComputeTypeSize(InsnIterator insn);
853 	Decorations GetDecorationsForId(TypeOrObjectID id) const;
854 	void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
855 	void ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const;
856 	void ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, const Span &indexIds) const;
857 
858 	// Creates an Object for the instruction's result in 'defs'.
859 	void DefineResult(const InsnIterator &insn);
860 
861 	using InterfaceVisitor = std::function<void(Decorations const, AttribType)>;
862 
863 	void VisitInterface(Object::ID id, const InterfaceVisitor &v) const;
864 
865 	int VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &v) const;
866 
867 	// MemoryElement describes a scalar element within a structure, and is
868 	// used by the callback function of VisitMemoryObject().
869 	struct MemoryElement
870 	{
871 		uint32_t index;    // index of the scalar element
872 		uint32_t offset;   // offset (in bytes) from the base of the object
873 		const Type &type;  // element type
874 	};
875 
876 	using MemoryVisitor = std::function<void(const MemoryElement &)>;
877 
878 	// VisitMemoryObject() walks a type tree in an explicitly laid out
879 	// storage class, calling the MemoryVisitor for each scalar element
880 	// within the
881 	void VisitMemoryObject(Object::ID id, bool resultIsPointer, const MemoryVisitor &v) const;
882 
883 	// VisitMemoryObjectInner() is internally called by VisitMemoryObject()
884 	void VisitMemoryObjectInner(Type::ID id, Decorations d, uint32_t &index, uint32_t offset, bool resultIsPointer, const MemoryVisitor &v) const;
885 
886 	Object &CreateConstant(InsnIterator it);
887 
888 	void ProcessInterfaceVariable(Object &object);
889 
getType(Type::ID id) const890 	const Type &getType(Type::ID id) const
891 	{
892 		auto it = types.find(id);
893 		ASSERT_MSG(it != types.end(), "Unknown type %d", id.value());
894 		return it->second;
895 	}
896 
getType(const Object & object) const897 	const Type &getType(const Object &object) const
898 	{
899 		return getType(object.typeId());
900 	}
901 
getObject(Object::ID id) const902 	const Object &getObject(Object::ID id) const
903 	{
904 		auto it = defs.find(id);
905 		ASSERT_MSG(it != defs.end(), "Unknown object %d", id.value());
906 		return it->second;
907 	}
908 
getObjectType(Object::ID id) const909 	const Type &getObjectType(Object::ID id) const
910 	{
911 		return getType(getObject(id));
912 	}
913 
getFunction(Function::ID id) const914 	const Function &getFunction(Function::ID id) const
915 	{
916 		auto it = functions.find(id);
917 		ASSERT_MSG(it != functions.end(), "Unknown function %d", id.value());
918 		return it->second;
919 	}
920 
getString(StringID id) const921 	const String &getString(StringID id) const
922 	{
923 		auto it = strings.find(id);
924 		ASSERT_MSG(it != strings.end(), "Unknown string %d", id.value());
925 		return it->second;
926 	}
927 
getExtension(Extension::ID id) const928 	const Extension &getExtension(Extension::ID id) const
929 	{
930 		auto it = extensionsByID.find(id);
931 		ASSERT_MSG(it != extensionsByID.end(), "Unknown extension %d", id.value());
932 		return it->second;
933 	}
934 
935 	// Returns the *component* offset in the literal for the given access chain.
936 	uint32_t WalkLiteralAccessChain(Type::ID id, const Span &indexes) const;
937 
938 	uint32_t GetConstScalarInt(Object::ID id) const;
939 	void EvalSpecConstantOp(InsnIterator insn);
940 	void EvalSpecConstantUnaryOp(InsnIterator insn);
941 	void EvalSpecConstantBinaryOp(InsnIterator insn);
942 
943 	// Fragment input interpolation functions
944 	uint32_t GetNumInputComponents(int32_t location) const;
945 	uint32_t GetPackedInterpolant(int32_t location) const;
946 
947 	// WriteCFGGraphVizDotFile() writes a graphviz dot file of the shader's
948 	// control flow to the given file path.
949 	void WriteCFGGraphVizDotFile(const char *path) const;
950 
951 	// OpcodeName() returns the name of the opcode op.
952 	static const char *OpcodeName(spv::Op opcode);
953 	static std::memory_order MemoryOrder(spv::MemorySemanticsMask memorySemantics);
954 
955 	// IsStatement() returns true if the given opcode actually performs
956 	// work (as opposed to declaring a type, defining a function start / end,
957 	// etc).
958 	static bool IsStatement(spv::Op opcode);
959 
960 	// HasTypeAndResult() returns true if the given opcode's instruction
961 	// has a result type ID and result ID, i.e. defines an Object.
962 	static bool HasTypeAndResult(spv::Op opcode);
963 
964 	// Returns 0 when invalid.
965 	static VkShaderStageFlagBits executionModelToStage(spv::ExecutionModel model);
966 
967 	static bool StoresInHelperInvocationsHaveNoEffect(spv::StorageClass storageClass);
968 	static bool IsExplicitLayout(spv::StorageClass storageClass);
969 	static bool IsTerminator(spv::Op opcode);
970 };
971 
972 // The SpirvShader class holds a parsed SPIR-V shader but also the pipeline
973 // state which affects code emission when passing it to SpirvEmitter.
974 class SpirvShader : public Spirv
975 {
976 public:
977 	SpirvShader(VkShaderStageFlagBits stage,
978 	            const char *entryPointName,
979 	            const SpirvBinary &insns,
980 	            const vk::RenderPass *renderPass,
981 	            uint32_t subpassIndex,
982 	            bool robustBufferAccess);
983 
984 	~SpirvShader();
985 
986 	// TODO(b/247020580): Move to SpirvRoutine
987 	void emitProlog(SpirvRoutine *routine) const;
988 	void emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount = 0) const;
989 	void emitEpilog(SpirvRoutine *routine) const;
990 
getRobustBufferAccess() const991 	bool getRobustBufferAccess() const { return robustBufferAccess; }
992 	OutOfBoundsBehavior getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const;
993 
getInputAttachmentFormat(int32_t index) const994 	vk::Format getInputAttachmentFormat(int32_t index) const { return inputAttachmentFormats[index]; }
995 
996 private:
997 	const bool robustBufferAccess;
998 
999 	std::vector<vk::Format> inputAttachmentFormats;
1000 };
1001 
1002 // The SpirvEmitter class translates the parsed SPIR-V shader into Reactor code.
1003 class SpirvEmitter
1004 {
1005 	using Type = Spirv::Type;
1006 	using Object = Spirv::Object;
1007 	using Block = Spirv::Block;
1008 	using InsnIterator = Spirv::InsnIterator;
1009 	using Decorations = Spirv::Decorations;
1010 	using Span = Spirv::Span;
1011 
1012 public:
1013 	static void emit(const SpirvShader &shader,
1014 	                 SpirvRoutine *routine,
1015 	                 Spirv::Function::ID entryPoint,
1016 	                 RValue<SIMD::Int> activeLaneMask,
1017 	                 RValue<SIMD::Int> storesAndAtomicsMask,
1018 	                 const vk::DescriptorSet::Bindings &descriptorSets,
1019 	                 unsigned int multiSampleCount);
1020 
1021 	// Helper for calling rr::Yield with result cast to an rr::Int.
1022 	enum class YieldResult
1023 	{
1024 		ControlBarrier = 0,
1025 	};
1026 
1027 private:
1028 	SpirvEmitter(const SpirvShader &shader,
1029 	             SpirvRoutine *routine,
1030 	             Spirv::Function::ID entryPoint,
1031 	             RValue<SIMD::Int> activeLaneMask,
1032 	             RValue<SIMD::Int> storesAndAtomicsMask,
1033 	             const vk::DescriptorSet::Bindings &descriptorSets,
1034 	             unsigned int multiSampleCount);
1035 
1036 	// Returns the mask describing the active lanes as updated by dynamic
1037 	// control flow. Active lanes include helper invocations, used for
1038 	// calculating fragment derivitives, which must not perform memory
1039 	// stores or atomic writes.
1040 	//
1041 	// Use activeStoresAndAtomicsMask() to consider both control flow and
1042 	// lanes which are permitted to perform memory stores and atomic
1043 	// operations
activeLaneMask() const1044 	RValue<SIMD::Int> activeLaneMask() const
1045 	{
1046 		ASSERT(activeLaneMaskValue != nullptr);
1047 		return RValue<SIMD::Int>(activeLaneMaskValue);
1048 	}
1049 
1050 	// Returns the immutable lane mask that describes which lanes are
1051 	// permitted to perform memory stores and atomic operations.
1052 	// Note that unlike activeStoresAndAtomicsMask() this mask *does not*
1053 	// consider lanes that have been made inactive due to control flow.
storesAndAtomicsMask() const1054 	RValue<SIMD::Int> storesAndAtomicsMask() const
1055 	{
1056 		ASSERT(storesAndAtomicsMaskValue != nullptr);
1057 		return RValue<SIMD::Int>(storesAndAtomicsMaskValue);
1058 	}
1059 
1060 	// Returns a lane mask that describes which lanes are permitted to
1061 	// perform memory stores and atomic operations, considering lanes that
1062 	// may have been made inactive due to control flow.
activeStoresAndAtomicsMask() const1063 	RValue<SIMD::Int> activeStoresAndAtomicsMask() const
1064 	{
1065 		return activeLaneMask() & storesAndAtomicsMask();
1066 	}
1067 
1068 	// Add a new active lane mask edge from the current block to out.
1069 	// The edge mask value will be (mask AND activeLaneMaskValue).
1070 	// If multiple active lane masks are added for the same edge, then
1071 	// they will be ORed together.
1072 	void addOutputActiveLaneMaskEdge(Block::ID out, RValue<SIMD::Int> mask);
1073 
1074 	// Add a new active lane mask for the edge from -> to.
1075 	// If multiple active lane masks are added for the same edge, then
1076 	// they will be ORed together.
1077 	void addActiveLaneMaskEdge(Block::ID from, Block::ID to, RValue<SIMD::Int> mask);
1078 
1079 	// OpImageSample variants
1080 	enum Variant : uint32_t
1081 	{
1082 		None,  // No Dref or Proj. Also used by OpImageFetch and OpImageQueryLod.
1083 		Dref,
1084 		Proj,
1085 		ProjDref,
1086 		VARIANT_LAST = ProjDref
1087 	};
1088 
1089 	// Compact representation of image instruction state that is passed to the
1090 	// trampoline function for retrieving/generating the corresponding sampling routine.
1091 	struct ImageInstructionSignature
1092 	{
ImageInstructionSignaturesw::SpirvEmitter::ImageInstructionSignature1093 		ImageInstructionSignature(Variant variant, SamplerMethod samplerMethod)
1094 		{
1095 			this->variant = variant;
1096 			this->samplerMethod = samplerMethod;
1097 		}
1098 
1099 		// Unmarshal from raw 32-bit data
ImageInstructionSignaturesw::SpirvEmitter::ImageInstructionSignature1100 		explicit ImageInstructionSignature(uint32_t signature)
1101 		    : signature(signature)
1102 		{}
1103 
getSamplerFunctionsw::SpirvEmitter::ImageInstructionSignature1104 		SamplerFunction getSamplerFunction() const
1105 		{
1106 			return { samplerMethod, offset != 0, sample != 0 };
1107 		}
1108 
isDrefsw::SpirvEmitter::ImageInstructionSignature1109 		bool isDref() const
1110 		{
1111 			return (variant == Dref) || (variant == ProjDref);
1112 		}
1113 
isProjsw::SpirvEmitter::ImageInstructionSignature1114 		bool isProj() const
1115 		{
1116 			return (variant == Proj) || (variant == ProjDref);
1117 		}
1118 
hasLodsw::SpirvEmitter::ImageInstructionSignature1119 		bool hasLod() const
1120 		{
1121 			return samplerMethod == Lod || samplerMethod == Fetch;  // We always pass a Lod operand for Fetch operations.
1122 		}
1123 
hasGradsw::SpirvEmitter::ImageInstructionSignature1124 		bool hasGrad() const
1125 		{
1126 			return samplerMethod == Grad;
1127 		}
1128 
1129 		union
1130 		{
1131 			struct
1132 			{
1133 				Variant variant : BITS(VARIANT_LAST);
1134 				SamplerMethod samplerMethod : BITS(SAMPLER_METHOD_LAST);
1135 				uint32_t gatherComponent : 2;
1136 				uint32_t dim : BITS(spv::DimSubpassData);  // spv::Dim
1137 				uint32_t arrayed : 1;
1138 				uint32_t imageFormat : BITS(spv::ImageFormatR64i);  // spv::ImageFormat
1139 
1140 				// Parameters are passed to the sampling routine in this order:
1141 				uint32_t coordinates : 3;       // 1-4 (does not contain projection component)
1142 				/*	uint32_t dref : 1; */       // Indicated by Variant::ProjDref|Dref
1143 				/*	uint32_t lodOrBias : 1; */  // Indicated by SamplerMethod::Lod|Bias|Fetch
1144 				uint32_t grad : 2;              // 0-3 components (for each of dx / dy)
1145 				uint32_t offset : 2;            // 0-3 components
1146 				uint32_t sample : 1;            // 0-1 scalar integer
1147 			};
1148 
1149 			uint32_t signature = 0;
1150 		};
1151 	};
1152 
1153 	// This gets stored as a literal in the generated code, so it should be compact.
1154 	static_assert(sizeof(ImageInstructionSignature) == sizeof(uint32_t), "ImageInstructionSignature must be 32-bit");
1155 
1156 	struct ImageInstruction : public ImageInstructionSignature
1157 	{
1158 		ImageInstruction(InsnIterator insn, const Spirv &shader, const SpirvEmitter &state);
1159 
1160 		const uint32_t position;
1161 
1162 		Type::ID resultTypeId = 0;
1163 		Object::ID resultId = 0;
1164 		Object::ID imageId = 0;
1165 		Object::ID samplerId = 0;
1166 		Object::ID coordinateId = 0;
1167 		Object::ID texelId = 0;
1168 		Object::ID drefId = 0;
1169 		Object::ID lodOrBiasId = 0;
1170 		Object::ID gradDxId = 0;
1171 		Object::ID gradDyId = 0;
1172 		Object::ID offsetId = 0;
1173 		Object::ID sampleId = 0;
1174 
1175 	private:
1176 		static ImageInstructionSignature parseVariantAndMethod(InsnIterator insn);
1177 		static uint32_t getImageOperandsIndex(InsnIterator insn);
1178 		static uint32_t getImageOperandsMask(InsnIterator insn);
1179 	};
1180 
1181 	class SampledImagePointer : public SIMD::Pointer
1182 	{
1183 	public:
SampledImagePointer(SIMD::Pointer image,Object::ID sampler)1184 		SampledImagePointer(SIMD::Pointer image, Object::ID sampler)
1185 		    : SIMD::Pointer(image)
1186 		    , samplerId(sampler)
1187 		{}
1188 		Object::ID samplerId;
1189 	};
1190 
1191 	// Generic wrapper over either per-lane intermediate value, or a constant.
1192 	// Constants are transparently widened to per-lane values in operator[].
1193 	// This is appropriate in most cases -- if we're not going to do something
1194 	// significantly different based on whether the value is uniform across lanes.
1195 	class Operand
1196 	{
1197 	public:
1198 		Operand(const Spirv &shader, const SpirvEmitter &state, Object::ID objectId);
1199 		Operand(const Intermediate &value);
1200 
Float(uint32_t i) const1201 		RValue<SIMD::Float> Float(uint32_t i) const
1202 		{
1203 			ASSERT(i < componentCount);
1204 
1205 			if(intermediate)
1206 			{
1207 				return intermediate->Float(i);
1208 			}
1209 
1210 			// Constructing a constant SIMD::Float is not guaranteed to preserve the data's exact
1211 			// bit pattern, but SPIR-V provides 32-bit words representing "the bit pattern for the constant".
1212 			// Thus we must first construct an integer constant, and bitcast to float.
1213 			return As<SIMD::Float>(SIMD::UInt(constant[i]));
1214 		}
1215 
Int(uint32_t i) const1216 		RValue<SIMD::Int> Int(uint32_t i) const
1217 		{
1218 			ASSERT(i < componentCount);
1219 
1220 			if(intermediate)
1221 			{
1222 				return intermediate->Int(i);
1223 			}
1224 
1225 			return SIMD::Int(constant[i]);
1226 		}
1227 
UInt(uint32_t i) const1228 		RValue<SIMD::UInt> UInt(uint32_t i) const
1229 		{
1230 			ASSERT(i < componentCount);
1231 
1232 			if(intermediate)
1233 			{
1234 				return intermediate->UInt(i);
1235 			}
1236 
1237 			return SIMD::UInt(constant[i]);
1238 		}
1239 
Pointer() const1240 		const SIMD::Pointer &Pointer() const
1241 		{
1242 			ASSERT(intermediate == nullptr);
1243 
1244 			return *pointer;
1245 		}
1246 
isPointer() const1247 		bool isPointer() const
1248 		{
1249 			return (pointer != nullptr);
1250 		}
1251 
SampledImage() const1252 		const SampledImagePointer &SampledImage() const
1253 		{
1254 			ASSERT(intermediate == nullptr);
1255 
1256 			return *sampledImage;
1257 		}
1258 
isSampledImage() const1259 		bool isSampledImage() const
1260 		{
1261 			return (sampledImage != nullptr);
1262 		}
1263 
1264 	private:
1265 		RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;)
1266 
1267 		// Delegate constructor
1268 		Operand(const SpirvEmitter &state, const Object &object);
1269 
1270 		const uint32_t *constant = nullptr;
1271 		const Intermediate *intermediate = nullptr;
1272 		const SIMD::Pointer *pointer = nullptr;
1273 		const SampledImagePointer *sampledImage = nullptr;
1274 
1275 	public:
1276 		const uint32_t componentCount;
1277 	};
1278 
RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;)1279 	RR_PRINT_ONLY(friend struct rr::PrintValue::Ty<Operand>;)
1280 
1281 	Intermediate &createIntermediate(Object::ID id, uint32_t componentCount)
1282 	{
1283 		auto it = intermediates.emplace(std::piecewise_construct,
1284 		                                std::forward_as_tuple(id),
1285 		                                std::forward_as_tuple(componentCount));
1286 		ASSERT_MSG(it.second, "Intermediate %d created twice", id.value());
1287 		return it.first->second;
1288 	}
1289 
getIntermediate(Object::ID id) const1290 	const Intermediate &getIntermediate(Object::ID id) const
1291 	{
1292 		auto it = intermediates.find(id);
1293 		ASSERT_MSG(it != intermediates.end(), "Unknown intermediate %d", id.value());
1294 		return it->second;
1295 	}
1296 
createPointer(Object::ID id,SIMD::Pointer ptr)1297 	void createPointer(Object::ID id, SIMD::Pointer ptr)
1298 	{
1299 		bool added = pointers.emplace(id, ptr).second;
1300 		ASSERT_MSG(added, "Pointer %d created twice", id.value());
1301 	}
1302 
getPointer(Object::ID id) const1303 	const SIMD::Pointer &getPointer(Object::ID id) const
1304 	{
1305 		auto it = pointers.find(id);
1306 		ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());
1307 		return it->second;
1308 	}
1309 
createSampledImage(Object::ID id,SampledImagePointer ptr)1310 	void createSampledImage(Object::ID id, SampledImagePointer ptr)
1311 	{
1312 		bool added = sampledImages.emplace(id, ptr).second;
1313 		ASSERT_MSG(added, "Sampled image %d created twice", id.value());
1314 	}
1315 
getSampledImage(Object::ID id) const1316 	const SampledImagePointer &getSampledImage(Object::ID id) const
1317 	{
1318 		auto it = sampledImages.find(id);
1319 		ASSERT_MSG(it != sampledImages.end(), "Unknown sampled image %d", id.value());
1320 		return it->second;
1321 	}
1322 
isSampledImage(Object::ID id) const1323 	bool isSampledImage(Object::ID id) const
1324 	{
1325 		return sampledImages.find(id) != sampledImages.end();
1326 	}
1327 
getImage(Object::ID id) const1328 	const SIMD::Pointer &getImage(Object::ID id) const
1329 	{
1330 		return isSampledImage(id) ? getSampledImage(id) : getPointer(id);
1331 	}
1332 
1333 	void EmitVariable(InsnIterator insn);
1334 	void EmitLoad(InsnIterator insn);
1335 	void EmitStore(InsnIterator insn);
1336 	void EmitAccessChain(InsnIterator insn);
1337 	void EmitCompositeConstruct(InsnIterator insn);
1338 	void EmitCompositeInsert(InsnIterator insn);
1339 	void EmitCompositeExtract(InsnIterator insn);
1340 	void EmitVectorShuffle(InsnIterator insn);
1341 	void EmitVectorTimesScalar(InsnIterator insn);
1342 	void EmitMatrixTimesVector(InsnIterator insn);
1343 	void EmitVectorTimesMatrix(InsnIterator insn);
1344 	void EmitMatrixTimesMatrix(InsnIterator insn);
1345 	void EmitOuterProduct(InsnIterator insn);
1346 	void EmitTranspose(InsnIterator insn);
1347 	void EmitVectorExtractDynamic(InsnIterator insn);
1348 	void EmitVectorInsertDynamic(InsnIterator insn);
1349 	void EmitUnaryOp(InsnIterator insn);
1350 	void EmitBinaryOp(InsnIterator insn);
1351 	void EmitDot(InsnIterator insn);
1352 	void EmitSelect(InsnIterator insn);
1353 	void EmitExtendedInstruction(InsnIterator insn);
1354 	void EmitExtGLSLstd450(InsnIterator insn);
1355 	void EmitAny(InsnIterator insn);
1356 	void EmitAll(InsnIterator insn);
1357 	void EmitBranch(InsnIterator insn);
1358 	void EmitBranchConditional(InsnIterator insn);
1359 	void EmitSwitch(InsnIterator insn);
1360 	void EmitUnreachable(InsnIterator insn);
1361 	void EmitReturn(InsnIterator insn);
1362 	void EmitTerminateInvocation(InsnIterator insn);
1363 	void EmitDemoteToHelperInvocation(InsnIterator insn);
1364 	void EmitIsHelperInvocation(InsnIterator insn);
1365 	void EmitFunctionCall(InsnIterator insn);
1366 	void EmitPhi(InsnIterator insn);
1367 	void EmitImageSample(const ImageInstruction &instruction);
1368 	void EmitImageQuerySizeLod(InsnIterator insn);
1369 	void EmitImageQuerySize(InsnIterator insn);
1370 	void EmitImageQueryLevels(InsnIterator insn);
1371 	void EmitImageQuerySamples(InsnIterator insn);
1372 	void EmitImageRead(const ImageInstruction &instruction);
1373 	void EmitImageWrite(const ImageInstruction &instruction);
1374 	void EmitImageTexelPointer(const ImageInstruction &instruction);
1375 	void EmitAtomicOp(InsnIterator insn);
1376 	void EmitAtomicCompareExchange(InsnIterator insn);
1377 	void EmitSampledImage(InsnIterator insn);
1378 	void EmitImage(InsnIterator insn);
1379 	void EmitCopyObject(InsnIterator insn);
1380 	void EmitCopyMemory(InsnIterator insn);
1381 	void EmitControlBarrier(InsnIterator insn);
1382 	void EmitMemoryBarrier(InsnIterator insn);
1383 	void EmitGroupNonUniform(InsnIterator insn);
1384 	void EmitArrayLength(InsnIterator insn);
1385 	void EmitBitcastPointer(Object::ID resultID, Operand &src);
1386 
1387 	enum InterpolationType
1388 	{
1389 		Centroid,
1390 		AtSample,
1391 		AtOffset,
1392 	};
1393 	SIMD::Float EmitInterpolate(const SIMD::Pointer &ptr, int32_t location, Object::ID paramId,
1394 	                            uint32_t component, InterpolationType type) const;
1395 
1396 	SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, Object::ID elementId, const Span &indexIds, bool nonUniform) const;
1397 	SIMD::Pointer WalkAccessChain(Object::ID id, Object::ID elementId, const Span &indexIds, bool nonUniform) const;
1398 
1399 	// Returns true if data in the given storage class is word-interleaved
1400 	// by each SIMD vector lane, otherwise data is stored linerally.
1401 	//
1402 	// Each lane addresses a single word, picked by a base pointer and an
1403 	// integer offset.
1404 	//
1405 	// A word is currently 32 bits (single float, int32_t, uint32_t).
1406 	// A lane is a single element of a SIMD vector register.
1407 	//
1408 	// Storage interleaved by lane - (IsStorageInterleavedByLane() == true):
1409 	// ---------------------------------------------------------------------
1410 	//
1411 	// Address = PtrBase + sizeof(Word) * (SIMD::Width * LaneOffset + LaneIndex)
1412 	//
1413 	// Assuming SIMD::Width == 4:
1414 	//
1415 	//                   Lane[0]  |  Lane[1]  |  Lane[2]  |  Lane[3]
1416 	//                 ===========+===========+===========+==========
1417 	//  LaneOffset=0: |  Word[0]  |  Word[1]  |  Word[2]  |  Word[3]
1418 	// ---------------+-----------+-----------+-----------+----------
1419 	//  LaneOffset=1: |  Word[4]  |  Word[5]  |  Word[6]  |  Word[7]
1420 	// ---------------+-----------+-----------+-----------+----------
1421 	//  LaneOffset=2: |  Word[8]  |  Word[9]  |  Word[a]  |  Word[b]
1422 	// ---------------+-----------+-----------+-----------+----------
1423 	//  LaneOffset=3: |  Word[c]  |  Word[d]  |  Word[e]  |  Word[f]
1424 	//
1425 	//
1426 	// Linear storage - (IsStorageInterleavedByLane() == false):
1427 	// ---------------------------------------------------------
1428 	//
1429 	// Address = PtrBase + sizeof(Word) * LaneOffset
1430 	//
1431 	//                   Lane[0]  |  Lane[1]  |  Lane[2]  |  Lane[3]
1432 	//                 ===========+===========+===========+==========
1433 	//  LaneOffset=0: |  Word[0]  |  Word[0]  |  Word[0]  |  Word[0]
1434 	// ---------------+-----------+-----------+-----------+----------
1435 	//  LaneOffset=1: |  Word[1]  |  Word[1]  |  Word[1]  |  Word[1]
1436 	// ---------------+-----------+-----------+-----------+----------
1437 	//  LaneOffset=2: |  Word[2]  |  Word[2]  |  Word[2]  |  Word[2]
1438 	// ---------------+-----------+-----------+-----------+----------
1439 	//  LaneOffset=3: |  Word[3]  |  Word[3]  |  Word[3]  |  Word[3]
1440 	//
1441 
1442 	static bool IsStorageInterleavedByLane(spv::StorageClass storageClass);
1443 	static SIMD::Pointer GetElementPointer(SIMD::Pointer structure, uint32_t offset, spv::StorageClass storageClass);
1444 
1445 	// Returns a SIMD::Pointer to the underlying data for the given pointer
1446 	// object.
1447 	// Handles objects of the following kinds:
1448 	//  - DescriptorSet
1449 	//  - Pointer
1450 	//  - InterfaceVariable
1451 	// Calling GetPointerToData with objects of any other kind will assert.
1452 	SIMD::Pointer GetPointerToData(Object::ID id, SIMD::Int arrayIndex, bool nonUniform) const;
1453 	void OffsetToElement(SIMD::Pointer &ptr, Object::ID elementId, int32_t arrayStride) const;
1454 
1455 	/* image istructions */
1456 
1457 	// Emits code to sample an image, regardless of whether any SIMD lanes are active.
1458 	void EmitImageSampleUnconditional(Array<SIMD::Float> &out, const ImageInstruction &instruction) const;
1459 
1460 	Pointer<Byte> getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const;
1461 	Pointer<Byte> getSamplerDescriptor(Pointer<Byte> imageDescriptor, const ImageInstruction &instruction, int laneIdx) const;
1462 	Pointer<Byte> lookupSamplerFunction(Pointer<Byte> imageDescriptor, Pointer<Byte> samplerDescriptor, const ImageInstruction &instruction) const;
1463 	void callSamplerFunction(Pointer<Byte> samplerFunction, Array<SIMD::Float> &out, Pointer<Byte> imageDescriptor, const ImageInstruction &instruction) const;
1464 
1465 	void GetImageDimensions(const Type &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
1466 	struct TexelAddressData
1467 	{
1468 		bool isArrayed;
1469 		spv::Dim dim;
1470 		int dims, texelSize;
1471 		SIMD::Int u, v, w, ptrOffset;
1472 	};
1473 	static TexelAddressData setupTexelAddressData(SIMD::Int rowPitch, SIMD::Int slicePitch, SIMD::Int samplePitch, ImageInstructionSignature instruction, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, const SpirvRoutine *routine);
1474 	static SIMD::Pointer GetNonUniformTexelAddress(ImageInstructionSignature instruction, SIMD::Pointer descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, SIMD::Int activeLaneMask, const SpirvRoutine *routine);
1475 	static SIMD::Pointer GetTexelAddress(ImageInstructionSignature instruction, Pointer<Byte> descriptor, SIMD::Int coordinate[], SIMD::Int sample, vk::Format imageFormat, OutOfBoundsBehavior outOfBoundsBehavior, const SpirvRoutine *routine);
1476 	static void WriteImage(ImageInstructionSignature instruction, Pointer<Byte> descriptor, const Pointer<SIMD::Int> &coord, const Pointer<SIMD::Int> &texelAndMask, vk::Format imageFormat);
1477 
1478 	/* control flow */
1479 
1480 	// Lookup the active lane mask for the edge from -> to.
1481 	// If from is unreachable, then a mask of all zeros is returned.
1482 	// Asserts if from is reachable and the edge does not exist.
1483 	RValue<SIMD::Int> GetActiveLaneMaskEdge(Block::ID from, Block::ID to) const;
1484 
1485 	// Updates the current active lane mask.
1486 	void SetActiveLaneMask(RValue<SIMD::Int> mask);
1487 	void SetStoresAndAtomicsMask(RValue<SIMD::Int> mask);
1488 
1489 	// Emit all the unvisited blocks (except for ignore) in DFS order,
1490 	// starting with id.
1491 	void EmitBlocks(Block::ID id, Block::ID ignore = 0);
1492 	void EmitNonLoop();
1493 	void EmitLoop();
1494 
1495 	void EmitInstructions(InsnIterator begin, InsnIterator end);
1496 	void EmitInstruction(InsnIterator insn);
1497 
1498 	// Helper for implementing OpStore, which doesn't take an InsnIterator so it
1499 	// can also store independent operands.
1500 	void Store(Object::ID pointerId, const Operand &value, bool atomic, std::memory_order memoryOrder) const;
1501 
1502 	// LoadPhi loads the phi values from the alloca storage and places the
1503 	// load values into the intermediate with the phi's result id.
1504 	void LoadPhi(InsnIterator insn);
1505 
1506 	// StorePhi updates the phi's alloca storage value using the incoming
1507 	// values from blocks that are both in the OpPhi instruction and in
1508 	// filter.
1509 	void StorePhi(Block::ID blockID, InsnIterator insn, const std::unordered_set<Block::ID> &filter);
1510 
1511 	// Emits a rr::Fence for the given MemorySemanticsMask.
1512 	void Fence(spv::MemorySemanticsMask semantics) const;
1513 
1514 	void Yield(YieldResult res) const;
1515 
1516 	// Helper as we often need to take dot products as part of doing other things.
1517 	static SIMD::Float FDot(unsigned numComponents, const Operand &x, const Operand &y);
1518 	static SIMD::Int SDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum);
1519 	static SIMD::UInt UDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum);
1520 	static SIMD::Int SUDot(unsigned numComponents, const Operand &x, const Operand &y, const Operand *accum);
1521 	static SIMD::Int AddSat(RValue<SIMD::Int> a, RValue<SIMD::Int> b);
1522 	static SIMD::UInt AddSat(RValue<SIMD::UInt> a, RValue<SIMD::UInt> b);
1523 
1524 	using ImageSampler = void(void *texture, void *uvsIn, void *texelOut, void *constants);
1525 	static ImageSampler *getImageSampler(const vk::Device *device, uint32_t signature, uint32_t samplerId, uint32_t imageViewId);
1526 	static std::shared_ptr<rr::Routine> emitSamplerRoutine(ImageInstructionSignature instruction, const Sampler &samplerState);
1527 	static std::shared_ptr<rr::Routine> emitWriteRoutine(ImageInstructionSignature instruction, const Sampler &samplerState);
1528 
1529 	// TODO(b/129523279): Eliminate conversion and use vk::Sampler members directly.
1530 	static sw::FilterType convertFilterMode(const vk::SamplerState *samplerState, VkImageViewType imageViewType, SamplerMethod samplerMethod);
1531 	static sw::MipmapType convertMipmapMode(const vk::SamplerState *samplerState);
1532 	static sw::AddressingMode convertAddressingMode(int coordinateIndex, const vk::SamplerState *samplerState, VkImageViewType imageViewType);
1533 
1534 	const SpirvShader &shader;
1535 	SpirvRoutine *const routine;                     // The current routine being built.
1536 	Spirv::Function::ID function;                    // The current function being built.
1537 	Block::ID block;                                 // The current block being built.
1538 	rr::Value *activeLaneMaskValue = nullptr;        // The current active lane mask.
1539 	rr::Value *storesAndAtomicsMaskValue = nullptr;  // The current atomics mask.
1540 	Spirv::Block::Set visited;                       // Blocks already built.
1541 	std::unordered_map<Block::Edge, RValue<SIMD::Int>, Block::Edge::Hash> edgeActiveLaneMasks;
1542 	std::deque<Block::ID> *pending;
1543 
1544 	const vk::DescriptorSet::Bindings &descriptorSets;
1545 
1546 	std::unordered_map<Object::ID, Intermediate> intermediates;
1547 	std::unordered_map<Object::ID, std::vector<SIMD::Float>> phis;
1548 	std::unordered_map<Object::ID, SIMD::Pointer> pointers;
1549 	std::unordered_map<Object::ID, SampledImagePointer> sampledImages;
1550 
1551 	const unsigned int multiSampleCount;
1552 };
1553 
1554 class SpirvRoutine
1555 {
1556 	using Object = Spirv::Object;
1557 
1558 public:
1559 	SpirvRoutine(const vk::PipelineLayout *pipelineLayout);
1560 
1561 	using Variable = Array<SIMD::Float>;
1562 
1563 	// Single-entry 'inline' sampler routine cache.
1564 	struct SamplerCache
1565 	{
1566 		Pointer<Byte> imageDescriptor = nullptr;
1567 		Int samplerId;
1568 
1569 		Pointer<Byte> function;
1570 	};
1571 
1572 	enum Interpolation
1573 	{
1574 		Perspective = 0,
1575 		Linear,
1576 		Flat,
1577 	};
1578 
1579 	struct InterpolationData
1580 	{
1581 		Pointer<Byte> primitive;
1582 		SIMD::Float x;
1583 		SIMD::Float y;
1584 		SIMD::Float rhw;
1585 		SIMD::Float xCentroid;
1586 		SIMD::Float yCentroid;
1587 		SIMD::Float rhwCentroid;
1588 	};
1589 
1590 	const vk::PipelineLayout *const pipelineLayout;
1591 
1592 	std::unordered_map<Object::ID, Variable> variables;
1593 	std::unordered_map<uint32_t, SamplerCache> samplerCache;  // Indexed by the instruction position, in words.
1594 	SIMD::Float inputs[MAX_INTERFACE_COMPONENTS];
1595 	Interpolation inputsInterpolation[MAX_INTERFACE_COMPONENTS];
1596 	SIMD::Float outputs[MAX_INTERFACE_COMPONENTS];
1597 	InterpolationData interpolationData;
1598 
1599 	Pointer<Byte> device;
1600 	Pointer<Byte> workgroupMemory;
1601 	Pointer<Pointer<Byte>> descriptorSets;
1602 	Pointer<Int> descriptorDynamicOffsets;
1603 	Pointer<Byte> pushConstants;
1604 	Pointer<Byte> constants;
1605 	Int discardMask = 0;
1606 
1607 	// Shader invocation state.
1608 	// Not all of these variables are used for every type of shader, and some
1609 	// are only used when debugging. See b/146486064 for more information.
1610 	// Give careful consideration to the runtime performance loss before adding
1611 	// more state here.
1612 	std::array<SIMD::Int, 2> windowSpacePosition;  // TODO(b/236162233): SIMD::Int2
1613 	Int layer;                                     // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex
1614 	Int instanceID;
1615 	SIMD::Int vertexIndex;
1616 	std::array<SIMD::Float, 4> fragCoord;   // TODO(b/236162233): SIMD::Float4
1617 	std::array<SIMD::Float, 2> pointCoord;  // TODO(b/236162233): SIMD::Float2
1618 	SIMD::Int helperInvocation;
1619 	Int4 numWorkgroups;
1620 	Int4 workgroupID;
1621 	Int4 workgroupSize;
1622 	Int subgroupsPerWorkgroup;
1623 	Int invocationsPerSubgroup;
1624 	Int subgroupIndex;
1625 	SIMD::Int localInvocationIndex;
1626 	std::array<SIMD::Int, 3> localInvocationID;   // TODO(b/236162233): SIMD::Int3
1627 	std::array<SIMD::Int, 3> globalInvocationID;  // TODO(b/236162233): SIMD::Int3
1628 
createVariable(Object::ID id,uint32_t componentCount)1629 	void createVariable(Object::ID id, uint32_t componentCount)
1630 	{
1631 		bool added = variables.emplace(id, Variable(componentCount)).second;
1632 		ASSERT_MSG(added, "Variable %d created twice", id.value());
1633 	}
1634 
getVariable(Object::ID id)1635 	Variable &getVariable(Object::ID id)
1636 	{
1637 		auto it = variables.find(id);
1638 		ASSERT_MSG(it != variables.end(), "Unknown variables %d", id.value());
1639 		return it->second;
1640 	}
1641 
1642 	// setImmutableInputBuiltins() sets all the immutable input builtins,
1643 	// common for all shader types.
1644 	void setImmutableInputBuiltins(const SpirvShader *shader);
1645 
1646 	static SIMD::Float interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, Interpolation interpolation);
1647 
1648 	// setInputBuiltin() calls f() with the builtin and value if the shader
1649 	// uses the input builtin, otherwise the call is a no-op.
1650 	// F is a function with the signature:
1651 	// void(const Spirv::BuiltinMapping& builtin, Array<SIMD::Float>& value)
1652 	template<typename F>
setInputBuiltin(const SpirvShader * shader,spv::BuiltIn id,F && f)1653 	inline void setInputBuiltin(const SpirvShader *shader, spv::BuiltIn id, F &&f)
1654 	{
1655 		auto it = shader->inputBuiltins.find(id);
1656 		if(it != shader->inputBuiltins.end())
1657 		{
1658 			const auto &builtin = it->second;
1659 			f(builtin, getVariable(builtin.Id));
1660 		}
1661 	}
1662 };
1663 
1664 }  // namespace sw
1665 
1666 #endif  // sw_SpirvShader_hpp
1667