blob: 605d1bdaa88bd486d3180ac46a99d463e4d1b596 [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,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400256 std::vector<UnusedUniform> *unusedUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000257 std::vector<VariableLocation> *uniformLocations)
258{
259 uniforms->swap(mUniforms);
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400260 unusedUniforms->swap(mUnusedUniforms);
Olli Etuahob78707c2017-03-09 15:03:11 +0000261 uniformLocations->swap(mUniformLocations);
262}
263
Jamie Madillbd044ed2017-06-05 12:59:21 -0400264bool UniformLinker::link(const Context *context,
265 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500266 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000267{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800268 if (mState.getAttachedShader(ShaderType::Vertex) &&
269 mState.getAttachedShader(ShaderType::Fragment))
Olli Etuahob78707c2017-03-09 15:03:11 +0000270 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800271 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +0800272 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000273 {
274 return false;
275 }
276 }
277
278 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
279 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -0400280 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000281 {
282 return false;
283 }
284
jchen10eaef1e52017-06-13 10:44:11 +0800285 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
286 {
287 return false;
288 }
289
Olli Etuahob78707c2017-03-09 15:03:11 +0000290 if (!indexUniforms(infoLog, uniformLocationBindings))
291 {
292 return false;
293 }
294
295 return true;
296}
297
Jiawei Shao73618602017-12-20 15:47:15 +0800298bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000299{
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800300 // Check that uniforms defined in the graphics shaders are identical
301 std::map<std::string, ShaderUniform> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000302
Jiawei Shao016105b2018-04-12 16:38:31 +0800303 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Olli Etuahob78707c2017-03-09 15:03:11 +0000304 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800305 Shader *currentShader = mState.getAttachedShader(shaderType);
306 if (currentShader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000307 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800308 if (shaderType == ShaderType::Vertex)
309 {
310 for (const sh::Uniform &vertexUniform : currentShader->getUniforms(context))
311 {
312 linkedUniforms[vertexUniform.name] =
313 std::make_pair(ShaderType::Vertex, &vertexUniform);
314 }
315 }
316 else
317 {
318 bool isLastShader = (shaderType == ShaderType::Fragment);
319 if (!ValidateGraphicsUniformsPerShader(context, currentShader, !isLastShader,
320 &linkedUniforms, infoLog))
321 {
322 return false;
323 }
324 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000325 }
326 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800327
Olli Etuahob78707c2017-03-09 15:03:11 +0000328 return true;
329}
330
Jamie Madill3c1da042017-11-27 18:33:40 -0500331bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000332{
Olli Etuahob78707c2017-03-09 15:03:11 +0000333 // Locations which have been allocated for an unused uniform.
334 std::set<GLuint> ignoredLocations;
335
336 int maxUniformLocation = -1;
337
338 // Gather uniform locations that have been set either using the bindUniformLocation API or by
339 // using a location layout qualifier and check conflicts between them.
340 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
Olli Etuaho44861c42018-03-23 14:36:39 +0200341 &ignoredLocations, &maxUniformLocation))
Olli Etuahob78707c2017-03-09 15:03:11 +0000342 {
343 return false;
344 }
345
346 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
347 // the line relies on only having statically used uniforms in mUniforms.
348 pruneUnusedUniforms();
349
350 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
351 std::vector<VariableLocation> unlocatedUniforms;
352 std::map<GLuint, VariableLocation> preLocatedUniforms;
353
354 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
355 {
356 const LinkedUniform &uniform = mUniforms[uniformIndex];
357
jchen10baf5d942017-08-28 20:45:48 +0800358 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000359 {
360 continue;
361 }
362
Olli Etuahod2551232017-10-26 20:03:33 +0300363 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000364 int shaderLocation = uniform.location;
365
366 if (shaderLocation != -1)
367 {
368 preSetLocation = shaderLocation;
369 }
370
Olli Etuaho465835d2017-09-26 13:34:10 +0300371 unsigned int elementCount = uniform.getBasicTypeElementCount();
372 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000373 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400374 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000375
376 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
377 {
378 int elementLocation = preSetLocation + arrayIndex;
379 preLocatedUniforms[elementLocation] = location;
380 }
381 else
382 {
383 unlocatedUniforms.push_back(location);
384 }
385 }
386 }
387
388 // Make enough space for all uniforms, with pre-set locations or not.
389 mUniformLocations.resize(
390 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
391 static_cast<size_t>(maxUniformLocation + 1)));
392
393 // Assign uniforms with pre-set locations
394 for (const auto &uniform : preLocatedUniforms)
395 {
396 mUniformLocations[uniform.first] = uniform.second;
397 }
398
399 // Assign ignored uniforms
400 for (const auto &ignoredLocation : ignoredLocations)
401 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400402 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000403 }
404
405 // Automatically assign locations for the rest of the uniforms
406 size_t nextUniformLocation = 0;
407 for (const auto &unlocatedUniform : unlocatedUniforms)
408 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400409 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000410 mUniformLocations[nextUniformLocation].ignored)
411 {
412 nextUniformLocation++;
413 }
414
415 ASSERT(nextUniformLocation < mUniformLocations.size());
416 mUniformLocations[nextUniformLocation] = unlocatedUniform;
417 nextUniformLocation++;
418 }
419
420 return true;
421}
422
423bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
424 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500425 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000426 std::set<GLuint> *ignoredLocations,
427 int *maxUniformLocation)
428{
Olli Etuaho44861c42018-03-23 14:36:39 +0200429 // All the locations where another uniform can't be located.
430 std::set<GLuint> reservedLocations;
431
Olli Etuahob78707c2017-03-09 15:03:11 +0000432 for (const LinkedUniform &uniform : mUniforms)
433 {
434 if (uniform.isBuiltIn())
435 {
436 continue;
437 }
438
Olli Etuahod2551232017-10-26 20:03:33 +0300439 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000440 int shaderLocation = uniform.location;
441
442 if (shaderLocation != -1)
443 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300444 unsigned int elementCount = uniform.getBasicTypeElementCount();
445
446 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000447 {
448 // GLSL ES 3.10 section 4.4.3
449 int elementLocation = shaderLocation + arrayIndex;
450 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200451 if (reservedLocations.find(elementLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000452 {
453 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
454 return false;
455 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200456 reservedLocations.insert(elementLocation);
Olli Etuaho107c7242018-03-20 15:45:35 +0200457 if (!uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000458 {
459 ignoredLocations->insert(elementLocation);
460 }
461 }
462 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200463 else if (apiBoundLocation != -1 && uniform.staticUse)
Olli Etuahob78707c2017-03-09 15:03:11 +0000464 {
465 // Only the first location is reserved even if the uniform is an array.
466 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200467 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000468 {
469 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
470 return false;
471 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200472 reservedLocations.insert(apiBoundLocation);
473 if (!uniform.active)
474 {
475 ignoredLocations->insert(apiBoundLocation);
476 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000477 }
478 }
479
480 // Record the uniform locations that were bound using the API for uniforms that were not found
481 // from the shader. Other uniforms should not be assigned to those locations.
482 for (const auto &locationBinding : uniformLocationBindings)
483 {
484 GLuint location = locationBinding.second;
Olli Etuaho44861c42018-03-23 14:36:39 +0200485 if (reservedLocations.find(location) == reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000486 {
487 ignoredLocations->insert(location);
488 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
489 }
490 }
491
492 return true;
493}
494
495void UniformLinker::pruneUnusedUniforms()
496{
497 auto uniformIter = mUniforms.begin();
498 while (uniformIter != mUniforms.end())
499 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200500 if (uniformIter->active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000501 {
502 ++uniformIter;
503 }
504 else
505 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400506 mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler());
Olli Etuahob78707c2017-03-09 15:03:11 +0000507 uniformIter = mUniforms.erase(uniformIter);
508 }
509 }
510}
511
512bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400513 const Context *context,
514 Shader *shader,
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800515 const Caps &caps,
Olli Etuahob78707c2017-03-09 15:03:11 +0000516 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800517 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800518 std::vector<LinkedUniform> &atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400519 std::vector<UnusedUniform> &unusedUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000520 InfoLog &infoLog)
521{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800522 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400523 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000524 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400525 shaderUniformCount +=
526 flattenUniform(uniform, &samplerUniforms, &imageUniforms, &atomicCounterUniforms,
527 &unusedUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000528 }
529
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800530 ShaderType shaderType = shader->getType();
531
532 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
533 GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
534 if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
Olli Etuahob78707c2017-03-09 15:03:11 +0000535 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800536 GLuint maxUniforms = 0u;
537
538 // See comments in GetUniformResourceLimitName()
539 if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
540 {
541 maxUniforms = maxUniformVectorsCount;
542 }
543 else
544 {
545 maxUniforms = maxUniformVectorsCount * 4;
546 }
547
548 LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000549 return false;
550 }
551
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800552 if (shaderUniformCount.samplerCount > caps.maxShaderTextureImageUnits[shaderType])
Olli Etuahob78707c2017-03-09 15:03:11 +0000553 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800554 LogUniformsExceedLimit(shaderType, UniformType::Sampler,
555 caps.maxShaderTextureImageUnits[shaderType], infoLog);
Olli Etuahob78707c2017-03-09 15:03:11 +0000556 return false;
557 }
558
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800559 if (shaderUniformCount.imageCount > caps.maxShaderImageUniforms[shaderType])
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800560 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800561 LogUniformsExceedLimit(shaderType, UniformType::Image,
562 caps.maxShaderImageUniforms[shaderType], infoLog);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800563 return false;
564 }
565
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800566 if (shaderUniformCount.atomicCounterCount > caps.maxShaderAtomicCounters[shaderType])
jchen10eaef1e52017-06-13 10:44:11 +0800567 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800568 LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
569 caps.maxShaderAtomicCounters[shaderType], infoLog);
jchen10eaef1e52017-06-13 10:44:11 +0800570 return false;
571 }
572
Olli Etuahob78707c2017-03-09 15:03:11 +0000573 return true;
574}
575
Jamie Madillbd044ed2017-06-05 12:59:21 -0400576bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000577{
578 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800579 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800580 std::vector<LinkedUniform> atomicCounterUniforms;
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400581 std::vector<UnusedUniform> unusedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000582
Jamie Madillbd044ed2017-06-05 12:59:21 -0400583 const Caps &caps = context->getCaps();
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800584 for (ShaderType shaderType : AllShaderTypes())
Olli Etuahob78707c2017-03-09 15:03:11 +0000585 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800586 Shader *shader = mState.getAttachedShader(shaderType);
587 if (!shader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000588 {
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800589 continue;
Olli Etuahob78707c2017-03-09 15:03:11 +0000590 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400591
Jiawei Shao0c4e08e2018-05-08 11:00:36 +0800592 if (!flattenUniformsAndCheckCapsForShader(context, shader, caps, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400593 imageUniforms, atomicCounterUniforms,
594 unusedUniforms, infoLog))
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800595 {
596 return false;
597 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000598 }
599
600 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800601 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800602 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400603 mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000604 return true;
605}
606
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800607UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000608 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800609 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800610 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800611 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400612 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800613 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000614{
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400615 int location = uniform.location;
616 ShaderUniformCount shaderUniformCount = flattenUniformImpl(
617 uniform, uniform.name, uniform.mappedName, samplerUniforms, imageUniforms,
618 atomicCounterUniforms, unusedUniforms, shaderType, uniform.active, uniform.staticUse,
619 uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200620 if (uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000621 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800622 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000623 }
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400624 else
625 {
626 unusedUniforms->emplace_back(uniform.name, IsSamplerType(uniform.type));
627 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800628 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000629}
630
Olli Etuaho465835d2017-09-26 13:34:10 +0300631UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
632 const sh::ShaderVariable &uniform,
633 unsigned int arrayNestingIndex,
634 const std::string &namePrefix,
635 const std::string &mappedNamePrefix,
636 std::vector<LinkedUniform> *samplerUniforms,
637 std::vector<LinkedUniform> *imageUniforms,
638 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400639 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800640 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200641 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200642 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300643 int binding,
644 int offset,
645 int *location)
646{
647 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
648 // innermost.
649 ShaderUniformCount shaderUniformCount;
650 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
651 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
652 {
653 const std::string elementName = namePrefix + ArrayString(arrayElement);
654 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
655 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
656 {
657 shaderUniformCount += flattenArrayOfStructsUniform(
658 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400659 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType, markActive,
660 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300661 }
662 else
663 {
664 shaderUniformCount += flattenStructUniform(
665 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400666 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
667 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300668 }
669 }
670 return shaderUniformCount;
671}
672
673UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
674 const std::vector<sh::ShaderVariable> &fields,
675 const std::string &namePrefix,
676 const std::string &mappedNamePrefix,
677 std::vector<LinkedUniform> *samplerUniforms,
678 std::vector<LinkedUniform> *imageUniforms,
679 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400680 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800681 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200682 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200683 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300684 int binding,
685 int offset,
686 int *location)
687{
688 ShaderUniformCount shaderUniformCount;
689 for (const sh::ShaderVariable &field : fields)
690 {
691 const std::string &fieldName = namePrefix + "." + field.name;
692 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
693
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400694 shaderUniformCount +=
695 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
696 atomicCounterUniforms, unusedUniforms, shaderType, markActive,
697 markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300698 }
699 return shaderUniformCount;
700}
701
702UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
703 const sh::ShaderVariable &uniform,
704 const std::string &namePrefix,
705 const std::string &mappedNamePrefix,
706 std::vector<LinkedUniform> *samplerUniforms,
707 std::vector<LinkedUniform> *imageUniforms,
708 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400709 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800710 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200711 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200712 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300713 int binding,
714 int offset,
715 int *location)
716{
717 ShaderUniformCount shaderUniformCount;
718
719 ASSERT(uniform.isArray());
720 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
721 ++arrayElement)
722 {
723 sh::ShaderVariable uniformElement = uniform;
724 uniformElement.indexIntoArray(arrayElement);
725 const std::string elementName = namePrefix + ArrayString(arrayElement);
726 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
727
Olli Etuaho44861c42018-03-23 14:36:39 +0200728 shaderUniformCount +=
729 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400730 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
731 markActive, markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300732 }
733 return shaderUniformCount;
734}
735
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800736UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000737 const sh::ShaderVariable &uniform,
738 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300739 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000740 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800741 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800742 std::vector<LinkedUniform> *atomicCounterUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400743 std::vector<UnusedUniform> *unusedUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800744 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200745 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200746 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000747 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800748 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000749 int *location)
750{
751 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800752 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000753
754 if (uniform.isStruct())
755 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300756 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000757 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400758 shaderUniformCount += flattenArrayOfStructsUniform(
759 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
760 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
761 binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000762 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300763 else
764 {
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400765 shaderUniformCount += flattenStructUniform(
766 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
767 atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
768 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300769 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800770 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000771 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300772 if (uniform.isArrayOfArrays())
773 {
774 // GLES 3.1 November 2016 section 7.3.1 page 77:
775 // "For an active variable declared as an array of an aggregate data type (structures or
776 // arrays), a separate entry will be generated for each active array element"
777 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400778 imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
779 markActive, markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300780 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000781
782 // Not a struct
783 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800784 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800785 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000786 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
787 if (isSampler)
788 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000789 uniformList = samplerUniforms;
790 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800791 else if (isImage)
792 {
793 uniformList = imageUniforms;
794 }
jchen10eaef1e52017-06-13 10:44:11 +0800795 else if (isAtomicCounter)
796 {
797 uniformList = atomicCounterUniforms;
798 }
Olli Etuahod2551232017-10-26 20:03:33 +0300799
800 std::string fullNameWithArrayIndex(fullName);
801 std::string fullMappedNameWithArrayIndex(fullMappedName);
802
803 if (uniform.isArray())
804 {
805 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
806 // and including [0] at the end of array variable names.
807 fullNameWithArrayIndex += "[0]";
808 fullMappedNameWithArrayIndex += "[0]";
809 }
810
811 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000812 if (existingUniform)
813 {
814 if (binding != -1)
815 {
816 existingUniform->binding = binding;
817 }
jchen10eaef1e52017-06-13 10:44:11 +0800818 if (offset != -1)
819 {
820 existingUniform->offset = offset;
821 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000822 if (*location != -1)
823 {
824 existingUniform->location = *location;
825 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200826 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000827 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200828 existingUniform->active = true;
829 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000830 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200831 if (markStaticUse)
832 {
833 existingUniform->staticUse = true;
834 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000835 }
836 else
837 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300838 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300839 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300840 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000841 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300842 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200843 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200844 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300845 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200846 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800847 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200848 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800849 }
Luc Ferrone17b5ba2018-06-04 14:28:58 -0400850 else
851 {
852 unusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler());
853 }
jchen10eaef1e52017-06-13 10:44:11 +0800854
Olli Etuahob78707c2017-03-09 15:03:11 +0000855 uniformList->push_back(linkedUniform);
856 }
857
Olli Etuaho465835d2017-09-26 13:34:10 +0300858 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
859 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000860
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800861 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800862 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800863 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800864 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500865 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500866 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800867 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000868
869 if (*location != -1)
870 {
871 *location += elementCount;
872 }
873
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800874 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000875}
876
jchen10eaef1e52017-06-13 10:44:11 +0800877bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
878{
879 unsigned int atomicCounterCount = 0;
880 for (const auto &uniform : mUniforms)
881 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200882 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800883 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300884 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800885 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
886 {
887 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
888 << caps.maxCombinedAtomicCounters << ").";
889 return false;
890 }
891 }
892 }
893 return true;
894}
895
Jamie Madill977abce2017-11-07 08:03:19 -0500896// InterfaceBlockLinker implementation.
897InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
Jiawei Shao016105b2018-04-12 16:38:31 +0800898 : mShaderBlocks({}), mBlocksOut(blocksOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500899{
900}
901
902InterfaceBlockLinker::~InterfaceBlockLinker()
903{
904}
905
Jiawei Shao016105b2018-04-12 16:38:31 +0800906void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
Jamie Madill977abce2017-11-07 08:03:19 -0500907 const std::vector<sh::InterfaceBlock> *blocks)
908{
Jiawei Shao016105b2018-04-12 16:38:31 +0800909 mShaderBlocks[shaderType] = blocks;
Jamie Madill977abce2017-11-07 08:03:19 -0500910}
911
912void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
913 const GetBlockMemberInfo &getMemberInfo) const
914{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500915 ASSERT(mBlocksOut->empty());
916
Jamie Madill977abce2017-11-07 08:03:19 -0500917 std::set<std::string> visitedList;
918
Jiawei Shao016105b2018-04-12 16:38:31 +0800919 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill977abce2017-11-07 08:03:19 -0500920 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800921 if (!mShaderBlocks[shaderType])
922 {
923 continue;
924 }
Jamie Madill977abce2017-11-07 08:03:19 -0500925
Jiawei Shao016105b2018-04-12 16:38:31 +0800926 for (const auto &block : *mShaderBlocks[shaderType])
Jamie Madill977abce2017-11-07 08:03:19 -0500927 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800928 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500929 continue;
930
931 if (visitedList.count(block.name) > 0)
932 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200933 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500934 {
935 for (InterfaceBlock &priorBlock : *mBlocksOut)
936 {
937 if (block.name == priorBlock.name)
938 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200939 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800940 // Update the block members static use.
941 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
942 block.fieldMappedPrefix(), -1,
943 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
944 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500945 }
946 }
947 }
948 }
949 else
950 {
951 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
952 visitedList.insert(block.name);
953 }
954 }
955 }
956}
957
958template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300959void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
960 const VarT &field,
961 unsigned int arrayNestingIndex,
962 const std::string &prefix,
963 const std::string &mappedPrefix,
964 int blockIndex,
965 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800966 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800967 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300968{
969 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
970 // innermost.
971 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
972 if (singleEntryForTopLevelArray)
973 {
974 entryGenerationArraySize = 1;
975 }
976 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
977 {
978 const std::string elementName = prefix + ArrayString(arrayElement);
979 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
980 if (arrayNestingIndex + 1u < field.arraySizes.size())
981 {
982 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
983 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800984 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300985 }
986 else
987 {
988 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800989 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300990 }
991 }
992}
993
994template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500995void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
996 const std::vector<VarT> &fields,
997 const std::string &prefix,
998 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800999 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +03001000 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001001 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001002 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001003{
1004 for (const VarT &field : fields)
1005 {
1006 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -05001007 std::string fullMappedName =
1008 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
1009
Olli Etuaho465835d2017-09-26 13:34:10 +03001010 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001011 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +03001012 }
1013}
1014
1015template <typename VarT>
1016void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
1017 const VarT &field,
1018 const std::string &fullName,
1019 const std::string &fullMappedName,
1020 int blockIndex,
1021 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001022 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001023 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +03001024{
1025 int nextArraySize = topLevelArraySize;
1026 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
1027 singleEntryForTopLevelArray)
1028 {
1029 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
1030 // member declared as an array of an aggregate type, an entry will be generated only
1031 // for the first array element, regardless of its type.'
1032 nextArraySize = field.getOutermostArraySize();
1033 }
1034
1035 if (field.isStruct())
1036 {
1037 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001038 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001039 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001040 blockIndex, singleEntryForTopLevelArray, nextArraySize,
1041 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001042 }
1043 else
1044 {
Olli Etuaho465835d2017-09-26 13:34:10 +03001045 ASSERT(nextArraySize == topLevelArraySize);
1046 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001047 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001048 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001049 return;
Jamie Madill977abce2017-11-07 08:03:19 -05001050 }
Olli Etuaho465835d2017-09-26 13:34:10 +03001051 if (field.isArrayOfArrays())
1052 {
1053 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
1054 if (singleEntryForTopLevelArray)
1055 {
1056 entryGenerationArraySize = 1u;
1057 }
1058 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
1059 ++arrayElement)
1060 {
1061 VarT fieldElement = field;
1062 fieldElement.indexIntoArray(arrayElement);
1063 const std::string elementName = fullName + ArrayString(arrayElement);
1064 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
1065
1066 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001067 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +03001068 }
1069 return;
1070 }
1071
Olli Etuaho465835d2017-09-26 13:34:10 +03001072 std::string fullNameWithArrayIndex = fullName;
1073 std::string fullMappedNameWithArrayIndex = fullMappedName;
1074
1075 if (field.isArray())
1076 {
1077 fullNameWithArrayIndex += "[0]";
1078 fullMappedNameWithArrayIndex += "[0]";
1079 }
1080
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001081 if (blockIndex == -1)
1082 {
Olli Etuaho107c7242018-03-20 15:45:35 +02001083 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001084 }
1085 else
1086 {
1087 // If getBlockMemberInfo returns false, the variable is optimized out.
1088 sh::BlockMemberInfo memberInfo;
1089 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
1090 {
1091 return;
1092 }
1093
1094 ASSERT(nextArraySize == topLevelArraySize);
1095 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1096 blockIndex, memberInfo, nextArraySize, shaderType);
1097 }
Jamie Madill977abce2017-11-07 08:03:19 -05001098}
1099
1100void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1101 const GetBlockMemberInfo &getMemberInfo,
1102 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001103 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001104{
1105 size_t blockSize = 0;
1106 std::vector<unsigned int> blockIndexes;
1107
1108 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001109 // Track the first and last block member index to determine the range of active block members in
1110 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001111 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1112 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001113 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001114 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001115 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1116
1117 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1118 ++blockMemberIndex)
1119 {
1120 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1121 }
1122
Jamie Madill977abce2017-11-07 08:03:19 -05001123 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1124 ++arrayElement)
1125 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001126 std::string blockArrayName = interfaceBlock.name;
1127 std::string blockMappedArrayName = interfaceBlock.mappedName;
1128 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001129 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001130 blockArrayName += ArrayString(arrayElement);
1131 blockMappedArrayName += ArrayString(arrayElement);
1132 }
Jamie Madill977abce2017-11-07 08:03:19 -05001133
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001134 // Don't define this block at all if it's not active in the implementation.
1135 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1136 {
1137 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001138 }
1139
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001140 // ESSL 3.10 section 4.4.4 page 58:
1141 // Any uniform or shader storage block declared without a binding qualifier is initially
1142 // assigned to block binding point zero.
1143 int blockBinding =
1144 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001145 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001146 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001147 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001148 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001149
1150 // Since all block elements in an array share the same active interface blocks, they
1151 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1152 // was active, here we will add every block element in the array.
1153 block.dataSize = static_cast<unsigned int>(blockSize);
1154 mBlocksOut->push_back(block);
1155 }
1156}
1157
1158// UniformBlockLinker implementation.
1159UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1160 std::vector<LinkedUniform> *uniformsOut)
1161 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1162{
1163}
1164
1165UniformBlockLinker::~UniformBlockLinker()
1166{
1167}
1168
Olli Etuaho465835d2017-09-26 13:34:10 +03001169void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1170 const std::string &fullName,
1171 const std::string &fullMappedName,
1172 int blockIndex,
1173 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001174 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001175 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001176{
Olli Etuaho465835d2017-09-26 13:34:10 +03001177 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001178 blockIndex, memberInfo);
1179 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001180 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001181
1182 // Since block uniforms have no location, we don't need to store them in the uniform locations
1183 // list.
1184 mUniformsOut->push_back(newUniform);
1185}
1186
1187size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1188{
1189 return mUniformsOut->size();
1190}
1191
Olli Etuaho107c7242018-03-20 15:45:35 +02001192void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001193 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001194 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001195{
Olli Etuaho107c7242018-03-20 15:45:35 +02001196 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001197}
1198
Jamie Madill977abce2017-11-07 08:03:19 -05001199// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001200ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1201 std::vector<BufferVariable> *bufferVariablesOut)
1202 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001203{
1204}
1205
1206ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1207{
1208}
1209
Olli Etuaho465835d2017-09-26 13:34:10 +03001210void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1211 const std::string &fullName,
1212 const std::string &fullMappedName,
1213 int blockIndex,
1214 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001215 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001216 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001217{
Olli Etuaho465835d2017-09-26 13:34:10 +03001218 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001219 blockIndex, memberInfo);
1220 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001221 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001222
1223 newBufferVariable.topLevelArraySize = topLevelArraySize;
1224
1225 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001226}
1227
1228size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1229{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001230 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001231}
1232
Olli Etuaho107c7242018-03-20 15:45:35 +02001233void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001234 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001235 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001236{
Olli Etuaho107c7242018-03-20 15:45:35 +02001237 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001238}
1239
Jiajia Qin94f1e892017-11-20 12:14:32 +08001240// AtomicCounterBufferLinker implementation.
1241AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1242 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1243 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1244{
1245}
1246
1247AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1248{
1249}
1250
1251void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1252{
1253 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1254 {
1255 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1256 ASSERT(bufferSize != sizeMap.end());
1257 atomicCounterBuffer.dataSize = bufferSize->second;
1258 }
1259}
1260
Olli Etuahob78707c2017-03-09 15:03:11 +00001261} // namespace gl