1 //
2 // Copyright 2017 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // ProgramLinkedResources.cpp: implements link-time checks for default block uniforms, and generates
8 // uniform locations. Populates data structures related to uniforms so that they can be stored in
9 // program state.
10
11 #include "libANGLE/ProgramLinkedResources.h"
12
13 #include "common/string_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Caps.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Shader.h"
18 #include "libANGLE/features.h"
19
20 namespace gl
21 {
22 namespace
23 {
FindUniform(std::vector<LinkedUniform> & list,const std::string & name)24 LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
25 {
26 for (LinkedUniform &uniform : list)
27 {
28 if (uniform.name == name)
29 return &uniform;
30 }
31
32 return nullptr;
33 }
34
35 template <typename VarT>
SetActive(std::vector<VarT> * list,const std::string & name,ShaderType shaderType,bool active)36 void SetActive(std::vector<VarT> *list, const std::string &name, ShaderType shaderType, bool active)
37 {
38 for (auto &variable : *list)
39 {
40 if (variable.name == name)
41 {
42 variable.setActive(shaderType, active);
43 return;
44 }
45 }
46 }
47
48 // GLSL ES Spec 3.00.3, section 4.3.5.
LinkValidateUniforms(const sh::ShaderVariable & uniform1,const sh::ShaderVariable & uniform2,std::string * mismatchedStructFieldName)49 LinkMismatchError LinkValidateUniforms(const sh::ShaderVariable &uniform1,
50 const sh::ShaderVariable &uniform2,
51 std::string *mismatchedStructFieldName)
52 {
53 #if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
54 const bool validatePrecisionFeature = true;
55 #else
56 const bool validatePrecisionFeature = false;
57 #endif
58
59 // Validate precision match of uniforms iff they are statically used
60 bool validatePrecision = uniform1.staticUse && uniform2.staticUse && validatePrecisionFeature;
61 LinkMismatchError linkError = LinkValidateProgramVariables(
62 uniform1, uniform2, validatePrecision, false, false, mismatchedStructFieldName);
63 if (linkError != LinkMismatchError::NO_MISMATCH)
64 {
65 return linkError;
66 }
67
68 // GLSL ES Spec 3.10.4, section 4.4.5.
69 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
70 {
71 return LinkMismatchError::BINDING_MISMATCH;
72 }
73
74 // GLSL ES Spec 3.10.4, section 9.2.1.
75 if (uniform1.location != -1 && uniform2.location != -1 &&
76 uniform1.location != uniform2.location)
77 {
78 return LinkMismatchError::LOCATION_MISMATCH;
79 }
80 if (uniform1.offset != uniform2.offset)
81 {
82 return LinkMismatchError::OFFSET_MISMATCH;
83 }
84
85 return LinkMismatchError::NO_MISMATCH;
86 }
87
88 using ShaderUniform = std::pair<ShaderType, const sh::ShaderVariable *>;
89
ValidateGraphicsUniformsPerShader(Shader * shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog)90 bool ValidateGraphicsUniformsPerShader(Shader *shaderToLink,
91 bool extendLinkedUniforms,
92 std::map<std::string, ShaderUniform> *linkedUniforms,
93 InfoLog &infoLog)
94 {
95 ASSERT(shaderToLink && linkedUniforms);
96
97 for (const sh::ShaderVariable &uniform : shaderToLink->getUniforms())
98 {
99 const auto &entry = linkedUniforms->find(uniform.name);
100 if (entry != linkedUniforms->end())
101 {
102 const sh::ShaderVariable &linkedUniform = *(entry->second.second);
103 std::string mismatchedStructFieldName;
104 LinkMismatchError linkError =
105 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
106 if (linkError != LinkMismatchError::NO_MISMATCH)
107 {
108 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
109 mismatchedStructFieldName, entry->second.first,
110 shaderToLink->getType());
111 return false;
112 }
113 }
114 else if (extendLinkedUniforms)
115 {
116 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
117 }
118 }
119
120 return true;
121 }
122
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)123 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
124 {
125 switch (shaderType)
126 {
127 case ShaderType::Vertex:
128 return static_cast<GLuint>(caps.maxVertexUniformVectors);
129 case ShaderType::Fragment:
130 return static_cast<GLuint>(caps.maxFragmentUniformVectors);
131
132 case ShaderType::Compute:
133 case ShaderType::Geometry:
134 case ShaderType::TessControl:
135 case ShaderType::TessEvaluation:
136 return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
137
138 default:
139 UNREACHABLE();
140 return 0u;
141 }
142 }
143
144 enum class UniformType : uint8_t
145 {
146 Variable = 0,
147 Sampler = 1,
148 Image = 2,
149 AtomicCounter = 3,
150
151 InvalidEnum = 4,
152 EnumCount = 4,
153 };
154
GetUniformResourceNameString(UniformType uniformType)155 const char *GetUniformResourceNameString(UniformType uniformType)
156 {
157 switch (uniformType)
158 {
159 case UniformType::Variable:
160 return "uniform";
161 case UniformType::Sampler:
162 return "texture image unit";
163 case UniformType::Image:
164 return "image uniform";
165 case UniformType::AtomicCounter:
166 return "atomic counter";
167 default:
168 UNREACHABLE();
169 return "";
170 }
171 }
172
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)173 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
174 {
175 // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
176 if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
177 {
178 return "MAX_TEXTURE_IMAGE_UNITS";
179 }
180
181 std::ostringstream ostream;
182 ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
183
184 switch (uniformType)
185 {
186 case UniformType::Variable:
187 // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
188 // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
189 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
190 {
191 ostream << "UNIFORM_VECTORS";
192 break;
193 }
194 // For compute and geometry shaders, there are no definitions on
195 // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
196 // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
197 else
198 {
199 ostream << "UNIFORM_COMPONENTS";
200 }
201 break;
202 case UniformType::Sampler:
203 ostream << "TEXTURE_IMAGE_UNITS";
204 break;
205 case UniformType::Image:
206 ostream << "IMAGE_UNIFORMS";
207 break;
208 case UniformType::AtomicCounter:
209 ostream << "ATOMIC_COUNTERS";
210 break;
211 default:
212 UNREACHABLE();
213 return "";
214 }
215
216 if (shaderType == ShaderType::Geometry)
217 {
218 ostream << "_EXT";
219 }
220
221 return ostream.str();
222 }
223
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)224 void LogUniformsExceedLimit(ShaderType shaderType,
225 UniformType uniformType,
226 GLuint limit,
227 InfoLog &infoLog)
228 {
229 infoLog << GetShaderTypeString(shaderType) << " shader "
230 << GetUniformResourceNameString(uniformType) << "s count exceeds "
231 << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
232 }
233
234 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
235 // added to "uniformsOut".
236 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
237 {
238 public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,ShaderType shaderType,int blockIndex)239 UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
240 const std::string &namePrefix,
241 const std::string &mappedNamePrefix,
242 std::vector<LinkedUniform> *uniformsOut,
243 ShaderType shaderType,
244 int blockIndex)
245 : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
246 mGetMemberInfo(getMemberInfo),
247 mUniformsOut(uniformsOut),
248 mShaderType(shaderType),
249 mBlockIndex(blockIndex)
250 {}
251
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)252 void visitNamedVariable(const sh::ShaderVariable &variable,
253 bool isRowMajor,
254 const std::string &name,
255 const std::string &mappedName,
256 const std::vector<unsigned int> &arraySizes) override
257 {
258 // If getBlockMemberInfo returns false, the variable is optimized out.
259 sh::BlockMemberInfo variableInfo;
260 if (!mGetMemberInfo(name, mappedName, &variableInfo))
261 return;
262
263 std::string nameWithArrayIndex = name;
264 std::string mappedNameWithArrayIndex = mappedName;
265
266 if (variable.isArray())
267 {
268 nameWithArrayIndex += "[0]";
269 mappedNameWithArrayIndex += "[0]";
270 }
271
272 if (mBlockIndex == -1)
273 {
274 SetActive(mUniformsOut, nameWithArrayIndex, mShaderType, variable.active);
275 return;
276 }
277
278 LinkedUniform newUniform(variable.type, variable.precision, nameWithArrayIndex,
279 variable.arraySizes, -1, -1, -1, mBlockIndex, variableInfo);
280 newUniform.mappedName = mappedNameWithArrayIndex;
281 newUniform.setActive(mShaderType, variable.active);
282
283 // Since block uniforms have no location, we don't need to store them in the uniform
284 // locations list.
285 mUniformsOut->push_back(newUniform);
286 }
287
288 private:
289 const GetBlockMemberInfoFunc &mGetMemberInfo;
290 std::vector<LinkedUniform> *mUniformsOut;
291 const ShaderType mShaderType;
292 const int mBlockIndex;
293 };
294
295 // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
296 // new buffer variable is stored in "bufferVariablesOut".
297 class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
298 {
299 public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)300 ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
301 const std::string &namePrefix,
302 const std::string &mappedNamePrefix,
303 std::vector<BufferVariable> *bufferVariablesOut,
304 ShaderType shaderType,
305 int blockIndex)
306 : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mStubEncoder),
307 mGetMemberInfo(getMemberInfo),
308 mBufferVariablesOut(bufferVariablesOut),
309 mShaderType(shaderType),
310 mBlockIndex(blockIndex)
311 {}
312
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)313 void visitNamedVariable(const sh::ShaderVariable &variable,
314 bool isRowMajor,
315 const std::string &name,
316 const std::string &mappedName,
317 const std::vector<unsigned int> &arraySizes) override
318 {
319 if (mSkipEnabled)
320 return;
321
322 // If getBlockMemberInfo returns false, the variable is optimized out.
323 sh::BlockMemberInfo variableInfo;
324 if (!mGetMemberInfo(name, mappedName, &variableInfo))
325 return;
326
327 std::string nameWithArrayIndex = name;
328 std::string mappedNameWithArrayIndex = mappedName;
329
330 if (variable.isArray())
331 {
332 nameWithArrayIndex += "[0]";
333 mappedNameWithArrayIndex += "[0]";
334 }
335
336 if (mBlockIndex == -1)
337 {
338 SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active);
339 return;
340 }
341
342 BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
343 variable.arraySizes, mBlockIndex, variableInfo);
344 newBufferVariable.mappedName = mappedNameWithArrayIndex;
345 newBufferVariable.setActive(mShaderType, variable.active);
346
347 newBufferVariable.topLevelArraySize = mTopLevelArraySize;
348
349 mBufferVariablesOut->push_back(newBufferVariable);
350 }
351
352 private:
353 const GetBlockMemberInfoFunc &mGetMemberInfo;
354 std::vector<BufferVariable> *mBufferVariablesOut;
355 const ShaderType mShaderType;
356 const int mBlockIndex;
357 sh::StubBlockEncoder mStubEncoder;
358 };
359
360 struct ShaderUniformCount
361 {
362 unsigned int vectorCount = 0;
363 unsigned int samplerCount = 0;
364 unsigned int imageCount = 0;
365 unsigned int atomicCounterCount = 0;
366 unsigned int fragmentInOutCount = 0;
367 };
368
operator +=(ShaderUniformCount & lhs,const ShaderUniformCount & rhs)369 ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
370 {
371 lhs.vectorCount += rhs.vectorCount;
372 lhs.samplerCount += rhs.samplerCount;
373 lhs.imageCount += rhs.imageCount;
374 lhs.atomicCounterCount += rhs.atomicCounterCount;
375 lhs.fragmentInOutCount += rhs.fragmentInOutCount;
376 return lhs;
377 }
378
379 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
380 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
381 // Counts for each uniform category are stored and can be queried with "getCounts".
382 class FlattenUniformVisitor : public sh::VariableNameVisitor
383 {
384 public:
FlattenUniformVisitor(ShaderType shaderType,const sh::ShaderVariable & uniform,std::vector<LinkedUniform> * uniforms,std::vector<LinkedUniform> * samplerUniforms,std::vector<LinkedUniform> * imageUniforms,std::vector<LinkedUniform> * atomicCounterUniforms,std::vector<LinkedUniform> * inputAttachmentUniforms,std::vector<UnusedUniform> * unusedUniforms)385 FlattenUniformVisitor(ShaderType shaderType,
386 const sh::ShaderVariable &uniform,
387 std::vector<LinkedUniform> *uniforms,
388 std::vector<LinkedUniform> *samplerUniforms,
389 std::vector<LinkedUniform> *imageUniforms,
390 std::vector<LinkedUniform> *atomicCounterUniforms,
391 std::vector<LinkedUniform> *inputAttachmentUniforms,
392 std::vector<UnusedUniform> *unusedUniforms)
393 : sh::VariableNameVisitor("", ""),
394 mShaderType(shaderType),
395 mMarkActive(uniform.active),
396 mMarkStaticUse(uniform.staticUse),
397 mBinding(uniform.binding),
398 mOffset(uniform.offset),
399 mLocation(uniform.location),
400 mUniforms(uniforms),
401 mSamplerUniforms(samplerUniforms),
402 mImageUniforms(imageUniforms),
403 mAtomicCounterUniforms(atomicCounterUniforms),
404 mInputAttachmentUniforms(inputAttachmentUniforms),
405 mUnusedUniforms(unusedUniforms)
406 {}
407
visitNamedOpaqueObject(const sh::ShaderVariable & variable,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)408 void visitNamedOpaqueObject(const sh::ShaderVariable &variable,
409 const std::string &name,
410 const std::string &mappedName,
411 const std::vector<unsigned int> &arraySizes) override
412 {
413 visitNamedVariable(variable, false, name, mappedName, arraySizes);
414 }
415
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)416 void visitNamedVariable(const sh::ShaderVariable &variable,
417 bool isRowMajor,
418 const std::string &name,
419 const std::string &mappedName,
420 const std::vector<unsigned int> &arraySizes) override
421 {
422 bool isSampler = IsSamplerType(variable.type);
423 bool isImage = IsImageType(variable.type);
424 bool isAtomicCounter = IsAtomicCounterType(variable.type);
425 bool isFragmentInOut = variable.isFragmentInOut;
426 std::vector<LinkedUniform> *uniformList = mUniforms;
427 if (isSampler)
428 {
429 uniformList = mSamplerUniforms;
430 }
431 else if (isImage)
432 {
433 uniformList = mImageUniforms;
434 }
435 else if (isAtomicCounter)
436 {
437 uniformList = mAtomicCounterUniforms;
438 }
439 else if (isFragmentInOut)
440 {
441 uniformList = mInputAttachmentUniforms;
442 }
443
444 std::string fullNameWithArrayIndex(name);
445 std::string fullMappedNameWithArrayIndex(mappedName);
446
447 if (variable.isArray())
448 {
449 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
450 // Resources and including [0] at the end of array variable names.
451 fullNameWithArrayIndex += "[0]";
452 fullMappedNameWithArrayIndex += "[0]";
453 }
454
455 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
456 if (existingUniform)
457 {
458 if (getBinding() != -1)
459 {
460 existingUniform->binding = getBinding();
461 }
462 if (getOffset() != -1)
463 {
464 existingUniform->offset = getOffset();
465 }
466 if (mLocation != -1)
467 {
468 existingUniform->location = mLocation;
469 }
470 if (mMarkActive)
471 {
472 existingUniform->active = true;
473 existingUniform->setActive(mShaderType, true);
474 }
475 if (mMarkStaticUse)
476 {
477 existingUniform->staticUse = true;
478 }
479 }
480 else
481 {
482 LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
483 variable.arraySizes, getBinding(), getOffset(), mLocation,
484 -1, sh::kDefaultBlockMemberInfo);
485 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
486 linkedUniform.active = mMarkActive;
487 linkedUniform.staticUse = mMarkStaticUse;
488 linkedUniform.outerArraySizes = arraySizes;
489 linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
490 linkedUniform.imageUnitFormat = variable.imageUnitFormat;
491 linkedUniform.isFragmentInOut = variable.isFragmentInOut;
492 if (variable.hasParentArrayIndex())
493 {
494 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
495 }
496 if (mMarkActive)
497 {
498 linkedUniform.setActive(mShaderType, true);
499 }
500 else
501 {
502 mUnusedUniforms->emplace_back(
503 linkedUniform.name, linkedUniform.isSampler(), linkedUniform.isImage(),
504 linkedUniform.isAtomicCounter(), linkedUniform.isFragmentInOut);
505 }
506
507 uniformList->push_back(linkedUniform);
508 }
509
510 unsigned int elementCount = variable.getBasicTypeElementCount();
511
512 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
513 // Likewise, don't count "real" uniforms towards opaque count.
514
515 if (!IsOpaqueType(variable.type) && !isFragmentInOut)
516 {
517 mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
518 }
519
520 mUniformCount.samplerCount += (isSampler ? elementCount : 0);
521 mUniformCount.imageCount += (isImage ? elementCount : 0);
522 mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
523 mUniformCount.fragmentInOutCount += (isFragmentInOut ? elementCount : 0);
524
525 if (mLocation != -1)
526 {
527 mLocation += elementCount;
528 }
529 }
530
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)531 void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
532 {
533 mStructStackSize++;
534 sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
535 }
536
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)537 void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
538 {
539 mStructStackSize--;
540 sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
541 }
542
getCounts() const543 ShaderUniformCount getCounts() const { return mUniformCount; }
544
545 private:
getBinding() const546 int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const547 int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
548
549 ShaderType mShaderType;
550
551 // Active and StaticUse are given separately because they are tracked at struct granularity.
552 bool mMarkActive;
553 bool mMarkStaticUse;
554 int mBinding;
555 int mOffset;
556 int mLocation;
557 std::vector<LinkedUniform> *mUniforms;
558 std::vector<LinkedUniform> *mSamplerUniforms;
559 std::vector<LinkedUniform> *mImageUniforms;
560 std::vector<LinkedUniform> *mAtomicCounterUniforms;
561 std::vector<LinkedUniform> *mInputAttachmentUniforms;
562 std::vector<UnusedUniform> *mUnusedUniforms;
563 ShaderUniformCount mUniformCount;
564 unsigned int mStructStackSize = 0;
565 };
566
567 class InterfaceBlockInfo final : angle::NonCopyable
568 {
569 public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)570 InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
571 : mCustomEncoderFactory(customEncoderFactory)
572 {}
573
574 void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
575
576 bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
577 bool getBlockMemberInfo(const std::string &name,
578 const std::string &mappedName,
579 sh::BlockMemberInfo *infoOut);
580
581 private:
582 size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
583
584 std::map<std::string, size_t> mBlockSizes;
585 sh::BlockLayoutMap mBlockLayout;
586 // Based on the interface block layout, the std140 or std430 encoders are used. On some
587 // platforms (currently only D3D), there could be another non-standard encoder used.
588 CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
589 };
590
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)591 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
592 {
593 for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
594 {
595 if (!IsActiveInterfaceBlock(interfaceBlock))
596 continue;
597
598 if (mBlockSizes.count(interfaceBlock.name) > 0)
599 continue;
600
601 size_t dataSize = getBlockInfo(interfaceBlock);
602 mBlockSizes[interfaceBlock.name] = dataSize;
603 }
604 }
605
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)606 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
607 {
608 ASSERT(IsActiveInterfaceBlock(interfaceBlock));
609
610 // define member uniforms
611 sh::Std140BlockEncoder std140Encoder;
612 sh::Std430BlockEncoder std430Encoder;
613 sh::BlockLayoutEncoder *customEncoder = nullptr;
614 sh::BlockLayoutEncoder *encoder = nullptr;
615
616 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
617 {
618 encoder = &std140Encoder;
619 }
620 else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
621 {
622 encoder = &std430Encoder;
623 }
624 else if (mCustomEncoderFactory)
625 {
626 encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
627 }
628 else
629 {
630 UNREACHABLE();
631 return 0;
632 }
633
634 sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
635 &mBlockLayout);
636
637 size_t offset = encoder->getCurrentOffset();
638
639 SafeDelete(customEncoder);
640
641 return offset;
642 }
643
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)644 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
645 const std::string &mappedName,
646 size_t *sizeOut)
647 {
648 size_t nameLengthWithoutArrayIndex;
649 ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
650 std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
651 auto sizeIter = mBlockSizes.find(baseName);
652 if (sizeIter == mBlockSizes.end())
653 {
654 *sizeOut = 0;
655 return false;
656 }
657
658 *sizeOut = sizeIter->second;
659 return true;
660 }
661
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)662 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
663 const std::string &mappedName,
664 sh::BlockMemberInfo *infoOut)
665 {
666 auto infoIter = mBlockLayout.find(name);
667 if (infoIter == mBlockLayout.end())
668 {
669 *infoOut = sh::kDefaultBlockMemberInfo;
670 return false;
671 }
672
673 *infoOut = infoIter->second;
674 return true;
675 }
676
GetFilteredVaryings(const std::vector<sh::ShaderVariable> & varyings,std::vector<const sh::ShaderVariable * > * filteredVaryingsOut)677 void GetFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
678 std::vector<const sh::ShaderVariable *> *filteredVaryingsOut)
679 {
680 for (const sh::ShaderVariable &varying : varyings)
681 {
682 // Built-in varyings obey special rules
683 if (varying.isBuiltIn())
684 {
685 continue;
686 }
687
688 filteredVaryingsOut->push_back(&varying);
689 }
690 }
691
LinkValidateVaryings(const sh::ShaderVariable & outputVarying,const sh::ShaderVariable & inputVarying,int shaderVersion,ShaderType frontShaderType,ShaderType backShaderType,bool isSeparable,std::string * mismatchedStructFieldName)692 LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
693 const sh::ShaderVariable &inputVarying,
694 int shaderVersion,
695 ShaderType frontShaderType,
696 ShaderType backShaderType,
697 bool isSeparable,
698 std::string *mismatchedStructFieldName)
699 {
700 // [ES 3.2 spec] 7.4.1 Shader Interface Matching:
701 // Tessellation control shader per-vertex output variables and blocks and tessellation control,
702 // tessellation evaluation, and geometry shader per-vertex input variables and blocks are
703 // required to be declared as arrays, with each element representing input or output values for
704 // a single vertex of a multi-vertex primitive. For the purposes of interface matching, such
705 // variables and blocks are treated as though they were not declared as arrays.
706 bool treatOutputAsNonArray =
707 (frontShaderType == ShaderType::TessControl && !outputVarying.isPatch);
708 bool treatInputAsNonArray =
709 ((backShaderType == ShaderType::TessControl ||
710 backShaderType == ShaderType::TessEvaluation || backShaderType == ShaderType::Geometry) &&
711 !inputVarying.isPatch);
712
713 // Skip the validation on the array sizes between a vertex output varying and a geometry input
714 // varying as it has been done before.
715 bool validatePrecision = isSeparable && (shaderVersion > 100);
716 LinkMismatchError linkError = LinkValidateProgramVariables(
717 outputVarying, inputVarying, validatePrecision, treatOutputAsNonArray, treatInputAsNonArray,
718 mismatchedStructFieldName);
719 if (linkError != LinkMismatchError::NO_MISMATCH)
720 {
721 return linkError;
722 }
723
724 // Explicit locations must match if the names match.
725 if (outputVarying.isSameNameAtLinkTime(inputVarying) &&
726 outputVarying.location != inputVarying.location)
727 {
728 return LinkMismatchError::LOCATION_MISMATCH;
729 }
730
731 if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
732 {
733 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
734 }
735
736 if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
737 {
738 return LinkMismatchError::INVARIANCE_MISMATCH;
739 }
740
741 return LinkMismatchError::NO_MISMATCH;
742 }
743
DoShaderVariablesMatch(int frontShaderVersion,ShaderType frontShaderType,ShaderType backShaderType,const sh::ShaderVariable & input,const sh::ShaderVariable & output,bool isSeparable,gl::InfoLog & infoLog)744 bool DoShaderVariablesMatch(int frontShaderVersion,
745 ShaderType frontShaderType,
746 ShaderType backShaderType,
747 const sh::ShaderVariable &input,
748 const sh::ShaderVariable &output,
749 bool isSeparable,
750 gl::InfoLog &infoLog)
751 {
752 bool namesMatch = input.isSameNameAtLinkTime(output);
753 bool locationsMatch = input.location != -1 && input.location == output.location;
754
755 // An output block is considered to match an input block in the subsequent
756 // shader if the two blocks have the same block name, and the members of the
757 // block match exactly in name, type, qualification, and declaration order.
758 //
759 // - For the purposes of shader interface matching, the gl_PointSize
760 // member of the intrinsically declared gl_PerVertex shader interface
761 // block is ignored.
762 // - Output blocks that do not match in name, but have a location and match
763 // in every other way listed above may be considered to match by some
764 // implementations, but not all - so this behaviour should not be relied
765 // upon.
766
767 // An output variable is considered to match an input variable in the subsequent
768 // shader if:
769 //
770 // - the two variables match in name, type, and qualification; or
771 // - the two variables are declared with the same location qualifier and
772 // match in type and qualification.
773
774 if (namesMatch || locationsMatch)
775 {
776 std::string mismatchedStructFieldName;
777 LinkMismatchError linkError =
778 LinkValidateVaryings(output, input, frontShaderVersion, frontShaderType, backShaderType,
779 isSeparable, &mismatchedStructFieldName);
780 if (linkError != LinkMismatchError::NO_MISMATCH)
781 {
782 LogLinkMismatch(infoLog, input.name, "varying", linkError, mismatchedStructFieldName,
783 frontShaderType, backShaderType);
784 return false;
785 }
786
787 return true;
788 }
789
790 return false;
791 }
792 } // anonymous namespace
793
UniformLinker(const ProgramState & state)794 UniformLinker::UniformLinker(const ProgramState &state) : mState(state) {}
795
796 UniformLinker::~UniformLinker() = default;
797
getResults(std::vector<LinkedUniform> * uniforms,std::vector<UnusedUniform> * unusedUniforms,std::vector<VariableLocation> * uniformLocations)798 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
799 std::vector<UnusedUniform> *unusedUniforms,
800 std::vector<VariableLocation> *uniformLocations)
801 {
802 uniforms->swap(mUniforms);
803 unusedUniforms->swap(mUnusedUniforms);
804 uniformLocations->swap(mUniformLocations);
805 }
806
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)807 bool UniformLinker::link(const Caps &caps,
808 InfoLog &infoLog,
809 const ProgramAliasedBindings &uniformLocationBindings)
810 {
811 if (mState.getAttachedShader(ShaderType::Vertex) &&
812 mState.getAttachedShader(ShaderType::Fragment))
813 {
814 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
815 if (!validateGraphicsUniforms(infoLog))
816 {
817 return false;
818 }
819 }
820
821 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
822 // Also check the maximum uniform vector and sampler counts.
823 if (!flattenUniformsAndCheckCaps(caps, infoLog))
824 {
825 return false;
826 }
827
828 if (!checkMaxCombinedAtomicCounters(caps, infoLog))
829 {
830 return false;
831 }
832
833 if (!indexUniforms(infoLog, uniformLocationBindings))
834 {
835 return false;
836 }
837
838 return true;
839 }
840
validateGraphicsUniforms(InfoLog & infoLog) const841 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
842 {
843 // Check that uniforms defined in the graphics shaders are identical
844 std::map<std::string, ShaderUniform> linkedUniforms;
845
846 for (const ShaderType shaderType : kAllGraphicsShaderTypes)
847 {
848 Shader *currentShader = mState.getAttachedShader(shaderType);
849 if (currentShader)
850 {
851 if (shaderType == ShaderType::Vertex)
852 {
853 for (const sh::ShaderVariable &vertexUniform : currentShader->getUniforms())
854 {
855 linkedUniforms[vertexUniform.name] =
856 std::make_pair(ShaderType::Vertex, &vertexUniform);
857 }
858 }
859 else
860 {
861 bool isLastShader = (shaderType == ShaderType::Fragment);
862 if (!ValidateGraphicsUniformsPerShader(currentShader, !isLastShader,
863 &linkedUniforms, infoLog))
864 {
865 return false;
866 }
867 }
868 }
869 }
870
871 return true;
872 }
873
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)874 bool UniformLinker::indexUniforms(InfoLog &infoLog,
875 const ProgramAliasedBindings &uniformLocationBindings)
876 {
877 // Locations which have been allocated for an unused uniform.
878 std::set<GLuint> ignoredLocations;
879
880 int maxUniformLocation = -1;
881
882 // Gather uniform locations that have been set either using the bindUniformLocation API or by
883 // using a location layout qualifier and check conflicts between them.
884 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
885 &ignoredLocations, &maxUniformLocation))
886 {
887 return false;
888 }
889
890 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
891 // the line relies on only having statically used uniforms in mUniforms.
892 pruneUnusedUniforms();
893
894 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
895 std::vector<VariableLocation> unlocatedUniforms;
896 std::map<GLuint, VariableLocation> preLocatedUniforms;
897
898 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
899 {
900 const LinkedUniform &uniform = mUniforms[uniformIndex];
901
902 if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
903 IsAtomicCounterType(uniform.type) || uniform.isFragmentInOut)
904 {
905 continue;
906 }
907
908 int preSetLocation = uniformLocationBindings.getBinding(uniform);
909 int shaderLocation = uniform.location;
910
911 if (shaderLocation != -1)
912 {
913 preSetLocation = shaderLocation;
914 }
915
916 unsigned int elementCount = uniform.getBasicTypeElementCount();
917 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
918 {
919 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
920
921 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
922 {
923 int elementLocation = preSetLocation + arrayIndex;
924 preLocatedUniforms[elementLocation] = location;
925 }
926 else
927 {
928 unlocatedUniforms.push_back(location);
929 }
930 }
931 }
932
933 // Make enough space for all uniforms, with pre-set locations or not.
934 mUniformLocations.resize(
935 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
936 static_cast<size_t>(maxUniformLocation + 1)));
937
938 // Assign uniforms with pre-set locations
939 for (const auto &uniform : preLocatedUniforms)
940 {
941 mUniformLocations[uniform.first] = uniform.second;
942 }
943
944 // Assign ignored uniforms
945 for (const auto &ignoredLocation : ignoredLocations)
946 {
947 mUniformLocations[ignoredLocation].markIgnored();
948 }
949
950 // Automatically assign locations for the rest of the uniforms
951 size_t nextUniformLocation = 0;
952 for (const auto &unlocatedUniform : unlocatedUniforms)
953 {
954 while (mUniformLocations[nextUniformLocation].used() ||
955 mUniformLocations[nextUniformLocation].ignored)
956 {
957 nextUniformLocation++;
958 }
959
960 ASSERT(nextUniformLocation < mUniformLocations.size());
961 mUniformLocations[nextUniformLocation] = unlocatedUniform;
962 nextUniformLocation++;
963 }
964
965 return true;
966 }
967
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)968 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
969 InfoLog &infoLog,
970 const ProgramAliasedBindings &uniformLocationBindings,
971 std::set<GLuint> *ignoredLocations,
972 int *maxUniformLocation)
973 {
974 // All the locations where another uniform can't be located.
975 std::set<GLuint> reservedLocations;
976
977 for (const LinkedUniform &uniform : mUniforms)
978 {
979 if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) || uniform.isFragmentInOut)
980 {
981 // The uniform of the fragment inout is not a normal uniform type. So, in the case of
982 // the fragment inout, this routine should be skipped.
983 continue;
984 }
985
986 int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
987 int shaderLocation = uniform.location;
988
989 if (shaderLocation != -1)
990 {
991 unsigned int elementCount = uniform.getBasicTypeElementCount();
992
993 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
994 {
995 // GLSL ES 3.10 section 4.4.3
996 int elementLocation = shaderLocation + arrayIndex;
997 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
998 if (reservedLocations.find(elementLocation) != reservedLocations.end())
999 {
1000 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
1001 return false;
1002 }
1003 reservedLocations.insert(elementLocation);
1004 if (!uniform.active)
1005 {
1006 ignoredLocations->insert(elementLocation);
1007 }
1008 }
1009 }
1010 else if (apiBoundLocation != -1 && uniform.staticUse)
1011 {
1012 // Only the first location is reserved even if the uniform is an array.
1013 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
1014 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
1015 {
1016 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
1017 return false;
1018 }
1019 reservedLocations.insert(apiBoundLocation);
1020 if (!uniform.active)
1021 {
1022 ignoredLocations->insert(apiBoundLocation);
1023 }
1024 }
1025 }
1026
1027 // Record the uniform locations that were bound using the API for uniforms that were not found
1028 // from the shader. Other uniforms should not be assigned to those locations.
1029 for (const auto &locationBinding : uniformLocationBindings)
1030 {
1031 GLuint location = locationBinding.second.location;
1032 if (reservedLocations.find(location) == reservedLocations.end())
1033 {
1034 ignoredLocations->insert(location);
1035 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
1036 }
1037 }
1038
1039 return true;
1040 }
1041
pruneUnusedUniforms()1042 void UniformLinker::pruneUnusedUniforms()
1043 {
1044 auto uniformIter = mUniforms.begin();
1045 while (uniformIter != mUniforms.end())
1046 {
1047 if (uniformIter->active)
1048 {
1049 ++uniformIter;
1050 }
1051 else
1052 {
1053 mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
1054 uniformIter->isImage(), uniformIter->isAtomicCounter(),
1055 uniformIter->isFragmentInOut);
1056 uniformIter = mUniforms.erase(uniformIter);
1057 }
1058 }
1059 }
1060
flattenUniformsAndCheckCapsForShader(Shader * shader,const Caps & caps,std::vector<LinkedUniform> & samplerUniforms,std::vector<LinkedUniform> & imageUniforms,std::vector<LinkedUniform> & atomicCounterUniforms,std::vector<LinkedUniform> & inputAttachmentUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)1061 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
1062 Shader *shader,
1063 const Caps &caps,
1064 std::vector<LinkedUniform> &samplerUniforms,
1065 std::vector<LinkedUniform> &imageUniforms,
1066 std::vector<LinkedUniform> &atomicCounterUniforms,
1067 std::vector<LinkedUniform> &inputAttachmentUniforms,
1068 std::vector<UnusedUniform> &unusedUniforms,
1069 InfoLog &infoLog)
1070 {
1071 ShaderUniformCount shaderUniformCount;
1072 for (const sh::ShaderVariable &uniform : shader->getUniforms())
1073 {
1074 FlattenUniformVisitor flattener(shader->getType(), uniform, &mUniforms, &samplerUniforms,
1075 &imageUniforms, &atomicCounterUniforms,
1076 &inputAttachmentUniforms, &unusedUniforms);
1077 sh::TraverseShaderVariable(uniform, false, &flattener);
1078
1079 if (uniform.active)
1080 {
1081 shaderUniformCount += flattener.getCounts();
1082 }
1083 else
1084 {
1085 unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
1086 IsImageType(uniform.type),
1087 IsAtomicCounterType(uniform.type), uniform.isFragmentInOut);
1088 }
1089 }
1090
1091 ShaderType shaderType = shader->getType();
1092
1093 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
1094 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
1095 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
1096 {
1097 GLuint maxUniforms = 0u;
1098
1099 // See comments in GetUniformResourceLimitName()
1100 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
1101 {
1102 maxUniforms = maxUniformVectorsCount;
1103 }
1104 else
1105 {
1106 maxUniforms = maxUniformVectorsCount * 4;
1107 }
1108
1109 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
1110 return false;
1111 }
1112
1113 if (shaderUniformCount.samplerCount >
1114 static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
1115 {
1116 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
1117 caps.maxShaderTextureImageUnits[shaderType], infoLog);
1118 return false;
1119 }
1120
1121 if (shaderUniformCount.imageCount >
1122 static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
1123 {
1124 LogUniformsExceedLimit(shaderType, UniformType::Image,
1125 caps.maxShaderImageUniforms[shaderType], infoLog);
1126 return false;
1127 }
1128
1129 if (shaderUniformCount.atomicCounterCount >
1130 static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
1131 {
1132 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
1133 caps.maxShaderAtomicCounters[shaderType], infoLog);
1134 return false;
1135 }
1136
1137 return true;
1138 }
1139
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1140 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1141 {
1142 std::vector<LinkedUniform> samplerUniforms;
1143 std::vector<LinkedUniform> imageUniforms;
1144 std::vector<LinkedUniform> atomicCounterUniforms;
1145 std::vector<LinkedUniform> inputAttachmentUniforms;
1146 std::vector<UnusedUniform> unusedUniforms;
1147
1148 for (const ShaderType shaderType : AllShaderTypes())
1149 {
1150 Shader *shader = mState.getAttachedShader(shaderType);
1151 if (!shader)
1152 {
1153 continue;
1154 }
1155
1156 if (!flattenUniformsAndCheckCapsForShader(shader, caps, samplerUniforms, imageUniforms,
1157 atomicCounterUniforms, inputAttachmentUniforms,
1158 unusedUniforms, infoLog))
1159 {
1160 return false;
1161 }
1162 }
1163
1164 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1165 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1166 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1167 mUniforms.insert(mUniforms.end(), inputAttachmentUniforms.begin(),
1168 inputAttachmentUniforms.end());
1169 mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1170 return true;
1171 }
1172
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1173 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1174 {
1175 unsigned int atomicCounterCount = 0;
1176 for (const auto &uniform : mUniforms)
1177 {
1178 if (IsAtomicCounterType(uniform.type) && uniform.active)
1179 {
1180 atomicCounterCount += uniform.getBasicTypeElementCount();
1181 if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1182 {
1183 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1184 << caps.maxCombinedAtomicCounters << ").";
1185 return false;
1186 }
1187 }
1188 }
1189 return true;
1190 }
1191
1192 // InterfaceBlockLinker implementation.
1193 InterfaceBlockLinker::InterfaceBlockLinker() = default;
1194
1195 InterfaceBlockLinker::~InterfaceBlockLinker() = default;
1196
init(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1197 void InterfaceBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1198 std::vector<std::string> *unusedInterfaceBlocksOut)
1199 {
1200 mBlocksOut = blocksOut;
1201 mUnusedInterfaceBlocksOut = unusedInterfaceBlocksOut;
1202 }
1203
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1204 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1205 const std::vector<sh::InterfaceBlock> *blocks)
1206 {
1207 mShaderBlocks[shaderType] = blocks;
1208 }
1209
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1210 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1211 const GetBlockMemberInfoFunc &getMemberInfo) const
1212 {
1213 ASSERT(mBlocksOut->empty());
1214
1215 std::set<std::string> visitedList;
1216
1217 for (const ShaderType shaderType : AllShaderTypes())
1218 {
1219 if (!mShaderBlocks[shaderType])
1220 {
1221 continue;
1222 }
1223
1224 for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1225 {
1226 if (!IsActiveInterfaceBlock(block))
1227 {
1228 mUnusedInterfaceBlocksOut->push_back(block.name);
1229 continue;
1230 }
1231
1232 if (visitedList.count(block.name) == 0)
1233 {
1234 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1235 visitedList.insert(block.name);
1236 continue;
1237 }
1238
1239 if (!block.active)
1240 {
1241 mUnusedInterfaceBlocksOut->push_back(block.name);
1242 continue;
1243 }
1244
1245 for (InterfaceBlock &priorBlock : *mBlocksOut)
1246 {
1247 if (block.name == priorBlock.name)
1248 {
1249 priorBlock.setActive(shaderType, true);
1250
1251 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1252 getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1253 shaderType, -1));
1254
1255 sh::TraverseShaderVariables(block.fields, false, visitor.get());
1256 }
1257 }
1258 }
1259 }
1260 }
1261
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1262 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1263 const GetBlockMemberInfoFunc &getMemberInfo,
1264 const sh::InterfaceBlock &interfaceBlock,
1265 ShaderType shaderType) const
1266 {
1267 size_t blockSize = 0;
1268 std::vector<unsigned int> blockIndexes;
1269
1270 int blockIndex = static_cast<int>(mBlocksOut->size());
1271 // Track the first and last block member index to determine the range of active block members in
1272 // the block.
1273 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1274
1275 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1276 getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1277 shaderType, blockIndex));
1278 sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1279
1280 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1281
1282 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1283 ++blockMemberIndex)
1284 {
1285 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1286 }
1287
1288 unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1289
1290 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1291 ++arrayElement)
1292 {
1293 std::string blockArrayName = interfaceBlock.name;
1294 std::string blockMappedArrayName = interfaceBlock.mappedName;
1295 if (interfaceBlock.isArray())
1296 {
1297 blockArrayName += ArrayString(arrayElement);
1298 blockMappedArrayName += ArrayString(arrayElement);
1299 }
1300
1301 // Don't define this block at all if it's not active in the implementation.
1302 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1303 {
1304 continue;
1305 }
1306
1307 // ESSL 3.10 section 4.4.4 page 58:
1308 // Any uniform or shader storage block declared without a binding qualifier is initially
1309 // assigned to block binding point zero.
1310 int blockBinding =
1311 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1312 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1313 interfaceBlock.isArray(), arrayElement, firstFieldArraySize,
1314 blockBinding);
1315 block.memberIndexes = blockIndexes;
1316 block.setActive(shaderType, interfaceBlock.active);
1317
1318 // Since all block elements in an array share the same active interface blocks, they
1319 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1320 // was active, here we will add every block element in the array.
1321 block.dataSize = static_cast<unsigned int>(blockSize);
1322 mBlocksOut->push_back(block);
1323 }
1324 }
1325
1326 // UniformBlockLinker implementation.
1327 UniformBlockLinker::UniformBlockLinker() = default;
1328
~UniformBlockLinker()1329 UniformBlockLinker::~UniformBlockLinker() {}
1330
init(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * unusedInterfaceBlocksOut)1331 void UniformBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1332 std::vector<LinkedUniform> *uniformsOut,
1333 std::vector<std::string> *unusedInterfaceBlocksOut)
1334 {
1335 InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1336 mUniformsOut = uniformsOut;
1337 }
1338
getCurrentBlockMemberIndex() const1339 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1340 {
1341 return mUniformsOut->size();
1342 }
1343
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1344 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1345 const GetBlockMemberInfoFunc &getMemberInfo,
1346 const std::string &namePrefix,
1347 const std::string &mappedNamePrefix,
1348 ShaderType shaderType,
1349 int blockIndex) const
1350 {
1351 return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1352 mUniformsOut, shaderType, blockIndex);
1353 }
1354
1355 // ShaderStorageBlockLinker implementation.
1356 ShaderStorageBlockLinker::ShaderStorageBlockLinker() = default;
1357
1358 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() = default;
1359
init(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1360 void ShaderStorageBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1361 std::vector<BufferVariable> *bufferVariablesOut,
1362 std::vector<std::string> *unusedInterfaceBlocksOut)
1363 {
1364 InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1365 mBufferVariablesOut = bufferVariablesOut;
1366 }
1367
getCurrentBlockMemberIndex() const1368 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1369 {
1370 return mBufferVariablesOut->size();
1371 }
1372
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1373 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1374 const GetBlockMemberInfoFunc &getMemberInfo,
1375 const std::string &namePrefix,
1376 const std::string &mappedNamePrefix,
1377 ShaderType shaderType,
1378 int blockIndex) const
1379 {
1380 return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1381 mBufferVariablesOut, shaderType, blockIndex);
1382 }
1383
1384 // AtomicCounterBufferLinker implementation.
1385 AtomicCounterBufferLinker::AtomicCounterBufferLinker() = default;
1386
1387 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() = default;
1388
init(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1389 void AtomicCounterBufferLinker::init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1390 {
1391 mAtomicCounterBuffersOut = atomicCounterBuffersOut;
1392 }
1393
link(const std::map<int,unsigned int> & sizeMap) const1394 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1395 {
1396 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1397 {
1398 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1399 ASSERT(bufferSize != sizeMap.end());
1400 atomicCounterBuffer.dataSize = bufferSize->second;
1401 }
1402 }
1403
1404 ProgramLinkedResources::ProgramLinkedResources() = default;
1405
1406 ProgramLinkedResources::~ProgramLinkedResources() = default;
1407
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1408 void ProgramLinkedResources::init(std::vector<InterfaceBlock> *uniformBlocksOut,
1409 std::vector<LinkedUniform> *uniformsOut,
1410 std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1411 std::vector<BufferVariable> *bufferVariablesOut,
1412 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1413 {
1414 uniformBlockLinker.init(uniformBlocksOut, uniformsOut, &unusedInterfaceBlocks);
1415 shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1416 &unusedInterfaceBlocks);
1417 atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1418 }
1419
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1420 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1421 const ProgramLinkedResources &resources) const
1422 {
1423 // Gather uniform interface block info.
1424 InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1425 for (const ShaderType shaderType : AllShaderTypes())
1426 {
1427 Shader *shader = programState.getAttachedShader(shaderType);
1428 if (shader)
1429 {
1430 uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
1431 }
1432 }
1433
1434 auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1435 const std::string &mappedName, size_t *sizeOut) {
1436 return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1437 };
1438
1439 auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1440 const std::string &mappedName,
1441 sh::BlockMemberInfo *infoOut) {
1442 return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1443 };
1444
1445 // Link uniform interface blocks.
1446 resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1447
1448 // Gather storage buffer interface block info.
1449 InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1450 for (const ShaderType shaderType : AllShaderTypes())
1451 {
1452 Shader *shader = programState.getAttachedShader(shaderType);
1453 if (shader)
1454 {
1455 shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
1456 }
1457 }
1458 auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1459 const std::string &mappedName,
1460 size_t *sizeOut) {
1461 return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1462 };
1463
1464 auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1465 const std::string &mappedName,
1466 sh::BlockMemberInfo *infoOut) {
1467 return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1468 };
1469
1470 // Link storage buffer interface blocks.
1471 resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1472 getShaderStorageBlockMemberInfo);
1473
1474 // Gather and link atomic counter buffer interface blocks.
1475 std::map<int, unsigned int> sizeMap;
1476 getAtomicCounterBufferSizeMap(programState, sizeMap);
1477 resources.atomicCounterBufferLinker.link(sizeMap);
1478 }
1479
getAtomicCounterBufferSizeMap(const ProgramState & programState,std::map<int,unsigned int> & sizeMapOut) const1480 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1481 const ProgramState &programState,
1482 std::map<int, unsigned int> &sizeMapOut) const
1483 {
1484 for (unsigned int index : programState.getAtomicCounterUniformRange())
1485 {
1486 const LinkedUniform &glUniform = programState.getUniforms()[index];
1487
1488 auto &bufferDataSize = sizeMapOut[glUniform.binding];
1489
1490 // Calculate the size of the buffer by finding the end of the last uniform with the same
1491 // binding. The end of the uniform is calculated by finding the initial offset of the
1492 // uniform and adding size of the uniform. For arrays, the size is the number of elements
1493 // times the element size (should always by 4 for atomic_units).
1494 unsigned dataOffset =
1495 glUniform.offset + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1496 glUniform.getElementSize());
1497 if (dataOffset > bufferDataSize)
1498 {
1499 bufferDataSize = dataOffset;
1500 }
1501 }
1502 }
1503
1504 // Note: this is broken for pipelines with modified/discarded shaders. http://anglebug.com/5506
LinkValidateProgramGlobalNames(InfoLog & infoLog,const HasAttachedShaders & programOrPipeline)1505 bool LinkValidateProgramGlobalNames(InfoLog &infoLog, const HasAttachedShaders &programOrPipeline)
1506 {
1507 angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1508 using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1509 angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1510
1511 for (ShaderType shaderType : kAllGraphicsShaderTypes)
1512 {
1513 Shader *shader = programOrPipeline.getAttachedShader(shaderType);
1514 if (!shader)
1515 {
1516 continue;
1517 }
1518
1519 // Build a map of Uniforms
1520 const std::vector<sh::ShaderVariable> uniforms = shader->getUniforms();
1521 for (const auto &uniform : uniforms)
1522 {
1523 uniformMap[uniform.name] = &uniform;
1524 }
1525
1526 // Build a map of Uniform Blocks
1527 // This will also detect any field name conflicts between Uniform Blocks without instance
1528 // names
1529 const std::vector<sh::InterfaceBlock> &uniformBlocks = shader->getUniformBlocks();
1530 for (const auto &uniformBlock : uniformBlocks)
1531 {
1532 // Only uniform blocks without an instance name can create a conflict with their field
1533 // names
1534 if (!uniformBlock.instanceName.empty())
1535 {
1536 continue;
1537 }
1538
1539 for (const auto &field : uniformBlock.fields)
1540 {
1541 if (!uniformBlockFieldMap.count(field.name))
1542 {
1543 // First time we've seen this uniform block field name, so add the
1544 // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1545 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1546 std::vector<BlockAndFieldPair> newUniformBlockList;
1547 newUniformBlockList.push_back(blockAndFieldPair);
1548 uniformBlockFieldMap[field.name] = newUniformBlockList;
1549 continue;
1550 }
1551
1552 // We've seen this name before.
1553 // We need to check each of the uniform blocks that contain a field with this name
1554 // to see if there's a conflict or not.
1555 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1556 uniformBlockFieldMap[field.name];
1557 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1558 {
1559 const sh::InterfaceBlock *prevUniformBlock = prevBlockFieldPair.first;
1560 const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1561
1562 if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1563 {
1564 // The same uniform block should, by definition, contain the same field name
1565 continue;
1566 }
1567
1568 // The uniform blocks don't match, so check if the necessary field properties
1569 // also match
1570 if ((field.name == prevUniformBlockField->name) &&
1571 (field.type == prevUniformBlockField->type) &&
1572 (field.precision == prevUniformBlockField->precision))
1573 {
1574 infoLog << "Name conflicts between uniform block field names: "
1575 << field.name;
1576 return false;
1577 }
1578 }
1579
1580 // No conflict, so record this pair
1581 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1582 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1583 }
1584 }
1585 }
1586
1587 // Validate no uniform names conflict with attribute names
1588 Shader *vertexShader = programOrPipeline.getAttachedShader(ShaderType::Vertex);
1589 if (vertexShader)
1590 {
1591 // ESSL 3.00.6 section 4.3.5:
1592 // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1593 // but not in another (e.g., a fragment shader), then that name is still
1594 // available in the other stage for a different use.
1595 std::unordered_set<std::string> uniforms;
1596 for (const sh::ShaderVariable &uniform : vertexShader->getUniforms())
1597 {
1598 uniforms.insert(uniform.name);
1599 }
1600 for (const auto &attrib : vertexShader->getActiveAttributes())
1601 {
1602 if (uniforms.count(attrib.name))
1603 {
1604 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1605 return false;
1606 }
1607 }
1608 }
1609
1610 // Validate no Uniform Block fields conflict with other Uniforms
1611 for (const auto &uniformBlockField : uniformBlockFieldMap)
1612 {
1613 const std::string &fieldName = uniformBlockField.first;
1614 if (uniformMap.count(fieldName))
1615 {
1616 infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1617 return false;
1618 }
1619 }
1620
1621 return true;
1622 }
1623
1624 // [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)1625 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1626 const std::vector<sh::ShaderVariable> &inputVaryings,
1627 ShaderType frontShaderType,
1628 ShaderType backShaderType,
1629 int frontShaderVersion,
1630 int backShaderVersion,
1631 bool isSeparable,
1632 gl::InfoLog &infoLog)
1633 {
1634 ASSERT(frontShaderVersion == backShaderVersion);
1635
1636 std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1637 std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1638
1639 GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1640 GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1641
1642 // Separable programs require the number of inputs and outputs match
1643 if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1644 {
1645 infoLog << GetShaderTypeString(backShaderType)
1646 << " does not consume all varyings generated by "
1647 << GetShaderTypeString(frontShaderType);
1648 return false;
1649 }
1650 if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1651 {
1652 infoLog << GetShaderTypeString(frontShaderType)
1653 << " does not generate all varyings consumed by "
1654 << GetShaderTypeString(backShaderType);
1655 return false;
1656 }
1657
1658 // All inputs must match all outputs
1659 for (const sh::ShaderVariable *input : filteredInputVaryings)
1660 {
1661 bool match = false;
1662 for (const sh::ShaderVariable *output : filteredOutputVaryings)
1663 {
1664 if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1665 *output, isSeparable, infoLog))
1666 {
1667 match = true;
1668 break;
1669 }
1670 }
1671
1672 // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1673 // whether the input is statically used - a statically used input should fail this test even
1674 // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1675 if (!match && input->staticUse)
1676 {
1677 const std::string &name =
1678 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1679 infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1680 << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1681 return false;
1682 }
1683 }
1684
1685 return true;
1686 }
1687
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1688 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1689 const sh::ShaderVariable &variable2,
1690 bool validatePrecision,
1691 bool treatVariable1AsNonArray,
1692 bool treatVariable2AsNonArray,
1693 std::string *mismatchedStructOrBlockMemberName)
1694 {
1695 if (variable1.type != variable2.type)
1696 {
1697 return LinkMismatchError::TYPE_MISMATCH;
1698 }
1699
1700 bool variable1IsArray = variable1.isArray();
1701 bool variable2IsArray = variable2.isArray();
1702 if (treatVariable1AsNonArray)
1703 {
1704 ASSERT(variable1IsArray);
1705 variable1IsArray = false;
1706 }
1707 if (treatVariable2AsNonArray)
1708 {
1709 ASSERT(variable2IsArray);
1710 variable2IsArray = false;
1711 }
1712 // TODO(anglebug.com/5557): Investigate interactions with arrays-of-arrays.
1713 if (variable1IsArray != variable2IsArray)
1714 {
1715 return LinkMismatchError::ARRAYNESS_MISMATCH;
1716 }
1717 if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1718 variable1.arraySizes != variable2.arraySizes)
1719 {
1720 return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1721 }
1722 if (validatePrecision && variable1.precision != variable2.precision)
1723 {
1724 return LinkMismatchError::PRECISION_MISMATCH;
1725 }
1726 if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1727 variable1.structOrBlockName != variable2.structOrBlockName)
1728 {
1729 return LinkMismatchError::STRUCT_NAME_MISMATCH;
1730 }
1731 if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1732 {
1733 return LinkMismatchError::FORMAT_MISMATCH;
1734 }
1735
1736 if (variable1.fields.size() != variable2.fields.size())
1737 {
1738 return LinkMismatchError::FIELD_NUMBER_MISMATCH;
1739 }
1740 const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
1741 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1742 {
1743 const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
1744 const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
1745
1746 if (member1.name != member2.name)
1747 {
1748 return LinkMismatchError::FIELD_NAME_MISMATCH;
1749 }
1750
1751 if (member1.interpolation != member2.interpolation)
1752 {
1753 return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
1754 }
1755
1756 if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
1757 {
1758 if (member1.location != member2.location)
1759 {
1760 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
1761 }
1762
1763 if (member1.structOrBlockName != member2.structOrBlockName)
1764 {
1765 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
1766 }
1767 }
1768
1769 LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
1770 member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
1771 if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
1772 {
1773 AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
1774 return linkErrorOnField;
1775 }
1776 }
1777
1778 return LinkMismatchError::NO_MISMATCH;
1779 }
1780
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)1781 void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
1782 {
1783 ASSERT(mismatchedFieldName);
1784 if (mismatchedFieldName->empty())
1785 {
1786 *mismatchedFieldName = parentName;
1787 }
1788 else
1789 {
1790 std::ostringstream stream;
1791 stream << parentName << "." << *mismatchedFieldName;
1792 *mismatchedFieldName = stream.str();
1793 }
1794 }
1795
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)1796 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
1797 const std::vector<sh::ShaderVariable> &fragmentVaryings,
1798 int vertexShaderVersion,
1799 InfoLog &infoLog)
1800 {
1801 bool glPositionIsInvariant = false;
1802 bool glPointSizeIsInvariant = false;
1803 bool glFragCoordIsInvariant = false;
1804 bool glPointCoordIsInvariant = false;
1805
1806 for (const sh::ShaderVariable &varying : vertexVaryings)
1807 {
1808 if (!varying.isBuiltIn())
1809 {
1810 continue;
1811 }
1812 if (varying.name.compare("gl_Position") == 0)
1813 {
1814 glPositionIsInvariant = varying.isInvariant;
1815 }
1816 else if (varying.name.compare("gl_PointSize") == 0)
1817 {
1818 glPointSizeIsInvariant = varying.isInvariant;
1819 }
1820 }
1821
1822 for (const sh::ShaderVariable &varying : fragmentVaryings)
1823 {
1824 if (!varying.isBuiltIn())
1825 {
1826 continue;
1827 }
1828 if (varying.name.compare("gl_FragCoord") == 0)
1829 {
1830 glFragCoordIsInvariant = varying.isInvariant;
1831 }
1832 else if (varying.name.compare("gl_PointCoord") == 0)
1833 {
1834 glPointCoordIsInvariant = varying.isInvariant;
1835 }
1836 }
1837
1838 // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
1839 // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
1840 // Not requiring invariance to match is supported by:
1841 // dEQP, WebGL CTS, Nexus 5X GLES
1842 if (glFragCoordIsInvariant && !glPositionIsInvariant)
1843 {
1844 infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
1845 "declared invariant.";
1846 return false;
1847 }
1848 if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
1849 {
1850 infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
1851 "declared invariant.";
1852 return false;
1853 }
1854
1855 return true;
1856 }
1857
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)1858 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
1859 const std::vector<sh::ShaderVariable> &inputVaryings,
1860 ShaderType outputShaderType,
1861 ShaderType inputShaderType,
1862 int outputShaderVersion,
1863 int inputShaderVersion,
1864 InfoLog &infoLog)
1865 {
1866 ASSERT(outputShaderVersion == inputShaderVersion);
1867
1868 // Only ESSL 1.0 has restrictions on matching input and output invariance
1869 if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
1870 inputShaderType == ShaderType::Fragment)
1871 {
1872 return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
1873 outputShaderVersion, infoLog);
1874 }
1875
1876 uint32_t sizeClipDistance = 0;
1877 uint32_t sizeCullDistance = 0;
1878
1879 for (const sh::ShaderVariable &varying : outputVaryings)
1880 {
1881 if (!varying.isBuiltIn())
1882 {
1883 continue;
1884 }
1885 if (varying.name.compare("gl_ClipDistance") == 0)
1886 {
1887 sizeClipDistance = varying.getOutermostArraySize();
1888 }
1889 else if (varying.name.compare("gl_CullDistance") == 0)
1890 {
1891 sizeCullDistance = varying.getOutermostArraySize();
1892 }
1893 }
1894
1895 for (const sh::ShaderVariable &varying : inputVaryings)
1896 {
1897 if (!varying.isBuiltIn())
1898 {
1899 continue;
1900 }
1901 if (varying.name.compare("gl_ClipDistance") == 0)
1902 {
1903 if (sizeClipDistance != varying.getOutermostArraySize())
1904 {
1905 infoLog << "If either shader redeclares the built-in arrays gl_ClipDistance[] the "
1906 "array must have the same size in both shaders.";
1907 return false;
1908 }
1909 }
1910 else if (varying.name.compare("gl_CullDistance") == 0)
1911 {
1912 if (sizeCullDistance != varying.getOutermostArraySize())
1913 {
1914 infoLog << "If either shader redeclares the built-in arrays gl_CullDistance[] the "
1915 "array must have the same size in both shaders.";
1916 return false;
1917 }
1918 }
1919 }
1920 return true;
1921 }
1922 } // namespace gl
1923