blob: 7207ac42ba2a26dfc3945d2b3dc6d8087b9c54cf [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
7// UniformLinker.cpp: implements link-time checks for default block uniforms, and generates uniform
8// locations. Populates data structures related to uniforms so that they can be stored in program
9// state.
10
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 Shao73618602017-12-20 15:47:15 +0800134 const sh::Uniform &linkedUniform = *(entry->second);
Olli Etuaho465835d2017-09-26 13:34:10 +0300135 const std::string &uniformName = "uniform '" + linkedUniform.name + "'";
Jiawei Shao73618602017-12-20 15:47:15 +0800136 if (!LinkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform))
Olli Etuahob78707c2017-03-09 15:03:11 +0000137 {
138 return false;
139 }
140 }
141 }
142 return true;
143}
144
145// GLSL ES Spec 3.00.3, section 4.3.5.
Jiawei Shao73618602017-12-20 15:47:15 +0800146bool UniformLinker::LinkValidateUniforms(InfoLog &infoLog,
Olli Etuahob78707c2017-03-09 15:03:11 +0000147 const std::string &uniformName,
148 const sh::Uniform &vertexUniform,
149 const sh::Uniform &fragmentUniform)
150{
151#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
152 const bool validatePrecision = true;
153#else
154 const bool validatePrecision = false;
155#endif
156
Jiawei Shao73618602017-12-20 15:47:15 +0800157 if (!Program::LinkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
Olli Etuahob78707c2017-03-09 15:03:11 +0000158 validatePrecision))
159 {
160 return false;
161 }
162
163 // GLSL ES Spec 3.10.4, section 4.4.5.
164 if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
165 vertexUniform.binding != fragmentUniform.binding)
166 {
167 infoLog << "Binding layout qualifiers for " << uniformName
168 << " differ between vertex and fragment shaders.";
169 return false;
170 }
171
172 // GLSL ES Spec 3.10.4, section 9.2.1.
173 if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
174 vertexUniform.location != fragmentUniform.location)
175 {
176 infoLog << "Location layout qualifiers for " << uniformName
177 << " differ between vertex and fragment shaders.";
178 return false;
179 }
jchen10eaef1e52017-06-13 10:44:11 +0800180 if (vertexUniform.offset != fragmentUniform.offset)
181 {
182 infoLog << "Offset layout qualifiers for " << uniformName
183 << " differ between vertex and fragment shaders.";
184 return false;
185 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000186
187 return true;
188}
189
Jamie Madill3c1da042017-11-27 18:33:40 -0500190bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000191{
192 // All the locations where another uniform can't be located.
193 std::set<GLuint> reservedLocations;
194 // Locations which have been allocated for an unused uniform.
195 std::set<GLuint> ignoredLocations;
196
197 int maxUniformLocation = -1;
198
199 // Gather uniform locations that have been set either using the bindUniformLocation API or by
200 // using a location layout qualifier and check conflicts between them.
201 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
202 &reservedLocations, &ignoredLocations,
203 &maxUniformLocation))
204 {
205 return false;
206 }
207
208 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
209 // the line relies on only having statically used uniforms in mUniforms.
210 pruneUnusedUniforms();
211
212 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
213 std::vector<VariableLocation> unlocatedUniforms;
214 std::map<GLuint, VariableLocation> preLocatedUniforms;
215
216 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
217 {
218 const LinkedUniform &uniform = mUniforms[uniformIndex];
219
jchen10baf5d942017-08-28 20:45:48 +0800220 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000221 {
222 continue;
223 }
224
Olli Etuahod2551232017-10-26 20:03:33 +0300225 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000226 int shaderLocation = uniform.location;
227
228 if (shaderLocation != -1)
229 {
230 preSetLocation = shaderLocation;
231 }
232
Olli Etuaho465835d2017-09-26 13:34:10 +0300233 unsigned int elementCount = uniform.getBasicTypeElementCount();
234 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000235 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400236 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000237
238 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
239 {
240 int elementLocation = preSetLocation + arrayIndex;
241 preLocatedUniforms[elementLocation] = location;
242 }
243 else
244 {
245 unlocatedUniforms.push_back(location);
246 }
247 }
248 }
249
250 // Make enough space for all uniforms, with pre-set locations or not.
251 mUniformLocations.resize(
252 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
253 static_cast<size_t>(maxUniformLocation + 1)));
254
255 // Assign uniforms with pre-set locations
256 for (const auto &uniform : preLocatedUniforms)
257 {
258 mUniformLocations[uniform.first] = uniform.second;
259 }
260
261 // Assign ignored uniforms
262 for (const auto &ignoredLocation : ignoredLocations)
263 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400264 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000265 }
266
267 // Automatically assign locations for the rest of the uniforms
268 size_t nextUniformLocation = 0;
269 for (const auto &unlocatedUniform : unlocatedUniforms)
270 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400271 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000272 mUniformLocations[nextUniformLocation].ignored)
273 {
274 nextUniformLocation++;
275 }
276
277 ASSERT(nextUniformLocation < mUniformLocations.size());
278 mUniformLocations[nextUniformLocation] = unlocatedUniform;
279 nextUniformLocation++;
280 }
281
282 return true;
283}
284
285bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
286 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500287 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000288 std::set<GLuint> *reservedLocations,
289 std::set<GLuint> *ignoredLocations,
290 int *maxUniformLocation)
291{
292 for (const LinkedUniform &uniform : mUniforms)
293 {
294 if (uniform.isBuiltIn())
295 {
296 continue;
297 }
298
Olli Etuahod2551232017-10-26 20:03:33 +0300299 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000300 int shaderLocation = uniform.location;
301
302 if (shaderLocation != -1)
303 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300304 unsigned int elementCount = uniform.getBasicTypeElementCount();
305
306 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000307 {
308 // GLSL ES 3.10 section 4.4.3
309 int elementLocation = shaderLocation + arrayIndex;
310 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
311 if (reservedLocations->find(elementLocation) != reservedLocations->end())
312 {
313 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
314 return false;
315 }
316 reservedLocations->insert(elementLocation);
317 if (!uniform.staticUse)
318 {
319 ignoredLocations->insert(elementLocation);
320 }
321 }
322 }
323 else if (apiBoundLocation != -1 && uniform.staticUse)
324 {
325 // Only the first location is reserved even if the uniform is an array.
326 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
327 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
328 {
329 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
330 return false;
331 }
332 reservedLocations->insert(apiBoundLocation);
333 }
334 }
335
336 // Record the uniform locations that were bound using the API for uniforms that were not found
337 // from the shader. Other uniforms should not be assigned to those locations.
338 for (const auto &locationBinding : uniformLocationBindings)
339 {
340 GLuint location = locationBinding.second;
341 if (reservedLocations->find(location) == reservedLocations->end())
342 {
343 ignoredLocations->insert(location);
344 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
345 }
346 }
347
348 return true;
349}
350
351void UniformLinker::pruneUnusedUniforms()
352{
353 auto uniformIter = mUniforms.begin();
354 while (uniformIter != mUniforms.end())
355 {
356 if (uniformIter->staticUse)
357 {
358 ++uniformIter;
359 }
360 else
361 {
362 uniformIter = mUniforms.erase(uniformIter);
363 }
364 }
365}
366
367bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400368 const Context *context,
369 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000370 GLuint maxUniformComponents,
371 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800372 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800373 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000374 const std::string &componentsErrorMessage,
375 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800376 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800377 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000378 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800379 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800380 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000381 InfoLog &infoLog)
382{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800383 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400384 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000385 {
jchen10baf5d942017-08-28 20:45:48 +0800386 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
387 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000388 }
389
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800390 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000391 {
392 infoLog << componentsErrorMessage << maxUniformComponents << ").";
393 return false;
394 }
395
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800396 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000397 {
398 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
399 return false;
400 }
401
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800402 if (shaderUniformCount.imageCount > maxImageUnits)
403 {
404 infoLog << imageErrorMessage << maxImageUnits << ").";
405 return false;
406 }
407
jchen10eaef1e52017-06-13 10:44:11 +0800408 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
409 {
410 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
411 return false;
412 }
413
Olli Etuahob78707c2017-03-09 15:03:11 +0000414 return true;
415}
416
Jamie Madillbd044ed2017-06-05 12:59:21 -0400417bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000418{
419 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800420 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800421 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000422
Jamie Madillbd044ed2017-06-05 12:59:21 -0400423 const Caps &caps = context->getCaps();
424
Olli Etuahob78707c2017-03-09 15:03:11 +0000425 if (mState.getAttachedComputeShader())
426 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400427 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000428
429 // TODO (mradev): check whether we need finer-grained component counting
430 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400431 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800432 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800433 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000434 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
435 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800436 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
437 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
438 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000439 {
440 return false;
441 }
442 }
443 else
444 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400445 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000446
447 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400448 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800449 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800450 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000451 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
452 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800453 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
454 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
455 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000456 {
457 return false;
458 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400459
460 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000461
462 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400463 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800464 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000465 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800466 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
467 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800468 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
469 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000470 {
471 return false;
472 }
473 }
474
475 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800476 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800477 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000478 return true;
479}
480
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800481UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000482 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800483 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800484 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800485 std::vector<LinkedUniform> *atomicCounterUniforms,
486 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000487{
Jamie Madill977abce2017-11-07 08:03:19 -0500488 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800489 ShaderUniformCount shaderUniformCount =
490 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
491 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
492 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000493 if (uniform.staticUse)
494 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800495 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000496 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800497 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000498}
499
Olli Etuaho465835d2017-09-26 13:34:10 +0300500UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
501 const sh::ShaderVariable &uniform,
502 unsigned int arrayNestingIndex,
503 const std::string &namePrefix,
504 const std::string &mappedNamePrefix,
505 std::vector<LinkedUniform> *samplerUniforms,
506 std::vector<LinkedUniform> *imageUniforms,
507 std::vector<LinkedUniform> *atomicCounterUniforms,
508 GLenum shaderType,
509 bool markStaticUse,
510 int binding,
511 int offset,
512 int *location)
513{
514 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
515 // innermost.
516 ShaderUniformCount shaderUniformCount;
517 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
518 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
519 {
520 const std::string elementName = namePrefix + ArrayString(arrayElement);
521 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
522 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
523 {
524 shaderUniformCount += flattenArrayOfStructsUniform(
525 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
526 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
527 location);
528 }
529 else
530 {
531 shaderUniformCount += flattenStructUniform(
532 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
533 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
534 }
535 }
536 return shaderUniformCount;
537}
538
539UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
540 const std::vector<sh::ShaderVariable> &fields,
541 const std::string &namePrefix,
542 const std::string &mappedNamePrefix,
543 std::vector<LinkedUniform> *samplerUniforms,
544 std::vector<LinkedUniform> *imageUniforms,
545 std::vector<LinkedUniform> *atomicCounterUniforms,
546 GLenum shaderType,
547 bool markStaticUse,
548 int binding,
549 int offset,
550 int *location)
551{
552 ShaderUniformCount shaderUniformCount;
553 for (const sh::ShaderVariable &field : fields)
554 {
555 const std::string &fieldName = namePrefix + "." + field.name;
556 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
557
558 shaderUniformCount +=
559 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
560 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
561 }
562 return shaderUniformCount;
563}
564
565UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
566 const sh::ShaderVariable &uniform,
567 const std::string &namePrefix,
568 const std::string &mappedNamePrefix,
569 std::vector<LinkedUniform> *samplerUniforms,
570 std::vector<LinkedUniform> *imageUniforms,
571 std::vector<LinkedUniform> *atomicCounterUniforms,
572 GLenum shaderType,
573 bool markStaticUse,
574 int binding,
575 int offset,
576 int *location)
577{
578 ShaderUniformCount shaderUniformCount;
579
580 ASSERT(uniform.isArray());
581 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
582 ++arrayElement)
583 {
584 sh::ShaderVariable uniformElement = uniform;
585 uniformElement.indexIntoArray(arrayElement);
586 const std::string elementName = namePrefix + ArrayString(arrayElement);
587 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
588
589 shaderUniformCount += flattenUniformImpl(
590 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
591 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
592 }
593 return shaderUniformCount;
594}
595
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800596UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000597 const sh::ShaderVariable &uniform,
598 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300599 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000600 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800601 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800602 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800603 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000604 bool markStaticUse,
605 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800606 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000607 int *location)
608{
609 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800610 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000611
612 if (uniform.isStruct())
613 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300614 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000615 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300616 shaderUniformCount += flattenArrayOfStructsUniform(
617 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
618 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000619 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300620 else
621 {
622 shaderUniformCount += flattenStructUniform(
623 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
624 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
625 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800626 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000627 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300628 if (uniform.isArrayOfArrays())
629 {
630 // GLES 3.1 November 2016 section 7.3.1 page 77:
631 // "For an active variable declared as an array of an aggregate data type (structures or
632 // arrays), a separate entry will be generated for each active array element"
633 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
634 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
635 binding, offset, location);
636 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000637
638 // Not a struct
639 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800640 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800641 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000642 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
643 if (isSampler)
644 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000645 uniformList = samplerUniforms;
646 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800647 else if (isImage)
648 {
649 uniformList = imageUniforms;
650 }
jchen10eaef1e52017-06-13 10:44:11 +0800651 else if (isAtomicCounter)
652 {
653 uniformList = atomicCounterUniforms;
654 }
Olli Etuahod2551232017-10-26 20:03:33 +0300655
656 std::string fullNameWithArrayIndex(fullName);
657 std::string fullMappedNameWithArrayIndex(fullMappedName);
658
659 if (uniform.isArray())
660 {
661 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
662 // and including [0] at the end of array variable names.
663 fullNameWithArrayIndex += "[0]";
664 fullMappedNameWithArrayIndex += "[0]";
665 }
666
667 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000668 if (existingUniform)
669 {
670 if (binding != -1)
671 {
672 existingUniform->binding = binding;
673 }
jchen10eaef1e52017-06-13 10:44:11 +0800674 if (offset != -1)
675 {
676 existingUniform->offset = offset;
677 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000678 if (*location != -1)
679 {
680 existingUniform->location = *location;
681 }
682 if (markStaticUse)
683 {
684 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800685 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000686 }
687 }
688 else
689 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300690 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300691 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300692 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000693 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300694 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
695 linkedUniform.staticUse = markStaticUse;
696 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800697 if (markStaticUse)
698 {
jchen104ef25032017-11-01 09:36:51 +0800699 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800700 }
jchen10eaef1e52017-06-13 10:44:11 +0800701
Olli Etuahob78707c2017-03-09 15:03:11 +0000702 uniformList->push_back(linkedUniform);
703 }
704
Olli Etuaho465835d2017-09-26 13:34:10 +0300705 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
706 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000707
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800708 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800709 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800710 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800711 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500712 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500713 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800714 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000715
716 if (*location != -1)
717 {
718 *location += elementCount;
719 }
720
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800721 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000722}
723
jchen10eaef1e52017-06-13 10:44:11 +0800724bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
725{
726 unsigned int atomicCounterCount = 0;
727 for (const auto &uniform : mUniforms)
728 {
729 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
730 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300731 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800732 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
733 {
734 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
735 << caps.maxCombinedAtomicCounters << ").";
736 return false;
737 }
738 }
739 }
740 return true;
741}
742
Jamie Madill977abce2017-11-07 08:03:19 -0500743// InterfaceBlockLinker implementation.
744InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
745 : mBlocksOut(blocksOut)
746{
747}
748
749InterfaceBlockLinker::~InterfaceBlockLinker()
750{
751}
752
753void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
754 const std::vector<sh::InterfaceBlock> *blocks)
755{
756 mShaderBlocks.push_back(std::make_pair(shader, blocks));
757}
758
759void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
760 const GetBlockMemberInfo &getMemberInfo) const
761{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500762 ASSERT(mBlocksOut->empty());
763
Jamie Madill977abce2017-11-07 08:03:19 -0500764 std::set<std::string> visitedList;
765
766 for (const auto &shaderBlocks : mShaderBlocks)
767 {
768 const GLenum shaderType = shaderBlocks.first;
769
770 for (const auto &block : *shaderBlocks.second)
771 {
772 // Only 'packed' blocks are allowed to be considered inactive.
773 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
774 continue;
775
776 if (visitedList.count(block.name) > 0)
777 {
778 if (block.staticUse)
779 {
780 for (InterfaceBlock &priorBlock : *mBlocksOut)
781 {
782 if (block.name == priorBlock.name)
783 {
784 priorBlock.setStaticUse(shaderType, true);
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800785 // Update the block members static use.
786 defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
787 block.fieldMappedPrefix(), -1,
788 block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
789 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500790 }
791 }
792 }
793 }
794 else
795 {
796 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
797 visitedList.insert(block.name);
798 }
799 }
800 }
801}
802
803template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300804void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
805 const VarT &field,
806 unsigned int arrayNestingIndex,
807 const std::string &prefix,
808 const std::string &mappedPrefix,
809 int blockIndex,
810 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800811 int topLevelArraySize,
812 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300813{
814 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
815 // innermost.
816 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
817 if (singleEntryForTopLevelArray)
818 {
819 entryGenerationArraySize = 1;
820 }
821 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
822 {
823 const std::string elementName = prefix + ArrayString(arrayElement);
824 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
825 if (arrayNestingIndex + 1u < field.arraySizes.size())
826 {
827 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
828 elementName, elementMappedName, blockIndex, false,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800829 topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300830 }
831 else
832 {
833 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800834 blockIndex, false, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300835 }
836 }
837}
838
839template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500840void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
841 const std::vector<VarT> &fields,
842 const std::string &prefix,
843 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800844 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300845 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800846 int topLevelArraySize,
847 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -0500848{
849 for (const VarT &field : fields)
850 {
851 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500852 std::string fullMappedName =
853 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
854
Olli Etuaho465835d2017-09-26 13:34:10 +0300855 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800856 singleEntryForTopLevelArray, topLevelArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300857 }
858}
859
860template <typename VarT>
861void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
862 const VarT &field,
863 const std::string &fullName,
864 const std::string &fullMappedName,
865 int blockIndex,
866 bool singleEntryForTopLevelArray,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800867 int topLevelArraySize,
868 GLenum shaderType) const
Olli Etuaho465835d2017-09-26 13:34:10 +0300869{
870 int nextArraySize = topLevelArraySize;
871 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
872 singleEntryForTopLevelArray)
873 {
874 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
875 // member declared as an array of an aggregate type, an entry will be generated only
876 // for the first array element, regardless of its type.'
877 nextArraySize = field.getOutermostArraySize();
878 }
879
880 if (field.isStruct())
881 {
882 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500883 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300884 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800885 blockIndex, singleEntryForTopLevelArray, nextArraySize,
886 shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500887 }
888 else
889 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300890 ASSERT(nextArraySize == topLevelArraySize);
891 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800892 false, nextArraySize, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500893 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300894 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500895 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300896 if (field.isArrayOfArrays())
897 {
898 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
899 if (singleEntryForTopLevelArray)
900 {
901 entryGenerationArraySize = 1u;
902 }
903 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
904 ++arrayElement)
905 {
906 VarT fieldElement = field;
907 fieldElement.indexIntoArray(arrayElement);
908 const std::string elementName = fullName + ArrayString(arrayElement);
909 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
910
911 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800912 blockIndex, false, nextArraySize, shaderType);
Olli Etuaho465835d2017-09-26 13:34:10 +0300913 }
914 return;
915 }
916
Olli Etuaho465835d2017-09-26 13:34:10 +0300917 std::string fullNameWithArrayIndex = fullName;
918 std::string fullMappedNameWithArrayIndex = fullMappedName;
919
920 if (field.isArray())
921 {
922 fullNameWithArrayIndex += "[0]";
923 fullMappedNameWithArrayIndex += "[0]";
924 }
925
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800926 if (blockIndex == -1)
927 {
928 updateBlockMemberStaticUsedImpl(fullNameWithArrayIndex, shaderType, field.staticUse);
929 }
930 else
931 {
932 // If getBlockMemberInfo returns false, the variable is optimized out.
933 sh::BlockMemberInfo memberInfo;
934 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
935 {
936 return;
937 }
938
939 ASSERT(nextArraySize == topLevelArraySize);
940 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
941 blockIndex, memberInfo, nextArraySize, shaderType);
942 }
Jamie Madill977abce2017-11-07 08:03:19 -0500943}
944
945void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
946 const GetBlockMemberInfo &getMemberInfo,
947 const sh::InterfaceBlock &interfaceBlock,
948 GLenum shaderType) const
949{
950 size_t blockSize = 0;
951 std::vector<unsigned int> blockIndexes;
952
953 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800954 // Track the first and last block member index to determine the range of active block members in
955 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500956 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
957 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800958 interfaceBlock.fieldMappedPrefix(), blockIndex,
Qin Jiajiacd3acf62017-12-05 16:27:25 +0800959 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
Jamie Madill977abce2017-11-07 08:03:19 -0500960 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
961
962 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
963 ++blockMemberIndex)
964 {
965 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
966 }
967
Jamie Madill977abce2017-11-07 08:03:19 -0500968 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
969 ++arrayElement)
970 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800971 std::string blockArrayName = interfaceBlock.name;
972 std::string blockMappedArrayName = interfaceBlock.mappedName;
973 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500974 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800975 blockArrayName += ArrayString(arrayElement);
976 blockMappedArrayName += ArrayString(arrayElement);
977 }
Jamie Madill977abce2017-11-07 08:03:19 -0500978
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800979 // Don't define this block at all if it's not active in the implementation.
980 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
981 {
982 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500983 }
984
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800985 // ESSL 3.10 section 4.4.4 page 58:
986 // Any uniform or shader storage block declared without a binding qualifier is initially
987 // assigned to block binding point zero.
988 int blockBinding =
989 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -0500990 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800991 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -0500992 block.memberIndexes = blockIndexes;
993 block.setStaticUse(shaderType, interfaceBlock.staticUse);
994
995 // Since all block elements in an array share the same active interface blocks, they
996 // will all be active once any block member is used. So, since interfaceBlock.name[0]
997 // was active, here we will add every block element in the array.
998 block.dataSize = static_cast<unsigned int>(blockSize);
999 mBlocksOut->push_back(block);
1000 }
1001}
1002
1003// UniformBlockLinker implementation.
1004UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1005 std::vector<LinkedUniform> *uniformsOut)
1006 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
1007{
1008}
1009
1010UniformBlockLinker::~UniformBlockLinker()
1011{
1012}
1013
Olli Etuaho465835d2017-09-26 13:34:10 +03001014void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1015 const std::string &fullName,
1016 const std::string &fullMappedName,
1017 int blockIndex,
1018 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001019 int /*topLevelArraySize*/,
1020 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001021{
Olli Etuaho465835d2017-09-26 13:34:10 +03001022 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -05001023 blockIndex, memberInfo);
1024 newUniform.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001025 newUniform.setStaticUse(shaderType, field.staticUse);
Jamie Madill977abce2017-11-07 08:03:19 -05001026
1027 // Since block uniforms have no location, we don't need to store them in the uniform locations
1028 // list.
1029 mUniformsOut->push_back(newUniform);
1030}
1031
1032size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1033{
1034 return mUniformsOut->size();
1035}
1036
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001037void UniformBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1038 GLenum shaderType,
1039 bool staticUse) const
1040{
1041 SetStaticUse(mUniformsOut, fullName, shaderType, staticUse);
1042}
1043
Jamie Madill977abce2017-11-07 08:03:19 -05001044// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001045ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1046 std::vector<BufferVariable> *bufferVariablesOut)
1047 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001048{
1049}
1050
1051ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1052{
1053}
1054
Olli Etuaho465835d2017-09-26 13:34:10 +03001055void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1056 const std::string &fullName,
1057 const std::string &fullMappedName,
1058 int blockIndex,
1059 const sh::BlockMemberInfo &memberInfo,
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001060 int topLevelArraySize,
1061 GLenum shaderType) const
Jamie Madill977abce2017-11-07 08:03:19 -05001062{
Olli Etuaho465835d2017-09-26 13:34:10 +03001063 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001064 blockIndex, memberInfo);
1065 newBufferVariable.mappedName = fullMappedName;
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001066 newBufferVariable.setStaticUse(shaderType, field.staticUse);
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001067
1068 newBufferVariable.topLevelArraySize = topLevelArraySize;
1069
1070 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001071}
1072
1073size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1074{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001075 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001076}
1077
Qin Jiajiacd3acf62017-12-05 16:27:25 +08001078void ShaderStorageBlockLinker::updateBlockMemberStaticUsedImpl(const std::string &fullName,
1079 GLenum shaderType,
1080 bool staticUse) const
1081{
1082 SetStaticUse(mBufferVariablesOut, fullName, shaderType, staticUse);
1083}
1084
Jiajia Qin94f1e892017-11-20 12:14:32 +08001085// AtomicCounterBufferLinker implementation.
1086AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1087 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1088 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1089{
1090}
1091
1092AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1093{
1094}
1095
1096void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1097{
1098 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1099 {
1100 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1101 ASSERT(bufferSize != sizeMap.end());
1102 atomicCounterBuffer.dataSize = bufferSize->second;
1103 }
1104}
1105
Olli Etuahob78707c2017-03-09 15:03:11 +00001106} // namespace gl