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