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 validatePrecision = true;
55 #else
56 const bool validatePrecision = false;
57 #endif
58
59 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
60 uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
61 if (linkError != LinkMismatchError::NO_MISMATCH)
62 {
63 return linkError;
64 }
65
66 // GLSL ES Spec 3.10.4, section 4.4.5.
67 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
68 {
69 return LinkMismatchError::BINDING_MISMATCH;
70 }
71
72 // GLSL ES Spec 3.10.4, section 9.2.1.
73 if (uniform1.location != -1 && uniform2.location != -1 &&
74 uniform1.location != uniform2.location)
75 {
76 return LinkMismatchError::LOCATION_MISMATCH;
77 }
78 if (uniform1.offset != uniform2.offset)
79 {
80 return LinkMismatchError::OFFSET_MISMATCH;
81 }
82
83 return LinkMismatchError::NO_MISMATCH;
84 }
85
86 using ShaderUniform = std::pair<ShaderType, const sh::ShaderVariable *>;
87
ValidateGraphicsUniformsPerShader(Shader * shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog)88 bool ValidateGraphicsUniformsPerShader(Shader *shaderToLink,
89 bool extendLinkedUniforms,
90 std::map<std::string, ShaderUniform> *linkedUniforms,
91 InfoLog &infoLog)
92 {
93 ASSERT(shaderToLink && linkedUniforms);
94
95 for (const sh::ShaderVariable &uniform : shaderToLink->getUniforms())
96 {
97 const auto &entry = linkedUniforms->find(uniform.name);
98 if (entry != linkedUniforms->end())
99 {
100 const sh::ShaderVariable &linkedUniform = *(entry->second.second);
101 std::string mismatchedStructFieldName;
102 LinkMismatchError linkError =
103 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
104 if (linkError != LinkMismatchError::NO_MISMATCH)
105 {
106 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
107 mismatchedStructFieldName, entry->second.first,
108 shaderToLink->getType());
109 return false;
110 }
111 }
112 else if (extendLinkedUniforms)
113 {
114 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
115 }
116 }
117
118 return true;
119 }
120
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)121 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
122 {
123 switch (shaderType)
124 {
125 case ShaderType::Vertex:
126 return static_cast<GLuint>(caps.maxVertexUniformVectors);
127 case ShaderType::Fragment:
128 return static_cast<GLuint>(caps.maxFragmentUniformVectors);
129
130 case ShaderType::Compute:
131 case ShaderType::Geometry:
132 return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
133
134 default:
135 UNREACHABLE();
136 return 0u;
137 }
138 }
139
140 enum class UniformType : uint8_t
141 {
142 Variable = 0,
143 Sampler = 1,
144 Image = 2,
145 AtomicCounter = 3,
146
147 InvalidEnum = 4,
148 EnumCount = 4,
149 };
150
GetUniformResourceNameString(UniformType uniformType)151 const char *GetUniformResourceNameString(UniformType uniformType)
152 {
153 switch (uniformType)
154 {
155 case UniformType::Variable:
156 return "uniform";
157 case UniformType::Sampler:
158 return "texture image unit";
159 case UniformType::Image:
160 return "image uniform";
161 case UniformType::AtomicCounter:
162 return "atomic counter";
163 default:
164 UNREACHABLE();
165 return "";
166 }
167 }
168
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)169 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
170 {
171 // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
172 if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
173 {
174 return "MAX_TEXTURE_IMAGE_UNITS";
175 }
176
177 std::ostringstream ostream;
178 ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
179
180 switch (uniformType)
181 {
182 case UniformType::Variable:
183 // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
184 // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
185 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
186 {
187 ostream << "UNIFORM_VECTORS";
188 break;
189 }
190 // For compute and geometry shaders, there are no definitions on
191 // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
192 // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
193 else
194 {
195 ostream << "UNIFORM_COMPONENTS";
196 }
197 break;
198 case UniformType::Sampler:
199 ostream << "TEXTURE_IMAGE_UNITS";
200 break;
201 case UniformType::Image:
202 ostream << "IMAGE_UNIFORMS";
203 break;
204 case UniformType::AtomicCounter:
205 ostream << "ATOMIC_COUNTERS";
206 break;
207 default:
208 UNREACHABLE();
209 return "";
210 }
211
212 if (shaderType == ShaderType::Geometry)
213 {
214 ostream << "_EXT";
215 }
216
217 return ostream.str();
218 }
219
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)220 void LogUniformsExceedLimit(ShaderType shaderType,
221 UniformType uniformType,
222 GLuint limit,
223 InfoLog &infoLog)
224 {
225 infoLog << GetShaderTypeString(shaderType) << " shader "
226 << GetUniformResourceNameString(uniformType) << "s count exceeds "
227 << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
228 }
229
230 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
231 // added to "uniformsOut".
232 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
233 {
234 public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,ShaderType shaderType,int blockIndex)235 UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
236 const std::string &namePrefix,
237 const std::string &mappedNamePrefix,
238 std::vector<LinkedUniform> *uniformsOut,
239 ShaderType shaderType,
240 int blockIndex)
241 : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
242 mGetMemberInfo(getMemberInfo),
243 mUniformsOut(uniformsOut),
244 mShaderType(shaderType),
245 mBlockIndex(blockIndex)
246 {}
247
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)248 void visitNamedVariable(const sh::ShaderVariable &variable,
249 bool isRowMajor,
250 const std::string &name,
251 const std::string &mappedName,
252 const std::vector<unsigned int> &arraySizes) override
253 {
254 // If getBlockMemberInfo returns false, the variable is optimized out.
255 sh::BlockMemberInfo variableInfo;
256 if (!mGetMemberInfo(name, mappedName, &variableInfo))
257 return;
258
259 std::string nameWithArrayIndex = name;
260 std::string mappedNameWithArrayIndex = mappedName;
261
262 if (variable.isArray())
263 {
264 nameWithArrayIndex += "[0]";
265 mappedNameWithArrayIndex += "[0]";
266 }
267
268 if (mBlockIndex == -1)
269 {
270 SetActive(mUniformsOut, nameWithArrayIndex, mShaderType, variable.active);
271 return;
272 }
273
274 LinkedUniform newUniform(variable.type, variable.precision, nameWithArrayIndex,
275 variable.arraySizes, -1, -1, -1, mBlockIndex, variableInfo);
276 newUniform.mappedName = mappedNameWithArrayIndex;
277 newUniform.setActive(mShaderType, variable.active);
278
279 // Since block uniforms have no location, we don't need to store them in the uniform
280 // locations list.
281 mUniformsOut->push_back(newUniform);
282 }
283
284 private:
285 const GetBlockMemberInfoFunc &mGetMemberInfo;
286 std::vector<LinkedUniform> *mUniformsOut;
287 const ShaderType mShaderType;
288 const int mBlockIndex;
289 };
290
291 // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
292 // new buffer variable is stored in "bufferVariablesOut".
293 class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
294 {
295 public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)296 ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
297 const std::string &namePrefix,
298 const std::string &mappedNamePrefix,
299 std::vector<BufferVariable> *bufferVariablesOut,
300 ShaderType shaderType,
301 int blockIndex)
302 : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mDummyEncoder),
303 mGetMemberInfo(getMemberInfo),
304 mBufferVariablesOut(bufferVariablesOut),
305 mShaderType(shaderType),
306 mBlockIndex(blockIndex)
307 {}
308
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)309 void visitNamedVariable(const sh::ShaderVariable &variable,
310 bool isRowMajor,
311 const std::string &name,
312 const std::string &mappedName,
313 const std::vector<unsigned int> &arraySizes) override
314 {
315 if (mSkipEnabled)
316 return;
317
318 // If getBlockMemberInfo returns false, the variable is optimized out.
319 sh::BlockMemberInfo variableInfo;
320 if (!mGetMemberInfo(name, mappedName, &variableInfo))
321 return;
322
323 std::string nameWithArrayIndex = name;
324 std::string mappedNameWithArrayIndex = mappedName;
325
326 if (variable.isArray())
327 {
328 nameWithArrayIndex += "[0]";
329 mappedNameWithArrayIndex += "[0]";
330 }
331
332 if (mBlockIndex == -1)
333 {
334 SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active);
335 return;
336 }
337
338 BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
339 variable.arraySizes, mBlockIndex, variableInfo);
340 newBufferVariable.mappedName = mappedNameWithArrayIndex;
341 newBufferVariable.setActive(mShaderType, variable.active);
342
343 newBufferVariable.topLevelArraySize = mTopLevelArraySize;
344
345 mBufferVariablesOut->push_back(newBufferVariable);
346 }
347
348 private:
349 const GetBlockMemberInfoFunc &mGetMemberInfo;
350 std::vector<BufferVariable> *mBufferVariablesOut;
351 const ShaderType mShaderType;
352 const int mBlockIndex;
353 sh::DummyBlockEncoder mDummyEncoder;
354 };
355
356 struct ShaderUniformCount
357 {
358 unsigned int vectorCount = 0;
359 unsigned int samplerCount = 0;
360 unsigned int imageCount = 0;
361 unsigned int atomicCounterCount = 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 return lhs;
371 }
372
373 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
374 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
375 // Counts for each uniform category are stored and can be queried with "getCounts".
376 class FlattenUniformVisitor : public sh::VariableNameVisitor
377 {
378 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<UnusedUniform> * unusedUniforms)379 FlattenUniformVisitor(ShaderType shaderType,
380 const sh::ShaderVariable &uniform,
381 std::vector<LinkedUniform> *uniforms,
382 std::vector<LinkedUniform> *samplerUniforms,
383 std::vector<LinkedUniform> *imageUniforms,
384 std::vector<LinkedUniform> *atomicCounterUniforms,
385 std::vector<UnusedUniform> *unusedUniforms)
386 : sh::VariableNameVisitor("", ""),
387 mShaderType(shaderType),
388 mMarkActive(uniform.active),
389 mMarkStaticUse(uniform.staticUse),
390 mBinding(uniform.binding),
391 mOffset(uniform.offset),
392 mLocation(uniform.location),
393 mUniforms(uniforms),
394 mSamplerUniforms(samplerUniforms),
395 mImageUniforms(imageUniforms),
396 mAtomicCounterUniforms(atomicCounterUniforms),
397 mUnusedUniforms(unusedUniforms)
398 {}
399
visitNamedSampler(const sh::ShaderVariable & sampler,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)400 void visitNamedSampler(const sh::ShaderVariable &sampler,
401 const std::string &name,
402 const std::string &mappedName,
403 const std::vector<unsigned int> &arraySizes) override
404 {
405 visitNamedVariable(sampler, false, name, mappedName, arraySizes);
406 }
407
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)408 void visitNamedVariable(const sh::ShaderVariable &variable,
409 bool isRowMajor,
410 const std::string &name,
411 const std::string &mappedName,
412 const std::vector<unsigned int> &arraySizes) override
413 {
414 bool isSampler = IsSamplerType(variable.type);
415 bool isImage = IsImageType(variable.type);
416 bool isAtomicCounter = IsAtomicCounterType(variable.type);
417 std::vector<LinkedUniform> *uniformList = mUniforms;
418 if (isSampler)
419 {
420 uniformList = mSamplerUniforms;
421 }
422 else if (isImage)
423 {
424 uniformList = mImageUniforms;
425 }
426 else if (isAtomicCounter)
427 {
428 uniformList = mAtomicCounterUniforms;
429 }
430
431 std::string fullNameWithArrayIndex(name);
432 std::string fullMappedNameWithArrayIndex(mappedName);
433
434 if (variable.isArray())
435 {
436 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
437 // Resources and including [0] at the end of array variable names.
438 fullNameWithArrayIndex += "[0]";
439 fullMappedNameWithArrayIndex += "[0]";
440 }
441
442 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
443 if (existingUniform)
444 {
445 if (getBinding() != -1)
446 {
447 existingUniform->binding = getBinding();
448 }
449 if (getOffset() != -1)
450 {
451 existingUniform->offset = getOffset();
452 }
453 if (mLocation != -1)
454 {
455 existingUniform->location = mLocation;
456 }
457 if (mMarkActive)
458 {
459 existingUniform->active = true;
460 existingUniform->setActive(mShaderType, true);
461 }
462 if (mMarkStaticUse)
463 {
464 existingUniform->staticUse = true;
465 }
466 }
467 else
468 {
469 LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
470 variable.arraySizes, getBinding(), getOffset(), mLocation,
471 -1, sh::kDefaultBlockMemberInfo);
472 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
473 linkedUniform.active = mMarkActive;
474 linkedUniform.staticUse = mMarkStaticUse;
475 linkedUniform.outerArraySizes = arraySizes;
476 if (variable.hasParentArrayIndex())
477 {
478 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
479 }
480 if (mMarkActive)
481 {
482 linkedUniform.setActive(mShaderType, true);
483 }
484 else
485 {
486 mUnusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler(),
487 linkedUniform.isImage(),
488 linkedUniform.isAtomicCounter());
489 }
490
491 uniformList->push_back(linkedUniform);
492 }
493
494 unsigned int elementCount = variable.getBasicTypeElementCount();
495
496 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
497 // Likewise, don't count "real" uniforms towards opaque count.
498
499 if (!IsOpaqueType(variable.type))
500 {
501 mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
502 }
503
504 mUniformCount.samplerCount += (isSampler ? elementCount : 0);
505 mUniformCount.imageCount += (isImage ? elementCount : 0);
506 mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
507
508 if (mLocation != -1)
509 {
510 mLocation += elementCount;
511 }
512 }
513
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)514 void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
515 {
516 mStructStackSize++;
517 sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
518 }
519
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)520 void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
521 {
522 mStructStackSize--;
523 sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
524 }
525
getCounts() const526 ShaderUniformCount getCounts() const { return mUniformCount; }
527
528 private:
getBinding() const529 int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const530 int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
531
532 ShaderType mShaderType;
533
534 // Active and StaticUse are given separately because they are tracked at struct granularity.
535 bool mMarkActive;
536 bool mMarkStaticUse;
537 int mBinding;
538 int mOffset;
539 int mLocation;
540 std::vector<LinkedUniform> *mUniforms;
541 std::vector<LinkedUniform> *mSamplerUniforms;
542 std::vector<LinkedUniform> *mImageUniforms;
543 std::vector<LinkedUniform> *mAtomicCounterUniforms;
544 std::vector<UnusedUniform> *mUnusedUniforms;
545 ShaderUniformCount mUniformCount;
546 unsigned int mStructStackSize = 0;
547 };
548
549 class InterfaceBlockInfo final : angle::NonCopyable
550 {
551 public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)552 InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
553 : mCustomEncoderFactory(customEncoderFactory)
554 {}
555
556 void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
557
558 bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
559 bool getBlockMemberInfo(const std::string &name,
560 const std::string &mappedName,
561 sh::BlockMemberInfo *infoOut);
562
563 private:
564 size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
565
566 std::map<std::string, size_t> mBlockSizes;
567 sh::BlockLayoutMap mBlockLayout;
568 // Based on the interface block layout, the std140 or std430 encoders are used. On some
569 // platforms (currently only D3D), there could be another non-standard encoder used.
570 CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
571 };
572
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)573 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
574 {
575 for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
576 {
577 if (!IsActiveInterfaceBlock(interfaceBlock))
578 continue;
579
580 if (mBlockSizes.count(interfaceBlock.name) > 0)
581 continue;
582
583 size_t dataSize = getBlockInfo(interfaceBlock);
584 mBlockSizes[interfaceBlock.name] = dataSize;
585 }
586 }
587
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)588 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
589 {
590 ASSERT(IsActiveInterfaceBlock(interfaceBlock));
591
592 // define member uniforms
593 sh::Std140BlockEncoder std140Encoder;
594 sh::Std430BlockEncoder std430Encoder;
595 sh::BlockLayoutEncoder *customEncoder = nullptr;
596 sh::BlockLayoutEncoder *encoder = nullptr;
597
598 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
599 {
600 encoder = &std140Encoder;
601 }
602 else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
603 {
604 encoder = &std430Encoder;
605 }
606 else if (mCustomEncoderFactory)
607 {
608 encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
609 }
610 else
611 {
612 UNREACHABLE();
613 return 0;
614 }
615
616 sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
617 &mBlockLayout);
618
619 size_t offset = encoder->getCurrentOffset();
620
621 SafeDelete(customEncoder);
622
623 return offset;
624 }
625
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)626 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
627 const std::string &mappedName,
628 size_t *sizeOut)
629 {
630 size_t nameLengthWithoutArrayIndex;
631 ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
632 std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
633 auto sizeIter = mBlockSizes.find(baseName);
634 if (sizeIter == mBlockSizes.end())
635 {
636 *sizeOut = 0;
637 return false;
638 }
639
640 *sizeOut = sizeIter->second;
641 return true;
642 }
643
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)644 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
645 const std::string &mappedName,
646 sh::BlockMemberInfo *infoOut)
647 {
648 auto infoIter = mBlockLayout.find(name);
649 if (infoIter == mBlockLayout.end())
650 {
651 *infoOut = sh::kDefaultBlockMemberInfo;
652 return false;
653 }
654
655 *infoOut = infoIter->second;
656 return true;
657 }
658 } // anonymous namespace
659
UniformLinker(const ProgramState & state)660 UniformLinker::UniformLinker(const ProgramState &state) : mState(state) {}
661
662 UniformLinker::~UniformLinker() = default;
663
getResults(std::vector<LinkedUniform> * uniforms,std::vector<UnusedUniform> * unusedUniforms,std::vector<VariableLocation> * uniformLocations)664 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
665 std::vector<UnusedUniform> *unusedUniforms,
666 std::vector<VariableLocation> *uniformLocations)
667 {
668 uniforms->swap(mUniforms);
669 unusedUniforms->swap(mUnusedUniforms);
670 uniformLocations->swap(mUniformLocations);
671 }
672
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)673 bool UniformLinker::link(const Caps &caps,
674 InfoLog &infoLog,
675 const ProgramAliasedBindings &uniformLocationBindings)
676 {
677 if (mState.getAttachedShader(ShaderType::Vertex) &&
678 mState.getAttachedShader(ShaderType::Fragment))
679 {
680 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
681 if (!validateGraphicsUniforms(infoLog))
682 {
683 return false;
684 }
685 }
686
687 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
688 // Also check the maximum uniform vector and sampler counts.
689 if (!flattenUniformsAndCheckCaps(caps, infoLog))
690 {
691 return false;
692 }
693
694 if (!checkMaxCombinedAtomicCounters(caps, infoLog))
695 {
696 return false;
697 }
698
699 if (!indexUniforms(infoLog, uniformLocationBindings))
700 {
701 return false;
702 }
703
704 return true;
705 }
706
validateGraphicsUniforms(InfoLog & infoLog) const707 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
708 {
709 // Check that uniforms defined in the graphics shaders are identical
710 std::map<std::string, ShaderUniform> linkedUniforms;
711
712 for (const ShaderType shaderType : kAllGraphicsShaderTypes)
713 {
714 Shader *currentShader = mState.getAttachedShader(shaderType);
715 if (currentShader)
716 {
717 if (shaderType == ShaderType::Vertex)
718 {
719 for (const sh::ShaderVariable &vertexUniform : currentShader->getUniforms())
720 {
721 linkedUniforms[vertexUniform.name] =
722 std::make_pair(ShaderType::Vertex, &vertexUniform);
723 }
724 }
725 else
726 {
727 bool isLastShader = (shaderType == ShaderType::Fragment);
728 if (!ValidateGraphicsUniformsPerShader(currentShader, !isLastShader,
729 &linkedUniforms, infoLog))
730 {
731 return false;
732 }
733 }
734 }
735 }
736
737 return true;
738 }
739
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)740 bool UniformLinker::indexUniforms(InfoLog &infoLog,
741 const ProgramAliasedBindings &uniformLocationBindings)
742 {
743 // Locations which have been allocated for an unused uniform.
744 std::set<GLuint> ignoredLocations;
745
746 int maxUniformLocation = -1;
747
748 // Gather uniform locations that have been set either using the bindUniformLocation API or by
749 // using a location layout qualifier and check conflicts between them.
750 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
751 &ignoredLocations, &maxUniformLocation))
752 {
753 return false;
754 }
755
756 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
757 // the line relies on only having statically used uniforms in mUniforms.
758 pruneUnusedUniforms();
759
760 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
761 std::vector<VariableLocation> unlocatedUniforms;
762 std::map<GLuint, VariableLocation> preLocatedUniforms;
763
764 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
765 {
766 const LinkedUniform &uniform = mUniforms[uniformIndex];
767
768 if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
769 IsAtomicCounterType(uniform.type))
770 {
771 continue;
772 }
773
774 int preSetLocation = uniformLocationBindings.getBinding(uniform);
775 int shaderLocation = uniform.location;
776
777 if (shaderLocation != -1)
778 {
779 preSetLocation = shaderLocation;
780 }
781
782 unsigned int elementCount = uniform.getBasicTypeElementCount();
783 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
784 {
785 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
786
787 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
788 {
789 int elementLocation = preSetLocation + arrayIndex;
790 preLocatedUniforms[elementLocation] = location;
791 }
792 else
793 {
794 unlocatedUniforms.push_back(location);
795 }
796 }
797 }
798
799 // Make enough space for all uniforms, with pre-set locations or not.
800 mUniformLocations.resize(
801 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
802 static_cast<size_t>(maxUniformLocation + 1)));
803
804 // Assign uniforms with pre-set locations
805 for (const auto &uniform : preLocatedUniforms)
806 {
807 mUniformLocations[uniform.first] = uniform.second;
808 }
809
810 // Assign ignored uniforms
811 for (const auto &ignoredLocation : ignoredLocations)
812 {
813 mUniformLocations[ignoredLocation].markIgnored();
814 }
815
816 // Automatically assign locations for the rest of the uniforms
817 size_t nextUniformLocation = 0;
818 for (const auto &unlocatedUniform : unlocatedUniforms)
819 {
820 while (mUniformLocations[nextUniformLocation].used() ||
821 mUniformLocations[nextUniformLocation].ignored)
822 {
823 nextUniformLocation++;
824 }
825
826 ASSERT(nextUniformLocation < mUniformLocations.size());
827 mUniformLocations[nextUniformLocation] = unlocatedUniform;
828 nextUniformLocation++;
829 }
830
831 return true;
832 }
833
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)834 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
835 InfoLog &infoLog,
836 const ProgramAliasedBindings &uniformLocationBindings,
837 std::set<GLuint> *ignoredLocations,
838 int *maxUniformLocation)
839 {
840 // All the locations where another uniform can't be located.
841 std::set<GLuint> reservedLocations;
842
843 for (const LinkedUniform &uniform : mUniforms)
844 {
845 if (uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn())
846 {
847 continue;
848 }
849
850 int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
851 int shaderLocation = uniform.location;
852
853 if (shaderLocation != -1)
854 {
855 unsigned int elementCount = uniform.getBasicTypeElementCount();
856
857 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
858 {
859 // GLSL ES 3.10 section 4.4.3
860 int elementLocation = shaderLocation + arrayIndex;
861 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
862 if (reservedLocations.find(elementLocation) != reservedLocations.end())
863 {
864 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
865 return false;
866 }
867 reservedLocations.insert(elementLocation);
868 if (!uniform.active)
869 {
870 ignoredLocations->insert(elementLocation);
871 }
872 }
873 }
874 else if (apiBoundLocation != -1 && uniform.staticUse)
875 {
876 // Only the first location is reserved even if the uniform is an array.
877 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
878 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
879 {
880 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
881 return false;
882 }
883 reservedLocations.insert(apiBoundLocation);
884 if (!uniform.active)
885 {
886 ignoredLocations->insert(apiBoundLocation);
887 }
888 }
889 }
890
891 // Record the uniform locations that were bound using the API for uniforms that were not found
892 // from the shader. Other uniforms should not be assigned to those locations.
893 for (const auto &locationBinding : uniformLocationBindings)
894 {
895 GLuint location = locationBinding.second.location;
896 if (reservedLocations.find(location) == reservedLocations.end())
897 {
898 ignoredLocations->insert(location);
899 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
900 }
901 }
902
903 return true;
904 }
905
pruneUnusedUniforms()906 void UniformLinker::pruneUnusedUniforms()
907 {
908 auto uniformIter = mUniforms.begin();
909 while (uniformIter != mUniforms.end())
910 {
911 if (uniformIter->active)
912 {
913 ++uniformIter;
914 }
915 else
916 {
917 mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
918 uniformIter->isImage(), uniformIter->isAtomicCounter());
919 uniformIter = mUniforms.erase(uniformIter);
920 }
921 }
922 }
923
flattenUniformsAndCheckCapsForShader(Shader * shader,const Caps & caps,std::vector<LinkedUniform> & samplerUniforms,std::vector<LinkedUniform> & imageUniforms,std::vector<LinkedUniform> & atomicCounterUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)924 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
925 Shader *shader,
926 const Caps &caps,
927 std::vector<LinkedUniform> &samplerUniforms,
928 std::vector<LinkedUniform> &imageUniforms,
929 std::vector<LinkedUniform> &atomicCounterUniforms,
930 std::vector<UnusedUniform> &unusedUniforms,
931 InfoLog &infoLog)
932 {
933 ShaderUniformCount shaderUniformCount;
934 for (const sh::ShaderVariable &uniform : shader->getUniforms())
935 {
936 FlattenUniformVisitor flattener(shader->getType(), uniform, &mUniforms, &samplerUniforms,
937 &imageUniforms, &atomicCounterUniforms, &unusedUniforms);
938 sh::TraverseShaderVariable(uniform, false, &flattener);
939
940 if (uniform.active)
941 {
942 shaderUniformCount += flattener.getCounts();
943 }
944 else
945 {
946 unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
947 IsImageType(uniform.type),
948 IsAtomicCounterType(uniform.type));
949 }
950 }
951
952 ShaderType shaderType = shader->getType();
953
954 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
955 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
956 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
957 {
958 GLuint maxUniforms = 0u;
959
960 // See comments in GetUniformResourceLimitName()
961 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
962 {
963 maxUniforms = maxUniformVectorsCount;
964 }
965 else
966 {
967 maxUniforms = maxUniformVectorsCount * 4;
968 }
969
970 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
971 return false;
972 }
973
974 if (shaderUniformCount.samplerCount >
975 static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
976 {
977 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
978 caps.maxShaderTextureImageUnits[shaderType], infoLog);
979 return false;
980 }
981
982 if (shaderUniformCount.imageCount >
983 static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
984 {
985 LogUniformsExceedLimit(shaderType, UniformType::Image,
986 caps.maxShaderImageUniforms[shaderType], infoLog);
987 return false;
988 }
989
990 if (shaderUniformCount.atomicCounterCount >
991 static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
992 {
993 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
994 caps.maxShaderAtomicCounters[shaderType], infoLog);
995 return false;
996 }
997
998 return true;
999 }
1000
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1001 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1002 {
1003 std::vector<LinkedUniform> samplerUniforms;
1004 std::vector<LinkedUniform> imageUniforms;
1005 std::vector<LinkedUniform> atomicCounterUniforms;
1006 std::vector<UnusedUniform> unusedUniforms;
1007
1008 for (const ShaderType shaderType : AllShaderTypes())
1009 {
1010 Shader *shader = mState.getAttachedShader(shaderType);
1011 if (!shader)
1012 {
1013 continue;
1014 }
1015
1016 if (!flattenUniformsAndCheckCapsForShader(shader, caps, samplerUniforms, imageUniforms,
1017 atomicCounterUniforms, unusedUniforms, infoLog))
1018 {
1019 return false;
1020 }
1021 }
1022
1023 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1024 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1025 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1026 mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1027 return true;
1028 }
1029
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1030 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1031 {
1032 unsigned int atomicCounterCount = 0;
1033 for (const auto &uniform : mUniforms)
1034 {
1035 if (IsAtomicCounterType(uniform.type) && uniform.active)
1036 {
1037 atomicCounterCount += uniform.getBasicTypeElementCount();
1038 if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1039 {
1040 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1041 << caps.maxCombinedAtomicCounters << ").";
1042 return false;
1043 }
1044 }
1045 }
1046 return true;
1047 }
1048
1049 // InterfaceBlockLinker implementation.
InterfaceBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1050 InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1051 std::vector<std::string> *unusedInterfaceBlocksOut)
1052 : mShaderBlocks({}), mBlocksOut(blocksOut), mUnusedInterfaceBlocksOut(unusedInterfaceBlocksOut)
1053 {}
1054
~InterfaceBlockLinker()1055 InterfaceBlockLinker::~InterfaceBlockLinker() {}
1056
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1057 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1058 const std::vector<sh::InterfaceBlock> *blocks)
1059 {
1060 mShaderBlocks[shaderType] = blocks;
1061 }
1062
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1063 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1064 const GetBlockMemberInfoFunc &getMemberInfo) const
1065 {
1066 ASSERT(mBlocksOut->empty());
1067
1068 std::set<std::string> visitedList;
1069
1070 for (const ShaderType shaderType : AllShaderTypes())
1071 {
1072 if (!mShaderBlocks[shaderType])
1073 {
1074 continue;
1075 }
1076
1077 for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1078 {
1079 if (!IsActiveInterfaceBlock(block))
1080 {
1081 mUnusedInterfaceBlocksOut->push_back(block.name);
1082 continue;
1083 }
1084
1085 if (visitedList.count(block.name) == 0)
1086 {
1087 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1088 visitedList.insert(block.name);
1089 continue;
1090 }
1091
1092 if (!block.active)
1093 {
1094 mUnusedInterfaceBlocksOut->push_back(block.name);
1095 continue;
1096 }
1097
1098 for (InterfaceBlock &priorBlock : *mBlocksOut)
1099 {
1100 if (block.name == priorBlock.name)
1101 {
1102 priorBlock.setActive(shaderType, true);
1103
1104 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1105 getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1106 shaderType, -1));
1107
1108 sh::TraverseShaderVariables(block.fields, false, visitor.get());
1109 }
1110 }
1111 }
1112 }
1113 }
1114
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1115 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1116 const GetBlockMemberInfoFunc &getMemberInfo,
1117 const sh::InterfaceBlock &interfaceBlock,
1118 ShaderType shaderType) const
1119 {
1120 size_t blockSize = 0;
1121 std::vector<unsigned int> blockIndexes;
1122
1123 int blockIndex = static_cast<int>(mBlocksOut->size());
1124 // Track the first and last block member index to determine the range of active block members in
1125 // the block.
1126 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1127
1128 std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1129 getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1130 shaderType, blockIndex));
1131 sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1132
1133 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1134
1135 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1136 ++blockMemberIndex)
1137 {
1138 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1139 }
1140
1141 unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1142
1143 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1144 ++arrayElement)
1145 {
1146 std::string blockArrayName = interfaceBlock.name;
1147 std::string blockMappedArrayName = interfaceBlock.mappedName;
1148 if (interfaceBlock.isArray())
1149 {
1150 blockArrayName += ArrayString(arrayElement);
1151 blockMappedArrayName += ArrayString(arrayElement);
1152 }
1153
1154 // Don't define this block at all if it's not active in the implementation.
1155 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1156 {
1157 continue;
1158 }
1159
1160 // ESSL 3.10 section 4.4.4 page 58:
1161 // Any uniform or shader storage block declared without a binding qualifier is initially
1162 // assigned to block binding point zero.
1163 int blockBinding =
1164 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1165 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1166 interfaceBlock.isArray(), arrayElement, firstFieldArraySize,
1167 blockBinding);
1168 block.memberIndexes = blockIndexes;
1169 block.setActive(shaderType, interfaceBlock.active);
1170
1171 // Since all block elements in an array share the same active interface blocks, they
1172 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1173 // was active, here we will add every block element in the array.
1174 block.dataSize = static_cast<unsigned int>(blockSize);
1175 mBlocksOut->push_back(block);
1176 }
1177 }
1178
1179 // UniformBlockLinker implementation.
UniformBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * unusedInterfaceBlocksOut)1180 UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1181 std::vector<LinkedUniform> *uniformsOut,
1182 std::vector<std::string> *unusedInterfaceBlocksOut)
1183 : InterfaceBlockLinker(blocksOut, unusedInterfaceBlocksOut), mUniformsOut(uniformsOut)
1184 {}
1185
~UniformBlockLinker()1186 UniformBlockLinker::~UniformBlockLinker() {}
1187
getCurrentBlockMemberIndex() const1188 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1189 {
1190 return mUniformsOut->size();
1191 }
1192
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1193 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1194 const GetBlockMemberInfoFunc &getMemberInfo,
1195 const std::string &namePrefix,
1196 const std::string &mappedNamePrefix,
1197 ShaderType shaderType,
1198 int blockIndex) const
1199 {
1200 return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1201 mUniformsOut, shaderType, blockIndex);
1202 }
1203
1204 // ShaderStorageBlockLinker implementation.
ShaderStorageBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1205 ShaderStorageBlockLinker::ShaderStorageBlockLinker(
1206 std::vector<InterfaceBlock> *blocksOut,
1207 std::vector<BufferVariable> *bufferVariablesOut,
1208 std::vector<std::string> *unusedInterfaceBlocksOut)
1209 : InterfaceBlockLinker(blocksOut, unusedInterfaceBlocksOut),
1210 mBufferVariablesOut(bufferVariablesOut)
1211 {}
1212
~ShaderStorageBlockLinker()1213 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() {}
1214
getCurrentBlockMemberIndex() const1215 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1216 {
1217 return mBufferVariablesOut->size();
1218 }
1219
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1220 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1221 const GetBlockMemberInfoFunc &getMemberInfo,
1222 const std::string &namePrefix,
1223 const std::string &mappedNamePrefix,
1224 ShaderType shaderType,
1225 int blockIndex) const
1226 {
1227 return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1228 mBufferVariablesOut, shaderType, blockIndex);
1229 }
1230
1231 // AtomicCounterBufferLinker implementation.
AtomicCounterBufferLinker(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1232 AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1233 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1234 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1235 {}
1236
~AtomicCounterBufferLinker()1237 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() {}
1238
link(const std::map<int,unsigned int> & sizeMap) const1239 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1240 {
1241 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1242 {
1243 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1244 ASSERT(bufferSize != sizeMap.end());
1245 atomicCounterBuffer.dataSize = bufferSize->second;
1246 }
1247 }
1248
ProgramLinkedResources(GLuint maxVaryingVectors,PackMode packMode,std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1249 ProgramLinkedResources::ProgramLinkedResources(
1250 GLuint maxVaryingVectors,
1251 PackMode packMode,
1252 std::vector<InterfaceBlock> *uniformBlocksOut,
1253 std::vector<LinkedUniform> *uniformsOut,
1254 std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1255 std::vector<BufferVariable> *bufferVariablesOut,
1256 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1257 : varyingPacking(maxVaryingVectors, packMode),
1258 uniformBlockLinker(uniformBlocksOut, uniformsOut, &unusedInterfaceBlocks),
1259 shaderStorageBlockLinker(shaderStorageBlocksOut, bufferVariablesOut, &unusedInterfaceBlocks),
1260 atomicCounterBufferLinker(atomicCounterBuffersOut)
1261 {}
1262
1263 ProgramLinkedResources::~ProgramLinkedResources() = default;
1264
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1265 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1266 const ProgramLinkedResources &resources) const
1267 {
1268 // Gather uniform interface block info.
1269 InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1270 for (const ShaderType shaderType : AllShaderTypes())
1271 {
1272 Shader *shader = programState.getAttachedShader(shaderType);
1273 if (shader)
1274 {
1275 uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
1276 }
1277 }
1278
1279 auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1280 const std::string &mappedName, size_t *sizeOut) {
1281 return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1282 };
1283
1284 auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1285 const std::string &mappedName,
1286 sh::BlockMemberInfo *infoOut) {
1287 return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1288 };
1289
1290 // Link uniform interface blocks.
1291 resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1292
1293 // Gather storage bufer interface block info.
1294 InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1295 for (const ShaderType shaderType : AllShaderTypes())
1296 {
1297 Shader *shader = programState.getAttachedShader(shaderType);
1298 if (shader)
1299 {
1300 shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
1301 }
1302 }
1303 auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1304 const std::string &mappedName,
1305 size_t *sizeOut) {
1306 return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1307 };
1308
1309 auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1310 const std::string &mappedName,
1311 sh::BlockMemberInfo *infoOut) {
1312 return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1313 };
1314
1315 // Link storage buffer interface blocks.
1316 resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1317 getShaderStorageBlockMemberInfo);
1318
1319 // Gather and link atomic counter buffer interface blocks.
1320 std::map<int, unsigned int> sizeMap;
1321 getAtomicCounterBufferSizeMap(programState, sizeMap);
1322 resources.atomicCounterBufferLinker.link(sizeMap);
1323 }
1324
getAtomicCounterBufferSizeMap(const ProgramState & programState,std::map<int,unsigned int> & sizeMapOut) const1325 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1326 const ProgramState &programState,
1327 std::map<int, unsigned int> &sizeMapOut) const
1328 {
1329 for (unsigned int index : programState.getAtomicCounterUniformRange())
1330 {
1331 const LinkedUniform &glUniform = programState.getUniforms()[index];
1332
1333 auto &bufferDataSize = sizeMapOut[glUniform.binding];
1334
1335 // Calculate the size of the buffer by finding the end of the last uniform with the same
1336 // binding. The end of the uniform is calculated by finding the initial offset of the
1337 // uniform and adding size of the uniform. For arrays, the size is the number of elements
1338 // times the element size (should always by 4 for atomic_units).
1339 unsigned dataOffset =
1340 glUniform.offset + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1341 glUniform.getElementSize());
1342 if (dataOffset > bufferDataSize)
1343 {
1344 bufferDataSize = dataOffset;
1345 }
1346 }
1347 }
1348
1349 } // namespace gl
1350