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());
......
......@@ -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