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