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