blob: 8b3e4d31f033a046ec5d093b5f0b371b5c600143 [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
jchen103fd614d2018-08-13 12:21:58 +0800104bool ValidateGraphicsUniformsPerShader(Shader *shaderToLink,
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800105 bool extendLinkedUniforms,
106 std::map<std::string, ShaderUniform> *linkedUniforms,
107 InfoLog &infoLog)
108{
jchen103fd614d2018-08-13 12:21:58 +0800109 ASSERT(shaderToLink && linkedUniforms);
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800110
jchen103fd614d2018-08-13 12:21:58 +0800111 for (const sh::Uniform &uniform : shaderToLink->getUniforms())
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800112 {
113 const auto &entry = linkedUniforms->find(uniform.name);
114 if (entry != linkedUniforms->end())
115 {
116 const sh::Uniform &linkedUniform = *(entry->second.second);
117 std::string mismatchedStructFieldName;
118 LinkMismatchError linkError =
119 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
120 if (linkError != LinkMismatchError::NO_MISMATCH)
121 {
122 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
123 mismatchedStructFieldName, entry->second.first,
124 shaderToLink->getType());
125 return false;
126 }
127 }
128 else if (extendLinkedUniforms)
129 {
130 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
131 }
132 }
133
134 return true;
135}
136
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800137GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
138{
139 switch (shaderType)
140 {
141 case ShaderType::Vertex:
142 return caps.maxVertexUniformVectors;
143 case ShaderType::Fragment:
144 return caps.maxFragmentUniformVectors;
145
146 case ShaderType::Compute:
147 case ShaderType::Geometry:
148 return caps.maxShaderUniformComponents[shaderType] / 4;
149
150 default:
151 UNREACHABLE();
152 return 0u;
153 }
154}
155
156enum class UniformType : uint8_t
157{
158 Variable = 0,
159 Sampler = 1,
160 Image = 2,
161 AtomicCounter = 3,
162
163 InvalidEnum = 4,
164 EnumCount = 4,
165};
166
167const char *GetUniformResourceNameString(UniformType uniformType)
168{
169 switch (uniformType)
170 {
171 case UniformType::Variable:
172 return "uniform";
173 case UniformType::Sampler:
174 return "texture image unit";
175 case UniformType::Image:
176 return "image uniform";
177 case UniformType::AtomicCounter:
178 return "atomic counter";
179 default:
180 UNREACHABLE();
181 return "";
182 }
183}
184
185std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
186{
187 // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
188 if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
189 {
190 return "MAX_TEXTURE_IMAGE_UNITS";
191 }
192
193 std::ostringstream ostream;
194 ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
195
196 switch (uniformType)
197 {
198 case UniformType::Variable:
199 // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
200 // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
201 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
202 {
203 ostream << "UNIFORM_VECTORS";
204 break;
205 }
206 // For compute and geometry shaders, there are no definitions on
207 // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
208 // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
209 else
210 {
211 ostream << "UNIFORM_COMPONENTS";
212 }
213 break;
214 case UniformType::Sampler:
215 ostream << "TEXTURE_IMAGE_UNITS";
216 break;
217 case UniformType::Image:
218 ostream << "IMAGE_UNIFORMS";
219 break;
220 case UniformType::AtomicCounter:
221 ostream << "ATOMIC_COUNTERS";
222 break;
223 default:
224 UNREACHABLE();
225 return "";
226 }
227
228 if (shaderType == ShaderType::Geometry)
229 {
230 ostream << "_EXT";
231 }
232
233 return ostream.str();
234}
235
236void LogUniformsExceedLimit(ShaderType shaderType,
237 UniformType uniformType,
238 GLuint limit,
239 InfoLog &infoLog)
240{
241 infoLog << GetShaderTypeString(shaderType) << " shader "
242 << GetUniformResourceNameString(uniformType) << "s count exceeds "
243 << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
244}
245
Olli Etuahod2551232017-10-26 20:03:33 +0300246} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +0000247
248UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
249{
250}
251
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500252UniformLinker::~UniformLinker() = default;
253
Olli Etuahob78707c2017-03-09 15:03:11 +0000254void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400255 std::vector<UnusedUniform> *unusedUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000256 std::vector<VariableLocation> *uniformLocations)
257{
258 uniforms->swap(mUniforms);
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400259 unusedUniforms->swap(mUnusedUniforms);
Olli Etuahob78707c2017-03-09 15:03:11 +0000260 uniformLocations->swap(mUniformLocations);
261}
262
jchen103fd614d2018-08-13 12:21:58 +0800263bool UniformLinker::link(const Caps &caps,
Jamie Madillbd044ed2017-06-05 12:59:21 -0400264 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500265 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000266{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800267 if (mState.getAttachedShader(ShaderType::Vertex) &&
268 mState.getAttachedShader(ShaderType::Fragment))
Olli Etuahob78707c2017-03-09 15:03:11 +0000269 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800270 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
jchen103fd614d2018-08-13 12:21:58 +0800271 if (!validateGraphicsUniforms(infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000272 {
273 return false;
274 }
275 }
276
277 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
278 // Also check the maximum uniform vector and sampler counts.
jchen103fd614d2018-08-13 12:21:58 +0800279 if (!flattenUniformsAndCheckCaps(caps, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000280 {
281 return false;
282 }
283
jchen103fd614d2018-08-13 12:21:58 +0800284 if (!checkMaxCombinedAtomicCounters(caps, infoLog))
jchen10eaef1e52017-06-13 10:44:11 +0800285 {
286 return false;
287 }
288
Olli Etuahob78707c2017-03-09 15:03:11 +0000289 if (!indexUniforms(infoLog, uniformLocationBindings))
290 {
291 return false;
292 }
293
294 return true;
295}
296
jchen103fd614d2018-08-13 12:21:58 +0800297bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000298{
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800299 // Check that uniforms defined in the graphics shaders are identical
300 std::map<std::string, ShaderUniform> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000301
Jiawei Shao016105b2018-04-12 16:38:31 +0800302 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Olli Etuahob78707c2017-03-09 15:03:11 +0000303 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800304 Shader *currentShader = mState.getAttachedShader(shaderType);
305 if (currentShader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000306 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800307 if (shaderType == ShaderType::Vertex)
308 {
jchen103fd614d2018-08-13 12:21:58 +0800309 for (const sh::Uniform &vertexUniform : currentShader->getUniforms())
Jiawei Shao016105b2018-04-12 16:38:31 +0800310 {
311 linkedUniforms[vertexUniform.name] =
312 std::make_pair(ShaderType::Vertex, &vertexUniform);
313 }
314 }
315 else
316 {
317 bool isLastShader = (shaderType == ShaderType::Fragment);
jchen103fd614d2018-08-13 12:21:58 +0800318 if (!ValidateGraphicsUniformsPerShader(currentShader, !isLastShader,
Jiawei Shao016105b2018-04-12 16:38:31 +0800319 &linkedUniforms, infoLog))
320 {
321 return false;
322 }
323 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000324 }
325 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800326
Olli Etuahob78707c2017-03-09 15:03:11 +0000327 return true;
328}
329
Jamie Madill3c1da042017-11-27 18:33:40 -0500330bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000331{
Olli Etuahob78707c2017-03-09 15:03:11 +0000332 // Locations which have been allocated for an unused uniform.
333 std::set<GLuint> ignoredLocations;
334
335 int maxUniformLocation = -1;
336
337 // Gather uniform locations that have been set either using the bindUniformLocation API or by
338 // using a location layout qualifier and check conflicts between them.
339 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
Olli Etuaho44861c42018-03-23 14:36:39 +0200340 &ignoredLocations, &maxUniformLocation))
Olli Etuahob78707c2017-03-09 15:03:11 +0000341 {
342 return false;
343 }
344
345 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
346 // the line relies on only having statically used uniforms in mUniforms.
347 pruneUnusedUniforms();
348
349 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
350 std::vector<VariableLocation> unlocatedUniforms;
351 std::map<GLuint, VariableLocation> preLocatedUniforms;
352
353 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
354 {
355 const LinkedUniform &uniform = mUniforms[uniformIndex];
356
jchen10baf5d942017-08-28 20:45:48 +0800357 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000358 {
359 continue;
360 }
361
Olli Etuahod2551232017-10-26 20:03:33 +0300362 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000363 int shaderLocation = uniform.location;
364
365 if (shaderLocation != -1)
366 {
367 preSetLocation = shaderLocation;
368 }
369
Olli Etuaho465835d2017-09-26 13:34:10 +0300370 unsigned int elementCount = uniform.getBasicTypeElementCount();
371 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000372 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400373 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000374
375 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
376 {
377 int elementLocation = preSetLocation + arrayIndex;
378 preLocatedUniforms[elementLocation] = location;
379 }
380 else
381 {
382 unlocatedUniforms.push_back(location);
383 }
384 }
385 }
386
387 // Make enough space for all uniforms, with pre-set locations or not.
388 mUniformLocations.resize(
389 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
390 static_cast<size_t>(maxUniformLocation + 1)));
391
392 // Assign uniforms with pre-set locations
393 for (const auto &uniform : preLocatedUniforms)
394 {
395 mUniformLocations[uniform.first] = uniform.second;
396 }
397
398 // Assign ignored uniforms
399 for (const auto &ignoredLocation : ignoredLocations)
400 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400401 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000402 }
403
404 // Automatically assign locations for the rest of the uniforms
405 size_t nextUniformLocation = 0;
406 for (const auto &unlocatedUniform : unlocatedUniforms)
407 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400408 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000409 mUniformLocations[nextUniformLocation].ignored)
410 {
411 nextUniformLocation++;
412 }
413
414 ASSERT(nextUniformLocation < mUniformLocations.size());
415 mUniformLocations[nextUniformLocation] = unlocatedUniform;
416 nextUniformLocation++;
417 }
418
419 return true;
420}
421
422bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
423 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500424 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000425 std::set<GLuint> *ignoredLocations,
426 int *maxUniformLocation)
427{
Olli Etuaho44861c42018-03-23 14:36:39 +0200428 // All the locations where another uniform can't be located.
429 std::set<GLuint> reservedLocations;
430
Olli Etuahob78707c2017-03-09 15:03:11 +0000431 for (const LinkedUniform &uniform : mUniforms)
432 {
433 if (uniform.isBuiltIn())
434 {
435 continue;
436 }
437
Olli Etuahod2551232017-10-26 20:03:33 +0300438 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000439 int shaderLocation = uniform.location;
440
441 if (shaderLocation != -1)
442 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300443 unsigned int elementCount = uniform.getBasicTypeElementCount();
444
445 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000446 {
447 // GLSL ES 3.10 section 4.4.3
448 int elementLocation = shaderLocation + arrayIndex;
449 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200450 if (reservedLocations.find(elementLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000451 {
452 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
453 return false;
454 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200455 reservedLocations.insert(elementLocation);
Olli Etuaho107c7242018-03-20 15:45:35 +0200456 if (!uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000457 {
458 ignoredLocations->insert(elementLocation);
459 }
460 }
461 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200462 else if (apiBoundLocation != -1 && uniform.staticUse)
Olli Etuahob78707c2017-03-09 15:03:11 +0000463 {
464 // Only the first location is reserved even if the uniform is an array.
465 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200466 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000467 {
468 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
469 return false;
470 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200471 reservedLocations.insert(apiBoundLocation);
472 if (!uniform.active)
473 {
474 ignoredLocations->insert(apiBoundLocation);
475 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000476 }
477 }
478
479 // Record the uniform locations that were bound using the API for uniforms that were not found
480 // from the shader. Other uniforms should not be assigned to those locations.
481 for (const auto &locationBinding : uniformLocationBindings)
482 {
483 GLuint location = locationBinding.second;
Olli Etuaho44861c42018-03-23 14:36:39 +0200484 if (reservedLocations.find(location) == reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000485 {
486 ignoredLocations->insert(location);
487 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
488 }
489 }
490
491 return true;
492}
493
494void UniformLinker::pruneUnusedUniforms()
495{
496 auto uniformIter = mUniforms.begin();
497 while (uniformIter != mUniforms.end())
498 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200499 if (uniformIter->active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000500 {
501 ++uniformIter;
502 }
503 else
504 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400505 mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler());
Olli Etuahob78707c2017-03-09 15:03:11 +0000506 uniformIter = mUniforms.erase(uniformIter);
507 }
508 }
509}
510
511bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400512 Shader *shader,
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800513 const Caps &caps,
Olli Etuahob78707c2017-03-09 15:03:11 +0000514 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800515 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800516 std::vector<LinkedUniform> &atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400517 std::vector<UnusedUniform> &unusedUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000518 InfoLog &infoLog)
519{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800520 ShaderUniformCount shaderUniformCount;
jchen103fd614d2018-08-13 12:21:58 +0800521 for (const sh::Uniform &uniform : shader->getUniforms())
Olli Etuahob78707c2017-03-09 15:03:11 +0000522 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400523 shaderUniformCount +=
524 flattenUniform(uniform, &samplerUniforms, &imageUniforms, &atomicCounterUniforms,
525 &unusedUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000526 }
527
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800528 ShaderType shaderType = shader->getType();
529
530 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
531 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
532 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
Olli Etuahob78707c2017-03-09 15:03:11 +0000533 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800534 GLuint maxUniforms = 0u;
535
536 // See comments in GetUniformResourceLimitName()
537 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
538 {
539 maxUniforms = maxUniformVectorsCount;
540 }
541 else
542 {
543 maxUniforms = maxUniformVectorsCount * 4;
544 }
545
546 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000547 return false;
548 }
549
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800550 if (shaderUniformCount.samplerCount > caps.maxShaderTextureImageUnits[shaderType])
Olli Etuahob78707c2017-03-09 15:03:11 +0000551 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800552 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
553 caps.maxShaderTextureImageUnits[shaderType], infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000554 return false;
555 }
556
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800557 if (shaderUniformCount.imageCount > caps.maxShaderImageUniforms[shaderType])
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800558 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800559 LogUniformsExceedLimit(shaderType, UniformType::Image,
560 caps.maxShaderImageUniforms[shaderType], infoLog);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800561 return false;
562 }
563
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800564 if (shaderUniformCount.atomicCounterCount > caps.maxShaderAtomicCounters[shaderType])
jchen10eaef1e52017-06-13 10:44:11 +0800565 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800566 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
567 caps.maxShaderAtomicCounters[shaderType], infoLog);
jchen10eaef1e52017-06-13 10:44:11 +0800568 return false;
569 }
570
Olli Etuahob78707c2017-03-09 15:03:11 +0000571 return true;
572}
573
jchen103fd614d2018-08-13 12:21:58 +0800574bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000575{
576 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800577 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800578 std::vector<LinkedUniform> atomicCounterUniforms;
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400579 std::vector<UnusedUniform> unusedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000580
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800581 for (ShaderType shaderType : AllShaderTypes())
Olli Etuahob78707c2017-03-09 15:03:11 +0000582 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800583 Shader *shader = mState.getAttachedShader(shaderType);
584 if (!shader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000585 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800586 continue;
Olli Etuahob78707c2017-03-09 15:03:11 +0000587 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400588
jchen103fd614d2018-08-13 12:21:58 +0800589 if (!flattenUniformsAndCheckCapsForShader(shader, caps, samplerUniforms, imageUniforms,
590 atomicCounterUniforms, unusedUniforms, infoLog))
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800591 {
592 return false;
593 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000594 }
595
596 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800597 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800598 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400599 mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000600 return true;
601}
602
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800603UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000604 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800605 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800606 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800607 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400608 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800609 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000610{
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400611 int location = uniform.location;
612 ShaderUniformCount shaderUniformCount = flattenUniformImpl(
613 uniform, uniform.name, uniform.mappedName, samplerUniforms, imageUniforms,
614 atomicCounterUniforms, unusedUniforms, shaderType, uniform.active, uniform.staticUse,
615 uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200616 if (uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000617 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800618 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000619 }
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400620 else
621 {
622 unusedUniforms->emplace_back(uniform.name, IsSamplerType(uniform.type));
623 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800624 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000625}
626
Olli Etuaho465835d2017-09-26 13:34:10 +0300627UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
628 const sh::ShaderVariable &uniform,
629 unsigned int arrayNestingIndex,
630 const std::string &namePrefix,
631 const std::string &mappedNamePrefix,
632 std::vector<LinkedUniform> *samplerUniforms,
633 std::vector<LinkedUniform> *imageUniforms,
634 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400635 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800636 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200637 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200638 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300639 int binding,
640 int offset,
641 int *location)
642{
643 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
644 // innermost.
645 ShaderUniformCount shaderUniformCount;
646 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
647 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
648 {
649 const std::string elementName = namePrefix + ArrayString(arrayElement);
650 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
651 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
652 {
653 shaderUniformCount += flattenArrayOfStructsUniform(
654 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400655 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType, markActive,
656 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300657 }
658 else
659 {
660 shaderUniformCount += flattenStructUniform(
661 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400662 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
663 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300664 }
665 }
666 return shaderUniformCount;
667}
668
669UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
670 const std::vector<sh::ShaderVariable> &fields,
671 const std::string &namePrefix,
672 const std::string &mappedNamePrefix,
673 std::vector<LinkedUniform> *samplerUniforms,
674 std::vector<LinkedUniform> *imageUniforms,
675 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400676 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800677 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200678 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200679 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300680 int binding,
681 int offset,
682 int *location)
683{
684 ShaderUniformCount shaderUniformCount;
685 for (const sh::ShaderVariable &field : fields)
686 {
687 const std::string &fieldName = namePrefix + "." + field.name;
688 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
689
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400690 shaderUniformCount +=
691 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
692 atomicCounterUniforms, unusedUniforms, shaderType, markActive,
693 markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300694 }
695 return shaderUniformCount;
696}
697
698UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
699 const sh::ShaderVariable &uniform,
700 const std::string &namePrefix,
701 const std::string &mappedNamePrefix,
702 std::vector<LinkedUniform> *samplerUniforms,
703 std::vector<LinkedUniform> *imageUniforms,
704 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400705 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800706 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200707 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200708 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300709 int binding,
710 int offset,
711 int *location)
712{
713 ShaderUniformCount shaderUniformCount;
714
715 ASSERT(uniform.isArray());
716 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
717 ++arrayElement)
718 {
719 sh::ShaderVariable uniformElement = uniform;
720 uniformElement.indexIntoArray(arrayElement);
721 const std::string elementName = namePrefix + ArrayString(arrayElement);
722 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
723
Olli Etuaho44861c42018-03-23 14:36:39 +0200724 shaderUniformCount +=
725 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400726 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
727 markActive, markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300728 }
729 return shaderUniformCount;
730}
731
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800732UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000733 const sh::ShaderVariable &uniform,
734 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300735 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000736 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800737 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800738 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400739 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800740 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200741 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200742 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000743 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800744 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000745 int *location)
746{
747 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800748 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000749
750 if (uniform.isStruct())
751 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300752 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000753 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400754 shaderUniformCount += flattenArrayOfStructsUniform(
755 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
756 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
757 binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000758 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300759 else
760 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400761 shaderUniformCount += flattenStructUniform(
762 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
763 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
764 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300765 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800766 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000767 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300768 if (uniform.isArrayOfArrays())
769 {
770 // GLES 3.1 November 2016 section 7.3.1 page 77:
771 // "For an active variable declared as an array of an aggregate data type (structures or
772 // arrays), a separate entry will be generated for each active array element"
773 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400774 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
775 markActive, markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300776 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000777
778 // Not a struct
779 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800780 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800781 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000782 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
783 if (isSampler)
784 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000785 uniformList = samplerUniforms;
786 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800787 else if (isImage)
788 {
789 uniformList = imageUniforms;
790 }
jchen10eaef1e52017-06-13 10:44:11 +0800791 else if (isAtomicCounter)
792 {
793 uniformList = atomicCounterUniforms;
794 }
Olli Etuahod2551232017-10-26 20:03:33 +0300795
796 std::string fullNameWithArrayIndex(fullName);
797 std::string fullMappedNameWithArrayIndex(fullMappedName);
798
799 if (uniform.isArray())
800 {
801 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
802 // and including [0] at the end of array variable names.
803 fullNameWithArrayIndex += "[0]";
804 fullMappedNameWithArrayIndex += "[0]";
805 }
806
807 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000808 if (existingUniform)
809 {
810 if (binding != -1)
811 {
812 existingUniform->binding = binding;
813 }
jchen10eaef1e52017-06-13 10:44:11 +0800814 if (offset != -1)
815 {
816 existingUniform->offset = offset;
817 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000818 if (*location != -1)
819 {
820 existingUniform->location = *location;
821 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200822 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000823 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200824 existingUniform->active = true;
825 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000826 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200827 if (markStaticUse)
828 {
829 existingUniform->staticUse = true;
830 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000831 }
832 else
833 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300834 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300835 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300836 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000837 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300838 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200839 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200840 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300841 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200842 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800843 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200844 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800845 }
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400846 else
847 {
848 unusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler());
849 }
jchen10eaef1e52017-06-13 10:44:11 +0800850
Olli Etuahob78707c2017-03-09 15:03:11 +0000851 uniformList->push_back(linkedUniform);
852 }
853
Olli Etuaho465835d2017-09-26 13:34:10 +0300854 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
855 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000856
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800857 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800858 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800859 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800860 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500861 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500862 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800863 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000864
865 if (*location != -1)
866 {
867 *location += elementCount;
868 }
869
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800870 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000871}
872
jchen10eaef1e52017-06-13 10:44:11 +0800873bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
874{
875 unsigned int atomicCounterCount = 0;
876 for (const auto &uniform : mUniforms)
877 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200878 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800879 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300880 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800881 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
882 {
883 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
884 << caps.maxCombinedAtomicCounters << ").";
885 return false;
886 }
887 }
888 }
889 return true;
890}
891
Jamie Madill977abce2017-11-07 08:03:19 -0500892// InterfaceBlockLinker implementation.
893InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
Jiawei Shao016105b2018-04-12 16:38:31 +0800894 : mShaderBlocks({}), mBlocksOut(blocksOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500895{
896}
897
898InterfaceBlockLinker::~InterfaceBlockLinker()
899{
900}
901
Jiawei Shao016105b2018-04-12 16:38:31 +0800902void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
Jamie Madill977abce2017-11-07 08:03:19 -0500903 const std::vector<sh::InterfaceBlock> *blocks)
904{
Jiawei Shao016105b2018-04-12 16:38:31 +0800905 mShaderBlocks[shaderType] = blocks;
Jamie Madill977abce2017-11-07 08:03:19 -0500906}
907
908void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
909 const GetBlockMemberInfo &getMemberInfo) const
910{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500911 ASSERT(mBlocksOut->empty());
912
Jamie Madill977abce2017-11-07 08:03:19 -0500913 std::set<std::string> visitedList;
914
Jiawei Shao016105b2018-04-12 16:38:31 +0800915 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill977abce2017-11-07 08:03:19 -0500916 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800917 if (!mShaderBlocks[shaderType])
918 {
919 continue;
920 }
Jamie Madill977abce2017-11-07 08:03:19 -0500921
Jiawei Shao016105b2018-04-12 16:38:31 +0800922 for (const auto &block : *mShaderBlocks[shaderType])
Jamie Madill977abce2017-11-07 08:03:19 -0500923 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800924 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500925 continue;
926
927 if (visitedList.count(block.name) > 0)
928 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200929 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500930 {
931 for (InterfaceBlock &priorBlock : *mBlocksOut)
932 {
933 if (block.name == priorBlock.name)
934 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200935 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800936 // Update the block members static use.
937 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
938 block.fieldMappedPrefix(), -1,
939 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
940 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500941 }
942 }
943 }
944 }
945 else
946 {
947 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
948 visitedList.insert(block.name);
949 }
950 }
951 }
952}
953
954template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300955void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
956 const VarT &field,
957 unsigned int arrayNestingIndex,
958 const std::string &prefix,
959 const std::string &mappedPrefix,
960 int blockIndex,
961 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800962 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800963 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300964{
965 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
966 // innermost.
967 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
968 if (singleEntryForTopLevelArray)
969 {
970 entryGenerationArraySize = 1;
971 }
972 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
973 {
974 const std::string elementName = prefix + ArrayString(arrayElement);
975 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
976 if (arrayNestingIndex + 1u < field.arraySizes.size())
977 {
978 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
979 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800980 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300981 }
982 else
983 {
984 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800985 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300986 }
987 }
988}
989
990template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500991void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
992 const std::vector<VarT> &fields,
993 const std::string &prefix,
994 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800995 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300996 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800997 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800998 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500999{
1000 for (const VarT &field : fields)
1001 {
1002 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -05001003 std::string fullMappedName =
1004 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
1005
Olli Etuaho465835d2017-09-26 13:34:10 +03001006 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001007 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +03001008 }
1009}
1010
1011template <typename VarT>
1012void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
1013 const VarT &field,
1014 const std::string &fullName,
1015 const std::string &fullMappedName,
1016 int blockIndex,
1017 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001018 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001019 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +03001020{
1021 int nextArraySize = topLevelArraySize;
1022 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
1023 singleEntryForTopLevelArray)
1024 {
1025 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
1026 // member declared as an array of an aggregate type, an entry will be generated only
1027 // for the first array element, regardless of its type.'
1028 nextArraySize = field.getOutermostArraySize();
1029 }
1030
1031 if (field.isStruct())
1032 {
1033 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001034 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001035 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001036 blockIndex, singleEntryForTopLevelArray, nextArraySize,
1037 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001038 }
1039 else
1040 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001041 ASSERT(nextArraySize == topLevelArraySize);
1042 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001043 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001044 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001045 return;
Jamie Madill977abce2017-11-07 08:03:19 -05001046 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001047 if (field.isArrayOfArrays())
1048 {
1049 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
1050 if (singleEntryForTopLevelArray)
1051 {
1052 entryGenerationArraySize = 1u;
1053 }
1054 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
1055 ++arrayElement)
1056 {
1057 VarT fieldElement = field;
1058 fieldElement.indexIntoArray(arrayElement);
1059 const std::string elementName = fullName + ArrayString(arrayElement);
1060 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
1061
1062 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001063 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +03001064 }
1065 return;
1066 }
1067
Olli Etuaho465835d2017-09-26 13:34:10 +03001068 std::string fullNameWithArrayIndex = fullName;
1069 std::string fullMappedNameWithArrayIndex = fullMappedName;
1070
1071 if (field.isArray())
1072 {
1073 fullNameWithArrayIndex += "[0]";
1074 fullMappedNameWithArrayIndex += "[0]";
1075 }
1076
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001077 if (blockIndex == -1)
1078 {
Olli Etuaho107c7242018-03-20 15:45:35 +02001079 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001080 }
1081 else
1082 {
1083 // If getBlockMemberInfo returns false, the variable is optimized out.
1084 sh::BlockMemberInfo memberInfo;
1085 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
1086 {
1087 return;
1088 }
1089
1090 ASSERT(nextArraySize == topLevelArraySize);
1091 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1092 blockIndex, memberInfo, nextArraySize, shaderType);
1093 }
Jamie Madill977abce2017-11-07 08:03:19 -05001094}
1095
1096void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1097 const GetBlockMemberInfo &getMemberInfo,
1098 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001099 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001100{
1101 size_t blockSize = 0;
1102 std::vector<unsigned int> blockIndexes;
1103
1104 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001105 // Track the first and last block member index to determine the range of active block members in
1106 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001107 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1108 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001109 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001110 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001111 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1112
1113 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1114 ++blockMemberIndex)
1115 {
1116 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1117 }
1118
Jamie Madill977abce2017-11-07 08:03:19 -05001119 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1120 ++arrayElement)
1121 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001122 std::string blockArrayName = interfaceBlock.name;
1123 std::string blockMappedArrayName = interfaceBlock.mappedName;
1124 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001125 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001126 blockArrayName += ArrayString(arrayElement);
1127 blockMappedArrayName += ArrayString(arrayElement);
1128 }
Jamie Madill977abce2017-11-07 08:03:19 -05001129
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001130 // Don't define this block at all if it's not active in the implementation.
1131 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1132 {
1133 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001134 }
1135
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001136 // ESSL 3.10 section 4.4.4 page 58:
1137 // Any uniform or shader storage block declared without a binding qualifier is initially
1138 // assigned to block binding point zero.
1139 int blockBinding =
1140 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001141 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001142 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001143 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001144 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001145
1146 // Since all block elements in an array share the same active interface blocks, they
1147 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1148 // was active, here we will add every block element in the array.
1149 block.dataSize = static_cast<unsigned int>(blockSize);
1150 mBlocksOut->push_back(block);
1151 }
1152}
1153
1154// UniformBlockLinker implementation.
1155UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1156 std::vector<LinkedUniform> *uniformsOut)
1157 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1158{
1159}
1160
1161UniformBlockLinker::~UniformBlockLinker()
1162{
1163}
1164
Olli Etuaho465835d2017-09-26 13:34:10 +03001165void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1166 const std::string &fullName,
1167 const std::string &fullMappedName,
1168 int blockIndex,
1169 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001170 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001171 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001172{
Olli Etuaho465835d2017-09-26 13:34:10 +03001173 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001174 blockIndex, memberInfo);
1175 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001176 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001177
1178 // Since block uniforms have no location, we don't need to store them in the uniform locations
1179 // list.
1180 mUniformsOut->push_back(newUniform);
1181}
1182
1183size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1184{
1185 return mUniformsOut->size();
1186}
1187
Olli Etuaho107c7242018-03-20 15:45:35 +02001188void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001189 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001190 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001191{
Olli Etuaho107c7242018-03-20 15:45:35 +02001192 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001193}
1194
Jamie Madill977abce2017-11-07 08:03:19 -05001195// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001196ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1197 std::vector<BufferVariable> *bufferVariablesOut)
1198 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001199{
1200}
1201
1202ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1203{
1204}
1205
Olli Etuaho465835d2017-09-26 13:34:10 +03001206void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1207 const std::string &fullName,
1208 const std::string &fullMappedName,
1209 int blockIndex,
1210 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001211 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001212 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001213{
Olli Etuaho465835d2017-09-26 13:34:10 +03001214 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001215 blockIndex, memberInfo);
1216 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001217 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001218
1219 newBufferVariable.topLevelArraySize = topLevelArraySize;
1220
1221 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001222}
1223
1224size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1225{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001226 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001227}
1228
Olli Etuaho107c7242018-03-20 15:45:35 +02001229void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001230 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001231 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001232{
Olli Etuaho107c7242018-03-20 15:45:35 +02001233 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001234}
1235
Jiajia Qin94f1e892017-11-20 12:14:32 +08001236// AtomicCounterBufferLinker implementation.
1237AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1238 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1239 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1240{
1241}
1242
1243AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1244{
1245}
1246
1247void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1248{
1249 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1250 {
1251 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1252 ASSERT(bufferSize != sizeMap.end());
1253 atomicCounterBuffer.dataSize = bufferSize->second;
1254 }
1255}
1256
Olli Etuahob78707c2017-03-09 15:03:11 +00001257} // namespace gl