blob: f60897f1698ede70cf3b989d6b91b768237c1120 [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
11#include "libANGLE/UniformLinker.h"
12
13#include "common/utilities.h"
14#include "libANGLE/Caps.h"
Jamie Madillbd044ed2017-06-05 12:59:21 -040015#include "libANGLE/Context.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000016#include "libANGLE/Shader.h"
Jiawei-Shaoddb5eb52017-03-14 13:36:18 +080017#include "libANGLE/features.h"
Olli Etuahob78707c2017-03-09 15:03:11 +000018
19namespace gl
20{
21
22namespace
23{
24
25LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
26{
27 for (LinkedUniform &uniform : list)
28 {
29 if (uniform.name == name)
30 return &uniform;
31 }
32
33 return nullptr;
34}
35
36} // anonymouse namespace
37
38UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
39{
40}
41
42void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
43 std::vector<VariableLocation> *uniformLocations)
44{
45 uniforms->swap(mUniforms);
46 uniformLocations->swap(mUniformLocations);
47}
48
Jamie Madillbd044ed2017-06-05 12:59:21 -040049bool UniformLinker::link(const Context *context,
50 InfoLog &infoLog,
Olli Etuahob78707c2017-03-09 15:03:11 +000051 const Program::Bindings &uniformLocationBindings)
52{
53 if (mState.getAttachedVertexShader() && mState.getAttachedFragmentShader())
54 {
55 ASSERT(mState.getAttachedComputeShader() == nullptr);
Jamie Madillbd044ed2017-06-05 12:59:21 -040056 if (!validateVertexAndFragmentUniforms(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000057 {
58 return false;
59 }
60 }
61
62 // Flatten the uniforms list (nested fields) into a simple list (no nesting).
63 // Also check the maximum uniform vector and sampler counts.
Jamie Madillbd044ed2017-06-05 12:59:21 -040064 if (!flattenUniformsAndCheckCaps(context, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +000065 {
66 return false;
67 }
68
jchen10eaef1e52017-06-13 10:44:11 +080069 if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
70 {
71 return false;
72 }
73
Olli Etuahob78707c2017-03-09 15:03:11 +000074 if (!indexUniforms(infoLog, uniformLocationBindings))
75 {
76 return false;
77 }
78
79 return true;
80}
81
Jamie Madillbd044ed2017-06-05 12:59:21 -040082bool UniformLinker::validateVertexAndFragmentUniforms(const Context *context,
83 InfoLog &infoLog) const
Olli Etuahob78707c2017-03-09 15:03:11 +000084{
85 // Check that uniforms defined in the vertex and fragment shaders are identical
86 std::map<std::string, LinkedUniform> linkedUniforms;
87 const std::vector<sh::Uniform> &vertexUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -040088 mState.getAttachedVertexShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +000089 const std::vector<sh::Uniform> &fragmentUniforms =
Jamie Madillbd044ed2017-06-05 12:59:21 -040090 mState.getAttachedFragmentShader()->getUniforms(context);
Olli Etuahob78707c2017-03-09 15:03:11 +000091
92 for (const sh::Uniform &vertexUniform : vertexUniforms)
93 {
94 linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
95 }
96
97 for (const sh::Uniform &fragmentUniform : fragmentUniforms)
98 {
99 auto entry = linkedUniforms.find(fragmentUniform.name);
100 if (entry != linkedUniforms.end())
101 {
102 LinkedUniform *linkedUniform = &entry->second;
103 const std::string &uniformName = "uniform '" + linkedUniform->name + "'";
104 if (!linkValidateUniforms(infoLog, uniformName, *linkedUniform, fragmentUniform))
105 {
106 return false;
107 }
108 }
109 }
110 return true;
111}
112
113// GLSL ES Spec 3.00.3, section 4.3.5.
114bool UniformLinker::linkValidateUniforms(InfoLog &infoLog,
115 const std::string &uniformName,
116 const sh::Uniform &vertexUniform,
117 const sh::Uniform &fragmentUniform)
118{
119#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
120 const bool validatePrecision = true;
121#else
122 const bool validatePrecision = false;
123#endif
124
125 if (!Program::linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
126 validatePrecision))
127 {
128 return false;
129 }
130
131 // GLSL ES Spec 3.10.4, section 4.4.5.
132 if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
133 vertexUniform.binding != fragmentUniform.binding)
134 {
135 infoLog << "Binding layout qualifiers for " << uniformName
136 << " differ between vertex and fragment shaders.";
137 return false;
138 }
139
140 // GLSL ES Spec 3.10.4, section 9.2.1.
141 if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
142 vertexUniform.location != fragmentUniform.location)
143 {
144 infoLog << "Location layout qualifiers for " << uniformName
145 << " differ between vertex and fragment shaders.";
146 return false;
147 }
jchen10eaef1e52017-06-13 10:44:11 +0800148 if (vertexUniform.offset != fragmentUniform.offset)
149 {
150 infoLog << "Offset layout qualifiers for " << uniformName
151 << " differ between vertex and fragment shaders.";
152 return false;
153 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000154
155 return true;
156}
157
158bool UniformLinker::indexUniforms(InfoLog &infoLog,
159 const Program::Bindings &uniformLocationBindings)
160{
161 // All the locations where another uniform can't be located.
162 std::set<GLuint> reservedLocations;
163 // Locations which have been allocated for an unused uniform.
164 std::set<GLuint> ignoredLocations;
165
166 int maxUniformLocation = -1;
167
168 // Gather uniform locations that have been set either using the bindUniformLocation API or by
169 // using a location layout qualifier and check conflicts between them.
170 if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
171 &reservedLocations, &ignoredLocations,
172 &maxUniformLocation))
173 {
174 return false;
175 }
176
177 // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
178 // the line relies on only having statically used uniforms in mUniforms.
179 pruneUnusedUniforms();
180
181 // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
182 std::vector<VariableLocation> unlocatedUniforms;
183 std::map<GLuint, VariableLocation> preLocatedUniforms;
184
185 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
186 {
187 const LinkedUniform &uniform = mUniforms[uniformIndex];
188
jchen10baf5d942017-08-28 20:45:48 +0800189 if (uniform.isBuiltIn() || IsAtomicCounterType(uniform.type))
Olli Etuahob78707c2017-03-09 15:03:11 +0000190 {
191 continue;
192 }
193
194 int preSetLocation = uniformLocationBindings.getBinding(uniform.name);
195 int shaderLocation = uniform.location;
196
197 if (shaderLocation != -1)
198 {
199 preSetLocation = shaderLocation;
200 }
201
202 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
203 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400204 VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
Olli Etuahob78707c2017-03-09 15:03:11 +0000205
206 if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
207 {
208 int elementLocation = preSetLocation + arrayIndex;
209 preLocatedUniforms[elementLocation] = location;
210 }
211 else
212 {
213 unlocatedUniforms.push_back(location);
214 }
215 }
216 }
217
218 // Make enough space for all uniforms, with pre-set locations or not.
219 mUniformLocations.resize(
220 std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
221 static_cast<size_t>(maxUniformLocation + 1)));
222
223 // Assign uniforms with pre-set locations
224 for (const auto &uniform : preLocatedUniforms)
225 {
226 mUniformLocations[uniform.first] = uniform.second;
227 }
228
229 // Assign ignored uniforms
230 for (const auto &ignoredLocation : ignoredLocations)
231 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400232 mUniformLocations[ignoredLocation].markIgnored();
Olli Etuahob78707c2017-03-09 15:03:11 +0000233 }
234
235 // Automatically assign locations for the rest of the uniforms
236 size_t nextUniformLocation = 0;
237 for (const auto &unlocatedUniform : unlocatedUniforms)
238 {
Jamie Madillfb997ec2017-09-20 15:44:27 -0400239 while (mUniformLocations[nextUniformLocation].used() ||
Olli Etuahob78707c2017-03-09 15:03:11 +0000240 mUniformLocations[nextUniformLocation].ignored)
241 {
242 nextUniformLocation++;
243 }
244
245 ASSERT(nextUniformLocation < mUniformLocations.size());
246 mUniformLocations[nextUniformLocation] = unlocatedUniform;
247 nextUniformLocation++;
248 }
249
250 return true;
251}
252
253bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
254 InfoLog &infoLog,
255 const Program::Bindings &uniformLocationBindings,
256 std::set<GLuint> *reservedLocations,
257 std::set<GLuint> *ignoredLocations,
258 int *maxUniformLocation)
259{
260 for (const LinkedUniform &uniform : mUniforms)
261 {
262 if (uniform.isBuiltIn())
263 {
264 continue;
265 }
266
267 int apiBoundLocation = uniformLocationBindings.getBinding(uniform.name);
268 int shaderLocation = uniform.location;
269
270 if (shaderLocation != -1)
271 {
272 for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
273 {
274 // GLSL ES 3.10 section 4.4.3
275 int elementLocation = shaderLocation + arrayIndex;
276 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
277 if (reservedLocations->find(elementLocation) != reservedLocations->end())
278 {
279 infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
280 return false;
281 }
282 reservedLocations->insert(elementLocation);
283 if (!uniform.staticUse)
284 {
285 ignoredLocations->insert(elementLocation);
286 }
287 }
288 }
289 else if (apiBoundLocation != -1 && uniform.staticUse)
290 {
291 // Only the first location is reserved even if the uniform is an array.
292 *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
293 if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
294 {
295 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
296 return false;
297 }
298 reservedLocations->insert(apiBoundLocation);
299 }
300 }
301
302 // Record the uniform locations that were bound using the API for uniforms that were not found
303 // from the shader. Other uniforms should not be assigned to those locations.
304 for (const auto &locationBinding : uniformLocationBindings)
305 {
306 GLuint location = locationBinding.second;
307 if (reservedLocations->find(location) == reservedLocations->end())
308 {
309 ignoredLocations->insert(location);
310 *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
311 }
312 }
313
314 return true;
315}
316
317void UniformLinker::pruneUnusedUniforms()
318{
319 auto uniformIter = mUniforms.begin();
320 while (uniformIter != mUniforms.end())
321 {
322 if (uniformIter->staticUse)
323 {
324 ++uniformIter;
325 }
326 else
327 {
328 uniformIter = mUniforms.erase(uniformIter);
329 }
330 }
331}
332
333bool UniformLinker::flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400334 const Context *context,
335 Shader *shader,
Olli Etuahob78707c2017-03-09 15:03:11 +0000336 GLuint maxUniformComponents,
337 GLuint maxTextureImageUnits,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800338 GLuint maxImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800339 GLuint maxAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000340 const std::string &componentsErrorMessage,
341 const std::string &samplerErrorMessage,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800342 const std::string &imageErrorMessage,
jchen10eaef1e52017-06-13 10:44:11 +0800343 const std::string &atomicCounterErrorMessage,
Olli Etuahob78707c2017-03-09 15:03:11 +0000344 std::vector<LinkedUniform> &samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800345 std::vector<LinkedUniform> &imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800346 std::vector<LinkedUniform> &atomicCounterUniforms,
Olli Etuahob78707c2017-03-09 15:03:11 +0000347 InfoLog &infoLog)
348{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800349 ShaderUniformCount shaderUniformCount;
Jamie Madillbd044ed2017-06-05 12:59:21 -0400350 for (const sh::Uniform &uniform : shader->getUniforms(context))
Olli Etuahob78707c2017-03-09 15:03:11 +0000351 {
jchen10baf5d942017-08-28 20:45:48 +0800352 shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms,
353 &atomicCounterUniforms, shader->getType());
Olli Etuahob78707c2017-03-09 15:03:11 +0000354 }
355
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800356 if (shaderUniformCount.vectorCount > maxUniformComponents)
Olli Etuahob78707c2017-03-09 15:03:11 +0000357 {
358 infoLog << componentsErrorMessage << maxUniformComponents << ").";
359 return false;
360 }
361
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800362 if (shaderUniformCount.samplerCount > maxTextureImageUnits)
Olli Etuahob78707c2017-03-09 15:03:11 +0000363 {
364 infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
365 return false;
366 }
367
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800368 if (shaderUniformCount.imageCount > maxImageUnits)
369 {
370 infoLog << imageErrorMessage << maxImageUnits << ").";
371 return false;
372 }
373
jchen10eaef1e52017-06-13 10:44:11 +0800374 if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
375 {
376 infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
377 return false;
378 }
379
Olli Etuahob78707c2017-03-09 15:03:11 +0000380 return true;
381}
382
Jamie Madillbd044ed2017-06-05 12:59:21 -0400383bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog)
Olli Etuahob78707c2017-03-09 15:03:11 +0000384{
385 std::vector<LinkedUniform> samplerUniforms;
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800386 std::vector<LinkedUniform> imageUniforms;
jchen10eaef1e52017-06-13 10:44:11 +0800387 std::vector<LinkedUniform> atomicCounterUniforms;
Olli Etuahob78707c2017-03-09 15:03:11 +0000388
Jamie Madillbd044ed2017-06-05 12:59:21 -0400389 const Caps &caps = context->getCaps();
390
Olli Etuahob78707c2017-03-09 15:03:11 +0000391 if (mState.getAttachedComputeShader())
392 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400393 Shader *computeShader = mState.getAttachedComputeShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000394
395 // TODO (mradev): check whether we need finer-grained component counting
396 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400397 context, computeShader, caps.maxComputeUniformComponents / 4,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800398 caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800399 caps.maxComputeAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000400 "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
401 "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800402 "Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
403 "Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
404 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000405 {
406 return false;
407 }
408 }
409 else
410 {
Jamie Madillbd044ed2017-06-05 12:59:21 -0400411 Shader *vertexShader = mState.getAttachedVertexShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000412
413 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400414 context, vertexShader, caps.maxVertexUniformVectors,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800415 caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800416 caps.maxVertexAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000417 "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
418 "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
jchen10eaef1e52017-06-13 10:44:11 +0800419 "Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
420 "Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
421 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000422 {
423 return false;
424 }
Jamie Madillbd044ed2017-06-05 12:59:21 -0400425
426 Shader *fragmentShader = mState.getAttachedFragmentShader();
Olli Etuahob78707c2017-03-09 15:03:11 +0000427
428 if (!flattenUniformsAndCheckCapsForShader(
Jamie Madillbd044ed2017-06-05 12:59:21 -0400429 context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
jchen10eaef1e52017-06-13 10:44:11 +0800430 caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
Olli Etuahob78707c2017-03-09 15:03:11 +0000431 "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800432 "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
433 "Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
jchen10eaef1e52017-06-13 10:44:11 +0800434 "Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
435 samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
Olli Etuahob78707c2017-03-09 15:03:11 +0000436 {
437 return false;
438 }
439 }
440
441 mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800442 mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
jchen10eaef1e52017-06-13 10:44:11 +0800443 mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
Olli Etuahob78707c2017-03-09 15:03:11 +0000444 return true;
445}
446
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800447UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
Olli Etuahob78707c2017-03-09 15:03:11 +0000448 const sh::Uniform &uniform,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800449 std::vector<LinkedUniform> *samplerUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800450 std::vector<LinkedUniform> *imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800451 std::vector<LinkedUniform> *atomicCounterUniforms,
452 GLenum shaderType)
Olli Etuahob78707c2017-03-09 15:03:11 +0000453{
454 int location = uniform.location;
jchen10baf5d942017-08-28 20:45:48 +0800455 ShaderUniformCount shaderUniformCount =
456 flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
457 imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
458 uniform.binding, uniform.offset, &location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000459 if (uniform.staticUse)
460 {
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800461 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000462 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800463 return ShaderUniformCount();
Olli Etuahob78707c2017-03-09 15:03:11 +0000464}
465
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800466UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
Olli Etuahob78707c2017-03-09 15:03:11 +0000467 const sh::ShaderVariable &uniform,
468 const std::string &fullName,
Olli Etuaho855d9642017-05-17 14:05:06 +0300469 const std::string &fullMappedName,
Olli Etuahob78707c2017-03-09 15:03:11 +0000470 std::vector<LinkedUniform> *samplerUniforms,
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800471 std::vector<LinkedUniform> *imageUniforms,
jchen10eaef1e52017-06-13 10:44:11 +0800472 std::vector<LinkedUniform> *atomicCounterUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800473 GLenum shaderType,
Olli Etuahob78707c2017-03-09 15:03:11 +0000474 bool markStaticUse,
475 int binding,
jchen10eaef1e52017-06-13 10:44:11 +0800476 int offset,
Olli Etuahob78707c2017-03-09 15:03:11 +0000477 int *location)
478{
479 ASSERT(location);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 ShaderUniformCount shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000481
482 if (uniform.isStruct())
483 {
484 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
485 {
486 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
487
488 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
489 {
490 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
491 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
Olli Etuaho855d9642017-05-17 14:05:06 +0300492 const std::string &fieldFullMappedName =
493 (fullMappedName + elementString + "." + field.mappedName);
Olli Etuahob78707c2017-03-09 15:03:11 +0000494
Olli Etuaho855d9642017-05-17 14:05:06 +0300495 shaderUniformCount += flattenUniformImpl(
496 field, fieldFullName, fieldFullMappedName, samplerUniforms, imageUniforms,
jchen10baf5d942017-08-28 20:45:48 +0800497 atomicCounterUniforms, shaderType, markStaticUse, -1, -1, location);
Olli Etuahob78707c2017-03-09 15:03:11 +0000498 }
499 }
500
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800501 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000502 }
503
504 // Not a struct
505 bool isSampler = IsSamplerType(uniform.type);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800506 bool isImage = IsImageType(uniform.type);
jchen10eaef1e52017-06-13 10:44:11 +0800507 bool isAtomicCounter = IsAtomicCounterType(uniform.type);
Olli Etuahob78707c2017-03-09 15:03:11 +0000508 std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
509 if (isSampler)
510 {
Olli Etuahob78707c2017-03-09 15:03:11 +0000511 uniformList = samplerUniforms;
512 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800513 else if (isImage)
514 {
515 uniformList = imageUniforms;
516 }
jchen10eaef1e52017-06-13 10:44:11 +0800517 else if (isAtomicCounter)
518 {
519 uniformList = atomicCounterUniforms;
520 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000521 LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
522 if (existingUniform)
523 {
524 if (binding != -1)
525 {
526 existingUniform->binding = binding;
527 }
jchen10eaef1e52017-06-13 10:44:11 +0800528 if (offset != -1)
529 {
530 existingUniform->offset = offset;
531 }
Olli Etuahob78707c2017-03-09 15:03:11 +0000532 if (*location != -1)
533 {
534 existingUniform->location = *location;
535 }
536 if (markStaticUse)
537 {
538 existingUniform->staticUse = true;
jchen10baf5d942017-08-28 20:45:48 +0800539 MarkResourceStaticUse(existingUniform, shaderType, true);
Olli Etuahob78707c2017-03-09 15:03:11 +0000540 }
541 }
542 else
543 {
544 LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
jchen10baf5d942017-08-28 20:45:48 +0800545 binding, offset, *location, -1,
Olli Etuahob78707c2017-03-09 15:03:11 +0000546 sh::BlockMemberInfo::getDefaultBlockInfo());
Olli Etuaho855d9642017-05-17 14:05:06 +0300547 linkedUniform.mappedName = fullMappedName;
Olli Etuahob78707c2017-03-09 15:03:11 +0000548 linkedUniform.staticUse = markStaticUse;
jchen10baf5d942017-08-28 20:45:48 +0800549 if (markStaticUse)
550 {
551 MarkResourceStaticUse(&linkedUniform, shaderType, true);
552 }
jchen10eaef1e52017-06-13 10:44:11 +0800553
Olli Etuahob78707c2017-03-09 15:03:11 +0000554 uniformList->push_back(linkedUniform);
555 }
556
557 unsigned int elementCount = uniform.elementCount();
558
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800559 // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
jchen10eaef1e52017-06-13 10:44:11 +0800560 // Likewise, don't count "real" uniforms towards opaque count.
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800561 shaderUniformCount.vectorCount =
jchen10eaef1e52017-06-13 10:44:11 +0800562 (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800563 shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
564 shaderUniformCount.imageCount = (isImage ? elementCount : 0);
jchen10eaef1e52017-06-13 10:44:11 +0800565 shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
Olli Etuahob78707c2017-03-09 15:03:11 +0000566
567 if (*location != -1)
568 {
569 *location += elementCount;
570 }
571
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800572 return shaderUniformCount;
Olli Etuahob78707c2017-03-09 15:03:11 +0000573}
574
jchen10eaef1e52017-06-13 10:44:11 +0800575bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
576{
577 unsigned int atomicCounterCount = 0;
578 for (const auto &uniform : mUniforms)
579 {
580 if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
581 {
582 atomicCounterCount += uniform.elementCount();
583 if (atomicCounterCount > caps.maxCombinedAtomicCounters)
584 {
585 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
586 << caps.maxCombinedAtomicCounters << ").";
587 return false;
588 }
589 }
590 }
591 return true;
592}
593
Olli Etuahob78707c2017-03-09 15:03:11 +0000594} // namespace gl