blob: fcd1bbce9082837bfd513bf2e86fa79ac509b33d [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
Olli Etuahod2551232017-10-26 20:03:33 +030067} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +000068
69UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
70{
71}
72
Jamie Madillacf2f3a2017-11-21 19:22:44 -050073UniformLinker::~UniformLinker() = default;
74
Olli Etuahob78707c2017-03-09 15:03:11 +000075void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
76 std::vector<VariableLocation> *uniformLocations)
77{
78 uniforms->swap(mUniforms);
79 uniformLocations->swap(mUniformLocations);
80}
81
Jamie Madillbd044ed2017-06-05 12:59:21 -040082bool UniformLinker::link(const Context *context,
83 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -050084 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +000085{
86 if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader())
87 {
88 ASSERT(mState.getAttachedComputeShader() == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +080089 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000090 {
91 return false;
92 }
93 }
94
95 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
96 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -040097 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000098 {
99 return false;
100 }
101
jchen10eaef1e52017-06-13 10:44:11 +0800102 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
103 {
104 return false;
105 }
106
Olli Etuahob78707c2017-03-09 15:03:11 +0000107 if (!indexUniforms(infoLog, uniformLocationBindings))
108 {
109 return false;
110 }
111
112 return true;
113}
114
Jiawei Shao73618602017-12-20 15:47:15 +0800115bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000116{
117 // Check that uniforms defined in the vertex and fragment shaders are identical
Jiawei Shao73618602017-12-20 15:47:15 +0800118 std::map<std::string, const sh::Uniform *> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000119 const std::vector<sh::Uniform> &vertexUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400120 mState.getAttachedVertexShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000121 const std::vector<sh::Uniform> &fragmentUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400122 mState.getAttachedFragmentShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000123
124 for (const sh::Uniform &vertexUniform : vertexUniforms)
125 {
Jiawei Shao73618602017-12-20 15:47:15 +0800126 linkedUniforms[vertexUniform.name] = &vertexUniform;
Olli Etuahob78707c2017-03-09 15:03:11 +0000127 }
128
129 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
130 {
131 auto entry = linkedUniforms.find(fragmentUniform.name);
132 if (entry != linkedUniforms.end())
133 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800134 const sh::Uniform &vertexUniform = *(entry->second);
135 std::string mismatchedStructFieldName;
136 LinkMismatchError linkError =
137 LinkValidateUniforms(vertexUniform, fragmentUniform, &mismatchedStructFieldName);
138 if (linkError != LinkMismatchError::NO_MISMATCH)
Olli Etuahob78707c2017-03-09 15:03:11 +0000139 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800140 LogLinkMismatch(infoLog, fragmentUniform.name, "uniform", linkError,
141 mismatchedStructFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
Olli Etuahob78707c2017-03-09 15:03:11 +0000142 return false;
143 }
144 }
145 }
146 return true;
147}
148
149// GLSL ES Spec 3.00.3, section 4.3.5.
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800150LinkMismatchError UniformLinker::LinkValidateUniforms(const sh::Uniform &uniform1,
151 const sh::Uniform &uniform2,
152 std::string *mismatchedStructFieldName)
Olli Etuahob78707c2017-03-09 15:03:11 +0000153{
154#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
155 const bool validatePrecision = true;
156#else
157 const bool validatePrecision = false;
158#endif
159
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800160 LinkMismatchError linkError = Program::LinkValidateVariablesBase(
161 uniform1, uniform2, validatePrecision, mismatchedStructFieldName);
162 if (linkError != LinkMismatchError::NO_MISMATCH)
Olli Etuahob78707c2017-03-09 15:03:11 +0000163 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800164 return linkError;
Olli Etuahob78707c2017-03-09 15:03:11 +0000165 }
166
167 // GLSL ES Spec 3.10.4, section 4.4.5.
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800168 if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
Olli Etuahob78707c2017-03-09 15:03:11 +0000169 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800170 return LinkMismatchError::BINDING_MISMATCH;
Olli Etuahob78707c2017-03-09 15:03:11 +0000171 }
172
173 // GLSL ES Spec 3.10.4, section 9.2.1.
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800174 if (uniform1.location != -1 && uniform2.location != -1 &&
175 uniform1.location != uniform2.location)
Olli Etuahob78707c2017-03-09 15:03:11 +0000176 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800177 return LinkMismatchError::LOCATION_MISMATCH;
Olli Etuahob78707c2017-03-09 15:03:11 +0000178 }
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800179 if (uniform1.offset != uniform2.offset)
jchen10eaef1e52017-06-13 10:44:11 +0800180 {
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800181 return LinkMismatchError::OFFSET_MISMATCH;
jchen10eaef1e52017-06-13 10:44:11 +0800182 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000183
Jiawei Shao881b7bf2017-12-25 11:18:37 +0800184 return LinkMismatchError::NO_MISMATCH;
Olli Etuahob78707c2017-03-09 15:03:11 +0000185}
186
Jamie Madill3c1da042017-11-27 18:33:40 -0500187bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000188{
189 // All the locations where another uniform can't be located.
190 std::set<GLuint> reservedLocations;
191 // Locations which have been allocated for an unused uniform.
192 std::set<GLuint> ignoredLocations;
193
194 int maxUniformLocation = -1;
195
196 // Gather uniform locations that have been set either using the bindUniformLocation API or by
197 // using a location layout qualifier and check conflicts between them.
198 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
199 &reservedLocations, &ignoredLocations,
200 &maxUniformLocation))
201 {
202 return false;
203 }
204
205 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
206 // the line relies on only having statically used uniforms in mUniforms.
207 pruneUnusedUniforms();
208
209 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
210 std::vector<VariableLocation> unlocatedUniforms;
211 std::map<GLuint, VariableLocation> preLocatedUniforms;
212
213 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
214 {
215 const LinkedUniform &uniform = mUniforms[uniformIndex];
216
jchen10baf5d942017-08-28 20:45:48 +0800217 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000218 {
219 continue;
220 }
221
Olli Etuahod2551232017-10-26 20:03:33 +0300222 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000223 int shaderLocation = uniform.location;
224
225 if (shaderLocation != -1)
226 {
227 preSetLocation = shaderLocation;
228 }
229
Olli Etuaho465835d2017-09-26 13:34:10 +0300230 unsigned int elementCount = uniform.getBasicTypeElementCount();
231 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000232 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400233 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000234
235 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
236 {
237 int elementLocation = preSetLocation + arrayIndex;
238 preLocatedUniforms[elementLocation] = location;
239 }
240 else
241 {
242 unlocatedUniforms.push_back(location);
243 }
244 }
245 }
246
247 // Make enough space for all uniforms, with pre-set locations or not.
248 mUniformLocations.resize(
249 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
250 static_cast<size_t>(maxUniformLocation + 1)));
251
252 // Assign uniforms with pre-set locations
253 for (const auto &uniform : preLocatedUniforms)
254 {
255 mUniformLocations[uniform.first] = uniform.second;
256 }
257
258 // Assign ignored uniforms
259 for (const auto &ignoredLocation : ignoredLocations)
260 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400261 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000262 }
263
264 // Automatically assign locations for the rest of the uniforms
265 size_t nextUniformLocation = 0;
266 for (const auto &unlocatedUniform : unlocatedUniforms)
267 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400268 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000269 mUniformLocations[nextUniformLocation].ignored)
270 {
271 nextUniformLocation++;
272 }
273
274 ASSERT(nextUniformLocation < mUniformLocations.size());
275 mUniformLocations[nextUniformLocation] = unlocatedUniform;
276 nextUniformLocation++;
277 }
278
279 return true;
280}
281
282bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
283 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500284 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000285 std::set<GLuint> *reservedLocations,
286 std::set<GLuint> *ignoredLocations,
287 int *maxUniformLocation)
288{
289 for (const LinkedUniform &uniform : mUniforms)
290 {
291 if (uniform.isBuiltIn())
292 {
293 continue;
294 }
295
Olli Etuahod2551232017-10-26 20:03:33 +0300296 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000297 int shaderLocation = uniform.location;
298
299 if (shaderLocation != -1)
300 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300301 unsigned int elementCount = uniform.getBasicTypeElementCount();
302
303 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000304 {
305 // GLSL ES 3.10 section 4.4.3
306 int elementLocation = shaderLocation + arrayIndex;
307 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
308 if (reservedLocations->find(elementLocation) != reservedLocations->end())
309 {
310 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
311 return false;
312 }
313 reservedLocations->insert(elementLocation);
314 if (!uniform.staticUse)
315 {
316 ignoredLocations->insert(elementLocation);
317 }
318 }
319 }
320 else if (apiBoundLocation != -1 && uniform.staticUse)
321 {
322 // Only the first location is reserved even if the uniform is an array.
323 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
324 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
325 {
326 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
327 return false;
328 }
329 reservedLocations->insert(apiBoundLocation);
330 }
331 }
332
333 // Record the uniform locations that were bound using the API for uniforms that were not found
334 // from the shader. Other uniforms should not be assigned to those locations.
335 for (const auto &locationBinding : uniformLocationBindings)
336 {
337 GLuint location = locationBinding.second;
338 if (reservedLocations->find(location) == reservedLocations->end())
339 {
340 ignoredLocations->insert(location);
341 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
342 }
343 }
344
345 return true;
346}
347
348void UniformLinker::pruneUnusedUniforms()
349{
350 auto uniformIter = mUniforms.begin();
351 while (uniformIter != mUniforms.end())
352 {
353 if (uniformIter->staticUse)
354 {
355 ++uniformIter;
356 }
357 else
358 {
359 uniformIter = mUniforms.erase(uniformIter);
360 }
361 }
362}
363
364bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400365 const Context *context,
366 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000367 GLuint maxUniformComponents,
368 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800369 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800370 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000371 const std::string &componentsErrorMessage,
372 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800373 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800374 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000375 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800376 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800377 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000378 InfoLog &infoLog)
379{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800380 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400381 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000382 {
jchen10baf5d942017-08-28 20:45:48 +0800383 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
384 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000385 }
386
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800387 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000388 {
389 infoLog << componentsErrorMessage << maxUniformComponents << ").";
390 return false;
391 }
392
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800393 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000394 {
395 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
396 return false;
397 }
398
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800399 if (shaderUniformCount.imageCount > maxImageUnits)
400 {
401 infoLog << imageErrorMessage << maxImageUnits << ").";
402 return false;
403 }
404
jchen10eaef1e52017-06-13 10:44:11 +0800405 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
406 {
407 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
408 return false;
409 }
410
Olli Etuahob78707c2017-03-09 15:03:11 +0000411 return true;
412}
413
Jamie Madillbd044ed2017-06-05 12:59:21 -0400414bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000415{
416 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800417 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800418 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000419
Jamie Madillbd044ed2017-06-05 12:59:21 -0400420 const Caps &caps = context->getCaps();
421
Olli Etuahob78707c2017-03-09 15:03:11 +0000422 if (mState.getAttachedComputeShader())
423 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400424 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000425
426 // TODO (mradev): check whether we need finer-grained component counting
427 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400428 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800429 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800430 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000431 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
432 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800433 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
434 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
435 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000436 {
437 return false;
438 }
439 }
440 else
441 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400442 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000443
444 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400445 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800446 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800447 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000448 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
449 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800450 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
451 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
452 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000453 {
454 return false;
455 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400456
457 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000458
459 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400460 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800461 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000462 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800463 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
464 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800465 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
466 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000467 {
468 return false;
469 }
470 }
471
472 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800473 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800474 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000475 return true;
476}
477
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800478UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000479 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800481 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800482 std::vector<LinkedUniform> *atomicCounterUniforms,
483 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000484{
Jamie Madill977abce2017-11-07 08:03:19 -0500485 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800486 ShaderUniformCount shaderUniformCount =
487 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
488 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
489 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000490 if (uniform.staticUse)
491 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800492 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000493 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800494 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000495}
496
Olli Etuaho465835d2017-09-26 13:34:10 +0300497UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
498 const sh::ShaderVariable &uniform,
499 unsigned int arrayNestingIndex,
500 const std::string &namePrefix,
501 const std::string &mappedNamePrefix,
502 std::vector<LinkedUniform> *samplerUniforms,
503 std::vector<LinkedUniform> *imageUniforms,
504 std::vector<LinkedUniform> *atomicCounterUniforms,
505 GLenum shaderType,
506 bool markStaticUse,
507 int binding,
508 int offset,
509 int *location)
510{
511 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
512 // innermost.
513 ShaderUniformCount shaderUniformCount;
514 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
515 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
516 {
517 const std::string elementName = namePrefix + ArrayString(arrayElement);
518 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
519 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
520 {
521 shaderUniformCount += flattenArrayOfStructsUniform(
522 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
523 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
524 location);
525 }
526 else
527 {
528 shaderUniformCount += flattenStructUniform(
529 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
530 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
531 }
532 }
533 return shaderUniformCount;
534}
535
536UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
537 const std::vector<sh::ShaderVariable> &fields,
538 const std::string &namePrefix,
539 const std::string &mappedNamePrefix,
540 std::vector<LinkedUniform> *samplerUniforms,
541 std::vector<LinkedUniform> *imageUniforms,
542 std::vector<LinkedUniform> *atomicCounterUniforms,
543 GLenum shaderType,
544 bool markStaticUse,
545 int binding,
546 int offset,
547 int *location)
548{
549 ShaderUniformCount shaderUniformCount;
550 for (const sh::ShaderVariable &field : fields)
551 {
552 const std::string &fieldName = namePrefix + "." + field.name;
553 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
554
555 shaderUniformCount +=
556 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
557 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
558 }
559 return shaderUniformCount;
560}
561
562UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
563 const sh::ShaderVariable &uniform,
564 const std::string &namePrefix,
565 const std::string &mappedNamePrefix,
566 std::vector<LinkedUniform> *samplerUniforms,
567 std::vector<LinkedUniform> *imageUniforms,
568 std::vector<LinkedUniform> *atomicCounterUniforms,
569 GLenum shaderType,
570 bool markStaticUse,
571 int binding,
572 int offset,
573 int *location)
574{
575 ShaderUniformCount shaderUniformCount;
576
577 ASSERT(uniform.isArray());
578 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
579 ++arrayElement)
580 {
581 sh::ShaderVariable uniformElement = uniform;
582 uniformElement.indexIntoArray(arrayElement);
583 const std::string elementName = namePrefix + ArrayString(arrayElement);
584 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
585
586 shaderUniformCount += flattenUniformImpl(
587 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
588 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
589 }
590 return shaderUniformCount;
591}
592
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800593UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000594 const sh::ShaderVariable &uniform,
595 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300596 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000597 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800598 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800599 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800600 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000601 bool markStaticUse,
602 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800603 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000604 int *location)
605{
606 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800607 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000608
609 if (uniform.isStruct())
610 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300611 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000612 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300613 shaderUniformCount += flattenArrayOfStructsUniform(
614 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
615 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000616 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300617 else
618 {
619 shaderUniformCount += flattenStructUniform(
620 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
621 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
622 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800623 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000624 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300625 if (uniform.isArrayOfArrays())
626 {
627 // GLES 3.1 November 2016 section 7.3.1 page 77:
628 // "For an active variable declared as an array of an aggregate data type (structures or
629 // arrays), a separate entry will be generated for each active array element"
630 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
631 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
632 binding, offset, location);
633 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000634
635 // Not a struct
636 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800637 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800638 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000639 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
640 if (isSampler)
641 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000642 uniformList = samplerUniforms;
643 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800644 else if (isImage)
645 {
646 uniformList = imageUniforms;
647 }
jchen10eaef1e52017-06-13 10:44:11 +0800648 else if (isAtomicCounter)
649 {
650 uniformList = atomicCounterUniforms;
651 }
Olli Etuahod2551232017-10-26 20:03:33 +0300652
653 std::string fullNameWithArrayIndex(fullName);
654 std::string fullMappedNameWithArrayIndex(fullMappedName);
655
656 if (uniform.isArray())
657 {
658 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
659 // and including [0] at the end of array variable names.
660 fullNameWithArrayIndex += "[0]";
661 fullMappedNameWithArrayIndex += "[0]";
662 }
663
664 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000665 if (existingUniform)
666 {
667 if (binding != -1)
668 {
669 existingUniform->binding = binding;
670 }
jchen10eaef1e52017-06-13 10:44:11 +0800671 if (offset != -1)
672 {
673 existingUniform->offset = offset;
674 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000675 if (*location != -1)
676 {
677 existingUniform->location = *location;
678 }
679 if (markStaticUse)
680 {
681 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800682 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000683 }
684 }
685 else
686 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300687 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300688 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300689 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000690 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300691 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
692 linkedUniform.staticUse = markStaticUse;
693 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800694 if (markStaticUse)
695 {
jchen104ef25032017-11-01 09:36:51 +0800696 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800697 }
jchen10eaef1e52017-06-13 10:44:11 +0800698
Olli Etuahob78707c2017-03-09 15:03:11 +0000699 uniformList->push_back(linkedUniform);
700 }
701
Olli Etuaho465835d2017-09-26 13:34:10 +0300702 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
703 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000704
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800705 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800706 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800707 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800708 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500709 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500710 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800711 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000712
713 if (*location != -1)
714 {
715 *location += elementCount;
716 }
717
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800718 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000719}
720
jchen10eaef1e52017-06-13 10:44:11 +0800721bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
722{
723 unsigned int atomicCounterCount = 0;
724 for (const auto &uniform : mUniforms)
725 {
726 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
727 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300728 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800729 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
730 {
731 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
732 << caps.maxCombinedAtomicCounters << ").";
733 return false;
734 }
735 }
736 }
737 return true;
738}
739
Jamie Madill977abce2017-11-07 08:03:19 -0500740// InterfaceBlockLinker implementation.
741InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
742 : mBlocksOut(blocksOut)
743{
744}
745
746InterfaceBlockLinker::~InterfaceBlockLinker()
747{
748}
749
750void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
751 const std::vector<sh::InterfaceBlock> *blocks)
752{
753 mShaderBlocks.push_back(std::make_pair(shader, blocks));
754}
755
756void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
757 const GetBlockMemberInfo &getMemberInfo) const
758{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500759 ASSERT(mBlocksOut->empty());
760
Jamie Madill977abce2017-11-07 08:03:19 -0500761 std::set<std::string> visitedList;
762
763 for (const auto &shaderBlocks : mShaderBlocks)
764 {
765 const GLenum shaderType = shaderBlocks.first;
766
767 for (const auto &block : *shaderBlocks.second)
768 {
769 // Only 'packed' blocks are allowed to be considered inactive.
770 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
771 continue;
772
773 if (visitedList.count(block.name) > 0)
774 {
775 if (block.staticUse)
776 {
777 for (InterfaceBlock &priorBlock : *mBlocksOut)
778 {
779 if (block.name == priorBlock.name)
780 {
781 priorBlock.setStaticUse(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800782 // Update the block members static use.
783 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
784 block.fieldMappedPrefix(), -1,
785 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
786 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500787 }
788 }
789 }
790 }
791 else
792 {
793 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
794 visitedList.insert(block.name);
795 }
796 }
797 }
798}
799
800template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300801void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
802 const VarT &field,
803 unsigned int arrayNestingIndex,
804 const std::string &prefix,
805 const std::string &mappedPrefix,
806 int blockIndex,
807 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800808 int topLevelArraySize,
809 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300810{
811 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
812 // innermost.
813 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
814 if (singleEntryForTopLevelArray)
815 {
816 entryGenerationArraySize = 1;
817 }
818 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
819 {
820 const std::string elementName = prefix + ArrayString(arrayElement);
821 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
822 if (arrayNestingIndex + 1u < field.arraySizes.size())
823 {
824 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
825 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800826 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300827 }
828 else
829 {
830 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800831 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300832 }
833 }
834}
835
836template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500837void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
838 const std::vector<VarT> &fields,
839 const std::string &prefix,
840 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800841 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300842 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800843 int topLevelArraySize,
844 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500845{
846 for (const VarT &field : fields)
847 {
848 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500849 std::string fullMappedName =
850 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
851
Olli Etuaho465835d2017-09-26 13:34:10 +0300852 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800853 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300854 }
855}
856
857template <typename VarT>
858void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
859 const VarT &field,
860 const std::string &fullName,
861 const std::string &fullMappedName,
862 int blockIndex,
863 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800864 int topLevelArraySize,
865 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300866{
867 int nextArraySize = topLevelArraySize;
868 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
869 singleEntryForTopLevelArray)
870 {
871 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
872 // member declared as an array of an aggregate type, an entry will be generated only
873 // for the first array element, regardless of its type.'
874 nextArraySize = field.getOutermostArraySize();
875 }
876
877 if (field.isStruct())
878 {
879 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500880 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300881 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800882 blockIndex, singleEntryForTopLevelArray, nextArraySize,
883 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500884 }
885 else
886 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300887 ASSERT(nextArraySize == topLevelArraySize);
888 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800889 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500890 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300891 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500892 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300893 if (field.isArrayOfArrays())
894 {
895 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
896 if (singleEntryForTopLevelArray)
897 {
898 entryGenerationArraySize = 1u;
899 }
900 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
901 ++arrayElement)
902 {
903 VarT fieldElement = field;
904 fieldElement.indexIntoArray(arrayElement);
905 const std::string elementName = fullName + ArrayString(arrayElement);
906 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
907
908 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800909 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300910 }
911 return;
912 }
913
Olli Etuaho465835d2017-09-26 13:34:10 +0300914 std::string fullNameWithArrayIndex = fullName;
915 std::string fullMappedNameWithArrayIndex = fullMappedName;
916
917 if (field.isArray())
918 {
919 fullNameWithArrayIndex += "[0]";
920 fullMappedNameWithArrayIndex += "[0]";
921 }
922
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800923 if (blockIndex == -1)
924 {
925 updateBlockMemberStaticUsedImpl(fullNameWithArrayIndex, shaderType, field.staticUse);
926 }
927 else
928 {
929 // If getBlockMemberInfo returns false, the variable is optimized out.
930 sh::BlockMemberInfo memberInfo;
931 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
932 {
933 return;
934 }
935
936 ASSERT(nextArraySize == topLevelArraySize);
937 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
938 blockIndex, memberInfo, nextArraySize, shaderType);
939 }
Jamie Madill977abce2017-11-07 08:03:19 -0500940}
941
942void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
943 const GetBlockMemberInfo &getMemberInfo,
944 const sh::InterfaceBlock &interfaceBlock,
945 GLenum shaderType) const
946{
947 size_t blockSize = 0;
948 std::vector<unsigned int> blockIndexes;
949
950 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800951 // Track the first and last block member index to determine the range of active block members in
952 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500953 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
954 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800955 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800956 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500957 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
958
959 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
960 ++blockMemberIndex)
961 {
962 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
963 }
964
Jamie Madill977abce2017-11-07 08:03:19 -0500965 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
966 ++arrayElement)
967 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800968 std::string blockArrayName = interfaceBlock.name;
969 std::string blockMappedArrayName = interfaceBlock.mappedName;
970 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500971 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800972 blockArrayName += ArrayString(arrayElement);
973 blockMappedArrayName += ArrayString(arrayElement);
974 }
Jamie Madill977abce2017-11-07 08:03:19 -0500975
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800976 // Don't define this block at all if it's not active in the implementation.
977 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
978 {
979 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500980 }
981
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800982 // ESSL 3.10 section 4.4.4 page 58:
983 // Any uniform or shader storage block declared without a binding qualifier is initially
984 // assigned to block binding point zero.
985 int blockBinding =
986 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -0500987 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800988 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -0500989 block.memberIndexes = blockIndexes;
990 block.setStaticUse(shaderType, interfaceBlock.staticUse);
991
992 // Since all block elements in an array share the same active interface blocks, they
993 // will all be active once any block member is used. So, since interfaceBlock.name[0]
994 // was active, here we will add every block element in the array.
995 block.dataSize = static_cast<unsigned int>(blockSize);
996 mBlocksOut->push_back(block);
997 }
998}
999
1000// UniformBlockLinker implementation.
1001UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1002 std::vector<LinkedUniform> *uniformsOut)
1003 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1004{
1005}
1006
1007UniformBlockLinker::~UniformBlockLinker()
1008{
1009}
1010
Olli Etuaho465835d2017-09-26 13:34:10 +03001011void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1012 const std::string &fullName,
1013 const std::string &fullMappedName,
1014 int blockIndex,
1015 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001016 int /*topLevelArraySize*/,
1017 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001018{
Olli Etuaho465835d2017-09-26 13:34:10 +03001019 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001020 blockIndex, memberInfo);
1021 newUniform.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001022 newUniform.setStaticUse(shaderType, field.staticUse);
Jamie Madill977abce2017-11-07 08:03:19 -05001023
1024 // Since block uniforms have no location, we don't need to store them in the uniform locations
1025 // list.
1026 mUniformsOut->push_back(newUniform);
1027}
1028
1029size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1030{
1031 return mUniformsOut->size();
1032}
1033
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001034void UniformBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1035 GLenum shaderType,
1036 bool staticUse) const
1037{
1038 SetStaticUse(mUniformsOut, fullName, shaderType, staticUse);
1039}
1040
Jamie Madill977abce2017-11-07 08:03:19 -05001041// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001042ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1043 std::vector<BufferVariable> *bufferVariablesOut)
1044 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001045{
1046}
1047
1048ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1049{
1050}
1051
Olli Etuaho465835d2017-09-26 13:34:10 +03001052void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1053 const std::string &fullName,
1054 const std::string &fullMappedName,
1055 int blockIndex,
1056 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001057 int topLevelArraySize,
1058 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001059{
Olli Etuaho465835d2017-09-26 13:34:10 +03001060 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001061 blockIndex, memberInfo);
1062 newBufferVariable.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001063 newBufferVariable.setStaticUse(shaderType, field.staticUse);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001064
1065 newBufferVariable.topLevelArraySize = topLevelArraySize;
1066
1067 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001068}
1069
1070size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1071{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001072 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001073}
1074
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001075void ShaderStorageBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1076 GLenum shaderType,
1077 bool staticUse) const
1078{
1079 SetStaticUse(mBufferVariablesOut, fullName, shaderType, staticUse);
1080}
1081
Jiajia Qin94f1e892017-11-20 12:14:32 +08001082// AtomicCounterBufferLinker implementation.
1083AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1084 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1085 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1086{
1087}
1088
1089AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1090{
1091}
1092
1093void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1094{
1095 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1096 {
1097 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1098 ASSERT(bufferSize != sizeMap.end());
1099 atomicCounterBuffer.dataSize = bufferSize->second;
1100 }
1101}
1102
Olli Etuahob78707c2017-03-09 15:03:11 +00001103} // namespace gl