1 //
2 // Copyright 2017 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
7 // ProgramLinkedResources.cpp: implements link-time checks for default block uniforms, and generates
8 // uniform locations. Populates data structures related to uniforms so that they can be stored in
9 // program state.
10
11 #include "libANGLE/ProgramLinkedResources.h"
12
13 #include "common/string_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Caps.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Shader.h"
18 #include "libANGLE/features.h"
19
20 namespace gl
21 {
22 namespace
23 {
FindUniform(std::vector<UsedUniform> & list,const std::string & name)24 UsedUniform *FindUniform(std::vector<UsedUniform> &list, const std::string &name)
25 {
26 for (UsedUniform &uniform : list)
27 {
28 if (uniform.name == name)
29 return &uniform;
30 }
31
32 return nullptr;
33 }
34
35 template <typename VarT>
SetActive(std::vector<VarT> * list,const std::string & name,ShaderType shaderType,bool active,uint32_t id)36 void SetActive(std::vector<VarT> *list,
37 const std::string &name,
38 ShaderType shaderType,
39 bool active,
40 uint32_t id)
41 {
42 for (auto &variable : *list)
43 {
44 if (variable.name == name)
45 {
46 variable.setActive(shaderType, active, id);
47 return;
48 }
49 }
50 }
51
52 template <typename VarT>
SetActive(std::vector<VarT> * list,std::vector<std::string> * nameList,const std::string & name,ShaderType shaderType,bool active,uint32_t id)53 void SetActive(std::vector<VarT> *list,
54 std::vector<std::string> *nameList,
55 const std::string &name,
56 ShaderType shaderType,
57 bool active,
58 uint32_t id)
59 {
60 for (GLint index = 0; index < static_cast<GLint>(nameList->size()); index++)
61 {
62 if ((*nameList)[index] == name)
63 {
64 (*list)[index].setActive(shaderType, active, id);
65 return;
66 }
67 }
68 }
69
70 // GLSL ES Spec 3.00.3, section 4.3.5.
LinkValidateUniforms(const sh::ShaderVariable & uniform1,const sh::ShaderVariable & uniform2,std::string * mismatchedStructFieldName)71 LinkMismatchError LinkValidateUniforms(const sh::ShaderVariable &uniform1,
72 const sh::ShaderVariable &uniform2,
73 std::string *mismatchedStructFieldName)
74 {
75 #if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION
76 const bool validatePrecisionFeature = true;
77 #else
78 const bool validatePrecisionFeature = false;
79 #endif
80
81 // Validate precision match of uniforms iff they are statically used
82 bool validatePrecision = uniform1.staticUse && uniform2.staticUse && validatePrecisionFeature;
83 LinkMismatchError linkError = LinkValidateProgramVariables(
84 uniform1, uniform2, validatePrecision, false, false, mismatchedStructFieldName);
85 if (linkError != LinkMismatchError::NO_MISMATCH)
86 {
87 return linkError;
88 }
89
90 // GLSL ES Spec 3.10.4, section 4.4.5.
91 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
92 {
93 return LinkMismatchError::BINDING_MISMATCH;
94 }
95
96 // GLSL ES Spec 3.10.4, section 9.2.1.
97 if (uniform1.location != -1 && uniform2.location != -1 &&
98 uniform1.location != uniform2.location)
99 {
100 return LinkMismatchError::LOCATION_MISMATCH;
101 }
102 if (uniform1.offset != uniform2.offset)
103 {
104 return LinkMismatchError::OFFSET_MISMATCH;
105 }
106
107 return LinkMismatchError::NO_MISMATCH;
108 }
109
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)110 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
111 {
112 switch (shaderType)
113 {
114 case ShaderType::Vertex:
115 return static_cast<GLuint>(caps.maxVertexUniformVectors);
116 case ShaderType::Fragment:
117 return static_cast<GLuint>(caps.maxFragmentUniformVectors);
118
119 case ShaderType::Compute:
120 case ShaderType::Geometry:
121 case ShaderType::TessControl:
122 case ShaderType::TessEvaluation:
123 return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
124
125 default:
126 UNREACHABLE();
127 return 0u;
128 }
129 }
130
131 enum class UniformType : uint8_t
132 {
133 Variable = 0,
134 Sampler = 1,
135 Image = 2,
136 AtomicCounter = 3,
137
138 InvalidEnum = 4,
139 EnumCount = 4,
140 };
141
GetUniformResourceNameString(UniformType uniformType)142 const char *GetUniformResourceNameString(UniformType uniformType)
143 {
144 switch (uniformType)
145 {
146 case UniformType::Variable:
147 return "uniform";
148 case UniformType::Sampler:
149 return "texture image unit";
150 case UniformType::Image:
151 return "image uniform";
152 case UniformType::AtomicCounter:
153 return "atomic counter";
154 default:
155 UNREACHABLE();
156 return "";
157 }
158 }
159
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)160 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
161 {
162 // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
163 if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
164 {
165 return "MAX_TEXTURE_IMAGE_UNITS";
166 }
167
168 std::ostringstream ostream;
169 ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
170
171 switch (uniformType)
172 {
173 case UniformType::Variable:
174 // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
175 // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
176 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
177 {
178 ostream << "UNIFORM_VECTORS";
179 break;
180 }
181 // For compute and geometry shaders, there are no definitions on
182 // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
183 // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
184 else
185 {
186 ostream << "UNIFORM_COMPONENTS";
187 }
188 break;
189 case UniformType::Sampler:
190 ostream << "TEXTURE_IMAGE_UNITS";
191 break;
192 case UniformType::Image:
193 ostream << "IMAGE_UNIFORMS";
194 break;
195 case UniformType::AtomicCounter:
196 ostream << "ATOMIC_COUNTERS";
197 break;
198 default:
199 UNREACHABLE();
200 return "";
201 }
202
203 if (shaderType == ShaderType::Geometry)
204 {
205 ostream << "_EXT";
206 }
207
208 return ostream.str();
209 }
210
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)211 void LogUniformsExceedLimit(ShaderType shaderType,
212 UniformType uniformType,
213 GLuint limit,
214 InfoLog &infoLog)
215 {
216 infoLog << GetShaderTypeString(shaderType) << " shader "
217 << GetUniformResourceNameString(uniformType) << "s count exceeds "
218 << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
219 }
220
221 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
222 // added to "uniformsOut".
223 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
224 {
225 public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,ShaderType shaderType,int blockIndex)226 UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
227 const std::string &namePrefix,
228 const std::string &mappedNamePrefix,
229 std::vector<LinkedUniform> *uniformsOut,
230 std::vector<std::string> *uniformNamesOut,
231 std::vector<std::string> *uniformMappedNamesOut,
232 ShaderType shaderType,
233 int blockIndex)
234 : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
235 mGetMemberInfo(getMemberInfo),
236 mUniformsOut(uniformsOut),
237 mUniformNamesOut(uniformNamesOut),
238 mUniformMappedNamesOut(uniformMappedNamesOut),
239 mShaderType(shaderType),
240 mBlockIndex(blockIndex)
241 {}
242
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)243 void visitNamedVariable(const sh::ShaderVariable &variable,
244 bool isRowMajor,
245 const std::string &name,
246 const std::string &mappedName,
247 const std::vector<unsigned int> &arraySizes) override
248 {
249 // If getBlockMemberInfo returns false, the variable is optimized out.
250 sh::BlockMemberInfo variableInfo;
251 if (!mGetMemberInfo(name, mappedName, &variableInfo))
252 return;
253
254 std::string nameWithArrayIndex = name;
255 std::string mappedNameWithArrayIndex = mappedName;
256
257 if (variable.isArray())
258 {
259 nameWithArrayIndex += "[0]";
260 mappedNameWithArrayIndex += "[0]";
261 }
262
263 if (mBlockIndex == -1)
264 {
265 SetActive(mUniformsOut, mUniformNamesOut, nameWithArrayIndex, mShaderType,
266 variable.active, variable.id);
267 return;
268 }
269
270 LinkedUniform newUniform(variable.type, variable.precision, variable.arraySizes, -1, -1, -1,
271 mBlockIndex, variableInfo);
272 newUniform.setActive(mShaderType, variable.active, variable.id);
273
274 // Since block uniforms have no location, we don't need to store them in the uniform
275 // locations list.
276 mUniformsOut->push_back(newUniform);
277 mUniformNamesOut->push_back(nameWithArrayIndex);
278 mUniformMappedNamesOut->push_back(mappedNameWithArrayIndex);
279 }
280
281 private:
282 const GetBlockMemberInfoFunc &mGetMemberInfo;
283 std::vector<LinkedUniform> *mUniformsOut;
284 std::vector<std::string> *mUniformNamesOut;
285 std::vector<std::string> *mUniformMappedNamesOut;
286 const ShaderType mShaderType;
287 const int mBlockIndex;
288 };
289
290 // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
291 // new buffer variable is stored in "bufferVariablesOut".
292 class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
293 {
294 public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)295 ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
296 const std::string &namePrefix,
297 const std::string &mappedNamePrefix,
298 std::vector<BufferVariable> *bufferVariablesOut,
299 ShaderType shaderType,
300 int blockIndex)
301 : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mStubEncoder),
302 mGetMemberInfo(getMemberInfo),
303 mBufferVariablesOut(bufferVariablesOut),
304 mShaderType(shaderType),
305 mBlockIndex(blockIndex)
306 {}
307
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)308 void visitNamedVariable(const sh::ShaderVariable &variable,
309 bool isRowMajor,
310 const std::string &name,
311 const std::string &mappedName,
312 const std::vector<unsigned int> &arraySizes) override
313 {
314 if (mSkipEnabled)
315 return;
316
317 // If getBlockMemberInfo returns false, the variable is optimized out.
318 sh::BlockMemberInfo variableInfo;
319 if (!mGetMemberInfo(name, mappedName, &variableInfo))
320 return;
321
322 std::string nameWithArrayIndex = name;
323 std::string mappedNameWithArrayIndex = mappedName;
324
325 if (variable.isArray())
326 {
327 nameWithArrayIndex += "[0]";
328 mappedNameWithArrayIndex += "[0]";
329 }
330
331 if (mBlockIndex == -1)
332 {
333 SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active,
334 variable.id);
335 return;
336 }
337
338 BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
339 variable.arraySizes, mBlockIndex, mTopLevelArraySize,
340 variableInfo);
341 newBufferVariable.mappedName = mappedNameWithArrayIndex;
342 newBufferVariable.setActive(mShaderType, variable.active, variable.id);
343
344 mBufferVariablesOut->push_back(newBufferVariable);
345 }
346
347 private:
348 const GetBlockMemberInfoFunc &mGetMemberInfo;
349 std::vector<BufferVariable> *mBufferVariablesOut;
350 const ShaderType mShaderType;
351 const int mBlockIndex;
352 sh::StubBlockEncoder mStubEncoder;
353 };
354
355 struct ShaderUniformCount
356 {
357 unsigned int vectorCount = 0;
358 unsigned int samplerCount = 0;
359 unsigned int imageCount = 0;
360 unsigned int atomicCounterCount = 0;
361 unsigned int fragmentInOutCount = 0;
362 };
363
operator +=(ShaderUniformCount & lhs,const ShaderUniformCount & rhs)364 ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
365 {
366 lhs.vectorCount += rhs.vectorCount;
367 lhs.samplerCount += rhs.samplerCount;
368 lhs.imageCount += rhs.imageCount;
369 lhs.atomicCounterCount += rhs.atomicCounterCount;
370 lhs.fragmentInOutCount += rhs.fragmentInOutCount;
371 return lhs;
372 }
373
374 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
375 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
376 // Counts for each uniform category are stored and can be queried with "getCounts".
377 class FlattenUniformVisitor : public sh::VariableNameVisitor
378 {
379 public:
FlattenUniformVisitor(ShaderType shaderType,const sh::ShaderVariable & uniform,std::vector<UsedUniform> * uniforms,std::vector<UsedUniform> * samplerUniforms,std::vector<UsedUniform> * imageUniforms,std::vector<UsedUniform> * atomicCounterUniforms,std::vector<UsedUniform> * inputAttachmentUniforms,std::vector<UnusedUniform> * unusedUniforms)380 FlattenUniformVisitor(ShaderType shaderType,
381 const sh::ShaderVariable &uniform,
382 std::vector<UsedUniform> *uniforms,
383 std::vector<UsedUniform> *samplerUniforms,
384 std::vector<UsedUniform> *imageUniforms,
385 std::vector<UsedUniform> *atomicCounterUniforms,
386 std::vector<UsedUniform> *inputAttachmentUniforms,
387 std::vector<UnusedUniform> *unusedUniforms)
388 : sh::VariableNameVisitor("", ""),
389 mShaderType(shaderType),
390 mMarkActive(uniform.active),
391 mMarkStaticUse(uniform.staticUse),
392 mBinding(uniform.binding),
393 mOffset(uniform.offset),
394 mLocation(uniform.location),
395 mUniforms(uniforms),
396 mSamplerUniforms(samplerUniforms),
397 mImageUniforms(imageUniforms),
398 mAtomicCounterUniforms(atomicCounterUniforms),
399 mInputAttachmentUniforms(inputAttachmentUniforms),
400 mUnusedUniforms(unusedUniforms)
401 {}
402
visitNamedOpaqueObject(const sh::ShaderVariable & variable,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)403 void visitNamedOpaqueObject(const sh::ShaderVariable &variable,
404 const std::string &name,
405 const std::string &mappedName,
406 const std::vector<unsigned int> &arraySizes) override
407 {
408 visitNamedVariable(variable, false, name, mappedName, arraySizes);
409 }
410
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)411 void visitNamedVariable(const sh::ShaderVariable &variable,
412 bool isRowMajor,
413 const std::string &name,
414 const std::string &mappedName,
415 const std::vector<unsigned int> &arraySizes) override
416 {
417 bool isSampler = IsSamplerType(variable.type);
418 bool isImage = IsImageType(variable.type);
419 bool isAtomicCounter = IsAtomicCounterType(variable.type);
420 bool isFragmentInOut = variable.isFragmentInOut;
421 std::vector<UsedUniform> *uniformList = mUniforms;
422 if (isSampler)
423 {
424 uniformList = mSamplerUniforms;
425 }
426 else if (isImage)
427 {
428 uniformList = mImageUniforms;
429 }
430 else if (isAtomicCounter)
431 {
432 uniformList = mAtomicCounterUniforms;
433 }
434 else if (isFragmentInOut)
435 {
436 uniformList = mInputAttachmentUniforms;
437 }
438
439 std::string fullNameWithArrayIndex(name);
440 std::string fullMappedNameWithArrayIndex(mappedName);
441
442 if (variable.isArray())
443 {
444 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
445 // Resources and including [0] at the end of array variable names.
446 fullNameWithArrayIndex += "[0]";
447 fullMappedNameWithArrayIndex += "[0]";
448 }
449
450 UsedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
451 if (existingUniform)
452 {
453 if (getBinding() != -1)
454 {
455 existingUniform->binding = getBinding();
456 }
457 if (getOffset() != -1)
458 {
459 existingUniform->offset = getOffset();
460 }
461 if (mLocation != -1)
462 {
463 existingUniform->location = mLocation;
464 }
465 if (mMarkActive)
466 {
467 existingUniform->active = true;
468 existingUniform->setActive(mShaderType, true, variable.id);
469 }
470 if (mMarkStaticUse)
471 {
472 existingUniform->staticUse = true;
473 }
474 }
475 else
476 {
477 UsedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
478 variable.arraySizes, getBinding(), getOffset(), mLocation, -1,
479 sh::kDefaultBlockMemberInfo);
480 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
481 linkedUniform.active = mMarkActive;
482 linkedUniform.staticUse = mMarkStaticUse;
483 linkedUniform.outerArraySizes = arraySizes;
484 linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
485 linkedUniform.id = variable.id;
486 linkedUniform.imageUnitFormat = variable.imageUnitFormat;
487 linkedUniform.isFragmentInOut = variable.isFragmentInOut;
488 if (variable.hasParentArrayIndex())
489 {
490 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
491 }
492
493 std::vector<unsigned int> arrayDims = arraySizes;
494 ASSERT(variable.arraySizes.size() == 1 || variable.arraySizes.size() == 0);
495 arrayDims.push_back(variable.arraySizes.empty() ? 1 : variable.arraySizes[0]);
496
497 size_t numDimensions = arraySizes.size();
498 uint32_t arrayStride = 1;
499 for (size_t dimension = numDimensions; dimension > 0;)
500 {
501 --dimension;
502 arrayStride *= arrayDims[dimension + 1];
503 linkedUniform.outerArrayOffset += arrayStride * mArrayElementStack[dimension];
504 }
505
506 if (mMarkActive)
507 {
508 linkedUniform.setActive(mShaderType, true, variable.id);
509 }
510 else
511 {
512 mUnusedUniforms->emplace_back(
513 linkedUniform.name, linkedUniform.isSampler(), linkedUniform.isImage(),
514 linkedUniform.isAtomicCounter(), linkedUniform.isFragmentInOut);
515 }
516
517 uniformList->push_back(linkedUniform);
518 }
519
520 unsigned int elementCount = variable.getBasicTypeElementCount();
521
522 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
523 // Likewise, don't count "real" uniforms towards opaque count.
524
525 if (!IsOpaqueType(variable.type) && !isFragmentInOut)
526 {
527 mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
528 }
529
530 mUniformCount.samplerCount += (isSampler ? elementCount : 0);
531 mUniformCount.imageCount += (isImage ? elementCount : 0);
532 mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
533 mUniformCount.fragmentInOutCount += (isFragmentInOut ? elementCount : 0);
534
535 if (mLocation != -1)
536 {
537 mLocation += elementCount;
538 }
539 }
540
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)541 void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
542 {
543 mStructStackSize++;
544 sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
545 }
546
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)547 void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
548 {
549 mStructStackSize--;
550 sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
551 }
552
enterArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)553 void enterArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
554 {
555 mArrayElementStack.push_back(arrayElement);
556 sh::VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
557 }
558
exitArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)559 void exitArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
560 {
561 mArrayElementStack.pop_back();
562 sh::VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
563 }
564
getCounts() const565 ShaderUniformCount getCounts() const { return mUniformCount; }
566
567 private:
getBinding() const568 int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const569 int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
570
571 ShaderType mShaderType;
572
573 // Active and StaticUse are given separately because they are tracked at struct granularity.
574 bool mMarkActive;
575 bool mMarkStaticUse;
576 int mBinding;
577 int mOffset;
578 int mLocation;
579 std::vector<UsedUniform> *mUniforms;
580 std::vector<UsedUniform> *mSamplerUniforms;
581 std::vector<UsedUniform> *mImageUniforms;
582 std::vector<UsedUniform> *mAtomicCounterUniforms;
583 std::vector<UsedUniform> *mInputAttachmentUniforms;
584 std::vector<UnusedUniform> *mUnusedUniforms;
585 std::vector<unsigned int> mArrayElementStack;
586 ShaderUniformCount mUniformCount;
587 unsigned int mStructStackSize = 0;
588 };
589
590 class InterfaceBlockInfo final : angle::NonCopyable
591 {
592 public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)593 InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
594 : mCustomEncoderFactory(customEncoderFactory)
595 {}
596
597 void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
598
599 bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
600 bool getBlockMemberInfo(const std::string &name,
601 const std::string &mappedName,
602 sh::BlockMemberInfo *infoOut);
603
604 private:
605 size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
606
607 std::map<std::string, size_t> mBlockSizes;
608 sh::BlockLayoutMap mBlockLayout;
609 // Based on the interface block layout, the std140 or std430 encoders are used. On some
610 // platforms (currently only D3D), there could be another non-standard encoder used.
611 CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
612 };
613
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)614 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
615 {
616 for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
617 {
618 if (!IsActiveInterfaceBlock(interfaceBlock))
619 continue;
620
621 if (mBlockSizes.count(interfaceBlock.name) > 0)
622 continue;
623
624 size_t dataSize = getBlockInfo(interfaceBlock);
625 mBlockSizes[interfaceBlock.name] = dataSize;
626 }
627 }
628
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)629 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
630 {
631 ASSERT(IsActiveInterfaceBlock(interfaceBlock));
632
633 // define member uniforms
634 sh::Std140BlockEncoder std140Encoder;
635 sh::Std430BlockEncoder std430Encoder;
636 sh::BlockLayoutEncoder *customEncoder = nullptr;
637 sh::BlockLayoutEncoder *encoder = nullptr;
638
639 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
640 {
641 encoder = &std140Encoder;
642 }
643 else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
644 {
645 encoder = &std430Encoder;
646 }
647 else if (mCustomEncoderFactory)
648 {
649 encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
650 }
651 else
652 {
653 UNREACHABLE();
654 return 0;
655 }
656
657 sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
658 &mBlockLayout);
659
660 size_t offset = encoder->getCurrentOffset();
661
662 SafeDelete(customEncoder);
663
664 return offset;
665 }
666
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)667 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
668 const std::string &mappedName,
669 size_t *sizeOut)
670 {
671 size_t nameLengthWithoutArrayIndex;
672 ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
673 std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
674 auto sizeIter = mBlockSizes.find(baseName);
675 if (sizeIter == mBlockSizes.end())
676 {
677 *sizeOut = 0;
678 return false;
679 }
680
681 *sizeOut = sizeIter->second;
682 return true;
683 }
684
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)685 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
686 const std::string &mappedName,
687 sh::BlockMemberInfo *infoOut)
688 {
689 auto infoIter = mBlockLayout.find(name);
690 if (infoIter == mBlockLayout.end())
691 {
692 *infoOut = sh::kDefaultBlockMemberInfo;
693 return false;
694 }
695
696 *infoOut = infoIter->second;
697 return true;
698 }
699
GetFilteredVaryings(const std::vector<sh::ShaderVariable> & varyings,std::vector<const sh::ShaderVariable * > * filteredVaryingsOut)700 void GetFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
701 std::vector<const sh::ShaderVariable *> *filteredVaryingsOut)
702 {
703 for (const sh::ShaderVariable &varying : varyings)
704 {
705 // Built-in varyings obey special rules
706 if (varying.isBuiltIn())
707 {
708 continue;
709 }
710
711 filteredVaryingsOut->push_back(&varying);
712 }
713 }
714
LinkValidateVaryings(const sh::ShaderVariable & outputVarying,const sh::ShaderVariable & inputVarying,int shaderVersion,ShaderType frontShaderType,ShaderType backShaderType,bool isSeparable,std::string * mismatchedStructFieldName)715 LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
716 const sh::ShaderVariable &inputVarying,
717 int shaderVersion,
718 ShaderType frontShaderType,
719 ShaderType backShaderType,
720 bool isSeparable,
721 std::string *mismatchedStructFieldName)
722 {
723 // [ES 3.2 spec] 7.4.1 Shader Interface Matching:
724 // Tessellation control shader per-vertex output variables and blocks and tessellation control,
725 // tessellation evaluation, and geometry shader per-vertex input variables and blocks are
726 // required to be declared as arrays, with each element representing input or output values for
727 // a single vertex of a multi-vertex primitive. For the purposes of interface matching, such
728 // variables and blocks are treated as though they were not declared as arrays.
729 bool treatOutputAsNonArray =
730 (frontShaderType == ShaderType::TessControl && !outputVarying.isPatch);
731 bool treatInputAsNonArray =
732 ((backShaderType == ShaderType::TessControl ||
733 backShaderType == ShaderType::TessEvaluation || backShaderType == ShaderType::Geometry) &&
734 !inputVarying.isPatch);
735
736 // Skip the validation on the array sizes between a vertex output varying and a geometry input
737 // varying as it has been done before.
738 bool validatePrecision = isSeparable && (shaderVersion > 100);
739 LinkMismatchError linkError = LinkValidateProgramVariables(
740 outputVarying, inputVarying, validatePrecision, treatOutputAsNonArray, treatInputAsNonArray,
741 mismatchedStructFieldName);
742 if (linkError != LinkMismatchError::NO_MISMATCH)
743 {
744 return linkError;
745 }
746
747 // Explicit locations must match if the names match.
748 if (outputVarying.isSameNameAtLinkTime(inputVarying) &&
749 outputVarying.location != inputVarying.location)
750 {
751 return LinkMismatchError::LOCATION_MISMATCH;
752 }
753
754 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
755 {
756 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
757 }
758
759 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
760 {
761 return LinkMismatchError::INVARIANCE_MISMATCH;
762 }
763
764 return LinkMismatchError::NO_MISMATCH;
765 }
766
DoShaderVariablesMatch(int frontShaderVersion,ShaderType frontShaderType,ShaderType backShaderType,const sh::ShaderVariable & input,const sh::ShaderVariable & output,bool isSeparable,gl::InfoLog & infoLog)767 bool DoShaderVariablesMatch(int frontShaderVersion,
768 ShaderType frontShaderType,
769 ShaderType backShaderType,
770 const sh::ShaderVariable &input,
771 const sh::ShaderVariable &output,
772 bool isSeparable,
773 gl::InfoLog &infoLog)
774 {
775 bool namesMatch = input.isSameNameAtLinkTime(output);
776 bool locationsMatch = input.location != -1 && input.location == output.location;
777
778 // An output block is considered to match an input block in the subsequent
779 // shader if the two blocks have the same block name, and the members of the
780 // block match exactly in name, type, qualification, and declaration order.
781 //
782 // - For the purposes of shader interface matching, the gl_PointSize
783 // member of the intrinsically declared gl_PerVertex shader interface
784 // block is ignored.
785 // - Output blocks that do not match in name, but have a location and match
786 // in every other way listed above may be considered to match by some
787 // implementations, but not all - so this behaviour should not be relied
788 // upon.
789
790 // An output variable is considered to match an input variable in the subsequent
791 // shader if:
792 //
793 // - the two variables match in name, type, and qualification; or
794 // - the two variables are declared with the same location qualifier and
795 // match in type and qualification.
796
797 if (namesMatch || locationsMatch)
798 {
799 std::string mismatchedStructFieldName;
800 LinkMismatchError linkError =
801 LinkValidateVaryings(output, input, frontShaderVersion, frontShaderType, backShaderType,
802 isSeparable, &mismatchedStructFieldName);
803 if (linkError != LinkMismatchError::NO_MISMATCH)
804 {
805 LogLinkMismatch(infoLog, input.name, "varying", linkError, mismatchedStructFieldName,
806 frontShaderType, backShaderType);
807 return false;
808 }
809
810 return true;
811 }
812
813 return false;
814 }
815
GetInterfaceBlockTypeString(sh::BlockType blockType)816 const char *GetInterfaceBlockTypeString(sh::BlockType blockType)
817 {
818 switch (blockType)
819 {
820 case sh::BlockType::kBlockUniform:
821 return "uniform block";
822 case sh::BlockType::kBlockBuffer:
823 return "shader storage block";
824 default:
825 UNREACHABLE();
826 return "";
827 }
828 }
829
GetInterfaceBlockLimitName(ShaderType shaderType,sh::BlockType blockType)830 std::string GetInterfaceBlockLimitName(ShaderType shaderType, sh::BlockType blockType)
831 {
832 std::ostringstream stream;
833 stream << "GL_MAX_" << GetShaderTypeString(shaderType) << "_";
834
835 switch (blockType)
836 {
837 case sh::BlockType::kBlockUniform:
838 stream << "UNIFORM_BUFFERS";
839 break;
840 case sh::BlockType::kBlockBuffer:
841 stream << "SHADER_STORAGE_BLOCKS";
842 break;
843 default:
844 UNREACHABLE();
845 return "";
846 }
847
848 if (shaderType == ShaderType::Geometry)
849 {
850 stream << "_EXT";
851 }
852
853 return stream.str();
854 }
855
LogInterfaceBlocksExceedLimit(InfoLog & infoLog,ShaderType shaderType,sh::BlockType blockType,GLuint limit)856 void LogInterfaceBlocksExceedLimit(InfoLog &infoLog,
857 ShaderType shaderType,
858 sh::BlockType blockType,
859 GLuint limit)
860 {
861 infoLog << GetShaderTypeString(shaderType) << " shader "
862 << GetInterfaceBlockTypeString(blockType) << " count exceeds "
863 << GetInterfaceBlockLimitName(shaderType, blockType) << " (" << limit << ")";
864 }
865
ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,sh::BlockType blockType,GLuint * combinedInterfaceBlocksCount,InfoLog & infoLog)866 bool ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
867 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
868 ShaderType shaderType,
869 sh::BlockType blockType,
870 GLuint *combinedInterfaceBlocksCount,
871 InfoLog &infoLog)
872 {
873 GLuint blockCount = 0;
874 for (const sh::InterfaceBlock &block : interfaceBlocks)
875 {
876 if (IsActiveInterfaceBlock(block))
877 {
878 blockCount += std::max(block.arraySize, 1u);
879 if (blockCount > maxInterfaceBlocks)
880 {
881 LogInterfaceBlocksExceedLimit(infoLog, shaderType, blockType, maxInterfaceBlocks);
882 return false;
883 }
884 }
885 }
886
887 // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
888 // If a uniform block is used by multiple shader stages, each such use counts separately
889 // against this combined limit.
890 // [OpenGL ES 3.1] Chapter 7.8 Page 111:
891 // If a shader storage block in a program is referenced by multiple shaders, each such
892 // reference counts separately against this combined limit.
893 if (combinedInterfaceBlocksCount)
894 {
895 *combinedInterfaceBlocksCount += blockCount;
896 }
897
898 return true;
899 }
900 } // anonymous namespace
901
902 // UsedUniform implementation
UsedUniform()903 UsedUniform::UsedUniform() {}
904
UsedUniform(GLenum typeIn,GLenum precisionIn,const std::string & nameIn,const std::vector<unsigned int> & arraySizesIn,const int bindingIn,const int offsetIn,const int locationIn,const int bufferIndexIn,const sh::BlockMemberInfo & blockInfoIn)905 UsedUniform::UsedUniform(GLenum typeIn,
906 GLenum precisionIn,
907 const std::string &nameIn,
908 const std::vector<unsigned int> &arraySizesIn,
909 const int bindingIn,
910 const int offsetIn,
911 const int locationIn,
912 const int bufferIndexIn,
913 const sh::BlockMemberInfo &blockInfoIn)
914 : typeInfo(&GetUniformTypeInfo(typeIn)),
915 bufferIndex(bufferIndexIn),
916 blockInfo(blockInfoIn),
917 outerArrayOffset(0)
918 {
919 type = typeIn;
920 precision = precisionIn;
921 name = nameIn;
922 arraySizes = arraySizesIn;
923 binding = bindingIn;
924 offset = offsetIn;
925 location = locationIn;
926 ASSERT(!isArrayOfArrays());
927 ASSERT(!isArray() || !isStruct());
928 }
929
UsedUniform(const UsedUniform & other)930 UsedUniform::UsedUniform(const UsedUniform &other)
931 {
932 *this = other;
933 }
934
operator =(const UsedUniform & other)935 UsedUniform &UsedUniform::operator=(const UsedUniform &other)
936 {
937 if (this != &other)
938 {
939 sh::ShaderVariable::operator=(other);
940 activeVariable = other.activeVariable;
941
942 typeInfo = other.typeInfo;
943 bufferIndex = other.bufferIndex;
944 blockInfo = other.blockInfo;
945 outerArraySizes = other.outerArraySizes;
946 outerArrayOffset = other.outerArrayOffset;
947 }
948 return *this;
949 }
950
~UsedUniform()951 UsedUniform::~UsedUniform() {}
952
953 // UniformLinker implementation
UniformLinker(const ShaderBitSet & activeShaderStages,const ShaderMap<std::vector<sh::ShaderVariable>> & shaderUniforms)954 UniformLinker::UniformLinker(const ShaderBitSet &activeShaderStages,
955 const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms)
956 : mActiveShaderStages(activeShaderStages), mShaderUniforms(shaderUniforms)
957 {}
958
959 UniformLinker::~UniformLinker() = default;
960
getResults(std::vector<LinkedUniform> * uniforms,std::vector<std::string> * uniformNames,std::vector<std::string> * uniformMappedNames,std::vector<UnusedUniform> * unusedUniformsOutOrNull,std::vector<VariableLocation> * uniformLocationsOutOrNull)961 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
962 std::vector<std::string> *uniformNames,
963 std::vector<std::string> *uniformMappedNames,
964 std::vector<UnusedUniform> *unusedUniformsOutOrNull,
965 std::vector<VariableLocation> *uniformLocationsOutOrNull)
966 {
967 uniforms->reserve(mUniforms.size());
968 uniformNames->reserve(mUniforms.size());
969 uniformMappedNames->reserve(mUniforms.size());
970 for (const UsedUniform &usedUniform : mUniforms)
971 {
972 uniforms->emplace_back(usedUniform);
973 uniformNames->emplace_back(usedUniform.name);
974 uniformMappedNames->emplace_back(usedUniform.mappedName);
975 }
976
977 if (unusedUniformsOutOrNull)
978 {
979 unusedUniformsOutOrNull->swap(mUnusedUniforms);
980 }
981
982 if (uniformLocationsOutOrNull)
983 {
984 uniformLocationsOutOrNull->swap(mUniformLocations);
985 }
986 }
987
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)988 bool UniformLinker::link(const Caps &caps,
989 InfoLog &infoLog,
990 const ProgramAliasedBindings &uniformLocationBindings)
991 {
992 if (mActiveShaderStages[ShaderType::Vertex] && mActiveShaderStages[ShaderType::Fragment])
993 {
994 if (!validateGraphicsUniforms(infoLog))
995 {
996 return false;
997 }
998 }
999
1000 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1001 // Also check the maximum uniform vector and sampler counts.
1002 if (!flattenUniformsAndCheckCaps(caps, infoLog))
1003 {
1004 return false;
1005 }
1006
1007 if (!checkMaxCombinedAtomicCounters(caps, infoLog))
1008 {
1009 return false;
1010 }
1011
1012 if (!indexUniforms(infoLog, uniformLocationBindings))
1013 {
1014 return false;
1015 }
1016
1017 return true;
1018 }
1019
validateGraphicsUniforms(InfoLog & infoLog) const1020 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
1021 {
1022 // Check that uniforms defined in the graphics shaders are identical
1023 std::map<std::string, ShaderUniform> linkedUniforms;
1024
1025 for (const ShaderType shaderType : mActiveShaderStages)
1026 {
1027 if (shaderType == ShaderType::Vertex)
1028 {
1029 for (const sh::ShaderVariable &vertexUniform : mShaderUniforms[ShaderType::Vertex])
1030 {
1031 linkedUniforms[vertexUniform.name] =
1032 std::make_pair(ShaderType::Vertex, &vertexUniform);
1033 }
1034 }
1035 else
1036 {
1037 bool isLastShader = (shaderType == ShaderType::Fragment);
1038 if (!validateGraphicsUniformsPerShader(shaderType, !isLastShader, &linkedUniforms,
1039 infoLog))
1040 {
1041 return false;
1042 }
1043 }
1044 }
1045
1046 return true;
1047 }
1048
validateGraphicsUniformsPerShader(ShaderType shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog) const1049 bool UniformLinker::validateGraphicsUniformsPerShader(
1050 ShaderType shaderToLink,
1051 bool extendLinkedUniforms,
1052 std::map<std::string, ShaderUniform> *linkedUniforms,
1053 InfoLog &infoLog) const
1054 {
1055 ASSERT(mActiveShaderStages[shaderToLink] && linkedUniforms);
1056
1057 for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderToLink])
1058 {
1059 const auto &entry = linkedUniforms->find(uniform.name);
1060 if (entry != linkedUniforms->end())
1061 {
1062 const sh::ShaderVariable &linkedUniform = *(entry->second.second);
1063 std::string mismatchedStructFieldName;
1064 LinkMismatchError linkError =
1065 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
1066 if (linkError != LinkMismatchError::NO_MISMATCH)
1067 {
1068 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
1069 mismatchedStructFieldName, entry->second.first, shaderToLink);
1070 return false;
1071 }
1072 }
1073 else if (extendLinkedUniforms)
1074 {
1075 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink, &uniform);
1076 }
1077 }
1078
1079 return true;
1080 }
1081
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)1082 bool UniformLinker::indexUniforms(InfoLog &infoLog,
1083 const ProgramAliasedBindings &uniformLocationBindings)
1084 {
1085 // Locations which have been allocated for an unused uniform.
1086 std::set<GLuint> ignoredLocations;
1087
1088 int maxUniformLocation = -1;
1089
1090 // Gather uniform locations that have been set either using the bindUniformLocationCHROMIUM API
1091 // or by using a location layout qualifier and check conflicts between them.
1092 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
1093 &ignoredLocations, &maxUniformLocation))
1094 {
1095 return false;
1096 }
1097
1098 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
1099 // the line relies on only having statically used uniforms in mUniforms.
1100 pruneUnusedUniforms();
1101
1102 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
1103 std::vector<VariableLocation> unlocatedUniforms;
1104 std::map<GLuint, VariableLocation> preLocatedUniforms;
1105
1106 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1107 {
1108 const UsedUniform &uniform = mUniforms[uniformIndex];
1109
1110 if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
1111 IsAtomicCounterType(uniform.type) || uniform.isFragmentInOut)
1112 {
1113 continue;
1114 }
1115
1116 int preSetLocation = uniformLocationBindings.getBinding(uniform);
1117 int shaderLocation = uniform.location;
1118
1119 if (shaderLocation != -1)
1120 {
1121 preSetLocation = shaderLocation;
1122 }
1123
1124 unsigned int elementCount = uniform.getBasicTypeElementCount();
1125 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1126 {
1127 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
1128
1129 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
1130 {
1131 int elementLocation = preSetLocation + arrayIndex;
1132 preLocatedUniforms[elementLocation] = location;
1133 }
1134 else
1135 {
1136 unlocatedUniforms.push_back(location);
1137 }
1138 }
1139 }
1140
1141 // Make enough space for all uniforms, with pre-set locations or not.
1142 mUniformLocations.resize(
1143 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
1144 static_cast<size_t>(maxUniformLocation + 1)));
1145
1146 // Assign uniforms with pre-set locations
1147 for (const auto &uniform : preLocatedUniforms)
1148 {
1149 mUniformLocations[uniform.first] = uniform.second;
1150 }
1151
1152 // Assign ignored uniforms
1153 for (const auto &ignoredLocation : ignoredLocations)
1154 {
1155 mUniformLocations[ignoredLocation].markIgnored();
1156 }
1157
1158 // Automatically assign locations for the rest of the uniforms
1159 size_t nextUniformLocation = 0;
1160 for (const auto &unlocatedUniform : unlocatedUniforms)
1161 {
1162 while (mUniformLocations[nextUniformLocation].used() ||
1163 mUniformLocations[nextUniformLocation].ignored)
1164 {
1165 nextUniformLocation++;
1166 }
1167
1168 ASSERT(nextUniformLocation < mUniformLocations.size());
1169 mUniformLocations[nextUniformLocation] = unlocatedUniform;
1170 nextUniformLocation++;
1171 }
1172
1173 return true;
1174 }
1175
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)1176 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
1177 InfoLog &infoLog,
1178 const ProgramAliasedBindings &uniformLocationBindings,
1179 std::set<GLuint> *ignoredLocations,
1180 int *maxUniformLocation)
1181 {
1182 // All the locations where another uniform can't be located.
1183 std::set<GLuint> reservedLocations;
1184
1185 for (const UsedUniform &uniform : mUniforms)
1186 {
1187 if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) || uniform.isFragmentInOut)
1188 {
1189 // The uniform of the fragment inout is not a normal uniform type. So, in the case of
1190 // the fragment inout, this routine should be skipped.
1191 continue;
1192 }
1193
1194 int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
1195 int shaderLocation = uniform.location;
1196
1197 if (shaderLocation != -1)
1198 {
1199 unsigned int elementCount = uniform.getBasicTypeElementCount();
1200
1201 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1202 {
1203 // GLSL ES 3.10 section 4.4.3
1204 int elementLocation = shaderLocation + arrayIndex;
1205 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
1206 if (reservedLocations.find(elementLocation) != reservedLocations.end())
1207 {
1208 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
1209 return false;
1210 }
1211 reservedLocations.insert(elementLocation);
1212 if (!uniform.active)
1213 {
1214 ignoredLocations->insert(elementLocation);
1215 }
1216 }
1217 }
1218 else if (apiBoundLocation != -1 && uniform.staticUse)
1219 {
1220 // Only the first location is reserved even if the uniform is an array.
1221 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
1222 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
1223 {
1224 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
1225 return false;
1226 }
1227 reservedLocations.insert(apiBoundLocation);
1228 if (!uniform.active)
1229 {
1230 ignoredLocations->insert(apiBoundLocation);
1231 }
1232 }
1233 }
1234
1235 // Record the uniform locations that were bound using the API for uniforms that were not found
1236 // from the shader. Other uniforms should not be assigned to those locations.
1237 for (const auto &locationBinding : uniformLocationBindings)
1238 {
1239 GLuint location = locationBinding.second.location;
1240 if (reservedLocations.find(location) == reservedLocations.end())
1241 {
1242 ignoredLocations->insert(location);
1243 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
1244 }
1245 }
1246
1247 return true;
1248 }
1249
pruneUnusedUniforms()1250 void UniformLinker::pruneUnusedUniforms()
1251 {
1252 auto uniformIter = mUniforms.begin();
1253 while (uniformIter != mUniforms.end())
1254 {
1255 if (uniformIter->active)
1256 {
1257 ++uniformIter;
1258 }
1259 else
1260 {
1261 mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
1262 uniformIter->isImage(), uniformIter->isAtomicCounter(),
1263 uniformIter->isFragmentInOut);
1264 uniformIter = mUniforms.erase(uniformIter);
1265 }
1266 }
1267 }
1268
flattenUniformsAndCheckCapsForShader(ShaderType shaderType,const Caps & caps,std::vector<UsedUniform> & samplerUniforms,std::vector<UsedUniform> & imageUniforms,std::vector<UsedUniform> & atomicCounterUniforms,std::vector<UsedUniform> & inputAttachmentUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)1269 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
1270 ShaderType shaderType,
1271 const Caps &caps,
1272 std::vector<UsedUniform> &samplerUniforms,
1273 std::vector<UsedUniform> &imageUniforms,
1274 std::vector<UsedUniform> &atomicCounterUniforms,
1275 std::vector<UsedUniform> &inputAttachmentUniforms,
1276 std::vector<UnusedUniform> &unusedUniforms,
1277 InfoLog &infoLog)
1278 {
1279 ShaderUniformCount shaderUniformCount;
1280 for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderType])
1281 {
1282 FlattenUniformVisitor flattener(shaderType, uniform, &mUniforms, &samplerUniforms,
1283 &imageUniforms, &atomicCounterUniforms,
1284 &inputAttachmentUniforms, &unusedUniforms);
1285 sh::TraverseShaderVariable(uniform, false, &flattener);
1286
1287 if (uniform.active)
1288 {
1289 shaderUniformCount += flattener.getCounts();
1290 }
1291 else
1292 {
1293 unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
1294 IsImageType(uniform.type),
1295 IsAtomicCounterType(uniform.type), uniform.isFragmentInOut);
1296 }
1297 }
1298
1299 // This code does not do fine-grained component counting.
1300 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
1301 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
1302 {
1303 GLuint maxUniforms = 0u;
1304
1305 // See comments in GetUniformResourceLimitName()
1306 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
1307 {
1308 maxUniforms = maxUniformVectorsCount;
1309 }
1310 else
1311 {
1312 maxUniforms = maxUniformVectorsCount * 4;
1313 }
1314
1315 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
1316 return false;
1317 }
1318
1319 if (shaderUniformCount.samplerCount >
1320 static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
1321 {
1322 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
1323 caps.maxShaderTextureImageUnits[shaderType], infoLog);
1324 return false;
1325 }
1326
1327 if (shaderUniformCount.imageCount >
1328 static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
1329 {
1330 LogUniformsExceedLimit(shaderType, UniformType::Image,
1331 caps.maxShaderImageUniforms[shaderType], infoLog);
1332 return false;
1333 }
1334
1335 if (shaderUniformCount.atomicCounterCount >
1336 static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
1337 {
1338 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
1339 caps.maxShaderAtomicCounters[shaderType], infoLog);
1340 return false;
1341 }
1342
1343 return true;
1344 }
1345
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1346 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1347 {
1348 std::vector<UsedUniform> samplerUniforms;
1349 std::vector<UsedUniform> imageUniforms;
1350 std::vector<UsedUniform> atomicCounterUniforms;
1351 std::vector<UsedUniform> inputAttachmentUniforms;
1352 std::vector<UnusedUniform> unusedUniforms;
1353
1354 for (const ShaderType shaderType : mActiveShaderStages)
1355 {
1356 if (!flattenUniformsAndCheckCapsForShader(shaderType, caps, samplerUniforms, imageUniforms,
1357 atomicCounterUniforms, inputAttachmentUniforms,
1358 unusedUniforms, infoLog))
1359 {
1360 return false;
1361 }
1362 }
1363
1364 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1365 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1366 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1367 mUniforms.insert(mUniforms.end(), inputAttachmentUniforms.begin(),
1368 inputAttachmentUniforms.end());
1369 mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1370 return true;
1371 }
1372
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1373 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1374 {
1375 unsigned int atomicCounterCount = 0;
1376 for (const auto &uniform : mUniforms)
1377 {
1378 if (IsAtomicCounterType(uniform.type) && uniform.active)
1379 {
1380 atomicCounterCount += uniform.getBasicTypeElementCount();
1381 if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1382 {
1383 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1384 << caps.maxCombinedAtomicCounters << ").";
1385 return false;
1386 }
1387 }
1388 }
1389 return true;
1390 }
1391
1392 // InterfaceBlockLinker implementation.
1393 InterfaceBlockLinker::InterfaceBlockLinker() = default;
1394
1395 InterfaceBlockLinker::~InterfaceBlockLinker() = default;
1396
init(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1397 void InterfaceBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1398 std::vector<std::string> *unusedInterfaceBlocksOut)
1399 {
1400 mBlocksOut = blocksOut;
1401 mUnusedInterfaceBlocksOut = unusedInterfaceBlocksOut;
1402 }
1403
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1404 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1405 const std::vector<sh::InterfaceBlock> *blocks)
1406 {
1407 mShaderBlocks[shaderType] = blocks;
1408 }
1409
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1410 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1411 const GetBlockMemberInfoFunc &getMemberInfo) const
1412 {
1413 ASSERT(mBlocksOut->empty());
1414
1415 std::set<std::string> visitedList;
1416
1417 for (const ShaderType shaderType : AllShaderTypes())
1418 {
1419 if (!mShaderBlocks[shaderType])
1420 {
1421 continue;
1422 }
1423
1424 for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1425 {
1426 if (!IsActiveInterfaceBlock(block))
1427 {
1428 mUnusedInterfaceBlocksOut->push_back(block.name);
1429 continue;
1430 }
1431
1432 if (visitedList.count(block.name) == 0)
1433 {
1434 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1435 visitedList.insert(block.name);
1436 continue;
1437 }
1438
1439 if (!block.active)
1440 {
1441 mUnusedInterfaceBlocksOut->push_back(block.name);
1442 continue;
1443 }
1444
1445 for (InterfaceBlock &priorBlock : *mBlocksOut)
1446 {
1447 if (block.name == priorBlock.name)
1448 {
1449 priorBlock.setActive(shaderType, true, block.id);
1450
1451 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1452 getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1453 shaderType, -1));
1454
1455 sh::TraverseShaderVariables(block.fields, false, visitor.get());
1456 }
1457 }
1458 }
1459 }
1460 }
1461
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1462 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1463 const GetBlockMemberInfoFunc &getMemberInfo,
1464 const sh::InterfaceBlock &interfaceBlock,
1465 ShaderType shaderType) const
1466 {
1467 size_t blockSize = 0;
1468 std::vector<unsigned int> blockIndexes;
1469
1470 const int blockIndex = static_cast<int>(mBlocksOut->size());
1471 // Track the first and last block member index to determine the range of active block members in
1472 // the block.
1473 const size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1474
1475 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1476 getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1477 shaderType, blockIndex));
1478 sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1479
1480 const size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1481
1482 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1483 ++blockMemberIndex)
1484 {
1485 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1486 }
1487
1488 const unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1489
1490 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1491 ++arrayElement)
1492 {
1493 std::string blockArrayName = interfaceBlock.name;
1494 std::string blockMappedArrayName = interfaceBlock.mappedName;
1495 if (interfaceBlock.isArray())
1496 {
1497 blockArrayName += ArrayString(arrayElement);
1498 blockMappedArrayName += ArrayString(arrayElement);
1499 }
1500
1501 // Don't define this block at all if it's not active in the implementation.
1502 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1503 {
1504 continue;
1505 }
1506
1507 // ESSL 3.10 section 4.4.4 page 58:
1508 // Any uniform or shader storage block declared without a binding qualifier is initially
1509 // assigned to block binding point zero.
1510 const int blockBinding =
1511 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1512 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1513 interfaceBlock.isArray(), interfaceBlock.isReadOnly, arrayElement,
1514 firstFieldArraySize, blockBinding);
1515 block.memberIndexes = blockIndexes;
1516 block.setActive(shaderType, interfaceBlock.active, interfaceBlock.id);
1517
1518 // Since all block elements in an array share the same active interface blocks, they
1519 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1520 // was active, here we will add every block element in the array.
1521 block.pod.dataSize = static_cast<unsigned int>(blockSize);
1522 mBlocksOut->push_back(block);
1523 }
1524 }
1525
1526 // UniformBlockLinker implementation.
1527 UniformBlockLinker::UniformBlockLinker() = default;
1528
~UniformBlockLinker()1529 UniformBlockLinker::~UniformBlockLinker() {}
1530
init(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1531 void UniformBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1532 std::vector<LinkedUniform> *uniformsOut,
1533 std::vector<std::string> *uniformNamesOut,
1534 std::vector<std::string> *uniformMappedNamesOut,
1535 std::vector<std::string> *unusedInterfaceBlocksOut)
1536 {
1537 InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1538 mUniformsOut = uniformsOut;
1539 mUniformNamesOut = uniformNamesOut;
1540 mUniformMappedNamesOut = uniformMappedNamesOut;
1541 }
1542
getCurrentBlockMemberIndex() const1543 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1544 {
1545 return mUniformsOut->size();
1546 }
1547
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1548 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1549 const GetBlockMemberInfoFunc &getMemberInfo,
1550 const std::string &namePrefix,
1551 const std::string &mappedNamePrefix,
1552 ShaderType shaderType,
1553 int blockIndex) const
1554 {
1555 return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1556 mUniformsOut, mUniformNamesOut, mUniformMappedNamesOut,
1557 shaderType, blockIndex);
1558 }
1559
1560 // ShaderStorageBlockLinker implementation.
1561 ShaderStorageBlockLinker::ShaderStorageBlockLinker() = default;
1562
1563 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() = default;
1564
init(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1565 void ShaderStorageBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1566 std::vector<BufferVariable> *bufferVariablesOut,
1567 std::vector<std::string> *unusedInterfaceBlocksOut)
1568 {
1569 InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1570 mBufferVariablesOut = bufferVariablesOut;
1571 }
1572
getCurrentBlockMemberIndex() const1573 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1574 {
1575 return mBufferVariablesOut->size();
1576 }
1577
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1578 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1579 const GetBlockMemberInfoFunc &getMemberInfo,
1580 const std::string &namePrefix,
1581 const std::string &mappedNamePrefix,
1582 ShaderType shaderType,
1583 int blockIndex) const
1584 {
1585 return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1586 mBufferVariablesOut, shaderType, blockIndex);
1587 }
1588
1589 // AtomicCounterBufferLinker implementation.
1590 AtomicCounterBufferLinker::AtomicCounterBufferLinker() = default;
1591
1592 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() = default;
1593
init(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1594 void AtomicCounterBufferLinker::init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1595 {
1596 mAtomicCounterBuffersOut = atomicCounterBuffersOut;
1597 }
1598
link(const std::map<int,unsigned int> & sizeMap) const1599 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1600 {
1601 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1602 {
1603 auto bufferSize = sizeMap.find(atomicCounterBuffer.pod.inShaderBinding);
1604 ASSERT(bufferSize != sizeMap.end());
1605 atomicCounterBuffer.pod.dataSize = bufferSize->second;
1606 }
1607 }
1608
1609 LinkingVariables::LinkingVariables() = default;
1610 LinkingVariables::~LinkingVariables() = default;
1611
initForProgram(const ProgramState & state)1612 void LinkingVariables::initForProgram(const ProgramState &state)
1613 {
1614 for (ShaderType shaderType : kAllGraphicsShaderTypes)
1615 {
1616 const SharedCompiledShaderState &shader = state.getAttachedShader(shaderType);
1617 if (shader)
1618 {
1619 outputVaryings[shaderType] = shader->outputVaryings;
1620 inputVaryings[shaderType] = shader->inputVaryings;
1621 uniforms[shaderType] = shader->uniforms;
1622 uniformBlocks[shaderType] = shader->uniformBlocks;
1623 isShaderStageUsedBitset.set(shaderType);
1624 }
1625 }
1626 }
1627
initForProgramPipeline(const ProgramPipelineState & state)1628 void LinkingVariables::initForProgramPipeline(const ProgramPipelineState &state)
1629 {
1630 for (ShaderType shaderType : state.getExecutable().getLinkedShaderStages())
1631 {
1632 const SharedProgramExecutable &executable = state.getShaderProgramExecutable(shaderType);
1633 ASSERT(executable);
1634 outputVaryings[shaderType] = executable->getLinkedOutputVaryings(shaderType);
1635 inputVaryings[shaderType] = executable->getLinkedInputVaryings(shaderType);
1636 uniforms[shaderType] = executable->getLinkedUniforms(shaderType);
1637 uniformBlocks[shaderType] = executable->getLinkedUniformBlocks(shaderType);
1638 isShaderStageUsedBitset.set(shaderType);
1639 }
1640 }
1641
1642 ProgramLinkedResources::ProgramLinkedResources() = default;
1643 ProgramLinkedResources::~ProgramLinkedResources() = default;
1644
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1645 void ProgramLinkedResources::init(std::vector<InterfaceBlock> *uniformBlocksOut,
1646 std::vector<LinkedUniform> *uniformsOut,
1647 std::vector<std::string> *uniformNamesOut,
1648 std::vector<std::string> *uniformMappedNamesOut,
1649 std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1650 std::vector<BufferVariable> *bufferVariablesOut,
1651 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1652 {
1653 uniformBlockLinker.init(uniformBlocksOut, uniformsOut, uniformNamesOut, uniformMappedNamesOut,
1654 &unusedInterfaceBlocks);
1655 shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1656 &unusedInterfaceBlocks);
1657 atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1658 }
1659
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1660 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1661 const ProgramLinkedResources &resources) const
1662 {
1663 // Gather uniform interface block info.
1664 InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1665 for (const ShaderType shaderType : AllShaderTypes())
1666 {
1667 const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1668 if (shader)
1669 {
1670 uniformBlockInfo.getShaderBlockInfo(shader->uniformBlocks);
1671 }
1672 }
1673
1674 auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1675 const std::string &mappedName, size_t *sizeOut) {
1676 return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1677 };
1678
1679 auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1680 const std::string &mappedName,
1681 sh::BlockMemberInfo *infoOut) {
1682 return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1683 };
1684
1685 // Link uniform interface blocks.
1686 resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1687
1688 // Gather storage buffer interface block info.
1689 InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1690 for (const ShaderType shaderType : AllShaderTypes())
1691 {
1692 const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1693 if (shader)
1694 {
1695 shaderStorageBlockInfo.getShaderBlockInfo(shader->shaderStorageBlocks);
1696 }
1697 }
1698 auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1699 const std::string &mappedName,
1700 size_t *sizeOut) {
1701 return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1702 };
1703
1704 auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1705 const std::string &mappedName,
1706 sh::BlockMemberInfo *infoOut) {
1707 return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1708 };
1709
1710 // Link storage buffer interface blocks.
1711 resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1712 getShaderStorageBlockMemberInfo);
1713
1714 // Gather and link atomic counter buffer interface blocks.
1715 std::map<int, unsigned int> sizeMap;
1716 getAtomicCounterBufferSizeMap(programState.getExecutable(), sizeMap);
1717 resources.atomicCounterBufferLinker.link(sizeMap);
1718 }
1719
getAtomicCounterBufferSizeMap(const ProgramExecutable & executable,std::map<int,unsigned int> & sizeMapOut) const1720 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1721 const ProgramExecutable &executable,
1722 std::map<int, unsigned int> &sizeMapOut) const
1723 {
1724 for (unsigned int index : executable.getAtomicCounterUniformRange())
1725 {
1726 const LinkedUniform &glUniform = executable.getUniforms()[index];
1727
1728 auto &bufferDataSize = sizeMapOut[glUniform.getBinding()];
1729
1730 // Calculate the size of the buffer by finding the end of the last uniform with the same
1731 // binding. The end of the uniform is calculated by finding the initial offset of the
1732 // uniform and adding size of the uniform. For arrays, the size is the number of elements
1733 // times the element size (should always by 4 for atomic_units).
1734 unsigned dataOffset =
1735 glUniform.getOffset() + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1736 glUniform.getElementSize());
1737 if (dataOffset > bufferDataSize)
1738 {
1739 bufferDataSize = dataOffset;
1740 }
1741 }
1742 }
1743
LinkValidateProgramGlobalNames(InfoLog & infoLog,const ProgramExecutable & executable,const LinkingVariables & linkingVariables)1744 bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
1745 const ProgramExecutable &executable,
1746 const LinkingVariables &linkingVariables)
1747 {
1748 angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1749 using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1750 angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1751
1752 for (ShaderType shaderType : kAllGraphicsShaderTypes)
1753 {
1754 if (!linkingVariables.isShaderStageUsedBitset[shaderType])
1755 {
1756 continue;
1757 }
1758
1759 // Build a map of Uniforms
1760 const std::vector<sh::ShaderVariable> &uniforms = linkingVariables.uniforms[shaderType];
1761 for (const auto &uniform : uniforms)
1762 {
1763 uniformMap[uniform.name] = &uniform;
1764 }
1765
1766 // Build a map of Uniform Blocks
1767 // This will also detect any field name conflicts between Uniform Blocks without instance
1768 // names
1769 const std::vector<sh::InterfaceBlock> &uniformBlocks =
1770 linkingVariables.uniformBlocks[shaderType];
1771
1772 for (const auto &uniformBlock : uniformBlocks)
1773 {
1774 // Only uniform blocks without an instance name can create a conflict with their field
1775 // names
1776 if (!uniformBlock.instanceName.empty())
1777 {
1778 continue;
1779 }
1780
1781 for (const auto &field : uniformBlock.fields)
1782 {
1783 if (!uniformBlockFieldMap.count(field.name))
1784 {
1785 // First time we've seen this uniform block field name, so add the
1786 // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1787 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1788 std::vector<BlockAndFieldPair> newUniformBlockList;
1789 newUniformBlockList.push_back(blockAndFieldPair);
1790 uniformBlockFieldMap[field.name] = newUniformBlockList;
1791 continue;
1792 }
1793
1794 // We've seen this name before.
1795 // We need to check each of the uniform blocks that contain a field with this name
1796 // to see if there's a conflict or not.
1797 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1798 uniformBlockFieldMap[field.name];
1799 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1800 {
1801 const sh::InterfaceBlock *prevUniformBlock = prevBlockFieldPair.first;
1802 const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1803
1804 if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1805 {
1806 // The same uniform block should, by definition, contain the same field name
1807 continue;
1808 }
1809
1810 // The uniform blocks don't match, so check if the necessary field properties
1811 // also match
1812 if ((field.name == prevUniformBlockField->name) &&
1813 (field.type == prevUniformBlockField->type) &&
1814 (field.precision == prevUniformBlockField->precision))
1815 {
1816 infoLog << "Name conflicts between uniform block field names: "
1817 << field.name;
1818 return false;
1819 }
1820 }
1821
1822 // No conflict, so record this pair
1823 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1824 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1825 }
1826 }
1827 }
1828
1829 // Validate no uniform names conflict with attribute names
1830 if (linkingVariables.isShaderStageUsedBitset[ShaderType::Vertex])
1831 {
1832 // ESSL 3.00.6 section 4.3.5:
1833 // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1834 // but not in another (e.g., a fragment shader), then that name is still
1835 // available in the other stage for a different use.
1836 std::unordered_set<std::string> uniforms;
1837 for (const sh::ShaderVariable &uniform : linkingVariables.uniforms[ShaderType::Vertex])
1838 {
1839 uniforms.insert(uniform.name);
1840 }
1841 for (const auto &attrib : executable.getProgramInputs())
1842 {
1843 if (uniforms.count(attrib.name))
1844 {
1845 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1846 return false;
1847 }
1848 }
1849 }
1850
1851 // Validate no Uniform Block fields conflict with other Uniforms
1852 for (const auto &uniformBlockField : uniformBlockFieldMap)
1853 {
1854 const std::string &fieldName = uniformBlockField.first;
1855 if (uniformMap.count(fieldName))
1856 {
1857 infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1858 return false;
1859 }
1860 }
1861
1862 return true;
1863 }
1864
1865 // [OpenGL ES 3.2] Chapter 7.4.1 "Shader Interface Matching"
LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType frontShaderType,ShaderType backShaderType,int frontShaderVersion,int backShaderVersion,bool isSeparable,gl::InfoLog & infoLog)1866 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1867 const std::vector<sh::ShaderVariable> &inputVaryings,
1868 ShaderType frontShaderType,
1869 ShaderType backShaderType,
1870 int frontShaderVersion,
1871 int backShaderVersion,
1872 bool isSeparable,
1873 gl::InfoLog &infoLog)
1874 {
1875 ASSERT(frontShaderVersion == backShaderVersion);
1876
1877 std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1878 std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1879
1880 GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1881 GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1882
1883 // Separable programs require the number of inputs and outputs match
1884 if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1885 {
1886 infoLog << GetShaderTypeString(backShaderType)
1887 << " does not consume all varyings generated by "
1888 << GetShaderTypeString(frontShaderType);
1889 return false;
1890 }
1891 if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1892 {
1893 infoLog << GetShaderTypeString(frontShaderType)
1894 << " does not generate all varyings consumed by "
1895 << GetShaderTypeString(backShaderType);
1896 return false;
1897 }
1898
1899 // All inputs must match all outputs
1900 for (const sh::ShaderVariable *input : filteredInputVaryings)
1901 {
1902 bool match = false;
1903 for (const sh::ShaderVariable *output : filteredOutputVaryings)
1904 {
1905 if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1906 *output, isSeparable, infoLog))
1907 {
1908 match = true;
1909 break;
1910 }
1911 }
1912
1913 // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1914 // whether the input is statically used - a statically used input should fail this test even
1915 // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1916 if (!match && input->staticUse)
1917 {
1918 const std::string &name =
1919 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1920 infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1921 << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1922 return false;
1923 }
1924 }
1925
1926 return true;
1927 }
1928
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1929 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1930 const sh::ShaderVariable &variable2,
1931 bool validatePrecision,
1932 bool treatVariable1AsNonArray,
1933 bool treatVariable2AsNonArray,
1934 std::string *mismatchedStructOrBlockMemberName)
1935 {
1936 if (variable1.type != variable2.type)
1937 {
1938 return LinkMismatchError::TYPE_MISMATCH;
1939 }
1940
1941 bool variable1IsArray = variable1.isArray();
1942 bool variable2IsArray = variable2.isArray();
1943 if (treatVariable1AsNonArray)
1944 {
1945 ASSERT(variable1IsArray);
1946 variable1IsArray = false;
1947 }
1948 if (treatVariable2AsNonArray)
1949 {
1950 ASSERT(variable2IsArray);
1951 variable2IsArray = false;
1952 }
1953 // TODO(anglebug.com/5557): Investigate interactions with arrays-of-arrays.
1954 if (variable1IsArray != variable2IsArray)
1955 {
1956 return LinkMismatchError::ARRAYNESS_MISMATCH;
1957 }
1958 if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1959 variable1.arraySizes != variable2.arraySizes)
1960 {
1961 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1962 }
1963 if (validatePrecision && variable1.precision != variable2.precision)
1964 {
1965 return LinkMismatchError::PRECISION_MISMATCH;
1966 }
1967 if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1968 variable1.structOrBlockName != variable2.structOrBlockName)
1969 {
1970 return LinkMismatchError::STRUCT_NAME_MISMATCH;
1971 }
1972 if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1973 {
1974 return LinkMismatchError::FORMAT_MISMATCH;
1975 }
1976
1977 if (variable1.fields.size() != variable2.fields.size())
1978 {
1979 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
1980 }
1981 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
1982 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1983 {
1984 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
1985 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
1986
1987 if (member1.name != member2.name)
1988 {
1989 return LinkMismatchError::FIELD_NAME_MISMATCH;
1990 }
1991
1992 if (member1.interpolation != member2.interpolation)
1993 {
1994 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
1995 }
1996
1997 if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
1998 {
1999 if (member1.location != member2.location)
2000 {
2001 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
2002 }
2003
2004 if (member1.structOrBlockName != member2.structOrBlockName)
2005 {
2006 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
2007 }
2008 }
2009
2010 LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
2011 member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
2012 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
2013 {
2014 AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2015 return linkErrorOnField;
2016 }
2017 }
2018
2019 return LinkMismatchError::NO_MISMATCH;
2020 }
2021
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)2022 void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
2023 {
2024 ASSERT(mismatchedFieldName);
2025 if (mismatchedFieldName->empty())
2026 {
2027 *mismatchedFieldName = parentName;
2028 }
2029 else
2030 {
2031 std::ostringstream stream;
2032 stream << parentName << "." << *mismatchedFieldName;
2033 *mismatchedFieldName = stream.str();
2034 }
2035 }
2036
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)2037 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
2038 const std::vector<sh::ShaderVariable> &fragmentVaryings,
2039 int vertexShaderVersion,
2040 InfoLog &infoLog)
2041 {
2042 bool glPositionIsInvariant = false;
2043 bool glPointSizeIsInvariant = false;
2044 bool glFragCoordIsInvariant = false;
2045 bool glPointCoordIsInvariant = false;
2046
2047 for (const sh::ShaderVariable &varying : vertexVaryings)
2048 {
2049 if (!varying.isBuiltIn())
2050 {
2051 continue;
2052 }
2053 if (varying.name.compare("gl_Position") == 0)
2054 {
2055 glPositionIsInvariant = varying.isInvariant;
2056 }
2057 else if (varying.name.compare("gl_PointSize") == 0)
2058 {
2059 glPointSizeIsInvariant = varying.isInvariant;
2060 }
2061 }
2062
2063 for (const sh::ShaderVariable &varying : fragmentVaryings)
2064 {
2065 if (!varying.isBuiltIn())
2066 {
2067 continue;
2068 }
2069 if (varying.name.compare("gl_FragCoord") == 0)
2070 {
2071 glFragCoordIsInvariant = varying.isInvariant;
2072 }
2073 else if (varying.name.compare("gl_PointCoord") == 0)
2074 {
2075 glPointCoordIsInvariant = varying.isInvariant;
2076 }
2077 }
2078
2079 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2080 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2081 // Not requiring invariance to match is supported by:
2082 // dEQP, WebGL CTS, Nexus 5X GLES
2083 if (glFragCoordIsInvariant && !glPositionIsInvariant)
2084 {
2085 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2086 "declared invariant.";
2087 return false;
2088 }
2089 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2090 {
2091 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2092 "declared invariant.";
2093 return false;
2094 }
2095
2096 return true;
2097 }
2098
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)2099 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
2100 const std::vector<sh::ShaderVariable> &inputVaryings,
2101 ShaderType outputShaderType,
2102 ShaderType inputShaderType,
2103 int outputShaderVersion,
2104 int inputShaderVersion,
2105 InfoLog &infoLog)
2106 {
2107 ASSERT(outputShaderVersion == inputShaderVersion);
2108
2109 // Only ESSL 1.0 has restrictions on matching input and output invariance
2110 if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
2111 inputShaderType == ShaderType::Fragment)
2112 {
2113 return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
2114 outputShaderVersion, infoLog);
2115 }
2116
2117 uint32_t sizeClipDistance = 0;
2118 uint32_t sizeCullDistance = 0;
2119
2120 for (const sh::ShaderVariable &varying : outputVaryings)
2121 {
2122 if (!varying.isBuiltIn())
2123 {
2124 continue;
2125 }
2126 if (varying.name.compare("gl_ClipDistance") == 0)
2127 {
2128 sizeClipDistance = varying.getOutermostArraySize();
2129 }
2130 else if (varying.name.compare("gl_CullDistance") == 0)
2131 {
2132 sizeCullDistance = varying.getOutermostArraySize();
2133 }
2134 }
2135
2136 for (const sh::ShaderVariable &varying : inputVaryings)
2137 {
2138 if (!varying.isBuiltIn())
2139 {
2140 continue;
2141 }
2142 if (varying.name.compare("gl_ClipDistance") == 0)
2143 {
2144 if (sizeClipDistance != varying.getOutermostArraySize())
2145 {
2146 infoLog
2147 << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2148 "the array must have the same size as in the previous shader stage. "
2149 << "Output size " << sizeClipDistance << ", input size "
2150 << varying.getOutermostArraySize() << ".";
2151 return false;
2152 }
2153 }
2154 else if (varying.name.compare("gl_CullDistance") == 0)
2155 {
2156 if (sizeCullDistance != varying.getOutermostArraySize())
2157 {
2158 infoLog
2159 << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2160 "the array must have the same size as in the previous shader stage. "
2161 << "Output size " << sizeCullDistance << ", input size "
2162 << varying.getOutermostArraySize() << ".";
2163
2164 return false;
2165 }
2166 }
2167 }
2168 return true;
2169 }
2170
LogAmbiguousFieldLinkMismatch(InfoLog & infoLog,const std::string & blockName1,const std::string & blockName2,const std::string & fieldName,ShaderType shaderType1,ShaderType shaderType2)2171 void LogAmbiguousFieldLinkMismatch(InfoLog &infoLog,
2172 const std::string &blockName1,
2173 const std::string &blockName2,
2174 const std::string &fieldName,
2175 ShaderType shaderType1,
2176 ShaderType shaderType2)
2177 {
2178 infoLog << "Ambiguous field '" << fieldName << "' in blocks '" << blockName1 << "' ("
2179 << GetShaderTypeString(shaderType1) << " shader) and '" << blockName2 << "' ("
2180 << GetShaderTypeString(shaderType2) << " shader) which don't have instance names.";
2181 }
2182
ValidateInstancelessGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * instancelessBlocksFields,InfoLog & infoLog)2183 bool ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2184 const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2185 ShaderType shaderType,
2186 InterfaceBlockMap *instancelessBlocksFields,
2187 InfoLog &infoLog)
2188 {
2189 ASSERT(instancelessBlocksFields);
2190
2191 for (const sh::InterfaceBlock &block : interfaceBlocks)
2192 {
2193 if (!block.instanceName.empty())
2194 {
2195 continue;
2196 }
2197
2198 for (const sh::ShaderVariable &field : block.fields)
2199 {
2200 const auto &entry = instancelessBlocksFields->find(field.name);
2201 if (entry != instancelessBlocksFields->end())
2202 {
2203 const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2204 if (block.name != linkedBlock.name)
2205 {
2206 LogAmbiguousFieldLinkMismatch(infoLog, block.name, linkedBlock.name, field.name,
2207 entry->second.first, shaderType);
2208 return false;
2209 }
2210 }
2211 else
2212 {
2213 (*instancelessBlocksFields)[field.name] = std::make_pair(shaderType, &block);
2214 }
2215 }
2216 }
2217
2218 return true;
2219 }
2220
LinkValidateInterfaceBlockFields(const sh::ShaderVariable & blockField1,const sh::ShaderVariable & blockField2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2221 LinkMismatchError LinkValidateInterfaceBlockFields(const sh::ShaderVariable &blockField1,
2222 const sh::ShaderVariable &blockField2,
2223 bool webglCompatibility,
2224 std::string *mismatchedBlockFieldName)
2225 {
2226 if (blockField1.name != blockField2.name)
2227 {
2228 return LinkMismatchError::FIELD_NAME_MISMATCH;
2229 }
2230
2231 // If webgl, validate precision of UBO fields, otherwise don't. See Khronos bug 10287.
2232 LinkMismatchError linkError = LinkValidateProgramVariables(
2233 blockField1, blockField2, webglCompatibility, false, false, mismatchedBlockFieldName);
2234 if (linkError != LinkMismatchError::NO_MISMATCH)
2235 {
2236 AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2237 return linkError;
2238 }
2239
2240 if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
2241 {
2242 AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2243 return LinkMismatchError::MATRIX_PACKING_MISMATCH;
2244 }
2245
2246 return LinkMismatchError::NO_MISMATCH;
2247 }
2248
AreMatchingInterfaceBlocks(const sh::InterfaceBlock & interfaceBlock1,const sh::InterfaceBlock & interfaceBlock2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2249 LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2250 const sh::InterfaceBlock &interfaceBlock2,
2251 bool webglCompatibility,
2252 std::string *mismatchedBlockFieldName)
2253 {
2254 // validate blocks for the same member types
2255 if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
2256 {
2257 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
2258 }
2259 if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
2260 {
2261 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2262 }
2263 if (interfaceBlock1.layout != interfaceBlock2.layout ||
2264 interfaceBlock1.binding != interfaceBlock2.binding)
2265 {
2266 return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
2267 }
2268 if (interfaceBlock1.instanceName.empty() != interfaceBlock2.instanceName.empty())
2269 {
2270 return LinkMismatchError::INSTANCE_NAME_MISMATCH;
2271 }
2272 const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
2273 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2274 {
2275 const sh::ShaderVariable &member1 = interfaceBlock1.fields[blockMemberIndex];
2276 const sh::ShaderVariable &member2 = interfaceBlock2.fields[blockMemberIndex];
2277
2278 LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2279 member1, member2, webglCompatibility, mismatchedBlockFieldName);
2280 if (linkError != LinkMismatchError::NO_MISMATCH)
2281 {
2282 return linkError;
2283 }
2284 }
2285 return LinkMismatchError::NO_MISMATCH;
2286 }
2287
InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * linkedInterfaceBlocks)2288 void InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2289 ShaderType shaderType,
2290 InterfaceBlockMap *linkedInterfaceBlocks)
2291 {
2292 ASSERT(linkedInterfaceBlocks);
2293
2294 for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
2295 {
2296 (*linkedInterfaceBlocks)[interfaceBlock.name] = std::make_pair(shaderType, &interfaceBlock);
2297 }
2298 }
2299
ValidateGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocksToLink,ShaderType shaderType,bool webglCompatibility,InterfaceBlockMap * linkedBlocks,InfoLog & infoLog)2300 bool ValidateGraphicsInterfaceBlocksPerShader(
2301 const std::vector<sh::InterfaceBlock> &interfaceBlocksToLink,
2302 ShaderType shaderType,
2303 bool webglCompatibility,
2304 InterfaceBlockMap *linkedBlocks,
2305 InfoLog &infoLog)
2306 {
2307 ASSERT(linkedBlocks);
2308
2309 for (const sh::InterfaceBlock &block : interfaceBlocksToLink)
2310 {
2311 const auto &entry = linkedBlocks->find(block.name);
2312 if (entry != linkedBlocks->end())
2313 {
2314 const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2315 std::string mismatchedStructFieldName;
2316 LinkMismatchError linkError = AreMatchingInterfaceBlocks(
2317 block, linkedBlock, webglCompatibility, &mismatchedStructFieldName);
2318 if (linkError != LinkMismatchError::NO_MISMATCH)
2319 {
2320 LogLinkMismatch(infoLog, block.name, GetInterfaceBlockTypeString(block.blockType),
2321 linkError, mismatchedStructFieldName, entry->second.first,
2322 shaderType);
2323 return false;
2324 }
2325 }
2326 else
2327 {
2328 (*linkedBlocks)[block.name] = std::make_pair(shaderType, &block);
2329 }
2330 }
2331
2332 return true;
2333 }
2334
ValidateInterfaceBlocksMatch(GLuint numShadersHasInterfaceBlocks,const ShaderMap<const std::vector<sh::InterfaceBlock> * > & shaderInterfaceBlocks,InfoLog & infoLog,bool webglCompatibility,InterfaceBlockMap * instancelessInterfaceBlocksFields)2335 bool ValidateInterfaceBlocksMatch(
2336 GLuint numShadersHasInterfaceBlocks,
2337 const ShaderMap<const std::vector<sh::InterfaceBlock> *> &shaderInterfaceBlocks,
2338 InfoLog &infoLog,
2339 bool webglCompatibility,
2340 InterfaceBlockMap *instancelessInterfaceBlocksFields)
2341 {
2342 for (ShaderType shaderType : kAllGraphicsShaderTypes)
2343 {
2344 // Validate that instanceless blocks of different names don't have fields of the same name.
2345 if (shaderInterfaceBlocks[shaderType] &&
2346 !ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2347 *shaderInterfaceBlocks[shaderType], shaderType, instancelessInterfaceBlocksFields,
2348 infoLog))
2349 {
2350 return false;
2351 }
2352 }
2353
2354 if (numShadersHasInterfaceBlocks < 2u)
2355 {
2356 return true;
2357 }
2358
2359 ASSERT(!shaderInterfaceBlocks[ShaderType::Compute]);
2360
2361 // Check that interface blocks defined in the graphics shaders are identical
2362
2363 InterfaceBlockMap linkedInterfaceBlocks;
2364
2365 bool interfaceBlockMapInitialized = false;
2366 for (ShaderType shaderType : kAllGraphicsShaderTypes)
2367 {
2368 if (!shaderInterfaceBlocks[shaderType])
2369 {
2370 continue;
2371 }
2372
2373 if (!interfaceBlockMapInitialized)
2374 {
2375 InitializeInterfaceBlockMap(*shaderInterfaceBlocks[shaderType], shaderType,
2376 &linkedInterfaceBlocks);
2377 interfaceBlockMapInitialized = true;
2378 }
2379 else if (!ValidateGraphicsInterfaceBlocksPerShader(*shaderInterfaceBlocks[shaderType],
2380 shaderType, webglCompatibility,
2381 &linkedInterfaceBlocks, infoLog))
2382 {
2383 return false;
2384 }
2385 }
2386
2387 return true;
2388 }
2389
LinkValidateProgramInterfaceBlocks(const Caps & caps,const Version & clientVersion,bool webglCompatibility,ShaderBitSet activeProgramStages,const ProgramLinkedResources & resources,InfoLog & infoLog,GLuint * combinedShaderStorageBlocksCountOut)2390 bool LinkValidateProgramInterfaceBlocks(const Caps &caps,
2391 const Version &clientVersion,
2392 bool webglCompatibility,
2393 ShaderBitSet activeProgramStages,
2394 const ProgramLinkedResources &resources,
2395 InfoLog &infoLog,
2396 GLuint *combinedShaderStorageBlocksCountOut)
2397 {
2398 ASSERT(combinedShaderStorageBlocksCountOut);
2399
2400 GLuint combinedUniformBlocksCount = 0u;
2401 GLuint numShadersHasUniformBlocks = 0u;
2402 ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderUniformBlocks = {};
2403 InterfaceBlockMap instancelessInterfaceBlocksFields;
2404
2405 for (ShaderType shaderType : activeProgramStages)
2406 {
2407 const std::vector<sh::InterfaceBlock> &uniformBlocks =
2408 resources.uniformBlockLinker.getShaderBlocks(shaderType);
2409 if (!uniformBlocks.empty())
2410 {
2411 if (!ValidateInterfaceBlocksCount(
2412 static_cast<GLuint>(caps.maxShaderUniformBlocks[shaderType]), uniformBlocks,
2413 shaderType, sh::BlockType::kBlockUniform, &combinedUniformBlocksCount, infoLog))
2414 {
2415 return false;
2416 }
2417
2418 allShaderUniformBlocks[shaderType] = &uniformBlocks;
2419 ++numShadersHasUniformBlocks;
2420 }
2421 }
2422
2423 if (combinedUniformBlocksCount > static_cast<GLuint>(caps.maxCombinedUniformBlocks))
2424 {
2425 infoLog << "The sum of the number of active uniform blocks exceeds "
2426 "MAX_COMBINED_UNIFORM_BLOCKS ("
2427 << caps.maxCombinedUniformBlocks << ").";
2428 return false;
2429 }
2430
2431 if (!ValidateInterfaceBlocksMatch(numShadersHasUniformBlocks, allShaderUniformBlocks, infoLog,
2432 webglCompatibility, &instancelessInterfaceBlocksFields))
2433 {
2434 return false;
2435 }
2436
2437 if (clientVersion >= Version(3, 1))
2438 {
2439 *combinedShaderStorageBlocksCountOut = 0u;
2440 GLuint numShadersHasShaderStorageBlocks = 0u;
2441 ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderStorageBlocks = {};
2442 for (ShaderType shaderType : activeProgramStages)
2443 {
2444 const std::vector<sh::InterfaceBlock> &shaderStorageBlocks =
2445 resources.shaderStorageBlockLinker.getShaderBlocks(shaderType);
2446 if (!shaderStorageBlocks.empty())
2447 {
2448 if (!ValidateInterfaceBlocksCount(
2449 static_cast<GLuint>(caps.maxShaderStorageBlocks[shaderType]),
2450 shaderStorageBlocks, shaderType, sh::BlockType::kBlockBuffer,
2451 combinedShaderStorageBlocksCountOut, infoLog))
2452 {
2453 return false;
2454 }
2455
2456 allShaderStorageBlocks[shaderType] = &shaderStorageBlocks;
2457 ++numShadersHasShaderStorageBlocks;
2458 }
2459 }
2460
2461 if (*combinedShaderStorageBlocksCountOut >
2462 static_cast<GLuint>(caps.maxCombinedShaderStorageBlocks))
2463 {
2464 infoLog << "The sum of the number of active shader storage blocks exceeds "
2465 "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2466 << caps.maxCombinedShaderStorageBlocks << ").";
2467 return false;
2468 }
2469
2470 if (!ValidateInterfaceBlocksMatch(numShadersHasShaderStorageBlocks, allShaderStorageBlocks,
2471 infoLog, webglCompatibility,
2472 &instancelessInterfaceBlocksFields))
2473 {
2474 return false;
2475 }
2476 }
2477
2478 return true;
2479 }
2480
2481 } // namespace gl
2482