Support UBOs in RendererGL and ProgramGL.
BUG=angleproject:882
BUG=angleproject:883
Change-Id: I36f8ef42d87e289658a6ba4899380bc72b9bcebf
Reviewed-on: https://chromium-review.googlesource.com/299871
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 14a50ba..13277b3 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -1520,6 +1520,7 @@
void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
{
mData.mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding;
+ mProgram->setUniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
}
GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const
@@ -1533,6 +1534,7 @@
{
mData.mUniformBlockBindings[blockId] = 0;
}
+ mData.mActiveUniformBlockBindings.reset();
}
void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode)
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 6e9d682..9a0eac9 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -182,6 +182,10 @@
ASSERT(uniformBlockIndex < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS);
return mUniformBlockBindings[uniformBlockIndex];
}
+ const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
+ {
+ return mActiveUniformBlockBindings;
+ }
const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; }
const AttributesMask &getActiveAttribLocationsMask() const
{
@@ -213,6 +217,7 @@
GLenum mTransformFeedbackBufferMode;
GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS];
+ UniformBlockBindingMask mActiveUniformBlockBindings;
std::vector<sh::Attribute> mAttributes;
std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 1e26f2b..746b514 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -995,32 +995,10 @@
mUniformBuffers[index].set(buffer, offset, size);
}
-GLuint State::getIndexedUniformBufferId(GLuint index) const
+const OffsetBindingPointer<Buffer> &State::getIndexedUniformBuffer(size_t index) const
{
ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].id();
-}
-
-Buffer *State::getIndexedUniformBuffer(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].get();
-}
-
-GLintptr State::getIndexedUniformBufferOffset(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].getOffset();
-}
-
-GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const
-{
- ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
-
- return mUniformBuffers[index].getSize();
+ return mUniformBuffers[index];
}
void State::setCopyReadBufferBinding(Buffer *buffer)
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index 1102056..b53dce6 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -203,10 +203,7 @@
// GL_UNIFORM_BUFFER - Both indexed and generic targets
void setGenericUniformBufferBinding(Buffer *buffer);
void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size);
- GLuint getIndexedUniformBufferId(GLuint index) const;
- Buffer *getIndexedUniformBuffer(GLuint index) const;
- GLintptr getIndexedUniformBufferOffset(GLuint index) const;
- GLsizeiptr getIndexedUniformBufferSize(GLuint index) const;
+ const OffsetBindingPointer<Buffer> &getIndexedUniformBuffer(size_t index) const;
// GL_COPY_[READ/WRITE]_BUFFER
void setCopyReadBufferBinding(Buffer *buffer);
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index b7d9084..9fea750 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -273,6 +273,9 @@
// Used in Program and VertexArray.
typedef std::bitset<MAX_VERTEX_ATTRIBS> AttributesMask;
+
+// Use in Program
+typedef std::bitset<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> UniformBlockBindingMask;
}
namespace rx
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index a47b18e..5cc4abe 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -66,6 +66,9 @@
virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0;
+ // TODO: synchronize in syncState when dirty bits exist.
+ virtual void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
+
// Gather uniform block active uniform indices, and uniform block offset info.
virtual void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
std::vector<gl::LinkedUniform> *uniforms) = 0;
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 9011f86..ae50617 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -1344,6 +1344,10 @@
setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
}
+void ProgramD3D::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+}
+
void ProgramD3D::defineUniformsAndAssignRegisters()
{
D3DUniformMap uniformMap;
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index 148371e..f08e0fe 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -131,6 +131,8 @@
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+ void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+
const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; }
const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; }
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 1cb4a0b..ab01482 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1008,13 +1008,14 @@
continue;
}
- gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
- GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
- GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
+ const OffsetBindingPointer<gl::Buffer> &uniformBuffer =
+ data.state->getIndexedUniformBuffer(binding);
+ GLintptr uniformBufferOffset = uniformBuffer.getOffset();
+ GLsizeiptr uniformBufferSize = uniformBuffer.getSize();
- if (uniformBuffer)
+ if (uniformBuffer.get() != nullptr)
{
- Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer);
+ Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get());
ID3D11Buffer *constantBuffer;
if (mRenderer11DeviceCaps.supportsConstantBufferOffsets)
@@ -1068,13 +1069,14 @@
continue;
}
- gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding);
- GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding);
- GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding);
+ const OffsetBindingPointer<gl::Buffer> &uniformBuffer =
+ data.state->getIndexedUniformBuffer(binding);
+ GLintptr uniformBufferOffset = uniformBuffer.getOffset();
+ GLsizeiptr uniformBufferSize = uniformBuffer.getSize();
- if (uniformBuffer)
+ if (uniformBuffer.get() != nullptr)
{
- Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer);
+ Buffer11 *bufferStorage = GetImplAs<Buffer11>(uniformBuffer.get());
ID3D11Buffer *constantBuffer;
if (mRenderer11DeviceCaps.supportsConstantBufferOffsets)
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index bbb4540..3363c72 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -299,6 +299,12 @@
mFunctions->uniformMatrix4x3fv(uniLoc(location), count, transpose, value);
}
+void ProgramGL::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ mFunctions->uniformBlockBinding(mProgramID, mUniformBlockRealLocationMap[uniformBlockIndex],
+ uniformBlockBinding);
+}
+
void ProgramGL::reset()
{
mUniformRealLocationMap.clear();
@@ -316,9 +322,104 @@
return mSamplerBindings;
}
-void ProgramGL::gatherUniformBlockInfo(std::vector<gl::UniformBlock> * /*uniformBlocks*/,
- std::vector<gl::LinkedUniform> * /*uniforms*/)
+void ProgramGL::gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
+ std::vector<gl::LinkedUniform> *uniforms)
{
- // TODO(jmadill): Gather uniform block layout info, and data sizes.
+ mUniformBlockRealLocationMap.resize(uniformBlocks->size(), 0);
+
+ for (int i = 0; i < uniformBlocks->size(); i++)
+ {
+ auto &uniformBlock = uniformBlocks->at(i);
+
+ std::stringstream fullNameStr;
+ fullNameStr << uniformBlock.name;
+ if (uniformBlock.isArray)
+ {
+ fullNameStr << "[" << uniformBlock.arrayElement << "]";
+ }
+
+ GLuint blockIndex = mFunctions->getUniformBlockIndex(mProgramID, fullNameStr.str().c_str());
+ if (blockIndex != GL_INVALID_INDEX)
+ {
+ mUniformBlockRealLocationMap[i] = blockIndex;
+
+ GLint dataSize = 0;
+ mFunctions->getActiveUniformBlockiv(mProgramID, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE,
+ &dataSize);
+ uniformBlock.dataSize = dataSize;
+ }
+ else
+ {
+ // Remove this uniform block
+ uniformBlocks->erase(uniformBlocks->begin() + i);
+ i--;
+ }
+ }
+
+ for (int uniformIdx = 0; uniformIdx < uniforms->size(); uniformIdx++)
+ {
+ auto &uniform = uniforms->at(uniformIdx);
+ if (uniform.isInDefaultBlock())
+ {
+ continue;
+ }
+
+ const GLchar *uniformName = uniform.name.c_str();
+ GLuint uniformIndex = 0;
+ mFunctions->getUniformIndices(mProgramID, 1, &uniformName, &uniformIndex);
+
+ if (uniformIndex == -1)
+ {
+ // Uniform member has been optimized out, remove it from the list
+ // TODO: Clean this up by using a class to wrap around the uniforms so manual removal is
+ // not needed.
+ for (size_t uniformBlockIdx = 0; uniformBlockIdx < uniformBlocks->size();
+ uniformBlockIdx++)
+ {
+ auto &uniformBlock = uniformBlocks->at(uniformBlockIdx);
+ for (int memberIndex = 0; memberIndex < uniformBlock.memberUniformIndexes.size();
+ memberIndex++)
+ {
+ if (uniformBlock.memberUniformIndexes[memberIndex] ==
+ static_cast<unsigned int>(uniformIdx))
+ {
+ uniformBlock.memberUniformIndexes.erase(
+ uniformBlock.memberUniformIndexes.begin() + memberIndex);
+ memberIndex--;
+ }
+ else if (uniformBlock.memberUniformIndexes[memberIndex] >
+ static_cast<unsigned int>(uniformIdx))
+ {
+ uniformBlock.memberUniformIndexes[memberIndex]--;
+ }
+ }
+ }
+ uniforms->erase(uniforms->begin() + uniformIdx);
+ uniformIdx--;
+ }
+ else
+ {
+ GLint offset = 0;
+ mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_OFFSET,
+ &offset);
+ uniform.blockInfo.offset = offset;
+
+ GLint arrayStride = 0;
+ mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_ARRAY_STRIDE,
+ &arrayStride);
+ uniform.blockInfo.arrayStride = arrayStride;
+
+ GLint matrixStride = 0;
+ mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_MATRIX_STRIDE,
+ &matrixStride);
+ uniform.blockInfo.matrixStride = matrixStride;
+
+ // TODO: determine this at the gl::Program level.
+ GLint isRowMajorMatrix = 0;
+ mFunctions->getActiveUniformsiv(mProgramID, 1, &uniformIndex, GL_UNIFORM_IS_ROW_MAJOR,
+ &isRowMajorMatrix);
+ uniform.blockInfo.isRowMajorMatrix = isRowMajorMatrix != GL_FALSE;
+ }
+ }
}
}
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 982d5bb..15ced61 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -62,6 +62,8 @@
void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override;
+ void setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+
void gatherUniformBlockInfo(std::vector<gl::UniformBlock> *uniformBlocks,
std::vector<gl::LinkedUniform> *uniforms) override;
@@ -78,6 +80,7 @@
StateManagerGL *mStateManager;
std::vector<GLint> mUniformRealLocationMap;
+ std::vector<GLuint> mUniformBlockRealLocationMap;
// An array of the samplers that are used by the program
std::vector<SamplerBindingGL> mSamplerBindings;
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index 7c7a246..33dc97c 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -22,12 +22,18 @@
namespace rx
{
+
+StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0)
+{
+}
+
StateManagerGL::StateManagerGL(const FunctionsGL *functions, const gl::Caps &rendererCaps)
: mFunctions(functions),
mProgram(0),
mVAO(0),
mVertexAttribCurrentValues(rendererCaps.maxVertexAttributes),
mBuffers(),
+ mIndexedBuffers(),
mTextureUnitIndex(0),
mTextures(),
mSamplers(rendererCaps.maxCombinedTextureImageUnits, 0),
@@ -103,6 +109,8 @@
mTextures[GL_TEXTURE_2D_ARRAY].resize(rendererCaps.maxCombinedTextureImageUnits);
mTextures[GL_TEXTURE_3D].resize(rendererCaps.maxCombinedTextureImageUnits);
+ mIndexedBuffers[GL_UNIFORM_BUFFER].resize(rendererCaps.maxCombinedUniformBlocks);
+
// Initialize point sprite state for desktop GL
if (mFunctions->standard == STANDARD_GL_DESKTOP)
{
@@ -193,6 +201,17 @@
}
}
+ for (const auto &bufferTypeIter : mIndexedBuffers)
+ {
+ for (size_t bindIndex = 0; bindIndex < bufferTypeIter.second.size(); bindIndex++)
+ {
+ if (bufferTypeIter.second[bindIndex].buffer == buffer)
+ {
+ bindBufferBase(bufferTypeIter.first, bindIndex, 0);
+ }
+ }
+ }
+
mFunctions->deleteBuffers(1, &buffer);
}
}
@@ -255,6 +274,35 @@
}
}
+void StateManagerGL::bindBufferBase(GLenum type, size_t index, GLuint buffer)
+{
+ auto &binding = mIndexedBuffers[type][index];
+ if (binding.buffer != buffer || binding.offset != static_cast<size_t>(-1) ||
+ binding.size != static_cast<size_t>(-1))
+ {
+ binding.buffer = buffer;
+ binding.offset = static_cast<size_t>(-1);
+ binding.size = static_cast<size_t>(-1);
+ mFunctions->bindBufferBase(type, static_cast<GLuint>(index), buffer);
+ }
+}
+
+void StateManagerGL::bindBufferRange(GLenum type,
+ size_t index,
+ GLuint buffer,
+ size_t offset,
+ size_t size)
+{
+ auto &binding = mIndexedBuffers[type][index];
+ if (binding.buffer != buffer || binding.offset != offset || binding.size != size)
+ {
+ binding.buffer = buffer;
+ binding.offset = offset;
+ binding.size = size;
+ mFunctions->bindBufferRange(type, static_cast<GLuint>(index), buffer, offset, size);
+ }
+}
+
void StateManagerGL::activeTexture(size_t unit)
{
if (mTextureUnitIndex != unit)
@@ -498,6 +546,30 @@
const ProgramGL *programGL = GetImplAs<ProgramGL>(program);
useProgram(programGL->getProgramID());
+ for (size_t uniformBlockIndex = 0;
+ uniformBlockIndex < gl::IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS;
+ uniformBlockIndex++)
+ {
+ GLuint binding = program->getUniformBlockBinding(static_cast<GLuint>(uniformBlockIndex));
+ const OffsetBindingPointer<gl::Buffer> &uniformBuffer =
+ data.state->getIndexedUniformBuffer(binding);
+
+ if (uniformBuffer.get() != nullptr)
+ {
+ BufferGL *bufferGL = GetImplAs<BufferGL>(uniformBuffer.get());
+
+ if (uniformBuffer.getSize() == 0)
+ {
+ bindBufferBase(GL_UNIFORM_BUFFER, binding, bufferGL->getBufferID());
+ }
+ else
+ {
+ bindBufferRange(GL_UNIFORM_BUFFER, binding, bufferGL->getBufferID(),
+ uniformBuffer.getOffset(), uniformBuffer.getSize());
+ }
+ }
+ }
+
const std::vector<SamplerBindingGL> &appliedSamplerUniforms = programGL->getAppliedSamplerUniforms();
for (const SamplerBindingGL &samplerUniform : appliedSamplerUniforms)
{
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.h b/src/libANGLE/renderer/gl/StateManagerGL.h
index e999af3..2697acc 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.h
+++ b/src/libANGLE/renderer/gl/StateManagerGL.h
@@ -45,6 +45,8 @@
void useProgram(GLuint program);
void bindVertexArray(GLuint vao, GLuint elementArrayBuffer);
void bindBuffer(GLenum type, GLuint buffer);
+ void bindBufferBase(GLenum type, size_t index, GLuint buffer);
+ void bindBufferRange(GLenum type, size_t index, GLuint buffer, size_t offset, size_t size);
void activeTexture(size_t unit);
void bindTexture(GLenum type, GLuint texture);
void bindSampler(size_t unit, GLuint sampler);
@@ -140,6 +142,16 @@
std::map<GLenum, GLuint> mBuffers;
+ struct IndexedBufferBinding
+ {
+ IndexedBufferBinding();
+
+ size_t offset;
+ size_t size;
+ GLuint buffer;
+ };
+ std::map<GLenum, std::vector<IndexedBufferBinding>> mIndexedBuffers;
+
size_t mTextureUnitIndex;
std::map<GLenum, std::vector<GLuint>> mTextures;
std::vector<GLuint> mSamplers;
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 3d6b708..d233931 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1531,17 +1531,17 @@
{
const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
- const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
+ const OffsetBindingPointer<Buffer> &uniformBuffer =
+ state.getIndexedUniformBuffer(blockBinding);
- if (!uniformBuffer)
+ if (uniformBuffer.get() == nullptr)
{
// undefined behaviour
context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
return false;
}
- size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
-
+ size_t uniformBufferSize = uniformBuffer.getSize();
if (uniformBufferSize == 0)
{
// Bind the whole buffer.