blob: 5787c2b2732b0f34a7081b0addb02f6bf57c53fb [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
103 std::map<std::string, LinkedUniform> linkedUniforms;
104 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 {
111 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
112 }
113
114 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
115 {
116 auto entry = linkedUniforms.find(fragmentUniform.name);
117 if (entry != linkedUniforms.end())
118 {
119 LinkedUniform *linkedUniform = &entry->second;
120 const std::string &uniformName = "uniform '" + linkedUniform->name + "'";
121 if (!linkValidateUniforms(infoLog, uniformName, *linkedUniform, fragmentUniform))
122 {
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
219 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
220 {
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,
272 const Program::Bindings &uniformLocationBindings,
273 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 {
289 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
290 {
291 // GLSL ES 3.10 section 4.4.3
292 int elementLocation = shaderLocation + arrayIndex;
293 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
294 if (reservedLocations->find(elementLocation) != reservedLocations->end())
295 {
296 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
297 return false;
298 }
299 reservedLocations->insert(elementLocation);
300 if (!uniform.staticUse)
301 {
302 ignoredLocations->insert(elementLocation);
303 }
304 }
305 }
306 else if (apiBoundLocation != -1 && uniform.staticUse)
307 {
308 // Only the first location is reserved even if the uniform is an array.
309 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
310 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
311 {
312 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
313 return false;
314 }
315 reservedLocations->insert(apiBoundLocation);
316 }
317 }
318
319 // Record the uniform locations that were bound using the API for uniforms that were not found
320 // from the shader. Other uniforms should not be assigned to those locations.
321 for (const auto &locationBinding : uniformLocationBindings)
322 {
323 GLuint location = locationBinding.second;
324 if (reservedLocations->find(location) == reservedLocations->end())
325 {
326 ignoredLocations->insert(location);
327 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
328 }
329 }
330
331 return true;
332}
333
334void UniformLinker::pruneUnusedUniforms()
335{
336 auto uniformIter = mUniforms.begin();
337 while (uniformIter != mUniforms.end())
338 {
339 if (uniformIter->staticUse)
340 {
341 ++uniformIter;
342 }
343 else
344 {
345 uniformIter = mUniforms.erase(uniformIter);
346 }
347 }
348}
349
350bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400351 const Context *context,
352 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000353 GLuint maxUniformComponents,
354 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800355 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800356 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000357 const std::string &componentsErrorMessage,
358 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800359 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800360 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000361 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800362 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800363 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000364 InfoLog &infoLog)
365{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800366 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400367 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000368 {
jchen10baf5d942017-08-28 20:45:48 +0800369 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
370 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000371 }
372
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800373 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000374 {
375 infoLog << componentsErrorMessage << maxUniformComponents << ").";
376 return false;
377 }
378
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800379 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000380 {
381 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
382 return false;
383 }
384
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800385 if (shaderUniformCount.imageCount > maxImageUnits)
386 {
387 infoLog << imageErrorMessage << maxImageUnits << ").";
388 return false;
389 }
390
jchen10eaef1e52017-06-13 10:44:11 +0800391 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
392 {
393 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
394 return false;
395 }
396
Olli Etuahob78707c2017-03-09 15:03:11 +0000397 return true;
398}
399
Jamie Madillbd044ed2017-06-05 12:59:21 -0400400bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000401{
402 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800403 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800404 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000405
Jamie Madillbd044ed2017-06-05 12:59:21 -0400406 const Caps &caps = context->getCaps();
407
Olli Etuahob78707c2017-03-09 15:03:11 +0000408 if (mState.getAttachedComputeShader())
409 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400410 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000411
412 // TODO (mradev): check whether we need finer-grained component counting
413 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400414 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800415 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800416 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000417 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
418 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800419 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
420 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
421 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000422 {
423 return false;
424 }
425 }
426 else
427 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400428 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000429
430 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400431 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800432 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800433 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000434 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
435 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800436 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
437 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
438 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000439 {
440 return false;
441 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400442
443 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000444
445 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400446 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800447 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000448 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800449 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
450 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800451 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
452 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000453 {
454 return false;
455 }
456 }
457
458 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800459 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800460 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000461 return true;
462}
463
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800464UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000465 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800466 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800467 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800468 std::vector<LinkedUniform> *atomicCounterUniforms,
469 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000470{
Jamie Madill977abce2017-11-07 08:03:19 -0500471 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800472 ShaderUniformCount shaderUniformCount =
473 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
474 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
475 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000476 if (uniform.staticUse)
477 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800478 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000479 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000481}
482
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800483UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000484 const sh::ShaderVariable &uniform,
485 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300486 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000487 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800488 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800489 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800490 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000491 bool markStaticUse,
492 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800493 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000494 int *location)
495{
496 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800497 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000498
499 if (uniform.isStruct())
500 {
501 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
502 {
503 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
504
505 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
506 {
507 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
508 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
Olli Etuaho855d9642017-05-17 14:05:06 +0300509 const std::string &fieldFullMappedName =
510 (fullMappedName + elementString + "." + field.mappedName);
Olli Etuahob78707c2017-03-09 15:03:11 +0000511
Olli Etuaho855d9642017-05-17 14:05:06 +0300512 shaderUniformCount += flattenUniformImpl(
513 field, fieldFullName, fieldFullMappedName, samplerUniforms, imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800514 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000515 }
516 }
517
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800518 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000519 }
520
521 // Not a struct
522 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800523 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800524 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000525 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
526 if (isSampler)
527 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000528 uniformList = samplerUniforms;
529 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800530 else if (isImage)
531 {
532 uniformList = imageUniforms;
533 }
jchen10eaef1e52017-06-13 10:44:11 +0800534 else if (isAtomicCounter)
535 {
536 uniformList = atomicCounterUniforms;
537 }
Olli Etuahod2551232017-10-26 20:03:33 +0300538
539 std::string fullNameWithArrayIndex(fullName);
540 std::string fullMappedNameWithArrayIndex(fullMappedName);
541
542 if (uniform.isArray())
543 {
544 // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
545 // and including [0] at the end of array variable names.
546 fullNameWithArrayIndex += "[0]";
547 fullMappedNameWithArrayIndex += "[0]";
548 }
549
550 LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
Olli Etuahob78707c2017-03-09 15:03:11 +0000551 if (existingUniform)
552 {
553 if (binding != -1)
554 {
555 existingUniform->binding = binding;
556 }
jchen10eaef1e52017-06-13 10:44:11 +0800557 if (offset != -1)
558 {
559 existingUniform->offset = offset;
560 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000561 if (*location != -1)
562 {
563 existingUniform->location = *location;
564 }
565 if (markStaticUse)
566 {
567 existingUniform->staticUse = true;
jchen104ef25032017-11-01 09:36:51 +0800568 existingUniform->setStaticUse(shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000569 }
570 }
571 else
572 {
Olli Etuahod2551232017-10-26 20:03:33 +0300573 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
574 uniform.arraySize, binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000575 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuahod2551232017-10-26 20:03:33 +0300576 linkedUniform.mappedName = fullMappedNameWithArrayIndex;
Jamie Madill7af0de52017-11-06 17:09:33 -0500577 linkedUniform.staticUse = markStaticUse;
jchen10baf5d942017-08-28 20:45:48 +0800578 if (markStaticUse)
579 {
jchen104ef25032017-11-01 09:36:51 +0800580 linkedUniform.setStaticUse(shaderType, true);
jchen10baf5d942017-08-28 20:45:48 +0800581 }
jchen10eaef1e52017-06-13 10:44:11 +0800582
Olli Etuahob78707c2017-03-09 15:03:11 +0000583 uniformList->push_back(linkedUniform);
584 }
585
586 unsigned int elementCount = uniform.elementCount();
587
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800588 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800589 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800590 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800591 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Jamie Madill7af0de52017-11-06 17:09:33 -0500592 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
Jamie Madill977abce2017-11-07 08:03:19 -0500593 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800594 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000595
596 if (*location != -1)
597 {
598 *location += elementCount;
599 }
600
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800601 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000602}
603
jchen10eaef1e52017-06-13 10:44:11 +0800604bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
605{
606 unsigned int atomicCounterCount = 0;
607 for (const auto &uniform : mUniforms)
608 {
609 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
610 {
611 atomicCounterCount += uniform.elementCount();
612 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
613 {
614 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
615 << caps.maxCombinedAtomicCounters << ").";
616 return false;
617 }
618 }
619 }
620 return true;
621}
622
Jamie Madill977abce2017-11-07 08:03:19 -0500623// InterfaceBlockLinker implementation.
624InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
625 : mBlocksOut(blocksOut)
626{
627}
628
629InterfaceBlockLinker::~InterfaceBlockLinker()
630{
631}
632
633void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
634 const std::vector<sh::InterfaceBlock> *blocks)
635{
636 mShaderBlocks.push_back(std::make_pair(shader, blocks));
637}
638
639void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
640 const GetBlockMemberInfo &getMemberInfo) const
641{
Jamie Madill6db1c2e2017-11-08 09:17:40 -0500642 ASSERT(mBlocksOut->empty());
643
Jamie Madill977abce2017-11-07 08:03:19 -0500644 std::set<std::string> visitedList;
645
646 for (const auto &shaderBlocks : mShaderBlocks)
647 {
648 const GLenum shaderType = shaderBlocks.first;
649
650 for (const auto &block : *shaderBlocks.second)
651 {
652 // Only 'packed' blocks are allowed to be considered inactive.
653 if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
654 continue;
655
656 if (visitedList.count(block.name) > 0)
657 {
658 if (block.staticUse)
659 {
660 for (InterfaceBlock &priorBlock : *mBlocksOut)
661 {
662 if (block.name == priorBlock.name)
663 {
664 priorBlock.setStaticUse(shaderType, true);
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800665 // TODO(jiajia.qin@intel.com): update the block members static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500666 }
667 }
668 }
669 }
670 else
671 {
672 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
673 visitedList.insert(block.name);
674 }
675 }
676 }
677}
678
679template <typename VarT>
680void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
681 const std::vector<VarT> &fields,
682 const std::string &prefix,
683 const std::string &mappedPrefix,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800684 int blockIndex,
685 bool outsideTopLevelArray,
686 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -0500687{
688 for (const VarT &field : fields)
689 {
690 std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
691
692 std::string fullMappedName =
693 (mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
694
695 if (field.isStruct())
696 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800697 int nextArraySize = topLevelArraySize;
698 unsigned int elementCount = field.elementCount();
699
700 if (outsideTopLevelArray)
701 {
702 nextArraySize = elementCount;
703 // In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
704 // member declared as an array of an aggregate type, an entry will be generated only
705 // for the first array element, regardless of its type.'
706 elementCount = 1;
707 }
708
709 for (unsigned int arrayElement = 0; arrayElement < elementCount; arrayElement++)
Jamie Madill977abce2017-11-07 08:03:19 -0500710 {
711 const std::string elementName =
712 fullName + (field.isArray() ? ArrayString(arrayElement) : "");
713 const std::string elementMappedName =
714 fullMappedName + (field.isArray() ? ArrayString(arrayElement) : "");
715 defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800716 blockIndex, false, nextArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500717 }
718 }
719 else
720 {
721 // If getBlockMemberInfo returns false, the variable is optimized out.
722 sh::BlockMemberInfo memberInfo;
723 if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
724 {
725 continue;
726 }
727
728 if (field.isArray())
729 {
730 fullName += "[0]";
731 fullMappedName += "[0]";
732 }
733
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800734 defineBlockMember(field, fullName, fullMappedName, blockIndex, memberInfo,
735 topLevelArraySize);
Jamie Madill977abce2017-11-07 08:03:19 -0500736 }
737 }
738}
739
740void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
741 const GetBlockMemberInfo &getMemberInfo,
742 const sh::InterfaceBlock &interfaceBlock,
743 GLenum shaderType) const
744{
745 size_t blockSize = 0;
746 std::vector<unsigned int> blockIndexes;
747
748 int blockIndex = static_cast<int>(mBlocksOut->size());
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800749 // Track the first and last block member index to determine the range of active block members in
750 // the block.
Jamie Madill977abce2017-11-07 08:03:19 -0500751 size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
752 defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800753 interfaceBlock.fieldMappedPrefix(), blockIndex,
754 interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1);
Jamie Madill977abce2017-11-07 08:03:19 -0500755 size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
756
757 for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
758 ++blockMemberIndex)
759 {
760 blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
761 }
762
763 // ESSL 3.10 section 4.4.4 page 58:
764 // Any uniform or shader storage block declared without a binding qualifier is initially
765 // assigned to block binding point zero.
766 int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
767 for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
768 ++arrayElement)
769 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800770 std::string blockArrayName = interfaceBlock.name;
771 std::string blockMappedArrayName = interfaceBlock.mappedName;
772 if (interfaceBlock.isArray())
Jamie Madill977abce2017-11-07 08:03:19 -0500773 {
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800774 blockArrayName += ArrayString(arrayElement);
775 blockMappedArrayName += ArrayString(arrayElement);
776 }
Jamie Madill977abce2017-11-07 08:03:19 -0500777
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800778 // Don't define this block at all if it's not active in the implementation.
779 if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
780 {
781 continue;
Jamie Madill977abce2017-11-07 08:03:19 -0500782 }
783
784 InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
785 interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement);
786 block.memberIndexes = blockIndexes;
787 block.setStaticUse(shaderType, interfaceBlock.staticUse);
788
789 // Since all block elements in an array share the same active interface blocks, they
790 // will all be active once any block member is used. So, since interfaceBlock.name[0]
791 // was active, here we will add every block element in the array.
792 block.dataSize = static_cast<unsigned int>(blockSize);
793 mBlocksOut->push_back(block);
794 }
795}
796
797// UniformBlockLinker implementation.
798UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
799 std::vector<LinkedUniform> *uniformsOut)
800 : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
801{
802}
803
804UniformBlockLinker::~UniformBlockLinker()
805{
806}
807
808void UniformBlockLinker::defineBlockMember(const sh::ShaderVariable &field,
809 const std::string &fullName,
810 const std::string &fullMappedName,
811 int blockIndex,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800812 const sh::BlockMemberInfo &memberInfo,
813 int /* topLevelArraySize */) const
Jamie Madill977abce2017-11-07 08:03:19 -0500814{
815 LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1, -1,
816 blockIndex, memberInfo);
817 newUniform.mappedName = fullMappedName;
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800818 // TODO(jiajia.qin@intel.com): update the block memeber static use.
Jamie Madill977abce2017-11-07 08:03:19 -0500819
820 // Since block uniforms have no location, we don't need to store them in the uniform locations
821 // list.
822 mUniformsOut->push_back(newUniform);
823}
824
825size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
826{
827 return mUniformsOut->size();
828}
829
830// ShaderStorageBlockLinker implementation.
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800831ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut,
832 std::vector<BufferVariable> *bufferVariablesOut)
833 : InterfaceBlockLinker(blocksOut), mBufferVariablesOut(bufferVariablesOut)
Jamie Madill977abce2017-11-07 08:03:19 -0500834{
835}
836
837ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
838{
839}
840
841void ShaderStorageBlockLinker::defineBlockMember(const sh::ShaderVariable &field,
842 const std::string &fullName,
843 const std::string &fullMappedName,
844 int blockIndex,
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800845 const sh::BlockMemberInfo &memberInfo,
846 int topLevelArraySize) const
Jamie Madill977abce2017-11-07 08:03:19 -0500847{
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800848 BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySize,
849 blockIndex, memberInfo);
850 newBufferVariable.mappedName = fullMappedName;
851 // TODO(jiajia.qin@intel.com): update the block memeber static use.
852
853 newBufferVariable.topLevelArraySize = topLevelArraySize;
854
855 mBufferVariablesOut->push_back(newBufferVariable);
Jamie Madill977abce2017-11-07 08:03:19 -0500856}
857
858size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
859{
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800860 return mBufferVariablesOut->size();
Jamie Madill977abce2017-11-07 08:03:19 -0500861}
862
Olli Etuahob78707c2017-03-09 15:03:11 +0000863} // namespace gl