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