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