blob: b2c25599901cc0b80f9138ff9c815cb47ad2cd05 [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,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800465 caps.maxComputeTextureImageUnits, 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,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800482 caps.maxVertexTextureImageUnits, 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(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400496 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800497 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000498 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800499 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
500 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800501 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
502 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000503 {
504 return false;
505 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800506
Jiawei Shao385b3e02018-03-21 09:43:28 +0800507 Shader *geometryShader = mState.getAttachedShader(ShaderType::Geometry);
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800508 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
509 if (geometryShader &&
510 !flattenUniformsAndCheckCapsForShader(
511 context, geometryShader, caps.maxGeometryUniformComponents / 4,
512 caps.maxGeometryTextureImageUnits, caps.maxGeometryImageUniforms,
513 caps.maxGeometryAtomicCounters,
514 "Geometry shader active uniforms exceed MAX_GEOMETRY_UNIFORM_VECTORS_EXT (",
515 "Geometry shader sampler count exceeds MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (",
516 "Geometry shader image count exceeds MAX_GEOMETRY_IMAGE_UNIFORMS_EXT (",
517 "Geometry shader atomic counter count exceeds MAX_GEOMETRY_ATOMIC_COUNTERS_EXT (",
518 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
519 {
520 return false;
521 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000522 }
523
524 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800525 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800526 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000527 return true;
528}
529
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800530UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000531 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800532 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800533 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800534 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800535 ShaderType shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000536{
Jamie Madill977abce2017-11-07 08:03:19 -0500537 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800538 ShaderUniformCount shaderUniformCount =
539 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200540 imageUniforms, atomicCounterUniforms, shaderType, uniform.active,
Olli Etuaho44861c42018-03-23 14:36:39 +0200541 uniform.staticUse, uniform.binding, uniform.offset, &location);
Olli Etuaho107c7242018-03-20 15:45:35 +0200542 if (uniform.active)
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 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800546 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000547}
548
Olli Etuaho465835d2017-09-26 13:34:10 +0300549UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
550 const sh::ShaderVariable &uniform,
551 unsigned int arrayNestingIndex,
552 const std::string &namePrefix,
553 const std::string &mappedNamePrefix,
554 std::vector<LinkedUniform> *samplerUniforms,
555 std::vector<LinkedUniform> *imageUniforms,
556 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800557 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200558 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200559 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300560 int binding,
561 int offset,
562 int *location)
563{
564 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
565 // innermost.
566 ShaderUniformCount shaderUniformCount;
567 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
568 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
569 {
570 const std::string elementName = namePrefix + ArrayString(arrayElement);
571 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
572 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
573 {
574 shaderUniformCount += flattenArrayOfStructsUniform(
575 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200576 imageUniforms, atomicCounterUniforms, shaderType, markActive, markStaticUse,
577 binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300578 }
579 else
580 {
581 shaderUniformCount += flattenStructUniform(
582 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
Olli Etuaho44861c42018-03-23 14:36:39 +0200583 atomicCounterUniforms, shaderType, markActive, markStaticUse, binding, offset,
584 location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300585 }
586 }
587 return shaderUniformCount;
588}
589
590UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
591 const std::vector<sh::ShaderVariable> &fields,
592 const std::string &namePrefix,
593 const std::string &mappedNamePrefix,
594 std::vector<LinkedUniform> *samplerUniforms,
595 std::vector<LinkedUniform> *imageUniforms,
596 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800597 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200598 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200599 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300600 int binding,
601 int offset,
602 int *location)
603{
604 ShaderUniformCount shaderUniformCount;
605 for (const sh::ShaderVariable &field : fields)
606 {
607 const std::string &fieldName = namePrefix + "." + field.name;
608 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
609
Olli Etuaho44861c42018-03-23 14:36:39 +0200610 shaderUniformCount += flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms,
611 imageUniforms, atomicCounterUniforms, shaderType,
612 markActive, markStaticUse, -1, -1, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300613 }
614 return shaderUniformCount;
615}
616
617UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
618 const sh::ShaderVariable &uniform,
619 const std::string &namePrefix,
620 const std::string &mappedNamePrefix,
621 std::vector<LinkedUniform> *samplerUniforms,
622 std::vector<LinkedUniform> *imageUniforms,
623 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800624 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200625 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200626 bool markStaticUse,
Olli Etuaho465835d2017-09-26 13:34:10 +0300627 int binding,
628 int offset,
629 int *location)
630{
631 ShaderUniformCount shaderUniformCount;
632
633 ASSERT(uniform.isArray());
634 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
635 ++arrayElement)
636 {
637 sh::ShaderVariable uniformElement = uniform;
638 uniformElement.indexIntoArray(arrayElement);
639 const std::string elementName = namePrefix + ArrayString(arrayElement);
640 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
641
Olli Etuaho44861c42018-03-23 14:36:39 +0200642 shaderUniformCount +=
643 flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
644 imageUniforms, atomicCounterUniforms, shaderType, markActive,
645 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300646 }
647 return shaderUniformCount;
648}
649
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800650UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000651 const sh::ShaderVariable &uniform,
652 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300653 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000654 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800655 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800656 std::vector<LinkedUniform> *atomicCounterUniforms,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800657 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +0200658 bool markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200659 bool markStaticUse,
Olli Etuahob78707c2017-03-09 15:03:11 +0000660 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800661 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000662 int *location)
663{
664 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800665 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000666
667 if (uniform.isStruct())
668 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300669 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000670 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200671 shaderUniformCount +=
672 flattenArrayOfStructsUniform(uniform, 0u, fullName, fullMappedName, samplerUniforms,
673 imageUniforms, atomicCounterUniforms, shaderType,
674 markActive, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000675 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300676 else
677 {
Olli Etuaho44861c42018-03-23 14:36:39 +0200678 shaderUniformCount +=
679 flattenStructUniform(uniform.fields, fullName, fullMappedName, samplerUniforms,
680 imageUniforms, atomicCounterUniforms, shaderType, markActive,
681 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300682 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800683 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000684 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300685 if (uniform.isArrayOfArrays())
686 {
687 // GLES 3.1 November 2016 section 7.3.1 page 77:
688 // "For an active variable declared as an array of an aggregate data type (structures or
689 // arrays), a separate entry will be generated for each active array element"
690 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
Olli Etuaho107c7242018-03-20 15:45:35 +0200691 imageUniforms, atomicCounterUniforms, shaderType, markActive,
Olli Etuaho44861c42018-03-23 14:36:39 +0200692 markStaticUse, binding, offset, location);
Olli Etuaho465835d2017-09-26 13:34:10 +0300693 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000694
695 // Not a struct
696 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800697 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800698 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000699 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
700 if (isSampler)
701 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000702 uniformList = samplerUniforms;
703 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800704 else if (isImage)
705 {
706 uniformList = imageUniforms;
707 }
jchen10eaef1e52017-06-13 10:44:11 +0800708 else if (isAtomicCounter)
709 {
710 uniformList = atomicCounterUniforms;
711 }
Olli Etuahod2551232017-10-26 20:03:33 +0300712
713 std::string fullNameWithArrayIndex(fullName);
714 std::string fullMappedNameWithArrayIndex(fullMappedName);
715
716 if (uniform.isArray())
717 {
718 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
719 // and including [0] at the end of array variable names.
720 fullNameWithArrayIndex += "[0]";
721 fullMappedNameWithArrayIndex += "[0]";
722 }
723
724 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000725 if (existingUniform)
726 {
727 if (binding != -1)
728 {
729 existingUniform->binding = binding;
730 }
jchen10eaef1e52017-06-13 10:44:11 +0800731 if (offset != -1)
732 {
733 existingUniform->offset = offset;
734 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000735 if (*location != -1)
736 {
737 existingUniform->location = *location;
738 }
Olli Etuaho107c7242018-03-20 15:45:35 +0200739 if (markActive)
Olli Etuahob78707c2017-03-09 15:03:11 +0000740 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200741 existingUniform->active = true;
742 existingUniform->setActive(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000743 }
Olli Etuaho44861c42018-03-23 14:36:39 +0200744 if (markStaticUse)
745 {
746 existingUniform->staticUse = true;
747 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000748 }
749 else
750 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300751 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300752 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300753 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000754 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300755 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Olli Etuaho107c7242018-03-20 15:45:35 +0200756 linkedUniform.active = markActive;
Olli Etuaho44861c42018-03-23 14:36:39 +0200757 linkedUniform.staticUse = markStaticUse;
Olli Etuaho465835d2017-09-26 13:34:10 +0300758 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
Olli Etuaho107c7242018-03-20 15:45:35 +0200759 if (markActive)
jchen10baf5d942017-08-28 20:45:48 +0800760 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200761 linkedUniform.setActive(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800762 }
jchen10eaef1e52017-06-13 10:44:11 +0800763
Olli Etuahob78707c2017-03-09 15:03:11 +0000764 uniformList->push_back(linkedUniform);
765 }
766
Olli Etuaho465835d2017-09-26 13:34:10 +0300767 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
768 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000769
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800770 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800771 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800772 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800773 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500774 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500775 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800776 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000777
778 if (*location != -1)
779 {
780 *location += elementCount;
781 }
782
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800783 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000784}
785
jchen10eaef1e52017-06-13 10:44:11 +0800786bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
787{
788 unsigned int atomicCounterCount = 0;
789 for (const auto &uniform : mUniforms)
790 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200791 if (IsAtomicCounterType(uniform.type) && uniform.active)
jchen10eaef1e52017-06-13 10:44:11 +0800792 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300793 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800794 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
795 {
796 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
797 << caps.maxCombinedAtomicCounters << ").";
798 return false;
799 }
800 }
801 }
802 return true;
803}
804
Jamie Madill977abce2017-11-07 08:03:19 -0500805// InterfaceBlockLinker implementation.
806InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
Jiawei Shao016105b2018-04-12 16:38:31 +0800807 : mShaderBlocks({}), mBlocksOut(blocksOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500808{
809}
810
811InterfaceBlockLinker::~InterfaceBlockLinker()
812{
813}
814
Jiawei Shao016105b2018-04-12 16:38:31 +0800815void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
Jamie Madill977abce2017-11-07 08:03:19 -0500816 const std::vector<sh::InterfaceBlock> *blocks)
817{
Jiawei Shao016105b2018-04-12 16:38:31 +0800818 mShaderBlocks[shaderType] = blocks;
Jamie Madill977abce2017-11-07 08:03:19 -0500819}
820
821void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
822 const GetBlockMemberInfo &getMemberInfo) const
823{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500824 ASSERT(mBlocksOut->empty());
825
Jamie Madill977abce2017-11-07 08:03:19 -0500826 std::set<std::string> visitedList;
827
Jiawei Shao016105b2018-04-12 16:38:31 +0800828 for (ShaderType shaderType : AllShaderTypes())
Jamie Madill977abce2017-11-07 08:03:19 -0500829 {
Jiawei Shao016105b2018-04-12 16:38:31 +0800830 if (!mShaderBlocks[shaderType])
831 {
832 continue;
833 }
Jamie Madill977abce2017-11-07 08:03:19 -0500834
Jiawei Shao016105b2018-04-12 16:38:31 +0800835 for (const auto &block : *mShaderBlocks[shaderType])
Jamie Madill977abce2017-11-07 08:03:19 -0500836 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800837 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500838 continue;
839
840 if (visitedList.count(block.name) > 0)
841 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200842 if (block.active)
Jamie Madill977abce2017-11-07 08:03:19 -0500843 {
844 for (InterfaceBlock &priorBlock : *mBlocksOut)
845 {
846 if (block.name == priorBlock.name)
847 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200848 priorBlock.setActive(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800849 // Update the block members static use.
850 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
851 block.fieldMappedPrefix(), -1,
852 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
853 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500854 }
855 }
856 }
857 }
858 else
859 {
860 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
861 visitedList.insert(block.name);
862 }
863 }
864 }
865}
866
867template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300868void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
869 const VarT &field,
870 unsigned int arrayNestingIndex,
871 const std::string &prefix,
872 const std::string &mappedPrefix,
873 int blockIndex,
874 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800875 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800876 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300877{
878 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
879 // innermost.
880 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
881 if (singleEntryForTopLevelArray)
882 {
883 entryGenerationArraySize = 1;
884 }
885 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
886 {
887 const std::string elementName = prefix + ArrayString(arrayElement);
888 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
889 if (arrayNestingIndex + 1u < field.arraySizes.size())
890 {
891 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
892 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800893 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300894 }
895 else
896 {
897 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800898 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300899 }
900 }
901}
902
903template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500904void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
905 const std::vector<VarT> &fields,
906 const std::string &prefix,
907 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800908 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300909 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800910 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800911 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500912{
913 for (const VarT &field : fields)
914 {
915 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500916 std::string fullMappedName =
917 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
918
Olli Etuaho465835d2017-09-26 13:34:10 +0300919 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800920 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300921 }
922}
923
924template <typename VarT>
925void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
926 const VarT &field,
927 const std::string &fullName,
928 const std::string &fullMappedName,
929 int blockIndex,
930 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800931 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +0800932 ShaderType shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300933{
934 int nextArraySize = topLevelArraySize;
935 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
936 singleEntryForTopLevelArray)
937 {
938 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
939 // member declared as an array of an aggregate type, an entry will be generated only
940 // for the first array element, regardless of its type.'
941 nextArraySize = field.getOutermostArraySize();
942 }
943
944 if (field.isStruct())
945 {
946 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500947 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300948 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800949 blockIndex, singleEntryForTopLevelArray, nextArraySize,
950 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500951 }
952 else
953 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300954 ASSERT(nextArraySize == topLevelArraySize);
955 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800956 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500957 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300958 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500959 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300960 if (field.isArrayOfArrays())
961 {
962 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
963 if (singleEntryForTopLevelArray)
964 {
965 entryGenerationArraySize = 1u;
966 }
967 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
968 ++arrayElement)
969 {
970 VarT fieldElement = field;
971 fieldElement.indexIntoArray(arrayElement);
972 const std::string elementName = fullName + ArrayString(arrayElement);
973 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
974
975 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800976 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300977 }
978 return;
979 }
980
Olli Etuaho465835d2017-09-26 13:34:10 +0300981 std::string fullNameWithArrayIndex = fullName;
982 std::string fullMappedNameWithArrayIndex = fullMappedName;
983
984 if (field.isArray())
985 {
986 fullNameWithArrayIndex += "[0]";
987 fullMappedNameWithArrayIndex += "[0]";
988 }
989
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800990 if (blockIndex == -1)
991 {
Olli Etuaho107c7242018-03-20 15:45:35 +0200992 updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800993 }
994 else
995 {
996 // If getBlockMemberInfo returns false, the variable is optimized out.
997 sh::BlockMemberInfo memberInfo;
998 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
999 {
1000 return;
1001 }
1002
1003 ASSERT(nextArraySize == topLevelArraySize);
1004 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
1005 blockIndex, memberInfo, nextArraySize, shaderType);
1006 }
Jamie Madill977abce2017-11-07 08:03:19 -05001007}
1008
1009void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
1010 const GetBlockMemberInfo &getMemberInfo,
1011 const sh::InterfaceBlock &interfaceBlock,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001012 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001013{
1014 size_t blockSize = 0;
1015 std::vector<unsigned int> blockIndexes;
1016
1017 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001018 // Track the first and last block member index to determine the range of active block members in
1019 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001020 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1021 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001022 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001023 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001024 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1025
1026 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1027 ++blockMemberIndex)
1028 {
1029 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1030 }
1031
Jamie Madill977abce2017-11-07 08:03:19 -05001032 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1033 ++arrayElement)
1034 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001035 std::string blockArrayName = interfaceBlock.name;
1036 std::string blockMappedArrayName = interfaceBlock.mappedName;
1037 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001038 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001039 blockArrayName += ArrayString(arrayElement);
1040 blockMappedArrayName += ArrayString(arrayElement);
1041 }
Jamie Madill977abce2017-11-07 08:03:19 -05001042
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001043 // Don't define this block at all if it's not active in the implementation.
1044 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1045 {
1046 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001047 }
1048
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001049 // ESSL 3.10 section 4.4.4 page 58:
1050 // Any uniform or shader storage block declared without a binding qualifier is initially
1051 // assigned to block binding point zero.
1052 int blockBinding =
1053 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001054 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001055 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001056 block.memberIndexes = blockIndexes;
Olli Etuaho107c7242018-03-20 15:45:35 +02001057 block.setActive(shaderType, interfaceBlock.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001058
1059 // Since all block elements in an array share the same active interface blocks, they
1060 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1061 // was active, here we will add every block element in the array.
1062 block.dataSize = static_cast<unsigned int>(blockSize);
1063 mBlocksOut->push_back(block);
1064 }
1065}
1066
1067// UniformBlockLinker implementation.
1068UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1069 std::vector<LinkedUniform> *uniformsOut)
1070 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1071{
1072}
1073
1074UniformBlockLinker::~UniformBlockLinker()
1075{
1076}
1077
Olli Etuaho465835d2017-09-26 13:34:10 +03001078void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1079 const std::string &fullName,
1080 const std::string &fullMappedName,
1081 int blockIndex,
1082 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001083 int /*topLevelArraySize*/,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001084 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001085{
Olli Etuaho465835d2017-09-26 13:34:10 +03001086 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001087 blockIndex, memberInfo);
1088 newUniform.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001089 newUniform.setActive(shaderType, field.active);
Jamie Madill977abce2017-11-07 08:03:19 -05001090
1091 // Since block uniforms have no location, we don't need to store them in the uniform locations
1092 // list.
1093 mUniformsOut->push_back(newUniform);
1094}
1095
1096size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1097{
1098 return mUniformsOut->size();
1099}
1100
Olli Etuaho107c7242018-03-20 15:45:35 +02001101void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001102 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001103 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001104{
Olli Etuaho107c7242018-03-20 15:45:35 +02001105 SetActive(mUniformsOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001106}
1107
Jamie Madill977abce2017-11-07 08:03:19 -05001108// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001109ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1110 std::vector<BufferVariable> *bufferVariablesOut)
1111 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001112{
1113}
1114
1115ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1116{
1117}
1118
Olli Etuaho465835d2017-09-26 13:34:10 +03001119void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1120 const std::string &fullName,
1121 const std::string &fullMappedName,
1122 int blockIndex,
1123 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001124 int topLevelArraySize,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001125 ShaderType shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001126{
Olli Etuaho465835d2017-09-26 13:34:10 +03001127 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001128 blockIndex, memberInfo);
1129 newBufferVariable.mappedName = fullMappedName;
Olli Etuaho107c7242018-03-20 15:45:35 +02001130 newBufferVariable.setActive(shaderType, field.active);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001131
1132 newBufferVariable.topLevelArraySize = topLevelArraySize;
1133
1134 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001135}
1136
1137size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1138{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001139 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001140}
1141
Olli Etuaho107c7242018-03-20 15:45:35 +02001142void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
Jiawei Shao385b3e02018-03-21 09:43:28 +08001143 ShaderType shaderType,
Olli Etuaho107c7242018-03-20 15:45:35 +02001144 bool active) const
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001145{
Olli Etuaho107c7242018-03-20 15:45:35 +02001146 SetActive(mBufferVariablesOut, fullName, shaderType, active);
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001147}
1148
Jiajia Qin94f1e892017-11-20 12:14:32 +08001149// AtomicCounterBufferLinker implementation.
1150AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1151 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1152 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1153{
1154}
1155
1156AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1157{
1158}
1159
1160void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1161{
1162 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1163 {
1164 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1165 ASSERT(bufferSize != sizeMap.end());
1166 atomicCounterBuffer.dataSize = bufferSize->second;
1167 }
1168}
1169
Olli Etuahob78707c2017-03-09 15:03:11 +00001170} // namespace gl