• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Utilities to map shader interface variables to Vulkan mappings, and transform the SPIR-V
7 // accordingly.
8 //
9 
10 #include "libANGLE/renderer/vulkan/spv_utils.h"
11 
12 #include <array>
13 #include <cctype>
14 #include <numeric>
15 
16 #include "common/FixedVector.h"
17 #include "common/spirv/spirv_instruction_builder_autogen.h"
18 #include "common/spirv/spirv_instruction_parser_autogen.h"
19 #include "common/string_utils.h"
20 #include "common/utilities.h"
21 #include "libANGLE/Caps.h"
22 #include "libANGLE/ProgramLinkedResources.h"
23 #include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
24 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
25 #include "libANGLE/trace.h"
26 
27 namespace spirv = angle::spirv;
28 
29 namespace rx
30 {
31 namespace
32 {
33 template <size_t N>
ConstStrLen(const char (&)[N])34 constexpr size_t ConstStrLen(const char (&)[N])
35 {
36     static_assert(N > 0, "C++ shouldn't allow N to be zero");
37 
38     // The length of a string defined as a char array is the size of the array minus 1 (the
39     // terminating '\0').
40     return N - 1;
41 }
42 
43 // Test if there are non-zero indices in the uniform name, returning false in that case.  This
44 // happens for multi-dimensional arrays, where a uniform is created for every possible index of the
45 // array (except for the innermost dimension).  When assigning decorations (set/binding/etc), only
46 // the indices corresponding to the first element of the array should be specified.  This function
47 // is used to skip the other indices.
UniformNameIsIndexZero(const std::string & name)48 bool UniformNameIsIndexZero(const std::string &name)
49 {
50     size_t lastBracketClose = 0;
51 
52     while (true)
53     {
54         size_t openBracket = name.find('[', lastBracketClose);
55         if (openBracket == std::string::npos)
56         {
57             break;
58         }
59         size_t closeBracket = name.find(']', openBracket);
60 
61         // If the index between the brackets is not zero, ignore this uniform.
62         if (name.substr(openBracket + 1, closeBracket - openBracket - 1) != "0")
63         {
64             return false;
65         }
66         lastBracketClose = closeBracket;
67     }
68 
69     return true;
70 }
71 
72 template <typename OutputIter, typename ImplicitIter>
CountExplicitOutputs(OutputIter outputsBegin,OutputIter outputsEnd,ImplicitIter implicitsBegin,ImplicitIter implicitsEnd)73 uint32_t CountExplicitOutputs(OutputIter outputsBegin,
74                               OutputIter outputsEnd,
75                               ImplicitIter implicitsBegin,
76                               ImplicitIter implicitsEnd)
77 {
78     auto reduce = [implicitsBegin, implicitsEnd](uint32_t count, const sh::ShaderVariable &var) {
79         bool isExplicit = std::find(implicitsBegin, implicitsEnd, var.name) == implicitsEnd;
80         return count + isExplicit;
81     };
82 
83     return std::accumulate(outputsBegin, outputsEnd, 0, reduce);
84 }
85 
AddResourceInfoToAllStages(ShaderInterfaceVariableInfoMap * infoMap,gl::ShaderType shaderType,uint32_t varId,uint32_t descriptorSet,uint32_t binding)86 ShaderInterfaceVariableInfo *AddResourceInfoToAllStages(ShaderInterfaceVariableInfoMap *infoMap,
87                                                         gl::ShaderType shaderType,
88                                                         uint32_t varId,
89                                                         uint32_t descriptorSet,
90                                                         uint32_t binding)
91 {
92     gl::ShaderBitSet allStages;
93     allStages.set();
94 
95     ShaderInterfaceVariableInfo &info = infoMap->add(shaderType, varId);
96     info.descriptorSet                = descriptorSet;
97     info.binding                      = binding;
98     info.activeStages                 = allStages;
99     return &info;
100 }
101 
AddResourceInfo(ShaderInterfaceVariableInfoMap * infoMap,gl::ShaderBitSet stages,gl::ShaderType shaderType,uint32_t varId,uint32_t descriptorSet,uint32_t binding)102 ShaderInterfaceVariableInfo *AddResourceInfo(ShaderInterfaceVariableInfoMap *infoMap,
103                                              gl::ShaderBitSet stages,
104                                              gl::ShaderType shaderType,
105                                              uint32_t varId,
106                                              uint32_t descriptorSet,
107                                              uint32_t binding)
108 {
109     ShaderInterfaceVariableInfo &info = infoMap->add(shaderType, varId);
110     info.descriptorSet                = descriptorSet;
111     info.binding                      = binding;
112     info.activeStages                 = stages;
113     return &info;
114 }
115 
116 // Add location information for an in/out variable.
AddLocationInfo(ShaderInterfaceVariableInfoMap * infoMap,gl::ShaderType shaderType,uint32_t varId,uint32_t location,uint32_t component,uint8_t attributeComponentCount,uint8_t attributeLocationCount)117 ShaderInterfaceVariableInfo *AddLocationInfo(ShaderInterfaceVariableInfoMap *infoMap,
118                                              gl::ShaderType shaderType,
119                                              uint32_t varId,
120                                              uint32_t location,
121                                              uint32_t component,
122                                              uint8_t attributeComponentCount,
123                                              uint8_t attributeLocationCount)
124 {
125     // The info map for this id may or may not exist already.  This function merges the
126     // location/component information.
127     ShaderInterfaceVariableInfo &info = infoMap->addOrGet(shaderType, varId);
128 
129     ASSERT(info.descriptorSet == ShaderInterfaceVariableInfo::kInvalid);
130     ASSERT(info.binding == ShaderInterfaceVariableInfo::kInvalid);
131     if (info.location != ShaderInterfaceVariableInfo::kInvalid)
132     {
133         ASSERT(info.location == location);
134         ASSERT(info.component == component);
135     }
136     ASSERT(info.component == ShaderInterfaceVariableInfo::kInvalid);
137 
138     info.location  = location;
139     info.component = component;
140     info.activeStages.set(shaderType);
141     info.attributeComponentCount = attributeComponentCount;
142     info.attributeLocationCount  = attributeLocationCount;
143 
144     return &info;
145 }
146 
147 // Add location information for an in/out variable
AddVaryingLocationInfo(ShaderInterfaceVariableInfoMap * infoMap,const gl::VaryingInShaderRef & ref,const uint32_t location,const uint32_t component)148 void AddVaryingLocationInfo(ShaderInterfaceVariableInfoMap *infoMap,
149                             const gl::VaryingInShaderRef &ref,
150                             const uint32_t location,
151                             const uint32_t component)
152 {
153     // Skip statically-unused varyings, they are already pruned by the translator
154     if (ref.varying->id != 0)
155     {
156         AddLocationInfo(infoMap, ref.stage, ref.varying->id, location, component, 0, 0);
157     }
158 }
159 
160 // Modify an existing out variable and add transform feedback information.
SetXfbInfo(ShaderInterfaceVariableInfoMap * infoMap,gl::ShaderType shaderType,uint32_t varId,int fieldIndex,uint32_t xfbBuffer,uint32_t xfbOffset,uint32_t xfbStride,uint32_t arraySize,uint32_t columnCount,uint32_t rowCount,uint32_t arrayIndex,GLenum componentType)161 ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap,
162                                         gl::ShaderType shaderType,
163                                         uint32_t varId,
164                                         int fieldIndex,
165                                         uint32_t xfbBuffer,
166                                         uint32_t xfbOffset,
167                                         uint32_t xfbStride,
168                                         uint32_t arraySize,
169                                         uint32_t columnCount,
170                                         uint32_t rowCount,
171                                         uint32_t arrayIndex,
172                                         GLenum componentType)
173 {
174     ShaderInterfaceVariableInfo &info   = infoMap->getMutable(shaderType, varId);
175     ShaderInterfaceVariableXfbInfo *xfb = &info.xfb;
176 
177     if (fieldIndex >= 0)
178     {
179         if (info.fieldXfb.size() <= static_cast<size_t>(fieldIndex))
180         {
181             info.fieldXfb.resize(fieldIndex + 1);
182         }
183         xfb = &info.fieldXfb[fieldIndex];
184     }
185 
186     ASSERT(xfb->buffer == ShaderInterfaceVariableXfbInfo::kInvalid);
187     ASSERT(xfb->offset == ShaderInterfaceVariableXfbInfo::kInvalid);
188     ASSERT(xfb->stride == ShaderInterfaceVariableXfbInfo::kInvalid);
189 
190     if (arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid)
191     {
192         xfb->arrayElements.emplace_back();
193         xfb = &xfb->arrayElements.back();
194     }
195 
196     xfb->buffer        = xfbBuffer;
197     xfb->offset        = xfbOffset;
198     xfb->stride        = xfbStride;
199     xfb->arraySize     = arraySize;
200     xfb->columnCount   = columnCount;
201     xfb->rowCount      = rowCount;
202     xfb->arrayIndex    = arrayIndex;
203     xfb->componentType = componentType;
204 
205     return &info;
206 }
207 
AssignTransformFeedbackEmulationBindings(gl::ShaderType shaderType,const gl::ProgramExecutable & programExecutable,bool isTransformFeedbackStage,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)208 void AssignTransformFeedbackEmulationBindings(gl::ShaderType shaderType,
209                                               const gl::ProgramExecutable &programExecutable,
210                                               bool isTransformFeedbackStage,
211                                               SpvProgramInterfaceInfo *programInterfaceInfo,
212                                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
213 {
214     size_t bufferCount = 0;
215     if (isTransformFeedbackStage)
216     {
217         ASSERT(!programExecutable.getLinkedTransformFeedbackVaryings().empty());
218         const bool isInterleaved =
219             programExecutable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
220         bufferCount =
221             isInterleaved ? 1 : programExecutable.getLinkedTransformFeedbackVaryings().size();
222     }
223 
224     // Add entries for the transform feedback buffers to the info map, so they can have correct
225     // set/binding.
226     for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
227     {
228         AddResourceInfo(variableInfoMapOut, gl::ShaderBitSet().set(shaderType), shaderType,
229                         SpvGetXfbBufferBlockId(bufferIndex),
230                         ToUnderlying(DescriptorSetIndex::UniformsAndXfb),
231                         programInterfaceInfo->currentUniformBindingIndex);
232         ++programInterfaceInfo->currentUniformBindingIndex;
233     }
234 
235     // Remove inactive transform feedback buffers.
236     for (uint32_t bufferIndex = static_cast<uint32_t>(bufferCount);
237          bufferIndex < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; ++bufferIndex)
238     {
239         variableInfoMapOut->add(shaderType, SpvGetXfbBufferBlockId(bufferIndex));
240     }
241 }
242 
IsFirstRegisterOfVarying(const gl::PackedVaryingRegister & varyingReg,bool allowFields,uint32_t expectArrayIndex)243 bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg,
244                               bool allowFields,
245                               uint32_t expectArrayIndex)
246 {
247     const gl::PackedVarying &varying = *varyingReg.packedVarying;
248 
249     // In Vulkan GLSL, struct fields are not allowed to have location assignments.  The varying of a
250     // struct type is thus given a location equal to the one assigned to its first field.  With I/O
251     // blocks, transform feedback can capture an arbitrary field.  In that case, we need to look at
252     // every field, not just the first one.
253     if (!allowFields && varying.isStructField() &&
254         (varying.fieldIndex > 0 || varying.secondaryFieldIndex > 0))
255     {
256         return false;
257     }
258 
259     // Similarly, assign array varying locations to the assigned location of the first element.
260     // Transform feedback may capture array elements, so if a specific non-zero element is
261     // requested, accept that only.
262     if (varyingReg.varyingArrayIndex != expectArrayIndex ||
263         (varying.arrayIndex != GL_INVALID_INDEX && varying.arrayIndex != expectArrayIndex))
264     {
265         return false;
266     }
267 
268     // Similarly, assign matrix varying locations to the assigned location of the first row.
269     if (varyingReg.varyingRowIndex != 0)
270     {
271         return false;
272     }
273 
274     return true;
275 }
276 
AssignAttributeLocations(const gl::ProgramExecutable & programExecutable,gl::ShaderType shaderType,ShaderInterfaceVariableInfoMap * variableInfoMapOut)277 void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable,
278                               gl::ShaderType shaderType,
279                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
280 {
281     const std::array<std::string, 2> implicitInputs = {"gl_VertexID", "gl_InstanceID"};
282     gl::AttributesMask isLocationAssigned;
283     bool hasAliasingAttributes = false;
284 
285     // Assign attribute locations for the vertex shader.
286     for (const sh::ShaderVariable &attribute : programExecutable.getProgramInputs())
287     {
288         ASSERT(attribute.active);
289 
290         if (std::find(implicitInputs.begin(), implicitInputs.end(), attribute.name) !=
291             implicitInputs.end())
292         {
293             continue;
294         }
295 
296         const uint8_t colCount = static_cast<uint8_t>(gl::VariableColumnCount(attribute.type));
297         const uint8_t rowCount = static_cast<uint8_t>(gl::VariableRowCount(attribute.type));
298         const bool isMatrix    = colCount > 1 && rowCount > 1;
299 
300         const uint8_t componentCount = isMatrix ? rowCount : colCount;
301         const uint8_t locationCount  = isMatrix ? colCount : rowCount;
302 
303         AddLocationInfo(variableInfoMapOut, shaderType, attribute.id, attribute.location,
304                         ShaderInterfaceVariableInfo::kInvalid, componentCount, locationCount);
305 
306         // Detect if there are aliasing attributes.
307         if (!hasAliasingAttributes &&
308             programExecutable.getLinkedShaderVersion(gl::ShaderType::Vertex) == 100)
309         {
310             for (uint8_t offset = 0; offset < locationCount; ++offset)
311             {
312                 uint32_t location = attribute.location + offset;
313 
314                 // If there's aliasing, no need for futher processing.
315                 if (isLocationAssigned.test(location))
316                 {
317                     hasAliasingAttributes = true;
318                     break;
319                 }
320 
321                 isLocationAssigned.set(location);
322             }
323         }
324     }
325 
326     if (hasAliasingAttributes)
327     {
328         variableInfoMapOut->setHasAliasingAttributes();
329     }
330 }
331 
AssignSecondaryOutputLocations(const gl::ProgramExecutable & programExecutable,ShaderInterfaceVariableInfoMap * variableInfoMapOut)332 void AssignSecondaryOutputLocations(const gl::ProgramExecutable &programExecutable,
333                                     ShaderInterfaceVariableInfoMap *variableInfoMapOut)
334 {
335     const auto &secondaryOutputLocations = programExecutable.getSecondaryOutputLocations();
336     const auto &outputVariables          = programExecutable.getOutputVariables();
337 
338     // Handle EXT_blend_func_extended secondary outputs (ones with index=1)
339     for (const gl::VariableLocation &outputLocation : secondaryOutputLocations)
340     {
341         if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
342         {
343             const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index];
344 
345             uint32_t location = 0;
346             if (outputVar.location != -1)
347             {
348                 location = outputVar.location;
349             }
350 
351             ShaderInterfaceVariableInfo *info =
352                 AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, outputVar.id,
353                                 location, ShaderInterfaceVariableInfo::kInvalid, 0, 0);
354 
355             // If the shader source has not specified the index, specify it here.
356             if (outputVar.index == -1)
357             {
358                 // Index 1 is used to specify that the color be used as the second color input to
359                 // the blend equation
360                 info->index = 1;
361             }
362         }
363     }
364     // Handle secondary outputs for ESSL version less than 3.00
365     if (programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment) &&
366         programExecutable.getLinkedShaderVersion(gl::ShaderType::Fragment) == 100)
367     {
368         const std::array<std::string, 2> secondaryFrag = {"gl_SecondaryFragColorEXT",
369                                                           "gl_SecondaryFragDataEXT"};
370 
371         for (const sh::ShaderVariable &outputVar : outputVariables)
372         {
373             if (std::find(secondaryFrag.begin(), secondaryFrag.end(), outputVar.name) !=
374                 secondaryFrag.end())
375             {
376                 AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, outputVar.id, 0,
377                                 ShaderInterfaceVariableInfo::kInvalid, 0, 0);
378             }
379         }
380     }
381 }
382 
AssignOutputLocations(const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,ShaderInterfaceVariableInfoMap * variableInfoMapOut)383 void AssignOutputLocations(const gl::ProgramExecutable &programExecutable,
384                            const gl::ShaderType shaderType,
385                            ShaderInterfaceVariableInfoMap *variableInfoMapOut)
386 {
387     // Assign output locations for the fragment shader.
388     ASSERT(shaderType == gl::ShaderType::Fragment);
389 
390     const auto &outputLocations                      = programExecutable.getOutputLocations();
391     const auto &outputVariables                      = programExecutable.getOutputVariables();
392     const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask",
393                                                         "gl_FragStencilRefARB"};
394 
395     for (const gl::VariableLocation &outputLocation : outputLocations)
396     {
397         if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
398         {
399             const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index];
400 
401             uint32_t location = 0;
402             if (outputVar.location != -1)
403             {
404                 location = outputVar.location;
405             }
406             else if (std::find(implicitOutputs.begin(), implicitOutputs.end(), outputVar.name) ==
407                      implicitOutputs.end())
408             {
409                 // If there is only one output, it is allowed not to have a location qualifier, in
410                 // which case it defaults to 0.  GLSL ES 3.00 spec, section 4.3.8.2.
411                 ASSERT(CountExplicitOutputs(outputVariables.begin(), outputVariables.end(),
412                                             implicitOutputs.begin(), implicitOutputs.end()) == 1);
413             }
414 
415             AddLocationInfo(variableInfoMapOut, shaderType, outputVar.id, location,
416                             ShaderInterfaceVariableInfo::kInvalid, 0, 0);
417         }
418     }
419     // Handle outputs for ESSL version less than 3.00
420     if (programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment) &&
421         programExecutable.getLinkedShaderVersion(gl::ShaderType::Fragment) == 100)
422     {
423         for (const sh::ShaderVariable &outputVar : outputVariables)
424         {
425             if (outputVar.name == "gl_FragColor" || outputVar.name == "gl_FragData")
426             {
427                 AddLocationInfo(variableInfoMapOut, gl::ShaderType::Fragment, outputVar.id, 0,
428                                 ShaderInterfaceVariableInfo::kInvalid, 0, 0);
429             }
430         }
431     }
432 
433     AssignSecondaryOutputLocations(programExecutable, variableInfoMapOut);
434 }
435 
AssignVaryingLocations(const SpvSourceOptions & options,const gl::VaryingPacking & varyingPacking,const gl::ShaderType shaderType,const gl::ShaderType frontShaderType,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)436 void AssignVaryingLocations(const SpvSourceOptions &options,
437                             const gl::VaryingPacking &varyingPacking,
438                             const gl::ShaderType shaderType,
439                             const gl::ShaderType frontShaderType,
440                             SpvProgramInterfaceInfo *programInterfaceInfo,
441                             ShaderInterfaceVariableInfoMap *variableInfoMapOut)
442 {
443     uint32_t locationsUsedForEmulation = programInterfaceInfo->locationsUsedForXfbExtension;
444 
445     // Assign varying locations.
446     for (const gl::PackedVaryingRegister &varyingReg : varyingPacking.getRegisterList())
447     {
448         if (!IsFirstRegisterOfVarying(varyingReg, false, 0))
449         {
450             continue;
451         }
452 
453         const gl::PackedVarying &varying = *varyingReg.packedVarying;
454 
455         uint32_t location  = varyingReg.registerRow + locationsUsedForEmulation;
456         uint32_t component = ShaderInterfaceVariableInfo::kInvalid;
457         if (varyingReg.registerColumn > 0)
458         {
459             ASSERT(!varying.varying().isStruct());
460             ASSERT(!gl::IsMatrixType(varying.varying().type));
461             component = varyingReg.registerColumn;
462         }
463 
464         if (varying.frontVarying.varying && (varying.frontVarying.stage == shaderType))
465         {
466             AddVaryingLocationInfo(variableInfoMapOut, varying.frontVarying, location, component);
467         }
468 
469         if (varying.backVarying.varying && (varying.backVarying.stage == shaderType))
470         {
471             AddVaryingLocationInfo(variableInfoMapOut, varying.backVarying, location, component);
472         }
473     }
474 
475     // Add an entry for inactive varyings.
476     const gl::ShaderMap<std::vector<uint32_t>> &inactiveVaryingIds =
477         varyingPacking.getInactiveVaryingIds();
478     for (const uint32_t varyingId : inactiveVaryingIds[shaderType])
479     {
480         // If id is already in the map, it will automatically have marked all other stages inactive.
481         if (variableInfoMapOut->hasVariable(shaderType, varyingId))
482         {
483             continue;
484         }
485 
486         // Otherwise, add an entry for it with all locations inactive.
487         ShaderInterfaceVariableInfo &info = variableInfoMapOut->addOrGet(shaderType, varyingId);
488         ASSERT(info.location == ShaderInterfaceVariableInfo::kInvalid);
489     }
490 
491     // Add an entry for gl_PerVertex, for use with transform feedback capture of built-ins.
492     ShaderInterfaceVariableInfo &info =
493         variableInfoMapOut->addOrGet(shaderType, sh::vk::spirv::kIdOutputPerVertexBlock);
494     info.activeStages.set(shaderType);
495 }
496 
497 // Calculates XFB layout qualifier arguments for each transform feedback varying. Stores calculated
498 // values for the SPIR-V transformation.
AssignTransformFeedbackQualifiers(const gl::ProgramExecutable & programExecutable,const gl::VaryingPacking & varyingPacking,const gl::ShaderType shaderType,bool usesExtension,ShaderInterfaceVariableInfoMap * variableInfoMapOut)499 void AssignTransformFeedbackQualifiers(const gl::ProgramExecutable &programExecutable,
500                                        const gl::VaryingPacking &varyingPacking,
501                                        const gl::ShaderType shaderType,
502                                        bool usesExtension,
503                                        ShaderInterfaceVariableInfoMap *variableInfoMapOut)
504 {
505     const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
506         programExecutable.getLinkedTransformFeedbackVaryings();
507     const std::vector<GLsizei> &varyingStrides = programExecutable.getTransformFeedbackStrides();
508     const bool isInterleaved =
509         programExecutable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
510 
511     uint32_t currentOffset = 0;
512     uint32_t currentStride = 0;
513     uint32_t bufferIndex   = 0;
514 
515     for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
516     {
517         if (isInterleaved)
518         {
519             bufferIndex = 0;
520             if (varyingIndex > 0)
521             {
522                 const gl::TransformFeedbackVarying &prev = tfVaryings[varyingIndex - 1];
523                 currentOffset += prev.size() * gl::VariableExternalSize(prev.type);
524             }
525             currentStride = varyingStrides[0];
526         }
527         else
528         {
529             bufferIndex   = varyingIndex;
530             currentOffset = 0;
531             currentStride = varyingStrides[varyingIndex];
532         }
533 
534         const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
535         const gl::UniformTypeInfo &uniformInfo        = gl::GetUniformTypeInfo(tfVarying.type);
536         const uint32_t varyingSize =
537             tfVarying.isArray() ? tfVarying.size() : ShaderInterfaceVariableXfbInfo::kInvalid;
538 
539         if (tfVarying.isBuiltIn())
540         {
541             if (usesExtension && tfVarying.name == "gl_Position")
542             {
543                 // With the extension, gl_Position is captured via a special varying.
544                 SetXfbInfo(variableInfoMapOut, shaderType, sh::vk::spirv::kIdXfbExtensionPosition,
545                            -1, bufferIndex, currentOffset, currentStride, varyingSize,
546                            uniformInfo.columnCount, uniformInfo.rowCount,
547                            ShaderInterfaceVariableXfbInfo::kInvalid, uniformInfo.componentType);
548             }
549             else
550             {
551                 // gl_PerVertex is always defined as:
552                 //
553                 //    Field 0: gl_Position
554                 //    Field 1: gl_PointSize
555                 //    Field 2: gl_ClipDistance
556                 //    Field 3: gl_CullDistance
557                 //
558                 // With the extension, all fields except gl_Position can be captured directly by
559                 // decorating gl_PerVertex fields.
560                 int fieldIndex                                                              = -1;
561                 constexpr int kPerVertexMemberCount                                         = 4;
562                 constexpr std::array<const char *, kPerVertexMemberCount> kPerVertexMembers = {
563                     "gl_Position",
564                     "gl_PointSize",
565                     "gl_ClipDistance",
566                     "gl_CullDistance",
567                 };
568                 for (int index = 0; index < kPerVertexMemberCount; ++index)
569                 {
570                     if (tfVarying.name == kPerVertexMembers[index])
571                     {
572                         fieldIndex = index;
573                         break;
574                     }
575                 }
576                 ASSERT(fieldIndex != -1);
577                 ASSERT(!usesExtension || fieldIndex > 0);
578 
579                 SetXfbInfo(variableInfoMapOut, shaderType, sh::vk::spirv::kIdOutputPerVertexBlock,
580                            fieldIndex, bufferIndex, currentOffset, currentStride, varyingSize,
581                            uniformInfo.columnCount, uniformInfo.rowCount,
582                            ShaderInterfaceVariableXfbInfo::kInvalid, uniformInfo.componentType);
583             }
584 
585             continue;
586         }
587         // Note: capturing individual array elements using the Vulkan transform feedback extension
588         // is currently not supported due to limitations in the extension.
589         // ANGLE supports capturing the whole array.
590         // http://anglebug.com/4140
591         if (usesExtension && tfVarying.isArray() && tfVarying.arrayIndex != GL_INVALID_INDEX)
592         {
593             continue;
594         }
595 
596         // Find the varying with this name.  If a struct is captured, we would be iterating over its
597         // fields.  This is done when the first field of the struct is visited.  For I/O blocks on
598         // the other hand, we need to decorate the exact member that is captured (as whole-block
599         // capture is not supported).
600         const gl::PackedVarying *originalVarying = nullptr;
601         for (const gl::PackedVaryingRegister &varyingReg : varyingPacking.getRegisterList())
602         {
603             const uint32_t arrayIndex =
604                 tfVarying.arrayIndex == GL_INVALID_INDEX ? 0 : tfVarying.arrayIndex;
605             if (!IsFirstRegisterOfVarying(varyingReg, tfVarying.isShaderIOBlock, arrayIndex))
606             {
607                 continue;
608             }
609 
610             const gl::PackedVarying *varying = varyingReg.packedVarying;
611 
612             if (tfVarying.isShaderIOBlock)
613             {
614                 if (varying->frontVarying.parentStructName == tfVarying.structOrBlockName)
615                 {
616                     size_t pos = tfVarying.name.find_first_of(".");
617                     std::string fieldName =
618                         pos == std::string::npos ? tfVarying.name : tfVarying.name.substr(pos + 1);
619 
620                     if (fieldName == varying->frontVarying.varying->name.c_str())
621                     {
622                         originalVarying = varying;
623                         break;
624                     }
625                 }
626             }
627             else if (varying->frontVarying.varying->name == tfVarying.name)
628             {
629                 originalVarying = varying;
630                 break;
631             }
632         }
633 
634         if (originalVarying)
635         {
636             const int fieldIndex = tfVarying.isShaderIOBlock ? originalVarying->fieldIndex : -1;
637             const uint32_t arrayIndex = tfVarying.arrayIndex == GL_INVALID_INDEX
638                                             ? ShaderInterfaceVariableXfbInfo::kInvalid
639                                             : tfVarying.arrayIndex;
640 
641             // Set xfb info for this varying.  AssignVaryingLocations should have already added
642             // location information for these varyings.
643             SetXfbInfo(variableInfoMapOut, shaderType, originalVarying->frontVarying.varying->id,
644                        fieldIndex, bufferIndex, currentOffset, currentStride, varyingSize,
645                        uniformInfo.columnCount, uniformInfo.rowCount, arrayIndex,
646                        uniformInfo.componentType);
647         }
648     }
649 }
650 
AssignUniformBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)651 void AssignUniformBindings(const SpvSourceOptions &options,
652                            const gl::ProgramExecutable &programExecutable,
653                            SpvProgramInterfaceInfo *programInterfaceInfo,
654                            ShaderInterfaceVariableInfoMap *variableInfoMapOut)
655 {
656     for (const gl::ShaderType shaderType : programExecutable.getLinkedShaderStages())
657     {
658         AddResourceInfo(variableInfoMapOut, gl::ShaderBitSet().set(shaderType), shaderType,
659                         sh::vk::spirv::kIdDefaultUniformsBlock,
660                         ToUnderlying(DescriptorSetIndex::UniformsAndXfb),
661                         programInterfaceInfo->currentUniformBindingIndex);
662         ++programInterfaceInfo->currentUniformBindingIndex;
663 
664         // Assign binding to the driver uniforms block
665         AddResourceInfoToAllStages(variableInfoMapOut, shaderType,
666                                    sh::vk::spirv::kIdDriverUniformsBlock,
667                                    ToUnderlying(DescriptorSetIndex::Internal), 0);
668     }
669 }
670 
AssignInputAttachmentBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)671 void AssignInputAttachmentBindings(const SpvSourceOptions &options,
672                                    const gl::ProgramExecutable &programExecutable,
673                                    SpvProgramInterfaceInfo *programInterfaceInfo,
674                                    ShaderInterfaceVariableInfoMap *variableInfoMapOut)
675 {
676     if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment) ||
677         programExecutable.getFragmentInoutRange().empty())
678     {
679         return;
680     }
681 
682     const std::vector<gl::LinkedUniform> &uniforms = programExecutable.getUniforms();
683     const uint32_t baseInputAttachmentBindingIndex =
684         programInterfaceInfo->currentShaderResourceBindingIndex;
685     const gl::ShaderBitSet activeShaders{gl::ShaderType::Fragment};
686 
687     for (unsigned int uniformIndex : programExecutable.getFragmentInoutRange())
688     {
689         const gl::LinkedUniform &inputAttachmentUniform = uniforms[uniformIndex];
690         ASSERT(inputAttachmentUniform.isActive(gl::ShaderType::Fragment));
691 
692         const uint32_t inputAttachmentBindingIndex =
693             baseInputAttachmentBindingIndex + inputAttachmentUniform.getLocation();
694 
695         AddResourceInfo(variableInfoMapOut, activeShaders, gl::ShaderType::Fragment,
696 
697                         inputAttachmentUniform.getIds()[gl::ShaderType::Fragment],
698                         ToUnderlying(DescriptorSetIndex::ShaderResource),
699                         inputAttachmentBindingIndex);
700     }
701 
702     // For input attachment uniform, the descriptor set binding indices are allocated as much as
703     // the maximum draw buffers.
704     programInterfaceInfo->currentShaderResourceBindingIndex += gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
705 }
706 
AssignInterfaceBlockBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,const std::vector<gl::InterfaceBlock> & blocks,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)707 void AssignInterfaceBlockBindings(const SpvSourceOptions &options,
708                                   const gl::ProgramExecutable &programExecutable,
709                                   const std::vector<gl::InterfaceBlock> &blocks,
710 
711                                   SpvProgramInterfaceInfo *programInterfaceInfo,
712                                   ShaderInterfaceVariableInfoMap *variableInfoMapOut)
713 {
714     for (uint32_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
715     {
716         const gl::InterfaceBlock &block = blocks[blockIndex];
717 
718         // TODO: http://anglebug.com/4523: All blocks should be active
719         const gl::ShaderBitSet activeShaders =
720             programExecutable.getLinkedShaderStages() & block.activeShaders();
721         if (activeShaders.none())
722         {
723             continue;
724         }
725 
726         const bool isIndexZero = !block.isArray || block.arrayElement == 0;
727         if (!isIndexZero)
728         {
729             continue;
730         }
731 
732         variableInfoMapOut->addResource(activeShaders, block.getIds(),
733                                         ToUnderlying(DescriptorSetIndex::ShaderResource),
734                                         programInterfaceInfo->currentShaderResourceBindingIndex++);
735     }
736 }
737 
AssignAtomicCounterBufferBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)738 void AssignAtomicCounterBufferBindings(const SpvSourceOptions &options,
739                                        const gl::ProgramExecutable &programExecutable,
740                                        SpvProgramInterfaceInfo *programInterfaceInfo,
741                                        ShaderInterfaceVariableInfoMap *variableInfoMapOut)
742 {
743     const std::vector<gl::AtomicCounterBuffer> &buffers =
744         programExecutable.getAtomicCounterBuffers();
745 
746     if (buffers.size() == 0)
747     {
748         return;
749     }
750 
751     const gl::ShaderBitSet activeShaders = programExecutable.getLinkedShaderStages();
752     ASSERT(activeShaders.any());
753 
754     gl::ShaderMap<uint32_t> ids = {};
755     for (const gl::ShaderType shaderType : activeShaders)
756     {
757         ids[shaderType] = sh::vk::spirv::kIdAtomicCounterBlock;
758     }
759 
760     variableInfoMapOut->addResource(activeShaders, ids,
761                                     ToUnderlying(DescriptorSetIndex::ShaderResource),
762                                     programInterfaceInfo->currentShaderResourceBindingIndex++);
763 }
764 
AssignImageBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)765 void AssignImageBindings(const SpvSourceOptions &options,
766                          const gl::ProgramExecutable &programExecutable,
767                          SpvProgramInterfaceInfo *programInterfaceInfo,
768                          ShaderInterfaceVariableInfoMap *variableInfoMapOut)
769 {
770     const std::vector<gl::LinkedUniform> &uniforms = programExecutable.getUniforms();
771     const gl::RangeUI &imageUniformRange           = programExecutable.getImageUniformRange();
772     for (unsigned int uniformIndex : imageUniformRange)
773     {
774         const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
775 
776         // TODO: http://anglebug.com/4523: All uniforms should be active
777         const gl::ShaderBitSet activeShaders =
778             programExecutable.getLinkedShaderStages() & imageUniform.activeShaders();
779         if (activeShaders.none())
780         {
781             continue;
782         }
783 
784         const bool isIndexZero = UniformNameIsIndexZero(imageUniform.name);
785         if (!isIndexZero)
786         {
787             continue;
788         }
789 
790         variableInfoMapOut->addResource(activeShaders, imageUniform.getIds(),
791                                         ToUnderlying(DescriptorSetIndex::ShaderResource),
792                                         programInterfaceInfo->currentShaderResourceBindingIndex++);
793     }
794 }
795 
AssignNonTextureBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)796 void AssignNonTextureBindings(const SpvSourceOptions &options,
797                               const gl::ProgramExecutable &programExecutable,
798                               SpvProgramInterfaceInfo *programInterfaceInfo,
799                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
800 {
801     AssignInputAttachmentBindings(options, programExecutable, programInterfaceInfo,
802                                   variableInfoMapOut);
803 
804     const std::vector<gl::InterfaceBlock> &uniformBlocks = programExecutable.getUniformBlocks();
805     AssignInterfaceBlockBindings(options, programExecutable, uniformBlocks, programInterfaceInfo,
806                                  variableInfoMapOut);
807 
808     const std::vector<gl::InterfaceBlock> &storageBlocks =
809         programExecutable.getShaderStorageBlocks();
810     AssignInterfaceBlockBindings(options, programExecutable, storageBlocks, programInterfaceInfo,
811                                  variableInfoMapOut);
812 
813     AssignAtomicCounterBufferBindings(options, programExecutable, programInterfaceInfo,
814                                       variableInfoMapOut);
815 
816     AssignImageBindings(options, programExecutable, programInterfaceInfo, variableInfoMapOut);
817 }
818 
AssignTextureBindings(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)819 void AssignTextureBindings(const SpvSourceOptions &options,
820                            const gl::ProgramExecutable &programExecutable,
821                            SpvProgramInterfaceInfo *programInterfaceInfo,
822                            ShaderInterfaceVariableInfoMap *variableInfoMapOut)
823 {
824     // Assign textures to a descriptor set and binding.
825     const std::vector<gl::LinkedUniform> &uniforms = programExecutable.getUniforms();
826     const gl::RangeUI &samplerUniformRange         = programExecutable.getSamplerUniformRange();
827 
828     for (unsigned int uniformIndex : samplerUniformRange)
829     {
830         const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
831 
832         // TODO: http://anglebug.com/4523: All uniforms should be active
833         const gl::ShaderBitSet activeShaders =
834             programExecutable.getLinkedShaderStages() & samplerUniform.activeShaders();
835         if (activeShaders.none())
836         {
837             continue;
838         }
839 
840         const bool isIndexZero = UniformNameIsIndexZero(samplerUniform.name);
841         if (!isIndexZero)
842         {
843             continue;
844         }
845 
846         variableInfoMapOut->addResource(activeShaders, samplerUniform.getIds(),
847                                         ToUnderlying(DescriptorSetIndex::Texture),
848                                         programInterfaceInfo->currentTextureBindingIndex++);
849     }
850 }
851 
IsNonSemanticInstruction(const uint32_t * instruction)852 bool IsNonSemanticInstruction(const uint32_t *instruction)
853 {
854     // To avoid parsing the numerous GLSL OpExtInst instructions, take a quick peek at the set and
855     // skip instructions that aren't non-semantic.
856     return instruction[3] == sh::vk::spirv::kIdNonSemanticInstructionSet;
857 }
858 
859 // Base class for SPIR-V transformations.
860 class SpirvTransformerBase : angle::NonCopyable
861 {
862   public:
SpirvTransformerBase(const spirv::Blob & spirvBlobIn,const ShaderInterfaceVariableInfoMap & variableInfoMap,spirv::Blob * spirvBlobOut)863     SpirvTransformerBase(const spirv::Blob &spirvBlobIn,
864                          const ShaderInterfaceVariableInfoMap &variableInfoMap,
865                          spirv::Blob *spirvBlobOut)
866         : mSpirvBlobIn(spirvBlobIn), mVariableInfoMap(variableInfoMap), mSpirvBlobOut(spirvBlobOut)
867     {
868         gl::ShaderBitSet allStages;
869         allStages.set();
870         mBuiltinVariableInfo.activeStages = allStages;
871     }
872 
getVariableInfoByIdMap()873     std::vector<const ShaderInterfaceVariableInfo *> &getVariableInfoByIdMap()
874     {
875         return mVariableInfoById;
876     }
877 
878     static spirv::IdRef GetNewId(spirv::Blob *blob);
879     spirv::IdRef getNewId();
880 
881   protected:
882     // Common utilities
883     void onTransformBegin();
884     const uint32_t *getCurrentInstruction(spv::Op *opCodeOut, uint32_t *wordCountOut) const;
885     void copyInstruction(const uint32_t *instruction, size_t wordCount);
886 
887     // SPIR-V to transform:
888     const spirv::Blob &mSpirvBlobIn;
889 
890     // Input shader variable info map:
891     const ShaderInterfaceVariableInfoMap &mVariableInfoMap;
892 
893     // Transformed SPIR-V:
894     spirv::Blob *mSpirvBlobOut;
895 
896     // Traversal state:
897     size_t mCurrentWord       = 0;
898     bool mIsInFunctionSection = false;
899 
900     // Transformation state:
901 
902     // Shader variable info per id, if id is a shader variable.
903     std::vector<const ShaderInterfaceVariableInfo *> mVariableInfoById;
904     ShaderInterfaceVariableInfo mBuiltinVariableInfo;
905 };
906 
onTransformBegin()907 void SpirvTransformerBase::onTransformBegin()
908 {
909     // The translator succeeded in outputting SPIR-V, so we assume it's valid.
910     ASSERT(mSpirvBlobIn.size() >= spirv::kHeaderIndexInstructions);
911     // Since SPIR-V comes from a local call to the translator, it necessarily has the same
912     // endianness as the running architecture, so no byte-swapping is necessary.
913     ASSERT(mSpirvBlobIn[spirv::kHeaderIndexMagic] == spv::MagicNumber);
914 
915     // Make sure the transformer is not reused to avoid having to reinitialize it here.
916     ASSERT(mCurrentWord == 0);
917     ASSERT(mIsInFunctionSection == false);
918 
919     // Make sure the spirv::Blob is not reused.
920     ASSERT(mSpirvBlobOut->empty());
921 
922     // Copy the header to SPIR-V blob, we need that to be defined for SpirvTransformerBase::getNewId
923     // to work.
924     mSpirvBlobOut->assign(mSpirvBlobIn.begin(),
925                           mSpirvBlobIn.begin() + spirv::kHeaderIndexInstructions);
926 
927     mCurrentWord = spirv::kHeaderIndexInstructions;
928 }
929 
getCurrentInstruction(spv::Op * opCodeOut,uint32_t * wordCountOut) const930 const uint32_t *SpirvTransformerBase::getCurrentInstruction(spv::Op *opCodeOut,
931                                                             uint32_t *wordCountOut) const
932 {
933     ASSERT(mCurrentWord < mSpirvBlobIn.size());
934     const uint32_t *instruction = &mSpirvBlobIn[mCurrentWord];
935 
936     spirv::GetInstructionOpAndLength(instruction, opCodeOut, wordCountOut);
937 
938     // The translator succeeded in outputting SPIR-V, so we assume it's valid.
939     ASSERT(mCurrentWord + *wordCountOut <= mSpirvBlobIn.size());
940 
941     return instruction;
942 }
943 
copyInstruction(const uint32_t * instruction,size_t wordCount)944 void SpirvTransformerBase::copyInstruction(const uint32_t *instruction, size_t wordCount)
945 {
946     mSpirvBlobOut->insert(mSpirvBlobOut->end(), instruction, instruction + wordCount);
947 }
948 
GetNewId(spirv::Blob * blob)949 spirv::IdRef SpirvTransformerBase::GetNewId(spirv::Blob *blob)
950 {
951     return spirv::IdRef((*blob)[spirv::kHeaderIndexIndexBound]++);
952 }
953 
getNewId()954 spirv::IdRef SpirvTransformerBase::getNewId()
955 {
956     return GetNewId(mSpirvBlobOut);
957 }
958 
959 enum class TransformationState
960 {
961     Transformed,
962     Unchanged,
963 };
964 
965 class SpirvNonSemanticInstructions final : angle::NonCopyable
966 {
967   public:
SpirvNonSemanticInstructions(bool isLastPass)968     SpirvNonSemanticInstructions(bool isLastPass) : mIsLastPass(isLastPass) {}
969 
970     // Returns whether this is a non-semantic instruction (as opposed to GLSL extended
971     // instructions).  If it is non-semantic, returns the instruction code.
972     bool visitExtInst(const uint32_t *instruction, sh::vk::spirv::NonSemanticInstruction *instOut);
973 
974     // Cleans up non-semantic instructions in the last SPIR-V pass.
975     TransformationState transformExtInst(const uint32_t *instruction);
976 
hasSampleRateShading() const977     bool hasSampleRateShading() const
978     {
979         return (mOverviewFlags & sh::vk::spirv::kOverviewHasSampleRateShadingMask) != 0;
980     }
hasSampleID() const981     bool hasSampleID() const
982     {
983         return (mOverviewFlags & sh::vk::spirv::kOverviewHasSampleIDMask) != 0;
984     }
hasOutputPerVertex() const985     bool hasOutputPerVertex() const
986     {
987         return (mOverviewFlags & sh::vk::spirv::kOverviewHasOutputPerVertexMask) != 0;
988     }
989 
990   private:
991     // Whether this is the last SPIR-V pass. The non-semantics instructions are removed from the
992     // SPIR-V in the last pass.
993     const bool mIsLastPass;
994 
995     uint32_t mOverviewFlags;
996 };
997 
visitExtInst(const uint32_t * instruction,sh::vk::spirv::NonSemanticInstruction * instOut)998 bool SpirvNonSemanticInstructions::visitExtInst(const uint32_t *instruction,
999                                                 sh::vk::spirv::NonSemanticInstruction *instOut)
1000 {
1001     if (!IsNonSemanticInstruction(instruction))
1002     {
1003         return false;
1004     }
1005 
1006     spirv::IdResultType typeId;
1007     spirv::IdResult id;
1008     spirv::IdRef set;
1009     spirv::LiteralExtInstInteger extInst;
1010     spirv::ParseExtInst(instruction, &typeId, &id, &set, &extInst, nullptr);
1011 
1012     ASSERT(set == sh::vk::spirv::kIdNonSemanticInstructionSet);
1013     const uint32_t inst = extInst & sh::vk::spirv::kNonSemanticInstructionMask;
1014 
1015     // Recover the additional overview flags placed in the instruction id.
1016     if (inst == sh::vk::spirv::kNonSemanticOverview)
1017     {
1018         mOverviewFlags = extInst & ~sh::vk::spirv::kNonSemanticInstructionMask;
1019     }
1020 
1021     *instOut = static_cast<sh::vk::spirv::NonSemanticInstruction>(inst);
1022 
1023     return true;
1024 }
1025 
transformExtInst(const uint32_t * instruction)1026 TransformationState SpirvNonSemanticInstructions::transformExtInst(const uint32_t *instruction)
1027 {
1028     return IsNonSemanticInstruction(instruction) && mIsLastPass ? TransformationState::Transformed
1029                                                                 : TransformationState::Unchanged;
1030 }
1031 
1032 namespace ID
1033 {
1034 namespace
1035 {
1036 [[maybe_unused]] constexpr spirv::IdRef EntryPoint(sh::vk::spirv::kIdEntryPoint);
1037 [[maybe_unused]] constexpr spirv::IdRef Void(sh::vk::spirv::kIdVoid);
1038 [[maybe_unused]] constexpr spirv::IdRef Float(sh::vk::spirv::kIdFloat);
1039 [[maybe_unused]] constexpr spirv::IdRef Vec2(sh::vk::spirv::kIdVec2);
1040 [[maybe_unused]] constexpr spirv::IdRef Vec3(sh::vk::spirv::kIdVec3);
1041 [[maybe_unused]] constexpr spirv::IdRef Vec4(sh::vk::spirv::kIdVec4);
1042 [[maybe_unused]] constexpr spirv::IdRef Mat2(sh::vk::spirv::kIdMat2);
1043 [[maybe_unused]] constexpr spirv::IdRef Mat3(sh::vk::spirv::kIdMat3);
1044 [[maybe_unused]] constexpr spirv::IdRef Mat4(sh::vk::spirv::kIdMat4);
1045 [[maybe_unused]] constexpr spirv::IdRef Int(sh::vk::spirv::kIdInt);
1046 [[maybe_unused]] constexpr spirv::IdRef IVec4(sh::vk::spirv::kIdIVec4);
1047 [[maybe_unused]] constexpr spirv::IdRef Uint(sh::vk::spirv::kIdUint);
1048 [[maybe_unused]] constexpr spirv::IdRef IntZero(sh::vk::spirv::kIdIntZero);
1049 [[maybe_unused]] constexpr spirv::IdRef IntOne(sh::vk::spirv::kIdIntOne);
1050 [[maybe_unused]] constexpr spirv::IdRef IntTwo(sh::vk::spirv::kIdIntTwo);
1051 [[maybe_unused]] constexpr spirv::IdRef IntThree(sh::vk::spirv::kIdIntThree);
1052 [[maybe_unused]] constexpr spirv::IdRef IntInputTypePointer(sh::vk::spirv::kIdIntInputTypePointer);
1053 [[maybe_unused]] constexpr spirv::IdRef Vec4OutputTypePointer(
1054     sh::vk::spirv::kIdVec4OutputTypePointer);
1055 [[maybe_unused]] constexpr spirv::IdRef IVec4FunctionTypePointer(
1056     sh::vk::spirv::kIdIVec4FunctionTypePointer);
1057 [[maybe_unused]] constexpr spirv::IdRef OutputPerVertexTypePointer(
1058     sh::vk::spirv::kIdOutputPerVertexTypePointer);
1059 [[maybe_unused]] constexpr spirv::IdRef TransformPositionFunction(
1060     sh::vk::spirv::kIdTransformPositionFunction);
1061 [[maybe_unused]] constexpr spirv::IdRef XfbEmulationGetOffsetsFunction(
1062     sh::vk::spirv::kIdXfbEmulationGetOffsetsFunction);
1063 [[maybe_unused]] constexpr spirv::IdRef SampleID(sh::vk::spirv::kIdSampleID);
1064 
1065 [[maybe_unused]] constexpr spirv::IdRef InputPerVertexBlock(sh::vk::spirv::kIdInputPerVertexBlock);
1066 [[maybe_unused]] constexpr spirv::IdRef OutputPerVertexBlock(
1067     sh::vk::spirv::kIdOutputPerVertexBlock);
1068 [[maybe_unused]] constexpr spirv::IdRef OutputPerVertexVar(sh::vk::spirv::kIdOutputPerVertexVar);
1069 [[maybe_unused]] constexpr spirv::IdRef XfbExtensionPosition(
1070     sh::vk::spirv::kIdXfbExtensionPosition);
1071 [[maybe_unused]] constexpr spirv::IdRef XfbEmulationBufferBlockZero(
1072     sh::vk::spirv::kIdXfbEmulationBufferBlockZero);
1073 [[maybe_unused]] constexpr spirv::IdRef XfbEmulationBufferBlockOne(
1074     sh::vk::spirv::kIdXfbEmulationBufferBlockOne);
1075 [[maybe_unused]] constexpr spirv::IdRef XfbEmulationBufferBlockTwo(
1076     sh::vk::spirv::kIdXfbEmulationBufferBlockTwo);
1077 [[maybe_unused]] constexpr spirv::IdRef XfbEmulationBufferBlockThree(
1078     sh::vk::spirv::kIdXfbEmulationBufferBlockThree);
1079 }  // anonymous namespace
1080 }  // namespace ID
1081 
1082 // Helper class that trims input and output gl_PerVertex declarations to remove inactive builtins.
1083 //
1084 // gl_PerVertex is unique in that it's the only builtin of struct type.  This struct is pruned
1085 // by removing trailing inactive members.  Note that intermediate stages, i.e. geometry and
1086 // tessellation have two gl_PerVertex declarations, one for input and one for output.
1087 class SpirvPerVertexTrimmer final : angle::NonCopyable
1088 {
1089   public:
SpirvPerVertexTrimmer(const SpvTransformOptions & options,const ShaderInterfaceVariableInfoMap & variableInfoMap)1090     SpirvPerVertexTrimmer(const SpvTransformOptions &options,
1091                           const ShaderInterfaceVariableInfoMap &variableInfoMap)
1092         : mInputPerVertexMaxActiveMember{gl::PerVertexMember::Position},
1093           mOutputPerVertexMaxActiveMember{gl::PerVertexMember::Position},
1094           mInputPerVertexMaxActiveMemberIndex(0),
1095           mOutputPerVertexMaxActiveMemberIndex(0)
1096     {
1097         const gl::PerVertexMemberBitSet inputPerVertexActiveMembers =
1098             variableInfoMap.getInputPerVertexActiveMembers()[options.shaderType];
1099         const gl::PerVertexMemberBitSet outputPerVertexActiveMembers =
1100             variableInfoMap.getOutputPerVertexActiveMembers()[options.shaderType];
1101 
1102         // Currently, this transformation does not trim inactive members in between two active
1103         // members.
1104         if (inputPerVertexActiveMembers.any())
1105         {
1106             mInputPerVertexMaxActiveMember = inputPerVertexActiveMembers.last();
1107         }
1108         if (outputPerVertexActiveMembers.any())
1109         {
1110             mOutputPerVertexMaxActiveMember = outputPerVertexActiveMembers.last();
1111         }
1112     }
1113 
1114     void visitMemberDecorate(spirv::IdRef id,
1115                              spirv::LiteralInteger member,
1116                              spv::Decoration decoration,
1117                              const spirv::LiteralIntegerList &valueList);
1118 
1119     TransformationState transformMemberDecorate(spirv::IdRef typeId,
1120                                                 spirv::LiteralInteger member,
1121                                                 spv::Decoration decoration);
1122     TransformationState transformMemberName(spirv::IdRef id,
1123                                             spirv::LiteralInteger member,
1124                                             const spirv::LiteralString &name);
1125     TransformationState transformTypeStruct(spirv::IdResult id,
1126                                             spirv::IdRefList *memberList,
1127                                             spirv::Blob *blobOut);
1128 
1129   private:
isPerVertex(spirv::IdRef typeId) const1130     bool isPerVertex(spirv::IdRef typeId) const
1131     {
1132         return typeId == ID::OutputPerVertexBlock || typeId == ID::InputPerVertexBlock;
1133     }
getPerVertexMaxActiveMember(spirv::IdRef typeId) const1134     uint32_t getPerVertexMaxActiveMember(spirv::IdRef typeId) const
1135     {
1136         ASSERT(isPerVertex(typeId));
1137         return typeId == ID::OutputPerVertexBlock ? mOutputPerVertexMaxActiveMemberIndex
1138                                                   : mInputPerVertexMaxActiveMemberIndex;
1139     }
1140 
1141     gl::PerVertexMember mInputPerVertexMaxActiveMember;
1142     gl::PerVertexMember mOutputPerVertexMaxActiveMember;
1143 
1144     // If gl_ClipDistance and gl_CullDistance are not used, they are missing from gl_PerVertex.  So
1145     // the index of gl_CullDistance may not be the same as the value of
1146     // gl::PerVertexMember::CullDistance.
1147     //
1148     // By looking at OpMemberDecorate %kIdInput/OutputPerVertexBlock <Index> BuiltIn <Member>, the
1149     // <Index> corresponding to mInput/OutputPerVertexMaxActiveMember is discovered and kept in
1150     // mInput/OutputPerVertexMaxActiveMemberIndex
1151     uint32_t mInputPerVertexMaxActiveMemberIndex;
1152     uint32_t mOutputPerVertexMaxActiveMemberIndex;
1153 };
1154 
visitMemberDecorate(spirv::IdRef id,spirv::LiteralInteger member,spv::Decoration decoration,const spirv::LiteralIntegerList & valueList)1155 void SpirvPerVertexTrimmer::visitMemberDecorate(spirv::IdRef id,
1156                                                 spirv::LiteralInteger member,
1157                                                 spv::Decoration decoration,
1158                                                 const spirv::LiteralIntegerList &valueList)
1159 {
1160     if (decoration != spv::DecorationBuiltIn || !isPerVertex(id))
1161     {
1162         return;
1163     }
1164 
1165     // Map spv::BuiltIn to gl::PerVertexMember.
1166     ASSERT(!valueList.empty());
1167     const uint32_t builtIn              = valueList[0];
1168     gl::PerVertexMember perVertexMember = gl::PerVertexMember::Position;
1169     switch (builtIn)
1170     {
1171         case spv::BuiltInPosition:
1172             perVertexMember = gl::PerVertexMember::Position;
1173             break;
1174         case spv::BuiltInPointSize:
1175             perVertexMember = gl::PerVertexMember::PointSize;
1176             break;
1177         case spv::BuiltInClipDistance:
1178             perVertexMember = gl::PerVertexMember::ClipDistance;
1179             break;
1180         case spv::BuiltInCullDistance:
1181             perVertexMember = gl::PerVertexMember::CullDistance;
1182             break;
1183         default:
1184             UNREACHABLE();
1185     }
1186 
1187     if (id == ID::OutputPerVertexBlock && perVertexMember == mOutputPerVertexMaxActiveMember)
1188     {
1189         mOutputPerVertexMaxActiveMemberIndex = member;
1190     }
1191     else if (id == ID::InputPerVertexBlock && perVertexMember == mInputPerVertexMaxActiveMember)
1192     {
1193         mInputPerVertexMaxActiveMemberIndex = member;
1194     }
1195 }
1196 
transformMemberDecorate(spirv::IdRef typeId,spirv::LiteralInteger member,spv::Decoration decoration)1197 TransformationState SpirvPerVertexTrimmer::transformMemberDecorate(spirv::IdRef typeId,
1198                                                                    spirv::LiteralInteger member,
1199                                                                    spv::Decoration decoration)
1200 {
1201     // Transform the following:
1202     //
1203     // - OpMemberDecorate %gl_PerVertex N BuiltIn B
1204     // - OpMemberDecorate %gl_PerVertex N Invariant
1205     // - OpMemberDecorate %gl_PerVertex N RelaxedPrecision
1206     if (!isPerVertex(typeId) ||
1207         (decoration != spv::DecorationBuiltIn && decoration != spv::DecorationInvariant &&
1208          decoration != spv::DecorationRelaxedPrecision))
1209     {
1210         return TransformationState::Unchanged;
1211     }
1212 
1213     // Drop stripped fields.
1214     return member > getPerVertexMaxActiveMember(typeId) ? TransformationState::Transformed
1215                                                         : TransformationState::Unchanged;
1216 }
1217 
transformMemberName(spirv::IdRef id,spirv::LiteralInteger member,const spirv::LiteralString & name)1218 TransformationState SpirvPerVertexTrimmer::transformMemberName(spirv::IdRef id,
1219                                                                spirv::LiteralInteger member,
1220                                                                const spirv::LiteralString &name)
1221 {
1222     // Remove the instruction if it's a stripped member of gl_PerVertex.
1223     return isPerVertex(id) && member > getPerVertexMaxActiveMember(id)
1224                ? TransformationState::Transformed
1225                : TransformationState::Unchanged;
1226 }
1227 
transformTypeStruct(spirv::IdResult id,spirv::IdRefList * memberList,spirv::Blob * blobOut)1228 TransformationState SpirvPerVertexTrimmer::transformTypeStruct(spirv::IdResult id,
1229                                                                spirv::IdRefList *memberList,
1230                                                                spirv::Blob *blobOut)
1231 {
1232     if (!isPerVertex(id))
1233     {
1234         return TransformationState::Unchanged;
1235     }
1236 
1237     const uint32_t maxMembers = getPerVertexMaxActiveMember(id);
1238 
1239     // Change the definition of the gl_PerVertex struct by stripping unused fields at the end.
1240     const uint32_t memberCount = maxMembers + 1;
1241     memberList->resize_down(memberCount);
1242 
1243     spirv::WriteTypeStruct(blobOut, id, *memberList);
1244 
1245     return TransformationState::Transformed;
1246 }
1247 
1248 // Helper class that removes inactive varyings and replaces them with Private variables.
1249 class SpirvInactiveVaryingRemover final : angle::NonCopyable
1250 {
1251   public:
SpirvInactiveVaryingRemover()1252     SpirvInactiveVaryingRemover() {}
1253 
1254     void init(size_t indexCount);
1255 
1256     TransformationState transformAccessChain(spirv::IdResultType typeId,
1257                                              spirv::IdResult id,
1258                                              spirv::IdRef baseId,
1259                                              const spirv::IdRefList &indexList,
1260                                              spirv::Blob *blobOut);
1261     TransformationState transformDecorate(const ShaderInterfaceVariableInfo &info,
1262                                           gl::ShaderType shaderType,
1263                                           spirv::IdRef id,
1264                                           spv::Decoration decoration,
1265                                           const spirv::LiteralIntegerList &decorationValues,
1266                                           spirv::Blob *blobOut);
1267     TransformationState transformTypePointer(spirv::IdResult id,
1268                                              spv::StorageClass storageClass,
1269                                              spirv::IdRef typeId,
1270                                              spirv::Blob *blobOut);
1271     TransformationState transformVariable(spirv::IdResultType typeId,
1272                                           spirv::IdResult id,
1273                                           spv::StorageClass storageClass,
1274                                           spirv::Blob *blobOut);
1275 
1276     void modifyEntryPointInterfaceList(
1277         const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1278         gl::ShaderType shaderType,
1279         spirv::IdRefList *interfaceList);
1280 
isInactive(spirv::IdRef id) const1281     bool isInactive(spirv::IdRef id) const { return mIsInactiveById[id]; }
1282 
1283   private:
1284     // Each OpTypePointer instruction that defines a type with the Output storage class is
1285     // duplicated with a similar instruction but which defines a type with the Private storage
1286     // class.  If inactive varyings are encountered, its type is changed to the Private one.  The
1287     // following vector maps the Output type id to the corresponding Private one.
1288     std::vector<spirv::IdRef> mTypePointerTransformedId;
1289 
1290     // Whether a variable has been marked inactive.
1291     std::vector<bool> mIsInactiveById;
1292 };
1293 
init(size_t indexBound)1294 void SpirvInactiveVaryingRemover::init(size_t indexBound)
1295 {
1296     // Allocate storage for Output type pointer map.  At index i, this vector holds the identical
1297     // type as %i except for its storage class turned to Private.
1298     mTypePointerTransformedId.resize(indexBound);
1299     mIsInactiveById.resize(indexBound, false);
1300 }
1301 
transformAccessChain(spirv::IdResultType typeId,spirv::IdResult id,spirv::IdRef baseId,const spirv::IdRefList & indexList,spirv::Blob * blobOut)1302 TransformationState SpirvInactiveVaryingRemover::transformAccessChain(
1303     spirv::IdResultType typeId,
1304     spirv::IdResult id,
1305     spirv::IdRef baseId,
1306     const spirv::IdRefList &indexList,
1307     spirv::Blob *blobOut)
1308 {
1309     // Modifiy the instruction to use the private type.
1310     ASSERT(typeId < mTypePointerTransformedId.size());
1311     ASSERT(mTypePointerTransformedId[typeId].valid());
1312 
1313     spirv::WriteAccessChain(blobOut, mTypePointerTransformedId[typeId], id, baseId, indexList);
1314 
1315     return TransformationState::Transformed;
1316 }
1317 
transformDecorate(const ShaderInterfaceVariableInfo & info,gl::ShaderType shaderType,spirv::IdRef id,spv::Decoration decoration,const spirv::LiteralIntegerList & decorationValues,spirv::Blob * blobOut)1318 TransformationState SpirvInactiveVaryingRemover::transformDecorate(
1319     const ShaderInterfaceVariableInfo &info,
1320     gl::ShaderType shaderType,
1321     spirv::IdRef id,
1322     spv::Decoration decoration,
1323     const spirv::LiteralIntegerList &decorationValues,
1324     spirv::Blob *blobOut)
1325 {
1326     // If it's an inactive varying, remove the decoration altogether.
1327     return info.activeStages[shaderType] ? TransformationState::Unchanged
1328                                          : TransformationState::Transformed;
1329 }
1330 
modifyEntryPointInterfaceList(const std::vector<const ShaderInterfaceVariableInfo * > & variableInfoById,gl::ShaderType shaderType,spirv::IdRefList * interfaceList)1331 void SpirvInactiveVaryingRemover::modifyEntryPointInterfaceList(
1332     const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1333     gl::ShaderType shaderType,
1334     spirv::IdRefList *interfaceList)
1335 {
1336     // Filter out inactive varyings from entry point interface declaration.
1337     size_t writeIndex = 0;
1338     for (size_t index = 0; index < interfaceList->size(); ++index)
1339     {
1340         spirv::IdRef id((*interfaceList)[index]);
1341         const ShaderInterfaceVariableInfo *info = variableInfoById[id];
1342 
1343         ASSERT(info);
1344 
1345         if (!info->activeStages[shaderType])
1346         {
1347             continue;
1348         }
1349 
1350         (*interfaceList)[writeIndex] = id;
1351         ++writeIndex;
1352     }
1353 
1354     // Update the number of interface variables.
1355     interfaceList->resize_down(writeIndex);
1356 }
1357 
transformTypePointer(spirv::IdResult id,spv::StorageClass storageClass,spirv::IdRef typeId,spirv::Blob * blobOut)1358 TransformationState SpirvInactiveVaryingRemover::transformTypePointer(
1359     spirv::IdResult id,
1360     spv::StorageClass storageClass,
1361     spirv::IdRef typeId,
1362     spirv::Blob *blobOut)
1363 {
1364     // If the storage class is output, this may be used to create a variable corresponding to an
1365     // inactive varying, or if that varying is a struct, an Op*AccessChain retrieving a field of
1366     // that inactive varying.
1367     //
1368     // SPIR-V specifies the storage class both on the type and the variable declaration.  Otherwise
1369     // it would have been sufficient to modify the OpVariable instruction. For simplicity, duplicate
1370     // every "OpTypePointer Output" and "OpTypePointer Input" instruction except with the Private
1371     // storage class, in case it may be necessary later.
1372 
1373     // Cannot create a Private type declaration from builtins such as gl_PerVertex.
1374     if (typeId == sh::vk::spirv::kIdInputPerVertexBlock ||
1375         typeId == sh::vk::spirv::kIdOutputPerVertexBlock ||
1376         typeId == sh::vk::spirv::kIdInputPerVertexBlockArray ||
1377         typeId == sh::vk::spirv::kIdOutputPerVertexBlockArray)
1378     {
1379         return TransformationState::Unchanged;
1380     }
1381 
1382     if (storageClass != spv::StorageClassOutput && storageClass != spv::StorageClassInput)
1383     {
1384         return TransformationState::Unchanged;
1385     }
1386 
1387     const spirv::IdRef newPrivateTypeId(SpirvTransformerBase::GetNewId(blobOut));
1388 
1389     // Write OpTypePointer for the new PrivateType.
1390     spirv::WriteTypePointer(blobOut, newPrivateTypeId, spv::StorageClassPrivate, typeId);
1391 
1392     // Remember the id of the replacement.
1393     ASSERT(id < mTypePointerTransformedId.size());
1394     mTypePointerTransformedId[id] = newPrivateTypeId;
1395 
1396     // The original instruction should still be present as well.  At this point, we don't know
1397     // whether we will need the original or Private type.
1398     return TransformationState::Unchanged;
1399 }
1400 
transformVariable(spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass,spirv::Blob * blobOut)1401 TransformationState SpirvInactiveVaryingRemover::transformVariable(spirv::IdResultType typeId,
1402                                                                    spirv::IdResult id,
1403                                                                    spv::StorageClass storageClass,
1404                                                                    spirv::Blob *blobOut)
1405 {
1406     ASSERT(storageClass == spv::StorageClassOutput || storageClass == spv::StorageClassInput);
1407 
1408     ASSERT(typeId < mTypePointerTransformedId.size());
1409     ASSERT(mTypePointerTransformedId[typeId].valid());
1410     spirv::WriteVariable(blobOut, mTypePointerTransformedId[typeId], id, spv::StorageClassPrivate,
1411                          nullptr);
1412 
1413     mIsInactiveById[id] = true;
1414 
1415     return TransformationState::Transformed;
1416 }
1417 
1418 // Helper class that fixes varying precisions so they match between shader stages.
1419 class SpirvVaryingPrecisionFixer final : angle::NonCopyable
1420 {
1421   public:
SpirvVaryingPrecisionFixer()1422     SpirvVaryingPrecisionFixer() {}
1423 
1424     void init(size_t indexBound);
1425 
1426     void visitTypePointer(spirv::IdResult id, spv::StorageClass storageClass, spirv::IdRef typeId);
1427     void visitVariable(const ShaderInterfaceVariableInfo &info,
1428                        gl::ShaderType shaderType,
1429                        spirv::IdResultType typeId,
1430                        spirv::IdResult id,
1431                        spv::StorageClass storageClass,
1432                        spirv::Blob *blobOut);
1433 
1434     TransformationState transformVariable(const ShaderInterfaceVariableInfo &info,
1435                                           spirv::IdResultType typeId,
1436                                           spirv::IdResult id,
1437                                           spv::StorageClass storageClass,
1438                                           spirv::Blob *blobOut);
1439 
1440     void modifyEntryPointInterfaceList(spirv::IdRefList *interfaceList);
1441     void addDecorate(spirv::IdRef replacedId, spirv::Blob *blobOut);
1442     void writeInputPreamble(
1443         const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1444         gl::ShaderType shaderType,
1445         spirv::Blob *blobOut);
1446     void writeOutputPrologue(
1447         const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1448         gl::ShaderType shaderType,
1449         spirv::Blob *blobOut);
1450 
isReplaced(spirv::IdRef id) const1451     bool isReplaced(spirv::IdRef id) const { return mFixedVaryingId[id].valid(); }
getReplacementId(spirv::IdRef id) const1452     spirv::IdRef getReplacementId(spirv::IdRef id) const
1453     {
1454         return mFixedVaryingId[id].valid() ? mFixedVaryingId[id] : id;
1455     }
1456 
1457   private:
1458     std::vector<spirv::IdRef> mTypePointerTypeId;
1459     std::vector<spirv::IdRef> mFixedVaryingId;
1460     std::vector<spirv::IdRef> mFixedVaryingTypeId;
1461 };
1462 
init(size_t indexBound)1463 void SpirvVaryingPrecisionFixer::init(size_t indexBound)
1464 {
1465     // Allocate storage for precision mismatch fix up.
1466     mTypePointerTypeId.resize(indexBound);
1467     mFixedVaryingId.resize(indexBound);
1468     mFixedVaryingTypeId.resize(indexBound);
1469 }
1470 
visitTypePointer(spirv::IdResult id,spv::StorageClass storageClass,spirv::IdRef typeId)1471 void SpirvVaryingPrecisionFixer::visitTypePointer(spirv::IdResult id,
1472                                                   spv::StorageClass storageClass,
1473                                                   spirv::IdRef typeId)
1474 {
1475     mTypePointerTypeId[id] = typeId;
1476 }
1477 
visitVariable(const ShaderInterfaceVariableInfo & info,gl::ShaderType shaderType,spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass,spirv::Blob * blobOut)1478 void SpirvVaryingPrecisionFixer::visitVariable(const ShaderInterfaceVariableInfo &info,
1479                                                gl::ShaderType shaderType,
1480                                                spirv::IdResultType typeId,
1481                                                spirv::IdResult id,
1482                                                spv::StorageClass storageClass,
1483                                                spirv::Blob *blobOut)
1484 {
1485     if (info.useRelaxedPrecision && info.activeStages[shaderType] && !mFixedVaryingId[id].valid())
1486     {
1487         mFixedVaryingId[id]     = SpirvTransformerBase::GetNewId(blobOut);
1488         mFixedVaryingTypeId[id] = typeId;
1489     }
1490 }
1491 
transformVariable(const ShaderInterfaceVariableInfo & info,spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass,spirv::Blob * blobOut)1492 TransformationState SpirvVaryingPrecisionFixer::transformVariable(
1493     const ShaderInterfaceVariableInfo &info,
1494     spirv::IdResultType typeId,
1495     spirv::IdResult id,
1496     spv::StorageClass storageClass,
1497     spirv::Blob *blobOut)
1498 {
1499     if (info.useRelaxedPrecision &&
1500         (storageClass == spv::StorageClassOutput || storageClass == spv::StorageClassInput))
1501     {
1502         // Change existing OpVariable to use fixedVaryingId
1503         ASSERT(mFixedVaryingId[id].valid());
1504         spirv::WriteVariable(blobOut, typeId, mFixedVaryingId[id], storageClass, nullptr);
1505 
1506         return TransformationState::Transformed;
1507     }
1508     return TransformationState::Unchanged;
1509 }
1510 
writeInputPreamble(const std::vector<const ShaderInterfaceVariableInfo * > & variableInfoById,gl::ShaderType shaderType,spirv::Blob * blobOut)1511 void SpirvVaryingPrecisionFixer::writeInputPreamble(
1512     const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1513     gl::ShaderType shaderType,
1514     spirv::Blob *blobOut)
1515 {
1516     if (shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::Compute)
1517     {
1518         return;
1519     }
1520 
1521     // Copy from corrected varyings to temp global variables with original precision.
1522     for (uint32_t idIndex = spirv::kMinValidId; idIndex < variableInfoById.size(); idIndex++)
1523     {
1524         const spirv::IdRef id(idIndex);
1525         const ShaderInterfaceVariableInfo *info = variableInfoById[id];
1526         if (info && info->useRelaxedPrecision && info->activeStages[shaderType] &&
1527             info->varyingIsInput)
1528         {
1529             // This is an input varying, need to cast the mediump value that came from
1530             // the previous stage into a highp value that the code wants to work with.
1531             ASSERT(mFixedVaryingTypeId[id].valid());
1532 
1533             // Build OpLoad instruction to load the mediump value into a temporary
1534             const spirv::IdRef tempVar(SpirvTransformerBase::GetNewId(blobOut));
1535             const spirv::IdRef tempVarType(mTypePointerTypeId[mFixedVaryingTypeId[id]]);
1536             ASSERT(tempVarType.valid());
1537 
1538             spirv::WriteLoad(blobOut, tempVarType, tempVar, mFixedVaryingId[id], nullptr);
1539 
1540             // Build OpStore instruction to cast the mediump value to highp for use in
1541             // the function
1542             spirv::WriteStore(blobOut, id, tempVar, nullptr);
1543         }
1544     }
1545 }
1546 
modifyEntryPointInterfaceList(spirv::IdRefList * interfaceList)1547 void SpirvVaryingPrecisionFixer::modifyEntryPointInterfaceList(spirv::IdRefList *interfaceList)
1548 {
1549     // Modify interface list if any ID was replaced due to varying precision mismatch.
1550     for (size_t index = 0; index < interfaceList->size(); ++index)
1551     {
1552         (*interfaceList)[index] = getReplacementId((*interfaceList)[index]);
1553     }
1554 }
1555 
addDecorate(spirv::IdRef replacedId,spirv::Blob * blobOut)1556 void SpirvVaryingPrecisionFixer::addDecorate(spirv::IdRef replacedId, spirv::Blob *blobOut)
1557 {
1558     spirv::WriteDecorate(blobOut, replacedId, spv::DecorationRelaxedPrecision, {});
1559 }
1560 
writeOutputPrologue(const std::vector<const ShaderInterfaceVariableInfo * > & variableInfoById,gl::ShaderType shaderType,spirv::Blob * blobOut)1561 void SpirvVaryingPrecisionFixer::writeOutputPrologue(
1562     const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1563     gl::ShaderType shaderType,
1564     spirv::Blob *blobOut)
1565 {
1566     if (shaderType == gl::ShaderType::Fragment || shaderType == gl::ShaderType::Compute)
1567     {
1568         return;
1569     }
1570 
1571     // Copy from temp global variables with original precision to corrected varyings.
1572     for (uint32_t idIndex = spirv::kMinValidId; idIndex < variableInfoById.size(); idIndex++)
1573     {
1574         const spirv::IdRef id(idIndex);
1575         const ShaderInterfaceVariableInfo *info = variableInfoById[id];
1576         if (info && info->useRelaxedPrecision && info->activeStages[shaderType] &&
1577             info->varyingIsOutput)
1578         {
1579             ASSERT(mFixedVaryingTypeId[id].valid());
1580 
1581             // Build OpLoad instruction to load the highp value into a temporary
1582             const spirv::IdRef tempVar(SpirvTransformerBase::GetNewId(blobOut));
1583             const spirv::IdRef tempVarType(mTypePointerTypeId[mFixedVaryingTypeId[id]]);
1584             ASSERT(tempVarType.valid());
1585 
1586             spirv::WriteLoad(blobOut, tempVarType, tempVar, id, nullptr);
1587 
1588             // Build OpStore instruction to cast the highp value to mediump for output
1589             spirv::WriteStore(blobOut, mFixedVaryingId[id], tempVar, nullptr);
1590         }
1591     }
1592 }
1593 
1594 // Helper class that generates code for transform feedback
1595 class SpirvTransformFeedbackCodeGenerator final : angle::NonCopyable
1596 {
1597   public:
SpirvTransformFeedbackCodeGenerator(bool isEmulated)1598     SpirvTransformFeedbackCodeGenerator(bool isEmulated)
1599         : mIsEmulated(isEmulated),
1600           mHasTransformFeedbackOutput(false),
1601           mIsPositionCapturedByTransformFeedbackExtension(false)
1602     {}
1603 
1604     void visitVariable(const ShaderInterfaceVariableInfo &info,
1605                        gl::ShaderType shaderType,
1606                        spirv::IdResultType typeId,
1607                        spirv::IdResult id,
1608                        spv::StorageClass storageClass);
1609 
1610     TransformationState transformCapability(spv::Capability capability, spirv::Blob *blobOut);
1611     TransformationState transformDecorate(const ShaderInterfaceVariableInfo *info,
1612                                           gl::ShaderType shaderType,
1613                                           spirv::IdRef id,
1614                                           spv::Decoration decoration,
1615                                           const spirv::LiteralIntegerList &decorationValues,
1616                                           spirv::Blob *blobOut);
1617     TransformationState transformMemberDecorate(const ShaderInterfaceVariableInfo *info,
1618                                                 gl::ShaderType shaderType,
1619                                                 spirv::IdRef id,
1620                                                 spirv::LiteralInteger member,
1621                                                 spv::Decoration decoration,
1622                                                 spirv::Blob *blobOut);
1623     TransformationState transformName(spirv::IdRef id, spirv::LiteralString name);
1624     TransformationState transformMemberName(spirv::IdRef id,
1625                                             spirv::LiteralInteger member,
1626                                             spirv::LiteralString name);
1627     TransformationState transformTypeStruct(const ShaderInterfaceVariableInfo *info,
1628                                             gl::ShaderType shaderType,
1629                                             spirv::IdResult id,
1630                                             const spirv::IdRefList &memberList,
1631                                             spirv::Blob *blobOut);
1632     TransformationState transformTypePointer(const ShaderInterfaceVariableInfo *info,
1633                                              gl::ShaderType shaderType,
1634                                              spirv::IdResult id,
1635                                              spv::StorageClass storageClass,
1636                                              spirv::IdRef typeId,
1637                                              spirv::Blob *blobOut);
1638     TransformationState transformVariable(const ShaderInterfaceVariableInfo &info,
1639                                           const ShaderInterfaceVariableInfoMap &variableInfoMap,
1640                                           gl::ShaderType shaderType,
1641                                           spirv::IdResultType typeId,
1642                                           spirv::IdResult id,
1643                                           spv::StorageClass storageClass);
1644 
1645     void writePendingDeclarations(
1646         const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1647         spirv::Blob *blobOut);
1648     void writeTransformFeedbackExtensionOutput(spirv::IdRef positionId, spirv::Blob *blobOut);
1649     void writeTransformFeedbackEmulationOutput(
1650         const SpirvInactiveVaryingRemover &inactiveVaryingRemover,
1651         const SpirvVaryingPrecisionFixer &varyingPrecisionFixer,
1652         const bool usePrecisionFixer,
1653         spirv::Blob *blobOut);
1654     void addExecutionMode(spirv::IdRef entryPointId, spirv::Blob *blobOut);
1655     void addMemberDecorate(const ShaderInterfaceVariableInfo &info,
1656                            spirv::IdRef id,
1657                            spirv::Blob *blobOut);
1658     void addDecorate(const ShaderInterfaceVariableInfo &info,
1659                      spirv::IdRef id,
1660                      spirv::Blob *blobOut);
1661 
1662   private:
1663     void gatherXfbVaryings(const ShaderInterfaceVariableInfo &info, spirv::IdRef id);
1664     void visitXfbVarying(const ShaderInterfaceVariableXfbInfo &xfb,
1665                          spirv::IdRef baseId,
1666                          uint32_t fieldIndex);
1667     TransformationState transformTypeHelper(const ShaderInterfaceVariableInfo *info,
1668                                             gl::ShaderType shaderType,
1669                                             spirv::IdResult id);
1670     void writeIntConstant(uint32_t value, spirv::IdRef intId, spirv::Blob *blobOut);
1671     void getVaryingTypeIds(GLenum componentType,
1672                            bool isPrivate,
1673                            spirv::IdRef *typeIdOut,
1674                            spirv::IdRef *typePtrOut);
1675     void writeGetOffsetsCall(spirv::IdRef xfbOffsets, spirv::Blob *blobOut);
1676     void writeComponentCapture(uint32_t bufferIndex,
1677                                spirv::IdRef xfbOffset,
1678                                spirv::IdRef varyingTypeId,
1679                                spirv::IdRef varyingTypePtr,
1680                                spirv::IdRef varyingBaseId,
1681                                const spirv::IdRefList &accessChainIndices,
1682                                GLenum componentType,
1683                                spirv::Blob *blobOut);
1684 
1685     static constexpr size_t kXfbDecorationCount                           = 3;
1686     static constexpr spv::Decoration kXfbDecorations[kXfbDecorationCount] = {
1687         spv::DecorationXfbBuffer,
1688         spv::DecorationXfbStride,
1689         spv::DecorationOffset,
1690     };
1691 
1692     bool mIsEmulated;
1693     bool mHasTransformFeedbackOutput;
1694 
1695     // Ids needed to generate transform feedback support code.
1696     bool mIsPositionCapturedByTransformFeedbackExtension;
1697     gl::TransformFeedbackBuffersArray<spirv::IdRef> mBufferStrides;
1698     spirv::IdRef mBufferStridesCompositeId;
1699 
1700     // Type and constant ids:
1701     //
1702     // - mFloatOutputPointerId: id of OpTypePointer Output %kIdFloat
1703     // - mIntOutputPointerId: id of OpTypePointer Output %kIdInt
1704     // - mUintOutputPointerId: id of OpTypePointer Output %kIdUint
1705     // - mFloatPrivatePointerId, mIntPrivatePointerId, mUintPrivatePointerId: identical to the
1706     //   above, but with the Private storage class.  Used to load from varyings that have been
1707     //   replaced as part of precision mismatch fixup.
1708     // - mFloatUniformPointerId: id of OpTypePointer Uniform %kIdFloat
1709     //
1710     // - mIntNIds[n]: id of OpConstant %kIdInt n
1711     spirv::IdRef mFloatOutputPointerId;
1712     spirv::IdRef mIntOutputPointerId;
1713     spirv::IdRef mUintOutputPointerId;
1714     spirv::IdRef mFloatPrivatePointerId;
1715     spirv::IdRef mIntPrivatePointerId;
1716     spirv::IdRef mUintPrivatePointerId;
1717     spirv::IdRef mFloatUniformPointerId;
1718 
1719     // Id of constants such as row, column and array index.  Integers 0, 1, 2 and 3 are always
1720     // defined by the compiler.
1721     angle::FastVector<spirv::IdRef, 4> mIntNIds;
1722 
1723     // For transform feedback emulation, the captured elements are gathered in a list and sorted.
1724     // This allows the output generation code to always use offset += 1, thus relying on only one
1725     // constant (1).
1726     struct XfbVarying
1727     {
1728         // The varyings are sorted by info.offset.
1729         const ShaderInterfaceVariableXfbInfo *info;
1730         // Id of the base variable.
1731         spirv::IdRef baseId;
1732         // The field index, if a member of an I/O blocks
1733         uint32_t fieldIndex;
1734     };
1735     gl::TransformFeedbackBuffersArray<std::vector<XfbVarying>> mXfbVaryings;
1736 };
1737 
1738 constexpr size_t SpirvTransformFeedbackCodeGenerator::kXfbDecorationCount;
1739 constexpr spv::Decoration SpirvTransformFeedbackCodeGenerator::kXfbDecorations[kXfbDecorationCount];
1740 
visitVariable(const ShaderInterfaceVariableInfo & info,gl::ShaderType shaderType,spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass)1741 void SpirvTransformFeedbackCodeGenerator::visitVariable(const ShaderInterfaceVariableInfo &info,
1742                                                         gl::ShaderType shaderType,
1743                                                         spirv::IdResultType typeId,
1744                                                         spirv::IdResult id,
1745                                                         spv::StorageClass storageClass)
1746 {
1747     if (mIsEmulated)
1748     {
1749         gatherXfbVaryings(info, id);
1750         return;
1751     }
1752 
1753     // Note if the variable is captured by transform feedback.  In that case, the TransformFeedback
1754     // capability needs to be added.
1755     if ((info.xfb.buffer != ShaderInterfaceVariableInfo::kInvalid || !info.fieldXfb.empty()) &&
1756         info.activeStages[shaderType])
1757     {
1758         mHasTransformFeedbackOutput = true;
1759 
1760         // If this is the special ANGLEXfbPosition variable, remember its id to be used for the
1761         // ANGLEXfbPosition = gl_Position; assignment code generation.
1762         if (id == ID::XfbExtensionPosition)
1763         {
1764             mIsPositionCapturedByTransformFeedbackExtension = true;
1765         }
1766     }
1767 }
1768 
transformCapability(spv::Capability capability,spirv::Blob * blobOut)1769 TransformationState SpirvTransformFeedbackCodeGenerator::transformCapability(
1770     spv::Capability capability,
1771     spirv::Blob *blobOut)
1772 {
1773     if (!mHasTransformFeedbackOutput || mIsEmulated)
1774     {
1775         return TransformationState::Unchanged;
1776     }
1777 
1778     // Transform feedback capability shouldn't have already been specified.
1779     ASSERT(capability != spv::CapabilityTransformFeedback);
1780 
1781     // Vulkan shaders have either Shader, Geometry or Tessellation capability.  We find this
1782     // capability, and add the TransformFeedback capability right before it.
1783     if (capability != spv::CapabilityShader && capability != spv::CapabilityGeometry &&
1784         capability != spv::CapabilityTessellation)
1785     {
1786         return TransformationState::Unchanged;
1787     }
1788 
1789     // Write the TransformFeedback capability declaration.
1790     spirv::WriteCapability(blobOut, spv::CapabilityTransformFeedback);
1791 
1792     // The original capability is retained.
1793     return TransformationState::Unchanged;
1794 }
1795 
transformName(spirv::IdRef id,spirv::LiteralString name)1796 TransformationState SpirvTransformFeedbackCodeGenerator::transformName(spirv::IdRef id,
1797                                                                        spirv::LiteralString name)
1798 {
1799     // In the case of ANGLEXfbN, unconditionally remove the variable names.  If transform
1800     // feedback is not active, the corresponding variables will be removed.
1801     switch (id)
1802     {
1803         case sh::vk::spirv::kIdXfbEmulationBufferBlockZero:
1804         case sh::vk::spirv::kIdXfbEmulationBufferBlockOne:
1805         case sh::vk::spirv::kIdXfbEmulationBufferBlockTwo:
1806         case sh::vk::spirv::kIdXfbEmulationBufferBlockThree:
1807         case sh::vk::spirv::kIdXfbEmulationBufferVarZero:
1808         case sh::vk::spirv::kIdXfbEmulationBufferVarOne:
1809         case sh::vk::spirv::kIdXfbEmulationBufferVarTwo:
1810         case sh::vk::spirv::kIdXfbEmulationBufferVarThree:
1811             return TransformationState::Transformed;
1812         default:
1813             return TransformationState::Unchanged;
1814     }
1815 }
1816 
transformMemberName(spirv::IdRef id,spirv::LiteralInteger member,spirv::LiteralString name)1817 TransformationState SpirvTransformFeedbackCodeGenerator::transformMemberName(
1818     spirv::IdRef id,
1819     spirv::LiteralInteger member,
1820     spirv::LiteralString name)
1821 {
1822     switch (id)
1823     {
1824         case sh::vk::spirv::kIdXfbEmulationBufferBlockZero:
1825         case sh::vk::spirv::kIdXfbEmulationBufferBlockOne:
1826         case sh::vk::spirv::kIdXfbEmulationBufferBlockTwo:
1827         case sh::vk::spirv::kIdXfbEmulationBufferBlockThree:
1828             return TransformationState::Transformed;
1829         default:
1830             return TransformationState::Unchanged;
1831     }
1832 }
1833 
transformTypeHelper(const ShaderInterfaceVariableInfo * info,gl::ShaderType shaderType,spirv::IdResult id)1834 TransformationState SpirvTransformFeedbackCodeGenerator::transformTypeHelper(
1835     const ShaderInterfaceVariableInfo *info,
1836     gl::ShaderType shaderType,
1837     spirv::IdResult id)
1838 {
1839     switch (id)
1840     {
1841         case sh::vk::spirv::kIdXfbEmulationBufferBlockZero:
1842         case sh::vk::spirv::kIdXfbEmulationBufferBlockOne:
1843         case sh::vk::spirv::kIdXfbEmulationBufferBlockTwo:
1844         case sh::vk::spirv::kIdXfbEmulationBufferBlockThree:
1845             ASSERT(info);
1846             return info->activeStages[shaderType] ? TransformationState::Unchanged
1847                                                   : TransformationState::Transformed;
1848         default:
1849             return TransformationState::Unchanged;
1850     }
1851 }
1852 
transformDecorate(const ShaderInterfaceVariableInfo * info,gl::ShaderType shaderType,spirv::IdRef id,spv::Decoration decoration,const spirv::LiteralIntegerList & decorationValues,spirv::Blob * blobOut)1853 TransformationState SpirvTransformFeedbackCodeGenerator::transformDecorate(
1854     const ShaderInterfaceVariableInfo *info,
1855     gl::ShaderType shaderType,
1856     spirv::IdRef id,
1857     spv::Decoration decoration,
1858     const spirv::LiteralIntegerList &decorationValues,
1859     spirv::Blob *blobOut)
1860 {
1861     return transformTypeHelper(info, shaderType, id);
1862 }
1863 
transformMemberDecorate(const ShaderInterfaceVariableInfo * info,gl::ShaderType shaderType,spirv::IdRef id,spirv::LiteralInteger member,spv::Decoration decoration,spirv::Blob * blobOut)1864 TransformationState SpirvTransformFeedbackCodeGenerator::transformMemberDecorate(
1865     const ShaderInterfaceVariableInfo *info,
1866     gl::ShaderType shaderType,
1867     spirv::IdRef id,
1868     spirv::LiteralInteger member,
1869     spv::Decoration decoration,
1870     spirv::Blob *blobOut)
1871 {
1872     return transformTypeHelper(info, shaderType, id);
1873 }
1874 
transformTypeStruct(const ShaderInterfaceVariableInfo * info,gl::ShaderType shaderType,spirv::IdResult id,const spirv::IdRefList & memberList,spirv::Blob * blobOut)1875 TransformationState SpirvTransformFeedbackCodeGenerator::transformTypeStruct(
1876     const ShaderInterfaceVariableInfo *info,
1877     gl::ShaderType shaderType,
1878     spirv::IdResult id,
1879     const spirv::IdRefList &memberList,
1880     spirv::Blob *blobOut)
1881 {
1882     return transformTypeHelper(info, shaderType, id);
1883 }
1884 
transformTypePointer(const ShaderInterfaceVariableInfo * info,gl::ShaderType shaderType,spirv::IdResult id,spv::StorageClass storageClass,spirv::IdRef typeId,spirv::Blob * blobOut)1885 TransformationState SpirvTransformFeedbackCodeGenerator::transformTypePointer(
1886     const ShaderInterfaceVariableInfo *info,
1887     gl::ShaderType shaderType,
1888     spirv::IdResult id,
1889     spv::StorageClass storageClass,
1890     spirv::IdRef typeId,
1891     spirv::Blob *blobOut)
1892 {
1893     return transformTypeHelper(info, shaderType, typeId);
1894 }
1895 
transformVariable(const ShaderInterfaceVariableInfo & info,const ShaderInterfaceVariableInfoMap & variableInfoMap,gl::ShaderType shaderType,spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass)1896 TransformationState SpirvTransformFeedbackCodeGenerator::transformVariable(
1897     const ShaderInterfaceVariableInfo &info,
1898     const ShaderInterfaceVariableInfoMap &variableInfoMap,
1899     gl::ShaderType shaderType,
1900     spirv::IdResultType typeId,
1901     spirv::IdResult id,
1902     spv::StorageClass storageClass)
1903 {
1904     // This function is currently called for inactive variables.
1905     ASSERT(!info.activeStages[shaderType]);
1906 
1907     if (shaderType == gl::ShaderType::Vertex && storageClass == spv::StorageClassUniform)
1908     {
1909         // The ANGLEXfbN variables are unconditionally generated and may be inactive.  Remove these
1910         // variables in that case.
1911         ASSERT(&info == &variableInfoMap.getVariableById(shaderType, SpvGetXfbBufferBlockId(0)) ||
1912                &info == &variableInfoMap.getVariableById(shaderType, SpvGetXfbBufferBlockId(1)) ||
1913                &info == &variableInfoMap.getVariableById(shaderType, SpvGetXfbBufferBlockId(2)) ||
1914                &info == &variableInfoMap.getVariableById(shaderType, SpvGetXfbBufferBlockId(3)));
1915 
1916         // Drop the declaration.
1917         return TransformationState::Transformed;
1918     }
1919 
1920     return TransformationState::Unchanged;
1921 }
1922 
gatherXfbVaryings(const ShaderInterfaceVariableInfo & info,spirv::IdRef id)1923 void SpirvTransformFeedbackCodeGenerator::gatherXfbVaryings(const ShaderInterfaceVariableInfo &info,
1924                                                             spirv::IdRef id)
1925 {
1926     visitXfbVarying(info.xfb, id, ShaderInterfaceVariableXfbInfo::kInvalid);
1927 
1928     for (size_t fieldIndex = 0; fieldIndex < info.fieldXfb.size(); ++fieldIndex)
1929     {
1930         visitXfbVarying(info.fieldXfb[fieldIndex], id, static_cast<uint32_t>(fieldIndex));
1931     }
1932 }
1933 
visitXfbVarying(const ShaderInterfaceVariableXfbInfo & xfb,spirv::IdRef baseId,uint32_t fieldIndex)1934 void SpirvTransformFeedbackCodeGenerator::visitXfbVarying(const ShaderInterfaceVariableXfbInfo &xfb,
1935                                                           spirv::IdRef baseId,
1936                                                           uint32_t fieldIndex)
1937 {
1938     for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
1939     {
1940         visitXfbVarying(arrayElement, baseId, fieldIndex);
1941     }
1942 
1943     if (xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid)
1944     {
1945         return;
1946     }
1947 
1948     // Varyings captured to the same buffer have the same stride.
1949     ASSERT(mXfbVaryings[xfb.buffer].empty() ||
1950            mXfbVaryings[xfb.buffer][0].info->stride == xfb.stride);
1951 
1952     mXfbVaryings[xfb.buffer].push_back({&xfb, baseId, fieldIndex});
1953 }
1954 
writeIntConstant(uint32_t value,spirv::IdRef intId,spirv::Blob * blobOut)1955 void SpirvTransformFeedbackCodeGenerator::writeIntConstant(uint32_t value,
1956                                                            spirv::IdRef intId,
1957                                                            spirv::Blob *blobOut)
1958 {
1959     if (value == ShaderInterfaceVariableXfbInfo::kInvalid)
1960     {
1961         return;
1962     }
1963 
1964     if (mIntNIds.size() <= value)
1965     {
1966         // This member never resized down, so new elements can't have previous values.
1967         mIntNIds.resize_maybe_value_reuse(value + 1);
1968     }
1969     else if (mIntNIds[value].valid())
1970     {
1971         return;
1972     }
1973 
1974     mIntNIds[value] = SpirvTransformerBase::GetNewId(blobOut);
1975     spirv::WriteConstant(blobOut, ID::Int, mIntNIds[value],
1976                          spirv::LiteralContextDependentNumber(value));
1977 }
1978 
writePendingDeclarations(const std::vector<const ShaderInterfaceVariableInfo * > & variableInfoById,spirv::Blob * blobOut)1979 void SpirvTransformFeedbackCodeGenerator::writePendingDeclarations(
1980     const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
1981     spirv::Blob *blobOut)
1982 {
1983     if (!mIsEmulated)
1984     {
1985         return;
1986     }
1987 
1988     mFloatOutputPointerId  = SpirvTransformerBase::GetNewId(blobOut);
1989     mFloatPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
1990     spirv::WriteTypePointer(blobOut, mFloatOutputPointerId, spv::StorageClassOutput, ID::Float);
1991     spirv::WriteTypePointer(blobOut, mFloatPrivatePointerId, spv::StorageClassPrivate, ID::Float);
1992 
1993     mIntOutputPointerId  = SpirvTransformerBase::GetNewId(blobOut);
1994     mIntPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
1995     spirv::WriteTypePointer(blobOut, mIntOutputPointerId, spv::StorageClassOutput, ID::Int);
1996     spirv::WriteTypePointer(blobOut, mIntPrivatePointerId, spv::StorageClassPrivate, ID::Int);
1997 
1998     mUintOutputPointerId  = SpirvTransformerBase::GetNewId(blobOut);
1999     mUintPrivatePointerId = SpirvTransformerBase::GetNewId(blobOut);
2000     spirv::WriteTypePointer(blobOut, mUintOutputPointerId, spv::StorageClassOutput, ID::Uint);
2001     spirv::WriteTypePointer(blobOut, mUintPrivatePointerId, spv::StorageClassPrivate, ID::Uint);
2002 
2003     mFloatUniformPointerId = SpirvTransformerBase::GetNewId(blobOut);
2004     spirv::WriteTypePointer(blobOut, mFloatUniformPointerId, spv::StorageClassUniform, ID::Float);
2005 
2006     ASSERT(mIntNIds.empty());
2007     // All new elements initialized later after the resize. Additionally mIntNIds was always empty
2008     // before this resize, so previous value reuse is not possible.
2009     mIntNIds.resize_maybe_value_reuse(4);
2010     mIntNIds[0] = ID::IntZero;
2011     mIntNIds[1] = ID::IntOne;
2012     mIntNIds[2] = ID::IntTwo;
2013     mIntNIds[3] = ID::IntThree;
2014 
2015     spirv::IdRefList compositeIds;
2016     for (const std::vector<XfbVarying> &varyings : mXfbVaryings)
2017     {
2018         if (varyings.empty())
2019         {
2020             compositeIds.push_back(ID::IntZero);
2021             continue;
2022         }
2023 
2024         const ShaderInterfaceVariableXfbInfo *info0 = varyings[0].info;
2025 
2026         // Define the buffer stride constant
2027         ASSERT(info0->stride % sizeof(float) == 0);
2028         uint32_t stride = info0->stride / sizeof(float);
2029 
2030         mBufferStrides[info0->buffer] = SpirvTransformerBase::GetNewId(blobOut);
2031         spirv::WriteConstant(blobOut, ID::Int, mBufferStrides[info0->buffer],
2032                              spirv::LiteralContextDependentNumber(stride));
2033 
2034         compositeIds.push_back(mBufferStrides[info0->buffer]);
2035 
2036         // Define all the constants that would be necessary to load the components of the varying.
2037         for (const XfbVarying &varying : varyings)
2038         {
2039             writeIntConstant(varying.fieldIndex, ID::Int, blobOut);
2040             const ShaderInterfaceVariableXfbInfo *info = varying.info;
2041             if (info->arraySize == ShaderInterfaceVariableXfbInfo::kInvalid)
2042             {
2043                 continue;
2044             }
2045 
2046             uint32_t arrayIndexStart =
2047                 varying.info->arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid
2048                     ? varying.info->arrayIndex
2049                     : 0;
2050             uint32_t arrayIndexEnd = arrayIndexStart + info->arraySize;
2051 
2052             for (uint32_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
2053             {
2054                 writeIntConstant(arrayIndex, ID::Int, blobOut);
2055             }
2056         }
2057     }
2058 
2059     mBufferStridesCompositeId = SpirvTransformerBase::GetNewId(blobOut);
2060     spirv::WriteConstantComposite(blobOut, ID::IVec4, mBufferStridesCompositeId, compositeIds);
2061 }
2062 
writeTransformFeedbackExtensionOutput(spirv::IdRef positionId,spirv::Blob * blobOut)2063 void SpirvTransformFeedbackCodeGenerator::writeTransformFeedbackExtensionOutput(
2064     spirv::IdRef positionId,
2065     spirv::Blob *blobOut)
2066 {
2067     if (mIsEmulated)
2068     {
2069         return;
2070     }
2071 
2072     if (mIsPositionCapturedByTransformFeedbackExtension)
2073     {
2074         spirv::WriteStore(blobOut, ID::XfbExtensionPosition, positionId, nullptr);
2075     }
2076 }
2077 
2078 class AccessChainIndexListAppend final : angle::NonCopyable
2079 {
2080   public:
AccessChainIndexListAppend(bool condition,angle::FastVector<spirv::IdRef,4> intNIds,uint32_t index,spirv::IdRefList * indexList)2081     AccessChainIndexListAppend(bool condition,
2082                                angle::FastVector<spirv::IdRef, 4> intNIds,
2083                                uint32_t index,
2084                                spirv::IdRefList *indexList)
2085         : mCondition(condition), mIndexList(indexList)
2086     {
2087         if (mCondition)
2088         {
2089             mIndexList->push_back(intNIds[index]);
2090         }
2091     }
~AccessChainIndexListAppend()2092     ~AccessChainIndexListAppend()
2093     {
2094         if (mCondition)
2095         {
2096             mIndexList->pop_back();
2097         }
2098     }
2099 
2100   private:
2101     bool mCondition;
2102     spirv::IdRefList *mIndexList;
2103 };
2104 
writeTransformFeedbackEmulationOutput(const SpirvInactiveVaryingRemover & inactiveVaryingRemover,const SpirvVaryingPrecisionFixer & varyingPrecisionFixer,const bool usePrecisionFixer,spirv::Blob * blobOut)2105 void SpirvTransformFeedbackCodeGenerator::writeTransformFeedbackEmulationOutput(
2106     const SpirvInactiveVaryingRemover &inactiveVaryingRemover,
2107     const SpirvVaryingPrecisionFixer &varyingPrecisionFixer,
2108     const bool usePrecisionFixer,
2109     spirv::Blob *blobOut)
2110 {
2111     if (!mIsEmulated)
2112     {
2113         return;
2114     }
2115 
2116     // First, sort the varyings by offset, to simplify calculation of the output offset.
2117     for (std::vector<XfbVarying> &varyings : mXfbVaryings)
2118     {
2119         std::sort(varyings.begin(), varyings.end(),
2120                   [](const XfbVarying &first, const XfbVarying &second) {
2121                       return first.info->offset < second.info->offset;
2122                   });
2123     }
2124 
2125     // The following code is generated for transform feedback emulation:
2126     //
2127     //     ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
2128     //     // For buffer N:
2129     //     int xfbOffset = xfbOffsets[N]
2130     //     ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
2131     //     xfbOffset += 1;
2132     //     ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col + 1]
2133     //     xfbOffset += 1;
2134     //     ...
2135     //
2136     // The following pieces of SPIR-V code are generated according to the above:
2137     //
2138     // - For the initial offsets calculation:
2139     //
2140     //    %xfbOffsetsResult = OpFunctionCall %ivec4 %ANGLEGetXfbOffsets %stridesComposite
2141     //       %xfbOffsetsVar = OpVariable %kIdIVec4FunctionTypePointer Function
2142     //                        OpStore %xfbOffsetsVar %xfbOffsetsResult
2143     //          %xfbOffsets = OpLoad %ivec4 %xfbOffsetsVar
2144     //
2145     // - Initial code for each buffer N:
2146     //
2147     //           %xfbOffset = OpCompositeExtract %int %xfbOffsets N
2148     //
2149     // - For each varying being captured:
2150     //
2151     //                        // Load the component
2152     //        %componentPtr = OpAccessChain %floatOutputPtr %baseId %field %arrayIndex %row %col
2153     //           %component = OpLoad %float %componentPtr
2154     //                        // Store in xfb output
2155     //           %xfbOutPtr = OpAccessChain %floatUniformPtr %xfbBufferN %int0 %xfbOffset
2156     //                        OpStore %xfbOutPtr %component
2157     //                        // Increment offset
2158     //           %xfbOffset = OpIAdd %int %xfbOffset %int1
2159     //
2160     //   Note that if the varying being captured is integer, the first two instructions above would
2161     //   use the intger equivalent types, and the following instruction would bitcast it to float
2162     //   for storage:
2163     //
2164     //             %asFloat = OpBitcast %float %component
2165     //
2166 
2167     spirv::IdRef xfbOffsets;
2168 
2169     if (!mXfbVaryings.empty())
2170     {
2171         xfbOffsets = SpirvTransformerBase::GetNewId(blobOut);
2172 
2173         // ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
2174         writeGetOffsetsCall(xfbOffsets, blobOut);
2175     }
2176 
2177     // Go over the buffers one by one and capture the varyings.
2178     for (uint32_t bufferIndex = 0; bufferIndex < mXfbVaryings.size(); ++bufferIndex)
2179     {
2180         spirv::IdRef xfbOffset(SpirvTransformerBase::GetNewId(blobOut));
2181 
2182         // Get the offset corresponding to this buffer:
2183         //
2184         //     int xfbOffset = xfbOffsets[N]
2185         spirv::WriteCompositeExtract(blobOut, ID::Int, xfbOffset, xfbOffsets,
2186                                      {spirv::LiteralInteger(bufferIndex)});
2187 
2188         // Track offsets for verification.
2189         uint32_t offsetForVerification = 0;
2190 
2191         // Go over the varyings of this buffer in order.
2192         const std::vector<XfbVarying> &varyings = mXfbVaryings[bufferIndex];
2193         for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex)
2194         {
2195             const XfbVarying &varying                  = varyings[varyingIndex];
2196             const ShaderInterfaceVariableXfbInfo *info = varying.info;
2197             ASSERT(info->buffer == bufferIndex);
2198 
2199             // Each component of the varying being captured is loaded one by one.  This uses the
2200             // OpAccessChain instruction that takes a chain of "indices" to end up with the
2201             // component starting from the base variable.  For example:
2202             //
2203             //     var.member[3][2][0]
2204             //
2205             // where member is field number 4 in var and is a mat4, the access chain would be:
2206             //
2207             //     4 3 2 0
2208             //     ^ ^ ^ ^
2209             //     | | | |
2210             //     | | | row 0
2211             //     | | column 2
2212             //     | array element 3
2213             //     field 4
2214             //
2215             // The following tracks the access chain as the field, array elements, columns and rows
2216             // are looped over.
2217             spirv::IdRefList indexList;
2218             AccessChainIndexListAppend appendField(
2219                 varying.fieldIndex != ShaderInterfaceVariableXfbInfo::kInvalid, mIntNIds,
2220                 varying.fieldIndex, &indexList);
2221 
2222             // The varying being captured is either:
2223             //
2224             // - Not an array: In this case, no entry is added in the access chain
2225             // - An element of the array
2226             // - The whole array
2227             //
2228             uint32_t arrayIndexStart = 0;
2229             uint32_t arrayIndexEnd   = info->arraySize;
2230             const bool isArray       = info->arraySize != ShaderInterfaceVariableXfbInfo::kInvalid;
2231             if (varying.info->arrayIndex != ShaderInterfaceVariableXfbInfo::kInvalid)
2232             {
2233                 // Capturing a single element.
2234                 arrayIndexStart = varying.info->arrayIndex;
2235                 arrayIndexEnd   = arrayIndexStart + 1;
2236             }
2237             else if (!isArray)
2238             {
2239                 // Not an array.
2240                 arrayIndexEnd = 1;
2241             }
2242 
2243             // Sorting the varyings should have ensured that offsets are in order and that writing
2244             // to the output buffer sequentially ends up using the correct offsets.
2245             ASSERT(info->offset == offsetForVerification);
2246             offsetForVerification += (arrayIndexEnd - arrayIndexStart) * info->rowCount *
2247                                      info->columnCount * sizeof(float);
2248 
2249             // Determine the type of the component being captured.  OpBitcast is used (the
2250             // implementation of intBitsToFloat() and uintBitsToFloat() for non-float types).
2251             spirv::IdRef varyingTypeId;
2252             spirv::IdRef varyingTypePtr;
2253             const bool isPrivate =
2254                 inactiveVaryingRemover.isInactive(varying.baseId) ||
2255                 (usePrecisionFixer && varyingPrecisionFixer.isReplaced(varying.baseId));
2256             getVaryingTypeIds(info->componentType, isPrivate, &varyingTypeId, &varyingTypePtr);
2257 
2258             for (uint32_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
2259             {
2260                 AccessChainIndexListAppend appendArrayIndex(isArray, mIntNIds, arrayIndex,
2261                                                             &indexList);
2262                 for (uint32_t col = 0; col < info->columnCount; ++col)
2263                 {
2264                     AccessChainIndexListAppend appendColumn(info->columnCount > 1, mIntNIds, col,
2265                                                             &indexList);
2266                     for (uint32_t row = 0; row < info->rowCount; ++row)
2267                     {
2268                         AccessChainIndexListAppend appendRow(info->rowCount > 1, mIntNIds, row,
2269                                                              &indexList);
2270 
2271                         // Generate the code to capture a single component of the varying:
2272                         //
2273                         //     ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
2274                         writeComponentCapture(bufferIndex, xfbOffset, varyingTypeId, varyingTypePtr,
2275                                               varying.baseId, indexList, info->componentType,
2276                                               blobOut);
2277 
2278                         // Increment the offset:
2279                         //
2280                         //     xfbOffset += 1;
2281                         //
2282                         // which translates to:
2283                         //
2284                         //     %newOffsetId = OpIAdd %int %currentOffsetId %int1
2285                         spirv::IdRef nextOffset(SpirvTransformerBase::GetNewId(blobOut));
2286                         spirv::WriteIAdd(blobOut, ID::Int, nextOffset, xfbOffset, ID::IntOne);
2287                         xfbOffset = nextOffset;
2288                     }
2289                 }
2290             }
2291         }
2292     }
2293 }
2294 
getVaryingTypeIds(GLenum componentType,bool isPrivate,spirv::IdRef * typeIdOut,spirv::IdRef * typePtrOut)2295 void SpirvTransformFeedbackCodeGenerator::getVaryingTypeIds(GLenum componentType,
2296                                                             bool isPrivate,
2297                                                             spirv::IdRef *typeIdOut,
2298                                                             spirv::IdRef *typePtrOut)
2299 {
2300     switch (componentType)
2301     {
2302         case GL_INT:
2303             *typeIdOut  = ID::Int;
2304             *typePtrOut = isPrivate ? mIntPrivatePointerId : mIntOutputPointerId;
2305             break;
2306         case GL_UNSIGNED_INT:
2307             *typeIdOut  = ID::Uint;
2308             *typePtrOut = isPrivate ? mUintPrivatePointerId : mUintOutputPointerId;
2309             break;
2310         case GL_FLOAT:
2311             *typeIdOut  = ID::Float;
2312             *typePtrOut = isPrivate ? mFloatPrivatePointerId : mFloatOutputPointerId;
2313             break;
2314         default:
2315             UNREACHABLE();
2316     }
2317 
2318     ASSERT(typeIdOut->valid());
2319     ASSERT(typePtrOut->valid());
2320 }
2321 
writeGetOffsetsCall(spirv::IdRef xfbOffsets,spirv::Blob * blobOut)2322 void SpirvTransformFeedbackCodeGenerator::writeGetOffsetsCall(spirv::IdRef xfbOffsets,
2323                                                               spirv::Blob *blobOut)
2324 {
2325     const spirv::IdRef xfbOffsetsResult(SpirvTransformerBase::GetNewId(blobOut));
2326     const spirv::IdRef xfbOffsetsVar(SpirvTransformerBase::GetNewId(blobOut));
2327 
2328     // Generate code for the following:
2329     //
2330     //     ivec4 xfbOffsets = ANGLEGetXfbOffsets(ivec4(stride0, stride1, stride2, stride3));
2331 
2332     // Create a variable to hold the result.
2333     spirv::WriteVariable(blobOut, ID::IVec4FunctionTypePointer, xfbOffsetsVar,
2334                          spv::StorageClassFunction, nullptr);
2335     // Call a helper function generated by the translator to calculate the offsets for the current
2336     // vertex.
2337     spirv::WriteFunctionCall(blobOut, ID::IVec4, xfbOffsetsResult,
2338                              ID::XfbEmulationGetOffsetsFunction, {mBufferStridesCompositeId});
2339     // Store the results.
2340     spirv::WriteStore(blobOut, xfbOffsetsVar, xfbOffsetsResult, nullptr);
2341     // Load from the variable for use in expressions.
2342     spirv::WriteLoad(blobOut, ID::IVec4, xfbOffsets, xfbOffsetsVar, nullptr);
2343 }
2344 
writeComponentCapture(uint32_t bufferIndex,spirv::IdRef xfbOffset,spirv::IdRef varyingTypeId,spirv::IdRef varyingTypePtr,spirv::IdRef varyingBaseId,const spirv::IdRefList & accessChainIndices,GLenum componentType,spirv::Blob * blobOut)2345 void SpirvTransformFeedbackCodeGenerator::writeComponentCapture(
2346     uint32_t bufferIndex,
2347     spirv::IdRef xfbOffset,
2348     spirv::IdRef varyingTypeId,
2349     spirv::IdRef varyingTypePtr,
2350     spirv::IdRef varyingBaseId,
2351     const spirv::IdRefList &accessChainIndices,
2352     GLenum componentType,
2353     spirv::Blob *blobOut)
2354 {
2355     spirv::IdRef component(SpirvTransformerBase::GetNewId(blobOut));
2356     spirv::IdRef xfbOutPtr(SpirvTransformerBase::GetNewId(blobOut));
2357 
2358     // Generate code for the following:
2359     //
2360     //     ANGLEXfbN.xfbOut[xfbOffset] = tfVarying0.field[index][row][col]
2361 
2362     // Load from the component traversing the base variable with the given indices.  If there are no
2363     // indices, the variable can be loaded directly.
2364     spirv::IdRef loadPtr = varyingBaseId;
2365     if (!accessChainIndices.empty())
2366     {
2367         loadPtr = SpirvTransformerBase::GetNewId(blobOut);
2368         spirv::WriteAccessChain(blobOut, varyingTypePtr, loadPtr, varyingBaseId,
2369                                 accessChainIndices);
2370     }
2371     spirv::WriteLoad(blobOut, varyingTypeId, component, loadPtr, nullptr);
2372 
2373     // If the varying is int or uint, bitcast it to float to store in the float[] array used to
2374     // capture transform feedback output.
2375     spirv::IdRef asFloat = component;
2376     if (componentType != GL_FLOAT)
2377     {
2378         asFloat = SpirvTransformerBase::GetNewId(blobOut);
2379         spirv::WriteBitcast(blobOut, ID::Float, asFloat, component);
2380     }
2381 
2382     // Store into the transform feedback capture buffer at the current offset.  Note that this
2383     // buffer has only one field (xfbOut), hence ANGLEXfbN.xfbOut[xfbOffset] translates to ANGLEXfbN
2384     // with access chain {0, xfbOffset}.
2385     static_assert(gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS == 4);
2386     static_assert(sh::vk::spirv::kIdXfbEmulationBufferVarOne ==
2387                   sh::vk::spirv::kIdXfbEmulationBufferVarZero + 1);
2388     static_assert(sh::vk::spirv::kIdXfbEmulationBufferVarTwo ==
2389                   sh::vk::spirv::kIdXfbEmulationBufferVarZero + 2);
2390     static_assert(sh::vk::spirv::kIdXfbEmulationBufferVarThree ==
2391                   sh::vk::spirv::kIdXfbEmulationBufferVarZero + 3);
2392     spirv::WriteAccessChain(blobOut, mFloatUniformPointerId, xfbOutPtr,
2393                             spirv::IdRef(sh::vk::spirv::kIdXfbEmulationBufferVarZero + bufferIndex),
2394                             {ID::IntZero, xfbOffset});
2395     spirv::WriteStore(blobOut, xfbOutPtr, asFloat, nullptr);
2396 }
2397 
addExecutionMode(spirv::IdRef entryPointId,spirv::Blob * blobOut)2398 void SpirvTransformFeedbackCodeGenerator::addExecutionMode(spirv::IdRef entryPointId,
2399                                                            spirv::Blob *blobOut)
2400 {
2401     if (mIsEmulated)
2402     {
2403         return;
2404     }
2405 
2406     if (mHasTransformFeedbackOutput)
2407     {
2408         spirv::WriteExecutionMode(blobOut, entryPointId, spv::ExecutionModeXfb, {});
2409     }
2410 }
2411 
addMemberDecorate(const ShaderInterfaceVariableInfo & info,spirv::IdRef id,spirv::Blob * blobOut)2412 void SpirvTransformFeedbackCodeGenerator::addMemberDecorate(const ShaderInterfaceVariableInfo &info,
2413                                                             spirv::IdRef id,
2414                                                             spirv::Blob *blobOut)
2415 {
2416     if (mIsEmulated || info.fieldXfb.empty())
2417     {
2418         return;
2419     }
2420 
2421     for (uint32_t fieldIndex = 0; fieldIndex < info.fieldXfb.size(); ++fieldIndex)
2422     {
2423         const ShaderInterfaceVariableXfbInfo &xfb = info.fieldXfb[fieldIndex];
2424 
2425         if (xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid)
2426         {
2427             continue;
2428         }
2429 
2430         ASSERT(xfb.stride != ShaderInterfaceVariableXfbInfo::kInvalid);
2431         ASSERT(xfb.offset != ShaderInterfaceVariableXfbInfo::kInvalid);
2432 
2433         const uint32_t xfbDecorationValues[kXfbDecorationCount] = {
2434             xfb.buffer,
2435             xfb.stride,
2436             xfb.offset,
2437         };
2438 
2439         // Generate the following three instructions:
2440         //
2441         //     OpMemberDecorate %id fieldIndex XfbBuffer xfb.buffer
2442         //     OpMemberDecorate %id fieldIndex XfbStride xfb.stride
2443         //     OpMemberDecorate %id fieldIndex Offset xfb.offset
2444         for (size_t i = 0; i < kXfbDecorationCount; ++i)
2445         {
2446             spirv::WriteMemberDecorate(blobOut, id, spirv::LiteralInteger(fieldIndex),
2447                                        kXfbDecorations[i],
2448                                        {spirv::LiteralInteger(xfbDecorationValues[i])});
2449         }
2450     }
2451 }
2452 
addDecorate(const ShaderInterfaceVariableInfo & info,spirv::IdRef id,spirv::Blob * blobOut)2453 void SpirvTransformFeedbackCodeGenerator::addDecorate(const ShaderInterfaceVariableInfo &info,
2454                                                       spirv::IdRef id,
2455                                                       spirv::Blob *blobOut)
2456 {
2457     if (mIsEmulated || info.xfb.buffer == ShaderInterfaceVariableXfbInfo::kInvalid)
2458     {
2459         return;
2460     }
2461 
2462     ASSERT(info.xfb.stride != ShaderInterfaceVariableXfbInfo::kInvalid);
2463     ASSERT(info.xfb.offset != ShaderInterfaceVariableXfbInfo::kInvalid);
2464 
2465     const uint32_t xfbDecorationValues[kXfbDecorationCount] = {
2466         info.xfb.buffer,
2467         info.xfb.stride,
2468         info.xfb.offset,
2469     };
2470 
2471     // Generate the following three instructions:
2472     //
2473     //     OpDecorate %id XfbBuffer xfb.buffer
2474     //     OpDecorate %id XfbStride xfb.stride
2475     //     OpDecorate %id Offset xfb.offset
2476     for (size_t i = 0; i < kXfbDecorationCount; ++i)
2477     {
2478         spirv::WriteDecorate(blobOut, id, kXfbDecorations[i],
2479                              {spirv::LiteralInteger(xfbDecorationValues[i])});
2480     }
2481 }
2482 
2483 // Helper class that generates code for gl_Position transformations
2484 class SpirvPositionTransformer final : angle::NonCopyable
2485 {
2486   public:
SpirvPositionTransformer(const SpvTransformOptions & options)2487     SpirvPositionTransformer(const SpvTransformOptions &options) : mOptions(options) {}
2488 
2489     void writePositionTransformation(spirv::IdRef positionPointerId,
2490                                      spirv::IdRef positionId,
2491                                      spirv::Blob *blobOut);
2492 
2493   private:
2494     SpvTransformOptions mOptions;
2495 };
2496 
writePositionTransformation(spirv::IdRef positionPointerId,spirv::IdRef positionId,spirv::Blob * blobOut)2497 void SpirvPositionTransformer::writePositionTransformation(spirv::IdRef positionPointerId,
2498                                                            spirv::IdRef positionId,
2499                                                            spirv::Blob *blobOut)
2500 {
2501     // Generate the following SPIR-V for prerotation and depth transformation:
2502     //
2503     //     // Transform position based on uniforms by making a call to the ANGLETransformPosition
2504     //     // function that the translator has already provided.
2505     //     %transformed = OpFunctionCall %kIdVec4 %kIdTransformPositionFunction %position
2506     //
2507     //     // Store the results back in gl_Position
2508     //     OpStore %PositionPointer %transformedPosition
2509     //
2510     const spirv::IdRef transformedPositionId(SpirvTransformerBase::GetNewId(blobOut));
2511 
2512     spirv::WriteFunctionCall(blobOut, ID::Vec4, transformedPositionId,
2513                              ID::TransformPositionFunction, {positionId});
2514     spirv::WriteStore(blobOut, positionPointerId, transformedPositionId, nullptr);
2515 }
2516 
2517 // A transformation to handle both the isMultisampledFramebufferFetch and enableSampleShading
2518 // options.  The common transformation between these two options is the addition of the
2519 // SampleRateShading capability.
2520 class SpirvMultisampleTransformer final : angle::NonCopyable
2521 {
2522   public:
SpirvMultisampleTransformer(const SpvTransformOptions & options)2523     SpirvMultisampleTransformer(const SpvTransformOptions &options)
2524         : mOptions(options), mSampleIDDecorationsAdded(false), mAnyImageTypesModified(false)
2525     {}
~SpirvMultisampleTransformer()2526     ~SpirvMultisampleTransformer()
2527     {
2528         ASSERT(!mOptions.isMultisampledFramebufferFetch || mAnyImageTypesModified);
2529     }
2530 
2531     void init(size_t indexBound);
2532 
2533     void visitDecorate(spirv::IdRef id,
2534                        spv::Decoration decoration,
2535                        const spirv::LiteralIntegerList &valueList);
2536 
2537     void visitMemberDecorate(spirv::IdRef id,
2538                              spirv::LiteralInteger member,
2539                              spv::Decoration decoration);
2540 
2541     void visitTypeStruct(spirv::IdResult id, const spirv::IdRefList &memberList);
2542 
2543     void visitTypePointer(gl::ShaderType shaderType,
2544                           spirv::IdResult id,
2545                           spv::StorageClass storageClass,
2546                           spirv::IdRef typeId);
2547 
2548     void visitVariable(gl::ShaderType shaderType,
2549                        spirv::IdResultType typeId,
2550                        spirv::IdResult id,
2551                        spv::StorageClass storageClass);
2552 
2553     TransformationState transformCapability(const SpirvNonSemanticInstructions &nonSemantic,
2554                                             spv::Capability capability,
2555                                             spirv::Blob *blobOut);
2556 
2557     TransformationState transformTypeImage(const uint32_t *instruction, spirv::Blob *blobOut);
2558 
2559     void modifyEntryPointInterfaceList(const SpirvNonSemanticInstructions &nonSemantic,
2560                                        spirv::IdRefList *interfaceList,
2561                                        spirv::Blob *blobOut);
2562 
2563     void writePendingDeclarations(
2564         const SpirvNonSemanticInstructions &nonSemantic,
2565         const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
2566         spirv::Blob *blobOut);
2567 
2568     TransformationState transformDecorate(const SpirvNonSemanticInstructions &nonSemantic,
2569                                           const ShaderInterfaceVariableInfo &info,
2570                                           gl::ShaderType shaderType,
2571                                           spirv::IdRef id,
2572                                           spv::Decoration &decoration,
2573                                           spirv::Blob *blobOut);
2574 
2575     TransformationState transformImageRead(const uint32_t *instruction, spirv::Blob *blobOut);
2576 
2577   private:
2578     void visitVarying(gl::ShaderType shaderType, spirv::IdRef id, spv::StorageClass storageClass);
2579     bool skipSampleDecoration(spv::Decoration decoration);
2580 
2581     SpvTransformOptions mOptions;
2582     // Used to assert that the transformation is not unnecessarily run.
2583     bool mSampleIDDecorationsAdded;
2584     bool mAnyImageTypesModified;
2585 
2586     struct VaryingInfo
2587     {
2588         // Whether any variable is a varying
2589         bool isVarying = false;
2590         // Whether any variable or its members are already sample-, centroid- or flat-qualified.
2591         bool skipSampleDecoration = false;
2592         std::vector<bool> skipMemberSampleDecoration;
2593     };
2594     std::vector<VaryingInfo> mVaryingInfoById;
2595 };
2596 
init(size_t indexBound)2597 void SpirvMultisampleTransformer::init(size_t indexBound)
2598 {
2599     mVaryingInfoById.resize(indexBound);
2600 }
2601 
transformImageRead(const uint32_t * instruction,spirv::Blob * blobOut)2602 TransformationState SpirvMultisampleTransformer::transformImageRead(const uint32_t *instruction,
2603                                                                     spirv::Blob *blobOut)
2604 {
2605     // Transform the following:
2606     // %21 = OpImageRead %v4float %13 %20
2607     // to
2608     // %21 = OpImageRead %v4float %13 %20 Sample %17
2609     // where
2610     // %17 = OpLoad %int %gl_SampleID
2611 
2612     if (!mOptions.isMultisampledFramebufferFetch)
2613     {
2614         return TransformationState::Unchanged;
2615     }
2616 
2617     spirv::IdResultType idResultType;
2618     spirv::IdResult idResult;
2619     spirv::IdRef image;
2620     spirv::IdRef coordinate;
2621     spv::ImageOperandsMask imageOperands;
2622     spirv::IdRefList imageOperandIdsList;
2623 
2624     spirv::ParseImageRead(instruction, &idResultType, &idResult, &image, &coordinate,
2625                           &imageOperands, &imageOperandIdsList);
2626 
2627     ASSERT(ID::Int.valid());
2628 
2629     spirv::IdRef builtInSampleIDOpLoad = SpirvTransformerBase::GetNewId(blobOut);
2630 
2631     spirv::WriteLoad(blobOut, ID::Int, builtInSampleIDOpLoad, ID::SampleID, nullptr);
2632 
2633     imageOperands = spv::ImageOperandsMask::ImageOperandsSampleMask;
2634     imageOperandIdsList.push_back(builtInSampleIDOpLoad);
2635     spirv::WriteImageRead(blobOut, idResultType, idResult, image, coordinate, &imageOperands,
2636                           imageOperandIdsList);
2637     return TransformationState::Transformed;
2638 }
2639 
writePendingDeclarations(const SpirvNonSemanticInstructions & nonSemantic,const std::vector<const ShaderInterfaceVariableInfo * > & variableInfoById,spirv::Blob * blobOut)2640 void SpirvMultisampleTransformer::writePendingDeclarations(
2641     const SpirvNonSemanticInstructions &nonSemantic,
2642     const std::vector<const ShaderInterfaceVariableInfo *> &variableInfoById,
2643     spirv::Blob *blobOut)
2644 {
2645     // Add following declarations if they are not available yet
2646 
2647     // %int = OpTypeInt 32 1
2648     // %_ptr_Input_int = OpTypePointer Input %int
2649     // %gl_SampleID = OpVariable %_ptr_Input_int Input
2650 
2651     if (!mOptions.isMultisampledFramebufferFetch)
2652     {
2653         return;
2654     }
2655 
2656     if (nonSemantic.hasSampleID())
2657     {
2658         return;
2659     }
2660 
2661     spirv::WriteVariable(blobOut, ID::IntInputTypePointer, ID::SampleID, spv::StorageClassInput,
2662                          nullptr);
2663 }
2664 
transformTypeImage(const uint32_t * instruction,spirv::Blob * blobOut)2665 TransformationState SpirvMultisampleTransformer::transformTypeImage(const uint32_t *instruction,
2666                                                                     spirv::Blob *blobOut)
2667 {
2668     // Transform the following
2669     // %10 = OpTypeImage %float SubpassData 0 0 0 2
2670     // To
2671     // %10 = OpTypeImage %float SubpassData 0 0 1 2
2672 
2673     if (!mOptions.isMultisampledFramebufferFetch)
2674     {
2675         return TransformationState::Unchanged;
2676     }
2677 
2678     spirv::IdResult idResult;
2679     spirv::IdRef sampledType;
2680     spv::Dim dim;
2681     spirv::LiteralInteger depth;
2682     spirv::LiteralInteger arrayed;
2683     spirv::LiteralInteger ms;
2684     spirv::LiteralInteger sampled;
2685     spv::ImageFormat imageFormat;
2686     spv::AccessQualifier accessQualifier;
2687     spirv::ParseTypeImage(instruction, &idResult, &sampledType, &dim, &depth, &arrayed, &ms,
2688                           &sampled, &imageFormat, &accessQualifier);
2689 
2690     // Only transform input attachment image types.
2691     if (dim != spv::DimSubpassData)
2692     {
2693         return TransformationState::Unchanged;
2694     }
2695 
2696     ms = spirv::LiteralInteger(1);
2697     spirv::WriteTypeImage(blobOut, idResult, sampledType, dim, depth, arrayed, ms, sampled,
2698                           imageFormat, nullptr);
2699 
2700     mAnyImageTypesModified = true;
2701 
2702     return TransformationState::Transformed;
2703 }
2704 
2705 namespace
2706 {
verifyEntryPointsContainsID(const spirv::IdRefList & interfaceList)2707 bool verifyEntryPointsContainsID(const spirv::IdRefList &interfaceList)
2708 {
2709     for (spirv::IdRef interfaceId : interfaceList)
2710     {
2711         if (interfaceId == ID::SampleID)
2712         {
2713             return true;
2714         }
2715     }
2716     return false;
2717 }
2718 }  // namespace
2719 
modifyEntryPointInterfaceList(const SpirvNonSemanticInstructions & nonSemantic,spirv::IdRefList * interfaceList,spirv::Blob * blobOut)2720 void SpirvMultisampleTransformer::modifyEntryPointInterfaceList(
2721     const SpirvNonSemanticInstructions &nonSemantic,
2722     spirv::IdRefList *interfaceList,
2723     spirv::Blob *blobOut)
2724 {
2725     // Append %gl_sampleID to OpEntryPoint
2726     // Transform the following
2727     //
2728     //     OpEntryPoint Fragment %main "main" %_uo_color
2729     //
2730     // To
2731     //
2732     //     OpEntryPoint Fragment %main "main" %_uo_color %gl_SampleID
2733 
2734     if (!mOptions.isMultisampledFramebufferFetch)
2735     {
2736         return;
2737     }
2738 
2739     // Nothing to do if the shader had already declared SampleID
2740     if (nonSemantic.hasSampleID())
2741     {
2742         ASSERT(verifyEntryPointsContainsID(*interfaceList));
2743         return;
2744     }
2745 
2746     // Add the SampleID id to the interfaceList.  The variable will later be decalred in
2747     // writePendingDeclarations.
2748     interfaceList->push_back(ID::SampleID);
2749     return;
2750 }
2751 
transformCapability(const SpirvNonSemanticInstructions & nonSemantic,const spv::Capability capability,spirv::Blob * blobOut)2752 TransformationState SpirvMultisampleTransformer::transformCapability(
2753     const SpirvNonSemanticInstructions &nonSemantic,
2754     const spv::Capability capability,
2755     spirv::Blob *blobOut)
2756 {
2757     // Add a new OpCapability line:
2758     //
2759     //     OpCapability SampleRateShading
2760     //
2761     // right before the following instruction
2762     //
2763     //     OpCapability InputAttachment
2764 
2765     if (!mOptions.isMultisampledFramebufferFetch && !mOptions.enableSampleShading)
2766     {
2767         return TransformationState::Unchanged;
2768     }
2769 
2770     // Do not add the capability if the SPIR-V already has it
2771     if (nonSemantic.hasSampleRateShading())
2772     {
2773         return TransformationState::Unchanged;
2774     }
2775 
2776     // Make sure no duplicates
2777     ASSERT(capability != spv::CapabilitySampleRateShading);
2778 
2779     // Make sure we only add the new line on top of "OpCapability Shader"
2780     if (capability != spv::CapabilityShader)
2781     {
2782         return TransformationState::Unchanged;
2783     }
2784 
2785     spirv::WriteCapability(blobOut, spv::CapabilitySampleRateShading);
2786 
2787     // Leave the original OpCapability untouched
2788     return TransformationState::Unchanged;
2789 }
2790 
transformDecorate(const SpirvNonSemanticInstructions & nonSemantic,const ShaderInterfaceVariableInfo & info,gl::ShaderType shaderType,spirv::IdRef id,spv::Decoration & decoration,spirv::Blob * blobOut)2791 TransformationState SpirvMultisampleTransformer::transformDecorate(
2792     const SpirvNonSemanticInstructions &nonSemantic,
2793     const ShaderInterfaceVariableInfo &info,
2794     gl::ShaderType shaderType,
2795     spirv::IdRef id,
2796     spv::Decoration &decoration,
2797     spirv::Blob *blobOut)
2798 {
2799     if (mOptions.isMultisampledFramebufferFetch &&
2800         decoration == spv::DecorationInputAttachmentIndex && !nonSemantic.hasSampleID() &&
2801         !mSampleIDDecorationsAdded)
2802     {
2803         // Add the following instructions if they are not available yet:
2804         //
2805         //     OpDecorate %gl_SampleID RelaxedPrecision
2806         //     OpDecorate %gl_SampleID Flat
2807         //     OpDecorate %gl_SampleID BuiltIn SampleId
2808 
2809         spirv::WriteDecorate(blobOut, ID::SampleID, spv::DecorationRelaxedPrecision, {});
2810         spirv::WriteDecorate(blobOut, ID::SampleID, spv::DecorationFlat, {});
2811         spirv::WriteDecorate(blobOut, ID::SampleID, spv::DecorationBuiltIn,
2812                              {spirv::LiteralInteger(spv::BuiltIn::BuiltInSampleId)});
2813 
2814         mSampleIDDecorationsAdded = true;
2815     }
2816     if (mOptions.enableSampleShading && mVaryingInfoById[id].isVarying &&
2817         !mVaryingInfoById[id].skipSampleDecoration)
2818     {
2819         if (decoration == spv::DecorationLocation && info.activeStages[shaderType])
2820         {
2821             // Add the following instructions when the Location decoration is met, if the varying is
2822             // not already decorated with Sample:
2823             //
2824             //     OpDecorate %id Sample
2825             spirv::WriteDecorate(blobOut, id, spv::DecorationSample, {});
2826         }
2827         else if (decoration == spv::DecorationBlock)
2828         {
2829             // Add the following instructions when the Block decoration is met, for any member that
2830             // is not already decorated with Sample:
2831             //
2832             //     OpMemberDecorate %id member Sample
2833             for (uint32_t member = 0;
2834                  member < mVaryingInfoById[id].skipMemberSampleDecoration.size(); ++member)
2835             {
2836                 if (!mVaryingInfoById[id].skipMemberSampleDecoration[member])
2837                 {
2838                     spirv::WriteMemberDecorate(blobOut, id, spirv::LiteralInteger(member),
2839                                                spv::DecorationSample, {});
2840                 }
2841             }
2842         }
2843     }
2844 
2845     return TransformationState::Unchanged;
2846 }
2847 
skipSampleDecoration(spv::Decoration decoration)2848 bool SpirvMultisampleTransformer::skipSampleDecoration(spv::Decoration decoration)
2849 {
2850     // If a variable is already decorated with Sample, Patch or Centroid, it shouldn't be decorated
2851     // with Sample.  BuiltIns are also excluded.
2852     return decoration == spv::DecorationPatch || decoration == spv::DecorationCentroid ||
2853            decoration == spv::DecorationSample || decoration == spv::DecorationBuiltIn;
2854 }
2855 
visitDecorate(spirv::IdRef id,spv::Decoration decoration,const spirv::LiteralIntegerList & valueList)2856 void SpirvMultisampleTransformer::visitDecorate(spirv::IdRef id,
2857                                                 spv::Decoration decoration,
2858                                                 const spirv::LiteralIntegerList &valueList)
2859 {
2860     if (mOptions.enableSampleShading)
2861     {
2862         // Determine whether the id is already decorated with Sample.
2863         if (skipSampleDecoration(decoration))
2864         {
2865             mVaryingInfoById[id].skipSampleDecoration = true;
2866         }
2867     }
2868     return;
2869 }
2870 
visitMemberDecorate(spirv::IdRef id,spirv::LiteralInteger member,spv::Decoration decoration)2871 void SpirvMultisampleTransformer::visitMemberDecorate(spirv::IdRef id,
2872                                                       spirv::LiteralInteger member,
2873                                                       spv::Decoration decoration)
2874 {
2875     if (!mOptions.enableSampleShading)
2876     {
2877         return;
2878     }
2879 
2880     if (mVaryingInfoById[id].skipMemberSampleDecoration.size() <= member)
2881     {
2882         mVaryingInfoById[id].skipMemberSampleDecoration.resize(member + 1, false);
2883     }
2884     // Determine whether the member is already decorated with Sample.
2885     if (skipSampleDecoration(decoration))
2886     {
2887         mVaryingInfoById[id].skipMemberSampleDecoration[member] = true;
2888     }
2889 }
2890 
visitVarying(gl::ShaderType shaderType,spirv::IdRef id,spv::StorageClass storageClass)2891 void SpirvMultisampleTransformer::visitVarying(gl::ShaderType shaderType,
2892                                                spirv::IdRef id,
2893                                                spv::StorageClass storageClass)
2894 {
2895     if (!mOptions.enableSampleShading)
2896     {
2897         return;
2898     }
2899 
2900     // Vertex input and fragment output variables are not varyings and don't need to be decorated
2901     // with Sample.
2902     if ((shaderType == gl::ShaderType::Fragment && storageClass == spv::StorageClassOutput) ||
2903         (shaderType == gl::ShaderType::Vertex && storageClass == spv::StorageClassInput))
2904     {
2905         return;
2906     }
2907 
2908     const bool isVarying =
2909         storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput;
2910     mVaryingInfoById[id].isVarying = isVarying;
2911 }
2912 
visitTypeStruct(spirv::IdResult id,const spirv::IdRefList & memberList)2913 void SpirvMultisampleTransformer::visitTypeStruct(spirv::IdResult id,
2914                                                   const spirv::IdRefList &memberList)
2915 {
2916     if (mOptions.enableSampleShading)
2917     {
2918         mVaryingInfoById[id].skipMemberSampleDecoration.resize(memberList.size(), false);
2919     }
2920 }
2921 
visitTypePointer(gl::ShaderType shaderType,spirv::IdResult id,spv::StorageClass storageClass,spirv::IdRef typeId)2922 void SpirvMultisampleTransformer::visitTypePointer(gl::ShaderType shaderType,
2923                                                    spirv::IdResult id,
2924                                                    spv::StorageClass storageClass,
2925                                                    spirv::IdRef typeId)
2926 {
2927     // For I/O blocks, the Sample decoration should be specified on the members of the struct type.
2928     // For that purpose, we consider the struct type as the varying instead.
2929     visitVarying(shaderType, typeId, storageClass);
2930 }
2931 
visitVariable(gl::ShaderType shaderType,spirv::IdResultType typeId,spirv::IdResult id,spv::StorageClass storageClass)2932 void SpirvMultisampleTransformer::visitVariable(gl::ShaderType shaderType,
2933                                                 spirv::IdResultType typeId,
2934                                                 spirv::IdResult id,
2935                                                 spv::StorageClass storageClass)
2936 {
2937     visitVarying(shaderType, id, storageClass);
2938 }
2939 
2940 // A SPIR-V transformer.  It walks the instructions and modifies them as necessary, for example to
2941 // assign bindings or locations.
2942 class SpirvTransformer final : public SpirvTransformerBase
2943 {
2944   public:
SpirvTransformer(const spirv::Blob & spirvBlobIn,const SpvTransformOptions & options,bool isLastPass,const ShaderInterfaceVariableInfoMap & variableInfoMap,spirv::Blob * spirvBlobOut)2945     SpirvTransformer(const spirv::Blob &spirvBlobIn,
2946                      const SpvTransformOptions &options,
2947                      bool isLastPass,
2948                      const ShaderInterfaceVariableInfoMap &variableInfoMap,
2949                      spirv::Blob *spirvBlobOut)
2950         : SpirvTransformerBase(spirvBlobIn, variableInfoMap, spirvBlobOut),
2951           mOptions(options),
2952           mOverviewFlags(0),
2953           mNonSemanticInstructions(isLastPass),
2954           mPerVertexTrimmer(options, variableInfoMap),
2955           mXfbCodeGenerator(options.isTransformFeedbackEmulated),
2956           mPositionTransformer(options),
2957           mMultisampleTransformer(options)
2958     {}
2959 
2960     void transform();
2961 
2962   private:
2963     // A prepass to resolve interesting ids:
2964     void resolveVariableIds();
2965 
2966     // Transform instructions:
2967     void transformInstruction();
2968 
2969     // Instructions that are purely informational:
2970     void visitDecorate(const uint32_t *instruction);
2971     void visitMemberDecorate(const uint32_t *instruction);
2972     void visitTypeArray(const uint32_t *instruction);
2973     void visitTypePointer(const uint32_t *instruction);
2974     void visitTypeStruct(const uint32_t *instruction);
2975     void visitVariable(const uint32_t *instruction);
2976     void visitCapability(const uint32_t *instruction);
2977     bool visitExtInst(const uint32_t *instruction);
2978 
2979     // Instructions that potentially need transformation.  They return true if the instruction is
2980     // transformed.  If false is returned, the instruction should be copied as-is.
2981     TransformationState transformAccessChain(const uint32_t *instruction);
2982     TransformationState transformCapability(const uint32_t *instruction);
2983     TransformationState transformEntryPoint(const uint32_t *instruction);
2984     TransformationState transformExtension(const uint32_t *instruction);
2985     TransformationState transformExtInstImport(const uint32_t *instruction);
2986     TransformationState transformExtInst(const uint32_t *instruction);
2987     TransformationState transformDecorate(const uint32_t *instruction);
2988     TransformationState transformMemberDecorate(const uint32_t *instruction);
2989     TransformationState transformName(const uint32_t *instruction);
2990     TransformationState transformMemberName(const uint32_t *instruction);
2991     TransformationState transformTypePointer(const uint32_t *instruction);
2992     TransformationState transformTypeStruct(const uint32_t *instruction);
2993     TransformationState transformVariable(const uint32_t *instruction);
2994     TransformationState transformTypeImage(const uint32_t *instruction);
2995     TransformationState transformImageRead(const uint32_t *instruction);
2996 
2997     // Helpers:
2998     void visitTypeHelper(spirv::IdResult id, spirv::IdRef typeId);
2999     void writePendingDeclarations();
3000     void writeInputPreamble();
3001     void writeOutputPrologue();
3002 
3003     // Special flags:
3004     SpvTransformOptions mOptions;
3005 
3006     // Traversal state:
3007     spirv::IdRef mCurrentFunctionId;
3008 
3009     // Transformation state:
3010 
3011     uint32_t mOverviewFlags;
3012     SpirvNonSemanticInstructions mNonSemanticInstructions;
3013     SpirvPerVertexTrimmer mPerVertexTrimmer;
3014     SpirvInactiveVaryingRemover mInactiveVaryingRemover;
3015     SpirvVaryingPrecisionFixer mVaryingPrecisionFixer;
3016     SpirvTransformFeedbackCodeGenerator mXfbCodeGenerator;
3017     SpirvPositionTransformer mPositionTransformer;
3018     SpirvMultisampleTransformer mMultisampleTransformer;
3019 };
3020 
transform()3021 void SpirvTransformer::transform()
3022 {
3023     onTransformBegin();
3024 
3025     // First, find all necessary ids and associate them with the information required to transform
3026     // their decorations.  This is mostly derived from |mVariableInfoMap|, but may have additional
3027     // mappings; for example |mVariableInfoMap| maps an interface block's type ID to info, but the
3028     // transformer needs to discover the variable associated with that block and map it to the same
3029     // info.
3030     resolveVariableIds();
3031 
3032     while (mCurrentWord < mSpirvBlobIn.size())
3033     {
3034         transformInstruction();
3035     }
3036 }
3037 
resolveVariableIds()3038 void SpirvTransformer::resolveVariableIds()
3039 {
3040     const size_t indexBound = mSpirvBlobIn[spirv::kHeaderIndexIndexBound];
3041 
3042     mInactiveVaryingRemover.init(indexBound);
3043     if (mOptions.useSpirvVaryingPrecisionFixer)
3044     {
3045         mVaryingPrecisionFixer.init(indexBound);
3046     }
3047     if (mOptions.isMultisampledFramebufferFetch || mOptions.enableSampleShading)
3048     {
3049         mMultisampleTransformer.init(indexBound);
3050     }
3051 
3052     // Allocate storage for id-to-info map.  If %i is an id in mVariableInfoMap, index i in this
3053     // vector will hold a pointer to the ShaderInterfaceVariableInfo object associated with that
3054     // name in mVariableInfoMap.
3055     mVariableInfoById.resize(indexBound, nullptr);
3056 
3057     // Pre-populate from mVariableInfoMap.
3058     {
3059         const ShaderInterfaceVariableInfoMap::VariableInfoArray &data = mVariableInfoMap.getData();
3060         const ShaderInterfaceVariableInfoMap::IdToIndexMap &idToIndexMap =
3061             mVariableInfoMap.getIdToIndexMap()[mOptions.shaderType];
3062 
3063         for (uint32_t hashedId = 0; hashedId < idToIndexMap.size(); ++hashedId)
3064         {
3065             const uint32_t id                  = hashedId + sh::vk::spirv::kIdShaderVariablesBegin;
3066             const VariableIndex &variableIndex = idToIndexMap.at(hashedId);
3067             if (variableIndex.index == VariableIndex::kInvalid)
3068             {
3069                 continue;
3070             }
3071 
3072             const ShaderInterfaceVariableInfo &info = data[variableIndex.index];
3073 
3074             ASSERT(id < mVariableInfoById.size());
3075             mVariableInfoById[id] = &info;
3076         }
3077     }
3078 
3079     size_t currentWord = spirv::kHeaderIndexInstructions;
3080 
3081     while (currentWord < mSpirvBlobIn.size())
3082     {
3083         const uint32_t *instruction = &mSpirvBlobIn[currentWord];
3084 
3085         uint32_t wordCount;
3086         spv::Op opCode;
3087         spirv::GetInstructionOpAndLength(instruction, &opCode, &wordCount);
3088 
3089         switch (opCode)
3090         {
3091             case spv::OpDecorate:
3092                 visitDecorate(instruction);
3093                 break;
3094             case spv::OpMemberDecorate:
3095                 visitMemberDecorate(instruction);
3096                 break;
3097             case spv::OpTypeArray:
3098                 visitTypeArray(instruction);
3099                 break;
3100             case spv::OpTypePointer:
3101                 visitTypePointer(instruction);
3102                 break;
3103             case spv::OpTypeStruct:
3104                 visitTypeStruct(instruction);
3105                 break;
3106             case spv::OpVariable:
3107                 visitVariable(instruction);
3108                 break;
3109             case spv::OpExtInst:
3110                 if (visitExtInst(instruction))
3111                 {
3112                     return;
3113                 }
3114                 break;
3115             default:
3116                 break;
3117         }
3118 
3119         currentWord += wordCount;
3120     }
3121     UNREACHABLE();
3122 }
3123 
transformInstruction()3124 void SpirvTransformer::transformInstruction()
3125 {
3126     uint32_t wordCount;
3127     spv::Op opCode;
3128     const uint32_t *instruction = getCurrentInstruction(&opCode, &wordCount);
3129 
3130     if (opCode == spv::OpFunction)
3131     {
3132         spirv::IdResultType id;
3133         spv::FunctionControlMask functionControl;
3134         spirv::IdRef functionType;
3135         spirv::ParseFunction(instruction, &id, &mCurrentFunctionId, &functionControl,
3136                              &functionType);
3137 
3138         // SPIR-V is structured in sections.  Function declarations come last.  Only a few
3139         // instructions such as Op*Access* or OpEmitVertex opcodes inside functions need to be
3140         // inspected.
3141         mIsInFunctionSection = true;
3142     }
3143 
3144     // Only look at interesting instructions.
3145     TransformationState transformationState = TransformationState::Unchanged;
3146 
3147     if (mIsInFunctionSection)
3148     {
3149         // Look at in-function opcodes.
3150         switch (opCode)
3151         {
3152             case spv::OpExtInst:
3153                 transformationState = transformExtInst(instruction);
3154                 break;
3155             case spv::OpAccessChain:
3156             case spv::OpInBoundsAccessChain:
3157             case spv::OpPtrAccessChain:
3158             case spv::OpInBoundsPtrAccessChain:
3159                 transformationState = transformAccessChain(instruction);
3160                 break;
3161             case spv::OpImageRead:
3162                 transformationState = transformImageRead(instruction);
3163                 break;
3164             default:
3165                 break;
3166         }
3167     }
3168     else
3169     {
3170         // Look at global declaration opcodes.
3171         switch (opCode)
3172         {
3173             case spv::OpExtension:
3174                 transformationState = transformExtension(instruction);
3175                 break;
3176             case spv::OpExtInstImport:
3177                 transformationState = transformExtInstImport(instruction);
3178                 break;
3179             case spv::OpExtInst:
3180                 transformationState = transformExtInst(instruction);
3181                 break;
3182             case spv::OpName:
3183                 transformationState = transformName(instruction);
3184                 break;
3185             case spv::OpMemberName:
3186                 transformationState = transformMemberName(instruction);
3187                 break;
3188             case spv::OpCapability:
3189                 transformationState = transformCapability(instruction);
3190                 break;
3191             case spv::OpEntryPoint:
3192                 transformationState = transformEntryPoint(instruction);
3193                 break;
3194             case spv::OpDecorate:
3195                 transformationState = transformDecorate(instruction);
3196                 break;
3197             case spv::OpMemberDecorate:
3198                 transformationState = transformMemberDecorate(instruction);
3199                 break;
3200             case spv::OpTypeImage:
3201                 transformationState = transformTypeImage(instruction);
3202                 break;
3203             case spv::OpTypePointer:
3204                 transformationState = transformTypePointer(instruction);
3205                 break;
3206             case spv::OpTypeStruct:
3207                 transformationState = transformTypeStruct(instruction);
3208                 break;
3209             case spv::OpVariable:
3210                 transformationState = transformVariable(instruction);
3211                 break;
3212             default:
3213                 break;
3214         }
3215     }
3216 
3217     // If the instruction was not transformed, copy it to output as is.
3218     if (transformationState == TransformationState::Unchanged)
3219     {
3220         copyInstruction(instruction, wordCount);
3221     }
3222 
3223     // Advance to next instruction.
3224     mCurrentWord += wordCount;
3225 }
3226 
3227 // Called at the end of the declarations section.  Any declarations that are necessary but weren't
3228 // present in the original shader need to be done here.
writePendingDeclarations()3229 void SpirvTransformer::writePendingDeclarations()
3230 {
3231     mMultisampleTransformer.writePendingDeclarations(mNonSemanticInstructions, mVariableInfoById,
3232                                                      mSpirvBlobOut);
3233 
3234     // Pre-rotation and transformation of depth to Vulkan clip space require declarations that may
3235     // not necessarily be in the shader.  Transform feedback emulation additionally requires a few
3236     // overlapping ids.
3237     if (!mOptions.isLastPreFragmentStage)
3238     {
3239         return;
3240     }
3241 
3242     if (mOptions.isTransformFeedbackStage)
3243     {
3244         mXfbCodeGenerator.writePendingDeclarations(mVariableInfoById, mSpirvBlobOut);
3245     }
3246 }
3247 
3248 // Called by transformInstruction to insert necessary instructions for casting varyings.
writeInputPreamble()3249 void SpirvTransformer::writeInputPreamble()
3250 {
3251     if (mOptions.useSpirvVaryingPrecisionFixer)
3252     {
3253         mVaryingPrecisionFixer.writeInputPreamble(mVariableInfoById, mOptions.shaderType,
3254                                                   mSpirvBlobOut);
3255     }
3256 }
3257 
3258 // Called by transformInstruction to insert necessary instructions for casting varyings and
3259 // modifying gl_Position.
writeOutputPrologue()3260 void SpirvTransformer::writeOutputPrologue()
3261 {
3262     if (mOptions.useSpirvVaryingPrecisionFixer)
3263     {
3264         mVaryingPrecisionFixer.writeOutputPrologue(mVariableInfoById, mOptions.shaderType,
3265                                                    mSpirvBlobOut);
3266     }
3267     if (!mNonSemanticInstructions.hasOutputPerVertex())
3268     {
3269         return;
3270     }
3271 
3272     // Whether gl_Position should be transformed to account for pre-rotation and Vulkan clip space.
3273     const bool transformPosition = mOptions.isLastPreFragmentStage;
3274     const bool isXfbExtensionStage =
3275         mOptions.isTransformFeedbackStage && !mOptions.isTransformFeedbackEmulated;
3276     if (!transformPosition && !isXfbExtensionStage)
3277     {
3278         return;
3279     }
3280 
3281     // Load gl_Position with the following SPIR-V:
3282     //
3283     //     // Create an access chain to gl_PerVertex.gl_Position, which is always at index 0.
3284     //     %PositionPointer = OpAccessChain %kIdVec4OutputTypePointer %kIdOutputPerVertexVar
3285     //                                      %kIdIntZero
3286     //     // Load gl_Position
3287     //     %Position = OpLoad %kIdVec4 %PositionPointer
3288     //
3289     const spirv::IdRef positionPointerId(getNewId());
3290     const spirv::IdRef positionId(getNewId());
3291 
3292     spirv::WriteAccessChain(mSpirvBlobOut, ID::Vec4OutputTypePointer, positionPointerId,
3293                             ID::OutputPerVertexVar, {ID::IntZero});
3294     spirv::WriteLoad(mSpirvBlobOut, ID::Vec4, positionId, positionPointerId, nullptr);
3295 
3296     // Write transform feedback output before modifying gl_Position.
3297     if (isXfbExtensionStage)
3298     {
3299         mXfbCodeGenerator.writeTransformFeedbackExtensionOutput(positionId, mSpirvBlobOut);
3300     }
3301 
3302     if (transformPosition)
3303     {
3304         mPositionTransformer.writePositionTransformation(positionPointerId, positionId,
3305                                                          mSpirvBlobOut);
3306     }
3307 }
3308 
visitDecorate(const uint32_t * instruction)3309 void SpirvTransformer::visitDecorate(const uint32_t *instruction)
3310 {
3311     spirv::IdRef id;
3312     spv::Decoration decoration;
3313     spirv::LiteralIntegerList valueList;
3314     spirv::ParseDecorate(instruction, &id, &decoration, &valueList);
3315 
3316     mMultisampleTransformer.visitDecorate(id, decoration, valueList);
3317 }
3318 
visitMemberDecorate(const uint32_t * instruction)3319 void SpirvTransformer::visitMemberDecorate(const uint32_t *instruction)
3320 {
3321     spirv::IdRef typeId;
3322     spirv::LiteralInteger member;
3323     spv::Decoration decoration;
3324     spirv::LiteralIntegerList valueList;
3325     spirv::ParseMemberDecorate(instruction, &typeId, &member, &decoration, &valueList);
3326 
3327     mPerVertexTrimmer.visitMemberDecorate(typeId, member, decoration, valueList);
3328     mMultisampleTransformer.visitMemberDecorate(typeId, member, decoration);
3329 }
3330 
visitTypeHelper(spirv::IdResult id,spirv::IdRef typeId)3331 void SpirvTransformer::visitTypeHelper(spirv::IdResult id, spirv::IdRef typeId)
3332 {
3333     // Carry forward the mapping of typeId->info to id->info.  For interface block, it's the block
3334     // id that is mapped to the info, so this is necessary to eventually be able to map the variable
3335     // itself to the info.
3336     mVariableInfoById[id] = mVariableInfoById[typeId];
3337 }
3338 
visitTypeArray(const uint32_t * instruction)3339 void SpirvTransformer::visitTypeArray(const uint32_t *instruction)
3340 {
3341     spirv::IdResult id;
3342     spirv::IdRef elementType;
3343     spirv::IdRef length;
3344     spirv::ParseTypeArray(instruction, &id, &elementType, &length);
3345 
3346     visitTypeHelper(id, elementType);
3347 }
3348 
visitTypePointer(const uint32_t * instruction)3349 void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
3350 {
3351     spirv::IdResult id;
3352     spv::StorageClass storageClass;
3353     spirv::IdRef typeId;
3354     spirv::ParseTypePointer(instruction, &id, &storageClass, &typeId);
3355 
3356     visitTypeHelper(id, typeId);
3357     if (mOptions.useSpirvVaryingPrecisionFixer)
3358     {
3359         mVaryingPrecisionFixer.visitTypePointer(id, storageClass, typeId);
3360     }
3361     mMultisampleTransformer.visitTypePointer(mOptions.shaderType, id, storageClass, typeId);
3362 }
3363 
visitTypeStruct(const uint32_t * instruction)3364 void SpirvTransformer::visitTypeStruct(const uint32_t *instruction)
3365 {
3366     spirv::IdResult id;
3367     spirv::IdRefList memberList;
3368     ParseTypeStruct(instruction, &id, &memberList);
3369 
3370     mMultisampleTransformer.visitTypeStruct(id, memberList);
3371 }
3372 
visitVariable(const uint32_t * instruction)3373 void SpirvTransformer::visitVariable(const uint32_t *instruction)
3374 {
3375     spirv::IdResultType typeId;
3376     spirv::IdResult id;
3377     spv::StorageClass storageClass;
3378     spirv::ParseVariable(instruction, &typeId, &id, &storageClass, nullptr);
3379 
3380     // If storage class indicates that this is not a shader interface variable, ignore it.
3381     const bool isInterfaceBlockVariable =
3382         storageClass == spv::StorageClassUniform || storageClass == spv::StorageClassStorageBuffer;
3383     const bool isOpaqueUniform = storageClass == spv::StorageClassUniformConstant;
3384     const bool isInOut =
3385         storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput;
3386 
3387     if (!isInterfaceBlockVariable && !isOpaqueUniform && !isInOut)
3388     {
3389         return;
3390     }
3391 
3392     // If no info is already associated with this id, carry that forward from the type.  This
3393     // happens for interface blocks, where the id->info association is done on the type id.
3394     ASSERT(mVariableInfoById[id] == nullptr || mVariableInfoById[typeId] == nullptr);
3395     if (mVariableInfoById[id] == nullptr)
3396     {
3397         mVariableInfoById[id] = mVariableInfoById[typeId];
3398     }
3399 
3400     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
3401 
3402     // If this is an interface variable but no info is associated with it, it must be a built-in.
3403     if (info == nullptr)
3404     {
3405         // Make all builtins point to this no-op info.  Adding this entry allows us to ASSERT that
3406         // every shader interface variable is processed during the SPIR-V transformation.  This is
3407         // done when iterating the ids provided by OpEntryPoint.
3408         mVariableInfoById[id] = &mBuiltinVariableInfo;
3409         return;
3410     }
3411 
3412     if (mOptions.useSpirvVaryingPrecisionFixer)
3413     {
3414         mVaryingPrecisionFixer.visitVariable(*info, mOptions.shaderType, typeId, id, storageClass,
3415                                              mSpirvBlobOut);
3416     }
3417     if (mOptions.isTransformFeedbackStage)
3418     {
3419         mXfbCodeGenerator.visitVariable(*info, mOptions.shaderType, typeId, id, storageClass);
3420     }
3421 
3422     mMultisampleTransformer.visitVariable(mOptions.shaderType, typeId, id, storageClass);
3423 }
3424 
visitExtInst(const uint32_t * instruction)3425 bool SpirvTransformer::visitExtInst(const uint32_t *instruction)
3426 {
3427     sh::vk::spirv::NonSemanticInstruction inst;
3428     if (!mNonSemanticInstructions.visitExtInst(instruction, &inst))
3429     {
3430         return false;
3431     }
3432 
3433     switch (inst)
3434     {
3435         case sh::vk::spirv::kNonSemanticOverview:
3436             // SPIR-V is structured in sections (SPIR-V 1.0 Section 2.4 Logical Layout of a Module).
3437             // Names appear before decorations, which are followed by type+variables and finally
3438             // functions.  We are only interested in name and variable declarations (as well as type
3439             // declarations for the sake of nameless interface blocks).  Early out when the function
3440             // declaration section is met.
3441             //
3442             // This non-semantic instruction marks the beginning of the functions section.
3443             return true;
3444         default:
3445             UNREACHABLE();
3446     }
3447 
3448     return false;
3449 }
3450 
transformDecorate(const uint32_t * instruction)3451 TransformationState SpirvTransformer::transformDecorate(const uint32_t *instruction)
3452 {
3453     spirv::IdRef id;
3454     spv::Decoration decoration;
3455     spirv::LiteralIntegerList decorationValues;
3456     spirv::ParseDecorate(instruction, &id, &decoration, &decorationValues);
3457 
3458     ASSERT(id < mVariableInfoById.size());
3459     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
3460 
3461     // If variable is not a shader interface variable that needs modification, there's nothing to
3462     // do.
3463     if (info == nullptr)
3464     {
3465         return TransformationState::Unchanged;
3466     }
3467 
3468     mMultisampleTransformer.transformDecorate(mNonSemanticInstructions, *info, mOptions.shaderType,
3469                                               id, decoration, mSpirvBlobOut);
3470 
3471     if (mXfbCodeGenerator.transformDecorate(info, mOptions.shaderType, id, decoration,
3472                                             decorationValues,
3473                                             mSpirvBlobOut) == TransformationState::Transformed)
3474     {
3475         return TransformationState::Transformed;
3476     }
3477 
3478     if (mInactiveVaryingRemover.transformDecorate(*info, mOptions.shaderType, id, decoration,
3479                                                   decorationValues, mSpirvBlobOut) ==
3480         TransformationState::Transformed)
3481     {
3482         return TransformationState::Transformed;
3483     }
3484 
3485     // If using relaxed precision, generate instructions for the replacement id instead.
3486     if (mOptions.useSpirvVaryingPrecisionFixer)
3487     {
3488         id = mVaryingPrecisionFixer.getReplacementId(id);
3489     }
3490 
3491     uint32_t newDecorationValue = ShaderInterfaceVariableInfo::kInvalid;
3492 
3493     switch (decoration)
3494     {
3495         case spv::DecorationLocation:
3496             newDecorationValue = info->location;
3497             break;
3498         case spv::DecorationBinding:
3499             newDecorationValue = info->binding;
3500             break;
3501         case spv::DecorationDescriptorSet:
3502             newDecorationValue = info->descriptorSet;
3503             break;
3504         case spv::DecorationFlat:
3505         case spv::DecorationNoPerspective:
3506         case spv::DecorationCentroid:
3507         case spv::DecorationSample:
3508             if (mOptions.useSpirvVaryingPrecisionFixer && info->useRelaxedPrecision)
3509             {
3510                 // Change the id to replacement variable
3511                 spirv::WriteDecorate(mSpirvBlobOut, id, decoration, decorationValues);
3512                 return TransformationState::Transformed;
3513             }
3514             break;
3515         case spv::DecorationBlock:
3516             // If this is the Block decoration of a shader I/O block, add the transform feedback
3517             // decorations to its members right away.
3518             if (mOptions.isTransformFeedbackStage)
3519             {
3520                 mXfbCodeGenerator.addMemberDecorate(*info, id, mSpirvBlobOut);
3521             }
3522             break;
3523         case spv::DecorationInvariant:
3524             spirv::WriteDecorate(mSpirvBlobOut, id, spv::DecorationInvariant, {});
3525             return TransformationState::Transformed;
3526         default:
3527             break;
3528     }
3529 
3530     // If the decoration is not something we care about modifying, there's nothing to do.
3531     if (newDecorationValue == ShaderInterfaceVariableInfo::kInvalid)
3532     {
3533         return TransformationState::Unchanged;
3534     }
3535 
3536     // Modify the decoration value.
3537     ASSERT(decorationValues.size() == 1);
3538     spirv::WriteDecorate(mSpirvBlobOut, id, decoration,
3539                          {spirv::LiteralInteger(newDecorationValue)});
3540 
3541     // If there are decorations to be added, add them right after the Location decoration is
3542     // encountered.
3543     if (decoration != spv::DecorationLocation)
3544     {
3545         return TransformationState::Transformed;
3546     }
3547 
3548     // If any, the replacement variable is always reduced precision so add that decoration to
3549     // fixedVaryingId.
3550     if (mOptions.useSpirvVaryingPrecisionFixer && info->useRelaxedPrecision)
3551     {
3552         mVaryingPrecisionFixer.addDecorate(id, mSpirvBlobOut);
3553     }
3554 
3555     // Add component decoration, if any.
3556     if (info->component != ShaderInterfaceVariableInfo::kInvalid)
3557     {
3558         spirv::WriteDecorate(mSpirvBlobOut, id, spv::DecorationComponent,
3559                              {spirv::LiteralInteger(info->component)});
3560     }
3561 
3562     // Add index decoration, if any.
3563     if (info->index != ShaderInterfaceVariableInfo::kInvalid)
3564     {
3565         spirv::WriteDecorate(mSpirvBlobOut, id, spv::DecorationIndex,
3566                              {spirv::LiteralInteger(info->index)});
3567     }
3568 
3569     // Add Xfb decorations, if any.
3570     if (mOptions.isTransformFeedbackStage)
3571     {
3572         mXfbCodeGenerator.addDecorate(*info, id, mSpirvBlobOut);
3573     }
3574 
3575     return TransformationState::Transformed;
3576 }
3577 
transformMemberDecorate(const uint32_t * instruction)3578 TransformationState SpirvTransformer::transformMemberDecorate(const uint32_t *instruction)
3579 {
3580     spirv::IdRef typeId;
3581     spirv::LiteralInteger member;
3582     spv::Decoration decoration;
3583     spirv::ParseMemberDecorate(instruction, &typeId, &member, &decoration, nullptr);
3584 
3585     if (mPerVertexTrimmer.transformMemberDecorate(typeId, member, decoration) ==
3586         TransformationState::Transformed)
3587     {
3588         return TransformationState::Transformed;
3589     }
3590 
3591     ASSERT(typeId < mVariableInfoById.size());
3592     const ShaderInterfaceVariableInfo *info = mVariableInfoById[typeId];
3593 
3594     return mXfbCodeGenerator.transformMemberDecorate(info, mOptions.shaderType, typeId, member,
3595                                                      decoration, mSpirvBlobOut);
3596 }
3597 
transformCapability(const uint32_t * instruction)3598 TransformationState SpirvTransformer::transformCapability(const uint32_t *instruction)
3599 {
3600     spv::Capability capability;
3601     spirv::ParseCapability(instruction, &capability);
3602 
3603     TransformationState xfbTransformState =
3604         mXfbCodeGenerator.transformCapability(capability, mSpirvBlobOut);
3605     ASSERT(xfbTransformState == TransformationState::Unchanged);
3606 
3607     TransformationState multiSampleTransformState = mMultisampleTransformer.transformCapability(
3608         mNonSemanticInstructions, capability, mSpirvBlobOut);
3609     ASSERT(multiSampleTransformState == TransformationState::Unchanged);
3610 
3611     return TransformationState::Unchanged;
3612 }
3613 
transformName(const uint32_t * instruction)3614 TransformationState SpirvTransformer::transformName(const uint32_t *instruction)
3615 {
3616     spirv::IdRef id;
3617     spirv::LiteralString name;
3618     spirv::ParseName(instruction, &id, &name);
3619 
3620     return mXfbCodeGenerator.transformName(id, name);
3621 }
3622 
transformMemberName(const uint32_t * instruction)3623 TransformationState SpirvTransformer::transformMemberName(const uint32_t *instruction)
3624 {
3625     spirv::IdRef id;
3626     spirv::LiteralInteger member;
3627     spirv::LiteralString name;
3628     spirv::ParseMemberName(instruction, &id, &member, &name);
3629 
3630     if (mXfbCodeGenerator.transformMemberName(id, member, name) == TransformationState::Transformed)
3631     {
3632         return TransformationState::Transformed;
3633     }
3634 
3635     return mPerVertexTrimmer.transformMemberName(id, member, name);
3636 }
3637 
transformEntryPoint(const uint32_t * instruction)3638 TransformationState SpirvTransformer::transformEntryPoint(const uint32_t *instruction)
3639 {
3640     spv::ExecutionModel executionModel;
3641     spirv::IdRef entryPointId;
3642     spirv::LiteralString name;
3643     spirv::IdRefList interfaceList;
3644     spirv::ParseEntryPoint(instruction, &executionModel, &entryPointId, &name, &interfaceList);
3645 
3646     // Should only have one EntryPoint
3647     ASSERT(entryPointId == ID::EntryPoint);
3648 
3649     mInactiveVaryingRemover.modifyEntryPointInterfaceList(mVariableInfoById, mOptions.shaderType,
3650                                                           &interfaceList);
3651     if (mOptions.useSpirvVaryingPrecisionFixer)
3652     {
3653         mVaryingPrecisionFixer.modifyEntryPointInterfaceList(&interfaceList);
3654     }
3655 
3656     mMultisampleTransformer.modifyEntryPointInterfaceList(mNonSemanticInstructions, &interfaceList,
3657                                                           mSpirvBlobOut);
3658 
3659     // Write the entry point with the inactive interface variables removed.
3660     spirv::WriteEntryPoint(mSpirvBlobOut, executionModel, ID::EntryPoint, name, interfaceList);
3661 
3662     // Add an OpExecutionMode Xfb instruction if necessary.
3663     mXfbCodeGenerator.addExecutionMode(ID::EntryPoint, mSpirvBlobOut);
3664 
3665     return TransformationState::Transformed;
3666 }
3667 
transformTypePointer(const uint32_t * instruction)3668 TransformationState SpirvTransformer::transformTypePointer(const uint32_t *instruction)
3669 {
3670     spirv::IdResult id;
3671     spv::StorageClass storageClass;
3672     spirv::IdRef typeId;
3673     spirv::ParseTypePointer(instruction, &id, &storageClass, &typeId);
3674 
3675     if (mInactiveVaryingRemover.transformTypePointer(id, storageClass, typeId, mSpirvBlobOut) ==
3676         TransformationState::Transformed)
3677     {
3678         return TransformationState::Transformed;
3679     }
3680 
3681     ASSERT(id < mVariableInfoById.size());
3682     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
3683 
3684     return mXfbCodeGenerator.transformTypePointer(info, mOptions.shaderType, id, storageClass,
3685                                                   typeId, mSpirvBlobOut);
3686 }
3687 
transformExtension(const uint32_t * instruction)3688 TransformationState SpirvTransformer::transformExtension(const uint32_t *instruction)
3689 {
3690     // Drop the OpExtension "SPV_KHR_non_semantic_info" extension instruction.
3691     // SPV_KHR_non_semantic_info is used purely as a means of communication between the compiler and
3692     // the SPIR-V transformer, and is stripped away before the SPIR-V is handed off to the driver.
3693     spirv::LiteralString name;
3694     spirv::ParseExtension(instruction, &name);
3695 
3696     return strcmp(name, "SPV_KHR_non_semantic_info") == 0 ? TransformationState::Transformed
3697                                                           : TransformationState::Unchanged;
3698 }
3699 
transformExtInstImport(const uint32_t * instruction)3700 TransformationState SpirvTransformer::transformExtInstImport(const uint32_t *instruction)
3701 {
3702     // Drop the OpExtInstImport "NonSemantic.ANGLE" instruction.
3703     spirv::IdResult id;
3704     spirv::LiteralString name;
3705     ParseExtInstImport(instruction, &id, &name);
3706 
3707     return id == sh::vk::spirv::kIdNonSemanticInstructionSet ? TransformationState::Transformed
3708                                                              : TransformationState::Unchanged;
3709 }
3710 
transformExtInst(const uint32_t * instruction)3711 TransformationState SpirvTransformer::transformExtInst(const uint32_t *instruction)
3712 {
3713     sh::vk::spirv::NonSemanticInstruction inst;
3714     if (!mNonSemanticInstructions.visitExtInst(instruction, &inst))
3715     {
3716         return TransformationState::Unchanged;
3717     }
3718 
3719     switch (inst)
3720     {
3721         case sh::vk::spirv::kNonSemanticOverview:
3722             // Declare anything that we need but didn't find there already.
3723             writePendingDeclarations();
3724             break;
3725         case sh::vk::spirv::kNonSemanticEnter:
3726             // If there are any precision mismatches that need to be handled, temporary global
3727             // variables are created with the original precision.  Initialize those variables from
3728             // the varyings at the beginning of the shader.
3729             writeInputPreamble();
3730             break;
3731         case sh::vk::spirv::kNonSemanticVertexOutput:
3732             // Generate gl_Position transformations and transform feedback capture (through
3733             // extension) before return or EmitVertex().  Additionally, if there are any precision
3734             // mismatches that need to be ahendled, write the temporary variables that hold varyings
3735             // data.
3736             writeOutputPrologue();
3737             break;
3738         case sh::vk::spirv::kNonSemanticTransformFeedbackEmulation:
3739             // Transform feedback emulation is written to a designated function.  Allow its code to
3740             // be generated if this is the right function.
3741             if (mOptions.isTransformFeedbackStage)
3742             {
3743                 mXfbCodeGenerator.writeTransformFeedbackEmulationOutput(
3744                     mInactiveVaryingRemover, mVaryingPrecisionFixer,
3745                     mOptions.useSpirvVaryingPrecisionFixer, mSpirvBlobOut);
3746             }
3747             break;
3748         default:
3749             UNREACHABLE();
3750             break;
3751     }
3752 
3753     // Drop the instruction if this is the last pass
3754     return mNonSemanticInstructions.transformExtInst(instruction);
3755 }
3756 
transformTypeStruct(const uint32_t * instruction)3757 TransformationState SpirvTransformer::transformTypeStruct(const uint32_t *instruction)
3758 {
3759     spirv::IdResult id;
3760     spirv::IdRefList memberList;
3761     ParseTypeStruct(instruction, &id, &memberList);
3762 
3763     if (mPerVertexTrimmer.transformTypeStruct(id, &memberList, mSpirvBlobOut) ==
3764         TransformationState::Transformed)
3765     {
3766         return TransformationState::Transformed;
3767     }
3768 
3769     ASSERT(id < mVariableInfoById.size());
3770     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
3771 
3772     return mXfbCodeGenerator.transformTypeStruct(info, mOptions.shaderType, id, memberList,
3773                                                  mSpirvBlobOut);
3774 }
3775 
transformVariable(const uint32_t * instruction)3776 TransformationState SpirvTransformer::transformVariable(const uint32_t *instruction)
3777 {
3778     spirv::IdResultType typeId;
3779     spirv::IdResult id;
3780     spv::StorageClass storageClass;
3781     spirv::ParseVariable(instruction, &typeId, &id, &storageClass, nullptr);
3782 
3783     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
3784 
3785     // If variable is not a shader interface variable that needs modification, there's nothing to
3786     // do.
3787     if (info == nullptr)
3788     {
3789         return TransformationState::Unchanged;
3790     }
3791 
3792     // Furthermore, if it's not an inactive varying output, there's nothing to do.  Note that
3793     // inactive varying inputs are already pruned by the translator.
3794     // However, input or output storage class for interface block will not be pruned when a shader
3795     // is compiled separately.
3796     if (info->activeStages[mOptions.shaderType])
3797     {
3798         if (mOptions.useSpirvVaryingPrecisionFixer &&
3799             mVaryingPrecisionFixer.transformVariable(
3800                 *info, typeId, id, storageClass, mSpirvBlobOut) == TransformationState::Transformed)
3801         {
3802             // Make original variable a private global
3803             return mInactiveVaryingRemover.transformVariable(typeId, id, storageClass,
3804                                                              mSpirvBlobOut);
3805         }
3806         return TransformationState::Unchanged;
3807     }
3808 
3809     if (mXfbCodeGenerator.transformVariable(*info, mVariableInfoMap, mOptions.shaderType, typeId,
3810                                             id, storageClass) == TransformationState::Transformed)
3811     {
3812         return TransformationState::Transformed;
3813     }
3814 
3815     // The variable is inactive.  Output a modified variable declaration, where the type is the
3816     // corresponding type with the Private storage class.
3817     return mInactiveVaryingRemover.transformVariable(typeId, id, storageClass, mSpirvBlobOut);
3818 }
3819 
transformTypeImage(const uint32_t * instruction)3820 TransformationState SpirvTransformer::transformTypeImage(const uint32_t *instruction)
3821 {
3822     return mMultisampleTransformer.transformTypeImage(instruction, mSpirvBlobOut);
3823 }
3824 
transformImageRead(const uint32_t * instruction)3825 TransformationState SpirvTransformer::transformImageRead(const uint32_t *instruction)
3826 {
3827     return mMultisampleTransformer.transformImageRead(instruction, mSpirvBlobOut);
3828 }
3829 
transformAccessChain(const uint32_t * instruction)3830 TransformationState SpirvTransformer::transformAccessChain(const uint32_t *instruction)
3831 {
3832     spirv::IdResultType typeId;
3833     spirv::IdResult id;
3834     spirv::IdRef baseId;
3835     spirv::IdRefList indexList;
3836     spirv::ParseAccessChain(instruction, &typeId, &id, &baseId, &indexList);
3837 
3838     // If not accessing an inactive output varying, nothing to do.
3839     const ShaderInterfaceVariableInfo *info = mVariableInfoById[baseId];
3840     if (info == nullptr)
3841     {
3842         return TransformationState::Unchanged;
3843     }
3844 
3845     if (mOptions.useSpirvVaryingPrecisionFixer)
3846     {
3847         if (info->activeStages[mOptions.shaderType] && !info->useRelaxedPrecision)
3848         {
3849             return TransformationState::Unchanged;
3850         }
3851     }
3852     else
3853     {
3854         if (info->activeStages[mOptions.shaderType])
3855         {
3856             return TransformationState::Unchanged;
3857         }
3858     }
3859 
3860     return mInactiveVaryingRemover.transformAccessChain(typeId, id, baseId, indexList,
3861                                                         mSpirvBlobOut);
3862 }
3863 
3864 struct AliasingAttributeMap
3865 {
3866     // The SPIR-V id of the aliasing attribute with the most components.  This attribute will be
3867     // used to read from this location instead of every aliasing one.
3868     spirv::IdRef attribute;
3869 
3870     // SPIR-V ids of aliasing attributes.
3871     std::vector<spirv::IdRef> aliasingAttributes;
3872 };
3873 
ValidateShaderInterfaceVariableIsAttribute(const ShaderInterfaceVariableInfo * info)3874 void ValidateShaderInterfaceVariableIsAttribute(const ShaderInterfaceVariableInfo *info)
3875 {
3876     ASSERT(info);
3877     ASSERT(info->activeStages[gl::ShaderType::Vertex]);
3878     ASSERT(info->attributeComponentCount > 0);
3879     ASSERT(info->attributeLocationCount > 0);
3880     ASSERT(info->location != ShaderInterfaceVariableInfo::kInvalid);
3881 }
3882 
ValidateIsAliasingAttribute(const AliasingAttributeMap * aliasingMap,uint32_t id)3883 void ValidateIsAliasingAttribute(const AliasingAttributeMap *aliasingMap, uint32_t id)
3884 {
3885     ASSERT(id != aliasingMap->attribute);
3886     ASSERT(std::find(aliasingMap->aliasingAttributes.begin(), aliasingMap->aliasingAttributes.end(),
3887                      id) != aliasingMap->aliasingAttributes.end());
3888 }
3889 
3890 // A transformation that resolves vertex attribute aliases.  Note that vertex attribute aliasing is
3891 // only allowed in GLSL ES 100, where the attribute types can only be one of float, vec2, vec3,
3892 // vec4, mat2, mat3, and mat4.  Matrix attributes are handled by expanding them to multiple vector
3893 // attributes, each occupying one location.
3894 class SpirvVertexAttributeAliasingTransformer final : public SpirvTransformerBase
3895 {
3896   public:
SpirvVertexAttributeAliasingTransformer(const spirv::Blob & spirvBlobIn,const ShaderInterfaceVariableInfoMap & variableInfoMap,std::vector<const ShaderInterfaceVariableInfo * > && variableInfoById,spirv::Blob * spirvBlobOut)3897     SpirvVertexAttributeAliasingTransformer(
3898         const spirv::Blob &spirvBlobIn,
3899         const ShaderInterfaceVariableInfoMap &variableInfoMap,
3900         std::vector<const ShaderInterfaceVariableInfo *> &&variableInfoById,
3901         spirv::Blob *spirvBlobOut)
3902         : SpirvTransformerBase(spirvBlobIn, variableInfoMap, spirvBlobOut),
3903           mNonSemanticInstructions(true)
3904     {
3905         mVariableInfoById = std::move(variableInfoById);
3906     }
3907 
3908     void transform();
3909 
3910   private:
3911     // Preprocess aliasing attributes in preparation for their removal.
3912     void preprocessAliasingAttributes();
3913 
3914     // Transform instructions:
3915     void transformInstruction();
3916 
3917     // Helpers:
3918     spirv::IdRef getAliasingAttributeReplacementId(spirv::IdRef aliasingId, uint32_t offset) const;
3919     bool isMatrixAttribute(spirv::IdRef id) const;
3920 
3921     // Instructions that are purely informational:
3922     void visitTypePointer(const uint32_t *instruction);
3923 
3924     // Instructions that potentially need transformation.  They return true if the instruction is
3925     // transformed.  If false is returned, the instruction should be copied as-is.
3926     TransformationState transformEntryPoint(const uint32_t *instruction);
3927     TransformationState transformExtInst(const uint32_t *instruction);
3928     TransformationState transformName(const uint32_t *instruction);
3929     TransformationState transformDecorate(const uint32_t *instruction);
3930     TransformationState transformVariable(const uint32_t *instruction);
3931     TransformationState transformAccessChain(const uint32_t *instruction);
3932     void transformLoadHelper(spirv::IdRef pointerId,
3933                              spirv::IdRef typeId,
3934                              spirv::IdRef replacementId,
3935                              spirv::IdRef resultId);
3936     TransformationState transformLoad(const uint32_t *instruction);
3937 
3938     void declareExpandedMatrixVectors();
3939     void writeExpandedMatrixInitialization();
3940 
3941     // Transformation state:
3942 
3943     // Map of aliasing attributes per location.
3944     gl::AttribArray<AliasingAttributeMap> mAliasingAttributeMap;
3945 
3946     // For each id, this map indicates whether it refers to an aliasing attribute that needs to be
3947     // removed.
3948     std::vector<bool> mIsAliasingAttributeById;
3949 
3950     // Matrix attributes are split into vectors, each occupying one location.  The SPIR-V
3951     // declaration would need to change from:
3952     //
3953     //     %type = OpTypeMatrix %vectorType N
3954     //     %matrixType = OpTypePointer Input %type
3955     //     %matrix = OpVariable %matrixType Input
3956     //
3957     // to:
3958     //
3959     //     %matrixType = OpTypePointer Private %type
3960     //     %matrix = OpVariable %matrixType Private
3961     //
3962     //     %vecType = OpTypePointer Input %vectorType
3963     //
3964     //     %vec0 = OpVariable %vecType Input
3965     //     ...
3966     //     %vecN-1 = OpVariable %vecType Input
3967     //
3968     // For each id %matrix (which corresponds to a matrix attribute), this map contains %vec0.  The
3969     // ids of the split vectors are consecutive, so %veci == %vec0 + i.  %veciType is taken from
3970     // mInputTypePointers.
3971     std::vector<spirv::IdRef> mExpandedMatrixFirstVectorIdById;
3972 
3973     // Id of attribute types; float and veci.
floatType(uint32_t componentCount)3974     spirv::IdRef floatType(uint32_t componentCount)
3975     {
3976         static_assert(sh::vk::spirv::kIdVec2 == sh::vk::spirv::kIdFloat + 1);
3977         static_assert(sh::vk::spirv::kIdVec3 == sh::vk::spirv::kIdFloat + 2);
3978         static_assert(sh::vk::spirv::kIdVec4 == sh::vk::spirv::kIdFloat + 3);
3979         ASSERT(componentCount <= 4);
3980         return spirv::IdRef(sh::vk::spirv::kIdFloat + (componentCount - 1));
3981     }
3982 
3983     // Id of matrix attribute types.  Note that only square matrices are possible as attributes in
3984     // GLSL ES 1.00.
matrixType(uint32_t dimension)3985     spirv::IdRef matrixType(uint32_t dimension)
3986     {
3987         static_assert(sh::vk::spirv::kIdMat3 == sh::vk::spirv::kIdMat2 + 1);
3988         static_assert(sh::vk::spirv::kIdMat4 == sh::vk::spirv::kIdMat2 + 2);
3989         ASSERT(dimension >= 2 && dimension <= 4);
3990         return spirv::IdRef(sh::vk::spirv::kIdMat2 + (dimension - 2));
3991     }
3992 
3993     // Corresponding to floatType(), [i]: id of OpTypePointer Input %floatType(i).  [0] is unused.
3994     std::array<spirv::IdRef, 5> mInputTypePointers;
3995 
3996     // Corresponding to floatType(), [i]: id of OpTypePointer Private %floatType(i).  [0] is
3997     // unused.
3998     std::array<spirv::IdRef, 5> mPrivateFloatTypePointers;
3999 
4000     // Corresponding to matrixType(), [i]: id of OpTypePointer Private %matrixType(i).  [0] and
4001     // [1] are unused.
4002     std::array<spirv::IdRef, 5> mPrivateMatrixTypePointers;
4003 
4004     SpirvNonSemanticInstructions mNonSemanticInstructions;
4005 };
4006 
transform()4007 void SpirvVertexAttributeAliasingTransformer::transform()
4008 {
4009     onTransformBegin();
4010 
4011     preprocessAliasingAttributes();
4012 
4013     while (mCurrentWord < mSpirvBlobIn.size())
4014     {
4015         transformInstruction();
4016     }
4017 }
4018 
preprocessAliasingAttributes()4019 void SpirvVertexAttributeAliasingTransformer::preprocessAliasingAttributes()
4020 {
4021     const uint32_t indexBound = mSpirvBlobIn[spirv::kHeaderIndexIndexBound];
4022 
4023     mVariableInfoById.resize(indexBound, nullptr);
4024     mIsAliasingAttributeById.resize(indexBound, false);
4025     mExpandedMatrixFirstVectorIdById.resize(indexBound);
4026 
4027     // Go through attributes and find out which alias which.
4028     for (uint32_t idIndex = spirv::kMinValidId; idIndex < indexBound; ++idIndex)
4029     {
4030         const spirv::IdRef id(idIndex);
4031 
4032         const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
4033 
4034         // Ignore non attribute ids.
4035         if (info == nullptr || info->attributeComponentCount == 0)
4036         {
4037             continue;
4038         }
4039 
4040         ASSERT(info->activeStages[gl::ShaderType::Vertex]);
4041         ASSERT(info->location != ShaderInterfaceVariableInfo::kInvalid);
4042 
4043         const bool isMatrixAttribute = info->attributeLocationCount > 1;
4044 
4045         for (uint32_t offset = 0; offset < info->attributeLocationCount; ++offset)
4046         {
4047             uint32_t location = info->location + offset;
4048             ASSERT(location < mAliasingAttributeMap.size());
4049 
4050             spirv::IdRef attributeId(id);
4051 
4052             // If this is a matrix attribute, expand it to vectors.
4053             if (isMatrixAttribute)
4054             {
4055                 const spirv::IdRef matrixId(id);
4056 
4057                 // Get a new id for this location and associate it with the matrix.
4058                 attributeId = getNewId();
4059                 if (offset == 0)
4060                 {
4061                     mExpandedMatrixFirstVectorIdById[matrixId] = attributeId;
4062                 }
4063                 // The ids are consecutive.
4064                 ASSERT(attributeId == mExpandedMatrixFirstVectorIdById[matrixId] + offset);
4065 
4066                 mIsAliasingAttributeById.resize(attributeId + 1, false);
4067                 mVariableInfoById.resize(attributeId + 1, nullptr);
4068                 mVariableInfoById[attributeId] = info;
4069             }
4070 
4071             AliasingAttributeMap *aliasingMap = &mAliasingAttributeMap[location];
4072 
4073             // If this is the first attribute in this location, remember it.
4074             if (!aliasingMap->attribute.valid())
4075             {
4076                 aliasingMap->attribute = attributeId;
4077                 continue;
4078             }
4079 
4080             // Otherwise, either add it to the list of aliasing attributes, or replace the main
4081             // attribute (and add that to the list of aliasing attributes).  The one with the
4082             // largest number of components is used as the main attribute.
4083             const ShaderInterfaceVariableInfo *curMainAttribute =
4084                 mVariableInfoById[aliasingMap->attribute];
4085             ASSERT(curMainAttribute != nullptr && curMainAttribute->attributeComponentCount > 0);
4086 
4087             spirv::IdRef aliasingId;
4088             if (info->attributeComponentCount > curMainAttribute->attributeComponentCount)
4089             {
4090                 aliasingId             = aliasingMap->attribute;
4091                 aliasingMap->attribute = attributeId;
4092             }
4093             else
4094             {
4095                 aliasingId = attributeId;
4096             }
4097 
4098             aliasingMap->aliasingAttributes.push_back(aliasingId);
4099             ASSERT(!mIsAliasingAttributeById[aliasingId]);
4100             mIsAliasingAttributeById[aliasingId] = true;
4101         }
4102     }
4103 }
4104 
transformInstruction()4105 void SpirvVertexAttributeAliasingTransformer::transformInstruction()
4106 {
4107     uint32_t wordCount;
4108     spv::Op opCode;
4109     const uint32_t *instruction = getCurrentInstruction(&opCode, &wordCount);
4110 
4111     if (opCode == spv::OpFunction)
4112     {
4113         // SPIR-V is structured in sections.  Function declarations come last.
4114         mIsInFunctionSection = true;
4115     }
4116 
4117     // Only look at interesting instructions.
4118     TransformationState transformationState = TransformationState::Unchanged;
4119 
4120     if (mIsInFunctionSection)
4121     {
4122         // Look at in-function opcodes.
4123         switch (opCode)
4124         {
4125             case spv::OpExtInst:
4126                 transformationState = transformExtInst(instruction);
4127                 break;
4128             case spv::OpAccessChain:
4129             case spv::OpInBoundsAccessChain:
4130                 transformationState = transformAccessChain(instruction);
4131                 break;
4132             case spv::OpLoad:
4133                 transformationState = transformLoad(instruction);
4134                 break;
4135             default:
4136                 break;
4137         }
4138     }
4139     else
4140     {
4141         // Look at global declaration opcodes.
4142         switch (opCode)
4143         {
4144             // Informational instructions:
4145             case spv::OpTypePointer:
4146                 visitTypePointer(instruction);
4147                 break;
4148             // Instructions that may need transformation:
4149             case spv::OpEntryPoint:
4150                 transformationState = transformEntryPoint(instruction);
4151                 break;
4152             case spv::OpExtInst:
4153                 transformationState = transformExtInst(instruction);
4154                 break;
4155             case spv::OpName:
4156                 transformationState = transformName(instruction);
4157                 break;
4158             case spv::OpDecorate:
4159                 transformationState = transformDecorate(instruction);
4160                 break;
4161             case spv::OpVariable:
4162                 transformationState = transformVariable(instruction);
4163                 break;
4164             default:
4165                 break;
4166         }
4167     }
4168 
4169     // If the instruction was not transformed, copy it to output as is.
4170     if (transformationState == TransformationState::Unchanged)
4171     {
4172         copyInstruction(instruction, wordCount);
4173     }
4174 
4175     // Advance to next instruction.
4176     mCurrentWord += wordCount;
4177 }
4178 
getAliasingAttributeReplacementId(spirv::IdRef aliasingId,uint32_t offset) const4179 spirv::IdRef SpirvVertexAttributeAliasingTransformer::getAliasingAttributeReplacementId(
4180     spirv::IdRef aliasingId,
4181     uint32_t offset) const
4182 {
4183     // Get variable info corresponding to the aliasing attribute.
4184     const ShaderInterfaceVariableInfo *aliasingInfo = mVariableInfoById[aliasingId];
4185     ValidateShaderInterfaceVariableIsAttribute(aliasingInfo);
4186 
4187     // Find the replacement attribute.
4188     const AliasingAttributeMap *aliasingMap =
4189         &mAliasingAttributeMap[aliasingInfo->location + offset];
4190     ValidateIsAliasingAttribute(aliasingMap, aliasingId);
4191 
4192     const spirv::IdRef replacementId(aliasingMap->attribute);
4193     ASSERT(replacementId.valid() && replacementId < mIsAliasingAttributeById.size());
4194     ASSERT(!mIsAliasingAttributeById[replacementId]);
4195 
4196     return replacementId;
4197 }
4198 
isMatrixAttribute(spirv::IdRef id) const4199 bool SpirvVertexAttributeAliasingTransformer::isMatrixAttribute(spirv::IdRef id) const
4200 {
4201     return mExpandedMatrixFirstVectorIdById[id].valid();
4202 }
4203 
visitTypePointer(const uint32_t * instruction)4204 void SpirvVertexAttributeAliasingTransformer::visitTypePointer(const uint32_t *instruction)
4205 {
4206     spirv::IdResult id;
4207     spv::StorageClass storageClass;
4208     spirv::IdRef typeId;
4209     spirv::ParseTypePointer(instruction, &id, &storageClass, &typeId);
4210 
4211     // Only interested in OpTypePointer Input %vecN, where %vecN is the id of OpTypeVector %f32 N,
4212     // as well as OpTypePointer Private %matN, where %matN is the id of OpTypeMatrix %vecN N.
4213     // This is only for matN types (as allowed by GLSL ES 1.00), so N >= 2.
4214     if (storageClass == spv::StorageClassInput)
4215     {
4216         for (uint32_t n = 2; n <= 4; ++n)
4217         {
4218             if (typeId == floatType(n))
4219             {
4220                 ASSERT(!mInputTypePointers[n].valid());
4221                 mInputTypePointers[n] = id;
4222                 break;
4223             }
4224         }
4225     }
4226     else if (storageClass == spv::StorageClassPrivate)
4227     {
4228         for (uint32_t n = 2; n <= 4; ++n)
4229         {
4230             // Note that Private types may not be unique, as the previous transformation can
4231             // generate duplicates.
4232             if (typeId == floatType(n))
4233             {
4234                 mPrivateFloatTypePointers[n] = id;
4235                 break;
4236             }
4237             if (typeId == matrixType(n))
4238             {
4239                 mPrivateMatrixTypePointers[n] = id;
4240                 break;
4241             }
4242         }
4243     }
4244 }
4245 
transformEntryPoint(const uint32_t * instruction)4246 TransformationState SpirvVertexAttributeAliasingTransformer::transformEntryPoint(
4247     const uint32_t *instruction)
4248 {
4249     // Remove aliasing attributes from the shader interface declaration.
4250     spv::ExecutionModel executionModel;
4251     spirv::IdRef entryPointId;
4252     spirv::LiteralString name;
4253     spirv::IdRefList interfaceList;
4254     spirv::ParseEntryPoint(instruction, &executionModel, &entryPointId, &name, &interfaceList);
4255 
4256     // Should only have one EntryPoint
4257     ASSERT(entryPointId == ID::EntryPoint);
4258 
4259     // As a first pass, filter out matrix attributes and append their replacement vectors.
4260     size_t originalInterfaceListSize = interfaceList.size();
4261     for (size_t index = 0; index < originalInterfaceListSize; ++index)
4262     {
4263         const spirv::IdRef matrixId(interfaceList[index]);
4264 
4265         if (!mExpandedMatrixFirstVectorIdById[matrixId].valid())
4266         {
4267             continue;
4268         }
4269 
4270         const ShaderInterfaceVariableInfo *info = mVariableInfoById[matrixId];
4271         ValidateShaderInterfaceVariableIsAttribute(info);
4272 
4273         // Replace the matrix id with its first vector id.
4274         const spirv::IdRef vec0Id(mExpandedMatrixFirstVectorIdById[matrixId]);
4275         interfaceList[index] = vec0Id;
4276 
4277         // Append the rest of the vectors to the entry point.
4278         for (uint32_t offset = 1; offset < info->attributeLocationCount; ++offset)
4279         {
4280             const spirv::IdRef vecId(vec0Id + offset);
4281             interfaceList.push_back(vecId);
4282         }
4283     }
4284 
4285     // Filter out aliasing attributes from entry point interface declaration.
4286     size_t writeIndex = 0;
4287     for (size_t index = 0; index < interfaceList.size(); ++index)
4288     {
4289         const spirv::IdRef id(interfaceList[index]);
4290 
4291         // If this is an attribute that's aliasing another one in the same location, remove it.
4292         if (mIsAliasingAttributeById[id])
4293         {
4294             const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
4295             ValidateShaderInterfaceVariableIsAttribute(info);
4296 
4297             // The following assertion is only valid for non-matrix attributes.
4298             if (info->attributeLocationCount == 1)
4299             {
4300                 const AliasingAttributeMap *aliasingMap = &mAliasingAttributeMap[info->location];
4301                 ValidateIsAliasingAttribute(aliasingMap, id);
4302             }
4303 
4304             continue;
4305         }
4306 
4307         interfaceList[writeIndex] = id;
4308         ++writeIndex;
4309     }
4310 
4311     // Update the number of interface variables.
4312     interfaceList.resize_down(writeIndex);
4313 
4314     // Write the entry point with the aliasing attributes removed.
4315     spirv::WriteEntryPoint(mSpirvBlobOut, executionModel, ID::EntryPoint, name, interfaceList);
4316 
4317     return TransformationState::Transformed;
4318 }
4319 
transformExtInst(const uint32_t * instruction)4320 TransformationState SpirvVertexAttributeAliasingTransformer::transformExtInst(
4321     const uint32_t *instruction)
4322 {
4323     sh::vk::spirv::NonSemanticInstruction inst;
4324     if (!mNonSemanticInstructions.visitExtInst(instruction, &inst))
4325     {
4326         return TransformationState::Unchanged;
4327     }
4328 
4329     switch (inst)
4330     {
4331         case sh::vk::spirv::kNonSemanticOverview:
4332             // Declare the expanded matrix variables
4333             declareExpandedMatrixVectors();
4334             break;
4335         case sh::vk::spirv::kNonSemanticEnter:
4336             // The matrix attribute declarations have been changed to have Private storage class,
4337             // and they are initialized from the expanded (and potentially aliased) Input vectors.
4338             // This is done at the beginning of the entry point.
4339             writeExpandedMatrixInitialization();
4340             break;
4341         case sh::vk::spirv::kNonSemanticVertexOutput:
4342         case sh::vk::spirv::kNonSemanticTransformFeedbackEmulation:
4343             // Unused by this transformation
4344             break;
4345         default:
4346             UNREACHABLE();
4347             break;
4348     }
4349 
4350     // Drop the instruction if this is the last pass
4351     return mNonSemanticInstructions.transformExtInst(instruction);
4352 }
4353 
transformName(const uint32_t * instruction)4354 TransformationState SpirvVertexAttributeAliasingTransformer::transformName(
4355     const uint32_t *instruction)
4356 {
4357     spirv::IdRef id;
4358     spirv::LiteralString name;
4359     spirv::ParseName(instruction, &id, &name);
4360 
4361     // If id is not that of an aliasing attribute, there's nothing to do.
4362     ASSERT(id < mIsAliasingAttributeById.size());
4363     if (!mIsAliasingAttributeById[id])
4364     {
4365         return TransformationState::Unchanged;
4366     }
4367 
4368     // Drop debug annotations for this id.
4369     return TransformationState::Transformed;
4370 }
4371 
transformDecorate(const uint32_t * instruction)4372 TransformationState SpirvVertexAttributeAliasingTransformer::transformDecorate(
4373     const uint32_t *instruction)
4374 {
4375     spirv::IdRef id;
4376     spv::Decoration decoration;
4377     spirv::ParseDecorate(instruction, &id, &decoration, nullptr);
4378 
4379     if (isMatrixAttribute(id))
4380     {
4381         // If it's a matrix attribute, it's expanded to multiple vectors.  Insert the Location
4382         // decorations for these vectors here.
4383 
4384         // Keep all decorations except for Location.
4385         if (decoration != spv::DecorationLocation)
4386         {
4387             return TransformationState::Unchanged;
4388         }
4389 
4390         const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
4391         ValidateShaderInterfaceVariableIsAttribute(info);
4392 
4393         const spirv::IdRef vec0Id(mExpandedMatrixFirstVectorIdById[id]);
4394         ASSERT(vec0Id.valid());
4395 
4396         for (uint32_t offset = 0; offset < info->attributeLocationCount; ++offset)
4397         {
4398             const spirv::IdRef vecId(vec0Id + offset);
4399             if (mIsAliasingAttributeById[vecId])
4400             {
4401                 continue;
4402             }
4403 
4404             spirv::WriteDecorate(mSpirvBlobOut, vecId, decoration,
4405                                  {spirv::LiteralInteger(info->location + offset)});
4406         }
4407     }
4408     else
4409     {
4410         // If id is not that of an active attribute, there's nothing to do.
4411         const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
4412         if (info == nullptr || info->attributeComponentCount == 0 ||
4413             !info->activeStages[gl::ShaderType::Vertex])
4414         {
4415             return TransformationState::Unchanged;
4416         }
4417 
4418         // Always drop RelaxedPrecision from input attributes.  The temporary variable the attribute
4419         // is loaded into has RelaxedPrecision and will implicitly convert.
4420         if (decoration == spv::DecorationRelaxedPrecision)
4421         {
4422             return TransformationState::Transformed;
4423         }
4424 
4425         // If id is not that of an aliasing attribute, there's nothing else to do.
4426         ASSERT(id < mIsAliasingAttributeById.size());
4427         if (!mIsAliasingAttributeById[id])
4428         {
4429             return TransformationState::Unchanged;
4430         }
4431     }
4432 
4433     // Drop every decoration for this id.
4434     return TransformationState::Transformed;
4435 }
4436 
transformVariable(const uint32_t * instruction)4437 TransformationState SpirvVertexAttributeAliasingTransformer::transformVariable(
4438     const uint32_t *instruction)
4439 {
4440     spirv::IdResultType typeId;
4441     spirv::IdResult id;
4442     spv::StorageClass storageClass;
4443     spirv::ParseVariable(instruction, &typeId, &id, &storageClass, nullptr);
4444 
4445     if (!isMatrixAttribute(id))
4446     {
4447         // If id is not that of an aliasing attribute, there's nothing to do.  Note that matrix
4448         // declarations are always replaced.
4449         ASSERT(id < mIsAliasingAttributeById.size());
4450         if (!mIsAliasingAttributeById[id])
4451         {
4452             return TransformationState::Unchanged;
4453         }
4454     }
4455 
4456     ASSERT(storageClass == spv::StorageClassInput);
4457 
4458     // Drop the declaration.
4459     return TransformationState::Transformed;
4460 }
4461 
transformAccessChain(const uint32_t * instruction)4462 TransformationState SpirvVertexAttributeAliasingTransformer::transformAccessChain(
4463     const uint32_t *instruction)
4464 {
4465     spirv::IdResultType typeId;
4466     spirv::IdResult id;
4467     spirv::IdRef baseId;
4468     spirv::IdRefList indexList;
4469     spirv::ParseAccessChain(instruction, &typeId, &id, &baseId, &indexList);
4470 
4471     if (isMatrixAttribute(baseId))
4472     {
4473         // Write a modified OpAccessChain instruction.  Only modification is that the %type is
4474         // replaced with the Private version of it.  If there is one %index, that would be a vector
4475         // type, and if there are two %index'es, it's a float type.
4476         spirv::IdRef replacementTypeId;
4477 
4478         if (indexList.size() == 1)
4479         {
4480             // If indexed once, it uses a vector type.
4481             const ShaderInterfaceVariableInfo *info = mVariableInfoById[baseId];
4482             ValidateShaderInterfaceVariableIsAttribute(info);
4483 
4484             const uint32_t componentCount = info->attributeComponentCount;
4485 
4486             // %type must have been the Input vector type with the matrice's component size.
4487             ASSERT(typeId == mInputTypePointers[componentCount]);
4488 
4489             // Replace the type with the corresponding Private one.
4490             replacementTypeId = mPrivateFloatTypePointers[componentCount];
4491         }
4492         else
4493         {
4494             // If indexed twice, it uses the float type.
4495             ASSERT(indexList.size() == 2);
4496 
4497             // Replace the type with the Private pointer to float32.
4498             replacementTypeId = mPrivateFloatTypePointers[1];
4499         }
4500 
4501         spirv::WriteAccessChain(mSpirvBlobOut, replacementTypeId, id, baseId, indexList);
4502     }
4503     else
4504     {
4505         // If base id is not that of an aliasing attribute, there's nothing to do.
4506         ASSERT(baseId < mIsAliasingAttributeById.size());
4507         if (!mIsAliasingAttributeById[baseId])
4508         {
4509             return TransformationState::Unchanged;
4510         }
4511 
4512         // Find the replacement attribute for the aliasing one.
4513         const spirv::IdRef replacementId(getAliasingAttributeReplacementId(baseId, 0));
4514 
4515         // Get variable info corresponding to the replacement attribute.
4516         const ShaderInterfaceVariableInfo *replacementInfo = mVariableInfoById[replacementId];
4517         ValidateShaderInterfaceVariableIsAttribute(replacementInfo);
4518 
4519         // Write a modified OpAccessChain instruction.  Currently, the instruction is:
4520         //
4521         //     %id = OpAccessChain %type %base %index
4522         //
4523         // This is modified to:
4524         //
4525         //     %id = OpAccessChain %type %replacement %index
4526         //
4527         // Note that the replacement has at least as many components as the aliasing attribute,
4528         // and both attributes start at component 0 (GLSL ES restriction).  So, indexing the
4529         // replacement attribute with the same index yields the same result and type.
4530         spirv::WriteAccessChain(mSpirvBlobOut, typeId, id, replacementId, indexList);
4531     }
4532 
4533     return TransformationState::Transformed;
4534 }
4535 
transformLoadHelper(spirv::IdRef pointerId,spirv::IdRef typeId,spirv::IdRef replacementId,spirv::IdRef resultId)4536 void SpirvVertexAttributeAliasingTransformer::transformLoadHelper(spirv::IdRef pointerId,
4537                                                                   spirv::IdRef typeId,
4538                                                                   spirv::IdRef replacementId,
4539                                                                   spirv::IdRef resultId)
4540 {
4541     // Get variable info corresponding to the replacement attribute.
4542     const ShaderInterfaceVariableInfo *replacementInfo = mVariableInfoById[replacementId];
4543     ValidateShaderInterfaceVariableIsAttribute(replacementInfo);
4544 
4545     // Currently, the instruction is:
4546     //
4547     //     %id = OpLoad %type %pointer
4548     //
4549     // This is modified to:
4550     //
4551     //     %newId = OpLoad %replacementType %replacement
4552     //
4553     const spirv::IdRef loadResultId(getNewId());
4554     const spirv::IdRef replacementTypeId(floatType(replacementInfo->attributeComponentCount));
4555     ASSERT(replacementTypeId.valid());
4556 
4557     spirv::WriteLoad(mSpirvBlobOut, replacementTypeId, loadResultId, replacementId, nullptr);
4558 
4559     // If swizzle is not necessary, assign %newId to %resultId.
4560     const ShaderInterfaceVariableInfo *aliasingInfo = mVariableInfoById[pointerId];
4561     if (aliasingInfo->attributeComponentCount == replacementInfo->attributeComponentCount)
4562     {
4563         spirv::WriteCopyObject(mSpirvBlobOut, typeId, resultId, loadResultId);
4564         return;
4565     }
4566 
4567     // Take as many components from the replacement as the aliasing attribute wanted.  This is done
4568     // by either of the following instructions:
4569     //
4570     // - If aliasing attribute has only one component:
4571     //
4572     //     %resultId = OpCompositeExtract %floatType %newId 0
4573     //
4574     // - If aliasing attribute has more than one component:
4575     //
4576     //     %resultId = OpVectorShuffle %vecType %newId %newId 0 1 ...
4577     //
4578     ASSERT(aliasingInfo->attributeComponentCount < replacementInfo->attributeComponentCount);
4579     ASSERT(floatType(aliasingInfo->attributeComponentCount) == typeId);
4580 
4581     if (aliasingInfo->attributeComponentCount == 1)
4582     {
4583         spirv::WriteCompositeExtract(mSpirvBlobOut, typeId, resultId, loadResultId,
4584                                      {spirv::LiteralInteger(0)});
4585     }
4586     else
4587     {
4588         spirv::LiteralIntegerList swizzle = {spirv::LiteralInteger(0), spirv::LiteralInteger(1),
4589                                              spirv::LiteralInteger(2), spirv::LiteralInteger(3)};
4590         swizzle.resize_down(aliasingInfo->attributeComponentCount);
4591 
4592         spirv::WriteVectorShuffle(mSpirvBlobOut, typeId, resultId, loadResultId, loadResultId,
4593                                   swizzle);
4594     }
4595 }
4596 
transformLoad(const uint32_t * instruction)4597 TransformationState SpirvVertexAttributeAliasingTransformer::transformLoad(
4598     const uint32_t *instruction)
4599 {
4600     spirv::IdResultType typeId;
4601     spirv::IdResult id;
4602     spirv::IdRef pointerId;
4603     ParseLoad(instruction, &typeId, &id, &pointerId, nullptr);
4604 
4605     // Currently, the instruction is:
4606     //
4607     //     %id = OpLoad %type %pointer
4608     //
4609     // If non-matrix, this is modifed to load from the aliasing vector instead if aliasing.
4610     //
4611     // If matrix, this is modified such that %type points to the Private version of it.
4612     //
4613     if (isMatrixAttribute(pointerId))
4614     {
4615         const ShaderInterfaceVariableInfo *info = mVariableInfoById[pointerId];
4616         ValidateShaderInterfaceVariableIsAttribute(info);
4617 
4618         const spirv::IdRef replacementTypeId(matrixType(info->attributeLocationCount));
4619 
4620         spirv::WriteLoad(mSpirvBlobOut, replacementTypeId, id, pointerId, nullptr);
4621     }
4622     else
4623     {
4624         // If pointer id is not that of an aliasing attribute, there's nothing to do.
4625         ASSERT(pointerId < mIsAliasingAttributeById.size());
4626         if (!mIsAliasingAttributeById[pointerId])
4627         {
4628             return TransformationState::Unchanged;
4629         }
4630 
4631         // Find the replacement attribute for the aliasing one.
4632         const spirv::IdRef replacementId(getAliasingAttributeReplacementId(pointerId, 0));
4633 
4634         // Replace the load instruction by a load from the replacement id.
4635         transformLoadHelper(pointerId, typeId, replacementId, id);
4636     }
4637 
4638     return TransformationState::Transformed;
4639 }
4640 
declareExpandedMatrixVectors()4641 void SpirvVertexAttributeAliasingTransformer::declareExpandedMatrixVectors()
4642 {
4643     // Go through matrix attributes and expand them.
4644     for (uint32_t matrixIdIndex = spirv::kMinValidId;
4645          matrixIdIndex < mExpandedMatrixFirstVectorIdById.size(); ++matrixIdIndex)
4646     {
4647         const spirv::IdRef matrixId(matrixIdIndex);
4648 
4649         if (!mExpandedMatrixFirstVectorIdById[matrixId].valid())
4650         {
4651             continue;
4652         }
4653 
4654         const spirv::IdRef vec0Id(mExpandedMatrixFirstVectorIdById[matrixId]);
4655 
4656         const ShaderInterfaceVariableInfo *info = mVariableInfoById[matrixId];
4657         ValidateShaderInterfaceVariableIsAttribute(info);
4658 
4659         // Need to generate the following:
4660         //
4661         //     %privateType = OpTypePointer Private %matrixType
4662         //     %id = OpVariable %privateType Private
4663         //     %vecType = OpTypePointer %vecType Input
4664         //     %vec0 = OpVariable %vecType Input
4665         //     ...
4666         //     %vecN-1 = OpVariable %vecType Input
4667         const uint32_t componentCount = info->attributeComponentCount;
4668         const uint32_t locationCount  = info->attributeLocationCount;
4669         ASSERT(componentCount == locationCount);
4670 
4671         // OpTypePointer Private %matrixType
4672         spirv::IdRef privateType(mPrivateMatrixTypePointers[locationCount]);
4673         if (!privateType.valid())
4674         {
4675             privateType                               = getNewId();
4676             mPrivateMatrixTypePointers[locationCount] = privateType;
4677             spirv::WriteTypePointer(mSpirvBlobOut, privateType, spv::StorageClassPrivate,
4678                                     matrixType(locationCount));
4679         }
4680 
4681         // OpVariable %privateType Private
4682         spirv::WriteVariable(mSpirvBlobOut, privateType, matrixId, spv::StorageClassPrivate,
4683                              nullptr);
4684 
4685         // If the OpTypePointer is not declared for the vector type corresponding to each location,
4686         // declare it now.
4687         //
4688         //     %vecType = OpTypePointer %vecType Input
4689         spirv::IdRef inputType(mInputTypePointers[componentCount]);
4690         if (!inputType.valid())
4691         {
4692             inputType                          = getNewId();
4693             mInputTypePointers[componentCount] = inputType;
4694             spirv::WriteTypePointer(mSpirvBlobOut, inputType, spv::StorageClassInput,
4695                                     floatType(componentCount));
4696         }
4697 
4698         // Declare a vector for each column of the matrix.
4699         for (uint32_t offset = 0; offset < info->attributeLocationCount; ++offset)
4700         {
4701             const spirv::IdRef vecId(vec0Id + offset);
4702             if (!mIsAliasingAttributeById[vecId])
4703             {
4704                 spirv::WriteVariable(mSpirvBlobOut, inputType, vecId, spv::StorageClassInput,
4705                                      nullptr);
4706             }
4707         }
4708     }
4709 
4710     // Additionally, declare OpTypePointer Private %floatType(i) in case needed (used in
4711     // Op*AccessChain instructions, if any).
4712     for (uint32_t n = 1; n <= 4; ++n)
4713     {
4714         if (!mPrivateFloatTypePointers[n].valid())
4715         {
4716             const spirv::IdRef privateType(getNewId());
4717             mPrivateFloatTypePointers[n] = privateType;
4718             spirv::WriteTypePointer(mSpirvBlobOut, privateType, spv::StorageClassPrivate,
4719                                     floatType(n));
4720         }
4721     }
4722 }
4723 
writeExpandedMatrixInitialization()4724 void SpirvVertexAttributeAliasingTransformer::writeExpandedMatrixInitialization()
4725 {
4726     // Go through matrix attributes and initialize them.  Note that their declaration is replaced
4727     // with a Private storage class, but otherwise has the same id.
4728     for (uint32_t matrixIdIndex = spirv::kMinValidId;
4729          matrixIdIndex < mExpandedMatrixFirstVectorIdById.size(); ++matrixIdIndex)
4730     {
4731         const spirv::IdRef matrixId(matrixIdIndex);
4732 
4733         if (!mExpandedMatrixFirstVectorIdById[matrixId].valid())
4734         {
4735             continue;
4736         }
4737 
4738         const spirv::IdRef vec0Id(mExpandedMatrixFirstVectorIdById[matrixId]);
4739 
4740         // For every matrix, need to generate the following:
4741         //
4742         //     %vec0Id = OpLoad %vecType %vec0Pointer
4743         //     ...
4744         //     %vecN-1Id = OpLoad %vecType %vecN-1Pointer
4745         //     %mat = OpCompositeConstruct %matrixType %vec0 ... %vecN-1
4746         //     OpStore %matrixId %mat
4747 
4748         const ShaderInterfaceVariableInfo *info = mVariableInfoById[matrixId];
4749         ValidateShaderInterfaceVariableIsAttribute(info);
4750 
4751         spirv::IdRefList vecLoadIds;
4752         const uint32_t locationCount = info->attributeLocationCount;
4753         for (uint32_t offset = 0; offset < locationCount; ++offset)
4754         {
4755             const spirv::IdRef vecId(vec0Id + offset);
4756 
4757             // Load into temporary, potentially through an aliasing vector.
4758             spirv::IdRef replacementId(vecId);
4759             ASSERT(vecId < mIsAliasingAttributeById.size());
4760             if (mIsAliasingAttributeById[vecId])
4761             {
4762                 replacementId = getAliasingAttributeReplacementId(vecId, offset);
4763             }
4764 
4765             // Write a load instruction from the replacement id.
4766             vecLoadIds.push_back(getNewId());
4767             transformLoadHelper(matrixId, floatType(info->attributeComponentCount), replacementId,
4768                                 vecLoadIds.back());
4769         }
4770 
4771         // Aggregate the vector loads into a matrix.
4772         const spirv::IdRef compositeId(getNewId());
4773         spirv::WriteCompositeConstruct(mSpirvBlobOut, matrixType(locationCount), compositeId,
4774                                        vecLoadIds);
4775 
4776         // Store it in the private variable.
4777         spirv::WriteStore(mSpirvBlobOut, matrixId, compositeId, nullptr);
4778     }
4779 }
4780 }  // anonymous namespace
4781 
SpvCreateSourceOptions(const angle::FeaturesVk & features)4782 SpvSourceOptions SpvCreateSourceOptions(const angle::FeaturesVk &features)
4783 {
4784     SpvSourceOptions options;
4785 
4786     options.supportsTransformFeedbackExtension =
4787         features.supportsTransformFeedbackExtension.enabled;
4788     options.supportsTransformFeedbackEmulation = features.emulateTransformFeedback.enabled;
4789     options.enableTransformFeedbackEmulation   = options.supportsTransformFeedbackEmulation;
4790 
4791     return options;
4792 }
4793 
SpvGetXfbBufferBlockId(const uint32_t bufferIndex)4794 uint32_t SpvGetXfbBufferBlockId(const uint32_t bufferIndex)
4795 {
4796     ASSERT(bufferIndex < 4);
4797     static_assert(sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockOne ==
4798                   sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockZero + 1);
4799     static_assert(sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockTwo ==
4800                   sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockZero + 2);
4801     static_assert(sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockThree ==
4802                   sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockZero + 3);
4803 
4804     return sh::vk::spirv::ReservedIds::kIdXfbEmulationBufferBlockZero + bufferIndex;
4805 }
4806 
SpvAssignLocations(const SpvSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ProgramVaryingPacking & varyingPacking,const gl::ShaderType transformFeedbackStage,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)4807 void SpvAssignLocations(const SpvSourceOptions &options,
4808                         const gl::ProgramExecutable &programExecutable,
4809                         const gl::ProgramVaryingPacking &varyingPacking,
4810                         const gl::ShaderType transformFeedbackStage,
4811                         SpvProgramInterfaceInfo *programInterfaceInfo,
4812                         ShaderInterfaceVariableInfoMap *variableInfoMapOut)
4813 {
4814     const gl::ShaderBitSet shaderStages = programExecutable.getLinkedShaderStages();
4815 
4816     // Assign outputs to the fragment shader, if any.
4817     if (shaderStages[gl::ShaderType::Fragment] &&
4818         programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment))
4819     {
4820         AssignOutputLocations(programExecutable, gl::ShaderType::Fragment, variableInfoMapOut);
4821     }
4822 
4823     // Assign attributes to the vertex shader, if any.
4824     if (shaderStages[gl::ShaderType::Vertex] &&
4825         programExecutable.hasLinkedShaderStage(gl::ShaderType::Vertex))
4826     {
4827         AssignAttributeLocations(programExecutable, gl::ShaderType::Vertex, variableInfoMapOut);
4828 
4829         if (options.supportsTransformFeedbackEmulation)
4830         {
4831             // If transform feedback emulation is not enabled, mark all transform feedback output
4832             // buffers as inactive.
4833             const bool isTransformFeedbackStage =
4834                 transformFeedbackStage == gl::ShaderType::Vertex &&
4835                 options.enableTransformFeedbackEmulation &&
4836                 !programExecutable.getLinkedTransformFeedbackVaryings().empty();
4837 
4838             AssignTransformFeedbackEmulationBindings(gl::ShaderType::Vertex, programExecutable,
4839                                                      isTransformFeedbackStage, programInterfaceInfo,
4840                                                      variableInfoMapOut);
4841         }
4842     }
4843 
4844     gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
4845     for (const gl::ShaderType shaderType : shaderStages)
4846     {
4847         if (programExecutable.hasLinkedGraphicsShader())
4848         {
4849             const gl::VaryingPacking &inputPacking  = varyingPacking.getInputPacking(shaderType);
4850             const gl::VaryingPacking &outputPacking = varyingPacking.getOutputPacking(shaderType);
4851 
4852             // Assign varying locations.
4853             if (shaderType != gl::ShaderType::Vertex)
4854             {
4855                 AssignVaryingLocations(options, inputPacking, shaderType, frontShaderType,
4856                                        programInterfaceInfo, variableInfoMapOut);
4857 
4858                 // Record active members of in gl_PerVertex.
4859                 if (shaderType != gl::ShaderType::Fragment &&
4860                     frontShaderType != gl::ShaderType::InvalidEnum)
4861                 {
4862                     // If an output builtin is active in the previous stage, assume it's active in
4863                     // the input of the current stage as well.
4864                     const gl::ShaderMap<gl::PerVertexMemberBitSet> &outputPerVertexActiveMembers =
4865                         inputPacking.getOutputPerVertexActiveMembers();
4866                     variableInfoMapOut->setInputPerVertexActiveMembers(
4867                         shaderType, outputPerVertexActiveMembers[frontShaderType]);
4868                 }
4869             }
4870             if (shaderType != gl::ShaderType::Fragment)
4871             {
4872                 AssignVaryingLocations(options, outputPacking, shaderType, frontShaderType,
4873                                        programInterfaceInfo, variableInfoMapOut);
4874 
4875                 // Record active members of out gl_PerVertex.
4876                 const gl::ShaderMap<gl::PerVertexMemberBitSet> &outputPerVertexActiveMembers =
4877                     outputPacking.getOutputPerVertexActiveMembers();
4878                 variableInfoMapOut->setOutputPerVertexActiveMembers(
4879                     shaderType, outputPerVertexActiveMembers[shaderType]);
4880             }
4881 
4882             // Assign qualifiers to all varyings captured by transform feedback
4883             if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
4884                 shaderType == programExecutable.getLinkedTransformFeedbackStage())
4885             {
4886                 AssignTransformFeedbackQualifiers(programExecutable, outputPacking, shaderType,
4887                                                   options.supportsTransformFeedbackExtension,
4888                                                   variableInfoMapOut);
4889             }
4890         }
4891 
4892         frontShaderType = shaderType;
4893     }
4894 
4895     AssignUniformBindings(options, programExecutable, programInterfaceInfo, variableInfoMapOut);
4896     AssignTextureBindings(options, programExecutable, programInterfaceInfo, variableInfoMapOut);
4897     AssignNonTextureBindings(options, programExecutable, programInterfaceInfo, variableInfoMapOut);
4898 }
4899 
SpvAssignTransformFeedbackLocations(gl::ShaderType shaderType,const gl::ProgramExecutable & programExecutable,bool isTransformFeedbackStage,SpvProgramInterfaceInfo * programInterfaceInfo,ShaderInterfaceVariableInfoMap * variableInfoMapOut)4900 void SpvAssignTransformFeedbackLocations(gl::ShaderType shaderType,
4901                                          const gl::ProgramExecutable &programExecutable,
4902                                          bool isTransformFeedbackStage,
4903                                          SpvProgramInterfaceInfo *programInterfaceInfo,
4904                                          ShaderInterfaceVariableInfoMap *variableInfoMapOut)
4905 {
4906     // The only varying that requires additional resources is gl_Position, as it's indirectly
4907     // captured through ANGLEXfbPosition.
4908 
4909     const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
4910         programExecutable.getLinkedTransformFeedbackVaryings();
4911 
4912     bool capturesPosition = false;
4913 
4914     if (isTransformFeedbackStage)
4915     {
4916         for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
4917         {
4918             const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
4919             const std::string &tfVaryingName              = tfVarying.name;
4920 
4921             if (tfVaryingName == "gl_Position")
4922             {
4923                 ASSERT(tfVarying.isBuiltIn());
4924                 capturesPosition = true;
4925                 break;
4926             }
4927         }
4928     }
4929 
4930     if (capturesPosition)
4931     {
4932         AddLocationInfo(variableInfoMapOut, shaderType, sh::vk::spirv::kIdXfbExtensionPosition,
4933                         programInterfaceInfo->locationsUsedForXfbExtension, 0, 0, 0);
4934         ++programInterfaceInfo->locationsUsedForXfbExtension;
4935     }
4936     else
4937     {
4938         // Make sure this varying is removed from the other stages, or if position is not captured
4939         // at all.
4940         variableInfoMapOut->add(shaderType, sh::vk::spirv::kIdXfbExtensionPosition);
4941     }
4942 }
4943 
SpvGetShaderSpirvCode(const gl::Context * context,const SpvSourceOptions & options,const gl::ProgramState & programState,const gl::ProgramLinkedResources & resources,SpvProgramInterfaceInfo * programInterfaceInfo,gl::ShaderMap<const spirv::Blob * > * spirvBlobsOut,ShaderInterfaceVariableInfoMap * variableInfoMapOut)4944 void SpvGetShaderSpirvCode(const gl::Context *context,
4945                            const SpvSourceOptions &options,
4946                            const gl::ProgramState &programState,
4947                            const gl::ProgramLinkedResources &resources,
4948                            SpvProgramInterfaceInfo *programInterfaceInfo,
4949                            gl::ShaderMap<const spirv::Blob *> *spirvBlobsOut,
4950                            ShaderInterfaceVariableInfoMap *variableInfoMapOut)
4951 {
4952     for (const gl::ShaderType shaderType : gl::AllShaderTypes())
4953     {
4954         gl::Shader *glShader         = programState.getAttachedShader(shaderType);
4955         (*spirvBlobsOut)[shaderType] = glShader ? &glShader->getCompiledBinary(context) : nullptr;
4956     }
4957 
4958     const gl::ProgramExecutable &programExecutable = programState.getExecutable();
4959     gl::ShaderType xfbStage = programState.getAttachedTransformFeedbackStage();
4960 
4961     // This should be done before assigning varying location. Otherwise, We can encounter shader
4962     // interface mismatching problem in case the transformFeedback stage is not Vertex stage.
4963     for (const gl::ShaderType shaderType : programExecutable.getLinkedShaderStages())
4964     {
4965         // Assign location to varyings generated for transform feedback capture
4966         const bool isXfbStage = shaderType == xfbStage &&
4967                                 !programExecutable.getLinkedTransformFeedbackVaryings().empty();
4968         if (options.supportsTransformFeedbackExtension &&
4969             gl::ShaderTypeSupportsTransformFeedback(shaderType))
4970         {
4971             SpvAssignTransformFeedbackLocations(shaderType, programExecutable, isXfbStage,
4972                                                 programInterfaceInfo, variableInfoMapOut);
4973         }
4974     }
4975 
4976     SpvAssignLocations(options, programExecutable, resources.varyingPacking, xfbStage,
4977                        programInterfaceInfo, variableInfoMapOut);
4978 }
4979 
SpvTransformSpirvCode(const SpvTransformOptions & options,const ShaderInterfaceVariableInfoMap & variableInfoMap,const spirv::Blob & initialSpirvBlob,spirv::Blob * spirvBlobOut)4980 angle::Result SpvTransformSpirvCode(const SpvTransformOptions &options,
4981                                     const ShaderInterfaceVariableInfoMap &variableInfoMap,
4982                                     const spirv::Blob &initialSpirvBlob,
4983                                     spirv::Blob *spirvBlobOut)
4984 {
4985     if (initialSpirvBlob.empty())
4986     {
4987         return angle::Result::Continue;
4988     }
4989 
4990     const bool hasAliasingAttributes =
4991         options.shaderType == gl::ShaderType::Vertex && variableInfoMap.hasAliasingAttributes();
4992 
4993     // Transform the SPIR-V code by assigning location/set/binding values.
4994     SpirvTransformer transformer(initialSpirvBlob, options, !hasAliasingAttributes, variableInfoMap,
4995                                  spirvBlobOut);
4996     transformer.transform();
4997 
4998     // If there are aliasing vertex attributes, transform the SPIR-V again to remove them.
4999     if (hasAliasingAttributes)
5000     {
5001         spirv::Blob preTransformBlob = std::move(*spirvBlobOut);
5002         SpirvVertexAttributeAliasingTransformer aliasingTransformer(
5003             preTransformBlob, variableInfoMap, std::move(transformer.getVariableInfoByIdMap()),
5004             spirvBlobOut);
5005         aliasingTransformer.transform();
5006     }
5007 
5008     spirvBlobOut->shrink_to_fit();
5009 
5010     if (options.validate)
5011     {
5012         ASSERT(spirv::Validate(*spirvBlobOut));
5013     }
5014 
5015     return angle::Result::Continue;
5016 }
5017 }  // namespace rx
5018