OSDN Git Service

Plumb PipelineLayouts down to SpirvRoutine
[android-x86/external-swiftshader.git] / src / Pipeline / SpirvShader.hpp
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 "ShaderCore.hpp"
19 #include "SpirvID.hpp"
20 #include "System/Types.hpp"
21 #include "Vulkan/VkDebug.hpp"
22 #include "Vulkan/VkConfig.h"
23
24 #include <array>
25 #include <cstring>
26 #include <string>
27 #include <vector>
28 #include <unordered_map>
29 #include <cstdint>
30 #include <type_traits>
31 #include <memory>
32 #include <spirv/unified1/spirv.hpp>
33 #include <Device/Config.hpp>
34
35 namespace vk
36 {
37         class PipelineLayout;
38 } // namespace vk
39
40 namespace sw
41 {
42         // Forward declarations.
43         class SpirvRoutine;
44
45         // SIMD contains types that represent multiple scalars packed into a single
46         // vector data type. Types in the SIMD namespace provide a semantic hint
47         // that the data should be treated as a per-execution-lane scalar instead of
48         // a typical euclidean-style vector type.
49         namespace SIMD
50         {
51                 // Width is the number of per-lane scalars packed into each SIMD vector.
52                 static constexpr int Width = 4;
53
54                 using Float = rr::Float4;
55                 using Int = rr::Int4;
56                 using UInt = rr::UInt4;
57         }
58
59         // Incrementally constructed complex bundle of rvalues
60         // Effectively a restricted vector, supporting only:
61         // - allocation to a (runtime-known) fixed size
62         // - in-place construction of elements
63         // - const operator[]
64         class Intermediate
65         {
66         public:
67                 using Scalar = RValue<SIMD::Float>;
68
69                 Intermediate(uint32_t size) : contents(new ContentsType[size]), size(size) {
70 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
71                         memset(contents, 0, sizeof(ContentsType[size]));
72 #endif
73                 }
74
75                 ~Intermediate()
76                 {
77                         for (auto i = 0u; i < size; i++)
78                                 reinterpret_cast<Scalar *>(&contents[i])->~Scalar();
79                         delete [] contents;
80                 }
81
82                 void emplace(uint32_t n, Scalar&& value)
83                 {
84                         ASSERT(n < size);
85                         ASSERT(reinterpret_cast<Scalar const *>(&contents[n])->value == nullptr);
86                         new (&contents[n]) Scalar(value);
87                 }
88
89                 void emplace(uint32_t n, const Scalar& value)
90                 {
91                         ASSERT(n < size);
92                         ASSERT(reinterpret_cast<Scalar const *>(&contents[n])->value == nullptr);
93                         new (&contents[n]) Scalar(value);
94                 }
95
96                 Scalar const & operator[](uint32_t n) const
97                 {
98                         ASSERT(n < size);
99                         auto scalar = reinterpret_cast<Scalar const *>(&contents[n]);
100                         ASSERT(scalar->value != nullptr);
101                         return *scalar;
102                 }
103
104                 // No copy/move construction or assignment
105                 Intermediate(Intermediate const &) = delete;
106                 Intermediate(Intermediate &&) = delete;
107                 Intermediate & operator=(Intermediate const &) = delete;
108                 Intermediate & operator=(Intermediate &&) = delete;
109
110         private:
111                 using ContentsType = std::aligned_storage<sizeof(Scalar), alignof(Scalar)>::type;
112
113                 ContentsType *contents;
114                 uint32_t size;
115         };
116
117         class SpirvShader
118         {
119         public:
120                 using InsnStore = std::vector<uint32_t>;
121                 InsnStore insns;
122
123                 /* Pseudo-iterator over SPIRV instructions, designed to support range-based-for. */
124                 class InsnIterator
125                 {
126                         InsnStore::const_iterator iter;
127
128                 public:
129                         spv::Op opcode() const
130                         {
131                                 return static_cast<spv::Op>(*iter & spv::OpCodeMask);
132                         }
133
134                         uint32_t wordCount() const
135                         {
136                                 return *iter >> spv::WordCountShift;
137                         }
138
139                         uint32_t word(uint32_t n) const
140                         {
141                                 ASSERT(n < wordCount());
142                                 return iter[n];
143                         }
144
145                         uint32_t const * wordPointer(uint32_t n) const
146                         {
147                                 ASSERT(n < wordCount());
148                                 return &iter[n];
149                         }
150
151                         bool operator!=(InsnIterator const &other) const
152                         {
153                                 return iter != other.iter;
154                         }
155
156                         InsnIterator operator*() const
157                         {
158                                 return *this;
159                         }
160
161                         InsnIterator &operator++()
162                         {
163                                 iter += wordCount();
164                                 return *this;
165                         }
166
167                         InsnIterator const operator++(int)
168                         {
169                                 InsnIterator ret{*this};
170                                 iter += wordCount();
171                                 return ret;
172                         }
173
174                         InsnIterator(InsnIterator const &other) = default;
175
176                         InsnIterator() = default;
177
178                         explicit InsnIterator(InsnStore::const_iterator iter) : iter{iter}
179                         {
180                         }
181                 };
182
183                 /* range-based-for interface */
184                 InsnIterator begin() const
185                 {
186                         return InsnIterator{insns.cbegin() + 5};
187                 }
188
189                 InsnIterator end() const
190                 {
191                         return InsnIterator{insns.cend()};
192                 }
193
194                 class Type;
195                 using TypeID = SpirvID<Type>;
196
197                 class Type
198                 {
199                 public:
200                         InsnIterator definition;
201                         spv::StorageClass storageClass = static_cast<spv::StorageClass>(-1);
202                         uint32_t sizeInComponents = 0;
203                         bool isBuiltInBlock = false;
204
205                         // Inner element type for pointers, arrays, vectors and matrices.
206                         TypeID element;
207                 };
208
209                 class Object;
210                 using ObjectID = SpirvID<Object>;
211
212                 class Object
213                 {
214                 public:
215                         InsnIterator definition;
216                         TypeID type;
217                         ObjectID pointerBase;
218                         std::unique_ptr<uint32_t[]> constantValue = nullptr;
219
220                         enum class Kind
221                         {
222                                 Unknown,        /* for paranoia -- if we get left with an object in this state, the module was broken */
223                                 Variable,
224                                 InterfaceVariable,
225                                 Constant,
226                                 Value,
227                         } kind = Kind::Unknown;
228                 };
229
230                 struct TypeOrObject {}; // Dummy struct to represent a Type or Object.
231
232                 // TypeOrObjectID is an identifier that represents a Type or an Object,
233                 // and supports implicit casting to and from TypeID or ObjectID.
234                 class TypeOrObjectID : public SpirvID<TypeOrObject>
235                 {
236                 public:
237                         using Hash = std::hash<SpirvID<TypeOrObject>>;
238
239                         inline TypeOrObjectID(uint32_t id) : SpirvID(id) {}
240                         inline TypeOrObjectID(TypeID id) : SpirvID(id.value()) {}
241                         inline TypeOrObjectID(ObjectID id) : SpirvID(id.value()) {}
242                         inline operator TypeID() const { return TypeID(value()); }
243                         inline operator ObjectID() const { return ObjectID(value()); }
244                 };
245
246                 int getSerialID() const
247                 {
248                         return serialID;
249                 }
250
251                 explicit SpirvShader(InsnStore const &insns);
252
253                 struct Modes
254                 {
255                         bool EarlyFragmentTests : 1;
256                         bool DepthReplacing : 1;
257                         bool DepthGreater : 1;
258                         bool DepthLess : 1;
259                         bool DepthUnchanged : 1;
260                         bool ContainsKill : 1;
261                         bool NeedsCentroid : 1;
262
263                         // Compute workgroup dimensions
264                         int LocalSizeX, LocalSizeY, LocalSizeZ;
265                 };
266
267                 Modes const &getModes() const
268                 {
269                         return modes;
270                 }
271
272                 enum AttribType : unsigned char
273                 {
274                         ATTRIBTYPE_FLOAT,
275                         ATTRIBTYPE_INT,
276                         ATTRIBTYPE_UINT,
277                         ATTRIBTYPE_UNUSED,
278
279                         ATTRIBTYPE_LAST = ATTRIBTYPE_UINT
280                 };
281
282                 bool hasBuiltinInput(spv::BuiltIn b) const
283                 {
284                         return inputBuiltins.find(b) != inputBuiltins.end();
285                 }
286
287                 struct Decorations
288                 {
289                         int32_t Location;
290                         int32_t Component;
291                         int32_t DescriptorSet;
292                         int32_t Binding;
293                         spv::BuiltIn BuiltIn;
294                         bool HasLocation : 1;
295                         bool HasComponent : 1;
296                         bool HasDescriptorSet : 1;
297                         bool HasBinding : 1;
298                         bool HasBuiltIn : 1;
299                         bool Flat : 1;
300                         bool Centroid : 1;
301                         bool NoPerspective : 1;
302                         bool Block : 1;
303                         bool BufferBlock : 1;
304
305                         Decorations()
306                                         : Location{-1}, Component{0}, DescriptorSet{-1}, Binding{-1},
307                                           BuiltIn{static_cast<spv::BuiltIn>(-1)},
308                                           HasLocation{false}, HasComponent{false},
309                                           HasDescriptorSet{false}, HasBinding{false},
310                                           HasBuiltIn{false}, Flat{false}, Centroid{false},
311                                           NoPerspective{false}, Block{false}, BufferBlock{false}
312                         {
313                         }
314
315                         Decorations(Decorations const &) = default;
316
317                         void Apply(Decorations const &src);
318
319                         void Apply(spv::Decoration decoration, uint32_t arg);
320                 };
321
322                 std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
323                 std::unordered_map<TypeID, std::vector<Decorations>> memberDecorations;
324
325                 struct InterfaceComponent
326                 {
327                         AttribType Type;
328                         bool Flat : 1;
329                         bool Centroid : 1;
330                         bool NoPerspective : 1;
331
332                         InterfaceComponent()
333                                         : Type{ATTRIBTYPE_UNUSED}, Flat{false}, Centroid{false}, NoPerspective{false}
334                         {
335                         }
336                 };
337
338                 struct BuiltinMapping
339                 {
340                         ObjectID Id;
341                         uint32_t FirstComponent;
342                         uint32_t SizeInComponents;
343                 };
344
345                 std::vector<InterfaceComponent> inputs;
346                 std::vector<InterfaceComponent> outputs;
347
348                 void emitProlog(SpirvRoutine *routine) const;
349                 void emit(SpirvRoutine *routine) const;
350                 void emitEpilog(SpirvRoutine *routine) const;
351
352                 using BuiltInHash = std::hash<std::underlying_type<spv::BuiltIn>::type>;
353                 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
354                 std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
355
356                 Type const &getType(TypeID id) const
357                 {
358                         auto it = types.find(id);
359                         ASSERT(it != types.end());
360                         return it->second;
361                 }
362
363                 Object const &getObject(ObjectID id) const
364                 {
365                         auto it = defs.find(id);
366                         ASSERT(it != defs.end());
367                         return it->second;
368                 }
369
370         private:
371                 const int serialID;
372                 static volatile int serialCounter;
373                 Modes modes;
374                 HandleMap<Type> types;
375                 HandleMap<Object> defs;
376
377                 // DeclareType creates a Type for the given OpTypeX instruction, storing
378                 // it into the types map. It is called from the analysis pass (constructor).
379                 void DeclareType(InsnIterator insn);
380
381                 void ProcessExecutionMode(InsnIterator it);
382
383                 uint32_t ComputeTypeSize(InsnIterator insn);
384                 void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
385                 void ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const;
386
387                 template<typename F>
388                 int VisitInterfaceInner(TypeID id, Decorations d, F f) const;
389
390                 template<typename F>
391                 void VisitInterface(ObjectID id, F f) const;
392
393                 uint32_t GetConstantInt(ObjectID id) const;
394                 Object& CreateConstant(InsnIterator it);
395
396                 void ProcessInterfaceVariable(Object &object);
397
398                 SIMD::Int WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
399                 uint32_t WalkLiteralAccessChain(TypeID id, uint32_t numIndexes, uint32_t const *indexes) const;
400
401                 // Emit pass instructions:
402                 void EmitVariable(InsnIterator insn, SpirvRoutine *routine) const;
403                 void EmitLoad(InsnIterator insn, SpirvRoutine *routine) const;
404                 void EmitStore(InsnIterator insn, SpirvRoutine *routine) const;
405                 void EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const;
406                 void EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const;
407                 void EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const;
408                 void EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const;
409                 void EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const;
410                 void EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const;
411                 void EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const;
412                 void EmitDot(InsnIterator insn, SpirvRoutine *routine) const;
413
414                 // OpcodeName returns the name of the opcode op.
415                 // If NDEBUG is defined, then OpcodeName will only return the numerical code.
416                 static std::string OpcodeName(spv::Op op);
417         };
418
419         class SpirvRoutine
420         {
421         public:
422                 SpirvRoutine(vk::PipelineLayout const *pipelineLayout);
423
424                 using Value = Array<SIMD::Float>;
425
426                 vk::PipelineLayout const * const pipelineLayout;
427
428                 std::unordered_map<SpirvShader::ObjectID, Value> lvalues;
429
430                 std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates;
431
432                 Value inputs = Value{MAX_INTERFACE_COMPONENTS};
433                 Value outputs = Value{MAX_INTERFACE_COMPONENTS};
434
435                 std::array<Pointer<Byte>, vk::MAX_BOUND_DESCRIPTOR_SETS> descriptorSets;
436
437                 void createLvalue(SpirvShader::ObjectID id, uint32_t size)
438                 {
439                         lvalues.emplace(id, Value(size));
440                 }
441
442                 Intermediate& createIntermediate(SpirvShader::ObjectID id, uint32_t size)
443                 {
444                         auto it = intermediates.emplace(std::piecewise_construct,
445                                         std::forward_as_tuple(id),
446                                         std::forward_as_tuple(size));
447                         return it.first->second;
448                 }
449
450                 Value& getValue(SpirvShader::ObjectID id)
451                 {
452                         auto it = lvalues.find(id);
453                         ASSERT(it != lvalues.end());
454                         return it->second;
455                 }
456
457                 Intermediate const& getIntermediate(SpirvShader::ObjectID id) const
458                 {
459                         auto it = intermediates.find(id);
460                         ASSERT(it != intermediates.end());
461                         return it->second;
462                 }
463         };
464
465         class GenericValue
466         {
467                 // Generic wrapper over either per-lane intermediate value, or a constant.
468                 // Constants are transparently widened to per-lane values in operator[].
469                 // This is appropriate in most cases -- if we're not going to do something
470                 // significantly different based on whether the value is uniform across lanes.
471
472                 SpirvShader::Object const &obj;
473                 Intermediate const *intermediate;
474
475         public:
476                 GenericValue(SpirvShader const *shader, SpirvRoutine const *routine, SpirvShader::ObjectID objId) :
477                                 obj(shader->getObject(objId)),
478                                 intermediate(obj.kind == SpirvShader::Object::Kind::Value ? &routine->getIntermediate(objId) : nullptr) {}
479
480                 RValue<SIMD::Float> operator[](uint32_t i) const
481                 {
482                         if (intermediate)
483                                 return (*intermediate)[i];
484
485                         auto constantValue = reinterpret_cast<float *>(obj.constantValue.get());
486                         return RValue<SIMD::Float>(constantValue[i]);
487                 }
488         };
489
490 }
491
492 #endif  // sw_SpirvShader_hpp