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