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