blob: 2263544dcc99a01aefea9e73185692cd7c72b70f [file] [log] [blame]
Olli Etuahob78707c2017-03-09 15:03:11 +00001//
2// Copyright (c) 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
Jiawei Shao881b7bf2017-12-25 11:18:37 +08007// 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.
Olli Etuahob78707c2017-03-09 15:03:11 +000010
Jamie Madill7af0de52017-11-06 17:09:33 -050011#include "libANGLE/ProgramLinkedResources.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000012
Olli Etuahod2551232017-10-26 20:03:33 +030013#include "common/string_utils.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000014#include "common/utilities.h"
15#include "libANGLE/Caps.h"
Jamie Madillbd044ed2017-06-05 12:59:21 -040016#include "libANGLE/Context.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000017#include "libANGLE/Shader.h"
Jiawei-Shaoddb5eb52017-03-14 13:36:18 +080018#include "libANGLE/features.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000019
20namespace gl
21{
22
23namespace
24{
25
26LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
27{
28 for (LinkedUniform &uniform : list)
29 {
30 if (uniform.name == name)
31 return &uniform;
32 }
33
34 return nullptr;
35}
36
Jamie Madill3c1da042017-11-27 18:33:40 -050037int GetUniformLocationBinding(const ProgramBindings &uniformLocationBindings,
Olli Etuahod2551232017-10-26 20:03:33 +030038 const sh::Uniform &uniform)
39{
40 int binding = uniformLocationBindings.getBinding(uniform.name);
41 if (uniform.isArray() && binding == -1)
42 {
43 // Bindings for array uniforms can be set either with or without [0] in the end.
44 ASSERT(angle::EndsWith(uniform.name, "[0]"));
45 std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u);
46 return uniformLocationBindings.getBinding(nameWithoutIndex);
47 }
48 return binding;
49}
50
Qin Jiajiacd3acf62017-12-05 16:27:25 +080051template <typename VarT>
Jiawei Shao385b3e02018-03-21 09:43:28 +080052void SetActive(std::vector<VarT> *list, const std::string &name, ShaderType shaderType, bool active)
Qin Jiajiacd3acf62017-12-05 16:27:25 +080053{
54 for (auto &variable : *list)
55 {
56 if (variable.name == name)
57 {
Olli Etuaho107c7242018-03-20 15:45:35 +020058 variable.setActive(shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +080059 return;
60 }
61 }
62}
63
Jiawei Shao0d88ec92018-02-27 16:25:31 +080064// GLSL ES Spec 3.00.3, section 4.3.5.
65LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
66 const sh::Uniform &uniform2,
67 std::string *mismatchedStructFieldName)
68{
69#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
70 const bool validatePrecision = true;
71#else
72 const bool validatePrecision = false;
73#endif
74
75 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
76 uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
77 if (linkError != LinkMismatchError::NO_MISMATCH)
78 {
79 return linkError;
80 }
81
82 // GLSL ES Spec 3.10.4, section 4.4.5.
83 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
84 {
85 return LinkMismatchError::BINDING_MISMATCH;
86 }
87
88 // GLSL ES Spec 3.10.4, section 9.2.1.
89 if (uniform1.location != -1 && uniform2.location != -1 &&
90 uniform1.location != uniform2.location)
91 {
92 return LinkMismatchError::LOCATION_MISMATCH;
93 }
94 if (uniform1.offset != uniform2.offset)
95 {
96 return LinkMismatchError::OFFSET_MISMATCH;
97 }
98
99 return LinkMismatchError::NO_MISMATCH;
100}
101
Jiawei Shao385b3e02018-03-21 09:43:28 +0800102using ShaderUniform = std::pair<ShaderType, const sh::Uniform *>;
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800103
104bool ValidateGraphicsUniformsPerShader(const Context *context,
105 Shader *shaderToLink,
106 bool extendLinkedUniforms,
107 std::map<std::string, ShaderUniform> *linkedUniforms,
108 InfoLog &infoLog)
109{
110 ASSERT(context && shaderToLink && linkedUniforms);
111
112 for (const sh::Uniform &uniform : shaderToLink->getUniforms(context))
113 {
114 const auto &entry = linkedUniforms->find(uniform.name);
115 if (entry != linkedUniforms->end())
116 {
117 const sh::Uniform &linkedUniform = *(entry->second.second);
118 std::string mismatchedStructFieldName;
119 LinkMismatchError linkError =
120 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
121 if (linkError != LinkMismatchError::NO_MISMATCH)
122 {
123 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
124 mismatchedStructFieldName, entry->second.first,
125 shaderToLink->getType());
126 return false;
127 }
128 }
129 else if (extendLinkedUniforms)
130 {
131 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
132 }
133 }
134
135 return true;
136}
137
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800138GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
139{
140 switch (shaderType)
141 {
142 case ShaderType::Vertex:
143 return caps.maxVertexUniformVectors;
144 case ShaderType::Fragment:
145 return caps.maxFragmentUniformVectors;
146
147 case ShaderType::Compute:
148 case ShaderType::Geometry:
149 return caps.maxShaderUniformComponents[shaderType] / 4;
150
151 default:
152 UNREACHABLE();
153 return 0u;
154 }
155}
156
157enum class UniformType : uint8_t
158{
159 Variable = 0,
160 Sampler = 1,
161 Image = 2,
162 AtomicCounter = 3,
163
164 InvalidEnum = 4,
165 EnumCount = 4,
166};
167
168const char *GetUniformResourceNameString(UniformType uniformType)
169{
170 switch (uniformType)
171 {
172 case UniformType::Variable:
173 return "uniform";
174 case UniformType::Sampler:
175 return "texture image unit";
176 case UniformType::Image:
177 return "image uniform";
178 case UniformType::AtomicCounter:
179 return "atomic counter";
180 default:
181 UNREACHABLE();
182 return "";
183 }
184}
185
186std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
187{
188 // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
189 if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
190 {
191 return "MAX_TEXTURE_IMAGE_UNITS";
192 }
193
194 std::ostringstream ostream;
195 ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
196
197 switch (uniformType)
198 {
199 case UniformType::Variable:
200 // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
201 // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
202 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
203 {
204 ostream << "UNIFORM_VECTORS";
205 break;
206 }
207 // For compute and geometry shaders, there are no definitions on
208 // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
209 // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
210 else
211 {
212 ostream << "UNIFORM_COMPONENTS";
213 }
214 break;
215 case UniformType::Sampler:
216 ostream << "TEXTURE_IMAGE_UNITS";
217 break;
218 case UniformType::Image:
219 ostream << "IMAGE_UNIFORMS";
220 break;
221 case UniformType::AtomicCounter:
222 ostream << "ATOMIC_COUNTERS";
223 break;
224 default:
225 UNREACHABLE();
226 return "";
227 }
228
229 if (shaderType == ShaderType::Geometry)
230 {
231 ostream << "_EXT";
232 }
233
234 return ostream.str();
235}
236
237void LogUniformsExceedLimit(ShaderType shaderType,
238 UniformType uniformType,
239 GLuint limit,
240 InfoLog &infoLog)
241{
242 infoLog << GetShaderTypeString(shaderType) << " shader "
243 << GetUniformResourceNameString(uniformType) << "s count exceeds "
244 << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
245}
246
Olli Etuahod2551232017-10-26 20:03:33 +0300247} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +0000248
249UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
250{
251}
252
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500253UniformLinker::~UniformLinker() = default;
254
Olli Etuahob78707c2017-03-09 15:03:11 +0000255void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
256 std::vector<VariableLocation> *uniformLocations)
257{
258 uniforms->swap(mUniforms);
259 uniformLocations->swap(mUniformLocations);
260}
261
Jamie Madillbd044ed2017-06-05 12:59:21 -0400262bool UniformLinker::link(const Context *context,
263 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500264 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000265{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800266 if (mState.getAttachedShader(ShaderType::Vertex) &&
267 mState.getAttachedShader(ShaderType::Fragment))
Olli Etuahob78707c2017-03-09 15:03:11 +0000268 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800269 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +0800270 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000271 {
272 return false;
273 }
274 }
275
276 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
277 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -0400278 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000279 {
280 return false;
281 }
282
jchen10eaef1e52017-06-13 10:44:11 +0800283 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
284 {
285 return false;
286 }
287
Olli Etuahob78707c2017-03-09 15:03:11 +0000288 if (!indexUniforms(infoLog, uniformLocationBindings))
289 {
290 return false;
291 }
292
293 return true;
294}
295
Jiawei Shao73618602017-12-20 15:47:15 +0800296bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000297{
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800298 // Check that uniforms defined in the graphics shaders are identical
299 std::map<std::string, ShaderUniform> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000300
Jiawei Shao016105b2018-04-12 16:38:31 +0800301 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Olli Etuahob78707c2017-03-09 15:03:11 +0000302 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800303 Shader *currentShader = mState.getAttachedShader(shaderType);
304 if (currentShader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000305 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800306 if (shaderType == ShaderType::Vertex)
307 {
308 for (const sh::Uniform &vertexUniform : currentShader->getUniforms(context))
309 {
310 linkedUniforms[vertexUniform.name] =
311 std::make_pair(ShaderType::Vertex, &vertexUniform);
312 }
313 }
314 else
315 {
316 bool isLastShader = (shaderType == ShaderType::Fragment);
317 if (!ValidateGraphicsUniformsPerShader(context, currentShader, !isLastShader,
318 &linkedUniforms, infoLog))
319 {
320 return false;
321 }
322 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000323 }
324 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800325
Olli Etuahob78707c2017-03-09 15:03:11 +0000326 return true;
327}
328
Jamie Madill3c1da042017-11-27 18:33:40 -0500329bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000330{
Olli Etuahob78707c2017-03-09 15:03:11 +0000331 // Locations which have been allocated for an unused uniform.
332 std::set<GLuint> ignoredLocations;
333
334 int maxUniformLocation = -1;
335
336 // Gather uniform locations that have been set either using the bindUniformLocation API or by
337 // using a location layout qualifier and check conflicts between them.
338 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
Olli Etuaho44861c42018-03-23 14:36:39 +0200339 &ignoredLocations, &maxUniformLocation))
Olli Etuahob78707c2017-03-09 15:03:11 +0000340 {
341 return false;
342 }
343
344 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
345 // the line relies on only having statically used uniforms in mUniforms.
346 pruneUnusedUniforms();
347
348 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
349 std::vector<VariableLocation> unlocatedUniforms;
350 std::map<GLuint, VariableLocation> preLocatedUniforms;
351
352 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
353 {
354 const LinkedUniform &uniform = mUniforms[uniformIndex];
355
jchen10baf5d942017-08-28 20:45:48 +0800356 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000357 {
358 continue;
359 }
360
Olli Etuahod2551232017-10-26 20:03:33 +0300361 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000362 int shaderLocation = uniform.location;
363
364 if (shaderLocation != -1)
365 {
366 preSetLocation = shaderLocation;
367 }
368
Olli Etuaho465835d2017-09-26 13:34:10 +0300369 unsigned int elementCount = uniform.getBasicTypeElementCount();
370 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000371 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400372 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000373
374 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
375 {
376 int elementLocation = preSetLocation + arrayIndex;
377 preLocatedUniforms[elementLocation] = location;
378 }
379 else
380 {
381 unlocatedUniforms.push_back(location);
382 }
383 }
384 }
385
386 // Make enough space for all uniforms, with pre-set locations or not.
387 mUniformLocations.resize(
388 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
389 static_cast<size_t>(maxUniformLocation + 1)));
390
391 // Assign uniforms with pre-set locations
392 for (const auto &uniform : preLocatedUniforms)
393 {
394 mUniformLocations[uniform.first] = uniform.second;
395 }
396
397 // Assign ignored uniforms
398 for (const auto &ignoredLocation : ignoredLocations)
399 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400400 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000401 }
402
403 // Automatically assign locations for the rest of the uniforms
404 size_t nextUniformLocation = 0;
405 for (const auto &unlocatedUniform : unlocatedUniforms)
406 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400407 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000408 mUniformLocations[nextUniformLocation].ignored)
409 {
410 nextUniformLocation++;
411 }
412
413 ASSERT(nextUniformLocation < mUniformLocations.size());
414 mUniformLocations[nextUniformLocation] = unlocatedUniform;
415 nextUniformLocation++;
416 }
417
418 return true;
419}
420
421bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
422 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500423 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000424 std::set<GLuint> *ignoredLocations,
425 int *maxUniformLocation)
426{
Olli Etuaho44861c42018-03-23 14:36:39 +0200427 // All the locations where another uniform can't be located.
428 std::set<GLuint> reservedLocations;
429
Olli Etuahob78707c2017-03-09 15:03:11 +0000430 for (const LinkedUniform &uniform : mUniforms)
431 {
432 if (uniform.isBuiltIn())
433 {
434 continue;
435 }
436
Olli Etuahod2551232017-10-26 20:03:33 +0300437 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000438 int shaderLocation = uniform.location;
439
440 if (shaderLocation != -1)
441 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300442 unsigned int elementCount = uniform.getBasicTypeElementCount();
443
444 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000445 {
446 // GLSL ES 3.10 section 4.4.3
447 int elementLocation = shaderLocation + arrayIndex;
448 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200449 if (reservedLocations.find(elementLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000450 {
451 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
452 return false;
453 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200454 reservedLocations.insert(elementLocation);
Olli Etuaho107c7242018-03-20 15:45:35 +0200455 if (!uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000456 {
457 ignoredLocations->insert(elementLocation);
458 }
459 }
460 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200461 else if (apiBoundLocation != -1 && uniform.staticUse)
Olli Etuahob78707c2017-03-09 15:03:11 +0000462 {
463 // Only the first location is reserved even if the uniform is an array.
464 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200465 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000466 {
467 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
468 return false;
469 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200470 reservedLocations.insert(apiBoundLocation);
471 if (!uniform.active)
472 {
473 ignoredLocations->insert(apiBoundLocation);
474 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000475 }
476 }
477
478 // Record the uniform locations that were bound using the API for uniforms that were not found
479 // from the shader. Other uniforms should not be assigned to those locations.
480 for (const auto &locationBinding : uniformLocationBindings)
481 {
482 GLuint location = locationBinding.second;
Olli Etuaho44861c42018-03-23 14:36:39 +0200483 if (reservedLocations.find(location) == reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000484 {
485 ignoredLocations->insert(location);
486 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
487 }
488 }
489
490 return true;
491}
492
493void UniformLinker::pruneUnusedUniforms()
494{
495 auto uniformIter = mUniforms.begin();
496 while (uniformIter != mUniforms.end())
497 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200498 if (uniformIter->active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000499 {
500 ++uniformIter;
501 }
502 else
503 {
504 uniformIter = mUniforms.erase(uniformIter);
505 }
506 }
507}
508
509bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400510 const Context *context,
511 Shader *shader,
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800512 const Caps &caps,
Olli Etuahob78707c2017-03-09 15:03:11 +0000513 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800514 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800515 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000516 InfoLog &infoLog)
517{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800518 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400519 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000520 {
jchen10baf5d942017-08-28 20:45:48 +0800521 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
522 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000523 }
524
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800525 ShaderType shaderType = shader->getType();
526
527 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
528 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
529 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
Olli Etuahob78707c2017-03-09 15:03:11 +0000530 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800531 GLuint maxUniforms = 0u;
532
533 // See comments in GetUniformResourceLimitName()
534 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
535 {
536 maxUniforms = maxUniformVectorsCount;
537 }
538 else
539 {
540 maxUniforms = maxUniformVectorsCount * 4;
541 }
542
543 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000544 return false;
545 }
546
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800547 if (shaderUniformCount.samplerCount > caps.maxShaderTextureImageUnits[shaderType])
Olli Etuahob78707c2017-03-09 15:03:11 +0000548 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800549 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
550 caps.maxShaderTextureImageUnits[shaderType], infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000551 return false;
552 }
553
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800554 if (shaderUniformCount.imageCount > caps.maxShaderImageUniforms[shaderType])
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800555 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800556 LogUniformsExceedLimit(shaderType, UniformType::Image,
557 caps.maxShaderImageUniforms[shaderType], infoLog);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800558 return false;
559 }
560
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800561 if (shaderUniformCount.atomicCounterCount > caps.maxShaderAtomicCounters[shaderType])
jchen10eaef1e52017-06-13 10:44:11 +0800562 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800563 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
564 caps.maxShaderAtomicCounters[shaderType], infoLog);
jchen10eaef1e52017-06-13 10:44:11 +0800565 return false;
566 }
567
Olli Etuahob78707c2017-03-09 15:03:11 +0000568 return true;
569}
570
Jamie Madillbd044ed2017-06-05 12:59:21 -0400571bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000572{
573 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800574 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800575 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000576
Jamie Madillbd044ed2017-06-05 12:59:21 -0400577 const Caps &caps = context->getCaps();
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800578 for (ShaderType shaderType : AllShaderTypes())
Olli Etuahob78707c2017-03-09 15:03:11 +0000579 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800580 Shader *shader = mState.getAttachedShader(shaderType);
581 if (!shader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000582 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800583 continue;
Olli Etuahob78707c2017-03-09 15:03:11 +0000584 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400585
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800586 if (!flattenUniformsAndCheckCapsForShader(context, shader, caps, samplerUniforms,
587 imageUniforms, atomicCounterUniforms, infoLog))
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800588 {
589 return false;
590 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000591 }
592
593 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800594 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800595 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000596 return true;
597}
598
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800599UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000600 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800601 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800602 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800603 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800604 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000605{
Jamie Madill977abce2017-11-07 08:03:19 -0500606 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800607 ShaderUniformCount shaderUniformCount =
608 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200609 imageUniforms, atomicCounterUniforms, shaderType, uniform.active,
Olli Etuaho44861c42018-03-23 14:36:39 +0200610 uniform.staticUse, uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200611 if (uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000612 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800613 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000614 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800615 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000616}
617
Olli Etuaho465835d2017-09-26 13:34:10 +0300618UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
619 const sh::ShaderVariable &uniform,
620 unsigned int arrayNestingIndex,
621 const std::string &namePrefix,
622 const std::string &mappedNamePrefix,
623 std::vector<LinkedUniform> *samplerUniforms,
624 std::vector<LinkedUniform> *imageUniforms,
625 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800626 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200627 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200628 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300629 int binding,
630 int offset,
631 int *location)
632{
633 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
634 // innermost.
635 ShaderUniformCount shaderUniformCount;
636 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
637 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
638 {
639 const std::string elementName = namePrefix + ArrayString(arrayElement);
640 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
641 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
642 {
643 shaderUniformCount += flattenArrayOfStructsUniform(
644 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200645 imageUniforms, atomicCounterUniforms, shaderType, markActive, markStaticUse,
646 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300647 }
648 else
649 {
650 shaderUniformCount += flattenStructUniform(
651 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200652 atomicCounterUniforms, shaderType, markActive, markStaticUse, binding, offset,
653 location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300654 }
655 }
656 return shaderUniformCount;
657}
658
659UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
660 const std::vector<sh::ShaderVariable> &fields,
661 const std::string &namePrefix,
662 const std::string &mappedNamePrefix,
663 std::vector<LinkedUniform> *samplerUniforms,
664 std::vector<LinkedUniform> *imageUniforms,
665 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800666 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200667 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200668 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300669 int binding,
670 int offset,
671 int *location)
672{
673 ShaderUniformCount shaderUniformCount;
674 for (const sh::ShaderVariable &field : fields)
675 {
676 const std::string &fieldName = namePrefix + "." + field.name;
677 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
678
Olli Etuaho44861c42018-03-23 14:36:39 +0200679 shaderUniformCount += flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms,
680 imageUniforms, atomicCounterUniforms, shaderType,
681 markActive, markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300682 }
683 return shaderUniformCount;
684}
685
686UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
687 const sh::ShaderVariable &uniform,
688 const std::string &namePrefix,
689 const std::string &mappedNamePrefix,
690 std::vector<LinkedUniform> *samplerUniforms,
691 std::vector<LinkedUniform> *imageUniforms,
692 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800693 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200694 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200695 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300696 int binding,
697 int offset,
698 int *location)
699{
700 ShaderUniformCount shaderUniformCount;
701
702 ASSERT(uniform.isArray());
703 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
704 ++arrayElement)
705 {
706 sh::ShaderVariable uniformElement = uniform;
707 uniformElement.indexIntoArray(arrayElement);
708 const std::string elementName = namePrefix + ArrayString(arrayElement);
709 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
710
Olli Etuaho44861c42018-03-23 14:36:39 +0200711 shaderUniformCount +=
712 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
713 imageUniforms, atomicCounterUniforms, shaderType, markActive,
714 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300715 }
716 return shaderUniformCount;
717}
718
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800719UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000720 const sh::ShaderVariable &uniform,
721 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300722 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000723 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800724 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800725 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800726 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200727 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200728 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000729 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800730 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000731 int *location)
732{
733 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800734 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000735
736 if (uniform.isStruct())
737 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300738 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000739 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200740 shaderUniformCount +=
741 flattenArrayOfStructsUniform(uniform, 0u, fullName, fullMappedName, samplerUniforms,
742 imageUniforms, atomicCounterUniforms, shaderType,
743 markActive, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000744 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300745 else
746 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200747 shaderUniformCount +=
748 flattenStructUniform(uniform.fields, fullName, fullMappedName, samplerUniforms,
749 imageUniforms, atomicCounterUniforms, shaderType, markActive,
750 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300751 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800752 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000753 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300754 if (uniform.isArrayOfArrays())
755 {
756 // GLES 3.1 November 2016 section 7.3.1 page 77:
757 // "For an active variable declared as an array of an aggregate data type (structures or
758 // arrays), a separate entry will be generated for each active array element"
759 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200760 imageUniforms, atomicCounterUniforms, shaderType, markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200761 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300762 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000763
764 // Not a struct
765 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800766 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800767 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000768 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
769 if (isSampler)
770 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000771 uniformList = samplerUniforms;
772 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800773 else if (isImage)
774 {
775 uniformList = imageUniforms;
776 }
jchen10eaef1e52017-06-13 10:44:11 +0800777 else if (isAtomicCounter)
778 {
779 uniformList = atomicCounterUniforms;
780 }
Olli Etuahod2551232017-10-26 20:03:33 +0300781
782 std::string fullNameWithArrayIndex(fullName);
783 std::string fullMappedNameWithArrayIndex(fullMappedName);
784
785 if (uniform.isArray())
786 {
787 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
788 // and including [0] at the end of array variable names.
789 fullNameWithArrayIndex += "[0]";
790 fullMappedNameWithArrayIndex += "[0]";
791 }
792
793 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000794 if (existingUniform)
795 {
796 if (binding != -1)
797 {
798 existingUniform->binding = binding;
799 }
jchen10eaef1e52017-06-13 10:44:11 +0800800 if (offset != -1)
801 {
802 existingUniform->offset = offset;
803 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000804 if (*location != -1)
805 {
806 existingUniform->location = *location;
807 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200808 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000809 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200810 existingUniform->active = true;
811 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000812 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200813 if (markStaticUse)
814 {
815 existingUniform->staticUse = true;
816 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000817 }
818 else
819 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300820 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300821 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300822 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000823 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300824 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200825 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200826 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300827 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200828 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800829 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200830 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800831 }
jchen10eaef1e52017-06-13 10:44:11 +0800832
Olli Etuahob78707c2017-03-09 15:03:11 +0000833 uniformList->push_back(linkedUniform);
834 }
835
Olli Etuaho465835d2017-09-26 13:34:10 +0300836 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
837 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000838
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800839 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800840 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800841 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800842 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500843 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500844 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800845 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000846
847 if (*location != -1)
848 {
849 *location += elementCount;
850 }
851
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800852 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000853}
854
jchen10eaef1e52017-06-13 10:44:11 +0800855bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
856{
857 unsigned int atomicCounterCount = 0;
858 for (const auto &uniform : mUniforms)
859 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200860 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800861 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300862 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800863 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
864 {
865 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
866 << caps.maxCombinedAtomicCounters << ").";
867 return false;
868 }
869 }
870 }
871 return true;
872}
873
Jamie Madill977abce2017-11-07 08:03:19 -0500874// InterfaceBlockLinker implementation.
875InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
Jiawei Shao016105b2018-04-12 16:38:31 +0800876 : mShaderBlocks({}), mBlocksOut(blocksOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500877{
878}
879
880InterfaceBlockLinker::~InterfaceBlockLinker()
881{
882}
883
Jiawei Shao016105b2018-04-12 16:38:31 +0800884void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
Jamie Madill977abce2017-11-07 08:03:19 -0500885 const std::vector<sh::InterfaceBlock> *blocks)
886{
Jiawei Shao016105b2018-04-12 16:38:31 +0800887 mShaderBlocks[shaderType] = blocks;
Jamie Madill977abce2017-11-07 08:03:19 -0500888}
889
890void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
891 const GetBlockMemberInfo &getMemberInfo) const
892{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500893 ASSERT(mBlocksOut->empty());
894
Jamie Madill977abce2017-11-07 08:03:19 -0500895 std::set<std::string> visitedList;
896
Jiawei Shao016105b2018-04-12 16:38:31 +0800897 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill977abce2017-11-07 08:03:19 -0500898 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800899 if (!mShaderBlocks[shaderType])
900 {
901 continue;
902 }
Jamie Madill977abce2017-11-07 08:03:19 -0500903
Jiawei Shao016105b2018-04-12 16:38:31 +0800904 for (const auto &block : *mShaderBlocks[shaderType])
Jamie Madill977abce2017-11-07 08:03:19 -0500905 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800906 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500907 continue;
908
909 if (visitedList.count(block.name) > 0)
910 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200911 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500912 {
913 for (InterfaceBlock &priorBlock : *mBlocksOut)
914 {
915 if (block.name == priorBlock.name)
916 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200917 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800918 // Update the block members static use.
919 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
920 block.fieldMappedPrefix(), -1,
921 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
922 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500923 }
924 }
925 }
926 }
927 else
928 {
929 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
930 visitedList.insert(block.name);
931 }
932 }
933 }
934}
935
936template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300937void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
938 const VarT &field,
939 unsigned int arrayNestingIndex,
940 const std::string &prefix,
941 const std::string &mappedPrefix,
942 int blockIndex,
943 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800944 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800945 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300946{
947 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
948 // innermost.
949 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
950 if (singleEntryForTopLevelArray)
951 {
952 entryGenerationArraySize = 1;
953 }
954 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
955 {
956 const std::string elementName = prefix + ArrayString(arrayElement);
957 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
958 if (arrayNestingIndex + 1u < field.arraySizes.size())
959 {
960 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
961 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800962 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300963 }
964 else
965 {
966 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800967 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300968 }
969 }
970}
971
972template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500973void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
974 const std::vector<VarT> &fields,
975 const std::string &prefix,
976 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800977 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300978 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800979 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800980 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500981{
982 for (const VarT &field : fields)
983 {
984 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500985 std::string fullMappedName =
986 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
987
Olli Etuaho465835d2017-09-26 13:34:10 +0300988 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800989 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300990 }
991}
992
993template <typename VarT>
994void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
995 const VarT &field,
996 const std::string &fullName,
997 const std::string &fullMappedName,
998 int blockIndex,
999 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001000 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001001 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +03001002{
1003 int nextArraySize = topLevelArraySize;
1004 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
1005 singleEntryForTopLevelArray)
1006 {
1007 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
1008 // member declared as an array of an aggregate type, an entry will be generated only
1009 // for the first array element, regardless of its type.'
1010 nextArraySize = field.getOutermostArraySize();
1011 }
1012
1013 if (field.isStruct())
1014 {
1015 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001016 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001017 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001018 blockIndex, singleEntryForTopLevelArray, nextArraySize,
1019 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001020 }
1021 else
1022 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001023 ASSERT(nextArraySize == topLevelArraySize);
1024 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001025 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001026 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001027 return;
Jamie Madill977abce2017-11-07 08:03:19 -05001028 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001029 if (field.isArrayOfArrays())
1030 {
1031 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
1032 if (singleEntryForTopLevelArray)
1033 {
1034 entryGenerationArraySize = 1u;
1035 }
1036 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
1037 ++arrayElement)
1038 {
1039 VarT fieldElement = field;
1040 fieldElement.indexIntoArray(arrayElement);
1041 const std::string elementName = fullName + ArrayString(arrayElement);
1042 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
1043
1044 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001045 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +03001046 }
1047 return;
1048 }
1049
Olli Etuaho465835d2017-09-26 13:34:10 +03001050 std::string fullNameWithArrayIndex = fullName;
1051 std::string fullMappedNameWithArrayIndex = fullMappedName;
1052
1053 if (field.isArray())
1054 {
1055 fullNameWithArrayIndex += "[0]";
1056 fullMappedNameWithArrayIndex += "[0]";
1057 }
1058
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001059 if (blockIndex == -1)
1060 {
Olli Etuaho107c7242018-03-20 15:45:35 +02001061 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001062 }
1063 else
1064 {
1065 // If getBlockMemberInfo returns false, the variable is optimized out.
1066 sh::BlockMemberInfo memberInfo;
1067 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
1068 {
1069 return;
1070 }
1071
1072 ASSERT(nextArraySize == topLevelArraySize);
1073 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1074 blockIndex, memberInfo, nextArraySize, shaderType);
1075 }
Jamie Madill977abce2017-11-07 08:03:19 -05001076}
1077
1078void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1079 const GetBlockMemberInfo &getMemberInfo,
1080 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001081 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001082{
1083 size_t blockSize = 0;
1084 std::vector<unsigned int> blockIndexes;
1085
1086 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001087 // Track the first and last block member index to determine the range of active block members in
1088 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001089 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1090 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001091 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001092 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001093 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1094
1095 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1096 ++blockMemberIndex)
1097 {
1098 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1099 }
1100
Jamie Madill977abce2017-11-07 08:03:19 -05001101 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1102 ++arrayElement)
1103 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001104 std::string blockArrayName = interfaceBlock.name;
1105 std::string blockMappedArrayName = interfaceBlock.mappedName;
1106 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001107 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001108 blockArrayName += ArrayString(arrayElement);
1109 blockMappedArrayName += ArrayString(arrayElement);
1110 }
Jamie Madill977abce2017-11-07 08:03:19 -05001111
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001112 // Don't define this block at all if it's not active in the implementation.
1113 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1114 {
1115 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001116 }
1117
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001118 // ESSL 3.10 section 4.4.4 page 58:
1119 // Any uniform or shader storage block declared without a binding qualifier is initially
1120 // assigned to block binding point zero.
1121 int blockBinding =
1122 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001123 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001124 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001125 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001126 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001127
1128 // Since all block elements in an array share the same active interface blocks, they
1129 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1130 // was active, here we will add every block element in the array.
1131 block.dataSize = static_cast<unsigned int>(blockSize);
1132 mBlocksOut->push_back(block);
1133 }
1134}
1135
1136// UniformBlockLinker implementation.
1137UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1138 std::vector<LinkedUniform> *uniformsOut)
1139 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1140{
1141}
1142
1143UniformBlockLinker::~UniformBlockLinker()
1144{
1145}
1146
Olli Etuaho465835d2017-09-26 13:34:10 +03001147void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1148 const std::string &fullName,
1149 const std::string &fullMappedName,
1150 int blockIndex,
1151 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001152 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001153 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001154{
Olli Etuaho465835d2017-09-26 13:34:10 +03001155 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001156 blockIndex, memberInfo);
1157 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001158 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001159
1160 // Since block uniforms have no location, we don't need to store them in the uniform locations
1161 // list.
1162 mUniformsOut->push_back(newUniform);
1163}
1164
1165size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1166{
1167 return mUniformsOut->size();
1168}
1169
Olli Etuaho107c7242018-03-20 15:45:35 +02001170void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001171 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001172 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001173{
Olli Etuaho107c7242018-03-20 15:45:35 +02001174 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001175}
1176
Jamie Madill977abce2017-11-07 08:03:19 -05001177// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001178ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1179 std::vector<BufferVariable> *bufferVariablesOut)
1180 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001181{
1182}
1183
1184ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1185{
1186}
1187
Olli Etuaho465835d2017-09-26 13:34:10 +03001188void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1189 const std::string &fullName,
1190 const std::string &fullMappedName,
1191 int blockIndex,
1192 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001193 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001194 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001195{
Olli Etuaho465835d2017-09-26 13:34:10 +03001196 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001197 blockIndex, memberInfo);
1198 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001199 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001200
1201 newBufferVariable.topLevelArraySize = topLevelArraySize;
1202
1203 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001204}
1205
1206size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1207{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001208 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001209}
1210
Olli Etuaho107c7242018-03-20 15:45:35 +02001211void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001212 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001213 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001214{
Olli Etuaho107c7242018-03-20 15:45:35 +02001215 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001216}
1217
Jiajia Qin94f1e892017-11-20 12:14:32 +08001218// AtomicCounterBufferLinker implementation.
1219AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1220 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1221 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1222{
1223}
1224
1225AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1226{
1227}
1228
1229void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1230{
1231 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1232 {
1233 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1234 ASSERT(bufferSize != sizeMap.end());
1235 atomicCounterBuffer.dataSize = bufferSize->second;
1236 }
1237}
1238
Olli Etuahob78707c2017-03-09 15:03:11 +00001239} // namespace gl