blob: a33f7515259e190c7bfe5c3ef40016a0b95e15a8 [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
Olli Etuahod2551232017-10-26 20:03:33 +030037int GetUniformLocationBinding(const Program::Bindings &uniformLocationBindings,
38 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,
Olli Etuahob78707c2017-03-09 15:03:11 +000068 const Program::Bindings &uniformLocationBindings)
69{
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
175bool UniformLinker::indexUniforms(InfoLog &infoLog,
176 const Program::Bindings &uniformLocationBindings)
177{
178 // All the locations where another uniform can't be located.
179 std::set<GLuint> reservedLocations;
180 // Locations which have been allocated for an unused uniform.
181 std::set<GLuint> ignoredLocations;
182
183 int maxUniformLocation = -1;
184
185 // Gather uniform locations that have been set either using the bindUniformLocation API or by
186 // using a location layout qualifier and check conflicts between them.
187 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
188 &reservedLocations, &ignoredLocations,
189 &maxUniformLocation))
190 {
191 return false;
192 }
193
194 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
195 // the line relies on only having statically used uniforms in mUniforms.
196 pruneUnusedUniforms();
197
198 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
199 std::vector<VariableLocation> unlocatedUniforms;
200 std::map<GLuint, VariableLocation> preLocatedUniforms;
201
202 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
203 {
204 const LinkedUniform &uniform = mUniforms[uniformIndex];
205
jchen10baf5d942017-08-28 20:45:48 +0800206 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000207 {
208 continue;
209 }
210
Olli Etuahod2551232017-10-26 20:03:33 +0300211 int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000212 int shaderLocation = uniform.location;
213
214 if (shaderLocation != -1)
215 {
216 preSetLocation = shaderLocation;
217 }
218
Olli Etuaho465835d2017-09-26 13:34:10 +0300219 unsigned int elementCount = uniform.getBasicTypeElementCount();
220 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000221 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400222 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000223
224 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
225 {
226 int elementLocation = preSetLocation + arrayIndex;
227 preLocatedUniforms[elementLocation] = location;
228 }
229 else
230 {
231 unlocatedUniforms.push_back(location);
232 }
233 }
234 }
235
236 // Make enough space for all uniforms, with pre-set locations or not.
237 mUniformLocations.resize(
238 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
239 static_cast<size_t>(maxUniformLocation + 1)));
240
241 // Assign uniforms with pre-set locations
242 for (const auto &uniform : preLocatedUniforms)
243 {
244 mUniformLocations[uniform.first] = uniform.second;
245 }
246
247 // Assign ignored uniforms
248 for (const auto &ignoredLocation : ignoredLocations)
249 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400250 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000251 }
252
253 // Automatically assign locations for the rest of the uniforms
254 size_t nextUniformLocation = 0;
255 for (const auto &unlocatedUniform : unlocatedUniforms)
256 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400257 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000258 mUniformLocations[nextUniformLocation].ignored)
259 {
260 nextUniformLocation++;
261 }
262
263 ASSERT(nextUniformLocation < mUniformLocations.size());
264 mUniformLocations[nextUniformLocation] = unlocatedUniform;
265 nextUniformLocation++;
266 }
267
268 return true;
269}
270
271bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
272 InfoLog &infoLog,
273 const Program::Bindings &uniformLocationBindings,
274 std::set<GLuint> *reservedLocations,
275 std::set<GLuint> *ignoredLocations,
276 int *maxUniformLocation)
277{
278 for (const LinkedUniform &uniform : mUniforms)
279 {
280 if (uniform.isBuiltIn())
281 {
282 continue;
283 }
284
Olli Etuahod2551232017-10-26 20:03:33 +0300285 int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
Olli Etuahob78707c2017-03-09 15:03:11 +0000286 int shaderLocation = uniform.location;
287
288 if (shaderLocation != -1)
289 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300290 unsigned int elementCount = uniform.getBasicTypeElementCount();
291
292 for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
Olli Etuahob78707c2017-03-09 15:03:11 +0000293 {
294 // GLSL ES 3.10 section 4.4.3
295 int elementLocation = shaderLocation + arrayIndex;
296 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
297 if (reservedLocations->find(elementLocation) != reservedLocations->end())
298 {
299 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
300 return false;
301 }
302 reservedLocations->insert(elementLocation);
303 if (!uniform.staticUse)
304 {
305 ignoredLocations->insert(elementLocation);
306 }
307 }
308 }
309 else if (apiBoundLocation != -1 && uniform.staticUse)
310 {
311 // Only the first location is reserved even if the uniform is an array.
312 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
313 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
314 {
315 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
316 return false;
317 }
318 reservedLocations->insert(apiBoundLocation);
319 }
320 }
321
322 // Record the uniform locations that were bound using the API for uniforms that were not found
323 // from the shader. Other uniforms should not be assigned to those locations.
324 for (const auto &locationBinding : uniformLocationBindings)
325 {
326 GLuint location = locationBinding.second;
327 if (reservedLocations->find(location) == reservedLocations->end())
328 {
329 ignoredLocations->insert(location);
330 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
331 }
332 }
333
334 return true;
335}
336
337void UniformLinker::pruneUnusedUniforms()
338{
339 auto uniformIter = mUniforms.begin();
340 while (uniformIter != mUniforms.end())
341 {
342 if (uniformIter->staticUse)
343 {
344 ++uniformIter;
345 }
346 else
347 {
348 uniformIter = mUniforms.erase(uniformIter);
349 }
350 }
351}
352
353bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400354 const Context *context,
355 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000356 GLuint maxUniformComponents,
357 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800358 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800359 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000360 const std::string &componentsErrorMessage,
361 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800362 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800363 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000364 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800365 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800366 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000367 InfoLog &infoLog)
368{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800369 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400370 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000371 {
jchen10baf5d942017-08-28 20:45:48 +0800372 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
373 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000374 }
375
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800376 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000377 {
378 infoLog << componentsErrorMessage << maxUniformComponents << ").";
379 return false;
380 }
381
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800382 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000383 {
384 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
385 return false;
386 }
387
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800388 if (shaderUniformCount.imageCount > maxImageUnits)
389 {
390 infoLog << imageErrorMessage << maxImageUnits << ").";
391 return false;
392 }
393
jchen10eaef1e52017-06-13 10:44:11 +0800394 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
395 {
396 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
397 return false;
398 }
399
Olli Etuahob78707c2017-03-09 15:03:11 +0000400 return true;
401}
402
Jamie Madillbd044ed2017-06-05 12:59:21 -0400403bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000404{
405 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800406 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800407 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000408
Jamie Madillbd044ed2017-06-05 12:59:21 -0400409 const Caps &caps = context->getCaps();
410
Olli Etuahob78707c2017-03-09 15:03:11 +0000411 if (mState.getAttachedComputeShader())
412 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400413 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000414
415 // TODO (mradev): check whether we need finer-grained component counting
416 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400417 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800418 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800419 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000420 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
421 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800422 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
423 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
424 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000425 {
426 return false;
427 }
428 }
429 else
430 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400431 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000432
433 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400434 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800435 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800436 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000437 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
438 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800439 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
440 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
441 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000442 {
443 return false;
444 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400445
446 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000447
448 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400449 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800450 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000451 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800452 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
453 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800454 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
455 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000456 {
457 return false;
458 }
459 }
460
461 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800462 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800463 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000464 return true;
465}
466
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800467UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000468 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800469 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800470 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800471 std::vector<LinkedUniform> *atomicCounterUniforms,
472 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000473{
Jamie Madill977abce2017-11-07 08:03:19 -0500474 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800475 ShaderUniformCount shaderUniformCount =
476 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
477 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
478 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000479 if (uniform.staticUse)
480 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800481 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000482 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800483 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000484}
485
Olli Etuaho465835d2017-09-26 13:34:10 +0300486UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
487 const sh::ShaderVariable &uniform,
488 unsigned int arrayNestingIndex,
489 const std::string &namePrefix,
490 const std::string &mappedNamePrefix,
491 std::vector<LinkedUniform> *samplerUniforms,
492 std::vector<LinkedUniform> *imageUniforms,
493 std::vector<LinkedUniform> *atomicCounterUniforms,
494 GLenum shaderType,
495 bool markStaticUse,
496 int binding,
497 int offset,
498 int *location)
499{
500 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
501 // innermost.
502 ShaderUniformCount shaderUniformCount;
503 const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
504 for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
505 {
506 const std::string elementName = namePrefix + ArrayString(arrayElement);
507 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
508 if (arrayNestingIndex + 1u < uniform.arraySizes.size())
509 {
510 shaderUniformCount += flattenArrayOfStructsUniform(
511 uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
512 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse, binding, offset,
513 location);
514 }
515 else
516 {
517 shaderUniformCount += flattenStructUniform(
518 uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
519 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
520 }
521 }
522 return shaderUniformCount;
523}
524
525UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
526 const std::vector<sh::ShaderVariable> &fields,
527 const std::string &namePrefix,
528 const std::string &mappedNamePrefix,
529 std::vector<LinkedUniform> *samplerUniforms,
530 std::vector<LinkedUniform> *imageUniforms,
531 std::vector<LinkedUniform> *atomicCounterUniforms,
532 GLenum shaderType,
533 bool markStaticUse,
534 int binding,
535 int offset,
536 int *location)
537{
538 ShaderUniformCount shaderUniformCount;
539 for (const sh::ShaderVariable &field : fields)
540 {
541 const std::string &fieldName = namePrefix + "." + field.name;
542 const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
543
544 shaderUniformCount +=
545 flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
546 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
547 }
548 return shaderUniformCount;
549}
550
551UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
552 const sh::ShaderVariable &uniform,
553 const std::string &namePrefix,
554 const std::string &mappedNamePrefix,
555 std::vector<LinkedUniform> *samplerUniforms,
556 std::vector<LinkedUniform> *imageUniforms,
557 std::vector<LinkedUniform> *atomicCounterUniforms,
558 GLenum shaderType,
559 bool markStaticUse,
560 int binding,
561 int offset,
562 int *location)
563{
564 ShaderUniformCount shaderUniformCount;
565
566 ASSERT(uniform.isArray());
567 for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
568 ++arrayElement)
569 {
570 sh::ShaderVariable uniformElement = uniform;
571 uniformElement.indexIntoArray(arrayElement);
572 const std::string elementName = namePrefix + ArrayString(arrayElement);
573 const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
574
575 shaderUniformCount += flattenUniformImpl(
576 uniformElement, elementName, elementMappedName, samplerUniforms, imageUniforms,
577 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
578 }
579 return shaderUniformCount;
580}
581
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800582UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000583 const sh::ShaderVariable &uniform,
584 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300585 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000586 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800587 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800588 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800589 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000590 bool markStaticUse,
591 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800592 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000593 int *location)
594{
595 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800596 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000597
598 if (uniform.isStruct())
599 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300600 if (uniform.isArray())
Olli Etuahob78707c2017-03-09 15:03:11 +0000601 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300602 shaderUniformCount += flattenArrayOfStructsUniform(
603 uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
604 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000605 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300606 else
607 {
608 shaderUniformCount += flattenStructUniform(
609 uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
610 atomicCounterUniforms, shaderType, markStaticUse, binding, offset, location);
611 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800612 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000613 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300614 if (uniform.isArrayOfArrays())
615 {
616 // GLES 3.1 November 2016 section 7.3.1 page 77:
617 // "For an active variable declared as an array of an aggregate data type (structures or
618 // arrays), a separate entry will be generated for each active array element"
619 return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
620 imageUniforms, atomicCounterUniforms, shaderType, markStaticUse,
621 binding, offset, location);
622 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000623
624 // Not a struct
625 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800626 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800627 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000628 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
629 if (isSampler)
630 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000631 uniformList = samplerUniforms;
632 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800633 else if (isImage)
634 {
635 uniformList = imageUniforms;
636 }
jchen10eaef1e52017-06-13 10:44:11 +0800637 else if (isAtomicCounter)
638 {
639 uniformList = atomicCounterUniforms;
640 }
Olli Etuahod2551232017-10-26 20:03:33 +0300641
642 std::string fullNameWithArrayIndex(fullName);
643 std::string fullMappedNameWithArrayIndex(fullMappedName);
644
645 if (uniform.isArray())
646 {
647 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
648 // and including [0] at the end of array variable names.
649 fullNameWithArrayIndex += "[0]";
650 fullMappedNameWithArrayIndex += "[0]";
651 }
652
653 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000654 if (existingUniform)
655 {
656 if (binding != -1)
657 {
658 existingUniform->binding = binding;
659 }
jchen10eaef1e52017-06-13 10:44:11 +0800660 if (offset != -1)
661 {
662 existingUniform->offset = offset;
663 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000664 if (*location != -1)
665 {
666 existingUniform->location = *location;
667 }
668 if (markStaticUse)
669 {
670 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800671 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000672 }
673 }
674 else
675 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300676 ASSERT(uniform.arraySizes.size() <= 1u);
Olli Etuahod2551232017-10-26 20:03:33 +0300677 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300678 uniform.arraySizes, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000679 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho465835d2017-09-26 13:34:10 +0300680 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
681 linkedUniform.staticUse = markStaticUse;
682 linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
jchen10baf5d942017-08-28 20:45:48 +0800683 if (markStaticUse)
684 {
jchen104ef25032017-11-01 09:36:51 +0800685 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800686 }
jchen10eaef1e52017-06-13 10:44:11 +0800687
Olli Etuahob78707c2017-03-09 15:03:11 +0000688 uniformList->push_back(linkedUniform);
689 }
690
Olli Etuaho465835d2017-09-26 13:34:10 +0300691 // Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
692 unsigned int elementCount = uniform.getBasicTypeElementCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000693
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800694 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800695 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800696 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800697 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500698 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500699 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800700 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000701
702 if (*location != -1)
703 {
704 *location += elementCount;
705 }
706
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800707 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000708}
709
jchen10eaef1e52017-06-13 10:44:11 +0800710bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
711{
712 unsigned int atomicCounterCount = 0;
713 for (const auto &uniform : mUniforms)
714 {
715 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
716 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300717 atomicCounterCount += uniform.getBasicTypeElementCount();
jchen10eaef1e52017-06-13 10:44:11 +0800718 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
719 {
720 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
721 << caps.maxCombinedAtomicCounters << ").";
722 return false;
723 }
724 }
725 }
726 return true;
727}
728
Jamie Madill977abce2017-11-07 08:03:19 -0500729// InterfaceBlockLinker implementation.
730InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
731 : mBlocksOut(blocksOut)
732{
733}
734
735InterfaceBlockLinker::~InterfaceBlockLinker()
736{
737}
738
739void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
740 const std::vector<sh::InterfaceBlock> *blocks)
741{
742 mShaderBlocks.push_back(std::make_pair(shader, blocks));
743}
744
745void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
746 const GetBlockMemberInfo &getMemberInfo) const
747{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500748 ASSERT(mBlocksOut->empty());
749
Jamie Madill977abce2017-11-07 08:03:19 -0500750 std::set<std::string> visitedList;
751
752 for (const auto &shaderBlocks : mShaderBlocks)
753 {
754 const GLenum shaderType = shaderBlocks.first;
755
756 for (const auto &block : *shaderBlocks.second)
757 {
758 // Only 'packed' blocks are allowed to be considered inactive.
759 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
760 continue;
761
762 if (visitedList.count(block.name) > 0)
763 {
764 if (block.staticUse)
765 {
766 for (InterfaceBlock &priorBlock : *mBlocksOut)
767 {
768 if (block.name == priorBlock.name)
769 {
770 priorBlock.setStaticUse(shaderType, true);
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800771 // TODO(jiajia.qin@intel.com): update the block members static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500772 }
773 }
774 }
775 }
776 else
777 {
778 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
779 visitedList.insert(block.name);
780 }
781 }
782 }
783}
784
785template <typename VarT>
Olli Etuaho465835d2017-09-26 13:34:10 +0300786void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
787 const VarT &field,
788 unsigned int arrayNestingIndex,
789 const std::string &prefix,
790 const std::string &mappedPrefix,
791 int blockIndex,
792 bool singleEntryForTopLevelArray,
793 int topLevelArraySize) const
794{
795 // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
796 // innermost.
797 unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
798 if (singleEntryForTopLevelArray)
799 {
800 entryGenerationArraySize = 1;
801 }
802 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
803 {
804 const std::string elementName = prefix + ArrayString(arrayElement);
805 const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
806 if (arrayNestingIndex + 1u < field.arraySizes.size())
807 {
808 defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
809 elementName, elementMappedName, blockIndex, false,
810 topLevelArraySize);
811 }
812 else
813 {
814 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
815 blockIndex, false, topLevelArraySize);
816 }
817 }
818}
819
820template <typename VarT>
Jamie Madill977abce2017-11-07 08:03:19 -0500821void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
822 const std::vector<VarT> &fields,
823 const std::string &prefix,
824 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800825 int blockIndex,
Olli Etuaho465835d2017-09-26 13:34:10 +0300826 bool singleEntryForTopLevelArray,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800827 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -0500828{
829 for (const VarT &field : fields)
830 {
831 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
Jamie Madill977abce2017-11-07 08:03:19 -0500832 std::string fullMappedName =
833 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
834
Olli Etuaho465835d2017-09-26 13:34:10 +0300835 defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
836 singleEntryForTopLevelArray, topLevelArraySize);
837 }
838}
839
840template <typename VarT>
841void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
842 const VarT &field,
843 const std::string &fullName,
844 const std::string &fullMappedName,
845 int blockIndex,
846 bool singleEntryForTopLevelArray,
847 int topLevelArraySize) const
848{
849 int nextArraySize = topLevelArraySize;
850 if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
851 singleEntryForTopLevelArray)
852 {
853 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
854 // member declared as an array of an aggregate type, an entry will be generated only
855 // for the first array element, regardless of its type.'
856 nextArraySize = field.getOutermostArraySize();
857 }
858
859 if (field.isStruct())
860 {
861 if (field.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500862 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300863 defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
864 blockIndex, singleEntryForTopLevelArray,
865 nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500866 }
867 else
868 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300869 ASSERT(nextArraySize == topLevelArraySize);
870 defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
871 false, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500872 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300873 return;
Jamie Madill977abce2017-11-07 08:03:19 -0500874 }
Olli Etuaho465835d2017-09-26 13:34:10 +0300875 if (field.isArrayOfArrays())
876 {
877 unsigned int entryGenerationArraySize = field.getOutermostArraySize();
878 if (singleEntryForTopLevelArray)
879 {
880 entryGenerationArraySize = 1u;
881 }
882 for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
883 ++arrayElement)
884 {
885 VarT fieldElement = field;
886 fieldElement.indexIntoArray(arrayElement);
887 const std::string elementName = fullName + ArrayString(arrayElement);
888 const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
889
890 defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
891 blockIndex, false, nextArraySize);
892 }
893 return;
894 }
895
896 // If getBlockMemberInfo returns false, the variable is optimized out.
897 sh::BlockMemberInfo memberInfo;
898 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
899 {
900 return;
901 }
902
903 std::string fullNameWithArrayIndex = fullName;
904 std::string fullMappedNameWithArrayIndex = fullMappedName;
905
906 if (field.isArray())
907 {
908 fullNameWithArrayIndex += "[0]";
909 fullMappedNameWithArrayIndex += "[0]";
910 }
911
912 ASSERT(nextArraySize == topLevelArraySize);
913 defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex, blockIndex,
914 memberInfo, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500915}
916
917void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
918 const GetBlockMemberInfo &getMemberInfo,
919 const sh::InterfaceBlock &interfaceBlock,
920 GLenum shaderType) const
921{
922 size_t blockSize = 0;
923 std::vector<unsigned int> blockIndexes;
924
925 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800926 // Track the first and last block member index to determine the range of active block members in
927 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500928 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
929 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800930 interfaceBlock.fieldMappedPrefix(), blockIndex,
931 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1);
Jamie Madill977abce2017-11-07 08:03:19 -0500932 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
933
934 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
935 ++blockMemberIndex)
936 {
937 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
938 }
939
940 // ESSL 3.10 section 4.4.4 page 58:
941 // Any uniform or shader storage block declared without a binding qualifier is initially
942 // assigned to block binding point zero.
943 int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
944 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
945 ++arrayElement)
946 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800947 std::string blockArrayName = interfaceBlock.name;
948 std::string blockMappedArrayName = interfaceBlock.mappedName;
949 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500950 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800951 blockArrayName += ArrayString(arrayElement);
952 blockMappedArrayName += ArrayString(arrayElement);
953 }
Jamie Madill977abce2017-11-07 08:03:19 -0500954
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800955 // Don't define this block at all if it's not active in the implementation.
956 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
957 {
958 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500959 }
960
961 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
962 interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement);
963 block.memberIndexes = blockIndexes;
964 block.setStaticUse(shaderType, interfaceBlock.staticUse);
965
966 // Since all block elements in an array share the same active interface blocks, they
967 // will all be active once any block member is used. So, since interfaceBlock.name[0]
968 // was active, here we will add every block element in the array.
969 block.dataSize = static_cast<unsigned int>(blockSize);
970 mBlocksOut->push_back(block);
971 }
972}
973
974// UniformBlockLinker implementation.
975UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
976 std::vector<LinkedUniform> *uniformsOut)
977 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
978{
979}
980
981UniformBlockLinker::~UniformBlockLinker()
982{
983}
984
Olli Etuaho465835d2017-09-26 13:34:10 +0300985void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
986 const std::string &fullName,
987 const std::string &fullMappedName,
988 int blockIndex,
989 const sh::BlockMemberInfo &memberInfo,
990 int /*topLevelArraySize*/) const
Jamie Madill977abce2017-11-07 08:03:19 -0500991{
Olli Etuaho465835d2017-09-26 13:34:10 +0300992 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
Jamie Madill977abce2017-11-07 08:03:19 -0500993 blockIndex, memberInfo);
994 newUniform.mappedName = fullMappedName;
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800995 // TODO(jiajia.qin@intel.com): update the block memeber static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500996
997 // Since block uniforms have no location, we don't need to store them in the uniform locations
998 // list.
999 mUniformsOut->push_back(newUniform);
1000}
1001
1002size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1003{
1004 return mUniformsOut->size();
1005}
1006
1007// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001008ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1009 std::vector<BufferVariable> *bufferVariablesOut)
1010 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -05001011{
1012}
1013
1014ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
1015{
1016}
1017
Olli Etuaho465835d2017-09-26 13:34:10 +03001018void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
1019 const std::string &fullName,
1020 const std::string &fullMappedName,
1021 int blockIndex,
1022 const sh::BlockMemberInfo &memberInfo,
1023 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -05001024{
Olli Etuaho465835d2017-09-26 13:34:10 +03001025 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001026 blockIndex, memberInfo);
1027 newBufferVariable.mappedName = fullMappedName;
1028 // TODO(jiajia.qin@intel.com): update the block memeber static use.
1029
1030 newBufferVariable.topLevelArraySize = topLevelArraySize;
1031
1032 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -05001033}
1034
1035size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1036{
Jiajia Qin3a9090f2017-09-27 14:37:04 +08001037 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -05001038}
1039
Olli Etuahob78707c2017-03-09 15:03:11 +00001040} // namespace gl