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