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