blob: e1c9ff717fc4b6afd1126b680b08262de1f8336b [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
51} // anonymous namespace
Olli Etuahob78707c2017-03-09 15:03:11 +000052
53UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
54{
55}
56
Jamie Madillacf2f3a2017-11-21 19:22:44 -050057UniformLinker::~UniformLinker() = default;
58
Olli Etuahob78707c2017-03-09 15:03:11 +000059void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
60 std::vector<VariableLocation> *uniformLocations)
61{
62 uniforms->swap(mUniforms);
63 uniformLocations->swap(mUniformLocations);
64}
65
Jamie Madillbd044ed2017-06-05 12:59:21 -040066bool UniformLinker::link(const Context *context,
67 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -050068 const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +000069{
70 if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader())
71 {
72 ASSERT(mState.getAttachedComputeShader() == nullptr);
Jiawei Shao73618602017-12-20 15:47:15 +080073 if (!validateGraphicsUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000074 {
75 return false;
76 }
77 }
78
79 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
80 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -040081 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000082 {
83 return false;
84 }
85
jchen10eaef1e52017-06-13 10:44:11 +080086 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
87 {
88 return false;
89 }
90
Olli Etuahob78707c2017-03-09 15:03:11 +000091 if (!indexUniforms(infoLog, uniformLocationBindings))
92 {
93 return false;
94 }
95
96 return true;
97}
98
Jiawei Shao73618602017-12-20 15:47:15 +080099bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000100{
101 // Check that uniforms defined in the vertex and fragment shaders are identical
Jiawei Shao73618602017-12-20 15:47:15 +0800102 std::map<std::string, const sh::Uniform *> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000103 const std::vector<sh::Uniform> &vertexUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400104 mState.getAttachedVertexShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000105 const std::vector<sh::Uniform> &fragmentUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400106 mState.getAttachedFragmentShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000107
108 for (const sh::Uniform &vertexUniform : vertexUniforms)
109 {
Jiawei Shao73618602017-12-20 15:47:15 +0800110 linkedUniforms[vertexUniform.name] = &vertexUniform;
Olli Etuahob78707c2017-03-09 15:03:11 +0000111 }
112
113 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
114 {
115 auto entry = linkedUniforms.find(fragmentUniform.name);
116 if (entry != linkedUniforms.end())
117 {
Jiawei Shao73618602017-12-20 15:47:15 +0800118 const sh::Uniform &linkedUniform = *(entry->second);
Olli Etuaho465835d2017-09-26 13:34:10 +0300119 const std::string &uniformName = "uniform '" + linkedUniform.name + "'";
Jiawei Shao73618602017-12-20 15:47:15 +0800120 if (!LinkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform))
Olli Etuahob78707c2017-03-09 15:03:11 +0000121 {
122 return false;
123 }
124 }
125 }
126 return true;
127}
128
129// GLSL ES Spec 3.00.3, section 4.3.5.
Jiawei Shao73618602017-12-20 15:47:15 +0800130bool UniformLinker::LinkValidateUniforms(InfoLog &infoLog,
Olli Etuahob78707c2017-03-09 15:03:11 +0000131 const std::string &uniformName,
132 const sh::Uniform &vertexUniform,
133 const sh::Uniform &fragmentUniform)
134{
135#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
136 const bool validatePrecision = true;
137#else
138 const bool validatePrecision = false;
139#endif
140
Jiawei Shao73618602017-12-20 15:47:15 +0800141 if (!Program::LinkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
Olli Etuahob78707c2017-03-09 15:03:11 +0000142 validatePrecision))
143 {
144 return false;
145 }
146
147 // GLSL ES Spec 3.10.4, section 4.4.5.
148 if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
149 vertexUniform.binding != fragmentUniform.binding)
150 {
151 infoLog << "Binding layout qualifiers for " << uniformName
152 << " differ between vertex and fragment shaders.";
153 return false;
154 }
155
156 // GLSL ES Spec 3.10.4, section 9.2.1.
157 if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
158 vertexUniform.location != fragmentUniform.location)
159 {
160 infoLog << "Location layout qualifiers for " << uniformName
161 << " differ between vertex and fragment shaders.";
162 return false;
163 }
jchen10eaef1e52017-06-13 10:44:11 +0800164 if (vertexUniform.offset != fragmentUniform.offset)
165 {
166 infoLog << "Offset layout qualifiers for " << uniformName
167 << " differ between vertex and fragment shaders.";
168 return false;
169 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000170
171 return true;
172}
173
Jamie Madill3c1da042017-11-27 18:33:40 -0500174bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000175{
176 // All the locations where another uniform can't be located.
177 std::set<GLuint> reservedLocations;
178 // Locations which have been allocated for an unused uniform.
179 std::set<GLuint> ignoredLocations;
180
181 int maxUniformLocation = -1;
182
183 // Gather uniform locations that have been set either using the bindUniformLocation API or by
184 // using a location layout qualifier and check conflicts between them.
185 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
186 &reservedLocations, &ignoredLocations,
187 &maxUniformLocation))
188 {
189 return false;
190 }
191
192 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
193 // the line relies on only having statically used uniforms in mUniforms.
194 pruneUnusedUniforms();
195
196 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
197 std::vector<VariableLocation> unlocatedUniforms;
198 std::map<GLuint, VariableLocation> preLocatedUniforms;
199
200 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
201 {
202 const LinkedUniform &uniform = mUniforms[uniformIndex];
203
jchen10baf5d942017-08-28 20:45:48 +0800204 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000205 {
206 continue;
207 }
208
Olli Etuahod2551232017-10-26 20:03:33 +0300209 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000210 int shaderLocation = uniform.location;
211
212 if (shaderLocation != -1)
213 {
214 preSetLocation = shaderLocation;
215 }
216
Olli Etuaho465835d2017-09-26 13:34:10 +0300217 unsigned int elementCount = uniform.getBasicTypeElementCount();
218 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000219 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400220 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000221
222 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
223 {
224 int elementLocation = preSetLocation + arrayIndex;
225 preLocatedUniforms[elementLocation] = location;
226 }
227 else
228 {
229 unlocatedUniforms.push_back(location);
230 }
231 }
232 }
233
234 // Make enough space for all uniforms, with pre-set locations or not.
235 mUniformLocations.resize(
236 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
237 static_cast<size_t>(maxUniformLocation + 1)));
238
239 // Assign uniforms with pre-set locations
240 for (const auto &uniform : preLocatedUniforms)
241 {
242 mUniformLocations[uniform.first] = uniform.second;
243 }
244
245 // Assign ignored uniforms
246 for (const auto &ignoredLocation : ignoredLocations)
247 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400248 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000249 }
250
251 // Automatically assign locations for the rest of the uniforms
252 size_t nextUniformLocation = 0;
253 for (const auto &unlocatedUniform : unlocatedUniforms)
254 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400255 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000256 mUniformLocations[nextUniformLocation].ignored)
257 {
258 nextUniformLocation++;
259 }
260
261 ASSERT(nextUniformLocation < mUniformLocations.size());
262 mUniformLocations[nextUniformLocation] = unlocatedUniform;
263 nextUniformLocation++;
264 }
265
266 return true;
267}
268
269bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
270 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500271 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000272 std::set<GLuint> *reservedLocations,
273 std::set<GLuint> *ignoredLocations,
274 int *maxUniformLocation)
275{
276 for (const LinkedUniform &uniform : mUniforms)
277 {
278 if (uniform.isBuiltIn())
279 {
280 continue;
281 }
282
Olli Etuahod2551232017-10-26 20:03:33 +0300283 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000284 int shaderLocation = uniform.location;
285
286 if (shaderLocation != -1)
287 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300288 unsigned int elementCount = uniform.getBasicTypeElementCount();
289
290 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000291 {
292 // GLSL ES 3.10 section 4.4.3
293 int elementLocation = shaderLocation + arrayIndex;
294 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
295 if (reservedLocations->find(elementLocation) != reservedLocations->end())
296 {
297 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
298 return false;
299 }
300 reservedLocations->insert(elementLocation);
301 if (!uniform.staticUse)
302 {
303 ignoredLocations->insert(elementLocation);
304 }
305 }
306 }
307 else if (apiBoundLocation != -1 && uniform.staticUse)
308 {
309 // Only the first location is reserved even if the uniform is an array.
310 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
311 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
312 {
313 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
314 return false;
315 }
316 reservedLocations->insert(apiBoundLocation);
317 }
318 }
319
320 // Record the uniform locations that were bound using the API for uniforms that were not found
321 // from the shader. Other uniforms should not be assigned to those locations.
322 for (const auto &locationBinding : uniformLocationBindings)
323 {
324 GLuint location = locationBinding.second;
325 if (reservedLocations->find(location) == reservedLocations->end())
326 {
327 ignoredLocations->insert(location);
328 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
329 }
330 }
331
332 return true;
333}
334
335void UniformLinker::pruneUnusedUniforms()
336{
337 auto uniformIter = mUniforms.begin();
338 while (uniformIter != mUniforms.end())
339 {
340 if (uniformIter->staticUse)
341 {
342 ++uniformIter;
343 }
344 else
345 {
346 uniformIter = mUniforms.erase(uniformIter);
347 }
348 }
349}
350
351bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400352 const Context *context,
353 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000354 GLuint maxUniformComponents,
355 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800356 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800357 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000358 const std::string &componentsErrorMessage,
359 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800360 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800361 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000362 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800363 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800364 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000365 InfoLog &infoLog)
366{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800367 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400368 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000369 {
jchen10baf5d942017-08-28 20:45:48 +0800370 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
371 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000372 }
373
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800374 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000375 {
376 infoLog << componentsErrorMessage << maxUniformComponents << ").";
377 return false;
378 }
379
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800380 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000381 {
382 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
383 return false;
384 }
385
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800386 if (shaderUniformCount.imageCount > maxImageUnits)
387 {
388 infoLog << imageErrorMessage << maxImageUnits << ").";
389 return false;
390 }
391
jchen10eaef1e52017-06-13 10:44:11 +0800392 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
393 {
394 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
395 return false;
396 }
397
Olli Etuahob78707c2017-03-09 15:03:11 +0000398 return true;
399}
400
Jamie Madillbd044ed2017-06-05 12:59:21 -0400401bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000402{
403 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800404 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800405 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000406
Jamie Madillbd044ed2017-06-05 12:59:21 -0400407 const Caps &caps = context->getCaps();
408
Olli Etuahob78707c2017-03-09 15:03:11 +0000409 if (mState.getAttachedComputeShader())
410 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400411 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000412
413 // TODO (mradev): check whether we need finer-grained component counting
414 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400415 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800416 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800417 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000418 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
419 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800420 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
421 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
422 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000423 {
424 return false;
425 }
426 }
427 else
428 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400429 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000430
431 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400432 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800433 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800434 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000435 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
436 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800437 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
438 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
439 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000440 {
441 return false;
442 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400443
444 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000445
446 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400447 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800448 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000449 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800450 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
451 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800452 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
453 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000454 {
455 return false;
456 }
457 }
458
459 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800460 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800461 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000462 return true;
463}
464
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800465UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000466 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800467 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800468 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800469 std::vector<LinkedUniform> *atomicCounterUniforms,
470 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000471{
Jamie Madill977abce2017-11-07 08:03:19 -0500472 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800473 ShaderUniformCount shaderUniformCount =
474 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
475 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
476 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000477 if (uniform.staticUse)
478 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800479 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000480 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800481 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000482}
483
Olli Etuaho465835d2017-09-26 13:34:10 +0300484UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
485 const sh::ShaderVariable &uniform,
486 unsigned int arrayNestingIndex,
487 const std::string &namePrefix,
488 const std::string &mappedNamePrefix,
489 std::vector<LinkedUniform> *samplerUniforms,
490 std::vector<LinkedUniform> *imageUniforms,
491 std::vector<LinkedUniform> *atomicCounterUniforms,
492 GLenum shaderType,
493 bool markStaticUse,
494 int binding,
495 int offset,
496 int *location)
497{
498 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
499 // innermost.
500 ShaderUniformCount shaderUniformCount;
501 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
502 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
503 {
504 const std::string elementName = namePrefix + ArrayString(arrayElement);
505 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
506 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
507 {
508 shaderUniformCount += flattenArrayOfStructsUniform(
509 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
510 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
511 location);
512 }
513 else
514 {
515 shaderUniformCount += flattenStructUniform(
516 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
517 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
518 }
519 }
520 return shaderUniformCount;
521}
522
523UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
524 const std::vector<sh::ShaderVariable> &fields,
525 const std::string &namePrefix,
526 const std::string &mappedNamePrefix,
527 std::vector<LinkedUniform> *samplerUniforms,
528 std::vector<LinkedUniform> *imageUniforms,
529 std::vector<LinkedUniform> *atomicCounterUniforms,
530 GLenum shaderType,
531 bool markStaticUse,
532 int binding,
533 int offset,
534 int *location)
535{
536 ShaderUniformCount shaderUniformCount;
537 for (const sh::ShaderVariable &field : fields)
538 {
539 const std::string &fieldName = namePrefix + "." + field.name;
540 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
541
542 shaderUniformCount +=
543 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
544 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
545 }
546 return shaderUniformCount;
547}
548
549UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
550 const sh::ShaderVariable &uniform,
551 const std::string &namePrefix,
552 const std::string &mappedNamePrefix,
553 std::vector<LinkedUniform> *samplerUniforms,
554 std::vector<LinkedUniform> *imageUniforms,
555 std::vector<LinkedUniform> *atomicCounterUniforms,
556 GLenum shaderType,
557 bool markStaticUse,
558 int binding,
559 int offset,
560 int *location)
561{
562 ShaderUniformCount shaderUniformCount;
563
564 ASSERT(uniform.isArray());
565 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
566 ++arrayElement)
567 {
568 sh::ShaderVariable uniformElement = uniform;
569 uniformElement.indexIntoArray(arrayElement);
570 const std::string elementName = namePrefix + ArrayString(arrayElement);
571 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
572
573 shaderUniformCount += flattenUniformImpl(
574 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
575 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
576 }
577 return shaderUniformCount;
578}
579
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800580UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000581 const sh::ShaderVariable &uniform,
582 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300583 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000584 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800585 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800586 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800587 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000588 bool markStaticUse,
589 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800590 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000591 int *location)
592{
593 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800594 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000595
596 if (uniform.isStruct())
597 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300598 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000599 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300600 shaderUniformCount += flattenArrayOfStructsUniform(
601 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
602 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000603 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300604 else
605 {
606 shaderUniformCount += flattenStructUniform(
607 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
608 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
609 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800610 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000611 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300612 if (uniform.isArrayOfArrays())
613 {
614 // GLES 3.1 November 2016 section 7.3.1 page 77:
615 // "For an active variable declared as an array of an aggregate data type (structures or
616 // arrays), a separate entry will be generated for each active array element"
617 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
618 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
619 binding, offset, location);
620 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000621
622 // Not a struct
623 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800624 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800625 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000626 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
627 if (isSampler)
628 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000629 uniformList = samplerUniforms;
630 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800631 else if (isImage)
632 {
633 uniformList = imageUniforms;
634 }
jchen10eaef1e52017-06-13 10:44:11 +0800635 else if (isAtomicCounter)
636 {
637 uniformList = atomicCounterUniforms;
638 }
Olli Etuahod2551232017-10-26 20:03:33 +0300639
640 std::string fullNameWithArrayIndex(fullName);
641 std::string fullMappedNameWithArrayIndex(fullMappedName);
642
643 if (uniform.isArray())
644 {
645 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
646 // and including [0] at the end of array variable names.
647 fullNameWithArrayIndex += "[0]";
648 fullMappedNameWithArrayIndex += "[0]";
649 }
650
651 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000652 if (existingUniform)
653 {
654 if (binding != -1)
655 {
656 existingUniform->binding = binding;
657 }
jchen10eaef1e52017-06-13 10:44:11 +0800658 if (offset != -1)
659 {
660 existingUniform->offset = offset;
661 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000662 if (*location != -1)
663 {
664 existingUniform->location = *location;
665 }
666 if (markStaticUse)
667 {
668 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800669 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000670 }
671 }
672 else
673 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300674 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300675 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300676 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000677 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300678 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
679 linkedUniform.staticUse = markStaticUse;
680 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800681 if (markStaticUse)
682 {
jchen104ef25032017-11-01 09:36:51 +0800683 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800684 }
jchen10eaef1e52017-06-13 10:44:11 +0800685
Olli Etuahob78707c2017-03-09 15:03:11 +0000686 uniformList->push_back(linkedUniform);
687 }
688
Olli Etuaho465835d2017-09-26 13:34:10 +0300689 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
690 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000691
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800692 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800693 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800694 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800695 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500696 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500697 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800698 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000699
700 if (*location != -1)
701 {
702 *location += elementCount;
703 }
704
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800705 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000706}
707
jchen10eaef1e52017-06-13 10:44:11 +0800708bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
709{
710 unsigned int atomicCounterCount = 0;
711 for (const auto &uniform : mUniforms)
712 {
713 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
714 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300715 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800716 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
717 {
718 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
719 << caps.maxCombinedAtomicCounters << ").";
720 return false;
721 }
722 }
723 }
724 return true;
725}
726
Jamie Madill977abce2017-11-07 08:03:19 -0500727// InterfaceBlockLinker implementation.
728InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
729 : mBlocksOut(blocksOut)
730{
731}
732
733InterfaceBlockLinker::~InterfaceBlockLinker()
734{
735}
736
737void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
738 const std::vector<sh::InterfaceBlock> *blocks)
739{
740 mShaderBlocks.push_back(std::make_pair(shader, blocks));
741}
742
743void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
744 const GetBlockMemberInfo &getMemberInfo) const
745{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500746 ASSERT(mBlocksOut->empty());
747
Jamie Madill977abce2017-11-07 08:03:19 -0500748 std::set<std::string> visitedList;
749
750 for (const auto &shaderBlocks : mShaderBlocks)
751 {
752 const GLenum shaderType = shaderBlocks.first;
753
754 for (const auto &block : *shaderBlocks.second)
755 {
756 // Only 'packed' blocks are allowed to be considered inactive.
757 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
758 continue;
759
760 if (visitedList.count(block.name) > 0)
761 {
762 if (block.staticUse)
763 {
764 for (InterfaceBlock &priorBlock : *mBlocksOut)
765 {
766 if (block.name == priorBlock.name)
767 {
768 priorBlock.setStaticUse(shaderType, true);
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800769 // TODO(jiajia.qin@intel.com): update the block members static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500770 }
771 }
772 }
773 }
774 else
775 {
776 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
777 visitedList.insert(block.name);
778 }
779 }
780 }
781}
782
783template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300784void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
785 const VarT &field,
786 unsigned int arrayNestingIndex,
787 const std::string &prefix,
788 const std::string &mappedPrefix,
789 int blockIndex,
790 bool singleEntryForTopLevelArray,
791 int topLevelArraySize) const
792{
793 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
794 // innermost.
795 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
796 if (singleEntryForTopLevelArray)
797 {
798 entryGenerationArraySize = 1;
799 }
800 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
801 {
802 const std::string elementName = prefix + ArrayString(arrayElement);
803 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
804 if (arrayNestingIndex + 1u < field.arraySizes.size())
805 {
806 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
807 elementName, elementMappedName, blockIndex, false,
808 topLevelArraySize);
809 }
810 else
811 {
812 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
813 blockIndex, false, topLevelArraySize);
814 }
815 }
816}
817
818template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500819void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
820 const std::vector<VarT> &fields,
821 const std::string &prefix,
822 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800823 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300824 bool singleEntryForTopLevelArray,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800825 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -0500826{
827 for (const VarT &field : fields)
828 {
829 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500830 std::string fullMappedName =
831 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
832
Olli Etuaho465835d2017-09-26 13:34:10 +0300833 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
834 singleEntryForTopLevelArray, topLevelArraySize);
835 }
836}
837
838template <typename VarT>
839void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
840 const VarT &field,
841 const std::string &fullName,
842 const std::string &fullMappedName,
843 int blockIndex,
844 bool singleEntryForTopLevelArray,
845 int topLevelArraySize) const
846{
847 int nextArraySize = topLevelArraySize;
848 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
849 singleEntryForTopLevelArray)
850 {
851 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
852 // member declared as an array of an aggregate type, an entry will be generated only
853 // for the first array element, regardless of its type.'
854 nextArraySize = field.getOutermostArraySize();
855 }
856
857 if (field.isStruct())
858 {
859 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500860 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300861 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
862 blockIndex, singleEntryForTopLevelArray,
863 nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500864 }
865 else
866 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300867 ASSERT(nextArraySize == topLevelArraySize);
868 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
869 false, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500870 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300871 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500872 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300873 if (field.isArrayOfArrays())
874 {
875 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
876 if (singleEntryForTopLevelArray)
877 {
878 entryGenerationArraySize = 1u;
879 }
880 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
881 ++arrayElement)
882 {
883 VarT fieldElement = field;
884 fieldElement.indexIntoArray(arrayElement);
885 const std::string elementName = fullName + ArrayString(arrayElement);
886 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
887
888 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
889 blockIndex, false, nextArraySize);
890 }
891 return;
892 }
893
894 // If getBlockMemberInfo returns false, the variable is optimized out.
895 sh::BlockMemberInfo memberInfo;
896 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
897 {
898 return;
899 }
900
901 std::string fullNameWithArrayIndex = fullName;
902 std::string fullMappedNameWithArrayIndex = fullMappedName;
903
904 if (field.isArray())
905 {
906 fullNameWithArrayIndex += "[0]";
907 fullMappedNameWithArrayIndex += "[0]";
908 }
909
910 ASSERT(nextArraySize == topLevelArraySize);
911 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex, blockIndex,
912 memberInfo, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500913}
914
915void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
916 const GetBlockMemberInfo &getMemberInfo,
917 const sh::InterfaceBlock &interfaceBlock,
918 GLenum shaderType) const
919{
920 size_t blockSize = 0;
921 std::vector<unsigned int> blockIndexes;
922
923 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800924 // Track the first and last block member index to determine the range of active block members in
925 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500926 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
927 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800928 interfaceBlock.fieldMappedPrefix(), blockIndex,
929 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1);
Jamie Madill977abce2017-11-07 08:03:19 -0500930 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
931
932 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
933 ++blockMemberIndex)
934 {
935 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
936 }
937
Jamie Madill977abce2017-11-07 08:03:19 -0500938 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
939 ++arrayElement)
940 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800941 std::string blockArrayName = interfaceBlock.name;
942 std::string blockMappedArrayName = interfaceBlock.mappedName;
943 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500944 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800945 blockArrayName += ArrayString(arrayElement);
946 blockMappedArrayName += ArrayString(arrayElement);
947 }
Jamie Madill977abce2017-11-07 08:03:19 -0500948
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800949 // Don't define this block at all if it's not active in the implementation.
950 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
951 {
952 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500953 }
954
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800955 // ESSL 3.10 section 4.4.4 page 58:
956 // Any uniform or shader storage block declared without a binding qualifier is initially
957 // assigned to block binding point zero.
958 int blockBinding =
959 (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
Jamie Madill977abce2017-11-07 08:03:19 -0500960 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
Jiajia Qinfeb2c632017-12-08 17:59:19 +0800961 interfaceBlock.isArray(), arrayElement, blockBinding);
Jamie Madill977abce2017-11-07 08:03:19 -0500962 block.memberIndexes = blockIndexes;
963 block.setStaticUse(shaderType, interfaceBlock.staticUse);
964
965 // Since all block elements in an array share the same active interface blocks, they
966 // will all be active once any block member is used. So, since interfaceBlock.name[0]
967 // was active, here we will add every block element in the array.
968 block.dataSize = static_cast<unsigned int>(blockSize);
969 mBlocksOut->push_back(block);
970 }
971}
972
973// UniformBlockLinker implementation.
974UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
975 std::vector<LinkedUniform> *uniformsOut)
976 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
977{
978}
979
980UniformBlockLinker::~UniformBlockLinker()
981{
982}
983
Olli Etuaho465835d2017-09-26 13:34:10 +0300984void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
985 const std::string &fullName,
986 const std::string &fullMappedName,
987 int blockIndex,
988 const sh::BlockMemberInfo &memberInfo,
989 int /*topLevelArraySize*/) const
Jamie Madill977abce2017-11-07 08:03:19 -0500990{
Olli Etuaho465835d2017-09-26 13:34:10 +0300991 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -0500992 blockIndex, memberInfo);
993 newUniform.mappedName = fullMappedName;
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800994 // TODO(jiajia.qin@intel.com): update the block memeber static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500995
996 // Since block uniforms have no location, we don't need to store them in the uniform locations
997 // list.
998 mUniformsOut->push_back(newUniform);
999}
1000
1001size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1002{
1003 return mUniformsOut->size();
1004}
1005
1006// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001007ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1008 std::vector<BufferVariable> *bufferVariablesOut)
1009 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001010{
1011}
1012
1013ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1014{
1015}
1016
Olli Etuaho465835d2017-09-26 13:34:10 +03001017void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1018 const std::string &fullName,
1019 const std::string &fullMappedName,
1020 int blockIndex,
1021 const sh::BlockMemberInfo &memberInfo,
1022 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -05001023{
Olli Etuaho465835d2017-09-26 13:34:10 +03001024 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001025 blockIndex, memberInfo);
1026 newBufferVariable.mappedName = fullMappedName;
1027 // TODO(jiajia.qin@intel.com): update the block memeber static use.
1028
1029 newBufferVariable.topLevelArraySize = topLevelArraySize;
1030
1031 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001032}
1033
1034size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1035{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001036 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001037}
1038
Jiajia Qin94f1e892017-11-20 12:14:32 +08001039// AtomicCounterBufferLinker implementation.
1040AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1041 std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1042 : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1043{
1044}
1045
1046AtomicCounterBufferLinker::~AtomicCounterBufferLinker()
1047{
1048}
1049
1050void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1051{
1052 for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1053 {
1054 auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1055 ASSERT(bufferSize != sizeMap.end());
1056 atomicCounterBuffer.dataSize = bufferSize->second;
1057 }
1058}
1059
Olli Etuahob78707c2017-03-09 15:03:11 +00001060} // namespace gl