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