Move default-block uniform linking to a separate file
The code is easier to understand when it's encapsulated better.
This change is pure refactoring with no functional changes.
BUG=angleproject:1442
TEST=angle_end2end_tests
Change-Id: I6128fd72c65ca7a87af596cda4866c74c2a66c48
Reviewed-on: https://chromium-review.googlesource.com/452502
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index e7aa9dd..c1c5605 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -25,6 +25,7 @@
#include "libANGLE/VaryingPacking.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/Uniform.h"
+#include "libANGLE/UniformLinker.h"
namespace gl
{
@@ -125,17 +126,6 @@
}
}
-LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
-{
- for (LinkedUniform &uniform : list)
- {
- if (uniform.name == name)
- return &uniform;
- }
-
- return nullptr;
-}
-
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
@@ -1914,240 +1904,23 @@
return true;
}
-bool Program::validateVertexAndFragmentUniforms(InfoLog &infoLog) const
-{
- // Check that uniforms defined in the vertex and fragment shaders are identical
- std::map<std::string, LinkedUniform> linkedUniforms;
- const std::vector<sh::Uniform> &vertexUniforms = mState.mAttachedVertexShader->getUniforms();
- const std::vector<sh::Uniform> &fragmentUniforms =
- mState.mAttachedFragmentShader->getUniforms();
-
- for (const sh::Uniform &vertexUniform : vertexUniforms)
- {
- linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
- }
-
- for (const sh::Uniform &fragmentUniform : fragmentUniforms)
- {
- auto entry = linkedUniforms.find(fragmentUniform.name);
- if (entry != linkedUniforms.end())
- {
- LinkedUniform *linkedUniform = &entry->second;
- const std::string &uniformName = "uniform '" + linkedUniform->name + "'";
- if (!linkValidateUniforms(infoLog, uniformName, *linkedUniform, fragmentUniform))
- {
- return false;
- }
- }
- }
- return true;
-}
-
bool Program::linkUniforms(InfoLog &infoLog,
const Caps &caps,
const Bindings &uniformLocationBindings)
{
- if (mState.mAttachedVertexShader && mState.mAttachedFragmentShader)
- {
- ASSERT(mState.mAttachedComputeShader == nullptr);
- if (!validateVertexAndFragmentUniforms(infoLog))
- {
- return false;
- }
- }
-
- // Flatten the uniforms list (nested fields) into a simple list (no nesting).
- // Also check the maximum uniform vector and sampler counts.
- if (!flattenUniformsAndCheckCaps(caps, infoLog))
+ UniformLinker linker(mState);
+ if (!linker.link(infoLog, caps, uniformLocationBindings))
{
return false;
}
- if (!indexUniforms(infoLog, uniformLocationBindings))
- {
- return false;
- }
+ linker.getResults(&mState.mUniforms, &mState.mUniformLocations);
updateSamplerBindings();
return true;
}
-bool Program::gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog,
- const Bindings &uniformLocationBindings,
- std::set<GLuint> *reservedLocations,
- std::set<GLuint> *ignoredLocations,
- int *maxUniformLocation)
-{
- for (const LinkedUniform &uniform : mState.mUniforms)
- {
- if (uniform.isBuiltIn())
- {
- continue;
- }
-
- int apiBoundLocation = uniformLocationBindings.getBinding(uniform.name);
- int shaderLocation = uniform.location;
-
- if (shaderLocation != -1)
- {
- for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
- {
- // GLSL ES 3.10 section 4.4.3
- int elementLocation = shaderLocation + arrayIndex;
- *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
- if (reservedLocations->find(elementLocation) != reservedLocations->end())
- {
- infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
- return false;
- }
- reservedLocations->insert(elementLocation);
- if (!uniform.staticUse)
- {
- ignoredLocations->insert(elementLocation);
- }
- }
- }
- else if (apiBoundLocation != -1 && uniform.staticUse)
- {
- // Only the first location is reserved even if the uniform is an array.
- *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
- if (reservedLocations->find(apiBoundLocation) != reservedLocations->end())
- {
- infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
- return false;
- }
- reservedLocations->insert(apiBoundLocation);
- }
- }
-
- // Record the uniform locations that were bound using the API for uniforms that were not found
- // from the shader. Other uniforms should not be assigned to those locations.
- for (const auto &locationBinding : uniformLocationBindings)
- {
- GLuint location = locationBinding.second;
- if (reservedLocations->find(location) == reservedLocations->end())
- {
- ignoredLocations->insert(location);
- *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
- }
- }
-
- return true;
-}
-
-void Program::pruneUnusedUniforms()
-{
- auto uniformIter = mState.mUniforms.begin();
- while (uniformIter != mState.mUniforms.end())
- {
- if (uniformIter->staticUse)
- {
- ++uniformIter;
- }
- else
- {
- uniformIter = mState.mUniforms.erase(uniformIter);
- }
- }
-}
-
-bool Program::indexUniforms(InfoLog &infoLog,
- const Bindings &uniformLocationBindings)
-{
- // All the locations where another uniform can't be located.
- std::set<GLuint> reservedLocations;
- // Locations which have been allocated for an unused uniform.
- std::set<GLuint> ignoredLocations;
-
- int maxUniformLocation = -1;
-
- // Gather uniform locations that have been set either using the bindUniformLocation API or by
- // using a location layout qualifier and check conflicts between them.
- if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
- &reservedLocations, &ignoredLocations,
- &maxUniformLocation))
- {
- return false;
- }
-
- // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
- // the line relies on only having statically used uniforms in mState.mUniforms.
- pruneUnusedUniforms();
-
- // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
- std::vector<VariableLocation> unlocatedUniforms;
- std::map<GLuint, VariableLocation> preLocatedUniforms;
-
- for (size_t uniformIndex = 0; uniformIndex < mState.mUniforms.size(); uniformIndex++)
- {
- const LinkedUniform &uniform = mState.mUniforms[uniformIndex];
-
- if (uniform.isBuiltIn())
- {
- continue;
- }
-
- int preSetLocation = uniformLocationBindings.getBinding(uniform.name);
- int shaderLocation = uniform.location;
-
- if (shaderLocation != -1)
- {
- preSetLocation = shaderLocation;
- }
-
- for (unsigned int arrayIndex = 0; arrayIndex < uniform.elementCount(); arrayIndex++)
- {
- VariableLocation location(uniform.name, arrayIndex,
- static_cast<unsigned int>(uniformIndex));
-
- if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
- {
- int elementLocation = preSetLocation + arrayIndex;
- preLocatedUniforms[elementLocation] = location;
- }
- else
- {
- unlocatedUniforms.push_back(location);
- }
- }
- }
-
- // Make enough space for all uniforms, with pre-set locations or not.
- mState.mUniformLocations.resize(
- std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
- static_cast<size_t>(maxUniformLocation + 1)));
-
- // Assign uniforms with pre-set locations
- for (const auto &uniform : preLocatedUniforms)
- {
- mState.mUniformLocations[uniform.first] = uniform.second;
- }
-
- // Assign ignored uniforms
- for (const auto &ignoredLocation : ignoredLocations)
- {
- mState.mUniformLocations[ignoredLocation].ignored = true;
- }
-
- // Automatically assign locations for the rest of the uniforms
- size_t nextUniformLocation = 0;
- for (const auto &unlocatedUniform : unlocatedUniforms)
- {
- while (mState.mUniformLocations[nextUniformLocation].used ||
- mState.mUniformLocations[nextUniformLocation].ignored)
- {
- nextUniformLocation++;
- }
-
- ASSERT(nextUniformLocation < mState.mUniformLocations.size());
- mState.mUniformLocations[nextUniformLocation] = unlocatedUniform;
- nextUniformLocation++;
- }
-
- return true;
-}
-
void Program::updateSamplerBindings()
{
mState.mSamplerUniformRange.end = static_cast<unsigned int>(mState.mUniforms.size());
@@ -2488,41 +2261,6 @@
return true;
}
-// GLSL ES Spec 3.00.3, section 4.3.5.
-bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
-{
-#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
- const bool validatePrecision = true;
-#else
- const bool validatePrecision = false;
-#endif
-
- if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, validatePrecision))
- {
- return false;
- }
-
- // GLSL ES Spec 3.10.4, section 4.4.5.
- if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
- vertexUniform.binding != fragmentUniform.binding)
- {
- infoLog << "Binding layout qualifiers for " << uniformName
- << " differ between vertex and fragment shaders.";
- return false;
- }
-
- // GLSL ES Spec 3.10.4, section 9.2.1.
- if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
- vertexUniform.location != fragmentUniform.location)
- {
- infoLog << "Location layout qualifiers for " << uniformName
- << " differ between vertex and fragment shaders.";
- return false;
- }
-
- return true;
-}
-
bool Program::linkValidateVaryings(InfoLog &infoLog,
const std::string &varyingName,
const sh::Varying &vertexVarying,
@@ -2828,174 +2566,6 @@
}
}
-bool Program::flattenUniformsAndCheckCapsForShader(const Shader &shader,
- GLuint maxUniformComponents,
- GLuint maxTextureImageUnits,
- const std::string &componentsErrorMessage,
- const std::string &samplerErrorMessage,
- std::vector<LinkedUniform> &samplerUniforms,
- InfoLog &infoLog)
-{
- VectorAndSamplerCount vasCount;
- for (const sh::Uniform &uniform : shader.getUniforms())
- {
- vasCount += flattenUniform(uniform, &samplerUniforms);
- }
-
- if (vasCount.vectorCount > maxUniformComponents)
- {
- infoLog << componentsErrorMessage << maxUniformComponents << ").";
- return false;
- }
-
- if (vasCount.samplerCount > maxTextureImageUnits)
- {
- infoLog << samplerErrorMessage << maxTextureImageUnits << ").";
- return false;
- }
-
- return true;
-}
-
-bool Program::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
-{
- std::vector<LinkedUniform> samplerUniforms;
-
- if (mState.mAttachedComputeShader)
- {
- const Shader *computeShader = mState.getAttachedComputeShader();
-
- // TODO (mradev): check whether we need finer-grained component counting
- if (!flattenUniformsAndCheckCapsForShader(
- *computeShader, caps.maxComputeUniformComponents / 4,
- caps.maxComputeTextureImageUnits,
- "Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
- "Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
- samplerUniforms, infoLog))
- {
- return false;
- }
- }
- else
- {
- const Shader *vertexShader = mState.getAttachedVertexShader();
-
- if (!flattenUniformsAndCheckCapsForShader(
- *vertexShader, caps.maxVertexUniformVectors, caps.maxVertexTextureImageUnits,
- "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
- "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
- samplerUniforms, infoLog))
- {
- return false;
- }
- const Shader *fragmentShader = mState.getAttachedFragmentShader();
-
- if (!flattenUniformsAndCheckCapsForShader(
- *fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
- "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
- "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (", samplerUniforms,
- infoLog))
- {
- return false;
- }
- }
-
- mState.mUniforms.insert(mState.mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
- return true;
-}
-
-Program::VectorAndSamplerCount Program::flattenUniform(const sh::Uniform &uniform,
- std::vector<LinkedUniform> *samplerUniforms)
-{
- int location = uniform.location;
- VectorAndSamplerCount uniformVasCount = flattenUniformImpl(
- uniform, uniform.name, samplerUniforms, uniform.staticUse, uniform.binding, &location);
- if (uniform.staticUse)
- {
- return uniformVasCount;
- }
- return VectorAndSamplerCount();
-}
-
-Program::VectorAndSamplerCount Program::flattenUniformImpl(
- const sh::ShaderVariable &uniform,
- const std::string &fullName,
- std::vector<LinkedUniform> *samplerUniforms,
- bool markStaticUse,
- int binding,
- int *location)
-{
- ASSERT(location);
- VectorAndSamplerCount vectorAndSamplerCount;
-
- if (uniform.isStruct())
- {
- for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
- {
- const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
-
- for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
- {
- const sh::ShaderVariable &field = uniform.fields[fieldIndex];
- const std::string &fieldFullName = (fullName + elementString + "." + field.name);
-
- vectorAndSamplerCount += flattenUniformImpl(field, fieldFullName, samplerUniforms,
- markStaticUse, -1, location);
- }
- }
-
- return vectorAndSamplerCount;
- }
-
- // Not a struct
- bool isSampler = IsSamplerType(uniform.type);
- std::vector<gl::LinkedUniform> *uniformList = &mState.mUniforms;
- if (isSampler)
- {
- // Store sampler uniforms separately, so we'll append them to the end of the list.
- uniformList = samplerUniforms;
- }
- LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
- if (existingUniform)
- {
- if (binding != -1)
- {
- existingUniform->binding = binding;
- }
- if (*location != -1)
- {
- existingUniform->location = *location;
- }
- if (markStaticUse)
- {
- existingUniform->staticUse = true;
- }
- }
- else
- {
- LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
- binding, *location, -1,
- sh::BlockMemberInfo::getDefaultBlockInfo());
- linkedUniform.staticUse = markStaticUse;
- uniformList->push_back(linkedUniform);
- }
-
- unsigned int elementCount = uniform.elementCount();
-
- // Samplers aren't "real" uniforms, so they don't count towards register usage.
- // Likewise, don't count "real" uniforms towards sampler count.
- vectorAndSamplerCount.vectorCount =
- (isSampler ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
- vectorAndSamplerCount.samplerCount = (isSampler ? elementCount : 0);
-
- if (*location != -1)
- {
- *location += elementCount;
- }
-
- return vectorAndSamplerCount;
-}
-
void Program::gatherInterfaceBlockInfo()
{
ASSERT(mState.mUniformBlocks.empty());