• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Wrapper for Khronos glslang compiler.
7 //
8 
9 #include "libANGLE/renderer/glslang_wrapper_utils.h"
10 
11 // glslang has issues with some specific warnings.
12 ANGLE_DISABLE_EXTRA_SEMI_WARNING
13 ANGLE_DISABLE_SHADOWING_WARNING
14 
15 // glslang's version of ShaderLang.h, not to be confused with ANGLE's.
16 #include <glslang/Public/ShaderLang.h>
17 
18 // Other glslang includes.
19 #include <SPIRV/GlslangToSpv.h>
20 #include <StandAlone/ResourceLimits.h>
21 
22 ANGLE_REENABLE_SHADOWING_WARNING
23 ANGLE_REENABLE_EXTRA_SEMI_WARNING
24 
25 // SPIR-V headers include for AST transformation.
26 #include <spirv/unified1/spirv.hpp>
27 
28 // SPIR-V tools include for AST validation.
29 #include <spirv-tools/libspirv.hpp>
30 
31 #include <array>
32 #include <numeric>
33 
34 #include "common/FixedVector.h"
35 #include "common/string_utils.h"
36 #include "common/utilities.h"
37 #include "libANGLE/Caps.h"
38 #include "libANGLE/ProgramLinkedResources.h"
39 
40 #define ANGLE_GLSLANG_CHECK(CALLBACK, TEST, ERR) \
41     do                                           \
42     {                                            \
43         if (ANGLE_UNLIKELY(!(TEST)))             \
44         {                                        \
45             return CALLBACK(ERR);                \
46         }                                        \
47                                                  \
48     } while (0)
49 
50 namespace rx
51 {
52 namespace
53 {
54 constexpr char kXfbDeclMarker[]    = "@@ XFB-DECL @@";
55 constexpr char kXfbOutMarker[]     = "@@ XFB-OUT @@;";
56 constexpr char kXfbBuiltInPrefix[] = "xfbANGLE";
57 
58 template <size_t N>
ConstStrLen(const char (&)[N])59 constexpr size_t ConstStrLen(const char (&)[N])
60 {
61     static_assert(N > 0, "C++ shouldn't allow N to be zero");
62 
63     // The length of a string defined as a char array is the size of the array minus 1 (the
64     // terminating '\0').
65     return N - 1;
66 }
67 
GetBuiltInResourcesFromCaps(const gl::Caps & caps,TBuiltInResource * outBuiltInResources)68 void GetBuiltInResourcesFromCaps(const gl::Caps &caps, TBuiltInResource *outBuiltInResources)
69 {
70     outBuiltInResources->maxDrawBuffers                   = caps.maxDrawBuffers;
71     outBuiltInResources->maxAtomicCounterBindings         = caps.maxAtomicCounterBufferBindings;
72     outBuiltInResources->maxAtomicCounterBufferSize       = caps.maxAtomicCounterBufferSize;
73     outBuiltInResources->maxClipPlanes                    = caps.maxClipPlanes;
74     outBuiltInResources->maxCombinedAtomicCounterBuffers  = caps.maxCombinedAtomicCounterBuffers;
75     outBuiltInResources->maxCombinedAtomicCounters        = caps.maxCombinedAtomicCounters;
76     outBuiltInResources->maxCombinedImageUniforms         = caps.maxCombinedImageUniforms;
77     outBuiltInResources->maxCombinedTextureImageUnits     = caps.maxCombinedTextureImageUnits;
78     outBuiltInResources->maxCombinedShaderOutputResources = caps.maxCombinedShaderOutputResources;
79     outBuiltInResources->maxComputeWorkGroupCountX        = caps.maxComputeWorkGroupCount[0];
80     outBuiltInResources->maxComputeWorkGroupCountY        = caps.maxComputeWorkGroupCount[1];
81     outBuiltInResources->maxComputeWorkGroupCountZ        = caps.maxComputeWorkGroupCount[2];
82     outBuiltInResources->maxComputeWorkGroupSizeX         = caps.maxComputeWorkGroupSize[0];
83     outBuiltInResources->maxComputeWorkGroupSizeY         = caps.maxComputeWorkGroupSize[1];
84     outBuiltInResources->maxComputeWorkGroupSizeZ         = caps.maxComputeWorkGroupSize[2];
85     outBuiltInResources->minProgramTexelOffset            = caps.minProgramTexelOffset;
86     outBuiltInResources->maxFragmentUniformVectors        = caps.maxFragmentUniformVectors;
87     outBuiltInResources->maxFragmentInputComponents       = caps.maxFragmentInputComponents;
88     outBuiltInResources->maxGeometryInputComponents       = caps.maxGeometryInputComponents;
89     outBuiltInResources->maxGeometryOutputComponents      = caps.maxGeometryOutputComponents;
90     outBuiltInResources->maxGeometryOutputVertices        = caps.maxGeometryOutputVertices;
91     outBuiltInResources->maxGeometryTotalOutputComponents = caps.maxGeometryTotalOutputComponents;
92     outBuiltInResources->maxLights                        = caps.maxLights;
93     outBuiltInResources->maxProgramTexelOffset            = caps.maxProgramTexelOffset;
94     outBuiltInResources->maxVaryingComponents             = caps.maxVaryingComponents;
95     outBuiltInResources->maxVaryingVectors                = caps.maxVaryingVectors;
96     outBuiltInResources->maxVertexAttribs                 = caps.maxVertexAttributes;
97     outBuiltInResources->maxVertexOutputComponents        = caps.maxVertexOutputComponents;
98     outBuiltInResources->maxVertexUniformVectors          = caps.maxVertexUniformVectors;
99     outBuiltInResources->maxClipDistances                 = caps.maxClipDistances;
100 }
101 
102 // Test if there are non-zero indices in the uniform name, returning false in that case.  This
103 // happens for multi-dimensional arrays, where a uniform is created for every possible index of the
104 // array (except for the innermost dimension).  When assigning decorations (set/binding/etc), only
105 // the indices corresponding to the first element of the array should be specified.  This function
106 // is used to skip the other indices.
107 //
108 // If useOldRewriteStructSamplers, there are multiple samplers extracted out of struct arrays
109 // though, so the above only applies to the sampler array defined in the struct.
UniformNameIsIndexZero(const std::string & name,bool excludeCheckForOwningStructArrays)110 bool UniformNameIsIndexZero(const std::string &name, bool excludeCheckForOwningStructArrays)
111 {
112     size_t lastBracketClose = 0;
113 
114     if (excludeCheckForOwningStructArrays)
115     {
116         size_t lastDot = name.find_last_of('.');
117         if (lastDot != std::string::npos)
118         {
119             lastBracketClose = lastDot;
120         }
121     }
122 
123     while (true)
124     {
125         size_t openBracket = name.find('[', lastBracketClose);
126         if (openBracket == std::string::npos)
127         {
128             break;
129         }
130         size_t closeBracket = name.find(']', openBracket);
131 
132         // If the index between the brackets is not zero, ignore this uniform.
133         if (name.substr(openBracket + 1, closeBracket - openBracket - 1) != "0")
134         {
135             return false;
136         }
137         lastBracketClose = closeBracket;
138     }
139 
140     return true;
141 }
142 
MappedSamplerNameNeedsUserDefinedPrefix(const std::string & originalName)143 bool MappedSamplerNameNeedsUserDefinedPrefix(const std::string &originalName)
144 {
145     return originalName.find('.') == std::string::npos;
146 }
147 
148 template <typename OutputIter, typename ImplicitIter>
CountExplicitOutputs(OutputIter outputsBegin,OutputIter outputsEnd,ImplicitIter implicitsBegin,ImplicitIter implicitsEnd)149 uint32_t CountExplicitOutputs(OutputIter outputsBegin,
150                               OutputIter outputsEnd,
151                               ImplicitIter implicitsBegin,
152                               ImplicitIter implicitsEnd)
153 {
154     auto reduce = [implicitsBegin, implicitsEnd](uint32_t count, const sh::ShaderVariable &var) {
155         bool isExplicit = std::find(implicitsBegin, implicitsEnd, var.name) == implicitsEnd;
156         return count + isExplicit;
157     };
158 
159     return std::accumulate(outputsBegin, outputsEnd, 0, reduce);
160 }
161 
AddShaderInterfaceVariable(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName)162 ShaderInterfaceVariableInfo *AddShaderInterfaceVariable(ShaderInterfaceVariableInfoMap *infoMap,
163                                                         const std::string &varName)
164 {
165     ASSERT(infoMap->find(varName) == infoMap->end());
166     return &(*infoMap)[varName];
167 }
168 
GetShaderInterfaceVariable(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName)169 ShaderInterfaceVariableInfo *GetShaderInterfaceVariable(ShaderInterfaceVariableInfoMap *infoMap,
170                                                         const std::string &varName)
171 {
172     ASSERT(infoMap->find(varName) != infoMap->end());
173     return &(*infoMap)[varName];
174 }
175 
AddResourceInfoToAllStages(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName,uint32_t descriptorSet,uint32_t binding)176 ShaderInterfaceVariableInfo *AddResourceInfoToAllStages(ShaderInterfaceVariableInfoMap *infoMap,
177                                                         const std::string &varName,
178                                                         uint32_t descriptorSet,
179                                                         uint32_t binding)
180 {
181     gl::ShaderBitSet allStages;
182     allStages.set();
183 
184     ShaderInterfaceVariableInfo *info = AddShaderInterfaceVariable(infoMap, varName);
185     info->descriptorSet               = descriptorSet;
186     info->binding                     = binding;
187     info->activeStages                = allStages;
188     return info;
189 }
190 
AddResourceInfo(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName,uint32_t descriptorSet,uint32_t binding,const gl::ShaderType shaderType)191 ShaderInterfaceVariableInfo *AddResourceInfo(ShaderInterfaceVariableInfoMap *infoMap,
192                                              const std::string &varName,
193                                              uint32_t descriptorSet,
194                                              uint32_t binding,
195                                              const gl::ShaderType shaderType)
196 {
197     gl::ShaderBitSet stages;
198     stages.set(shaderType);
199 
200     ShaderInterfaceVariableInfo *info = AddShaderInterfaceVariable(infoMap, varName);
201     info->descriptorSet               = descriptorSet;
202     info->binding                     = binding;
203     info->activeStages                = stages;
204     return info;
205 }
206 
207 // Add location information for an in/out variable.
AddLocationInfo(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName,uint32_t location,uint32_t component,gl::ShaderType stage)208 ShaderInterfaceVariableInfo *AddLocationInfo(ShaderInterfaceVariableInfoMap *infoMap,
209                                              const std::string &varName,
210                                              uint32_t location,
211                                              uint32_t component,
212                                              gl::ShaderType stage)
213 {
214     // The info map for this name may or may not exist already.  This function merges the
215     // location/component information.
216     ShaderInterfaceVariableInfo *info = &(*infoMap)[varName];
217 
218     ASSERT(info->descriptorSet == ShaderInterfaceVariableInfo::kInvalid);
219     ASSERT(info->binding == ShaderInterfaceVariableInfo::kInvalid);
220     ASSERT(info->location == ShaderInterfaceVariableInfo::kInvalid);
221     ASSERT(info->component == ShaderInterfaceVariableInfo::kInvalid);
222 
223     info->location  = location;
224     info->component = component;
225     info->activeStages.set(stage);
226 
227     return info;
228 }
229 
230 // Modify an existing out variable and add transform feedback information.
SetXfbInfo(ShaderInterfaceVariableInfoMap * infoMap,const std::string & varName,uint32_t xfbBuffer,uint32_t xfbOffset,uint32_t xfbStride)231 ShaderInterfaceVariableInfo *SetXfbInfo(ShaderInterfaceVariableInfoMap *infoMap,
232                                         const std::string &varName,
233                                         uint32_t xfbBuffer,
234                                         uint32_t xfbOffset,
235                                         uint32_t xfbStride)
236 {
237     ShaderInterfaceVariableInfo *info = GetShaderInterfaceVariable(infoMap, varName);
238 
239     ASSERT(info->xfbBuffer == ShaderInterfaceVariableInfo::kInvalid);
240     ASSERT(info->xfbOffset == ShaderInterfaceVariableInfo::kInvalid);
241     ASSERT(info->xfbStride == ShaderInterfaceVariableInfo::kInvalid);
242 
243     info->xfbBuffer = xfbBuffer;
244     info->xfbOffset = xfbOffset;
245     info->xfbStride = xfbStride;
246     return info;
247 }
248 
SubstituteTransformFeedbackMarkers(const std::string & originalSource,const std::string & xfbDecl,const std::string & xfbOut)249 std::string SubstituteTransformFeedbackMarkers(const std::string &originalSource,
250                                                const std::string &xfbDecl,
251                                                const std::string &xfbOut)
252 {
253     const size_t xfbDeclMarkerStart = originalSource.find(kXfbDeclMarker);
254     const size_t xfbDeclMarkerEnd   = xfbDeclMarkerStart + ConstStrLen(kXfbDeclMarker);
255 
256     const size_t xfbOutMarkerStart = originalSource.find(kXfbOutMarker, xfbDeclMarkerStart);
257     const size_t xfbOutMarkerEnd   = xfbOutMarkerStart + ConstStrLen(kXfbOutMarker);
258 
259     // The shader is the following form:
260     //
261     // ..part1..
262     // @@ XFB-DECL @@
263     // ..part2..
264     // @@ XFB-OUT @@;
265     // ..part3..
266     //
267     // Construct the string by concatenating these five pieces, replacing the markers with the given
268     // values.
269     std::string result;
270 
271     result.append(&originalSource[0], &originalSource[xfbDeclMarkerStart]);
272     result.append(xfbDecl);
273     result.append(&originalSource[xfbDeclMarkerEnd], &originalSource[xfbOutMarkerStart]);
274     result.append(xfbOut);
275     result.append(&originalSource[xfbOutMarkerEnd], &originalSource[originalSource.size()]);
276 
277     return result;
278 }
279 
GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying & varying,const gl::UniformTypeInfo & info,size_t strideBytes,size_t offset,const std::string & bufferIndex)280 std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying,
281                                                    const gl::UniformTypeInfo &info,
282                                                    size_t strideBytes,
283                                                    size_t offset,
284                                                    const std::string &bufferIndex)
285 {
286     std::ostringstream result;
287 
288     ASSERT(strideBytes % 4 == 0);
289     size_t stride = strideBytes / 4;
290 
291     const size_t arrayIndexStart = varying.arrayIndex == GL_INVALID_INDEX ? 0 : varying.arrayIndex;
292     const size_t arrayIndexEnd   = arrayIndexStart + varying.size();
293 
294     for (size_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
295     {
296         for (int col = 0; col < info.columnCount; ++col)
297         {
298             for (int row = 0; row < info.rowCount; ++row)
299             {
300                 result << "xfbOut" << bufferIndex << "[" << sh::vk::kDriverUniformsVarName
301                        << ".xfbBufferOffsets[" << bufferIndex
302                        << "] + (gl_VertexIndex + gl_InstanceIndex * "
303                        << sh::vk::kDriverUniformsVarName << ".xfbVerticesPerDraw) * " << stride
304                        << " + " << offset << "] = " << info.glslAsFloat << "("
305                        << varying.mappedName;
306 
307                 if (varying.isArray())
308                 {
309                     result << "[" << arrayIndex << "]";
310                 }
311 
312                 if (info.columnCount > 1)
313                 {
314                     result << "[" << col << "]";
315                 }
316 
317                 if (info.rowCount > 1)
318                 {
319                     result << "[" << row << "]";
320                 }
321 
322                 result << ");\n";
323                 ++offset;
324             }
325         }
326     }
327 
328     return result.str();
329 }
330 
GenerateTransformFeedbackEmulationOutputs(GlslangSourceOptions & options,const gl::ProgramState & programState,GlslangProgramInterfaceInfo * programInterfaceInfo,std::string * vertexShader,ShaderInterfaceVariableInfoMap * variableInfoMapOut)331 void GenerateTransformFeedbackEmulationOutputs(GlslangSourceOptions &options,
332                                                const gl::ProgramState &programState,
333                                                GlslangProgramInterfaceInfo *programInterfaceInfo,
334                                                std::string *vertexShader,
335                                                ShaderInterfaceVariableInfoMap *variableInfoMapOut)
336 {
337     const std::vector<gl::TransformFeedbackVarying> &varyings =
338         programState.getLinkedTransformFeedbackVaryings();
339     const std::vector<GLsizei> &bufferStrides = programState.getTransformFeedbackStrides();
340     const bool isInterleaved =
341         programState.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
342     const size_t bufferCount = isInterleaved ? 1 : varyings.size();
343 
344     const std::string xfbSet = Str(programInterfaceInfo->uniformsAndXfbDescriptorSetIndex);
345     std::vector<std::string> xfbIndices(bufferCount);
346 
347     std::string xfbDecl;
348 
349     for (uint32_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
350     {
351         const std::string xfbBinding = Str(programInterfaceInfo->currentUniformBindingIndex);
352         xfbIndices[bufferIndex]      = Str(bufferIndex);
353 
354         std::string bufferName = GetXfbBufferName(bufferIndex);
355 
356         xfbDecl += "layout(set = " + xfbSet + ", binding = " + xfbBinding + ") buffer " +
357                    bufferName + " { float xfbOut" + Str(bufferIndex) + "[]; };\n";
358 
359         // Add this entry to the info map, so we can easily assert that every resource has an entry
360         // in this map.
361         AddResourceInfo(variableInfoMapOut, bufferName,
362                         programInterfaceInfo->uniformsAndXfbDescriptorSetIndex,
363                         programInterfaceInfo->currentUniformBindingIndex, gl::ShaderType::Vertex);
364         ++programInterfaceInfo->currentUniformBindingIndex;
365     }
366 
367     std::string xfbOut =
368         "if (" + std::string(sh::vk::kDriverUniformsVarName) + ".xfbActiveUnpaused != 0)\n{\n";
369     size_t outputOffset = 0;
370     for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex)
371     {
372         const size_t bufferIndex                    = isInterleaved ? 0 : varyingIndex;
373         const gl::TransformFeedbackVarying &varying = varyings[varyingIndex];
374 
375         // For every varying, output to the respective buffer packed.  If interleaved, the output is
376         // always to the same buffer, but at different offsets.
377         const gl::UniformTypeInfo &info = gl::GetUniformTypeInfo(varying.type);
378         xfbOut += GenerateTransformFeedbackVaryingOutput(varying, info, bufferStrides[bufferIndex],
379                                                          outputOffset, xfbIndices[bufferIndex]);
380 
381         if (isInterleaved)
382         {
383             outputOffset += info.columnCount * info.rowCount * varying.size();
384         }
385     }
386     xfbOut += "}\n";
387 
388     *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut);
389 }
390 
IsFirstRegisterOfVarying(const gl::PackedVaryingRegister & varyingReg)391 bool IsFirstRegisterOfVarying(const gl::PackedVaryingRegister &varyingReg)
392 {
393     const gl::PackedVarying &varying = *varyingReg.packedVarying;
394 
395     // In Vulkan GLSL, struct fields are not allowed to have location assignments.  The varying of a
396     // struct type is thus given a location equal to the one assigned to its first field.
397     if (varying.isStructField() && varying.fieldIndex > 0)
398     {
399         return false;
400     }
401 
402     // Similarly, assign array varying locations to the assigned location of the first element.
403     if (varyingReg.varyingArrayIndex != 0 || (varying.isArrayElement() && varying.arrayIndex != 0))
404     {
405         return false;
406     }
407 
408     // Similarly, assign matrix varying locations to the assigned location of the first row.
409     if (varyingReg.varyingRowIndex != 0)
410     {
411         return false;
412     }
413 
414     return true;
415 }
416 
417 // Calculates XFB layout qualifier arguments for each tranform feedback varying.  Stores calculated
418 // values for the SPIR-V transformation.
GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState & programState,const gl::ProgramLinkedResources & resources,std::string * vertexShader,uint32_t * locationsUsedForXfbExtensionOut)419 void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState,
420                                                const gl::ProgramLinkedResources &resources,
421                                                std::string *vertexShader,
422                                                uint32_t *locationsUsedForXfbExtensionOut)
423 {
424     const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
425         programState.getLinkedTransformFeedbackVaryings();
426 
427     std::string xfbDecl;
428     std::string xfbOut;
429 
430     for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
431     {
432         const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
433         const std::string &tfVaryingName              = tfVarying.mappedName;
434 
435         if (tfVarying.isBuiltIn())
436         {
437             // For simplicity, create a copy of every builtin that's captured so xfb qualifiers
438             // could be added to that instead.  This allows the SPIR-V transformation to ignore
439             // OpMemberName and OpMemberDecorate instructions.  Note that capturing gl_Position
440             // already requires such a copy, since the translator modifies this value at the end of
441             // main.  Capturing the rest of the built-ins are niche enough that the inefficiency
442             // involved in doing this is not a concern.
443 
444             uint32_t xfbVaryingLocation = resources.varyingPacking.getMaxSemanticIndex() +
445                                           ++(*locationsUsedForXfbExtensionOut);
446 
447             std::string xfbVaryingName = kXfbBuiltInPrefix + tfVaryingName;
448 
449             // Add declaration and initialization code for the new varying.
450             std::string varyingType = gl::GetGLSLTypeString(tfVarying.type);
451             xfbDecl += "layout(location = " + Str(xfbVaryingLocation) + ") out " + varyingType +
452                        " " + xfbVaryingName + ";\n";
453             xfbOut += xfbVaryingName + " = " + tfVaryingName + ";\n";
454         }
455     }
456 
457     *vertexShader = SubstituteTransformFeedbackMarkers(*vertexShader, xfbDecl, xfbOut);
458 }
459 
AssignAttributeLocations(const gl::ProgramExecutable & programExecutable,gl::ShaderType stage,ShaderInterfaceVariableInfoMap * variableInfoMapOut)460 void AssignAttributeLocations(const gl::ProgramExecutable &programExecutable,
461                               gl::ShaderType stage,
462                               ShaderInterfaceVariableInfoMap *variableInfoMapOut)
463 {
464     // Assign attribute locations for the vertex shader.
465     for (const sh::ShaderVariable &attribute : programExecutable.getProgramInputs())
466     {
467         ASSERT(attribute.active);
468 
469         AddLocationInfo(variableInfoMapOut, attribute.mappedName, attribute.location,
470                         ShaderInterfaceVariableInfo::kInvalid, stage);
471     }
472 }
473 
AssignOutputLocations(const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,ShaderInterfaceVariableInfoMap * variableInfoMapOut)474 void AssignOutputLocations(const gl::ProgramExecutable &programExecutable,
475                            const gl::ShaderType shaderType,
476                            ShaderInterfaceVariableInfoMap *variableInfoMapOut)
477 {
478     // Assign output locations for the fragment shader.
479     ASSERT(shaderType == gl::ShaderType::Fragment);
480     // TODO(syoussefi): Add support for EXT_blend_func_extended.  http://anglebug.com/3385
481     const auto &outputLocations                      = programExecutable.getOutputLocations();
482     const auto &outputVariables                      = programExecutable.getOutputVariables();
483     const std::array<std::string, 3> implicitOutputs = {"gl_FragDepth", "gl_SampleMask",
484                                                         "gl_FragStencilRefARB"};
485 
486     for (const gl::VariableLocation &outputLocation : outputLocations)
487     {
488         if (outputLocation.arrayIndex == 0 && outputLocation.used() && !outputLocation.ignored)
489         {
490             const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index];
491 
492             uint32_t location = 0;
493             if (outputVar.location != -1)
494             {
495                 location = outputVar.location;
496             }
497             else if (std::find(implicitOutputs.begin(), implicitOutputs.end(), outputVar.name) ==
498                      implicitOutputs.end())
499             {
500                 // If there is only one output, it is allowed not to have a location qualifier, in
501                 // which case it defaults to 0.  GLSL ES 3.00 spec, section 4.3.8.2.
502                 ASSERT(CountExplicitOutputs(outputVariables.begin(), outputVariables.end(),
503                                             implicitOutputs.begin(), implicitOutputs.end()) == 1);
504             }
505 
506             AddLocationInfo(variableInfoMapOut, outputVar.mappedName, location,
507                             ShaderInterfaceVariableInfo::kInvalid, shaderType);
508         }
509     }
510 
511     // When no fragment output is specified by the shader, the translator outputs webgl_FragColor or
512     // webgl_FragData.  Add an entry for these.  Even though the translator is already assigning
513     // location 0 to these entries, adding an entry for them here allows us to ASSERT that every
514     // shader interface variable is processed during the SPIR-V transformation.  This is done when
515     // iterating the ids provided by OpEntryPoint.
516     AddLocationInfo(variableInfoMapOut, "webgl_FragColor", 0, 0, shaderType);
517     AddLocationInfo(variableInfoMapOut, "webgl_FragData", 0, 0, shaderType);
518 }
519 
AssignVaryingLocations(const GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)520 void AssignVaryingLocations(const GlslangSourceOptions &options,
521                             const gl::ProgramExecutable &programExecutable,
522                             const gl::ShaderType shaderType,
523                             GlslangProgramInterfaceInfo *programInterfaceInfo,
524                             ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
525 {
526     uint32_t locationsUsedForEmulation = programInterfaceInfo->locationsUsedForXfbExtension;
527 
528     // Substitute layout and qualifier strings for the position varying added for line raster
529     // emulation.
530     if (options.emulateBresenhamLines)
531     {
532         uint32_t lineRasterEmulationPositionLocation = locationsUsedForEmulation++;
533 
534         AddLocationInfo(&(*variableInfoMapOut)[shaderType], sh::vk::kLineRasterEmulationPosition,
535                         lineRasterEmulationPositionLocation, ShaderInterfaceVariableInfo::kInvalid,
536                         shaderType);
537     }
538 
539     // Assign varying locations.
540     for (const gl::PackedVaryingRegister &varyingReg :
541          programExecutable.getResources().varyingPacking.getRegisterList())
542     {
543         if (!IsFirstRegisterOfVarying(varyingReg))
544         {
545             continue;
546         }
547 
548         const gl::PackedVarying &varying = *varyingReg.packedVarying;
549 
550         uint32_t location  = varyingReg.registerRow + locationsUsedForEmulation;
551         uint32_t component = ShaderInterfaceVariableInfo::kInvalid;
552         if (varyingReg.registerColumn > 0)
553         {
554             ASSERT(!varying.varying().isStruct());
555             ASSERT(!gl::IsMatrixType(varying.varying().type));
556             component = varyingReg.registerColumn;
557         }
558 
559         // In the following:
560         //
561         //     struct S { vec4 field; };
562         //     out S varStruct;
563         //
564         // "_uvarStruct" is found through |parentStructMappedName|, with |varying->mappedName|
565         // being "_ufield".  In such a case, use |parentStructMappedName|.
566         if (varying.frontVarying.varying && (varying.frontVarying.stage == shaderType))
567         {
568             const std::string &name = varying.isStructField()
569                                           ? varying.frontVarying.parentStructMappedName
570                                           : varying.frontVarying.varying->mappedName;
571             AddLocationInfo(&(*variableInfoMapOut)[varying.frontVarying.stage], name, location,
572                             component, varying.frontVarying.stage);
573         }
574         if (varying.backVarying.varying && (varying.backVarying.stage == shaderType))
575         {
576             const std::string &name = varying.isStructField()
577                                           ? varying.backVarying.parentStructMappedName
578                                           : varying.backVarying.varying->mappedName;
579             AddLocationInfo(&(*variableInfoMapOut)[varying.backVarying.stage], name, location,
580                             component, varying.backVarying.stage);
581         }
582     }
583 
584     // Add an entry for inactive varyings.
585     const gl::ShaderMap<std::vector<std::string>> &inactiveVaryingMappedNames =
586         programExecutable.getResources().varyingPacking.getInactiveVaryingMappedNames();
587     for (const std::string &varyingName : inactiveVaryingMappedNames[shaderType])
588     {
589         bool isBuiltin = angle::BeginsWith(varyingName, "gl_");
590         if (isBuiltin)
591         {
592             continue;
593         }
594 
595         // If name is already in the map, it will automatically have marked all other stages
596         // inactive.
597         if ((*variableInfoMapOut)[shaderType].find(varyingName) !=
598             (*variableInfoMapOut)[shaderType].end())
599         {
600             continue;
601         }
602 
603         // Otherwise, add an entry for it with all locations inactive.
604         ShaderInterfaceVariableInfo *info = &(*variableInfoMapOut)[shaderType][varyingName];
605         ASSERT(info->location == ShaderInterfaceVariableInfo::kInvalid);
606     }
607 }
608 
609 // Calculates XFB layout qualifier arguments for each tranform feedback varying.  Stores calculated
610 // values for the SPIR-V transformation.
AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable & programExecutable,uint32_t locationsUsedForXfbExtension,const gl::ShaderType shaderType,ShaderInterfaceVariableInfoMap * variableInfoMapOut)611 void AssignTransformFeedbackExtensionQualifiers(const gl::ProgramExecutable &programExecutable,
612                                                 uint32_t locationsUsedForXfbExtension,
613                                                 const gl::ShaderType shaderType,
614                                                 ShaderInterfaceVariableInfoMap *variableInfoMapOut)
615 {
616     const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
617         programExecutable.getLinkedTransformFeedbackVaryings();
618     const std::vector<GLsizei> &varyingStrides = programExecutable.getTransformFeedbackStrides();
619     const bool isInterleaved =
620         programExecutable.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
621 
622     std::string xfbDecl;
623     std::string xfbOut;
624     uint32_t currentOffset          = 0;
625     uint32_t currentStride          = 0;
626     uint32_t bufferIndex            = 0;
627     uint32_t currentBuiltinLocation = 0;
628 
629     for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
630     {
631         if (isInterleaved)
632         {
633             bufferIndex = 0;
634             if (varyingIndex > 0)
635             {
636                 const gl::TransformFeedbackVarying &prev = tfVaryings[varyingIndex - 1];
637                 currentOffset += prev.size() * gl::VariableExternalSize(prev.type);
638             }
639             currentStride = varyingStrides[0];
640         }
641         else
642         {
643             bufferIndex   = varyingIndex;
644             currentOffset = 0;
645             currentStride = varyingStrides[varyingIndex];
646         }
647 
648         const gl::TransformFeedbackVarying &tfVarying = tfVaryings[varyingIndex];
649         const std::string &tfVaryingName              = tfVarying.mappedName;
650 
651         if (tfVarying.isBuiltIn())
652         {
653             uint32_t xfbVaryingLocation = currentBuiltinLocation++;
654             std::string xfbVaryingName  = kXfbBuiltInPrefix + tfVaryingName;
655 
656             ASSERT(xfbVaryingLocation < locationsUsedForXfbExtension);
657 
658             AddLocationInfo(variableInfoMapOut, xfbVaryingName, xfbVaryingLocation,
659                             ShaderInterfaceVariableInfo::kInvalid, shaderType);
660             SetXfbInfo(variableInfoMapOut, xfbVaryingName, bufferIndex, currentOffset,
661                        currentStride);
662         }
663         else if (!tfVarying.isArray() || tfVarying.arrayIndex == 0)
664         {
665             // Note: capturing individual array elements using the Vulkan transform feedback
666             // extension is not supported, and it unlikely to be ever supported (on the contrary, it
667             // may be removed from the GLES spec).  http://anglebug.com/4140
668 
669             // Find the varying with this name.  If a struct is captured, we would be iterating over
670             // its fields, and the name of the varying is found through parentStructMappedName.  Not
671             // only that, but also we should only do this for the first field of the struct.
672             const gl::PackedVarying *originalVarying = nullptr;
673             for (const gl::PackedVaryingRegister &varyingReg :
674                  programExecutable.getResources().varyingPacking.getRegisterList())
675             {
676                 if (!IsFirstRegisterOfVarying(varyingReg))
677                 {
678                     continue;
679                 }
680 
681                 const gl::PackedVarying *varying = varyingReg.packedVarying;
682 
683                 if (varying->frontVarying.varying->name == tfVarying.name)
684                 {
685                     originalVarying = varying;
686                     break;
687                 }
688             }
689 
690             if (originalVarying)
691             {
692                 const std::string &mappedName =
693                     originalVarying->isStructField()
694                         ? originalVarying->frontVarying.parentStructMappedName
695                         : originalVarying->frontVarying.varying->mappedName;
696 
697                 // Set xfb info for this varying.  AssignVaryingLocations should have already added
698                 // location information for these varyings.
699                 SetXfbInfo(variableInfoMapOut, mappedName, bufferIndex, currentOffset,
700                            currentStride);
701             }
702         }
703     }
704 }
705 
AssignUniformBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)706 void AssignUniformBindings(GlslangSourceOptions &options,
707                            const gl::ProgramExecutable &programExecutable,
708                            const gl::ShaderType shaderType,
709                            GlslangProgramInterfaceInfo *programInterfaceInfo,
710                            ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
711 {
712     if (programExecutable.hasLinkedShaderStage(shaderType))
713     {
714         AddResourceInfo(&(*variableInfoMapOut)[shaderType], kDefaultUniformNames[shaderType],
715                         programInterfaceInfo->uniformsAndXfbDescriptorSetIndex,
716                         programInterfaceInfo->currentUniformBindingIndex, shaderType);
717         ++programInterfaceInfo->currentUniformBindingIndex;
718 
719         // Assign binding to the driver uniforms block
720         AddResourceInfoToAllStages(&(*variableInfoMapOut)[shaderType],
721                                    sh::vk::kDriverUniformsBlockName,
722                                    programInterfaceInfo->driverUniformsDescriptorSetIndex, 0);
723     }
724 }
725 
726 // TODO: http://anglebug.com/4512: Need to combine descriptor set bindings across
727 // shader stages.
AssignInterfaceBlockBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const std::vector<gl::InterfaceBlock> & blocks,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)728 void AssignInterfaceBlockBindings(GlslangSourceOptions &options,
729                                   const gl::ProgramExecutable &programExecutable,
730                                   const std::vector<gl::InterfaceBlock> &blocks,
731                                   const gl::ShaderType shaderType,
732                                   GlslangProgramInterfaceInfo *programInterfaceInfo,
733                                   ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
734 {
735     for (const gl::InterfaceBlock &block : blocks)
736     {
737         if (!block.isArray || block.arrayElement == 0)
738         {
739             // TODO: http://anglebug.com/4523: All blocks should be active
740             if (programExecutable.hasLinkedShaderStage(shaderType) && block.isActive(shaderType))
741             {
742                 AddResourceInfo(&(*variableInfoMapOut)[shaderType], block.mappedName,
743                                 programInterfaceInfo->shaderResourceDescriptorSetIndex,
744                                 programInterfaceInfo->currentShaderResourceBindingIndex,
745                                 shaderType);
746                 ++programInterfaceInfo->currentShaderResourceBindingIndex;
747             }
748         }
749     }
750 }
751 
752 // TODO: http://anglebug.com/4512: Need to combine descriptor set bindings across
753 // shader stages.
AssignAtomicCounterBufferBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const std::vector<gl::AtomicCounterBuffer> & buffers,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)754 void AssignAtomicCounterBufferBindings(GlslangSourceOptions &options,
755                                        const gl::ProgramExecutable &programExecutable,
756                                        const std::vector<gl::AtomicCounterBuffer> &buffers,
757                                        const gl::ShaderType shaderType,
758                                        GlslangProgramInterfaceInfo *programInterfaceInfo,
759                                        ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
760 {
761     if (buffers.size() == 0)
762     {
763         return;
764     }
765 
766     if (programExecutable.hasLinkedShaderStage(shaderType))
767     {
768         AddResourceInfo(&(*variableInfoMapOut)[shaderType], sh::vk::kAtomicCountersBlockName,
769                         programInterfaceInfo->shaderResourceDescriptorSetIndex,
770                         programInterfaceInfo->currentShaderResourceBindingIndex, shaderType);
771         ++programInterfaceInfo->currentShaderResourceBindingIndex;
772     }
773 }
774 
775 // TODO: http://anglebug.com/4512: Need to combine descriptor set bindings across
776 // shader stages.
AssignImageBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const std::vector<gl::LinkedUniform> & uniforms,const gl::RangeUI & imageUniformRange,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)777 void AssignImageBindings(GlslangSourceOptions &options,
778                          const gl::ProgramExecutable &programExecutable,
779                          const std::vector<gl::LinkedUniform> &uniforms,
780                          const gl::RangeUI &imageUniformRange,
781                          const gl::ShaderType shaderType,
782                          GlslangProgramInterfaceInfo *programInterfaceInfo,
783                          ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
784 {
785     for (unsigned int uniformIndex : imageUniformRange)
786     {
787         const gl::LinkedUniform &imageUniform = uniforms[uniformIndex];
788 
789         std::string name = imageUniform.mappedName;
790         if (GetImageNameWithoutIndices(&name))
791         {
792             if (programExecutable.hasLinkedShaderStage(shaderType))
793             {
794                 AddResourceInfo(&(*variableInfoMapOut)[shaderType], name,
795                                 programInterfaceInfo->shaderResourceDescriptorSetIndex,
796                                 programInterfaceInfo->currentShaderResourceBindingIndex,
797                                 shaderType);
798                 ++programInterfaceInfo->currentShaderResourceBindingIndex;
799             }
800         }
801     }
802 }
803 
AssignNonTextureBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)804 void AssignNonTextureBindings(GlslangSourceOptions &options,
805                               const gl::ProgramExecutable &programExecutable,
806                               const gl::ShaderType shaderType,
807                               GlslangProgramInterfaceInfo *programInterfaceInfo,
808                               ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
809 {
810     const std::vector<gl::InterfaceBlock> &uniformBlocks = programExecutable.getUniformBlocks();
811     AssignInterfaceBlockBindings(options, programExecutable, uniformBlocks, shaderType,
812                                  programInterfaceInfo, variableInfoMapOut);
813 
814     const std::vector<gl::InterfaceBlock> &storageBlocks =
815         programExecutable.getShaderStorageBlocks();
816     AssignInterfaceBlockBindings(options, programExecutable, storageBlocks, shaderType,
817                                  programInterfaceInfo, variableInfoMapOut);
818 
819     const std::vector<gl::AtomicCounterBuffer> &atomicCounterBuffers =
820         programExecutable.getAtomicCounterBuffers();
821     AssignAtomicCounterBufferBindings(options, programExecutable, atomicCounterBuffers, shaderType,
822                                       programInterfaceInfo, variableInfoMapOut);
823 
824     const std::vector<gl::LinkedUniform> &uniforms = programExecutable.getUniforms();
825     const gl::RangeUI &imageUniformRange           = programExecutable.getImageUniformRange();
826     AssignImageBindings(options, programExecutable, uniforms, imageUniformRange, shaderType,
827                         programInterfaceInfo, variableInfoMapOut);
828 }
829 
830 // TODO: http://anglebug.com/4512: Need to combine descriptor set bindings across
831 // shader stages.
AssignTextureBindings(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)832 void AssignTextureBindings(GlslangSourceOptions &options,
833                            const gl::ProgramExecutable &programExecutable,
834                            const gl::ShaderType shaderType,
835                            GlslangProgramInterfaceInfo *programInterfaceInfo,
836                            ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
837 {
838     // Assign textures to a descriptor set and binding.
839     const std::vector<gl::LinkedUniform> &uniforms = programExecutable.getUniforms();
840 
841     for (unsigned int uniformIndex : programExecutable.getSamplerUniformRange())
842     {
843         const gl::LinkedUniform &samplerUniform = uniforms[uniformIndex];
844 
845         if (!options.useOldRewriteStructSamplers &&
846             gl::SamplerNameContainsNonZeroArrayElement(samplerUniform.name))
847         {
848             continue;
849         }
850 
851         if (UniformNameIsIndexZero(samplerUniform.name, options.useOldRewriteStructSamplers))
852         {
853             // Samplers in structs are extracted and renamed.
854             const std::string samplerName = options.useOldRewriteStructSamplers
855                                                 ? GetMappedSamplerNameOld(samplerUniform.name)
856                                                 : GlslangGetMappedSamplerName(samplerUniform.name);
857 
858             // TODO: http://anglebug.com/4523: All uniforms should be active
859             if (programExecutable.hasLinkedShaderStage(shaderType) &&
860                 samplerUniform.isActive(shaderType))
861             {
862                 AddResourceInfo(&(*variableInfoMapOut)[shaderType], samplerName,
863                                 programInterfaceInfo->textureDescriptorSetIndex,
864                                 programInterfaceInfo->currentTextureBindingIndex, shaderType);
865                 ++programInterfaceInfo->currentTextureBindingIndex;
866             }
867         }
868     }
869 }
870 
871 constexpr gl::ShaderMap<EShLanguage> kShLanguageMap = {
872     {gl::ShaderType::Vertex, EShLangVertex},
873     {gl::ShaderType::Geometry, EShLangGeometry},
874     {gl::ShaderType::Fragment, EShLangFragment},
875     {gl::ShaderType::Compute, EShLangCompute},
876 };
877 
GetShaderSpirvCode(GlslangErrorCallback callback,const gl::Caps & glCaps,const gl::ShaderMap<std::string> & shaderSources,gl::ShaderMap<std::vector<uint32_t>> * spirvBlobsOut)878 angle::Result GetShaderSpirvCode(GlslangErrorCallback callback,
879                                  const gl::Caps &glCaps,
880                                  const gl::ShaderMap<std::string> &shaderSources,
881                                  gl::ShaderMap<std::vector<uint32_t>> *spirvBlobsOut)
882 {
883     // Enable SPIR-V and Vulkan rules when parsing GLSL
884     EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
885 
886     TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
887     GetBuiltInResourcesFromCaps(glCaps, &builtInResources);
888 
889     glslang::TShader vertexShader(EShLangVertex);
890     glslang::TShader fragmentShader(EShLangFragment);
891     glslang::TShader geometryShader(EShLangGeometry);
892     glslang::TShader computeShader(EShLangCompute);
893 
894     gl::ShaderMap<glslang::TShader *> shaders = {
895         {gl::ShaderType::Vertex, &vertexShader},
896         {gl::ShaderType::Fragment, &fragmentShader},
897         {gl::ShaderType::Geometry, &geometryShader},
898         {gl::ShaderType::Compute, &computeShader},
899     };
900     glslang::TProgram program;
901 
902     for (const gl::ShaderType shaderType : gl::AllShaderTypes())
903     {
904         if (shaderSources[shaderType].empty())
905         {
906             continue;
907         }
908 
909         const char *shaderString = shaderSources[shaderType].c_str();
910         int shaderLength         = static_cast<int>(shaderSources[shaderType].size());
911 
912         glslang::TShader *shader = shaders[shaderType];
913         shader->setStringsWithLengths(&shaderString, &shaderLength, 1);
914         shader->setEntryPoint("main");
915 
916         bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages);
917         if (!result)
918         {
919             ERR() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
920                   << shader->getInfoLog() << "\n"
921                   << shader->getInfoDebugLog() << "\n";
922             ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
923         }
924 
925         program.addShader(shader);
926     }
927 
928     bool linkResult = program.link(messages);
929     if (!linkResult)
930     {
931         ERR() << "Internal error linking Vulkan shaders:\n" << program.getInfoLog() << "\n";
932         ANGLE_GLSLANG_CHECK(callback, false, GlslangError::InvalidShader);
933     }
934 
935     for (const gl::ShaderType shaderType : gl::AllShaderTypes())
936     {
937         if (shaderSources[shaderType].empty())
938         {
939             continue;
940         }
941 
942         glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
943         glslang::GlslangToSpv(*intermediate, (*spirvBlobsOut)[shaderType]);
944     }
945 
946     return angle::Result::Continue;
947 }
948 
ValidateSpirvMessage(spv_message_level_t level,const char * source,const spv_position_t & position,const char * message)949 void ValidateSpirvMessage(spv_message_level_t level,
950                           const char *source,
951                           const spv_position_t &position,
952                           const char *message)
953 {
954     WARN() << "Level" << level << ": " << message;
955 }
956 
ValidateSpirv(const std::vector<uint32_t> & spirvBlob)957 bool ValidateSpirv(const std::vector<uint32_t> &spirvBlob)
958 {
959     spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
960 
961     spirvTools.SetMessageConsumer(ValidateSpirvMessage);
962     bool result = spirvTools.Validate(spirvBlob);
963 
964     if (!result)
965     {
966         std::string readableSpirv;
967         spirvTools.Disassemble(spirvBlob, &readableSpirv, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
968         WARN() << "Invalid SPIR-V:\n" << readableSpirv;
969     }
970 
971     return result;
972 }
973 
974 // A SPIR-V transformer.  It walks the instructions and modifies them as necessary, for example to
975 // assign bindings or locations.
976 class SpirvTransformer final : angle::NonCopyable
977 {
978   public:
SpirvTransformer(const std::vector<uint32_t> & spirvBlobIn,bool removeEarlyFragmentTestsOptimization,const ShaderInterfaceVariableInfoMap & variableInfoMap,gl::ShaderType shaderType,SpirvBlob * spirvBlobOut)979     SpirvTransformer(const std::vector<uint32_t> &spirvBlobIn,
980                      bool removeEarlyFragmentTestsOptimization,
981                      const ShaderInterfaceVariableInfoMap &variableInfoMap,
982                      gl::ShaderType shaderType,
983                      SpirvBlob *spirvBlobOut)
984         : mSpirvBlobIn(spirvBlobIn),
985           mShaderType(shaderType),
986           mHasTransformFeedbackOutput(false),
987           mVariableInfoMap(variableInfoMap),
988           mSpirvBlobOut(spirvBlobOut)
989     {
990         gl::ShaderBitSet allStages;
991         allStages.set();
992         mRemoveEarlyFragmentTestsOptimization = removeEarlyFragmentTestsOptimization;
993         mBuiltinVariableInfo.activeStages     = allStages;
994     }
995 
996     bool transform();
997 
998   private:
999     // SPIR-V 1.0 Table 1: First Words of Physical Layout
1000     enum HeaderIndex
1001     {
1002         kHeaderIndexMagic        = 0,
1003         kHeaderIndexVersion      = 1,
1004         kHeaderIndexGenerator    = 2,
1005         kHeaderIndexIndexBound   = 3,
1006         kHeaderIndexSchema       = 4,
1007         kHeaderIndexInstructions = 5,
1008     };
1009 
1010     // A prepass to resolve interesting ids:
1011     void resolveVariableIds();
1012 
1013     // Transform instructions:
1014     void transformInstruction();
1015 
1016     // Instructions that are purely informational:
1017     void visitName(const uint32_t *instruction);
1018     void visitTypeHelper(const uint32_t *instruction, size_t idIndex, size_t typeIdIndex);
1019     void visitTypeArray(const uint32_t *instruction);
1020     void visitTypePointer(const uint32_t *instruction);
1021     void visitVariable(const uint32_t *instruction);
1022 
1023     // Instructions that potentially need transformation.  They return true if the instruction is
1024     // transformed.  If false is returned, the instruction should be copied as-is.
1025     bool transformAccessChain(const uint32_t *instruction, size_t wordCount);
1026     bool transformCapability(const uint32_t *instruction, size_t wordCount);
1027     bool transformEntryPoint(const uint32_t *instruction, size_t wordCount);
1028     bool transformDecorate(const uint32_t *instruction, size_t wordCount);
1029     bool transformTypePointer(const uint32_t *instruction, size_t wordCount);
1030     bool transformVariable(const uint32_t *instruction, size_t wordCount);
1031     bool transformExecutionMode(const uint32_t *instruction, size_t wordCount);
1032 
1033     // Any other instructions:
1034     size_t copyInstruction(const uint32_t *instruction, size_t wordCount);
1035     uint32_t getNewId();
1036 
1037     // SPIR-V to transform:
1038     const std::vector<uint32_t> &mSpirvBlobIn;
1039     const gl::ShaderType mShaderType;
1040     bool mHasTransformFeedbackOutput;
1041 
1042     bool mRemoveEarlyFragmentTestsOptimization;
1043 
1044     // Input shader variable info map:
1045     const ShaderInterfaceVariableInfoMap &mVariableInfoMap;
1046     ShaderInterfaceVariableInfo mBuiltinVariableInfo;
1047 
1048     // Transformed SPIR-V:
1049     SpirvBlob *mSpirvBlobOut;
1050 
1051     // Traversal state:
1052     size_t mCurrentWord       = 0;
1053     bool mIsInFunctionSection = false;
1054 
1055     // Transformation state:
1056 
1057     // Names associated with ids through OpName.  The same name may be assigned to multiple ids, but
1058     // not all names are interesting (for example function arguments).  When the variable
1059     // declaration is met (OpVariable), the variable info is matched with the corresponding id's
1060     // name based on the Storage Class.
1061     std::vector<const char *> mNamesById;
1062 
1063     // Shader variable info per id, if id is a shader variable.
1064     std::vector<const ShaderInterfaceVariableInfo *> mVariableInfoById;
1065 
1066     // Each OpTypePointer instruction that defines a type with the Output storage class is
1067     // duplicated with a similar instruction but which defines a type with the Private storage
1068     // class.  If inactive varyings are encountered, its type is changed to the Private one.  The
1069     // following vector maps the Output type id to the corresponding Private one.
1070     std::vector<uint32_t> mTypePointerTransformedId;
1071 };
1072 
transform()1073 bool SpirvTransformer::transform()
1074 {
1075     // Glslang succeeded in outputting SPIR-V, so we assume it's valid.
1076     ASSERT(mSpirvBlobIn.size() >= kHeaderIndexInstructions);
1077     // Since SPIR-V comes from a local call to glslang, it necessarily has the same endianness as
1078     // the running architecture, so no byte-swapping is necessary.
1079     ASSERT(mSpirvBlobIn[kHeaderIndexMagic] == spv::MagicNumber);
1080 
1081     // Make sure the transformer is not reused to avoid having to reinitialize it here.
1082     ASSERT(mCurrentWord == 0);
1083     ASSERT(mIsInFunctionSection == false);
1084 
1085     // Make sure the SpirvBlob is not reused.
1086     ASSERT(mSpirvBlobOut->empty());
1087 
1088     // First, find all necessary ids and associate them with the information required to transform
1089     // their decorations.
1090     resolveVariableIds();
1091 
1092     // Copy the header to SpirvBlob
1093     mSpirvBlobOut->assign(mSpirvBlobIn.begin(), mSpirvBlobIn.begin() + kHeaderIndexInstructions);
1094 
1095     mCurrentWord = kHeaderIndexInstructions;
1096     while (mCurrentWord < mSpirvBlobIn.size())
1097     {
1098         transformInstruction();
1099     }
1100 
1101     return true;
1102 }
1103 
1104 // SPIR-V 1.0 Table 2: Instruction Physical Layout
GetSpirvInstructionLength(const uint32_t * instruction)1105 uint32_t GetSpirvInstructionLength(const uint32_t *instruction)
1106 {
1107     return instruction[0] >> 16;
1108 }
1109 
GetSpirvInstructionOp(const uint32_t * instruction)1110 uint32_t GetSpirvInstructionOp(const uint32_t *instruction)
1111 {
1112     constexpr uint32_t kOpMask = 0xFFFFu;
1113     return instruction[0] & kOpMask;
1114 }
1115 
SetSpirvInstructionLength(uint32_t * instruction,size_t length)1116 void SetSpirvInstructionLength(uint32_t *instruction, size_t length)
1117 {
1118     ASSERT(length < 0xFFFFu);
1119 
1120     constexpr uint32_t kLengthMask = 0xFFFF0000u;
1121     instruction[0] &= ~kLengthMask;
1122     instruction[0] |= length << 16;
1123 }
1124 
SetSpirvInstructionOp(uint32_t * instruction,uint32_t op)1125 void SetSpirvInstructionOp(uint32_t *instruction, uint32_t op)
1126 {
1127     constexpr uint32_t kOpMask = 0xFFFFu;
1128     instruction[0] &= ~kOpMask;
1129     instruction[0] |= op;
1130 }
1131 
resolveVariableIds()1132 void SpirvTransformer::resolveVariableIds()
1133 {
1134     size_t indexBound = mSpirvBlobIn[kHeaderIndexIndexBound];
1135 
1136     // Allocate storage for id-to-name map.  Used to associate ShaderInterfaceVariableInfo with ids
1137     // based on name, but only when it's determined that the name corresponds to a shader interface
1138     // variable.
1139     mNamesById.resize(indexBound + 1, nullptr);
1140 
1141     // Allocate storage for id-to-info map.  If %i is the id of a name in mVariableInfoMap, index i
1142     // in this vector will hold a pointer to the ShaderInterfaceVariableInfo object associated with
1143     // that name in mVariableInfoMap.
1144     mVariableInfoById.resize(indexBound + 1, nullptr);
1145 
1146     // Allocate storage for Output type pointer map.  At index i, this vector holds the identical
1147     // type as %i except for its storage class turned to Private.
1148     mTypePointerTransformedId.resize(indexBound + 1, 0);
1149 
1150     size_t currentWord = kHeaderIndexInstructions;
1151 
1152     while (currentWord < mSpirvBlobIn.size())
1153     {
1154         const uint32_t *instruction = &mSpirvBlobIn[currentWord];
1155 
1156         const uint32_t wordCount = GetSpirvInstructionLength(instruction);
1157         const uint32_t opCode    = GetSpirvInstructionOp(instruction);
1158 
1159         switch (opCode)
1160         {
1161             case spv::OpName:
1162                 visitName(instruction);
1163                 break;
1164             case spv::OpTypeArray:
1165                 visitTypeArray(instruction);
1166                 break;
1167             case spv::OpTypePointer:
1168                 visitTypePointer(instruction);
1169                 break;
1170             case spv::OpVariable:
1171                 visitVariable(instruction);
1172                 break;
1173             case spv::OpFunction:
1174                 // SPIR-V is structured in sections (SPIR-V 1.0 Section 2.4 Logical Layout of a
1175                 // Module). Names appear before decorations, which are followed by type+variables
1176                 // and finally functions.  We are only interested in name and variable declarations
1177                 // (as well as type declarations for the sake of nameless interface blocks).  Early
1178                 // out when the function declaration section is met.
1179                 return;
1180             default:
1181                 break;
1182         }
1183 
1184         currentWord += wordCount;
1185     }
1186 }
1187 
transformInstruction()1188 void SpirvTransformer::transformInstruction()
1189 {
1190     const uint32_t *instruction = &mSpirvBlobIn[mCurrentWord];
1191 
1192     const uint32_t wordCount = GetSpirvInstructionLength(instruction);
1193     const uint32_t opCode    = GetSpirvInstructionOp(instruction);
1194 
1195     // Since glslang succeeded in producing SPIR-V, we assume it to be valid.
1196     ASSERT(mCurrentWord + wordCount <= mSpirvBlobIn.size());
1197 
1198     if (opCode == spv::OpFunction)
1199     {
1200         // SPIR-V is structured in sections.  Function declarations come last.  Only Op*Access*
1201         // opcodes inside functions need to be inspected.
1202         mIsInFunctionSection = true;
1203     }
1204 
1205     // Only look at interesting instructions.
1206     bool transformed = false;
1207 
1208     if (mIsInFunctionSection)
1209     {
1210         // Look at in-function opcodes.
1211         switch (opCode)
1212         {
1213             case spv::OpAccessChain:
1214             case spv::OpInBoundsAccessChain:
1215             case spv::OpPtrAccessChain:
1216             case spv::OpInBoundsPtrAccessChain:
1217                 transformed = transformAccessChain(instruction, wordCount);
1218                 break;
1219             default:
1220                 break;
1221         }
1222     }
1223     else
1224     {
1225         // Look at global declaration opcodes.
1226         switch (opCode)
1227         {
1228             case spv::OpCapability:
1229                 transformed = transformCapability(instruction, wordCount);
1230                 break;
1231             case spv::OpEntryPoint:
1232                 transformed = transformEntryPoint(instruction, wordCount);
1233                 break;
1234             case spv::OpDecorate:
1235                 transformed = transformDecorate(instruction, wordCount);
1236                 break;
1237             case spv::OpTypePointer:
1238                 transformed = transformTypePointer(instruction, wordCount);
1239                 break;
1240             case spv::OpVariable:
1241                 transformed = transformVariable(instruction, wordCount);
1242                 break;
1243             case spv::OpExecutionMode:
1244                 transformed = transformExecutionMode(instruction, wordCount);
1245                 break;
1246             default:
1247                 break;
1248         }
1249     }
1250 
1251     // If the instruction was not transformed, copy it to output as is.
1252     if (!transformed)
1253     {
1254         copyInstruction(instruction, wordCount);
1255     }
1256 
1257     // Advance to next instruction.
1258     mCurrentWord += wordCount;
1259 }
1260 
visitName(const uint32_t * instruction)1261 void SpirvTransformer::visitName(const uint32_t *instruction)
1262 {
1263     // We currently don't have any big-endian devices in the list of supported platforms.  Literal
1264     // strings in SPIR-V are stored little-endian (SPIR-V 1.0 Section 2.2.1, Literal String), so if
1265     // a big-endian device is to be supported, the string matching here should be specialized.
1266     ASSERT(IsLittleEndian());
1267 
1268     // SPIR-V 1.0 Section 3.32 Instructions, OpName
1269     constexpr size_t kIdIndex   = 1;
1270     constexpr size_t kNameIndex = 2;
1271 
1272     const uint32_t id = instruction[kIdIndex];
1273     const char *name  = reinterpret_cast<const char *>(&instruction[kNameIndex]);
1274 
1275     // The names and ids are unique
1276     ASSERT(id < mNamesById.size());
1277     ASSERT(mNamesById[id] == nullptr);
1278 
1279     mNamesById[id] = name;
1280 }
1281 
visitTypeHelper(const uint32_t * instruction,const size_t idIndex,const size_t typeIdIndex)1282 void SpirvTransformer::visitTypeHelper(const uint32_t *instruction,
1283                                        const size_t idIndex,
1284                                        const size_t typeIdIndex)
1285 {
1286     const uint32_t id     = instruction[idIndex];
1287     const uint32_t typeId = instruction[typeIdIndex];
1288 
1289     // Every type id is declared only once.
1290     ASSERT(id < mNamesById.size());
1291     ASSERT(mNamesById[id] == nullptr);
1292 
1293     // Carry the name forward from the base type.  This is only necessary for interface blocks,
1294     // as the variable info is associated with the block name instead of the variable name (to
1295     // support nameless interface blocks).  When the variable declaration is met, either the
1296     // type name or the variable name is used to associate with info based on the variable's
1297     // storage class.
1298     ASSERT(typeId < mNamesById.size());
1299 
1300     mNamesById[id] = mNamesById[typeId];
1301 }
1302 
visitTypeArray(const uint32_t * instruction)1303 void SpirvTransformer::visitTypeArray(const uint32_t *instruction)
1304 {
1305     // SPIR-V 1.0 Section 3.32 Instructions, OpTypeArray
1306     constexpr size_t kIdIndex            = 1;
1307     constexpr size_t kElementTypeIdIndex = 2;
1308 
1309     visitTypeHelper(instruction, kIdIndex, kElementTypeIdIndex);
1310 }
1311 
visitTypePointer(const uint32_t * instruction)1312 void SpirvTransformer::visitTypePointer(const uint32_t *instruction)
1313 {
1314     // SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer
1315     constexpr size_t kIdIndex     = 1;
1316     constexpr size_t kTypeIdIndex = 3;
1317 
1318     visitTypeHelper(instruction, kIdIndex, kTypeIdIndex);
1319 }
1320 
visitVariable(const uint32_t * instruction)1321 void SpirvTransformer::visitVariable(const uint32_t *instruction)
1322 {
1323     // SPIR-V 1.0 Section 3.32 Instructions, OpVariable
1324     constexpr size_t kTypeIdIndex       = 1;
1325     constexpr size_t kIdIndex           = 2;
1326     constexpr size_t kStorageClassIndex = 3;
1327 
1328     // All resources that take set/binding should be transformed.
1329     const uint32_t typeId       = instruction[kTypeIdIndex];
1330     const uint32_t id           = instruction[kIdIndex];
1331     const uint32_t storageClass = instruction[kStorageClassIndex];
1332 
1333     ASSERT(typeId < mNamesById.size());
1334     ASSERT(id < mNamesById.size());
1335 
1336     // If storage class indicates that this is not a shader interface variable, ignore it.
1337     const bool isInterfaceBlockVariable =
1338         storageClass == spv::StorageClassUniform || storageClass == spv::StorageClassStorageBuffer;
1339     const bool isOpaqueUniform = storageClass == spv::StorageClassUniformConstant;
1340     const bool isInOut =
1341         storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput;
1342 
1343     if (!isInterfaceBlockVariable && !isOpaqueUniform && !isInOut)
1344     {
1345         return;
1346     }
1347 
1348     // The ids are unique.
1349     ASSERT(id < mVariableInfoById.size());
1350     ASSERT(mVariableInfoById[id] == nullptr);
1351 
1352     // For interface block variables, the name that's used to associate info is the block name
1353     // rather than the variable name.
1354     const char *name = mNamesById[isInterfaceBlockVariable ? typeId : id];
1355     ASSERT(name != nullptr);
1356 
1357     // Handle builtins, which all start with "gl_".  Either the variable name could be an indication
1358     // of a builtin variable (such as with gl_FragCoord) or the type name (such as with
1359     // gl_PerVertex).
1360     const bool isNameBuiltin = isInOut && angle::BeginsWith(name, "gl_");
1361     const bool isTypeBuiltin =
1362         isInOut && mNamesById[typeId] != nullptr && angle::BeginsWith(mNamesById[typeId], "gl_");
1363     if (isNameBuiltin || isTypeBuiltin)
1364     {
1365         // Make all builtins point to this no-op info.  Adding this entry allows us to ASSERT that
1366         // every shader interface variable is processed during the SPIR-V transformation.  This is
1367         // done when iterating the ids provided by OpEntryPoint.
1368         mVariableInfoById[id] = &mBuiltinVariableInfo;
1369         return;
1370     }
1371 
1372     // Every shader interface variable should have an associated data.
1373     auto infoIter = mVariableInfoMap.find(name);
1374     ASSERT(infoIter != mVariableInfoMap.end());
1375 
1376     const ShaderInterfaceVariableInfo *info = &infoIter->second;
1377 
1378     // Associate the id of this name with its info.
1379     mVariableInfoById[id] = info;
1380 
1381     // Note if the variable is captured by transform feedback.  In that case, the TransformFeedback
1382     // capability needs to be added.
1383     if (mShaderType != gl::ShaderType::Fragment &&
1384         info->xfbBuffer != ShaderInterfaceVariableInfo::kInvalid && info->activeStages[mShaderType])
1385     {
1386         mHasTransformFeedbackOutput = true;
1387     }
1388 }
1389 
transformDecorate(const uint32_t * instruction,size_t wordCount)1390 bool SpirvTransformer::transformDecorate(const uint32_t *instruction, size_t wordCount)
1391 {
1392     // SPIR-V 1.0 Section 3.32 Instructions, OpDecorate
1393     constexpr size_t kIdIndex              = 1;
1394     constexpr size_t kDecorationIndex      = 2;
1395     constexpr size_t kDecorationValueIndex = 3;
1396 
1397     uint32_t id         = instruction[kIdIndex];
1398     uint32_t decoration = instruction[kDecorationIndex];
1399 
1400     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
1401 
1402     // If variable is not a shader interface variable that needs modification, there's nothing to
1403     // do.
1404     if (info == nullptr)
1405     {
1406         return false;
1407     }
1408 
1409     // If it's an inactive varying, remove the decoration altogether.
1410     if (!info->activeStages[mShaderType])
1411     {
1412         return true;
1413     }
1414 
1415     uint32_t newDecorationValue = ShaderInterfaceVariableInfo::kInvalid;
1416 
1417     switch (decoration)
1418     {
1419         case spv::DecorationLocation:
1420             newDecorationValue = info->location;
1421             break;
1422         case spv::DecorationBinding:
1423             newDecorationValue = info->binding;
1424             break;
1425         case spv::DecorationDescriptorSet:
1426             newDecorationValue = info->descriptorSet;
1427             break;
1428         default:
1429             break;
1430     }
1431 
1432     // If the decoration is not something we care about modifying, there's nothing to do.
1433     if (newDecorationValue == ShaderInterfaceVariableInfo::kInvalid)
1434     {
1435         return false;
1436     }
1437 
1438     // Copy the decoration declaration and modify it.
1439     const size_t instructionOffset = copyInstruction(instruction, wordCount);
1440     (*mSpirvBlobOut)[instructionOffset + kDecorationValueIndex] = newDecorationValue;
1441 
1442     // If there are decorations to be added, add them right after the Location decoration is
1443     // encountered.
1444     if (decoration != spv::DecorationLocation)
1445     {
1446         return true;
1447     }
1448 
1449     // Add component decoration, if any.
1450     if (info->component != ShaderInterfaceVariableInfo::kInvalid)
1451     {
1452         // Copy the location decoration declaration and modify it to contain the Component
1453         // decoration.
1454         const size_t instOffset                         = copyInstruction(instruction, wordCount);
1455         (*mSpirvBlobOut)[instOffset + kDecorationIndex] = spv::DecorationComponent;
1456         (*mSpirvBlobOut)[instOffset + kDecorationValueIndex] = info->component;
1457     }
1458 
1459     // Add Xfb decorations, if any.
1460     if (mShaderType != gl::ShaderType::Fragment &&
1461         info->xfbBuffer != ShaderInterfaceVariableInfo::kInvalid)
1462     {
1463         ASSERT(info->xfbStride != ShaderInterfaceVariableInfo::kInvalid);
1464         ASSERT(info->xfbOffset != ShaderInterfaceVariableInfo::kInvalid);
1465 
1466         constexpr size_t kXfbDecorationCount                   = 3;
1467         constexpr uint32_t xfbDecorations[kXfbDecorationCount] = {
1468             spv::DecorationXfbBuffer,
1469             spv::DecorationXfbStride,
1470             spv::DecorationOffset,
1471         };
1472         const uint32_t xfbDecorationValues[kXfbDecorationCount] = {
1473             info->xfbBuffer,
1474             info->xfbStride,
1475             info->xfbOffset,
1476         };
1477 
1478         // Copy the location decoration declaration three times, and modify them to contain the
1479         // XfbBuffer, XfbStride and Offset decorations.
1480         for (size_t i = 0; i < kXfbDecorationCount; ++i)
1481         {
1482             const size_t xfbInstructionOffset = copyInstruction(instruction, wordCount);
1483             (*mSpirvBlobOut)[xfbInstructionOffset + kDecorationIndex]      = xfbDecorations[i];
1484             (*mSpirvBlobOut)[xfbInstructionOffset + kDecorationValueIndex] = xfbDecorationValues[i];
1485         }
1486     }
1487 
1488     return true;
1489 }
1490 
transformCapability(const uint32_t * instruction,size_t wordCount)1491 bool SpirvTransformer::transformCapability(const uint32_t *instruction, size_t wordCount)
1492 {
1493     if (!mHasTransformFeedbackOutput)
1494     {
1495         return false;
1496     }
1497 
1498     // SPIR-V 1.0 Section 3.32 Instructions, OpCapability
1499     constexpr size_t kCapabilityIndex = 1;
1500 
1501     uint32_t capability = instruction[kCapabilityIndex];
1502 
1503     // Transform feedback capability shouldn't have already been specified.
1504     ASSERT(capability != spv::CapabilityTransformFeedback);
1505 
1506     // Vulkan shaders have either Shader, Geometry or Tessellation capability.  We find this
1507     // capability, and add the TransformFeedback capability after it.
1508     if (capability != spv::CapabilityShader && capability != spv::CapabilityGeometry &&
1509         capability != spv::CapabilityTessellation)
1510     {
1511         return false;
1512     }
1513 
1514     // Copy the original capability declaration.
1515     copyInstruction(instruction, wordCount);
1516 
1517     // Create the TransformFeedback capability declaration.
1518 
1519     // SPIR-V 1.0 Section 3.32 Instructions, OpCapability
1520     constexpr size_t kCapabilityInstructionLength = 2;
1521 
1522     std::array<uint32_t, kCapabilityInstructionLength> newCapabilityDeclaration = {
1523         instruction[0],  // length+opcode is identical
1524     };
1525     // Fill the fields.
1526     newCapabilityDeclaration[kCapabilityIndex] = spv::CapabilityTransformFeedback;
1527 
1528     copyInstruction(newCapabilityDeclaration.data(), kCapabilityInstructionLength);
1529 
1530     return true;
1531 }
1532 
transformEntryPoint(const uint32_t * instruction,size_t wordCount)1533 bool SpirvTransformer::transformEntryPoint(const uint32_t *instruction, size_t wordCount)
1534 {
1535     // Remove inactive varyings from the shader interface declaration.
1536 
1537     // SPIR-V 1.0 Section 3.32 Instructions, OpEntryPoint
1538     constexpr size_t kNameIndex = 3;
1539 
1540     // Calculate the length of entry point name in words.  Note that endianness of the string
1541     // doesn't matter, since we are looking for the '\0' character and rounding up to the word size.
1542     // This calculates (strlen(name)+1+3) / 4, which is equal to strlen(name)/4+1.
1543     const size_t nameLength =
1544         strlen(reinterpret_cast<const char *>(&instruction[kNameIndex])) / 4 + 1;
1545     const uint32_t instructionLength = GetSpirvInstructionLength(instruction);
1546     const size_t interfaceStart      = kNameIndex + nameLength;
1547     const size_t interfaceCount      = instructionLength - interfaceStart;
1548 
1549     // Create a copy of the entry point for modification.
1550     std::vector<uint32_t> filteredEntryPoint(instruction, instruction + wordCount);
1551 
1552     // Filter out inactive varyings from entry point interface declaration.
1553     size_t writeIndex = interfaceStart;
1554     for (size_t index = 0; index < interfaceCount; ++index)
1555     {
1556         uint32_t id                             = instruction[interfaceStart + index];
1557         const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
1558 
1559         ASSERT(info);
1560 
1561         if (!info->activeStages[mShaderType])
1562         {
1563             continue;
1564         }
1565 
1566         filteredEntryPoint[writeIndex] = id;
1567         ++writeIndex;
1568     }
1569 
1570     // Update the length of the instruction.
1571     const size_t newLength = writeIndex;
1572     SetSpirvInstructionLength(filteredEntryPoint.data(), newLength);
1573 
1574     // Copy to output.
1575     copyInstruction(filteredEntryPoint.data(), newLength);
1576 
1577     // Add an OpExecutionMode Xfb instruction if necessary.
1578     if (!mHasTransformFeedbackOutput)
1579     {
1580         return true;
1581     }
1582 
1583     // SPIR-V 1.0 Section 3.32 Instructions, OpEntryPoint
1584     constexpr size_t kEntryPointIdIndex = 2;
1585 
1586     // SPIR-V 1.0 Section 3.32 Instructions, OpExecutionMode
1587     constexpr size_t kExecutionModeInstructionLength  = 3;
1588     constexpr size_t kExecutionModeIdIndex            = 1;
1589     constexpr size_t kExecutionModeExecutionModeIndex = 2;
1590 
1591     std::array<uint32_t, kExecutionModeInstructionLength> newExecutionModeDeclaration = {};
1592 
1593     // Fill the fields.
1594     SetSpirvInstructionOp(newExecutionModeDeclaration.data(), spv::OpExecutionMode);
1595     SetSpirvInstructionLength(newExecutionModeDeclaration.data(), kExecutionModeInstructionLength);
1596     newExecutionModeDeclaration[kExecutionModeIdIndex]            = instruction[kEntryPointIdIndex];
1597     newExecutionModeDeclaration[kExecutionModeExecutionModeIndex] = spv::ExecutionModeXfb;
1598 
1599     copyInstruction(newExecutionModeDeclaration.data(), kExecutionModeInstructionLength);
1600 
1601     return true;
1602 }
1603 
transformTypePointer(const uint32_t * instruction,size_t wordCount)1604 bool SpirvTransformer::transformTypePointer(const uint32_t *instruction, size_t wordCount)
1605 {
1606     // SPIR-V 1.0 Section 3.32 Instructions, OpTypePointer
1607     constexpr size_t kIdIndex           = 1;
1608     constexpr size_t kStorageClassIndex = 2;
1609     constexpr size_t kTypeIdIndex       = 3;
1610 
1611     const uint32_t id           = instruction[kIdIndex];
1612     const uint32_t storageClass = instruction[kStorageClassIndex];
1613     const uint32_t typeId       = instruction[kTypeIdIndex];
1614 
1615     // If the storage class is output, this may be used to create a variable corresponding to an
1616     // inactive varying, or if that varying is a struct, an Op*AccessChain retrieving a field of
1617     // that inactive varying.
1618     //
1619     // Unfortunately, SPIR-V specifies the storage class both on the type and the variable
1620     // declaration.  Otherwise it would have been sufficient to modify the OpVariable instruction.
1621     // For simplicty, copy every "OpTypePointer Output" instruction except with the Private storage
1622     // class, in case it may be necessary later.
1623 
1624     if (storageClass != spv::StorageClassOutput)
1625     {
1626         return false;
1627     }
1628 
1629     // Cannot create a Private type declaration from builtins such as gl_PerVertex.
1630     if (mNamesById[typeId] != nullptr && angle::BeginsWith(mNamesById[typeId], "gl_"))
1631     {
1632         return false;
1633     }
1634 
1635     // Copy the type declaration for modification.
1636     const size_t instructionOffset = copyInstruction(instruction, wordCount);
1637 
1638     const uint32_t newTypeId                                 = getNewId();
1639     (*mSpirvBlobOut)[instructionOffset + kIdIndex]           = newTypeId;
1640     (*mSpirvBlobOut)[instructionOffset + kStorageClassIndex] = spv::StorageClassPrivate;
1641 
1642     // Remember the id of the replacement.
1643     ASSERT(id < mTypePointerTransformedId.size());
1644     mTypePointerTransformedId[id] = newTypeId;
1645 
1646     // The original instruction should still be present as well.  At this point, we don't know
1647     // whether we will need the Output or Private type.
1648     return false;
1649 }
1650 
transformVariable(const uint32_t * instruction,size_t wordCount)1651 bool SpirvTransformer::transformVariable(const uint32_t *instruction, size_t wordCount)
1652 {
1653     // SPIR-V 1.0 Section 3.32 Instructions, OpVariable
1654     constexpr size_t kTypeIdIndex       = 1;
1655     constexpr size_t kIdIndex           = 2;
1656     constexpr size_t kStorageClassIndex = 3;
1657 
1658     const uint32_t id           = instruction[kIdIndex];
1659     const uint32_t typeId       = instruction[kTypeIdIndex];
1660     const uint32_t storageClass = instruction[kStorageClassIndex];
1661 
1662     const ShaderInterfaceVariableInfo *info = mVariableInfoById[id];
1663 
1664     // If variable is not a shader interface variable that needs modification, there's nothing to
1665     // do.
1666     if (info == nullptr)
1667     {
1668         return false;
1669     }
1670 
1671     // Furthermore, if it's not an inactive varying output, there's nothing to do.  Note that
1672     // inactive varying inputs are already pruned by the translator.
1673     ASSERT(storageClass != spv::StorageClassInput || info->activeStages[mShaderType]);
1674     if (info->activeStages[mShaderType])
1675     {
1676         return false;
1677     }
1678 
1679     ASSERT(storageClass == spv::StorageClassOutput);
1680 
1681     // Copy the variable declaration for modification.  Change its type to the corresponding type
1682     // with the Private storage class, as well as changing the storage class respecified in this
1683     // instruction.
1684     const size_t instructionOffset = copyInstruction(instruction, wordCount);
1685 
1686     ASSERT(typeId < mTypePointerTransformedId.size());
1687     ASSERT(mTypePointerTransformedId[typeId] != 0);
1688 
1689     (*mSpirvBlobOut)[instructionOffset + kTypeIdIndex]       = mTypePointerTransformedId[typeId];
1690     (*mSpirvBlobOut)[instructionOffset + kStorageClassIndex] = spv::StorageClassPrivate;
1691 
1692     return true;
1693 }
1694 
transformAccessChain(const uint32_t * instruction,size_t wordCount)1695 bool SpirvTransformer::transformAccessChain(const uint32_t *instruction, size_t wordCount)
1696 {
1697     // SPIR-V 1.0 Section 3.32 Instructions, OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain,
1698     // OpInBoundsPtrAccessChain
1699     constexpr size_t kTypeIdIndex = 1;
1700     constexpr size_t kBaseIdIndex = 3;
1701 
1702     const uint32_t typeId = instruction[kTypeIdIndex];
1703     const uint32_t baseId = instruction[kBaseIdIndex];
1704 
1705     // If not accessing an inactive output varying, nothing to do.
1706     const ShaderInterfaceVariableInfo *info = mVariableInfoById[baseId];
1707     if (info == nullptr || info->activeStages[mShaderType])
1708     {
1709         return false;
1710     }
1711 
1712     // Copy the instruction for modification.
1713     const size_t instructionOffset = copyInstruction(instruction, wordCount);
1714 
1715     ASSERT(typeId < mTypePointerTransformedId.size());
1716     ASSERT(mTypePointerTransformedId[typeId] != 0);
1717 
1718     (*mSpirvBlobOut)[instructionOffset + kTypeIdIndex] = mTypePointerTransformedId[typeId];
1719 
1720     return true;
1721 }
1722 
transformExecutionMode(const uint32_t * instruction,size_t wordCount)1723 bool SpirvTransformer::transformExecutionMode(const uint32_t *instruction, size_t wordCount)
1724 {
1725     // SPIR-V 1.0 Section 3.32 Instructions, OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain,
1726     // OpInBoundsPtrAccessChain
1727     constexpr size_t kModeIndex  = 2;
1728     const uint32_t executionMode = instruction[kModeIndex];
1729 
1730     if (executionMode == spv::ExecutionModeEarlyFragmentTests &&
1731         mRemoveEarlyFragmentTestsOptimization)
1732     {
1733         // skip the copy
1734         return true;
1735     }
1736     return false;
1737 }
1738 
copyInstruction(const uint32_t * instruction,size_t wordCount)1739 size_t SpirvTransformer::copyInstruction(const uint32_t *instruction, size_t wordCount)
1740 {
1741     size_t instructionOffset = mSpirvBlobOut->size();
1742     mSpirvBlobOut->insert(mSpirvBlobOut->end(), instruction, instruction + wordCount);
1743     return instructionOffset;
1744 }
1745 
getNewId()1746 uint32_t SpirvTransformer::getNewId()
1747 {
1748     return (*mSpirvBlobOut)[kHeaderIndexIndexBound]++;
1749 }
1750 }  // anonymous namespace
1751 
1752 const uint32_t ShaderInterfaceVariableInfo::kInvalid;
1753 
ShaderInterfaceVariableInfo()1754 ShaderInterfaceVariableInfo::ShaderInterfaceVariableInfo() {}
1755 
GlslangInitialize()1756 void GlslangInitialize()
1757 {
1758     int result = ShInitialize();
1759     ASSERT(result != 0);
1760 }
1761 
GlslangRelease()1762 void GlslangRelease()
1763 {
1764     int result = ShFinalize();
1765     ASSERT(result != 0);
1766 }
1767 
1768 // Strip indices from the name.  If there are non-zero indices, return false to indicate that this
1769 // image uniform doesn't require set/binding.  That is done on index 0.
GetImageNameWithoutIndices(std::string * name)1770 bool GetImageNameWithoutIndices(std::string *name)
1771 {
1772     if (name->back() != ']')
1773     {
1774         return true;
1775     }
1776 
1777     if (!UniformNameIsIndexZero(*name, false))
1778     {
1779         return false;
1780     }
1781 
1782     // Strip all indices
1783     *name = name->substr(0, name->find('['));
1784     return true;
1785 }
1786 
GetMappedSamplerNameOld(const std::string & originalName)1787 std::string GetMappedSamplerNameOld(const std::string &originalName)
1788 {
1789     std::string samplerName = gl::ParseResourceName(originalName, nullptr);
1790 
1791     // Samplers in structs are extracted.
1792     std::replace(samplerName.begin(), samplerName.end(), '.', '_');
1793 
1794     // Samplers in arrays of structs are also extracted.
1795     std::replace(samplerName.begin(), samplerName.end(), '[', '_');
1796     samplerName.erase(std::remove(samplerName.begin(), samplerName.end(), ']'), samplerName.end());
1797 
1798     if (MappedSamplerNameNeedsUserDefinedPrefix(originalName))
1799     {
1800         samplerName = sh::kUserDefinedNamePrefix + samplerName;
1801     }
1802 
1803     return samplerName;
1804 }
1805 
GlslangGetMappedSamplerName(const std::string & originalName)1806 std::string GlslangGetMappedSamplerName(const std::string &originalName)
1807 {
1808     std::string samplerName = originalName;
1809 
1810     // Samplers in structs are extracted.
1811     std::replace(samplerName.begin(), samplerName.end(), '.', '_');
1812 
1813     // Remove array elements
1814     auto out = samplerName.begin();
1815     for (auto in = samplerName.begin(); in != samplerName.end(); in++)
1816     {
1817         if (*in == '[')
1818         {
1819             while (*in != ']')
1820             {
1821                 in++;
1822                 ASSERT(in != samplerName.end());
1823             }
1824         }
1825         else
1826         {
1827             *out++ = *in;
1828         }
1829     }
1830 
1831     samplerName.erase(out, samplerName.end());
1832 
1833     if (MappedSamplerNameNeedsUserDefinedPrefix(originalName))
1834     {
1835         samplerName = sh::kUserDefinedNamePrefix + samplerName;
1836     }
1837 
1838     return samplerName;
1839 }
1840 
GetXfbBufferName(const uint32_t bufferIndex)1841 std::string GetXfbBufferName(const uint32_t bufferIndex)
1842 {
1843     return "xfbBuffer" + Str(bufferIndex);
1844 }
1845 
GlslangAssignLocations(GlslangSourceOptions & options,const gl::ProgramExecutable & programExecutable,const gl::ShaderType shaderType,GlslangProgramInterfaceInfo * programInterfaceInfo,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)1846 void GlslangAssignLocations(GlslangSourceOptions &options,
1847                             const gl::ProgramExecutable &programExecutable,
1848                             const gl::ShaderType shaderType,
1849                             GlslangProgramInterfaceInfo *programInterfaceInfo,
1850                             ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
1851 {
1852     // Assign outputs to the fragment shader, if any.
1853     if ((shaderType == gl::ShaderType::Fragment) &&
1854         programExecutable.hasLinkedShaderStage(gl::ShaderType::Fragment))
1855     {
1856         AssignOutputLocations(programExecutable, gl::ShaderType::Fragment,
1857                               &(*variableInfoMapOut)[gl::ShaderType::Fragment]);
1858     }
1859 
1860     // Assign attributes to the vertex shader, if any.
1861     if ((shaderType == gl::ShaderType::Vertex) &&
1862         programExecutable.hasLinkedShaderStage(gl::ShaderType::Vertex))
1863     {
1864         AssignAttributeLocations(programExecutable, gl::ShaderType::Vertex,
1865                                  &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
1866     }
1867 
1868     if (!programExecutable.hasLinkedShaderStage(gl::ShaderType::Compute))
1869     {
1870         // Assign varying locations.
1871         AssignVaryingLocations(options, programExecutable, shaderType, programInterfaceInfo,
1872                                variableInfoMapOut);
1873 
1874         if (!programExecutable.getLinkedTransformFeedbackVaryings().empty() &&
1875             options.supportsTransformFeedbackExtension && (shaderType == gl::ShaderType::Vertex))
1876         {
1877             AssignTransformFeedbackExtensionQualifiers(
1878                 programExecutable, programInterfaceInfo->locationsUsedForXfbExtension,
1879                 gl::ShaderType::Vertex, &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
1880         }
1881     }
1882 
1883     AssignUniformBindings(options, programExecutable, shaderType, programInterfaceInfo,
1884                           variableInfoMapOut);
1885     AssignTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
1886                           variableInfoMapOut);
1887     AssignNonTextureBindings(options, programExecutable, shaderType, programInterfaceInfo,
1888                              variableInfoMapOut);
1889 }
1890 
GlslangGetShaderSource(GlslangSourceOptions & options,const gl::ProgramState & programState,const gl::ProgramLinkedResources & resources,GlslangProgramInterfaceInfo * programInterfaceInfo,gl::ShaderMap<std::string> * shaderSourcesOut,ShaderMapInterfaceVariableInfoMap * variableInfoMapOut)1891 void GlslangGetShaderSource(GlslangSourceOptions &options,
1892                             const gl::ProgramState &programState,
1893                             const gl::ProgramLinkedResources &resources,
1894                             GlslangProgramInterfaceInfo *programInterfaceInfo,
1895                             gl::ShaderMap<std::string> *shaderSourcesOut,
1896                             ShaderMapInterfaceVariableInfoMap *variableInfoMapOut)
1897 {
1898     for (const gl::ShaderType shaderType : gl::AllShaderTypes())
1899     {
1900         gl::Shader *glShader            = programState.getAttachedShader(shaderType);
1901         (*shaderSourcesOut)[shaderType] = glShader ? glShader->getTranslatedSource() : "";
1902     }
1903 
1904     std::string *vertexSource = &(*shaderSourcesOut)[gl::ShaderType::Vertex];
1905 
1906     // Write transform feedback output code.
1907     if (!vertexSource->empty())
1908     {
1909         if (programState.getLinkedTransformFeedbackVaryings().empty())
1910         {
1911             *vertexSource = SubstituteTransformFeedbackMarkers(*vertexSource, "", "");
1912         }
1913         else
1914         {
1915             if (options.supportsTransformFeedbackExtension)
1916             {
1917                 GenerateTransformFeedbackExtensionOutputs(
1918                     programState, resources, vertexSource,
1919                     &programInterfaceInfo->locationsUsedForXfbExtension);
1920             }
1921             else if (options.emulateTransformFeedback)
1922             {
1923                 GenerateTransformFeedbackEmulationOutputs(
1924                     options, programState, programInterfaceInfo, vertexSource,
1925                     &(*variableInfoMapOut)[gl::ShaderType::Vertex]);
1926             }
1927         }
1928     }
1929 
1930     for (const gl::ShaderType shaderType : programState.getExecutable().getLinkedShaderStages())
1931     {
1932         GlslangAssignLocations(options, programState.getExecutable(), shaderType,
1933                                programInterfaceInfo, variableInfoMapOut);
1934     }
1935 }
1936 
GlslangTransformSpirvCode(const GlslangErrorCallback & callback,const gl::ShaderType shaderType,bool removeEarlyFragmentTestsOptimization,const ShaderInterfaceVariableInfoMap & variableInfoMap,const SpirvBlob & initialSpirvBlob,SpirvBlob * spirvBlobOut)1937 angle::Result GlslangTransformSpirvCode(const GlslangErrorCallback &callback,
1938                                         const gl::ShaderType shaderType,
1939                                         bool removeEarlyFragmentTestsOptimization,
1940                                         const ShaderInterfaceVariableInfoMap &variableInfoMap,
1941                                         const SpirvBlob &initialSpirvBlob,
1942                                         SpirvBlob *spirvBlobOut)
1943 {
1944     if (initialSpirvBlob.empty())
1945     {
1946         return angle::Result::Continue;
1947     }
1948 
1949     // Transform the SPIR-V code by assigning location/set/binding values.
1950     SpirvTransformer transformer(initialSpirvBlob, removeEarlyFragmentTestsOptimization,
1951                                  variableInfoMap, shaderType, spirvBlobOut);
1952     ANGLE_GLSLANG_CHECK(callback, transformer.transform(), GlslangError::InvalidSpirv);
1953 
1954     ASSERT(ValidateSpirv(*spirvBlobOut));
1955 
1956     return angle::Result::Continue;
1957 }
1958 
GlslangGetShaderSpirvCode(const GlslangErrorCallback & callback,const gl::ShaderBitSet & linkedShaderStages,const gl::Caps & glCaps,const gl::ShaderMap<std::string> & shaderSources,const ShaderMapInterfaceVariableInfoMap & variableInfoMap,gl::ShaderMap<SpirvBlob> * spirvBlobsOut)1959 angle::Result GlslangGetShaderSpirvCode(const GlslangErrorCallback &callback,
1960                                         const gl::ShaderBitSet &linkedShaderStages,
1961                                         const gl::Caps &glCaps,
1962                                         const gl::ShaderMap<std::string> &shaderSources,
1963                                         const ShaderMapInterfaceVariableInfoMap &variableInfoMap,
1964                                         gl::ShaderMap<SpirvBlob> *spirvBlobsOut)
1965 {
1966     gl::ShaderMap<SpirvBlob> initialSpirvBlobs;
1967     ANGLE_TRY(GetShaderSpirvCode(callback, glCaps, shaderSources, &initialSpirvBlobs));
1968 
1969     for (const gl::ShaderType shaderType : linkedShaderStages)
1970     {
1971         // we pass in false here to skip modifications related to  early fragment tests
1972         // optimizations and line rasterization. These are done in the initProgram time since they
1973         // are related to context state. We must keep original untouched spriv blobs here because we
1974         // do not have ability to add back in at initProgram time.
1975         angle::Result status =
1976             GlslangTransformSpirvCode(callback, shaderType, false, variableInfoMap[shaderType],
1977                                       initialSpirvBlobs[shaderType], &(*spirvBlobsOut)[shaderType]);
1978         if (status != angle::Result::Continue)
1979         {
1980             return status;
1981         }
1982     }
1983 
1984     return angle::Result::Continue;
1985 }
1986 }  // namespace rx
1987