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