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