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