Add compute program compilation and linking support
Compute shaders can be now compiled and linked to create programs.
Some tests are added to verify successful and unsuccessful compute
shader linking.
The patch also replaces std::array<int, 3> with a custom struct
WorkGroupSize.
BUG=angleproject:1442
TEST=angle_end2end_tests
TEST=angle_unittests
Change-Id: I4ab0ac05755d0167a6d2a798f8d7f1516cf54d84
Reviewed-on: https://chromium-review.googlesource.com/366740
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index ae67777..7f4226d 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -237,9 +237,11 @@
: mLabel(),
mAttachedFragmentShader(nullptr),
mAttachedVertexShader(nullptr),
+ mAttachedComputeShader(nullptr),
mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
mBinaryRetrieveableHint(false)
{
+ mComputeShaderLocalSize.fill(1);
}
ProgramState::~ProgramState()
@@ -253,6 +255,11 @@
{
mAttachedFragmentShader->release();
}
+
+ if (mAttachedComputeShader != nullptr)
+ {
+ mAttachedComputeShader->release();
+ }
}
const std::string &ProgramState::getLabel()
@@ -372,61 +379,96 @@
bool Program::attachShader(Shader *shader)
{
- if (shader->getType() == GL_VERTEX_SHADER)
+ switch (shader->getType())
{
- if (mState.mAttachedVertexShader)
+ case GL_VERTEX_SHADER:
{
- return false;
- }
+ if (mState.mAttachedVertexShader)
+ {
+ return false;
+ }
- mState.mAttachedVertexShader = shader;
- mState.mAttachedVertexShader->addRef();
- }
- else if (shader->getType() == GL_FRAGMENT_SHADER)
- {
- if (mState.mAttachedFragmentShader)
+ mState.mAttachedVertexShader = shader;
+ mState.mAttachedVertexShader->addRef();
+ break;
+ }
+ case GL_FRAGMENT_SHADER:
{
- return false;
- }
+ if (mState.mAttachedFragmentShader)
+ {
+ return false;
+ }
- mState.mAttachedFragmentShader = shader;
- mState.mAttachedFragmentShader->addRef();
+ mState.mAttachedFragmentShader = shader;
+ mState.mAttachedFragmentShader->addRef();
+ break;
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ if (mState.mAttachedComputeShader)
+ {
+ return false;
+ }
+
+ mState.mAttachedComputeShader = shader;
+ mState.mAttachedComputeShader->addRef();
+ break;
+ }
+ default:
+ UNREACHABLE();
}
- else UNREACHABLE();
return true;
}
bool Program::detachShader(Shader *shader)
{
- if (shader->getType() == GL_VERTEX_SHADER)
+ switch (shader->getType())
{
- if (mState.mAttachedVertexShader != shader)
+ case GL_VERTEX_SHADER:
{
- return false;
- }
+ if (mState.mAttachedVertexShader != shader)
+ {
+ return false;
+ }
- shader->release();
- mState.mAttachedVertexShader = nullptr;
- }
- else if (shader->getType() == GL_FRAGMENT_SHADER)
- {
- if (mState.mAttachedFragmentShader != shader)
+ shader->release();
+ mState.mAttachedVertexShader = nullptr;
+ break;
+ }
+ case GL_FRAGMENT_SHADER:
{
- return false;
- }
+ if (mState.mAttachedFragmentShader != shader)
+ {
+ return false;
+ }
- shader->release();
- mState.mAttachedFragmentShader = nullptr;
+ shader->release();
+ mState.mAttachedFragmentShader = nullptr;
+ break;
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ if (mState.mAttachedComputeShader != shader)
+ {
+ return false;
+ }
+
+ shader->release();
+ mState.mAttachedComputeShader = nullptr;
+ break;
+ }
+ default:
+ UNREACHABLE();
}
- else UNREACHABLE();
return true;
}
int Program::getAttachedShadersCount() const
{
- return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0);
+ return (mState.mAttachedVertexShader ? 1 : 0) + (mState.mAttachedFragmentShader ? 1 : 0) +
+ (mState.mAttachedComputeShader ? 1 : 0);
}
void Program::bindAttributeLocation(GLuint index, const char *name)
@@ -516,9 +558,9 @@
mProgram->setPathFragmentInputGen(binding.name, genMode, components, coeffs);
}
-// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
-// compiling them into binaries, determining the attribute mappings, and collecting
-// a list of uniforms
+// The attached shaders are checked for linking errors by matching up their variables.
+// Uniform, input and output variables get collected.
+// The code gets compiled into binaries.
Error Program::link(const ContextState &data)
{
unlink(false);
@@ -526,65 +568,119 @@
mInfoLog.reset();
resetUniformBlockBindings();
- if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled())
- {
- return Error(GL_NO_ERROR);
- }
- ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
+ const Caps &caps = data.getCaps();
- if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled())
+ bool isComputeShaderAttached = (mState.mAttachedComputeShader != nullptr);
+ bool nonComputeShadersAttached =
+ (mState.mAttachedVertexShader != nullptr || mState.mAttachedFragmentShader != nullptr);
+ // Check whether we both have a compute and non-compute shaders attached.
+ // If there are of both types attached, then linking should fail.
+ // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
+ if (isComputeShaderAttached == true && nonComputeShadersAttached == true)
{
- return Error(GL_NO_ERROR);
- }
- ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
-
- if (mState.mAttachedFragmentShader->getShaderVersion() !=
- mState.mAttachedVertexShader->getShaderVersion())
- {
- mInfoLog << "Fragment shader version does not match vertex shader version.";
- return Error(GL_NO_ERROR);
+ mInfoLog << "Both a compute and non-compute shaders are attached to the same program.";
+ return NoError();
}
- if (!linkAttributes(data, mInfoLog, mAttributeBindings, mState.mAttachedVertexShader))
+ if (mState.mAttachedComputeShader)
{
- return Error(GL_NO_ERROR);
+ if (!mState.mAttachedComputeShader->isCompiled())
+ {
+ mInfoLog << "Attached compute shader is not compiled.";
+ return NoError();
+ }
+ ASSERT(mState.mAttachedComputeShader->getType() == GL_COMPUTE_SHADER);
+
+ mState.mComputeShaderLocalSize = mState.mAttachedComputeShader->getWorkGroupSize();
+
+ // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
+ // If the work group size is not specified, a link time error should occur.
+ if (!mState.mComputeShaderLocalSize.isDeclared())
+ {
+ mInfoLog << "Work group size is not specified.";
+ return NoError();
+ }
+
+ if (!linkUniforms(mInfoLog, caps, mUniformBindings))
+ {
+ return NoError();
+ }
+
+ if (!linkUniformBlocks(mInfoLog, caps))
+ {
+ return NoError();
+ }
+
+ rx::LinkResult result = mProgram->link(data, mInfoLog);
+
+ if (result.error.isError() || !result.linkSuccess)
+ {
+ return result.error;
+ }
+ }
+ else
+ {
+ if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled())
+ {
+ return NoError();
+ }
+ ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER);
+
+ if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled())
+ {
+ return NoError();
+ }
+ ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER);
+
+ if (mState.mAttachedFragmentShader->getShaderVersion() !=
+ mState.mAttachedVertexShader->getShaderVersion())
+ {
+ mInfoLog << "Fragment shader version does not match vertex shader version.";
+ return NoError();
+ }
+
+ if (!linkAttributes(data, mInfoLog, mAttributeBindings, mState.mAttachedVertexShader))
+ {
+ return NoError();
+ }
+
+ if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
+ {
+ return NoError();
+ }
+
+ if (!linkUniforms(mInfoLog, caps, mUniformBindings))
+ {
+ return NoError();
+ }
+
+ if (!linkUniformBlocks(mInfoLog, caps))
+ {
+ return NoError();
+ }
+
+ const auto &mergedVaryings = getMergedVaryings();
+
+ if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, caps))
+ {
+ return NoError();
+ }
+
+ linkOutputVariables();
+
+ rx::LinkResult result = mProgram->link(data, mInfoLog);
+ if (result.error.isError() || !result.linkSuccess)
+ {
+ return result.error;
+ }
+
+ gatherTransformFeedbackVaryings(mergedVaryings);
}
- if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader))
- {
- return Error(GL_NO_ERROR);
- }
-
- if (!linkUniforms(mInfoLog, data.getCaps(), mUniformBindings))
- {
- return Error(GL_NO_ERROR);
- }
-
- if (!linkUniformBlocks(mInfoLog, data.getCaps()))
- {
- return Error(GL_NO_ERROR);
- }
-
- const auto &mergedVaryings = getMergedVaryings();
-
- if (!linkValidateTransformFeedback(mInfoLog, mergedVaryings, data.getCaps()))
- {
- return Error(GL_NO_ERROR);
- }
-
- linkOutputVariables();
-
- rx::LinkResult result = mProgram->link(data, mInfoLog);
- if (result.error.isError() || !result.linkSuccess)
- {
- return result.error;
- }
-
- gatherTransformFeedbackVaryings(mergedVaryings);
gatherInterfaceBlockInfo();
mLinked = true;
- return gl::Error(GL_NO_ERROR);
+ return NoError();
}
// Returns the program object to an unlinked state, before re-linking, or at destruction
@@ -603,6 +699,12 @@
mState.mAttachedVertexShader->release();
mState.mAttachedVertexShader = nullptr;
}
+
+ if (mState.mAttachedComputeShader)
+ {
+ mState.mAttachedComputeShader->release();
+ mState.mAttachedComputeShader = nullptr;
+ }
}
mState.mAttributes.clear();
@@ -612,6 +714,7 @@
mState.mUniformLocations.clear();
mState.mUniformBlocks.clear();
mState.mOutputVariables.clear();
+ mState.mComputeShaderLocalSize.fill(1);
mValidated = false;
@@ -655,6 +758,10 @@
return Error(GL_NO_ERROR);
}
+ mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
+ mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
+ mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
+
static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
"Too many vertex attribs for mask");
mState.mActiveAttribLocationsMask = stream.readInt<unsigned long>();
@@ -776,6 +883,10 @@
stream.writeInt(ANGLE_MINOR_VERSION);
stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
+ stream.writeInt(mState.mComputeShaderLocalSize[0]);
+ stream.writeInt(mState.mComputeShaderLocalSize[1]);
+ stream.writeInt(mState.mComputeShaderLocalSize[2]);
+
stream.writeInt(mState.mActiveAttribLocationsMask.to_ulong());
stream.writeInt(mState.mAttributes.size());
@@ -947,6 +1058,15 @@
{
int total = 0;
+ if (mState.mAttachedComputeShader)
+ {
+ if (total < maxCount)
+ {
+ shaders[total] = mState.mAttachedComputeShader->getHandle();
+ total++;
+ }
+ }
+
if (mState.mAttachedVertexShader)
{
if (total < maxCount)
@@ -1772,17 +1892,14 @@
return true;
}
-bool Program::linkUniforms(gl::InfoLog &infoLog,
- const gl::Caps &caps,
- const Bindings &uniformBindings)
+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();
- // Check that uniforms defined in the vertex and fragment shaders are identical
- std::map<std::string, LinkedUniform> linkedUniforms;
-
for (const sh::Uniform &vertexUniform : vertexUniforms)
{
linkedUniforms[vertexUniform.name] = LinkedUniform(vertexUniform);
@@ -1801,6 +1918,21 @@
}
}
}
+ return true;
+}
+
+bool Program::linkUniforms(gl::InfoLog &infoLog,
+ const gl::Caps &caps,
+ const Bindings &uniformBindings)
+{
+ 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.
@@ -1910,7 +2042,10 @@
return true;
}
-bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
+bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
+ const std::string &uniformName,
+ const sh::InterfaceBlockField &vertexUniform,
+ const sh::InterfaceBlockField &fragmentUniform)
{
// We don't validate precision on UBO fields. See resolution of Khronos bug 10287.
if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, false))
@@ -2034,36 +2169,40 @@
return true;
}
-bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
+bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
+ const std::vector<sh::InterfaceBlock> &intefaceBlocks,
+ const std::string &errorMessage,
+ InfoLog &infoLog) const
{
- const Shader &vertexShader = *mState.mAttachedVertexShader;
- const Shader &fragmentShader = *mState.mAttachedFragmentShader;
-
- const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
- const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
-
- // Check that interface blocks defined in the vertex and fragment shaders are identical
- typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
- UniformBlockMap linkedUniformBlocks;
-
- GLuint vertexBlockCount = 0;
- for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
+ GLuint blockCount = 0;
+ for (const sh::InterfaceBlock &block : intefaceBlocks)
{
- linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
-
- // Note: shared and std140 layouts are always considered active
- if (vertexInterfaceBlock.staticUse || vertexInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+ if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
{
- if (++vertexBlockCount > caps.maxVertexUniformBlocks)
+ if (++blockCount > maxUniformBlocks)
{
- infoLog << "Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS ("
- << caps.maxVertexUniformBlocks << ")";
+ infoLog << errorMessage << maxUniformBlocks << ")";
return false;
}
}
}
+ return true;
+}
- GLuint fragmentBlockCount = 0;
+bool Program::validateVertexAndFragmentInterfaceBlocks(
+ const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
+ const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
+ InfoLog &infoLog) const
+{
+ // Check that interface blocks defined in the vertex and fragment shaders are identical
+ typedef std::map<std::string, const sh::InterfaceBlock *> UniformBlockMap;
+ UniformBlockMap linkedUniformBlocks;
+
+ for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
+ {
+ linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
+ }
+
for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
{
auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
@@ -2075,26 +2214,59 @@
return false;
}
}
+ }
+ return true;
+}
- // Note: shared and std140 layouts are always considered active
- if (fragmentInterfaceBlock.staticUse ||
- fragmentInterfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+bool Program::linkUniformBlocks(InfoLog &infoLog, const Caps &caps)
+{
+ if (mState.mAttachedComputeShader)
+ {
+ const Shader &computeShader = *mState.mAttachedComputeShader;
+ const auto &computeInterfaceBlocks = computeShader.getInterfaceBlocks();
+
+ if (!validateUniformBlocksCount(
+ caps.maxComputeUniformBlocks, computeInterfaceBlocks,
+ "Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
+ infoLog))
{
- if (++fragmentBlockCount > caps.maxFragmentUniformBlocks)
- {
- infoLog
- << "Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS ("
- << caps.maxFragmentUniformBlocks << ")";
- return false;
- }
+ return false;
}
+ return true;
+ }
+
+ const Shader &vertexShader = *mState.mAttachedVertexShader;
+ const Shader &fragmentShader = *mState.mAttachedFragmentShader;
+
+ const auto &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
+ const auto &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
+
+ if (!validateUniformBlocksCount(
+ caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
+ "Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
+ {
+ return false;
+ }
+ if (!validateUniformBlocksCount(
+ caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
+ "Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
+ infoLog))
+ {
+
+ return false;
+ }
+ if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
+ infoLog))
+ {
+ return false;
}
return true;
}
-bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
- const sh::InterfaceBlock &fragmentInterfaceBlock)
+bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog,
+ const sh::InterfaceBlock &vertexInterfaceBlock,
+ const sh::InterfaceBlock &fragmentInterfaceBlock) const
{
const char* blockName = vertexInterfaceBlock.name.c_str();
// validate blocks for the same member types
@@ -2385,58 +2557,79 @@
}
}
+bool Program::flattenUniformsAndCheckCapsForShader(const gl::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())
+ {
+ if (uniform.staticUse)
+ {
+ vasCount += flattenUniform(uniform, uniform.name, &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)
{
- const gl::Shader *vertexShader = mState.getAttachedVertexShader();
- VectorAndSamplerCount vsCounts;
-
std::vector<LinkedUniform> samplerUniforms;
- for (const sh::Uniform &uniform : vertexShader->getUniforms())
+ if (mState.mAttachedComputeShader)
{
- if (uniform.staticUse)
+ const gl::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))
{
- vsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
+ return false;
}
}
-
- if (vsCounts.vectorCount > caps.maxVertexUniformVectors)
+ else
{
- infoLog << "Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS ("
- << caps.maxVertexUniformVectors << ").";
- return false;
- }
+ const gl::Shader *vertexShader = mState.getAttachedVertexShader();
- if (vsCounts.samplerCount > caps.maxVertexTextureImageUnits)
- {
- infoLog << "Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS ("
- << caps.maxVertexTextureImageUnits << ").";
- return false;
- }
-
- const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
- VectorAndSamplerCount fsCounts;
-
- for (const sh::Uniform &uniform : fragmentShader->getUniforms())
- {
- if (uniform.staticUse)
+ 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))
{
- fsCounts += flattenUniform(uniform, uniform.name, &samplerUniforms);
+ return false;
}
- }
+ const gl::Shader *fragmentShader = mState.getAttachedFragmentShader();
- if (fsCounts.vectorCount > caps.maxFragmentUniformVectors)
- {
- infoLog << "Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS ("
- << caps.maxFragmentUniformVectors << ").";
- return false;
- }
-
- if (fsCounts.samplerCount > caps.maxTextureImageUnits)
- {
- infoLog << "Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS ("
- << caps.maxTextureImageUnits << ").";
- return false;
+ 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;
+ }
}
mSamplerUniformRange.start = static_cast<unsigned int>(mState.mUniforms.size());
@@ -2506,14 +2699,39 @@
void Program::gatherInterfaceBlockInfo()
{
+ ASSERT(mState.mUniformBlocks.empty());
+
+ if (mState.mAttachedComputeShader)
+ {
+ const gl::Shader *computeShader = mState.getAttachedComputeShader();
+
+ for (const sh::InterfaceBlock &computeBlock : computeShader->getInterfaceBlocks())
+ {
+
+ // Only 'packed' blocks are allowed to be considered inactive.
+ if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ for (gl::UniformBlock &block : mState.mUniformBlocks)
+ {
+ if (block.name == computeBlock.name)
+ {
+ block.computeStaticUse = computeBlock.staticUse;
+ }
+ }
+
+ defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
+ }
+ return;
+ }
+
std::set<std::string> visitedList;
const gl::Shader *vertexShader = mState.getAttachedVertexShader();
- ASSERT(mState.mUniformBlocks.empty());
for (const sh::InterfaceBlock &vertexBlock : vertexShader->getInterfaceBlocks())
{
- // Only 'packed' blocks are allowed to be considered inacive.
+ // Only 'packed' blocks are allowed to be considered inactive.
if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
@@ -2528,7 +2746,7 @@
for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getInterfaceBlocks())
{
- // Only 'packed' blocks are allowed to be considered inacive.
+ // Only 'packed' blocks are allowed to be considered inactive.
if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
@@ -2618,14 +2836,25 @@
UniformBlock block(interfaceBlock.name, true, arrayElement);
block.memberUniformIndexes = blockUniformIndexes;
- if (shaderType == GL_VERTEX_SHADER)
+ switch (shaderType)
{
- block.vertexStaticUse = interfaceBlock.staticUse;
- }
- else
- {
- ASSERT(shaderType == GL_FRAGMENT_SHADER);
- block.fragmentStaticUse = interfaceBlock.staticUse;
+ case GL_VERTEX_SHADER:
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ case GL_FRAGMENT_SHADER:
+ {
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ block.computeStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ default:
+ UNREACHABLE();
}
// TODO(jmadill): Determine if we can ever have an inactive array element block.
@@ -2645,14 +2874,25 @@
UniformBlock block(interfaceBlock.name, false, 0);
block.memberUniformIndexes = blockUniformIndexes;
- if (shaderType == GL_VERTEX_SHADER)
+ switch (shaderType)
{
- block.vertexStaticUse = interfaceBlock.staticUse;
- }
- else
- {
- ASSERT(shaderType == GL_FRAGMENT_SHADER);
- block.fragmentStaticUse = interfaceBlock.staticUse;
+ case GL_VERTEX_SHADER:
+ {
+ block.vertexStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ case GL_FRAGMENT_SHADER:
+ {
+ block.fragmentStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ case GL_COMPUTE_SHADER:
+ {
+ block.computeStaticUse = interfaceBlock.staticUse;
+ break;
+ }
+ default:
+ UNREACHABLE();
}
block.dataSize = static_cast<unsigned int>(blockSize);