Commit 729b2c6e by Jiajia Qin Committed by Commit Bot

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: 's avatarGeoff Lang <geofflang@chromium.org>
parent 47bf2dc5
......@@ -1237,6 +1237,12 @@ void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfa
out << ", ";
if (interfaceBlock->blockBinding() > 0)
{
out << "binding = " << interfaceBlock->blockBinding();
out << ", ";
}
switch (interfaceBlock->matrixPacking())
{
case EmpUnspecified:
......
......@@ -120,6 +120,7 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.MaxAtomicCounterBufferSize = caps.maxAtomicCounterBufferSize;
mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings;
mResources.MaxShaderStorageBufferBindings = caps.maxShaderStorageBufferBindings;
// Needed by point size clamping workaround
mResources.MaxPointSize = caps.maxAliasedPointSize;
......
......@@ -90,6 +90,26 @@ void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *v
}
}
void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
{
stream->writeString(block.name);
stream->writeString(block.mappedName);
stream->writeInt(block.isArray);
stream->writeInt(block.arrayElement);
WriteShaderVariableBuffer(stream, block);
}
void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
{
block->name = stream->readString();
block->mappedName = stream->readString();
block->isArray = stream->readBool();
block->arrayElement = stream->readInt<unsigned int>();
LoadShaderVariableBuffer(stream, block);
}
class HashStream final : angle::NonCopyable
{
public:
......@@ -232,18 +252,23 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
++uniformBlockIndex)
{
UniformBlock uniformBlock;
stream.readString(&uniformBlock.name);
stream.readString(&uniformBlock.mappedName);
stream.readBool(&uniformBlock.isArray);
stream.readInt(&uniformBlock.arrayElement);
LoadShaderVariableBuffer(&stream, &uniformBlock);
InterfaceBlock uniformBlock;
LoadInterfaceBlock(&stream, &uniformBlock);
state->mUniformBlocks.push_back(uniformBlock);
state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
}
unsigned int shaderStorageBlockCount = stream.readInt<unsigned int>();
ASSERT(state->mShaderStorageBlocks.empty());
for (unsigned int shaderStorageBlockIndex = 0;
shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex)
{
InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(&stream, &shaderStorageBlock);
state->mShaderStorageBlocks.push_back(shaderStorageBlock);
}
unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
ASSERT(state->mAtomicCounterBuffers.empty());
for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
......@@ -412,14 +437,15 @@ void MemoryProgramCache::Serialize(const Context *context,
}
stream.writeInt(state.getUniformBlocks().size());
for (const UniformBlock &uniformBlock : state.getUniformBlocks())
for (const InterfaceBlock &uniformBlock : state.getUniformBlocks())
{
stream.writeString(uniformBlock.name);
stream.writeString(uniformBlock.mappedName);
stream.writeInt(uniformBlock.isArray);
stream.writeInt(uniformBlock.arrayElement);
WriteInterfaceBlock(&stream, uniformBlock);
}
WriteShaderVariableBuffer(&stream, uniformBlock);
stream.writeInt(state.getShaderStorageBlocks().size());
for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks())
{
WriteInterfaceBlock(&stream, shaderStorageBlock);
}
stream.writeInt(state.mAtomicCounterBuffers.size());
......
......@@ -193,6 +193,27 @@ bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::st
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 @@ Error Program::link(const gl::Context *context)
return NoError();
}
if (!linkUniformBlocks(context, mInfoLog))
if (!linkInterfaceBlocks(context, mInfoLog))
{
return NoError();
}
......@@ -740,7 +761,7 @@ Error Program::link(const gl::Context *context)
return NoError();
}
if (!linkUniformBlocks(context, mInfoLog))
if (!linkInterfaceBlocks(context, mInfoLog))
{
return NoError();
}
......@@ -1633,13 +1654,18 @@ GLuint Program::getActiveUniformBlockCount() const
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 @@ GLint Program::getActiveUniformBlockMaxLength() const
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 @@ GLuint Program::getUniformBlockIndex(const std::string &name) const
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 @@ GLuint Program::getUniformBlockIndex(const std::string &name) const
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 @@ GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
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 @@ bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
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 Program::validateVertexAndFragmentInterfaceBlocks(
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 @@ bool Program::validateVertexAndFragmentInterfaceBlocks(
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 Program::linkUniformBlocks(const Context *context, InfoLog &infoLog)
}
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 @@ void Program::gatherAtomicCounterBuffers()
// 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;
for (UniformBlock &block : mState.mUniformBlocks)
{
if (block.name == computeBlock.name)
{
block.computeStaticUse = computeBlock.staticUse;
}
}
// Only 'packed' blocks are allowed to be considered inactive.
if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
continue;
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 @@ void Program::gatherInterfaceBlockInfo(const Context *context)
if (visitedList.count(fragmentBlock.name) > 0)
{
for (UniformBlock &block : mState.mUniformBlocks)
if (fragmentBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
for (InterfaceBlock &block : mState.mUniformBlocks)
{
if (block.name == fragmentBlock.name)
{
block.fragmentStaticUse = fragmentBlock.staticUse;
}
}
}
else
{
if (block.name == fragmentBlock.name)
ASSERT(fragmentBlock.blockType == sh::BlockType::BLOCK_BUFFER);
for (InterfaceBlock &block : mState.mShaderStorageBlocks)
{
block.fragmentStaticUse = fragmentBlock.staticUse;
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::defineUniformBlockMembers(const std::vector<VarT> &fields,
}
}
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();
if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
{
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();
std::vector<unsigned int> blockUniformIndexes;
for (size_t blockUniformIndex = firstBlockUniformIndex;
blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
for (size_t blockUniformIndex = firstBlockUniformIndex;
blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
{
blockIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
}
}
else
{
blockUniformIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
// 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 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
{
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 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
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 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
}
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);
}
}
}
......
......@@ -246,6 +246,11 @@ class ProgramState final : angle::NonCopyable
ASSERT(uniformBlockIndex < mUniformBlocks.size());
return mUniformBlocks[uniformBlockIndex].binding;
}
GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
{
ASSERT(blockIndex < mShaderStorageBlocks.size());
return mShaderStorageBlocks[blockIndex].binding;
}
const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
{
return mActiveUniformBlockBindings;
......@@ -260,7 +265,11 @@ class ProgramState final : angle::NonCopyable
const std::map<int, VariableLocation> &getOutputLocations() const { return mOutputLocations; }
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
{
return mShaderStorageBlocks;
}
const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
const std::vector<ImageBinding> &getImageBindings() const { return mImageBindings; }
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
......@@ -319,7 +328,8 @@ class ProgramState final : angle::NonCopyable
// This makes opaque uniform validation easier, since we don't need a separate list.
std::vector<LinkedUniform> mUniforms;
std::vector<VariableLocation> mUniformLocations;
std::vector<UniformBlock> mUniformBlocks;
std::vector<InterfaceBlock> mUniformBlocks;
std::vector<InterfaceBlock> mShaderStorageBlocks;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mSamplerUniformRange;
RangeUI mImageUniformRange;
......@@ -474,14 +484,16 @@ class Program final : angle::NonCopyable, public LabeledObject
void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
GLuint getActiveUniformBlockCount() const;
GLuint getActiveShaderStorageBlockCount() const;
GLint getActiveUniformBlockMaxLength() const;
GLuint getUniformBlockIndex(const std::string &name) const;
void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
GLuint getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const;
const UniformBlock &getUniformBlockByIndex(GLuint index) const;
const InterfaceBlock &getUniformBlockByIndex(GLuint index) const;
void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode);
void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const;
......@@ -570,16 +582,12 @@ class Program final : angle::NonCopyable, public LabeledObject
void unlink();
bool linkAttributes(const Context *context, InfoLog &infoLog);
bool validateUniformBlocksCount(GLuint maxUniformBlocks,
const std::vector<sh::InterfaceBlock> &block,
const std::string &errorMessage,
InfoLog &infoLog) const;
bool validateVertexAndFragmentInterfaceBlocks(
const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
InfoLog &infoLog,
bool webglCompatibility) const;
bool linkUniformBlocks(const Context *context, InfoLog &infoLog);
bool linkInterfaceBlocks(const Context *context, InfoLog &infoLog);
bool linkVaryings(const Context *context, InfoLog &infoLog) const;
bool linkUniforms(const Context *context,
......@@ -614,6 +622,10 @@ class Program final : angle::NonCopyable, public LabeledObject
void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers();
void gatherComputeBlockInfo(const std::vector<sh::InterfaceBlock> &computeBlocks);
void gatherVertexAndFragmentBlockInfo(
const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks);
void gatherInterfaceBlockInfo(const Context *context);
template <typename VarT>
void defineUniformBlockMembers(const std::vector<VarT> &fields,
......@@ -621,7 +633,7 @@ class Program final : angle::NonCopyable, public LabeledObject
const std::string &mappedPrefix,
int blockIndex);
void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
void defineInterfaceBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
// Both these function update the cached uniform values and return a modified "count"
// so that the uniform update doesn't overflow the uniform.
......
......@@ -116,21 +116,21 @@ ShaderVariableBuffer::~ShaderVariableBuffer()
{
}
UniformBlock::UniformBlock() : isArray(false), arrayElement(0)
InterfaceBlock::InterfaceBlock() : isArray(false), arrayElement(0)
{
}
UniformBlock::UniformBlock(const std::string &nameIn,
const std::string &mappedNameIn,
bool isArrayIn,
unsigned int arrayElementIn,
int bindingIn)
InterfaceBlock::InterfaceBlock(const std::string &nameIn,
const std::string &mappedNameIn,
bool isArrayIn,
unsigned int arrayElementIn,
int bindingIn)
: name(nameIn), mappedName(mappedNameIn), isArray(isArrayIn), arrayElement(arrayElementIn)
{
binding = bindingIn;
}
std::string UniformBlock::nameWithArrayIndex() const
std::string InterfaceBlock::nameWithArrayIndex() const
{
std::stringstream fullNameStr;
fullNameStr << name;
......@@ -142,7 +142,7 @@ std::string UniformBlock::nameWithArrayIndex() const
return fullNameStr.str();
}
std::string UniformBlock::mappedNameWithArrayIndex() const
std::string InterfaceBlock::mappedNameWithArrayIndex() const
{
std::stringstream fullNameStr;
fullNameStr << mappedName;
......
......@@ -74,17 +74,17 @@ struct ShaderVariableBuffer
using AtomicCounterBuffer = ShaderVariableBuffer;
// Helper struct representing a single shader uniform block
struct UniformBlock : public ShaderVariableBuffer
// Helper struct representing a single shader interface block
struct InterfaceBlock : public ShaderVariableBuffer
{
UniformBlock();
UniformBlock(const std::string &nameIn,
const std::string &mappedNameIn,
bool isArrayIn,
unsigned int arrayElementIn,
int bindingIn);
UniformBlock(const UniformBlock &other) = default;
UniformBlock &operator=(const UniformBlock &other) = default;
InterfaceBlock();
InterfaceBlock(const std::string &nameIn,
const std::string &mappedNameIn,
bool isArrayIn,
unsigned int arrayElementIn,
int bindingIn);
InterfaceBlock(const InterfaceBlock &other) = default;
InterfaceBlock &operator=(const InterfaceBlock &other) = default;
std::string nameWithArrayIndex() const;
std::string mappedNameWithArrayIndex() const;
......
......@@ -588,7 +588,7 @@ GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programI
case GL_UNIFORM_BLOCK:
maxNameLength =
FindMaxSize(program->getState().getUniformBlocks(), &UniformBlock::name);
FindMaxSize(program->getState().getUniformBlocks(), &InterfaceBlock::name);
break;
// TODO(jie.a.chen@intel.com): more interfaces.
......@@ -612,7 +612,7 @@ GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum
{
case GL_UNIFORM_BLOCK:
return FindMaxSize(program->getState().getUniformBlocks(),
&UniformBlock::memberIndexes);
&InterfaceBlock::memberIndexes);
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_SHADER_STORAGE_BLOCK:
......@@ -1010,7 +1010,7 @@ void QueryActiveUniformBlockiv(const Program *program,
GLenum pname,
GLint *params)
{
const UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
const InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
switch (pname)
{
case GL_UNIFORM_BLOCK_BINDING:
......
......@@ -1670,7 +1670,7 @@ void ProgramD3D::ensureUniformBlocksInitialized()
SafeGetImplAs<ShaderD3D>(mState.getAttachedFragmentShader());
const ShaderD3D *computeShaderD3D = SafeGetImplAs<ShaderD3D>(mState.getAttachedComputeShader());
for (const gl::UniformBlock &uniformBlock : mState.getUniformBlocks())
for (const gl::InterfaceBlock &uniformBlock : mState.getUniformBlocks())
{
unsigned int uniformBlockElement = uniformBlock.isArray ? uniformBlock.arrayElement : 0;
......
......@@ -508,7 +508,7 @@ void ProgramGL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformB
if (mUniformBlockRealLocationMap.empty())
{
mUniformBlockRealLocationMap.reserve(mState.getUniformBlocks().size());
for (const gl::UniformBlock &uniformBlock : mState.getUniformBlocks())
for (const gl::InterfaceBlock &uniformBlock : mState.getUniformBlocks())
{
const std::string &mappedNameWithIndex = uniformBlock.mappedNameWithArrayIndex();
GLuint blockIndex =
......
......@@ -180,6 +180,7 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions,
mIndexedBuffers[GL_UNIFORM_BUFFER].resize(rendererCaps.maxCombinedUniformBlocks);
mIndexedBuffers[GL_ATOMIC_COUNTER_BUFFER].resize(rendererCaps.maxCombinedAtomicCounterBuffers);
mIndexedBuffers[GL_SHADER_STORAGE_BUFFER].resize(rendererCaps.maxCombinedShaderStorageBlocks);
for (GLenum queryType : QueryTypes)
{
......@@ -980,6 +981,28 @@ void StateManagerGL::updateProgramTextureAndSamplerBindings(const gl::Context *c
}
}
}
for (size_t blockIndex = 0; blockIndex < program->getActiveShaderStorageBlockCount();
blockIndex++)
{
GLuint binding = program->getShaderStorageBlockBinding(static_cast<GLuint>(blockIndex));
const auto &shaderStorageBuffer = glState.getIndexedShaderStorageBuffer(binding);
if (shaderStorageBuffer.get() != nullptr)
{
BufferGL *bufferGL = GetImplAs<BufferGL>(shaderStorageBuffer.get());
if (shaderStorageBuffer.getSize() == 0)
{
bindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, bufferGL->getBufferID());
}
else
{
bindBufferRange(GL_SHADER_STORAGE_BUFFER, binding, bufferGL->getBufferID(),
shaderStorageBuffer.getOffset(), shaderStorageBuffer.getSize());
}
}
}
}
gl::Error StateManagerGL::setGenericDrawState(const gl::Context *context)
......
......@@ -2617,7 +2617,7 @@ bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
for (unsigned int uniformBlockIndex = 0;
uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
{
const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
const gl::InterfaceBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
const OffsetBindingPointer<Buffer> &uniformBuffer =
state.getIndexedUniformBuffer(blockBinding);
......@@ -5584,7 +5584,7 @@ bool ValidateGetActiveUniformBlockivBase(Context *context,
{
if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
{
const UniformBlock &uniformBlock =
const InterfaceBlock &uniformBlock =
programObject->getUniformBlockByIndex(uniformBlockIndex);
*length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
}
......
......@@ -74,6 +74,7 @@
'<(angle_path)/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp',
'<(angle_path)/src/tests/gl_tests/RobustClientMemoryTest.cpp',
'<(angle_path)/src/tests/gl_tests/RobustResourceInitTest.cpp',
'<(angle_path)/src/tests/gl_tests/ShaderStorageBufferTest.cpp',
'<(angle_path)/src/tests/gl_tests/SimpleOperationTest.cpp',
'<(angle_path)/src/tests/gl_tests/SixteenBppTextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/SRGBFramebufferTest.cpp',
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ShaderStorageBufferTest:
// Various tests related for shader storage buffers.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
class ShaderStorageBufferTest31 : public ANGLETest
{
protected:
ShaderStorageBufferTest31()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// Matched block names within a shader interface must match in terms of having the same number of
// declarations with the same sequence of types.
TEST_P(ShaderStorageBufferTest31, MatchedBlockNameWithDifferentMemberType)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"buffer blockName {\n"
" float data;\n"
"};\n"
"void main()\n"
"{\n"
"}\n";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"buffer blockName {\n"
" uint data;\n"
"};\n"
"void main()\n"
"{\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_EQ(0u, program);
}
// Linking should fail if blocks in vertex shader exceed GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS.
TEST_P(ShaderStorageBufferTest31, ExceedMaxVertexShaderStorageBlocks)
{
std::ostringstream instanceCount;
GLint maxVertexShaderStorageBlocks;
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertexShaderStorageBlocks);
instanceCount << maxVertexShaderStorageBlocks;
const std::string &vertexShaderSource =
"#version 310 es\n"
"layout(shared) buffer blockName {\n"
" uint data;\n"
"} instance[" +
instanceCount.str() +
" + 1];\n"
"void main()\n"
"{\n"
"}\n";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"void main()\n"
"{\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_EQ(0u, program);
}
// Test shader storage buffer read write.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite)
{
// TODO(jiajia.qin@intel.com): Figure out why it fails on AMD platform.
ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
const std::string &csSource =
"#version 310 es\n"
"layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
"layout(binding = 1) buffer blockName {\n"
" uint data[2];\n"
"} instanceName;\n"
"void main()\n"
"{\n"
" instanceName.data[0] = 3u;\n"
" if (instanceName.data[0] == 3u)\n"
" instanceName.data[1] = 4u;\n"
" else\n"
" instanceName.data[1] = 5u;\n"
"}\n";
ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
glUseProgram(program.get());
unsigned int bufferData[2] = {0u};
// Create shader storage buffer
GLBuffer shaderStorageBuffer;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(bufferData), nullptr, GL_STATIC_DRAW);
// Bind shader storage buffer
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
// Dispath compute
glDispatchCompute(1, 1, 1);
glFinish();
// Read back shader storage buffer
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(bufferData), GL_MAP_READ_BIT);
memcpy(bufferData, ptr, sizeof(bufferData));
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
EXPECT_EQ(3u, bufferData[0]);
EXPECT_EQ(4u, bufferData[1]);
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(ShaderStorageBufferTest31, ES31_OPENGL(), ES31_OPENGLES());
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment