blob: 375546e89944fb62e653f978d796d59585e297e3 [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;
Olli Etuahob78707c2017-03-09 15:03:11 +0000191
Jiawei Shao016105b2018-04-12 16:38:31 +0800192 for (ShaderType shaderType : kAllGraphicsShaderTypes)
Olli Etuahob78707c2017-03-09 15:03:11 +0000193 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800194 Shader *currentShader = mState.getAttachedShader(shaderType);
195 if (currentShader)
Olli Etuahob78707c2017-03-09 15:03:11 +0000196 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800197 if (shaderType == ShaderType::Vertex)
198 {
199 for (const sh::Uniform &vertexUniform : currentShader->getUniforms(context))
200 {
201 linkedUniforms[vertexUniform.name] =
202 std::make_pair(ShaderType::Vertex, &vertexUniform);
203 }
204 }
205 else
206 {
207 bool isLastShader = (shaderType == ShaderType::Fragment);
208 if (!ValidateGraphicsUniformsPerShader(context, currentShader, !isLastShader,
209 &linkedUniforms, infoLog))
210 {
211 return false;
212 }
213 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000214 }
215 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800216
Olli Etuahob78707c2017-03-09 15:03:11 +0000217 return true;
218}
219
Jamie Madill3c1da042017-11-27 18:33:40 -0500220bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000221{
Olli Etuahob78707c2017-03-09 15:03:11 +0000222 // Locations which have been allocated for an unused uniform.
223 std::set<GLuint> ignoredLocations;
224
225 int maxUniformLocation = -1;
226
227 // Gather uniform locations that have been set either using the bindUniformLocation API or by
228 // using a location layout qualifier and check conflicts between them.
229 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
Olli Etuaho44861c42018-03-23 14:36:39 +0200230 &ignoredLocations, &maxUniformLocation))
Olli Etuahob78707c2017-03-09 15:03:11 +0000231 {
232 return false;
233 }
234
235 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
236 // the line relies on only having statically used uniforms in mUniforms.
237 pruneUnusedUniforms();
238
239 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
240 std::vector<VariableLocation> unlocatedUniforms;
241 std::map<GLuint, VariableLocation> preLocatedUniforms;
242
243 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
244 {
245 const LinkedUniform &uniform = mUniforms[uniformIndex];
246
jchen10baf5d942017-08-28 20:45:48 +0800247 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000248 {
249 continue;
250 }
251
Olli Etuahod2551232017-10-26 20:03:33 +0300252 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000253 int shaderLocation = uniform.location;
254
255 if (shaderLocation != -1)
256 {
257 preSetLocation = shaderLocation;
258 }
259
Olli Etuaho465835d2017-09-26 13:34:10 +0300260 unsigned int elementCount = uniform.getBasicTypeElementCount();
261 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000262 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400263 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000264
265 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
266 {
267 int elementLocation = preSetLocation + arrayIndex;
268 preLocatedUniforms[elementLocation] = location;
269 }
270 else
271 {
272 unlocatedUniforms.push_back(location);
273 }
274 }
275 }
276
277 // Make enough space for all uniforms, with pre-set locations or not.
278 mUniformLocations.resize(
279 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
280 static_cast<size_t>(maxUniformLocation + 1)));
281
282 // Assign uniforms with pre-set locations
283 for (const auto &uniform : preLocatedUniforms)
284 {
285 mUniformLocations[uniform.first] = uniform.second;
286 }
287
288 // Assign ignored uniforms
289 for (const auto &ignoredLocation : ignoredLocations)
290 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400291 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000292 }
293
294 // Automatically assign locations for the rest of the uniforms
295 size_t nextUniformLocation = 0;
296 for (const auto &unlocatedUniform : unlocatedUniforms)
297 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400298 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000299 mUniformLocations[nextUniformLocation].ignored)
300 {
301 nextUniformLocation++;
302 }
303
304 ASSERT(nextUniformLocation < mUniformLocations.size());
305 mUniformLocations[nextUniformLocation] = unlocatedUniform;
306 nextUniformLocation++;
307 }
308
309 return true;
310}
311
312bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
313 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500314 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000315 std::set<GLuint> *ignoredLocations,
316 int *maxUniformLocation)
317{
Olli Etuaho44861c42018-03-23 14:36:39 +0200318 // All the locations where another uniform can't be located.
319 std::set<GLuint> reservedLocations;
320
Olli Etuahob78707c2017-03-09 15:03:11 +0000321 for (const LinkedUniform &uniform : mUniforms)
322 {
323 if (uniform.isBuiltIn())
324 {
325 continue;
326 }
327
Olli Etuahod2551232017-10-26 20:03:33 +0300328 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000329 int shaderLocation = uniform.location;
330
331 if (shaderLocation != -1)
332 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300333 unsigned int elementCount = uniform.getBasicTypeElementCount();
334
335 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000336 {
337 // GLSL ES 3.10 section 4.4.3
338 int elementLocation = shaderLocation + arrayIndex;
339 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200340 if (reservedLocations.find(elementLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000341 {
342 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
343 return false;
344 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200345 reservedLocations.insert(elementLocation);
Olli Etuaho107c7242018-03-20 15:45:35 +0200346 if (!uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000347 {
348 ignoredLocations->insert(elementLocation);
349 }
350 }
351 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200352 else if (apiBoundLocation != -1 && uniform.staticUse)
Olli Etuahob78707c2017-03-09 15:03:11 +0000353 {
354 // Only the first location is reserved even if the uniform is an array.
355 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
Olli Etuaho44861c42018-03-23 14:36:39 +0200356 if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000357 {
358 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
359 return false;
360 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200361 reservedLocations.insert(apiBoundLocation);
362 if (!uniform.active)
363 {
364 ignoredLocations->insert(apiBoundLocation);
365 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000366 }
367 }
368
369 // Record the uniform locations that were bound using the API for uniforms that were not found
370 // from the shader. Other uniforms should not be assigned to those locations.
371 for (const auto &locationBinding : uniformLocationBindings)
372 {
373 GLuint location = locationBinding.second;
Olli Etuaho44861c42018-03-23 14:36:39 +0200374 if (reservedLocations.find(location) == reservedLocations.end())
Olli Etuahob78707c2017-03-09 15:03:11 +0000375 {
376 ignoredLocations->insert(location);
377 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
378 }
379 }
380
381 return true;
382}
383
384void UniformLinker::pruneUnusedUniforms()
385{
386 auto uniformIter = mUniforms.begin();
387 while (uniformIter != mUniforms.end())
388 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200389 if (uniformIter->active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000390 {
391 ++uniformIter;
392 }
393 else
394 {
395 uniformIter = mUniforms.erase(uniformIter);
396 }
397 }
398}
399
400bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400401 const Context *context,
402 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000403 GLuint maxUniformComponents,
404 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800405 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800406 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000407 const std::string &componentsErrorMessage,
408 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800409 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800410 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000411 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800412 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800413 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000414 InfoLog &infoLog)
415{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800416 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400417 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000418 {
jchen10baf5d942017-08-28 20:45:48 +0800419 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
420 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000421 }
422
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800423 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000424 {
425 infoLog << componentsErrorMessage << maxUniformComponents << ").";
426 return false;
427 }
428
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800429 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000430 {
431 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
432 return false;
433 }
434
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800435 if (shaderUniformCount.imageCount > maxImageUnits)
436 {
437 infoLog << imageErrorMessage << maxImageUnits << ").";
438 return false;
439 }
440
jchen10eaef1e52017-06-13 10:44:11 +0800441 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
442 {
443 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
444 return false;
445 }
446
Olli Etuahob78707c2017-03-09 15:03:11 +0000447 return true;
448}
449
Jamie Madillbd044ed2017-06-05 12:59:21 -0400450bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000451{
452 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800453 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800454 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000455
Jamie Madillbd044ed2017-06-05 12:59:21 -0400456 const Caps &caps = context->getCaps();
457
Jiawei Shao385b3e02018-03-21 09:43:28 +0800458 if (mState.getAttachedShader(ShaderType::Compute))
Olli Etuahob78707c2017-03-09 15:03:11 +0000459 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800460 Shader *computeShader = mState.getAttachedShader(ShaderType::Compute);
Olli Etuahob78707c2017-03-09 15:03:11 +0000461
462 // TODO (mradev): check whether we need finer-grained component counting
463 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400464 context, computeShader, caps.maxComputeUniformComponents / 4,
Jiawei Shao54aafe52018-04-27 14:54:57 +0800465 caps.maxShaderTextureImageUnits[ShaderType::Compute], caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800466 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000467 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
468 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800469 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
470 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
471 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000472 {
473 return false;
474 }
475 }
476 else
477 {
Jiawei Shao385b3e02018-03-21 09:43:28 +0800478 Shader *vertexShader = mState.getAttachedShader(ShaderType::Vertex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000479
480 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400481 context, vertexShader, caps.maxVertexUniformVectors,
Jiawei Shao54aafe52018-04-27 14:54:57 +0800482 caps.maxShaderTextureImageUnits[ShaderType::Vertex], caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800483 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000484 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
485 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800486 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
487 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
488 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000489 {
490 return false;
491 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400492
Jiawei Shao385b3e02018-03-21 09:43:28 +0800493 Shader *fragmentShader = mState.getAttachedShader(ShaderType::Fragment);
Olli Etuahob78707c2017-03-09 15:03:11 +0000494
495 if (!flattenUniformsAndCheckCapsForShader(
Jiawei Shao54aafe52018-04-27 14:54:57 +0800496 context, fragmentShader, caps.maxFragmentUniformVectors,
497 caps.maxShaderTextureImageUnits[ShaderType::Fragment],
jchen10eaef1e52017-06-13 10:44:11 +0800498 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000499 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800500 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
501 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800502 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
503 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000504 {
505 return false;
506 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800507
Jiawei Shao385b3e02018-03-21 09:43:28 +0800508 Shader *geometryShader = mState.getAttachedShader(ShaderType::Geometry);
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800509 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
510 if (geometryShader &&
511 !flattenUniformsAndCheckCapsForShader(
512 context, geometryShader, caps.maxGeometryUniformComponents / 4,
Jiawei Shao54aafe52018-04-27 14:54:57 +0800513 caps.maxShaderTextureImageUnits[ShaderType::Geometry],
514 caps.maxGeometryImageUniforms, caps.maxGeometryAtomicCounters,
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800515 "Geometry shader active uniforms exceed MAX_GEOMETRY_UNIFORM_VECTORS_EXT (",
516 "Geometry shader sampler count exceeds MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (",
517 "Geometry shader image count exceeds MAX_GEOMETRY_IMAGE_UNIFORMS_EXT (",
518 "Geometry shader atomic counter count exceeds MAX_GEOMETRY_ATOMIC_COUNTERS_EXT (",
519 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
520 {
521 return false;
522 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000523 }
524
525 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800526 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800527 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000528 return true;
529}
530
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800531UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000532 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800533 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800534 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800535 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800536 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000537{
Jamie Madill977abce2017-11-07 08:03:19 -0500538 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800539 ShaderUniformCount shaderUniformCount =
540 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200541 imageUniforms, atomicCounterUniforms, shaderType, uniform.active,
Olli Etuaho44861c42018-03-23 14:36:39 +0200542 uniform.staticUse, uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200543 if (uniform.active)
Olli Etuahob78707c2017-03-09 15:03:11 +0000544 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800545 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000546 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800547 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000548}
549
Olli Etuaho465835d2017-09-26 13:34:10 +0300550UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
551 const sh::ShaderVariable &uniform,
552 unsigned int arrayNestingIndex,
553 const std::string &namePrefix,
554 const std::string &mappedNamePrefix,
555 std::vector<LinkedUniform> *samplerUniforms,
556 std::vector<LinkedUniform> *imageUniforms,
557 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800558 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200559 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200560 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300561 int binding,
562 int offset,
563 int *location)
564{
565 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
566 // innermost.
567 ShaderUniformCount shaderUniformCount;
568 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
569 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
570 {
571 const std::string elementName = namePrefix + ArrayString(arrayElement);
572 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
573 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
574 {
575 shaderUniformCount += flattenArrayOfStructsUniform(
576 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200577 imageUniforms, atomicCounterUniforms, shaderType, markActive, markStaticUse,
578 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300579 }
580 else
581 {
582 shaderUniformCount += flattenStructUniform(
583 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200584 atomicCounterUniforms, shaderType, markActive, markStaticUse, binding, offset,
585 location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300586 }
587 }
588 return shaderUniformCount;
589}
590
591UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
592 const std::vector<sh::ShaderVariable> &fields,
593 const std::string &namePrefix,
594 const std::string &mappedNamePrefix,
595 std::vector<LinkedUniform> *samplerUniforms,
596 std::vector<LinkedUniform> *imageUniforms,
597 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800598 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200599 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200600 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300601 int binding,
602 int offset,
603 int *location)
604{
605 ShaderUniformCount shaderUniformCount;
606 for (const sh::ShaderVariable &field : fields)
607 {
608 const std::string &fieldName = namePrefix + "." + field.name;
609 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
610
Olli Etuaho44861c42018-03-23 14:36:39 +0200611 shaderUniformCount += flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms,
612 imageUniforms, atomicCounterUniforms, shaderType,
613 markActive, markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300614 }
615 return shaderUniformCount;
616}
617
618UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
619 const sh::ShaderVariable &uniform,
620 const std::string &namePrefix,
621 const std::string &mappedNamePrefix,
622 std::vector<LinkedUniform> *samplerUniforms,
623 std::vector<LinkedUniform> *imageUniforms,
624 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800625 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200626 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200627 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300628 int binding,
629 int offset,
630 int *location)
631{
632 ShaderUniformCount shaderUniformCount;
633
634 ASSERT(uniform.isArray());
635 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
636 ++arrayElement)
637 {
638 sh::ShaderVariable uniformElement = uniform;
639 uniformElement.indexIntoArray(arrayElement);
640 const std::string elementName = namePrefix + ArrayString(arrayElement);
641 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
642
Olli Etuaho44861c42018-03-23 14:36:39 +0200643 shaderUniformCount +=
644 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
645 imageUniforms, atomicCounterUniforms, shaderType, markActive,
646 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300647 }
648 return shaderUniformCount;
649}
650
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800651UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000652 const sh::ShaderVariable &uniform,
653 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300654 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000655 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800656 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800657 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800658 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200659 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200660 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000661 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800662 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000663 int *location)
664{
665 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800666 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000667
668 if (uniform.isStruct())
669 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300670 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000671 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200672 shaderUniformCount +=
673 flattenArrayOfStructsUniform(uniform, 0u, fullName, fullMappedName, samplerUniforms,
674 imageUniforms, atomicCounterUniforms, shaderType,
675 markActive, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000676 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300677 else
678 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200679 shaderUniformCount +=
680 flattenStructUniform(uniform.fields, fullName, fullMappedName, samplerUniforms,
681 imageUniforms, atomicCounterUniforms, shaderType, markActive,
682 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300683 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800684 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000685 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300686 if (uniform.isArrayOfArrays())
687 {
688 // GLES 3.1 November 2016 section 7.3.1 page 77:
689 // "For an active variable declared as an array of an aggregate data type (structures or
690 // arrays), a separate entry will be generated for each active array element"
691 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200692 imageUniforms, atomicCounterUniforms, shaderType, markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200693 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300694 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000695
696 // Not a struct
697 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800698 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800699 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000700 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
701 if (isSampler)
702 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000703 uniformList = samplerUniforms;
704 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800705 else if (isImage)
706 {
707 uniformList = imageUniforms;
708 }
jchen10eaef1e52017-06-13 10:44:11 +0800709 else if (isAtomicCounter)
710 {
711 uniformList = atomicCounterUniforms;
712 }
Olli Etuahod2551232017-10-26 20:03:33 +0300713
714 std::string fullNameWithArrayIndex(fullName);
715 std::string fullMappedNameWithArrayIndex(fullMappedName);
716
717 if (uniform.isArray())
718 {
719 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
720 // and including [0] at the end of array variable names.
721 fullNameWithArrayIndex += "[0]";
722 fullMappedNameWithArrayIndex += "[0]";
723 }
724
725 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000726 if (existingUniform)
727 {
728 if (binding != -1)
729 {
730 existingUniform->binding = binding;
731 }
jchen10eaef1e52017-06-13 10:44:11 +0800732 if (offset != -1)
733 {
734 existingUniform->offset = offset;
735 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000736 if (*location != -1)
737 {
738 existingUniform->location = *location;
739 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200740 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000741 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200742 existingUniform->active = true;
743 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000744 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200745 if (markStaticUse)
746 {
747 existingUniform->staticUse = true;
748 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000749 }
750 else
751 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300752 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300753 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300754 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000755 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300756 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200757 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200758 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300759 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200760 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800761 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200762 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800763 }
jchen10eaef1e52017-06-13 10:44:11 +0800764
Olli Etuahob78707c2017-03-09 15:03:11 +0000765 uniformList->push_back(linkedUniform);
766 }
767
Olli Etuaho465835d2017-09-26 13:34:10 +0300768 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
769 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000770
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800771 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800772 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800773 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800774 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500775 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500776 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800777 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000778
779 if (*location != -1)
780 {
781 *location += elementCount;
782 }
783
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800784 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000785}
786
jchen10eaef1e52017-06-13 10:44:11 +0800787bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
788{
789 unsigned int atomicCounterCount = 0;
790 for (const auto &uniform : mUniforms)
791 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200792 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800793 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300794 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800795 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
796 {
797 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
798 << caps.maxCombinedAtomicCounters << ").";
799 return false;
800 }
801 }
802 }
803 return true;
804}
805
Jamie Madill977abce2017-11-07 08:03:19 -0500806// InterfaceBlockLinker implementation.
807InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
Jiawei Shao016105b2018-04-12 16:38:31 +0800808 : mShaderBlocks({}), mBlocksOut(blocksOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500809{
810}
811
812InterfaceBlockLinker::~InterfaceBlockLinker()
813{
814}
815
Jiawei Shao016105b2018-04-12 16:38:31 +0800816void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
Jamie Madill977abce2017-11-07 08:03:19 -0500817 const std::vector<sh::InterfaceBlock> *blocks)
818{
Jiawei Shao016105b2018-04-12 16:38:31 +0800819 mShaderBlocks[shaderType] = blocks;
Jamie Madill977abce2017-11-07 08:03:19 -0500820}
821
822void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
823 const GetBlockMemberInfo &getMemberInfo) const
824{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500825 ASSERT(mBlocksOut->empty());
826
Jamie Madill977abce2017-11-07 08:03:19 -0500827 std::set<std::string> visitedList;
828
Jiawei Shao016105b2018-04-12 16:38:31 +0800829 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill977abce2017-11-07 08:03:19 -0500830 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800831 if (!mShaderBlocks[shaderType])
832 {
833 continue;
834 }
Jamie Madill977abce2017-11-07 08:03:19 -0500835
Jiawei Shao016105b2018-04-12 16:38:31 +0800836 for (const auto &block : *mShaderBlocks[shaderType])
Jamie Madill977abce2017-11-07 08:03:19 -0500837 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800838 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500839 continue;
840
841 if (visitedList.count(block.name) > 0)
842 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200843 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500844 {
845 for (InterfaceBlock &priorBlock : *mBlocksOut)
846 {
847 if (block.name == priorBlock.name)
848 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200849 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800850 // Update the block members static use.
851 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
852 block.fieldMappedPrefix(), -1,
853 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
854 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500855 }
856 }
857 }
858 }
859 else
860 {
861 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
862 visitedList.insert(block.name);
863 }
864 }
865 }
866}
867
868template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300869void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
870 const VarT &field,
871 unsigned int arrayNestingIndex,
872 const std::string &prefix,
873 const std::string &mappedPrefix,
874 int blockIndex,
875 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800876 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800877 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300878{
879 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
880 // innermost.
881 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
882 if (singleEntryForTopLevelArray)
883 {
884 entryGenerationArraySize = 1;
885 }
886 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
887 {
888 const std::string elementName = prefix + ArrayString(arrayElement);
889 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
890 if (arrayNestingIndex + 1u < field.arraySizes.size())
891 {
892 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
893 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800894 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300895 }
896 else
897 {
898 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800899 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300900 }
901 }
902}
903
904template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500905void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
906 const std::vector<VarT> &fields,
907 const std::string &prefix,
908 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800909 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300910 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800911 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800912 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500913{
914 for (const VarT &field : fields)
915 {
916 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500917 std::string fullMappedName =
918 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
919
Olli Etuaho465835d2017-09-26 13:34:10 +0300920 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800921 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300922 }
923}
924
925template <typename VarT>
926void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
927 const VarT &field,
928 const std::string &fullName,
929 const std::string &fullMappedName,
930 int blockIndex,
931 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800932 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800933 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300934{
935 int nextArraySize = topLevelArraySize;
936 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
937 singleEntryForTopLevelArray)
938 {
939 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
940 // member declared as an array of an aggregate type, an entry will be generated only
941 // for the first array element, regardless of its type.'
942 nextArraySize = field.getOutermostArraySize();
943 }
944
945 if (field.isStruct())
946 {
947 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500948 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300949 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800950 blockIndex, singleEntryForTopLevelArray, nextArraySize,
951 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500952 }
953 else
954 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300955 ASSERT(nextArraySize == topLevelArraySize);
956 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800957 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500958 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300959 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500960 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300961 if (field.isArrayOfArrays())
962 {
963 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
964 if (singleEntryForTopLevelArray)
965 {
966 entryGenerationArraySize = 1u;
967 }
968 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
969 ++arrayElement)
970 {
971 VarT fieldElement = field;
972 fieldElement.indexIntoArray(arrayElement);
973 const std::string elementName = fullName + ArrayString(arrayElement);
974 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
975
976 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800977 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300978 }
979 return;
980 }
981
Olli Etuaho465835d2017-09-26 13:34:10 +0300982 std::string fullNameWithArrayIndex = fullName;
983 std::string fullMappedNameWithArrayIndex = fullMappedName;
984
985 if (field.isArray())
986 {
987 fullNameWithArrayIndex += "[0]";
988 fullMappedNameWithArrayIndex += "[0]";
989 }
990
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800991 if (blockIndex == -1)
992 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200993 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800994 }
995 else
996 {
997 // If getBlockMemberInfo returns false, the variable is optimized out.
998 sh::BlockMemberInfo memberInfo;
999 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
1000 {
1001 return;
1002 }
1003
1004 ASSERT(nextArraySize == topLevelArraySize);
1005 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1006 blockIndex, memberInfo, nextArraySize, shaderType);
1007 }
Jamie Madill977abce2017-11-07 08:03:19 -05001008}
1009
1010void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1011 const GetBlockMemberInfo &getMemberInfo,
1012 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001013 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001014{
1015 size_t blockSize = 0;
1016 std::vector<unsigned int> blockIndexes;
1017
1018 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001019 // Track the first and last block member index to determine the range of active block members in
1020 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001021 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1022 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001023 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001024 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001025 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1026
1027 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1028 ++blockMemberIndex)
1029 {
1030 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1031 }
1032
Jamie Madill977abce2017-11-07 08:03:19 -05001033 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1034 ++arrayElement)
1035 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001036 std::string blockArrayName = interfaceBlock.name;
1037 std::string blockMappedArrayName = interfaceBlock.mappedName;
1038 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001039 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001040 blockArrayName += ArrayString(arrayElement);
1041 blockMappedArrayName += ArrayString(arrayElement);
1042 }
Jamie Madill977abce2017-11-07 08:03:19 -05001043
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001044 // Don't define this block at all if it's not active in the implementation.
1045 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1046 {
1047 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001048 }
1049
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001050 // ESSL 3.10 section 4.4.4 page 58:
1051 // Any uniform or shader storage block declared without a binding qualifier is initially
1052 // assigned to block binding point zero.
1053 int blockBinding =
1054 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001055 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001056 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001057 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001058 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001059
1060 // Since all block elements in an array share the same active interface blocks, they
1061 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1062 // was active, here we will add every block element in the array.
1063 block.dataSize = static_cast<unsigned int>(blockSize);
1064 mBlocksOut->push_back(block);
1065 }
1066}
1067
1068// UniformBlockLinker implementation.
1069UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1070 std::vector<LinkedUniform> *uniformsOut)
1071 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1072{
1073}
1074
1075UniformBlockLinker::~UniformBlockLinker()
1076{
1077}
1078
Olli Etuaho465835d2017-09-26 13:34:10 +03001079void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1080 const std::string &fullName,
1081 const std::string &fullMappedName,
1082 int blockIndex,
1083 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001084 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001085 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001086{
Olli Etuaho465835d2017-09-26 13:34:10 +03001087 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001088 blockIndex, memberInfo);
1089 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001090 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001091
1092 // Since block uniforms have no location, we don't need to store them in the uniform locations
1093 // list.
1094 mUniformsOut->push_back(newUniform);
1095}
1096
1097size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1098{
1099 return mUniformsOut->size();
1100}
1101
Olli Etuaho107c7242018-03-20 15:45:35 +02001102void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001103 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001104 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001105{
Olli Etuaho107c7242018-03-20 15:45:35 +02001106 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001107}
1108
Jamie Madill977abce2017-11-07 08:03:19 -05001109// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001110ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1111 std::vector<BufferVariable> *bufferVariablesOut)
1112 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001113{
1114}
1115
1116ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1117{
1118}
1119
Olli Etuaho465835d2017-09-26 13:34:10 +03001120void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1121 const std::string &fullName,
1122 const std::string &fullMappedName,
1123 int blockIndex,
1124 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001125 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001126 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001127{
Olli Etuaho465835d2017-09-26 13:34:10 +03001128 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001129 blockIndex, memberInfo);
1130 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001131 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001132
1133 newBufferVariable.topLevelArraySize = topLevelArraySize;
1134
1135 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001136}
1137
1138size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1139{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001140 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001141}
1142
Olli Etuaho107c7242018-03-20 15:45:35 +02001143void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001144 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001145 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001146{
Olli Etuaho107c7242018-03-20 15:45:35 +02001147 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001148}
1149
Jiajia Qin94f1e892017-11-20 12:14:32 +08001150// AtomicCounterBufferLinker implementation.
1151AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1152 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1153 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1154{
1155}
1156
1157AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1158{
1159}
1160
1161void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1162{
1163 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1164 {
1165 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1166 ASSERT(bufferSize != sizeMap.end());
1167 atomicCounterBuffer.dataSize = bufferSize->second;
1168 }
1169}
1170
Olli Etuahob78707c2017-03-09 15:03:11 +00001171} // namespace gl