ES31: Enable shader storage buffer support for OpenGL backend
BUG=angleproject:1951
TEST=angle_end2end_tests:ShaderStorageBuffer
Change-Id: I1afc3cd005ad2e595c6ce937fc53e17423f8ec8b
Reviewed-on: https://chromium-review.googlesource.com/618132
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 63b0c09..b7c5f1a 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -193,6 +193,27 @@
return false;
}
+bool validateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
+ const std::vector<sh::InterfaceBlock> &interfaceBlocks,
+ const std::string &errorMessage,
+ InfoLog &infoLog)
+{
+ GLuint blockCount = 0;
+ for (const sh::InterfaceBlock &block : interfaceBlocks)
+ {
+ if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
+ {
+ blockCount += (block.arraySize ? block.arraySize : 1);
+ if (blockCount > maxInterfaceBlocks)
+ {
+ infoLog << errorMessage << maxInterfaceBlocks << ")";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
} // anonymous namespace
const char *const g_fakepath = "C:\\fakepath";
@@ -693,7 +714,7 @@
return NoError();
}
- if (!linkUniformBlocks(context, mInfoLog))
+ if (!linkInterfaceBlocks(context, mInfoLog))
{
return NoError();
}
@@ -740,7 +761,7 @@
return NoError();
}
- if (!linkUniformBlocks(context, mInfoLog))
+ if (!linkInterfaceBlocks(context, mInfoLog))
{
return NoError();
}
@@ -1633,13 +1654,18 @@
return static_cast<GLuint>(mState.mUniformBlocks.size());
}
+GLuint Program::getActiveShaderStorageBlockCount() const
+{
+ return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
+}
+
void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
{
ASSERT(
uniformBlockIndex <
mState.mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
- const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
+ const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
if (bufSize > 0)
{
@@ -1662,7 +1688,7 @@
unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
{
- const UniformBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
+ const InterfaceBlock &uniformBlock = mState.mUniformBlocks[uniformBlockIndex];
if (!uniformBlock.name.empty())
{
int length = static_cast<int>(uniformBlock.nameWithArrayIndex().length());
@@ -1682,7 +1708,7 @@
unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
{
- const UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
+ const InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
if (uniformBlock.name == baseName)
{
const bool arrayElementZero =
@@ -1698,7 +1724,7 @@
return GL_INVALID_INDEX;
}
-const UniformBlock &Program::getUniformBlockByIndex(GLuint index) const
+const InterfaceBlock &Program::getUniformBlockByIndex(GLuint index) const
{
ASSERT(index < static_cast<GLuint>(mState.mUniformBlocks.size()));
return mState.mUniformBlocks[index];
@@ -1716,6 +1742,11 @@
return mState.getUniformBlockBinding(uniformBlockIndex);
}
+GLuint Program::getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const
+{
+ return mState.getShaderStorageBlockBinding(shaderStorageBlockIndex);
+}
+
void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
{
mState.mTransformFeedbackVaryingNames.resize(count);
@@ -2110,26 +2141,6 @@
return true;
}
-bool Program::validateUniformBlocksCount(GLuint maxUniformBlocks,
- const std::vector<sh::InterfaceBlock> &intefaceBlocks,
- const std::string &errorMessage,
- InfoLog &infoLog) const
-{
- GLuint blockCount = 0;
- for (const sh::InterfaceBlock &block : intefaceBlocks)
- {
- if (block.staticUse || block.layout != sh::BLOCKLAYOUT_PACKED)
- {
- if (++blockCount > maxUniformBlocks)
- {
- infoLog << errorMessage << maxUniformBlocks << ")";
- return false;
- }
- }
- }
- return true;
-}
-
bool Program::validateVertexAndFragmentInterfaceBlocks(
const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
@@ -2137,18 +2148,18 @@
bool webglCompatibility) 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;
+ typedef std::map<std::string, const sh::InterfaceBlock *> InterfaceBlockMap;
+ InterfaceBlockMap linkedInterfaceBlocks;
for (const sh::InterfaceBlock &vertexInterfaceBlock : vertexInterfaceBlocks)
{
- linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
+ linkedInterfaceBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
}
for (const sh::InterfaceBlock &fragmentInterfaceBlock : fragmentInterfaceBlocks)
{
- auto entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
- if (entry != linkedUniformBlocks.end())
+ auto entry = linkedInterfaceBlocks.find(fragmentInterfaceBlock.name);
+ if (entry != linkedInterfaceBlocks.end())
{
const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock,
@@ -2157,43 +2168,55 @@
return false;
}
}
+ // TODO(jiajia.qin@intel.com): Add
+ // MAX_COMBINED_UNIFORM_BLOCKS/MAX_COMBINED_SHADER_STORAGE_BLOCKS validation.
}
return true;
}
-bool Program::linkUniformBlocks(const Context *context, InfoLog &infoLog)
+bool Program::linkInterfaceBlocks(const Context *context, InfoLog &infoLog)
{
const auto &caps = context->getCaps();
if (mState.mAttachedComputeShader)
{
Shader &computeShader = *mState.mAttachedComputeShader;
- const auto &computeInterfaceBlocks = computeShader.getUniformBlocks(context);
+ const auto &computeUniformBlocks = computeShader.getUniformBlocks(context);
- if (!validateUniformBlocksCount(
- caps.maxComputeUniformBlocks, computeInterfaceBlocks,
+ if (!validateInterfaceBlocksCount(
+ caps.maxComputeUniformBlocks, computeUniformBlocks,
"Compute shader uniform block count exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS (",
infoLog))
{
return false;
}
+
+ const auto &computeShaderStorageBlocks = computeShader.getShaderStorageBlocks(context);
+ if (!validateInterfaceBlocksCount(caps.maxComputeShaderStorageBlocks,
+ computeShaderStorageBlocks,
+ "Compute shader shader storage block count exceeds "
+ "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS (",
+ infoLog))
+ {
+ return false;
+ }
return true;
}
Shader &vertexShader = *mState.mAttachedVertexShader;
Shader &fragmentShader = *mState.mAttachedFragmentShader;
- const auto &vertexInterfaceBlocks = vertexShader.getUniformBlocks(context);
- const auto &fragmentInterfaceBlocks = fragmentShader.getUniformBlocks(context);
+ const auto &vertexUniformBlocks = vertexShader.getUniformBlocks(context);
+ const auto &fragmentUniformBlocks = fragmentShader.getUniformBlocks(context);
- if (!validateUniformBlocksCount(
- caps.maxVertexUniformBlocks, vertexInterfaceBlocks,
+ if (!validateInterfaceBlocksCount(
+ caps.maxVertexUniformBlocks, vertexUniformBlocks,
"Vertex shader uniform block count exceeds GL_MAX_VERTEX_UNIFORM_BLOCKS (", infoLog))
{
return false;
}
- if (!validateUniformBlocksCount(
- caps.maxFragmentUniformBlocks, fragmentInterfaceBlocks,
+ if (!validateInterfaceBlocksCount(
+ caps.maxFragmentUniformBlocks, fragmentUniformBlocks,
"Fragment shader uniform block count exceeds GL_MAX_FRAGMENT_UNIFORM_BLOCKS (",
infoLog))
{
@@ -2202,12 +2225,42 @@
}
bool webglCompatibility = context->getExtensions().webglCompatibility;
- if (!validateVertexAndFragmentInterfaceBlocks(vertexInterfaceBlocks, fragmentInterfaceBlocks,
+ if (!validateVertexAndFragmentInterfaceBlocks(vertexUniformBlocks, fragmentUniformBlocks,
infoLog, webglCompatibility))
{
return false;
}
+ if (context->getClientVersion() >= Version(3, 1))
+ {
+ const auto &vertexShaderStorageBlocks = vertexShader.getShaderStorageBlocks(context);
+ const auto &fragmentShaderStorageBlocks = fragmentShader.getShaderStorageBlocks(context);
+
+ if (!validateInterfaceBlocksCount(caps.maxVertexShaderStorageBlocks,
+ vertexShaderStorageBlocks,
+ "Vertex shader shader storage block count exceeds "
+ "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS (",
+ infoLog))
+ {
+ return false;
+ }
+ if (!validateInterfaceBlocksCount(caps.maxFragmentShaderStorageBlocks,
+ fragmentShaderStorageBlocks,
+ "Fragment shader shader storage block count exceeds "
+ "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS (",
+ infoLog))
+ {
+
+ return false;
+ }
+
+ if (!validateVertexAndFragmentInterfaceBlocks(vertexShaderStorageBlocks,
+ fragmentShaderStorageBlocks, infoLog,
+ webglCompatibility))
+ {
+ return false;
+ }
+ }
return true;
}
@@ -2741,54 +2794,36 @@
// TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
}
-void Program::gatherInterfaceBlockInfo(const Context *context)
+void Program::gatherComputeBlockInfo(const std::vector<sh::InterfaceBlock> &computeBlocks)
{
- ASSERT(mState.mUniformBlocks.empty());
-
- if (mState.mAttachedComputeShader)
+ for (const sh::InterfaceBlock &computeBlock : computeBlocks)
{
- Shader *computeShader = mState.getAttachedComputeShader();
- for (const sh::InterfaceBlock &computeBlock : computeShader->getUniformBlocks(context))
- {
+ // Only 'packed' blocks are allowed to be considered inactive.
+ if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
- // Only 'packed' blocks are allowed to be considered inactive.
- if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
- continue;
-
- for (UniformBlock &block : mState.mUniformBlocks)
- {
- if (block.name == computeBlock.name)
- {
- block.computeStaticUse = computeBlock.staticUse;
- }
- }
-
- defineUniformBlock(computeBlock, GL_COMPUTE_SHADER);
- }
- return;
+ defineInterfaceBlock(computeBlock, GL_COMPUTE_SHADER);
}
+}
+void Program::gatherVertexAndFragmentBlockInfo(
+ const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
+ const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks)
+{
std::set<std::string> visitedList;
- Shader *vertexShader = mState.getAttachedVertexShader();
-
- for (const sh::InterfaceBlock &vertexBlock : vertexShader->getUniformBlocks(context))
+ for (const sh::InterfaceBlock &vertexBlock : vertexInterfaceBlocks)
{
// Only 'packed' blocks are allowed to be considered inactive.
if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
- if (visitedList.count(vertexBlock.name) > 0)
- continue;
-
- defineUniformBlock(vertexBlock, GL_VERTEX_SHADER);
+ defineInterfaceBlock(vertexBlock, GL_VERTEX_SHADER);
visitedList.insert(vertexBlock.name);
}
- Shader *fragmentShader = mState.getAttachedFragmentShader();
-
- for (const sh::InterfaceBlock &fragmentBlock : fragmentShader->getUniformBlocks(context))
+ for (const sh::InterfaceBlock &fragmentBlock : fragmentInterfaceBlocks)
{
// Only 'packed' blocks are allowed to be considered inactive.
if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
@@ -2796,24 +2831,65 @@
if (visitedList.count(fragmentBlock.name) > 0)
{
- for (UniformBlock &block : mState.mUniformBlocks)
+ if (fragmentBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
- if (block.name == fragmentBlock.name)
+ for (InterfaceBlock &block : mState.mUniformBlocks)
{
- block.fragmentStaticUse = fragmentBlock.staticUse;
+ if (block.name == fragmentBlock.name)
+ {
+ block.fragmentStaticUse = fragmentBlock.staticUse;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(fragmentBlock.blockType == sh::BlockType::BLOCK_BUFFER);
+ for (InterfaceBlock &block : mState.mShaderStorageBlocks)
+ {
+ if (block.name == fragmentBlock.name)
+ {
+ block.fragmentStaticUse = fragmentBlock.staticUse;
+ }
}
}
continue;
}
- defineUniformBlock(fragmentBlock, GL_FRAGMENT_SHADER);
+ defineInterfaceBlock(fragmentBlock, GL_FRAGMENT_SHADER);
visitedList.insert(fragmentBlock.name);
}
+}
+
+void Program::gatherInterfaceBlockInfo(const Context *context)
+{
+ ASSERT(mState.mUniformBlocks.empty());
+ ASSERT(mState.mShaderStorageBlocks.empty());
+
+ if (mState.mAttachedComputeShader)
+ {
+ Shader *computeShader = mState.getAttachedComputeShader();
+
+ gatherComputeBlockInfo(computeShader->getUniformBlocks(context));
+ gatherComputeBlockInfo(computeShader->getShaderStorageBlocks(context));
+ return;
+ }
+
+ Shader *vertexShader = mState.getAttachedVertexShader();
+ Shader *fragmentShader = mState.getAttachedFragmentShader();
+
+ gatherVertexAndFragmentBlockInfo(vertexShader->getUniformBlocks(context),
+ fragmentShader->getUniformBlocks(context));
+ if (context->getClientVersion() >= Version(3, 1))
+ {
+ gatherVertexAndFragmentBlockInfo(vertexShader->getShaderStorageBlocks(context),
+ fragmentShader->getShaderStorageBlocks(context));
+ }
+
// Set initial bindings from shader.
for (unsigned int blockIndex = 0; blockIndex < mState.mUniformBlocks.size(); blockIndex++)
{
- UniformBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
+ InterfaceBlock &uniformBlock = mState.mUniformBlocks[blockIndex];
bindUniformBlock(blockIndex, uniformBlock.binding);
}
}
@@ -2863,23 +2939,31 @@
}
}
-void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
+void Program::defineInterfaceBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
{
- int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
size_t blockSize = 0;
+ std::vector<unsigned int> blockIndexes;
- // Track the first and last uniform index to determine the range of active uniforms in the
- // block.
- size_t firstBlockUniformIndex = mState.mUniforms.size();
- defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(),
- interfaceBlock.fieldMappedPrefix(), blockIndex);
- size_t lastBlockUniformIndex = mState.mUniforms.size();
-
- std::vector<unsigned int> blockUniformIndexes;
- for (size_t blockUniformIndex = firstBlockUniformIndex;
- blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
- blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
+ int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
+ // Track the first and last uniform index to determine the range of active uniforms in the
+ // block.
+ size_t firstBlockUniformIndex = mState.mUniforms.size();
+ defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(),
+ interfaceBlock.fieldMappedPrefix(), blockIndex);
+ size_t lastBlockUniformIndex = mState.mUniforms.size();
+
+ for (size_t blockUniformIndex = firstBlockUniformIndex;
+ blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
+ {
+ blockIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
+ }
+ }
+ else
+ {
+ // TODO(jiajia.qin@intel.com) : Add buffer variables support and calculate the block index.
+ ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
}
// ESSL 3.10 section 4.4.4 page 58:
// Any uniform or shader storage block declared without a binding qualifier is initially
@@ -2889,16 +2973,22 @@
{
for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
{
- // Don't define this block at all if it's not active in the implementation.
- if (!mProgram->getUniformBlockSize(
- interfaceBlock.name + ArrayString(arrayElement),
- interfaceBlock.mappedName + ArrayString(arrayElement), &blockSize))
+ // TODO(jiajia.qin@intel.com) : use GetProgramResourceiv to calculate BUFFER_DATA_SIZE
+ // of UniformBlock and ShaderStorageBlock.
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
- continue;
+ // Don't define this block at all if it's not active in the implementation.
+ if (!mProgram->getUniformBlockSize(
+ interfaceBlock.name + ArrayString(arrayElement),
+ interfaceBlock.mappedName + ArrayString(arrayElement), &blockSize))
+ {
+ continue;
+ }
}
- UniformBlock block(interfaceBlock.name, interfaceBlock.mappedName, true, arrayElement,
- blockBinding + arrayElement);
- block.memberIndexes = blockUniformIndexes;
+
+ InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, true, arrayElement,
+ blockBinding + arrayElement);
+ block.memberIndexes = blockIndexes;
switch (shaderType)
{
@@ -2921,22 +3011,37 @@
UNREACHABLE();
}
- // Since all block elements in an array share the same active uniforms, they will all be
- // active once any uniform member is used. So, since interfaceBlock.name[0] was active,
- // here we will add every block element in the array.
+ // Since all block elements in an array share the same active interface blocks, they
+ // will all be active once any block member is used. So, since interfaceBlock.name[0]
+ // was active, here we will add every block element in the array.
block.dataSize = static_cast<unsigned int>(blockSize);
- mState.mUniformBlocks.push_back(block);
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
+ {
+ mState.mUniformBlocks.push_back(block);
+ }
+ else
+ {
+ ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
+ mState.mShaderStorageBlocks.push_back(block);
+ }
}
}
else
{
- if (!mProgram->getUniformBlockSize(interfaceBlock.name, interfaceBlock.mappedName,
- &blockSize))
+ // TODO(jiajia.qin@intel.com) : use GetProgramResourceiv to calculate BUFFER_DATA_SIZE
+ // of UniformBlock and ShaderStorageBlock.
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
- return;
+ if (!mProgram->getUniformBlockSize(interfaceBlock.name, interfaceBlock.mappedName,
+ &blockSize))
+ {
+ return;
+ }
}
- UniformBlock block(interfaceBlock.name, interfaceBlock.mappedName, false, 0, blockBinding);
- block.memberIndexes = blockUniformIndexes;
+
+ InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, false, 0,
+ blockBinding);
+ block.memberIndexes = blockIndexes;
switch (shaderType)
{
@@ -2960,7 +3065,15 @@
}
block.dataSize = static_cast<unsigned int>(blockSize);
- mState.mUniformBlocks.push_back(block);
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
+ {
+ mState.mUniformBlocks.push_back(block);
+ }
+ else
+ {
+ ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
+ mState.mShaderStorageBlocks.push_back(block);
+ }
}
}