blob: bcd2e05ff3541961414e839abc7b11c0b5a0f07b [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);
Jamie Madillbd044ed2017-06-05 12:59:21 -040073 if (!validateVertexAndFragmentUniforms(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
Jamie Madillbd044ed2017-06-05 12:59:21 -040099bool UniformLinker::validateVertexAndFragmentUniforms(const Context *context,
100 InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +0000101{
102 // Check that uniforms defined in the vertex and fragment shaders are identical
Olli Etuaho465835d2017-09-26 13:34:10 +0300103 std::map<std::string, sh::Uniform> linkedUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000104 const std::vector<sh::Uniform> &vertexUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400105 mState.getAttachedVertexShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000106 const std::vector<sh::Uniform> &fragmentUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -0400107 mState.getAttachedFragmentShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +0000108
109 for (const sh::Uniform &vertexUniform : vertexUniforms)
110 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300111 linkedUniforms[vertexUniform.name] = vertexUniform;
Olli Etuahob78707c2017-03-09 15:03:11 +0000112 }
113
114 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
115 {
116 auto entry = linkedUniforms.find(fragmentUniform.name);
117 if (entry != linkedUniforms.end())
118 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300119 const sh::Uniform &linkedUniform = entry->second;
120 const std::string &uniformName = "uniform '" + linkedUniform.name + "'";
121 if (!linkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform))
Olli Etuahob78707c2017-03-09 15:03:11 +0000122 {
123 return false;
124 }
125 }
126 }
127 return true;
128}
129
130// GLSL ES Spec 3.00.3, section 4.3.5.
131bool UniformLinker::linkValidateUniforms(InfoLog &infoLog,
132 const std::string &uniformName,
133 const sh::Uniform &vertexUniform,
134 const sh::Uniform &fragmentUniform)
135{
136#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
137 const bool validatePrecision = true;
138#else
139 const bool validatePrecision = false;
140#endif
141
142 if (!Program::linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
143 validatePrecision))
144 {
145 return false;
146 }
147
148 // GLSL ES Spec 3.10.4, section 4.4.5.
149 if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
150 vertexUniform.binding != fragmentUniform.binding)
151 {
152 infoLog << "Binding layout qualifiers for " << uniformName
153 << " differ between vertex and fragment shaders.";
154 return false;
155 }
156
157 // GLSL ES Spec 3.10.4, section 9.2.1.
158 if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
159 vertexUniform.location != fragmentUniform.location)
160 {
161 infoLog << "Location layout qualifiers for " << uniformName
162 << " differ between vertex and fragment shaders.";
163 return false;
164 }
jchen10eaef1e52017-06-13 10:44:11 +0800165 if (vertexUniform.offset != fragmentUniform.offset)
166 {
167 infoLog << "Offset layout qualifiers for " << uniformName
168 << " differ between vertex and fragment shaders.";
169 return false;
170 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000171
172 return true;
173}
174
Jamie Madill3c1da042017-11-27 18:33:40 -0500175bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
Olli Etuahob78707c2017-03-09 15:03:11 +0000176{
177 // All the locations where another uniform can't be located.
178 std::set<GLuint> reservedLocations;
179 // Locations which have been allocated for an unused uniform.
180 std::set<GLuint> ignoredLocations;
181
182 int maxUniformLocation = -1;
183
184 // Gather uniform locations that have been set either using the bindUniformLocation API or by
185 // using a location layout qualifier and check conflicts between them.
186 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
187 &reservedLocations, &ignoredLocations,
188 &maxUniformLocation))
189 {
190 return false;
191 }
192
193 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
194 // the line relies on only having statically used uniforms in mUniforms.
195 pruneUnusedUniforms();
196
197 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
198 std::vector<VariableLocation> unlocatedUniforms;
199 std::map<GLuint, VariableLocation> preLocatedUniforms;
200
201 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
202 {
203 const LinkedUniform &uniform = mUniforms[uniformIndex];
204
jchen10baf5d942017-08-28 20:45:48 +0800205 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000206 {
207 continue;
208 }
209
Olli Etuahod2551232017-10-26 20:03:33 +0300210 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000211 int shaderLocation = uniform.location;
212
213 if (shaderLocation != -1)
214 {
215 preSetLocation = shaderLocation;
216 }
217
Olli Etuaho465835d2017-09-26 13:34:10 +0300218 unsigned int elementCount = uniform.getBasicTypeElementCount();
219 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000220 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400221 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000222
223 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
224 {
225 int elementLocation = preSetLocation + arrayIndex;
226 preLocatedUniforms[elementLocation] = location;
227 }
228 else
229 {
230 unlocatedUniforms.push_back(location);
231 }
232 }
233 }
234
235 // Make enough space for all uniforms, with pre-set locations or not.
236 mUniformLocations.resize(
237 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
238 static_cast<size_t>(maxUniformLocation + 1)));
239
240 // Assign uniforms with pre-set locations
241 for (const auto &uniform : preLocatedUniforms)
242 {
243 mUniformLocations[uniform.first] = uniform.second;
244 }
245
246 // Assign ignored uniforms
247 for (const auto &ignoredLocation : ignoredLocations)
248 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400249 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000250 }
251
252 // Automatically assign locations for the rest of the uniforms
253 size_t nextUniformLocation = 0;
254 for (const auto &unlocatedUniform : unlocatedUniforms)
255 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400256 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000257 mUniformLocations[nextUniformLocation].ignored)
258 {
259 nextUniformLocation++;
260 }
261
262 ASSERT(nextUniformLocation < mUniformLocations.size());
263 mUniformLocations[nextUniformLocation] = unlocatedUniform;
264 nextUniformLocation++;
265 }
266
267 return true;
268}
269
270bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
271 InfoLog &infoLog,
Jamie Madill3c1da042017-11-27 18:33:40 -0500272 const ProgramBindings &uniformLocationBindings,
Olli Etuahob78707c2017-03-09 15:03:11 +0000273 std::set<GLuint> *reservedLocations,
274 std::set<GLuint> *ignoredLocations,
275 int *maxUniformLocation)
276{
277 for (const LinkedUniform &uniform : mUniforms)
278 {
279 if (uniform.isBuiltIn())
280 {
281 continue;
282 }
283
Olli Etuahod2551232017-10-26 20:03:33 +0300284 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000285 int shaderLocation = uniform.location;
286
287 if (shaderLocation != -1)
288 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300289 unsigned int elementCount = uniform.getBasicTypeElementCount();
290
291 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000292 {
293 // GLSL ES 3.10 section 4.4.3
294 int elementLocation = shaderLocation + arrayIndex;
295 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
296 if (reservedLocations->find(elementLocation) != reservedLocations->end())
297 {
298 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
299 return false;
300 }
301 reservedLocations->insert(elementLocation);
302 if (!uniform.staticUse)
303 {
304 ignoredLocations->insert(elementLocation);
305 }
306 }
307 }
308 else if (apiBoundLocation != -1 && uniform.staticUse)
309 {
310 // Only the first location is reserved even if the uniform is an array.
311 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
312 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
313 {
314 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
315 return false;
316 }
317 reservedLocations->insert(apiBoundLocation);
318 }
319 }
320
321 // Record the uniform locations that were bound using the API for uniforms that were not found
322 // from the shader. Other uniforms should not be assigned to those locations.
323 for (const auto &locationBinding : uniformLocationBindings)
324 {
325 GLuint location = locationBinding.second;
326 if (reservedLocations->find(location) == reservedLocations->end())
327 {
328 ignoredLocations->insert(location);
329 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
330 }
331 }
332
333 return true;
334}
335
336void UniformLinker::pruneUnusedUniforms()
337{
338 auto uniformIter = mUniforms.begin();
339 while (uniformIter != mUniforms.end())
340 {
341 if (uniformIter->staticUse)
342 {
343 ++uniformIter;
344 }
345 else
346 {
347 uniformIter = mUniforms.erase(uniformIter);
348 }
349 }
350}
351
352bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400353 const Context *context,
354 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000355 GLuint maxUniformComponents,
356 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800357 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800358 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000359 const std::string &componentsErrorMessage,
360 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800361 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800362 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000363 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800364 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800365 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000366 InfoLog &infoLog)
367{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800368 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400369 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000370 {
jchen10baf5d942017-08-28 20:45:48 +0800371 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
372 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000373 }
374
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800375 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000376 {
377 infoLog << componentsErrorMessage << maxUniformComponents << ").";
378 return false;
379 }
380
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800381 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000382 {
383 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
384 return false;
385 }
386
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800387 if (shaderUniformCount.imageCount > maxImageUnits)
388 {
389 infoLog << imageErrorMessage << maxImageUnits << ").";
390 return false;
391 }
392
jchen10eaef1e52017-06-13 10:44:11 +0800393 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
394 {
395 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
396 return false;
397 }
398
Olli Etuahob78707c2017-03-09 15:03:11 +0000399 return true;
400}
401
Jamie Madillbd044ed2017-06-05 12:59:21 -0400402bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000403{
404 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800405 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800406 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000407
Jamie Madillbd044ed2017-06-05 12:59:21 -0400408 const Caps &caps = context->getCaps();
409
Olli Etuahob78707c2017-03-09 15:03:11 +0000410 if (mState.getAttachedComputeShader())
411 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400412 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000413
414 // TODO (mradev): check whether we need finer-grained component counting
415 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400416 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800417 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800418 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000419 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
420 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800421 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
422 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
423 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000424 {
425 return false;
426 }
427 }
428 else
429 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400430 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000431
432 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400433 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800434 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800435 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000436 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
437 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800438 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
439 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
440 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000441 {
442 return false;
443 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400444
445 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000446
447 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400448 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800449 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000450 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800451 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
452 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800453 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
454 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000455 {
456 return false;
457 }
458 }
459
460 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800461 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800462 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000463 return true;
464}
465
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800466UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000467 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800468 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800469 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800470 std::vector<LinkedUniform> *atomicCounterUniforms,
471 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000472{
Jamie Madill977abce2017-11-07 08:03:19 -0500473 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800474 ShaderUniformCount shaderUniformCount =
475 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
476 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
477 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000478 if (uniform.staticUse)
479 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000481 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800482 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000483}
484
Olli Etuaho465835d2017-09-26 13:34:10 +0300485UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
486 const sh::ShaderVariable &uniform,
487 unsigned int arrayNestingIndex,
488 const std::string &namePrefix,
489 const std::string &mappedNamePrefix,
490 std::vector<LinkedUniform> *samplerUniforms,
491 std::vector<LinkedUniform> *imageUniforms,
492 std::vector<LinkedUniform> *atomicCounterUniforms,
493 GLenum shaderType,
494 bool markStaticUse,
495 int binding,
496 int offset,
497 int *location)
498{
499 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
500 // innermost.
501 ShaderUniformCount shaderUniformCount;
502 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
503 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
504 {
505 const std::string elementName = namePrefix + ArrayString(arrayElement);
506 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
507 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
508 {
509 shaderUniformCount += flattenArrayOfStructsUniform(
510 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
511 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
512 location);
513 }
514 else
515 {
516 shaderUniformCount += flattenStructUniform(
517 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
518 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
519 }
520 }
521 return shaderUniformCount;
522}
523
524UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
525 const std::vector<sh::ShaderVariable> &fields,
526 const std::string &namePrefix,
527 const std::string &mappedNamePrefix,
528 std::vector<LinkedUniform> *samplerUniforms,
529 std::vector<LinkedUniform> *imageUniforms,
530 std::vector<LinkedUniform> *atomicCounterUniforms,
531 GLenum shaderType,
532 bool markStaticUse,
533 int binding,
534 int offset,
535 int *location)
536{
537 ShaderUniformCount shaderUniformCount;
538 for (const sh::ShaderVariable &field : fields)
539 {
540 const std::string &fieldName = namePrefix + "." + field.name;
541 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
542
543 shaderUniformCount +=
544 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
545 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
546 }
547 return shaderUniformCount;
548}
549
550UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
551 const sh::ShaderVariable &uniform,
552 const std::string &namePrefix,
553 const std::string &mappedNamePrefix,
554 std::vector<LinkedUniform> *samplerUniforms,
555 std::vector<LinkedUniform> *imageUniforms,
556 std::vector<LinkedUniform> *atomicCounterUniforms,
557 GLenum shaderType,
558 bool markStaticUse,
559 int binding,
560 int offset,
561 int *location)
562{
563 ShaderUniformCount shaderUniformCount;
564
565 ASSERT(uniform.isArray());
566 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
567 ++arrayElement)
568 {
569 sh::ShaderVariable uniformElement = uniform;
570 uniformElement.indexIntoArray(arrayElement);
571 const std::string elementName = namePrefix + ArrayString(arrayElement);
572 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
573
574 shaderUniformCount += flattenUniformImpl(
575 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
576 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
577 }
578 return shaderUniformCount;
579}
580
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800581UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000582 const sh::ShaderVariable &uniform,
583 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300584 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000585 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800586 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800587 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800588 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000589 bool markStaticUse,
590 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800591 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000592 int *location)
593{
594 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800595 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000596
597 if (uniform.isStruct())
598 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300599 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000600 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300601 shaderUniformCount += flattenArrayOfStructsUniform(
602 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
603 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000604 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300605 else
606 {
607 shaderUniformCount += flattenStructUniform(
608 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
609 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
610 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800611 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000612 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300613 if (uniform.isArrayOfArrays())
614 {
615 // GLES 3.1 November 2016 section 7.3.1 page 77:
616 // "For an active variable declared as an array of an aggregate data type (structures or
617 // arrays), a separate entry will be generated for each active array element"
618 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
619 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
620 binding, offset, location);
621 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000622
623 // Not a struct
624 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800625 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800626 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000627 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
628 if (isSampler)
629 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000630 uniformList = samplerUniforms;
631 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800632 else if (isImage)
633 {
634 uniformList = imageUniforms;
635 }
jchen10eaef1e52017-06-13 10:44:11 +0800636 else if (isAtomicCounter)
637 {
638 uniformList = atomicCounterUniforms;
639 }
Olli Etuahod2551232017-10-26 20:03:33 +0300640
641 std::string fullNameWithArrayIndex(fullName);
642 std::string fullMappedNameWithArrayIndex(fullMappedName);
643
644 if (uniform.isArray())
645 {
646 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
647 // and including [0] at the end of array variable names.
648 fullNameWithArrayIndex += "[0]";
649 fullMappedNameWithArrayIndex += "[0]";
650 }
651
652 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000653 if (existingUniform)
654 {
655 if (binding != -1)
656 {
657 existingUniform->binding = binding;
658 }
jchen10eaef1e52017-06-13 10:44:11 +0800659 if (offset != -1)
660 {
661 existingUniform->offset = offset;
662 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000663 if (*location != -1)
664 {
665 existingUniform->location = *location;
666 }
667 if (markStaticUse)
668 {
669 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800670 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000671 }
672 }
673 else
674 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300675 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300676 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300677 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000678 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300679 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
680 linkedUniform.staticUse = markStaticUse;
681 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800682 if (markStaticUse)
683 {
jchen104ef25032017-11-01 09:36:51 +0800684 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800685 }
jchen10eaef1e52017-06-13 10:44:11 +0800686
Olli Etuahob78707c2017-03-09 15:03:11 +0000687 uniformList->push_back(linkedUniform);
688 }
689
Olli Etuaho465835d2017-09-26 13:34:10 +0300690 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
691 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000692
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800693 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800694 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800695 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800696 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500697 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500698 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800699 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000700
701 if (*location != -1)
702 {
703 *location += elementCount;
704 }
705
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800706 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000707}
708
jchen10eaef1e52017-06-13 10:44:11 +0800709bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
710{
711 unsigned int atomicCounterCount = 0;
712 for (const auto &uniform : mUniforms)
713 {
714 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
715 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300716 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800717 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
718 {
719 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
720 << caps.maxCombinedAtomicCounters << ").";
721 return false;
722 }
723 }
724 }
725 return true;
726}
727
Jamie Madill977abce2017-11-07 08:03:19 -0500728// InterfaceBlockLinker implementation.
729InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
730 : mBlocksOut(blocksOut)
731{
732}
733
734InterfaceBlockLinker::~InterfaceBlockLinker()
735{
736}
737
738void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
739 const std::vector<sh::InterfaceBlock> *blocks)
740{
741 mShaderBlocks.push_back(std::make_pair(shader, blocks));
742}
743
744void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
745 const GetBlockMemberInfo &getMemberInfo) const
746{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500747 ASSERT(mBlocksOut->empty());
748
Jamie Madill977abce2017-11-07 08:03:19 -0500749 std::set<std::string> visitedList;
750
751 for (const auto &shaderBlocks : mShaderBlocks)
752 {
753 const GLenum shaderType = shaderBlocks.first;
754
755 for (const auto &block : *shaderBlocks.second)
756 {
757 // Only 'packed' blocks are allowed to be considered inactive.
758 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
759 continue;
760
761 if (visitedList.count(block.name) > 0)
762 {
763 if (block.staticUse)
764 {
765 for (InterfaceBlock &priorBlock : *mBlocksOut)
766 {
767 if (block.name == priorBlock.name)
768 {
769 priorBlock.setStaticUse(shaderType, true);
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800770 // TODO(jiajia.qin@intel.com): update the block members static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500771 }
772 }
773 }
774 }
775 else
776 {
777 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
778 visitedList.insert(block.name);
779 }
780 }
781 }
782}
783
784template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300785void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
786 const VarT &field,
787 unsigned int arrayNestingIndex,
788 const std::string &prefix,
789 const std::string &mappedPrefix,
790 int blockIndex,
791 bool singleEntryForTopLevelArray,
792 int topLevelArraySize) const
793{
794 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
795 // innermost.
796 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
797 if (singleEntryForTopLevelArray)
798 {
799 entryGenerationArraySize = 1;
800 }
801 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
802 {
803 const std::string elementName = prefix + ArrayString(arrayElement);
804 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
805 if (arrayNestingIndex + 1u < field.arraySizes.size())
806 {
807 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
808 elementName, elementMappedName, blockIndex, false,
809 topLevelArraySize);
810 }
811 else
812 {
813 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
814 blockIndex, false, topLevelArraySize);
815 }
816 }
817}
818
819template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500820void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
821 const std::vector<VarT> &fields,
822 const std::string &prefix,
823 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800824 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300825 bool singleEntryForTopLevelArray,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800826 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -0500827{
828 for (const VarT &field : fields)
829 {
830 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500831 std::string fullMappedName =
832 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
833
Olli Etuaho465835d2017-09-26 13:34:10 +0300834 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
835 singleEntryForTopLevelArray, topLevelArraySize);
836 }
837}
838
839template <typename VarT>
840void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
841 const VarT &field,
842 const std::string &fullName,
843 const std::string &fullMappedName,
844 int blockIndex,
845 bool singleEntryForTopLevelArray,
846 int topLevelArraySize) const
847{
848 int nextArraySize = topLevelArraySize;
849 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
850 singleEntryForTopLevelArray)
851 {
852 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
853 // member declared as an array of an aggregate type, an entry will be generated only
854 // for the first array element, regardless of its type.'
855 nextArraySize = field.getOutermostArraySize();
856 }
857
858 if (field.isStruct())
859 {
860 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500861 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300862 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
863 blockIndex, singleEntryForTopLevelArray,
864 nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500865 }
866 else
867 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300868 ASSERT(nextArraySize == topLevelArraySize);
869 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
870 false, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500871 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300872 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500873 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300874 if (field.isArrayOfArrays())
875 {
876 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
877 if (singleEntryForTopLevelArray)
878 {
879 entryGenerationArraySize = 1u;
880 }
881 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
882 ++arrayElement)
883 {
884 VarT fieldElement = field;
885 fieldElement.indexIntoArray(arrayElement);
886 const std::string elementName = fullName + ArrayString(arrayElement);
887 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
888
889 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
890 blockIndex, false, nextArraySize);
891 }
892 return;
893 }
894
895 // If getBlockMemberInfo returns false, the variable is optimized out.
896 sh::BlockMemberInfo memberInfo;
897 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
898 {
899 return;
900 }
901
902 std::string fullNameWithArrayIndex = fullName;
903 std::string fullMappedNameWithArrayIndex = fullMappedName;
904
905 if (field.isArray())
906 {
907 fullNameWithArrayIndex += "[0]";
908 fullMappedNameWithArrayIndex += "[0]";
909 }
910
911 ASSERT(nextArraySize == topLevelArraySize);
912 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex, blockIndex,
913 memberInfo, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500914}
915
916void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
917 const GetBlockMemberInfo &getMemberInfo,
918 const sh::InterfaceBlock &interfaceBlock,
919 GLenum shaderType) const
920{
921 size_t blockSize = 0;
922 std::vector<unsigned int> blockIndexes;
923
924 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800925 // Track the first and last block member index to determine the range of active block members in
926 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500927 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
928 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800929 interfaceBlock.fieldMappedPrefix(), blockIndex,
930 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1);
Jamie Madill977abce2017-11-07 08:03:19 -0500931 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
932
933 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
934 ++blockMemberIndex)
935 {
936 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
937 }
938
939 // ESSL 3.10 section 4.4.4 page 58:
940 // Any uniform or shader storage block declared without a binding qualifier is initially
941 // assigned to block binding point zero.
942 int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
943 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
944 ++arrayElement)
945 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800946 std::string blockArrayName = interfaceBlock.name;
947 std::string blockMappedArrayName = interfaceBlock.mappedName;
948 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500949 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800950 blockArrayName += ArrayString(arrayElement);
951 blockMappedArrayName += ArrayString(arrayElement);
952 }
Jamie Madill977abce2017-11-07 08:03:19 -0500953
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800954 // Don't define this block at all if it's not active in the implementation.
955 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
956 {
957 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500958 }
959
960 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
961 interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement);
962 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