blob: 9ef76b70ff652f2eca3292e80f8160273c51ed21 [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
Olli Etuahod2551232017-10-26 20:03:33 +0300138} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +0000139
140UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
141{
142}
143
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500144UniformLinker::~UniformLinker() = default;
145
Olli Etuahob78707c2017-03-09 15:03:11 +0000146void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
147 std::vector<VariableLocation> *uniformLocations)
148{
149 uniforms->swap(mUniforms);
150 uniformLocations->swap(mUniformLocations);
151}
152
Jamie Madillbd044ed2017-06-05 12:59:21 -0400153bool UniformLinker::link(const Context *context,
154 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500155 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000156{
Jiawei Shao385b3e02018-03-21 09:43:28 +0800157 if (mState.getAttachedShader(ShaderType::Vertex) &&
158 mState.getAttachedShader(ShaderType::Fragment))
Olli Etuahob78707c2017-03-09 15:03:11 +0000159 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800160 ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +0800161 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000162 {
163 return false;
164 }
165 }
166
167 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
168 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -0400169 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000170 {
171 return false;
172 }
173
jchen10eaef1e52017-06-13 10:44:11 +0800174 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
175 {
176 return false;
177 }
178
Olli Etuahob78707c2017-03-09 15:03:11 +0000179 if (!indexUniforms(infoLog, uniformLocationBindings))
180 {
181 return false;
182 }
183
184 return true;
185}
186
Jiawei Shao73618602017-12-20 15:47:15 +0800187bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000188{
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800189 // Check that uniforms defined in the graphics shaders are identical
190 std::map<std::string, ShaderUniform> linkedUniforms;
Jiawei Shao385b3e02018-03-21 09:43:28 +0800191 for (const sh::Uniform &vertexUniform :
192 mState.getAttachedShader(ShaderType::Vertex)->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000193 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800194 linkedUniforms[vertexUniform.name] = std::make_pair(ShaderType::Vertex, &vertexUniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000195 }
196
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800197 std::vector<Shader *> activeShadersToLink;
Jiawei Shao385b3e02018-03-21 09:43:28 +0800198 if (mState.getAttachedShader(ShaderType::Geometry))
Olli Etuahob78707c2017-03-09 15:03:11 +0000199 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800200 activeShadersToLink.push_back(mState.getAttachedShader(ShaderType::Geometry));
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800201 }
Jiawei Shao385b3e02018-03-21 09:43:28 +0800202 activeShadersToLink.push_back(mState.getAttachedShader(ShaderType::Fragment));
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800203
204 const size_t numActiveShadersToLink = activeShadersToLink.size();
205 for (size_t shaderIndex = 0; shaderIndex < numActiveShadersToLink; ++shaderIndex)
206 {
207 bool isLastShader = (shaderIndex == numActiveShadersToLink - 1);
208 if (!ValidateGraphicsUniformsPerShader(context, activeShadersToLink[shaderIndex],
209 !isLastShader, &linkedUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000210 {
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800211 return false;
Olli Etuahob78707c2017-03-09 15:03:11 +0000212 }
213 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800214
Olli Etuahob78707c2017-03-09 15:03:11 +0000215 return true;
216}
217
Jamie Madill3c1da042017-11-27 18:33:40 -0500218bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000219{
Olli Etuahob78707c2017-03-09 15:03:11 +0000220 // Locations which have been allocated for an unused uniform.
221 std::set<GLuint> ignoredLocations;
222
223 int maxUniformLocation = -1;
224
225 // Gather uniform locations that have been set either using the bindUniformLocation API or by
226 // using a location layout qualifier and check conflicts between them.
227 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
Olli Etuaho44861c42018-03-23 14:36:39 +0200228 &ignoredLocations, &maxUniformLocation))
Olli Etuahob78707c2017-03-09 15:03:11 +0000229 {
230 return false;
231 }
232
233 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
234 // the line relies on only having statically used uniforms in mUniforms.
235 pruneUnusedUniforms();
236
237 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
238 std::vector<VariableLocation> unlocatedUniforms;
239 std::map<GLuint, VariableLocation> preLocatedUniforms;
240
241 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
242 {
243 const LinkedUniform &uniform = mUniforms[uniformIndex];
244
jchen10baf5d942017-08-28 20:45:48 +0800245 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000246 {
247 continue;
248 }
249
Olli Etuahod2551232017-10-26 20:03:33 +0300250 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000251 int shaderLocation = uniform.location;
252
253 if (shaderLocation != -1)
254 {
255 preSetLocation = shaderLocation;
256 }
257
Olli Etuaho465835d2017-09-26 13:34:10 +0300258 unsigned int elementCount = uniform.getBasicTypeElementCount();
259 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000260 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400261 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000262
263 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
264 {
265 int elementLocation = preSetLocation + arrayIndex;
266 preLocatedUniforms[elementLocation] = location;
267 }
268 else
269 {
270 unlocatedUniforms.push_back(location);
271 }
272 }
273 }
274
275 // Make enough space for all uniforms, with pre-set locations or not.
276 mUniformLocations.resize(
277 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
278 static_cast<size_t>(maxUniformLocation + 1)));
279
280 // Assign uniforms with pre-set locations
281 for (const auto &uniform : preLocatedUniforms)
282 {
283 mUniformLocations[uniform.first] = uniform.second;
284 }
285
286 // Assign ignored uniforms
287 for (const auto &ignoredLocation : ignoredLocations)
288 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400289 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000290 }
291
292 // Automatically assign locations for the rest of the uniforms
293 size_t nextUniformLocation = 0;
294 for (const auto &unlocatedUniform : unlocatedUniforms)
295 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400296 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000297 mUniformLocations[nextUniformLocation].ignored)
298 {
299 nextUniformLocation++;
300 }
301
302 ASSERT(nextUniformLocation < mUniformLocations.size());
303 mUniformLocations[nextUniformLocation] = unlocatedUniform;
304 nextUniformLocation++;
305 }
306
307 return true;
308}
309
310bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
311 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500312 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000313 std::set<GLuint> *ignoredLocations,
314 int *maxUniformLocation)
315{
Olli Etuaho44861c42018-03-23 14:36:39 +0200316 // All the locations where another uniform can't be located.
317 std::set<GLuint> reservedLocations;
318
Olli Etuahob78707c2017-03-09 15:03:11 +0000319 for (const LinkedUniform &uniform : mUniforms)
320 {
321 if (uniform.isBuiltIn())
322 {
323 continue;
324 }
325
Olli Etuahod2551232017-10-26 20:03:33 +0300326 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000327 int shaderLocation = uniform.location;
328
329 if (shaderLocation != -1)
330 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300331 unsigned int elementCount = uniform.getBasicTypeElementCount();
332
333 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000334 {
335 // GLSL ES 3.10 section 4.4.3
336 int elementLocation = shaderLocation + arrayIndex;
337 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200338 if (reservedLocations.find(elementLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000339 {
340 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
341 return false;
342 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200343 reservedLocations.insert(elementLocation);
Olli Etuaho107c7242018-03-20 15:45:35 +0200344 if (!uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000345 {
346 ignoredLocations->insert(elementLocation);
347 }
348 }
349 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200350 else if (apiBoundLocation != -1 && uniform.staticUse)
Olli Etuahob78707c2017-03-09 15:03:11 +0000351 {
352 // Only the first location is reserved even if the uniform is an array.
353 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200354 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000355 {
356 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
357 return false;
358 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200359 reservedLocations.insert(apiBoundLocation);
360 if (!uniform.active)
361 {
362 ignoredLocations->insert(apiBoundLocation);
363 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000364 }
365 }
366
367 // Record the uniform locations that were bound using the API for uniforms that were not found
368 // from the shader. Other uniforms should not be assigned to those locations.
369 for (const auto &locationBinding : uniformLocationBindings)
370 {
371 GLuint location = locationBinding.second;
Olli Etuaho44861c42018-03-23 14:36:39 +0200372 if (reservedLocations.find(location) == reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000373 {
374 ignoredLocations->insert(location);
375 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
376 }
377 }
378
379 return true;
380}
381
382void UniformLinker::pruneUnusedUniforms()
383{
384 auto uniformIter = mUniforms.begin();
385 while (uniformIter != mUniforms.end())
386 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200387 if (uniformIter->active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000388 {
389 ++uniformIter;
390 }
391 else
392 {
393 uniformIter = mUniforms.erase(uniformIter);
394 }
395 }
396}
397
398bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400399 const Context *context,
400 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000401 GLuint maxUniformComponents,
402 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800403 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800404 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000405 const std::string &componentsErrorMessage,
406 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800407 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800408 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000409 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800410 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800411 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000412 InfoLog &infoLog)
413{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800414 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400415 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000416 {
jchen10baf5d942017-08-28 20:45:48 +0800417 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
418 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000419 }
420
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800421 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000422 {
423 infoLog << componentsErrorMessage << maxUniformComponents << ").";
424 return false;
425 }
426
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800427 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000428 {
429 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
430 return false;
431 }
432
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800433 if (shaderUniformCount.imageCount > maxImageUnits)
434 {
435 infoLog << imageErrorMessage << maxImageUnits << ").";
436 return false;
437 }
438
jchen10eaef1e52017-06-13 10:44:11 +0800439 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
440 {
441 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
442 return false;
443 }
444
Olli Etuahob78707c2017-03-09 15:03:11 +0000445 return true;
446}
447
Jamie Madillbd044ed2017-06-05 12:59:21 -0400448bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000449{
450 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800451 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800452 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000453
Jamie Madillbd044ed2017-06-05 12:59:21 -0400454 const Caps &caps = context->getCaps();
455
Jiawei Shao385b3e02018-03-21 09:43:28 +0800456 if (mState.getAttachedShader(ShaderType::Compute))
Olli Etuahob78707c2017-03-09 15:03:11 +0000457 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800458 Shader *computeShader = mState.getAttachedShader(ShaderType::Compute);
Olli Etuahob78707c2017-03-09 15:03:11 +0000459
460 // TODO (mradev): check whether we need finer-grained component counting
461 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400462 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800463 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800464 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000465 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
466 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800467 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
468 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
469 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000470 {
471 return false;
472 }
473 }
474 else
475 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800476 Shader *vertexShader = mState.getAttachedShader(ShaderType::Vertex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000477
478 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400479 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800481 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000482 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
483 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800484 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
485 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
486 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000487 {
488 return false;
489 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400490
Jiawei Shao385b3e02018-03-21 09:43:28 +0800491 Shader *fragmentShader = mState.getAttachedShader(ShaderType::Fragment);
Olli Etuahob78707c2017-03-09 15:03:11 +0000492
493 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400494 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800495 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000496 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800497 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
498 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800499 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
500 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000501 {
502 return false;
503 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800504
Jiawei Shao385b3e02018-03-21 09:43:28 +0800505 Shader *geometryShader = mState.getAttachedShader(ShaderType::Geometry);
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800506 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
507 if (geometryShader &&
508 !flattenUniformsAndCheckCapsForShader(
509 context, geometryShader, caps.maxGeometryUniformComponents / 4,
510 caps.maxGeometryTextureImageUnits, caps.maxGeometryImageUniforms,
511 caps.maxGeometryAtomicCounters,
512 "Geometry shader active uniforms exceed MAX_GEOMETRY_UNIFORM_VECTORS_EXT (",
513 "Geometry shader sampler count exceeds MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (",
514 "Geometry shader image count exceeds MAX_GEOMETRY_IMAGE_UNIFORMS_EXT (",
515 "Geometry shader atomic counter count exceeds MAX_GEOMETRY_ATOMIC_COUNTERS_EXT (",
516 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
517 {
518 return false;
519 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000520 }
521
522 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800523 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800524 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000525 return true;
526}
527
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800528UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000529 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800530 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800531 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800532 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800533 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000534{
Jamie Madill977abce2017-11-07 08:03:19 -0500535 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800536 ShaderUniformCount shaderUniformCount =
537 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200538 imageUniforms, atomicCounterUniforms, shaderType, uniform.active,
Olli Etuaho44861c42018-03-23 14:36:39 +0200539 uniform.staticUse, uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200540 if (uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000541 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800542 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000543 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800544 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000545}
546
Olli Etuaho465835d2017-09-26 13:34:10 +0300547UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
548 const sh::ShaderVariable &uniform,
549 unsigned int arrayNestingIndex,
550 const std::string &namePrefix,
551 const std::string &mappedNamePrefix,
552 std::vector<LinkedUniform> *samplerUniforms,
553 std::vector<LinkedUniform> *imageUniforms,
554 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800555 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200556 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200557 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300558 int binding,
559 int offset,
560 int *location)
561{
562 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
563 // innermost.
564 ShaderUniformCount shaderUniformCount;
565 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
566 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
567 {
568 const std::string elementName = namePrefix + ArrayString(arrayElement);
569 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
570 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
571 {
572 shaderUniformCount += flattenArrayOfStructsUniform(
573 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200574 imageUniforms, atomicCounterUniforms, shaderType, markActive, markStaticUse,
575 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300576 }
577 else
578 {
579 shaderUniformCount += flattenStructUniform(
580 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200581 atomicCounterUniforms, shaderType, markActive, markStaticUse, binding, offset,
582 location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300583 }
584 }
585 return shaderUniformCount;
586}
587
588UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
589 const std::vector<sh::ShaderVariable> &fields,
590 const std::string &namePrefix,
591 const std::string &mappedNamePrefix,
592 std::vector<LinkedUniform> *samplerUniforms,
593 std::vector<LinkedUniform> *imageUniforms,
594 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800595 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200596 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200597 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300598 int binding,
599 int offset,
600 int *location)
601{
602 ShaderUniformCount shaderUniformCount;
603 for (const sh::ShaderVariable &field : fields)
604 {
605 const std::string &fieldName = namePrefix + "." + field.name;
606 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
607
Olli Etuaho44861c42018-03-23 14:36:39 +0200608 shaderUniformCount += flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms,
609 imageUniforms, atomicCounterUniforms, shaderType,
610 markActive, markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300611 }
612 return shaderUniformCount;
613}
614
615UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
616 const sh::ShaderVariable &uniform,
617 const std::string &namePrefix,
618 const std::string &mappedNamePrefix,
619 std::vector<LinkedUniform> *samplerUniforms,
620 std::vector<LinkedUniform> *imageUniforms,
621 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800622 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200623 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200624 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300625 int binding,
626 int offset,
627 int *location)
628{
629 ShaderUniformCount shaderUniformCount;
630
631 ASSERT(uniform.isArray());
632 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
633 ++arrayElement)
634 {
635 sh::ShaderVariable uniformElement = uniform;
636 uniformElement.indexIntoArray(arrayElement);
637 const std::string elementName = namePrefix + ArrayString(arrayElement);
638 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
639
Olli Etuaho44861c42018-03-23 14:36:39 +0200640 shaderUniformCount +=
641 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
642 imageUniforms, atomicCounterUniforms, shaderType, markActive,
643 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300644 }
645 return shaderUniformCount;
646}
647
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800648UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000649 const sh::ShaderVariable &uniform,
650 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300651 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000652 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800653 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800654 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800655 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200656 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200657 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000658 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800659 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000660 int *location)
661{
662 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800663 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000664
665 if (uniform.isStruct())
666 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300667 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000668 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200669 shaderUniformCount +=
670 flattenArrayOfStructsUniform(uniform, 0u, fullName, fullMappedName, samplerUniforms,
671 imageUniforms, atomicCounterUniforms, shaderType,
672 markActive, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000673 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300674 else
675 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200676 shaderUniformCount +=
677 flattenStructUniform(uniform.fields, fullName, fullMappedName, samplerUniforms,
678 imageUniforms, atomicCounterUniforms, shaderType, markActive,
679 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300680 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800681 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000682 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300683 if (uniform.isArrayOfArrays())
684 {
685 // GLES 3.1 November 2016 section 7.3.1 page 77:
686 // "For an active variable declared as an array of an aggregate data type (structures or
687 // arrays), a separate entry will be generated for each active array element"
688 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200689 imageUniforms, atomicCounterUniforms, shaderType, markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200690 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300691 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000692
693 // Not a struct
694 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800695 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800696 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000697 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
698 if (isSampler)
699 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000700 uniformList = samplerUniforms;
701 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800702 else if (isImage)
703 {
704 uniformList = imageUniforms;
705 }
jchen10eaef1e52017-06-13 10:44:11 +0800706 else if (isAtomicCounter)
707 {
708 uniformList = atomicCounterUniforms;
709 }
Olli Etuahod2551232017-10-26 20:03:33 +0300710
711 std::string fullNameWithArrayIndex(fullName);
712 std::string fullMappedNameWithArrayIndex(fullMappedName);
713
714 if (uniform.isArray())
715 {
716 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
717 // and including [0] at the end of array variable names.
718 fullNameWithArrayIndex += "[0]";
719 fullMappedNameWithArrayIndex += "[0]";
720 }
721
722 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000723 if (existingUniform)
724 {
725 if (binding != -1)
726 {
727 existingUniform->binding = binding;
728 }
jchen10eaef1e52017-06-13 10:44:11 +0800729 if (offset != -1)
730 {
731 existingUniform->offset = offset;
732 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000733 if (*location != -1)
734 {
735 existingUniform->location = *location;
736 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200737 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000738 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200739 existingUniform->active = true;
740 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000741 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200742 if (markStaticUse)
743 {
744 existingUniform->staticUse = true;
745 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000746 }
747 else
748 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300749 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300750 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300751 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000752 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300753 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200754 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200755 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300756 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200757 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800758 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200759 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800760 }
jchen10eaef1e52017-06-13 10:44:11 +0800761
Olli Etuahob78707c2017-03-09 15:03:11 +0000762 uniformList->push_back(linkedUniform);
763 }
764
Olli Etuaho465835d2017-09-26 13:34:10 +0300765 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
766 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000767
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800768 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800769 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800770 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800771 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500772 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500773 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800774 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000775
776 if (*location != -1)
777 {
778 *location += elementCount;
779 }
780
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800781 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000782}
783
jchen10eaef1e52017-06-13 10:44:11 +0800784bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
785{
786 unsigned int atomicCounterCount = 0;
787 for (const auto &uniform : mUniforms)
788 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200789 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800790 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300791 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800792 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
793 {
794 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
795 << caps.maxCombinedAtomicCounters << ").";
796 return false;
797 }
798 }
799 }
800 return true;
801}
802
Jamie Madill977abce2017-11-07 08:03:19 -0500803// InterfaceBlockLinker implementation.
804InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
805 : mBlocksOut(blocksOut)
806{
807}
808
809InterfaceBlockLinker::~InterfaceBlockLinker()
810{
811}
812
Jiawei Shao385b3e02018-03-21 09:43:28 +0800813void InterfaceBlockLinker::addShaderBlocks(ShaderType shader,
Jamie Madill977abce2017-11-07 08:03:19 -0500814 const std::vector<sh::InterfaceBlock> *blocks)
815{
816 mShaderBlocks.push_back(std::make_pair(shader, blocks));
817}
818
819void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
820 const GetBlockMemberInfo &getMemberInfo) const
821{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500822 ASSERT(mBlocksOut->empty());
823
Jamie Madill977abce2017-11-07 08:03:19 -0500824 std::set<std::string> visitedList;
825
826 for (const auto &shaderBlocks : mShaderBlocks)
827 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800828 const ShaderType shaderType = shaderBlocks.first;
Jamie Madill977abce2017-11-07 08:03:19 -0500829
830 for (const auto &block : *shaderBlocks.second)
831 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800832 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500833 continue;
834
835 if (visitedList.count(block.name) > 0)
836 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200837 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500838 {
839 for (InterfaceBlock &priorBlock : *mBlocksOut)
840 {
841 if (block.name == priorBlock.name)
842 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200843 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800844 // Update the block members static use.
845 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
846 block.fieldMappedPrefix(), -1,
847 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
848 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500849 }
850 }
851 }
852 }
853 else
854 {
855 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
856 visitedList.insert(block.name);
857 }
858 }
859 }
860}
861
862template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300863void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
864 const VarT &field,
865 unsigned int arrayNestingIndex,
866 const std::string &prefix,
867 const std::string &mappedPrefix,
868 int blockIndex,
869 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800870 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800871 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300872{
873 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
874 // innermost.
875 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
876 if (singleEntryForTopLevelArray)
877 {
878 entryGenerationArraySize = 1;
879 }
880 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
881 {
882 const std::string elementName = prefix + ArrayString(arrayElement);
883 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
884 if (arrayNestingIndex + 1u < field.arraySizes.size())
885 {
886 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
887 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800888 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300889 }
890 else
891 {
892 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800893 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300894 }
895 }
896}
897
898template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500899void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
900 const std::vector<VarT> &fields,
901 const std::string &prefix,
902 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800903 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300904 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800905 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800906 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500907{
908 for (const VarT &field : fields)
909 {
910 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500911 std::string fullMappedName =
912 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
913
Olli Etuaho465835d2017-09-26 13:34:10 +0300914 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800915 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300916 }
917}
918
919template <typename VarT>
920void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
921 const VarT &field,
922 const std::string &fullName,
923 const std::string &fullMappedName,
924 int blockIndex,
925 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800926 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800927 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300928{
929 int nextArraySize = topLevelArraySize;
930 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
931 singleEntryForTopLevelArray)
932 {
933 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
934 // member declared as an array of an aggregate type, an entry will be generated only
935 // for the first array element, regardless of its type.'
936 nextArraySize = field.getOutermostArraySize();
937 }
938
939 if (field.isStruct())
940 {
941 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500942 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300943 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800944 blockIndex, singleEntryForTopLevelArray, nextArraySize,
945 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500946 }
947 else
948 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300949 ASSERT(nextArraySize == topLevelArraySize);
950 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800951 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500952 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300953 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500954 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300955 if (field.isArrayOfArrays())
956 {
957 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
958 if (singleEntryForTopLevelArray)
959 {
960 entryGenerationArraySize = 1u;
961 }
962 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
963 ++arrayElement)
964 {
965 VarT fieldElement = field;
966 fieldElement.indexIntoArray(arrayElement);
967 const std::string elementName = fullName + ArrayString(arrayElement);
968 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
969
970 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800971 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300972 }
973 return;
974 }
975
Olli Etuaho465835d2017-09-26 13:34:10 +0300976 std::string fullNameWithArrayIndex = fullName;
977 std::string fullMappedNameWithArrayIndex = fullMappedName;
978
979 if (field.isArray())
980 {
981 fullNameWithArrayIndex += "[0]";
982 fullMappedNameWithArrayIndex += "[0]";
983 }
984
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800985 if (blockIndex == -1)
986 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200987 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800988 }
989 else
990 {
991 // If getBlockMemberInfo returns false, the variable is optimized out.
992 sh::BlockMemberInfo memberInfo;
993 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
994 {
995 return;
996 }
997
998 ASSERT(nextArraySize == topLevelArraySize);
999 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1000 blockIndex, memberInfo, nextArraySize, shaderType);
1001 }
Jamie Madill977abce2017-11-07 08:03:19 -05001002}
1003
1004void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1005 const GetBlockMemberInfo &getMemberInfo,
1006 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001007 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001008{
1009 size_t blockSize = 0;
1010 std::vector<unsigned int> blockIndexes;
1011
1012 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001013 // Track the first and last block member index to determine the range of active block members in
1014 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001015 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1016 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001017 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001018 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001019 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1020
1021 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1022 ++blockMemberIndex)
1023 {
1024 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1025 }
1026
Jamie Madill977abce2017-11-07 08:03:19 -05001027 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1028 ++arrayElement)
1029 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001030 std::string blockArrayName = interfaceBlock.name;
1031 std::string blockMappedArrayName = interfaceBlock.mappedName;
1032 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001033 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001034 blockArrayName += ArrayString(arrayElement);
1035 blockMappedArrayName += ArrayString(arrayElement);
1036 }
Jamie Madill977abce2017-11-07 08:03:19 -05001037
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001038 // Don't define this block at all if it's not active in the implementation.
1039 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1040 {
1041 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001042 }
1043
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001044 // ESSL 3.10 section 4.4.4 page 58:
1045 // Any uniform or shader storage block declared without a binding qualifier is initially
1046 // assigned to block binding point zero.
1047 int blockBinding =
1048 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001049 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001050 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001051 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001052 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001053
1054 // Since all block elements in an array share the same active interface blocks, they
1055 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1056 // was active, here we will add every block element in the array.
1057 block.dataSize = static_cast<unsigned int>(blockSize);
1058 mBlocksOut->push_back(block);
1059 }
1060}
1061
1062// UniformBlockLinker implementation.
1063UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1064 std::vector<LinkedUniform> *uniformsOut)
1065 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1066{
1067}
1068
1069UniformBlockLinker::~UniformBlockLinker()
1070{
1071}
1072
Olli Etuaho465835d2017-09-26 13:34:10 +03001073void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1074 const std::string &fullName,
1075 const std::string &fullMappedName,
1076 int blockIndex,
1077 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001078 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001079 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001080{
Olli Etuaho465835d2017-09-26 13:34:10 +03001081 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001082 blockIndex, memberInfo);
1083 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001084 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001085
1086 // Since block uniforms have no location, we don't need to store them in the uniform locations
1087 // list.
1088 mUniformsOut->push_back(newUniform);
1089}
1090
1091size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1092{
1093 return mUniformsOut->size();
1094}
1095
Olli Etuaho107c7242018-03-20 15:45:35 +02001096void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001097 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001098 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001099{
Olli Etuaho107c7242018-03-20 15:45:35 +02001100 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001101}
1102
Jamie Madill977abce2017-11-07 08:03:19 -05001103// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001104ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1105 std::vector<BufferVariable> *bufferVariablesOut)
1106 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001107{
1108}
1109
1110ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1111{
1112}
1113
Olli Etuaho465835d2017-09-26 13:34:10 +03001114void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1115 const std::string &fullName,
1116 const std::string &fullMappedName,
1117 int blockIndex,
1118 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001119 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001120 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001121{
Olli Etuaho465835d2017-09-26 13:34:10 +03001122 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001123 blockIndex, memberInfo);
1124 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001125 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001126
1127 newBufferVariable.topLevelArraySize = topLevelArraySize;
1128
1129 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001130}
1131
1132size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1133{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001134 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001135}
1136
Olli Etuaho107c7242018-03-20 15:45:35 +02001137void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001138 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001139 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001140{
Olli Etuaho107c7242018-03-20 15:45:35 +02001141 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001142}
1143
Jiajia Qin94f1e892017-11-20 12:14:32 +08001144// AtomicCounterBufferLinker implementation.
1145AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1146 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1147 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1148{
1149}
1150
1151AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1152{
1153}
1154
1155void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1156{
1157 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1158 {
1159 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1160 ASSERT(bufferSize != sizeMap.end());
1161 atomicCounterBuffer.dataSize = bufferSize->second;
1162 }
1163}
1164
Olli Etuahob78707c2017-03-09 15:03:11 +00001165} // namespace gl