blob: 77940b0f0e631abdeff90bb20415f0a83728a75a [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>
52void SetStaticUse(std::vector<VarT> *list,
53 const std::string &name,
54 GLenum shaderType,
55 bool staticUse)
56{
57 for (auto &variable : *list)
58 {
59 if (variable.name == name)
60 {
61 variable.setStaticUse(shaderType, staticUse);
62 return;
63 }
64 }
65}
66
Jiawei Shao0d88ec92018-02-27 16:25:31 +080067// GLSL ES Spec 3.00.3, section 4.3.5.
68LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
69 const sh::Uniform &uniform2,
70 std::string *mismatchedStructFieldName)
71{
72#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
73 const bool validatePrecision = true;
74#else
75 const bool validatePrecision = false;
76#endif
77
78 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
79 uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
80 if (linkError != LinkMismatchError::NO_MISMATCH)
81 {
82 return linkError;
83 }
84
85 // GLSL ES Spec 3.10.4, section 4.4.5.
86 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
87 {
88 return LinkMismatchError::BINDING_MISMATCH;
89 }
90
91 // GLSL ES Spec 3.10.4, section 9.2.1.
92 if (uniform1.location != -1 && uniform2.location != -1 &&
93 uniform1.location != uniform2.location)
94 {
95 return LinkMismatchError::LOCATION_MISMATCH;
96 }
97 if (uniform1.offset != uniform2.offset)
98 {
99 return LinkMismatchError::OFFSET_MISMATCH;
100 }
101
102 return LinkMismatchError::NO_MISMATCH;
103}
104
105using ShaderUniform = std::pair<GLenum, const sh::Uniform *>;
106
107bool ValidateGraphicsUniformsPerShader(const Context *context,
108 Shader *shaderToLink,
109 bool extendLinkedUniforms,
110 std::map<std::string, ShaderUniform> *linkedUniforms,
111 InfoLog &infoLog)
112{
113 ASSERT(context && shaderToLink && linkedUniforms);
114
115 for (const sh::Uniform &uniform : shaderToLink->getUniforms(context))
116 {
117 const auto &entry = linkedUniforms->find(uniform.name);
118 if (entry != linkedUniforms->end())
119 {
120 const sh::Uniform &linkedUniform = *(entry->second.second);
121 std::string mismatchedStructFieldName;
122 LinkMismatchError linkError =
123 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
124 if (linkError != LinkMismatchError::NO_MISMATCH)
125 {
126 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
127 mismatchedStructFieldName, entry->second.first,
128 shaderToLink->getType());
129 return false;
130 }
131 }
132 else if (extendLinkedUniforms)
133 {
134 (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
135 }
136 }
137
138 return true;
139}
140
Olli Etuahod2551232017-10-26 20:03:33 +0300141} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +0000142
143UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
144{
145}
146
Jamie Madillacf2f3a2017-11-21 19:22:44 -0500147UniformLinker::~UniformLinker() = default;
148
Olli Etuahob78707c2017-03-09 15:03:11 +0000149void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
150 std::vector<VariableLocation> *uniformLocations)
151{
152 uniforms->swap(mUniforms);
153 uniformLocations->swap(mUniformLocations);
154}
155
Jamie Madillbd044ed2017-06-05 12:59:21 -0400156bool UniformLinker::link(const Context *context,
157 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500158 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000159{
160 if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader())
161 {
162 ASSERT(mState.getAttachedComputeShader() == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +0800163 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000164 {
165 return false;
166 }
167 }
168
169 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
170 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -0400171 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000172 {
173 return false;
174 }
175
jchen10eaef1e52017-06-13 10:44:11 +0800176 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
177 {
178 return false;
179 }
180
Olli Etuahob78707c2017-03-09 15:03:11 +0000181 if (!indexUniforms(infoLog, uniformLocationBindings))
182 {
183 return false;
184 }
185
186 return true;
187}
188
Jiawei Shao73618602017-12-20 15:47:15 +0800189bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000190{
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800191 // Check that uniforms defined in the graphics shaders are identical
192 std::map<std::string, ShaderUniform> linkedUniforms;
193 for (const sh::Uniform &vertexUniform : mState.getAttachedVertexShader()->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000194 {
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800195 linkedUniforms[vertexUniform.name] = std::make_pair(GL_VERTEX_SHADER, &vertexUniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000196 }
197
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800198 std::vector<Shader *> activeShadersToLink;
199 if (mState.getAttachedGeometryShader())
Olli Etuahob78707c2017-03-09 15:03:11 +0000200 {
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800201 activeShadersToLink.push_back(mState.getAttachedGeometryShader());
202 }
203 activeShadersToLink.push_back(mState.getAttachedFragmentShader());
204
205 const size_t numActiveShadersToLink = activeShadersToLink.size();
206 for (size_t shaderIndex = 0; shaderIndex < numActiveShadersToLink; ++shaderIndex)
207 {
208 bool isLastShader = (shaderIndex == numActiveShadersToLink - 1);
209 if (!ValidateGraphicsUniformsPerShader(context, activeShadersToLink[shaderIndex],
210 !isLastShader, &linkedUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000211 {
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800212 return false;
Olli Etuahob78707c2017-03-09 15:03:11 +0000213 }
214 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800215
Olli Etuahob78707c2017-03-09 15:03:11 +0000216 return true;
217}
218
Jamie Madill3c1da042017-11-27 18:33:40 -0500219bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000220{
221 // All the locations where another uniform can't be located.
222 std::set<GLuint> reservedLocations;
223 // Locations which have been allocated for an unused uniform.
224 std::set<GLuint> ignoredLocations;
225
226 int maxUniformLocation = -1;
227
228 // Gather uniform locations that have been set either using the bindUniformLocation API or by
229 // using a location layout qualifier and check conflicts between them.
230 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
231 &reservedLocations, &ignoredLocations,
232 &maxUniformLocation))
233 {
234 return false;
235 }
236
237 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
238 // the line relies on only having statically used uniforms in mUniforms.
239 pruneUnusedUniforms();
240
241 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
242 std::vector<VariableLocation> unlocatedUniforms;
243 std::map<GLuint, VariableLocation> preLocatedUniforms;
244
245 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
246 {
247 const LinkedUniform &uniform = mUniforms[uniformIndex];
248
jchen10baf5d942017-08-28 20:45:48 +0800249 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000250 {
251 continue;
252 }
253
Olli Etuahod2551232017-10-26 20:03:33 +0300254 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000255 int shaderLocation = uniform.location;
256
257 if (shaderLocation != -1)
258 {
259 preSetLocation = shaderLocation;
260 }
261
Olli Etuaho465835d2017-09-26 13:34:10 +0300262 unsigned int elementCount = uniform.getBasicTypeElementCount();
263 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000264 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400265 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000266
267 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
268 {
269 int elementLocation = preSetLocation + arrayIndex;
270 preLocatedUniforms[elementLocation] = location;
271 }
272 else
273 {
274 unlocatedUniforms.push_back(location);
275 }
276 }
277 }
278
279 // Make enough space for all uniforms, with pre-set locations or not.
280 mUniformLocations.resize(
281 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
282 static_cast<size_t>(maxUniformLocation + 1)));
283
284 // Assign uniforms with pre-set locations
285 for (const auto &uniform : preLocatedUniforms)
286 {
287 mUniformLocations[uniform.first] = uniform.second;
288 }
289
290 // Assign ignored uniforms
291 for (const auto &ignoredLocation : ignoredLocations)
292 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400293 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000294 }
295
296 // Automatically assign locations for the rest of the uniforms
297 size_t nextUniformLocation = 0;
298 for (const auto &unlocatedUniform : unlocatedUniforms)
299 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400300 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000301 mUniformLocations[nextUniformLocation].ignored)
302 {
303 nextUniformLocation++;
304 }
305
306 ASSERT(nextUniformLocation < mUniformLocations.size());
307 mUniformLocations[nextUniformLocation] = unlocatedUniform;
308 nextUniformLocation++;
309 }
310
311 return true;
312}
313
314bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
315 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500316 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000317 std::set<GLuint> *reservedLocations,
318 std::set<GLuint> *ignoredLocations,
319 int *maxUniformLocation)
320{
321 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);
340 if (reservedLocations->find(elementLocation) != reservedLocations->end())
341 {
342 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
343 return false;
344 }
345 reservedLocations->insert(elementLocation);
346 if (!uniform.staticUse)
347 {
348 ignoredLocations->insert(elementLocation);
349 }
350 }
351 }
352 else if (apiBoundLocation != -1 && uniform.staticUse)
353 {
354 // Only the first location is reserved even if the uniform is an array.
355 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
356 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
357 {
358 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
359 return false;
360 }
361 reservedLocations->insert(apiBoundLocation);
362 }
363 }
364
365 // Record the uniform locations that were bound using the API for uniforms that were not found
366 // from the shader. Other uniforms should not be assigned to those locations.
367 for (const auto &locationBinding : uniformLocationBindings)
368 {
369 GLuint location = locationBinding.second;
370 if (reservedLocations->find(location) == reservedLocations->end())
371 {
372 ignoredLocations->insert(location);
373 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
374 }
375 }
376
377 return true;
378}
379
380void UniformLinker::pruneUnusedUniforms()
381{
382 auto uniformIter = mUniforms.begin();
383 while (uniformIter != mUniforms.end())
384 {
385 if (uniformIter->staticUse)
386 {
387 ++uniformIter;
388 }
389 else
390 {
391 uniformIter = mUniforms.erase(uniformIter);
392 }
393 }
394}
395
396bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400397 const Context *context,
398 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000399 GLuint maxUniformComponents,
400 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800401 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800402 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000403 const std::string &componentsErrorMessage,
404 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800405 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800406 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000407 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800408 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800409 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000410 InfoLog &infoLog)
411{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800412 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400413 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000414 {
jchen10baf5d942017-08-28 20:45:48 +0800415 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
416 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000417 }
418
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800419 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000420 {
421 infoLog << componentsErrorMessage << maxUniformComponents << ").";
422 return false;
423 }
424
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800425 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000426 {
427 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
428 return false;
429 }
430
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800431 if (shaderUniformCount.imageCount > maxImageUnits)
432 {
433 infoLog << imageErrorMessage << maxImageUnits << ").";
434 return false;
435 }
436
jchen10eaef1e52017-06-13 10:44:11 +0800437 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
438 {
439 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
440 return false;
441 }
442
Olli Etuahob78707c2017-03-09 15:03:11 +0000443 return true;
444}
445
Jamie Madillbd044ed2017-06-05 12:59:21 -0400446bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000447{
448 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800449 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800450 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000451
Jamie Madillbd044ed2017-06-05 12:59:21 -0400452 const Caps &caps = context->getCaps();
453
Olli Etuahob78707c2017-03-09 15:03:11 +0000454 if (mState.getAttachedComputeShader())
455 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400456 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000457
458 // TODO (mradev): check whether we need finer-grained component counting
459 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400460 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800461 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800462 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000463 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
464 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800465 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
466 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
467 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000468 {
469 return false;
470 }
471 }
472 else
473 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400474 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000475
476 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400477 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800478 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800479 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000480 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
481 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800482 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
483 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
484 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000485 {
486 return false;
487 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400488
489 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000490
491 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400492 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800493 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000494 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800495 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
496 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800497 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
498 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000499 {
500 return false;
501 }
Jiawei Shao0d88ec92018-02-27 16:25:31 +0800502
503 Shader *geometryShader = mState.getAttachedGeometryShader();
504 // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
505 if (geometryShader &&
506 !flattenUniformsAndCheckCapsForShader(
507 context, geometryShader, caps.maxGeometryUniformComponents / 4,
508 caps.maxGeometryTextureImageUnits, caps.maxGeometryImageUniforms,
509 caps.maxGeometryAtomicCounters,
510 "Geometry shader active uniforms exceed MAX_GEOMETRY_UNIFORM_VECTORS_EXT (",
511 "Geometry shader sampler count exceeds MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (",
512 "Geometry shader image count exceeds MAX_GEOMETRY_IMAGE_UNIFORMS_EXT (",
513 "Geometry shader atomic counter count exceeds MAX_GEOMETRY_ATOMIC_COUNTERS_EXT (",
514 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
515 {
516 return false;
517 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000518 }
519
520 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800521 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800522 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000523 return true;
524}
525
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800526UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000527 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800528 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800529 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800530 std::vector<LinkedUniform> *atomicCounterUniforms,
531 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000532{
Jamie Madill977abce2017-11-07 08:03:19 -0500533 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800534 ShaderUniformCount shaderUniformCount =
535 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
536 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
537 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000538 if (uniform.staticUse)
539 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800540 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000541 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800542 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000543}
544
Olli Etuaho465835d2017-09-26 13:34:10 +0300545UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
546 const sh::ShaderVariable &uniform,
547 unsigned int arrayNestingIndex,
548 const std::string &namePrefix,
549 const std::string &mappedNamePrefix,
550 std::vector<LinkedUniform> *samplerUniforms,
551 std::vector<LinkedUniform> *imageUniforms,
552 std::vector<LinkedUniform> *atomicCounterUniforms,
553 GLenum shaderType,
554 bool markStaticUse,
555 int binding,
556 int offset,
557 int *location)
558{
559 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
560 // innermost.
561 ShaderUniformCount shaderUniformCount;
562 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
563 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
564 {
565 const std::string elementName = namePrefix + ArrayString(arrayElement);
566 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
567 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
568 {
569 shaderUniformCount += flattenArrayOfStructsUniform(
570 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
571 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
572 location);
573 }
574 else
575 {
576 shaderUniformCount += flattenStructUniform(
577 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
578 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
579 }
580 }
581 return shaderUniformCount;
582}
583
584UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
585 const std::vector<sh::ShaderVariable> &fields,
586 const std::string &namePrefix,
587 const std::string &mappedNamePrefix,
588 std::vector<LinkedUniform> *samplerUniforms,
589 std::vector<LinkedUniform> *imageUniforms,
590 std::vector<LinkedUniform> *atomicCounterUniforms,
591 GLenum shaderType,
592 bool markStaticUse,
593 int binding,
594 int offset,
595 int *location)
596{
597 ShaderUniformCount shaderUniformCount;
598 for (const sh::ShaderVariable &field : fields)
599 {
600 const std::string &fieldName = namePrefix + "." + field.name;
601 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
602
603 shaderUniformCount +=
604 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
605 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
606 }
607 return shaderUniformCount;
608}
609
610UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
611 const sh::ShaderVariable &uniform,
612 const std::string &namePrefix,
613 const std::string &mappedNamePrefix,
614 std::vector<LinkedUniform> *samplerUniforms,
615 std::vector<LinkedUniform> *imageUniforms,
616 std::vector<LinkedUniform> *atomicCounterUniforms,
617 GLenum shaderType,
618 bool markStaticUse,
619 int binding,
620 int offset,
621 int *location)
622{
623 ShaderUniformCount shaderUniformCount;
624
625 ASSERT(uniform.isArray());
626 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
627 ++arrayElement)
628 {
629 sh::ShaderVariable uniformElement = uniform;
630 uniformElement.indexIntoArray(arrayElement);
631 const std::string elementName = namePrefix + ArrayString(arrayElement);
632 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
633
634 shaderUniformCount += flattenUniformImpl(
635 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
636 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
637 }
638 return shaderUniformCount;
639}
640
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800641UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000642 const sh::ShaderVariable &uniform,
643 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300644 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000645 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800646 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800647 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800648 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000649 bool markStaticUse,
650 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800651 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000652 int *location)
653{
654 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800655 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000656
657 if (uniform.isStruct())
658 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300659 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000660 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300661 shaderUniformCount += flattenArrayOfStructsUniform(
662 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
663 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000664 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300665 else
666 {
667 shaderUniformCount += flattenStructUniform(
668 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
669 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
670 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800671 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000672 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300673 if (uniform.isArrayOfArrays())
674 {
675 // GLES 3.1 November 2016 section 7.3.1 page 77:
676 // "For an active variable declared as an array of an aggregate data type (structures or
677 // arrays), a separate entry will be generated for each active array element"
678 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
679 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
680 binding, offset, location);
681 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000682
683 // Not a struct
684 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800685 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800686 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000687 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
688 if (isSampler)
689 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000690 uniformList = samplerUniforms;
691 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800692 else if (isImage)
693 {
694 uniformList = imageUniforms;
695 }
jchen10eaef1e52017-06-13 10:44:11 +0800696 else if (isAtomicCounter)
697 {
698 uniformList = atomicCounterUniforms;
699 }
Olli Etuahod2551232017-10-26 20:03:33 +0300700
701 std::string fullNameWithArrayIndex(fullName);
702 std::string fullMappedNameWithArrayIndex(fullMappedName);
703
704 if (uniform.isArray())
705 {
706 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
707 // and including [0] at the end of array variable names.
708 fullNameWithArrayIndex += "[0]";
709 fullMappedNameWithArrayIndex += "[0]";
710 }
711
712 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000713 if (existingUniform)
714 {
715 if (binding != -1)
716 {
717 existingUniform->binding = binding;
718 }
jchen10eaef1e52017-06-13 10:44:11 +0800719 if (offset != -1)
720 {
721 existingUniform->offset = offset;
722 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000723 if (*location != -1)
724 {
725 existingUniform->location = *location;
726 }
727 if (markStaticUse)
728 {
729 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800730 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000731 }
732 }
733 else
734 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300735 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300736 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300737 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000738 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300739 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
740 linkedUniform.staticUse = markStaticUse;
741 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800742 if (markStaticUse)
743 {
jchen104ef25032017-11-01 09:36:51 +0800744 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800745 }
jchen10eaef1e52017-06-13 10:44:11 +0800746
Olli Etuahob78707c2017-03-09 15:03:11 +0000747 uniformList->push_back(linkedUniform);
748 }
749
Olli Etuaho465835d2017-09-26 13:34:10 +0300750 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
751 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000752
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800753 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800754 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800755 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800756 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500757 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500758 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800759 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000760
761 if (*location != -1)
762 {
763 *location += elementCount;
764 }
765
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800766 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000767}
768
jchen10eaef1e52017-06-13 10:44:11 +0800769bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
770{
771 unsigned int atomicCounterCount = 0;
772 for (const auto &uniform : mUniforms)
773 {
774 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
775 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300776 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800777 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
778 {
779 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
780 << caps.maxCombinedAtomicCounters << ").";
781 return false;
782 }
783 }
784 }
785 return true;
786}
787
Jamie Madill977abce2017-11-07 08:03:19 -0500788// InterfaceBlockLinker implementation.
789InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
790 : mBlocksOut(blocksOut)
791{
792}
793
794InterfaceBlockLinker::~InterfaceBlockLinker()
795{
796}
797
798void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
799 const std::vector<sh::InterfaceBlock> *blocks)
800{
801 mShaderBlocks.push_back(std::make_pair(shader, blocks));
802}
803
804void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
805 const GetBlockMemberInfo &getMemberInfo) const
806{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500807 ASSERT(mBlocksOut->empty());
808
Jamie Madill977abce2017-11-07 08:03:19 -0500809 std::set<std::string> visitedList;
810
811 for (const auto &shaderBlocks : mShaderBlocks)
812 {
813 const GLenum shaderType = shaderBlocks.first;
814
815 for (const auto &block : *shaderBlocks.second)
816 {
Jiawei Shao1c08cbb2018-03-15 15:11:56 +0800817 if (!IsActiveInterfaceBlock(block))
Jamie Madill977abce2017-11-07 08:03:19 -0500818 continue;
819
820 if (visitedList.count(block.name) > 0)
821 {
822 if (block.staticUse)
823 {
824 for (InterfaceBlock &priorBlock : *mBlocksOut)
825 {
826 if (block.name == priorBlock.name)
827 {
828 priorBlock.setStaticUse(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800829 // Update the block members static use.
830 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
831 block.fieldMappedPrefix(), -1,
832 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
833 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500834 }
835 }
836 }
837 }
838 else
839 {
840 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
841 visitedList.insert(block.name);
842 }
843 }
844 }
845}
846
847template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300848void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
849 const VarT &field,
850 unsigned int arrayNestingIndex,
851 const std::string &prefix,
852 const std::string &mappedPrefix,
853 int blockIndex,
854 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800855 int topLevelArraySize,
856 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300857{
858 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
859 // innermost.
860 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
861 if (singleEntryForTopLevelArray)
862 {
863 entryGenerationArraySize = 1;
864 }
865 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
866 {
867 const std::string elementName = prefix + ArrayString(arrayElement);
868 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
869 if (arrayNestingIndex + 1u < field.arraySizes.size())
870 {
871 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
872 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800873 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300874 }
875 else
876 {
877 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800878 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300879 }
880 }
881}
882
883template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500884void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
885 const std::vector<VarT> &fields,
886 const std::string &prefix,
887 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800888 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300889 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800890 int topLevelArraySize,
891 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500892{
893 for (const VarT &field : fields)
894 {
895 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500896 std::string fullMappedName =
897 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
898
Olli Etuaho465835d2017-09-26 13:34:10 +0300899 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800900 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300901 }
902}
903
904template <typename VarT>
905void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
906 const VarT &field,
907 const std::string &fullName,
908 const std::string &fullMappedName,
909 int blockIndex,
910 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800911 int topLevelArraySize,
912 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300913{
914 int nextArraySize = topLevelArraySize;
915 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
916 singleEntryForTopLevelArray)
917 {
918 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
919 // member declared as an array of an aggregate type, an entry will be generated only
920 // for the first array element, regardless of its type.'
921 nextArraySize = field.getOutermostArraySize();
922 }
923
924 if (field.isStruct())
925 {
926 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500927 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300928 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800929 blockIndex, singleEntryForTopLevelArray, nextArraySize,
930 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500931 }
932 else
933 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300934 ASSERT(nextArraySize == topLevelArraySize);
935 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800936 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500937 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300938 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500939 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300940 if (field.isArrayOfArrays())
941 {
942 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
943 if (singleEntryForTopLevelArray)
944 {
945 entryGenerationArraySize = 1u;
946 }
947 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
948 ++arrayElement)
949 {
950 VarT fieldElement = field;
951 fieldElement.indexIntoArray(arrayElement);
952 const std::string elementName = fullName + ArrayString(arrayElement);
953 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
954
955 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800956 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300957 }
958 return;
959 }
960
Olli Etuaho465835d2017-09-26 13:34:10 +0300961 std::string fullNameWithArrayIndex = fullName;
962 std::string fullMappedNameWithArrayIndex = fullMappedName;
963
964 if (field.isArray())
965 {
966 fullNameWithArrayIndex += "[0]";
967 fullMappedNameWithArrayIndex += "[0]";
968 }
969
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800970 if (blockIndex == -1)
971 {
972 updateBlockMemberStaticUsedImpl(fullNameWithArrayIndex, shaderType, field.staticUse);
973 }
974 else
975 {
976 // If getBlockMemberInfo returns false, the variable is optimized out.
977 sh::BlockMemberInfo memberInfo;
978 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
979 {
980 return;
981 }
982
983 ASSERT(nextArraySize == topLevelArraySize);
984 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
985 blockIndex, memberInfo, nextArraySize, shaderType);
986 }
Jamie Madill977abce2017-11-07 08:03:19 -0500987}
988
989void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
990 const GetBlockMemberInfo &getMemberInfo,
991 const sh::InterfaceBlock &interfaceBlock,
992 GLenum shaderType) const
993{
994 size_t blockSize = 0;
995 std::vector<unsigned int> blockIndexes;
996
997 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800998 // Track the first and last block member index to determine the range of active block members in
999 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -05001000 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1001 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001002 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001003 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -05001004 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1005
1006 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1007 ++blockMemberIndex)
1008 {
1009 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1010 }
1011
Jamie Madill977abce2017-11-07 08:03:19 -05001012 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1013 ++arrayElement)
1014 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001015 std::string blockArrayName = interfaceBlock.name;
1016 std::string blockMappedArrayName = interfaceBlock.mappedName;
1017 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -05001018 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001019 blockArrayName += ArrayString(arrayElement);
1020 blockMappedArrayName += ArrayString(arrayElement);
1021 }
Jamie Madill977abce2017-11-07 08:03:19 -05001022
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001023 // Don't define this block at all if it's not active in the implementation.
1024 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1025 {
1026 continue;
Jamie Madill977abce2017-11-07 08:03:19 -05001027 }
1028
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001029 // ESSL 3.10 section 4.4.4 page 58:
1030 // Any uniform or shader storage block declared without a binding qualifier is initially
1031 // assigned to block binding point zero.
1032 int blockBinding =
1033 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -05001034 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001035 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -05001036 block.memberIndexes = blockIndexes;
1037 block.setStaticUse(shaderType, interfaceBlock.staticUse);
1038
1039 // Since all block elements in an array share the same active interface blocks, they
1040 // will all be active once any block member is used. So, since interfaceBlock.name[0]
1041 // was active, here we will add every block element in the array.
1042 block.dataSize = static_cast<unsigned int>(blockSize);
1043 mBlocksOut->push_back(block);
1044 }
1045}
1046
1047// UniformBlockLinker implementation.
1048UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1049 std::vector<LinkedUniform> *uniformsOut)
1050 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1051{
1052}
1053
1054UniformBlockLinker::~UniformBlockLinker()
1055{
1056}
1057
Olli Etuaho465835d2017-09-26 13:34:10 +03001058void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1059 const std::string &fullName,
1060 const std::string &fullMappedName,
1061 int blockIndex,
1062 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001063 int /*topLevelArraySize*/,
1064 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001065{
Olli Etuaho465835d2017-09-26 13:34:10 +03001066 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001067 blockIndex, memberInfo);
1068 newUniform.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001069 newUniform.setStaticUse(shaderType, field.staticUse);
Jamie Madill977abce2017-11-07 08:03:19 -05001070
1071 // Since block uniforms have no location, we don't need to store them in the uniform locations
1072 // list.
1073 mUniformsOut->push_back(newUniform);
1074}
1075
1076size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1077{
1078 return mUniformsOut->size();
1079}
1080
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001081void UniformBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1082 GLenum shaderType,
1083 bool staticUse) const
1084{
1085 SetStaticUse(mUniformsOut, fullName, shaderType, staticUse);
1086}
1087
Jamie Madill977abce2017-11-07 08:03:19 -05001088// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001089ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1090 std::vector<BufferVariable> *bufferVariablesOut)
1091 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001092{
1093}
1094
1095ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1096{
1097}
1098
Olli Etuaho465835d2017-09-26 13:34:10 +03001099void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1100 const std::string &fullName,
1101 const std::string &fullMappedName,
1102 int blockIndex,
1103 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001104 int topLevelArraySize,
1105 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001106{
Olli Etuaho465835d2017-09-26 13:34:10 +03001107 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001108 blockIndex, memberInfo);
1109 newBufferVariable.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001110 newBufferVariable.setStaticUse(shaderType, field.staticUse);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001111
1112 newBufferVariable.topLevelArraySize = topLevelArraySize;
1113
1114 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001115}
1116
1117size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1118{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001119 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001120}
1121
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001122void ShaderStorageBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1123 GLenum shaderType,
1124 bool staticUse) const
1125{
1126 SetStaticUse(mBufferVariablesOut, fullName, shaderType, staticUse);
1127}
1128
Jiajia Qin94f1e892017-11-20 12:14:32 +08001129// AtomicCounterBufferLinker implementation.
1130AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1131 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1132 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1133{
1134}
1135
1136AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1137{
1138}
1139
1140void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1141{
1142 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1143 {
1144 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1145 ASSERT(bufferSize != sizeMap.end());
1146 atomicCounterBuffer.dataSize = bufferSize->second;
1147 }
1148}
1149
Olli Etuahob78707c2017-03-09 15:03:11 +00001150} // namespace gl