Implement dirty bits acceleration for VertexArrayGL.
BUG=angleproject:1040
TEST=angle_end2end_tests,angle_perftests,WebGL
Change-Id: I91d9aea5eefb58ecaf5b1cc95926fddb2aa846ea
Reviewed-on: https://chromium-review.googlesource.com/289570
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 6c70a25..260713f 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1481,7 +1481,7 @@
void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
{
- mState.getVertexArray()->setVertexAttribDivisor(index, divisor);
+ mState.setVertexAttribDivisor(index, divisor);
}
void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 5791cb9..752f995 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -846,6 +846,8 @@
void State::setVertexArrayBinding(VertexArray *vertexArray)
{
mVertexArray = vertexArray;
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
}
GLuint State::getVertexArrayId() const
@@ -865,6 +867,8 @@
if (mVertexArray->id() == vertexArray)
{
mVertexArray = NULL;
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_BINDING);
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
return true;
}
@@ -1051,6 +1055,7 @@
void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
{
getVertexArray()->enableAttribute(attribNum, enabled);
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
}
void State::setVertexAttribf(GLuint index, const GLfloat values[4])
@@ -1074,10 +1079,23 @@
mDirtyBits.set(DIRTY_BIT_CURRENT_VALUE_0 + index);
}
-void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
- bool pureInteger, GLsizei stride, const void *pointer)
+void State::setVertexAttribState(unsigned int attribNum,
+ Buffer *boundBuffer,
+ GLint size,
+ GLenum type,
+ bool normalized,
+ bool pureInteger,
+ GLsizei stride,
+ const void *pointer)
{
getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer);
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
+}
+
+void State::setVertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ getVertexArray()->setVertexAttribDivisor(index, divisor);
+ mDirtyBits.set(DIRTY_BIT_VERTEX_ARRAY_OBJECT);
}
const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index a7c4afe..177c5ab 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -226,6 +226,7 @@
void setVertexAttribi(GLuint index, const GLint values[4]);
void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
+ void setVertexAttribDivisor(GLuint index, GLuint divisor);
const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const;
const void *getVertexAttribPointer(unsigned int attribNum) const;
diff --git a/src/libANGLE/VertexArray.cpp b/src/libANGLE/VertexArray.cpp
index 3489a31..4afc361 100644
--- a/src/libANGLE/VertexArray.cpp
+++ b/src/libANGLE/VertexArray.cpp
@@ -73,12 +73,14 @@
{
ASSERT(index < getMaxAttribs());
mData.mVertexAttributes[index].divisor = divisor;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_DIVISOR + index);
}
void VertexArray::enableAttribute(size_t attributeIndex, bool enabledState)
{
ASSERT(attributeIndex < getMaxAttribs());
mData.mVertexAttributes[attributeIndex].enabled = enabledState;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attributeIndex);
// Update state cache
if (enabledState)
@@ -109,11 +111,22 @@
attrib->pureInteger = pureInteger;
attrib->stride = stride;
attrib->pointer = pointer;
+ mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attributeIndex);
}
void VertexArray::setElementArrayBuffer(Buffer *buffer)
{
mData.mElementArrayBuffer.set(buffer);
+ mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
+}
+
+void VertexArray::syncImplState()
+{
+ if (mDirtyBits.any())
+ {
+ mVertexArray->syncState(mDirtyBits);
+ mDirtyBits.reset();
+ }
}
}
diff --git a/src/libANGLE/VertexArray.h b/src/libANGLE/VertexArray.h
index 1c75db5..bf0c922 100644
--- a/src/libANGLE/VertexArray.h
+++ b/src/libANGLE/VertexArray.h
@@ -15,6 +15,7 @@
#include "libANGLE/RefCountObject.h"
#include "libANGLE/Constants.h"
+#include "libANGLE/State.h"
#include "libANGLE/VertexAttribute.h"
#include <vector>
@@ -29,6 +30,9 @@
{
class Buffer;
+// Used in other places.
+typedef std::bitset<MAX_VERTEX_ATTRIBS> AttributesMask;
+
class VertexArray
{
public:
@@ -66,6 +70,10 @@
size_t getMaxAttribs() const { return mVertexAttributes.size(); }
size_t getMaxEnabledAttribute() const { return mMaxEnabledAttribute; }
const std::vector<VertexAttribute> &getVertexAttributes() const { return mVertexAttributes; }
+ const VertexAttribute &getVertexAttribute(size_t index) const
+ {
+ return mVertexAttributes[index];
+ }
private:
friend class VertexArray;
@@ -74,12 +82,37 @@
size_t mMaxEnabledAttribute;
};
+ enum DirtyBitType
+ {
+ DIRTY_BIT_ELEMENT_ARRAY_BUFFER,
+
+ // Reserve bits for enabled flags
+ DIRTY_BIT_ATTRIB_0_ENABLED,
+ DIRTY_BIT_ATTRIB_MAX_ENABLED = DIRTY_BIT_ATTRIB_0_ENABLED + gl::MAX_VERTEX_ATTRIBS,
+
+ // Reserve bits for attrib pointers
+ DIRTY_BIT_ATTRIB_0_POINTER = DIRTY_BIT_ATTRIB_MAX_ENABLED,
+ DIRTY_BIT_ATTRIB_MAX_POINTER = DIRTY_BIT_ATTRIB_0_POINTER + gl::MAX_VERTEX_ATTRIBS,
+
+ // Reserve bits for divisors
+ DIRTY_BIT_ATTRIB_0_DIVISOR = DIRTY_BIT_ATTRIB_MAX_POINTER,
+ DIRTY_BIT_ATTRIB_MAX_DIVISOR = DIRTY_BIT_ATTRIB_0_DIVISOR + gl::MAX_VERTEX_ATTRIBS,
+
+ DIRTY_BIT_UNKNOWN = DIRTY_BIT_ATTRIB_MAX_DIVISOR,
+ DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
+ };
+
+ typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
+
+ void syncImplState();
+
private:
GLuint mId;
rx::VertexArrayImpl *mVertexArray;
Data mData;
+ DirtyBits mDirtyBits;
};
}
diff --git a/src/libANGLE/renderer/VertexArrayImpl.h b/src/libANGLE/renderer/VertexArrayImpl.h
index 8381676..13617c7 100644
--- a/src/libANGLE/renderer/VertexArrayImpl.h
+++ b/src/libANGLE/renderer/VertexArrayImpl.h
@@ -21,7 +21,7 @@
public:
VertexArrayImpl(const gl::VertexArray::Data &data) : mData(data) { }
virtual ~VertexArrayImpl() { }
-
+ virtual void syncState(const gl::VertexArray::DirtyBits &dirtyBits) {}
protected:
const gl::VertexArray::Data &mData;
};
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index bb3571d..ddf7216 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -207,7 +207,7 @@
// TODO: determine attribute precision
setShaderAttribute(static_cast<size_t>(i), attributeType, GL_NONE, attributeName, attributeSize, location);
- mActiveAttributeLocations.push_back(location);
+ mActiveAttributesMask.set(location);
}
return LinkResult(true, gl::Error(GL_NO_ERROR));
@@ -445,7 +445,7 @@
mSamplerUniformMap.clear();
mSamplerBindings.clear();
- mActiveAttributeLocations.clear();
+ mActiveAttributesMask.reset();
}
GLuint ProgramGL::getProgramID() const
@@ -458,9 +458,9 @@
return mSamplerBindings;
}
-const std::vector<GLuint> &ProgramGL::getActiveAttributeLocations() const
+const gl::AttributesMask &ProgramGL::getActiveAttributesMask() const
{
- return mActiveAttributeLocations;
+ return mActiveAttributesMask;
}
}
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 785654b..b6e030a 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -95,7 +95,7 @@
GLuint getProgramID() const;
const std::vector<SamplerBindingGL> &getAppliedSamplerUniforms() const;
- const std::vector<GLuint> &getActiveAttributeLocations() const;
+ const gl::AttributesMask &getActiveAttributesMask() const;
private:
const FunctionsGL *mFunctions;
@@ -113,7 +113,7 @@
std::vector<SamplerBindingGL> mSamplerBindings;
// Array of attribute locations used by this program
- std::vector<GLuint> mActiveAttributeLocations;
+ gl::AttributesMask mActiveAttributesMask;
GLuint mProgramID;
};
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index 2f07074..e851c92 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -383,7 +383,8 @@
const gl::VertexArray *vao = state.getVertexArray();
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
- gl::Error error = vaoGL->syncDrawArraysState(programGL->getActiveAttributeLocations(), first, count);
+ gl::Error error =
+ vaoGL->syncDrawArraysState(programGL->getActiveAttributesMask(), first, count);
if (error.isError())
{
return error;
@@ -405,7 +406,8 @@
const gl::VertexArray *vao = state.getVertexArray();
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
- gl::Error error = vaoGL->syncDrawElementsState(programGL->getActiveAttributeLocations(), count, type, indices, outIndices);
+ gl::Error error = vaoGL->syncDrawElementsState(programGL->getActiveAttributesMask(), count,
+ type, indices, outIndices);
if (error.isError())
{
return error;
@@ -1079,7 +1081,7 @@
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_OBJECT:
- // TODO(jmadill): implement this
+ state.getVertexArray()->syncImplState();
break;
case gl::State::DIRTY_BIT_PROGRAM_BINDING:
// TODO(jmadill): implement this
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index 9e7cce8..0da7375 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -8,6 +8,7 @@
#include "libANGLE/renderer/gl/VertexArrayGL.h"
+#include "common/BitSetIterator.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/utilities.h"
@@ -18,10 +19,20 @@
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
+using namespace gl;
+
namespace rx
{
+namespace
+{
+bool AttributeNeedsStreaming(const VertexAttribute &attribute)
+{
+ return (attribute.enabled && attribute.buffer.get() == nullptr);
+}
-VertexArrayGL::VertexArrayGL(const gl::VertexArray::Data &data,
+} // anonymous namespace
+
+VertexArrayGL::VertexArrayGL(const VertexArray::Data &data,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: VertexArrayImpl(data),
@@ -64,29 +75,40 @@
}
}
-gl::Error VertexArrayGL::syncDrawArraysState(const std::vector<GLuint> &activeAttribLocations, GLint first, GLsizei count) const
+gl::Error VertexArrayGL::syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
+ GLint first,
+ GLsizei count) const
{
- return syncDrawState(activeAttribLocations, first, count, GL_NONE, nullptr, nullptr);
+ return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, nullptr);
}
-gl::Error VertexArrayGL::syncDrawElementsState(const std::vector<GLuint> &activeAttribLocations, GLsizei count,
- GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
+gl::Error VertexArrayGL::syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const GLvoid **outIndices) const
{
- return syncDrawState(activeAttribLocations, 0, count, type, indices, outIndices);
+ return syncDrawState(activeAttributesMask, 0, count, type, indices, outIndices);
}
-gl::Error VertexArrayGL::syncDrawState(const std::vector<GLuint> &activeAttribLocations, GLint first, GLsizei count, GLenum type, const GLvoid *indices, const GLvoid **outIndices) const
+gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttributesMask,
+ GLint first,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const GLvoid **outIndices) const
{
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
// Check if any attributes need to be streamed, determines if the index range needs to be computed
- bool attributesNeedStreaming = doAttributesNeedStreaming(activeAttribLocations);
+ bool attributesNeedStreaming = mAttributesNeedStreaming.any();
// Determine if an index buffer needs to be streamed and the range of vertices that need to be copied
- gl::RangeUI indexRange(0, 0);
+ RangeUI indexRange(0, 0);
if (type != GL_NONE)
{
- gl::Error error = syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
+ Error error =
+ syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
if (error.isError())
{
return error;
@@ -99,130 +121,24 @@
indexRange.end = first + count;
}
- // Sync the vertex attribute state and track what data needs to be streamed
- size_t streamingDataSize = 0;
- size_t maxAttributeDataSize = 0;
- gl::Error error = syncAttributeState(activeAttribLocations, attributesNeedStreaming, indexRange,
- &streamingDataSize, &maxAttributeDataSize);
- if (error.isError())
+ if (attributesNeedStreaming)
{
- return error;
- }
-
- if (streamingDataSize > 0)
- {
- ASSERT(attributesNeedStreaming);
-
- error = streamAttributes(activeAttribLocations, streamingDataSize, maxAttributeDataSize,
- indexRange);
+ Error error = streamAttributes(activeAttributesMask, indexRange);
if (error.isError())
{
return error;
}
}
- return gl::Error(GL_NO_ERROR);
+ return Error(GL_NO_ERROR);
}
-bool VertexArrayGL::doAttributesNeedStreaming(const std::vector<GLuint> &activeAttribLocations) const
-{
- // TODO: if GLES, nothing needs to be streamed
- const auto &attribs = mData.getVertexAttributes();
- for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
- {
- GLuint idx = activeAttribLocations[activeAttrib];
- if (attribs[idx].enabled && attribs[idx].buffer.get() == nullptr)
- {
- return true;
- }
- }
-
- return false;
-}
-
-gl::Error VertexArrayGL::syncAttributeState(const std::vector<GLuint> &activeAttribLocations, bool attributesNeedStreaming,
- const gl::RangeUI &indexRange, size_t *outStreamingDataSize, size_t *outMaxAttributeDataSize) const
-{
- *outStreamingDataSize = 0;
- *outMaxAttributeDataSize = 0;
-
- const auto &attribs = mData.getVertexAttributes();
- for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
- {
- GLuint idx = activeAttribLocations[activeAttrib];
- const auto &attrib = attribs[idx];
-
- // Always sync the enabled and divisor state, they are required for both streaming and buffered
- // attributes
- if (mAppliedAttributes[idx].enabled != attrib.enabled)
- {
- if (attrib.enabled)
- {
- mFunctions->enableVertexAttribArray(idx);
- }
- else
- {
- mFunctions->disableVertexAttribArray(idx);
- }
- mAppliedAttributes[idx].enabled = attrib.enabled;
- }
- if (mAppliedAttributes[idx].divisor != attrib.divisor)
- {
- mFunctions->vertexAttribDivisor(idx, attrib.divisor);
- mAppliedAttributes[idx].divisor = attrib.divisor;
- }
-
- if (attribs[idx].enabled && attrib.buffer.get() == nullptr)
- {
- ASSERT(attributesNeedStreaming);
-
- const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
-
- // If streaming is going to be required, compute the size of the required buffer
- // and how much slack space at the beginning of the buffer will be required by determining
- // the attribute with the largest data size.
- size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
- *outStreamingDataSize += typeSize * streamedVertexCount;
- *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
- }
- else
- {
- // Sync the attribute with no translation
- if (mAppliedAttributes[idx] != attrib)
- {
- const gl::Buffer *arrayBuffer = attrib.buffer.get();
- if (arrayBuffer != nullptr)
- {
- const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
- mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
- }
- else
- {
- mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
- }
-
- if (attrib.pureInteger)
- {
- mFunctions->vertexAttribIPointer(idx, attrib.size, attrib.type,
- attrib.stride, attrib.pointer);
- }
- else
- {
- mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type,
- attrib.normalized, attrib.stride,
- attrib.pointer);
- }
-
- mAppliedAttributes[idx] = attrib;
- }
- }
- }
-
- return gl::Error(GL_NO_ERROR);
-}
-
-gl::Error VertexArrayGL::syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
- gl::RangeUI *outIndexRange, const GLvoid **outIndices) const
+Error VertexArrayGL::syncIndexData(GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ bool attributesNeedStreaming,
+ RangeUI *outIndexRange,
+ const GLvoid **outIndices) const
{
ASSERT(outIndices);
@@ -242,7 +158,8 @@
if (attributesNeedStreaming)
{
ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
- gl::Error error = mData.getElementArrayBuffer()->getIndexRange(type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
+ Error error = mData.getElementArrayBuffer()->getIndexRange(
+ type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
if (error.isError())
{
return error;
@@ -260,7 +177,7 @@
// Only compute the index range if the attributes also need to be streamed
if (attributesNeedStreaming)
{
- *outIndexRange = gl::ComputeIndexRange(type, indices, count);
+ *outIndexRange = ComputeIndexRange(type, indices, count);
}
// Allocate the streaming element array buffer
@@ -274,7 +191,7 @@
mAppliedElementArrayBuffer.set(nullptr);
// Make sure the element array buffer is large enough
- const gl::Type &indexTypeInfo = gl::GetTypeInfo(type);
+ const Type &indexTypeInfo = GetTypeInfo(type);
size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
{
@@ -292,12 +209,51 @@
*outIndices = nullptr;
}
- return gl::Error(GL_NO_ERROR);
+ return Error(GL_NO_ERROR);
}
-gl::Error VertexArrayGL::streamAttributes(const std::vector<GLuint> &activeAttribLocations, size_t streamingDataSize,
- size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const
+void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
+ const gl::RangeUI &indexRange,
+ size_t *outStreamingDataSize,
+ size_t *outMaxAttributeDataSize) const
{
+ *outStreamingDataSize = 0;
+ *outMaxAttributeDataSize = 0;
+
+ ASSERT(mAttributesNeedStreaming.any());
+
+ const auto &attribs = mData.getVertexAttributes();
+ for (unsigned int idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
+ {
+ const auto &attrib = attribs[idx];
+ ASSERT(AttributeNeedsStreaming(attrib));
+
+ const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
+
+ // If streaming is going to be required, compute the size of the required buffer
+ // and how much slack space at the beginning of the buffer will be required by determining
+ // the attribute with the largest data size.
+ size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
+ *outStreamingDataSize += typeSize * streamedVertexCount;
+ *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
+ }
+}
+
+gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
+ const gl::RangeUI &indexRange) const
+{
+ // Sync the vertex attribute state and track what data needs to be streamed
+ size_t streamingDataSize = 0;
+ size_t maxAttributeDataSize = 0;
+
+ computeStreamingAttributeSizes(activeAttributesMask, indexRange, &streamingDataSize,
+ &maxAttributeDataSize);
+
+ if (streamingDataSize == 0)
+ {
+ return gl::Error(GL_NO_ERROR);
+ }
+
if (mStreamingArrayBuffer == 0)
{
mFunctions->genBuffers(1, &mStreamingArrayBuffer);
@@ -329,52 +285,48 @@
const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
const auto &attribs = mData.getVertexAttributes();
- for (size_t activeAttrib = 0; activeAttrib < activeAttribLocations.size(); activeAttrib++)
+ for (unsigned int idx :
+ angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
{
- GLuint idx = activeAttribLocations[activeAttrib];
const auto &attrib = attribs[idx];
+ ASSERT(AttributeNeedsStreaming(attrib));
- if (attrib.enabled && attrib.buffer.get() == nullptr)
+ const size_t sourceStride = ComputeVertexAttributeStride(attrib);
+ const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
+
+ const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
+
+ // Pack the data when copying it, user could have supplied a very large stride that
+ // would cause the buffer to be much larger than needed.
+ if (destStride == sourceStride)
{
- const size_t sourceStride = ComputeVertexAttributeStride(attrib);
- const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
-
- const uint8_t *inputPointer = reinterpret_cast<const uint8_t*>(attrib.pointer);
-
- // Pack the data when copying it, user could have supplied a very large stride that would
- // cause the buffer to be much larger than needed.
- if (destStride == sourceStride)
- {
- // Can copy in one go, the data is packed
- memcpy(bufferPointer + curBufferOffset,
- inputPointer + (sourceStride * indexRange.start),
- destStride * streamedVertexCount);
- }
- else
- {
- // Copy each vertex individually
- for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
- {
- memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
- inputPointer + (sourceStride * vertexIdx),
- destStride);
- }
- }
-
- // Compute where the 0-index vertex would be.
- const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
-
- mFunctions->vertexAttribPointer(
- idx, attrib.size, attrib.type, attrib.normalized,
- static_cast<GLsizei>(destStride),
- reinterpret_cast<const GLvoid *>(vertexStartOffset));
-
- curBufferOffset += destStride * streamedVertexCount;
-
- // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
- // need to be streamed later, there is no chance that the caching will skip it.
- mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
+ // Can copy in one go, the data is packed
+ memcpy(bufferPointer + curBufferOffset,
+ inputPointer + (sourceStride * indexRange.start),
+ destStride * streamedVertexCount);
}
+ else
+ {
+ // Copy each vertex individually
+ for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
+ {
+ memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
+ inputPointer + (sourceStride * vertexIdx), destStride);
+ }
+ }
+
+ // Compute where the 0-index vertex would be.
+ const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
+
+ mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type, attrib.normalized,
+ static_cast<GLsizei>(destStride),
+ reinterpret_cast<const GLvoid *>(vertexStartOffset));
+
+ curBufferOffset += destStride * streamedVertexCount;
+
+ // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
+ // need to be streamed later, there is no chance that the caching will skip it.
+ mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
}
unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
@@ -382,10 +334,10 @@
if (unmapResult != GL_TRUE)
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
+ return Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
}
- return gl::Error(GL_NO_ERROR);
+ return Error(GL_NO_ERROR);
}
GLuint VertexArrayGL::getVertexArrayID() const
@@ -403,4 +355,114 @@
return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
}
+void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
+{
+ const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
+ mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib));
}
+
+void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
+{
+ const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
+ if (mAppliedAttributes[attribIndex].enabled == attrib.enabled)
+ {
+ return;
+ }
+
+ updateNeedsStreaming(attribIndex);
+
+ mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
+ if (attrib.enabled)
+ {
+ mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
+ }
+ else
+ {
+ mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
+ }
+ mAppliedAttributes[attribIndex].enabled = attrib.enabled;
+}
+
+void VertexArrayGL::updateAttribPointer(size_t attribIndex)
+{
+ const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
+ if (mAppliedAttributes[attribIndex] == attrib)
+ {
+ return;
+ }
+
+ updateNeedsStreaming(attribIndex);
+ mAppliedAttributes[attribIndex] = attrib;
+
+ // If we need to stream, defer the attribPointer to the draw call.
+ if (mAttributesNeedStreaming[attribIndex])
+ {
+ return;
+ }
+
+ mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
+ const Buffer *arrayBuffer = attrib.buffer.get();
+ if (arrayBuffer != nullptr)
+ {
+ const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
+ mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
+ }
+ else
+ {
+ mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ if (attrib.pureInteger)
+ {
+ mFunctions->vertexAttribIPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
+ attrib.stride, attrib.pointer);
+ }
+ else
+ {
+ mFunctions->vertexAttribPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
+ attrib.normalized, attrib.stride, attrib.pointer);
+ }
+}
+
+void VertexArrayGL::syncState(const VertexArray::DirtyBits &dirtyBits)
+{
+ for (unsigned long dirtyBit : angle::IterateBitSet(dirtyBits))
+ {
+ if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
+ {
+ // TODO(jmadill): Element array buffer bindings
+ }
+ else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
+ dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
+ {
+ size_t attribIndex =
+ static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED;
+ updateAttribEnabled(attribIndex);
+ }
+ else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
+ dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
+ {
+ size_t attribIndex =
+ static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_POINTER;
+ updateAttribPointer(attribIndex);
+ }
+ else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR &&
+ dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_DIVISOR)
+ {
+ size_t attribIndex =
+ static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR;
+ const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
+
+ if (mAppliedAttributes[attribIndex].divisor != attrib.divisor)
+ {
+ mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
+ mFunctions->vertexAttribDivisor(static_cast<GLuint>(attribIndex), attrib.divisor);
+ mAppliedAttributes[attribIndex].divisor = attrib.divisor;
+ }
+ }
+ else
+ UNREACHABLE();
+ }
+}
+
+} // rx
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.h b/src/libANGLE/renderer/gl/VertexArrayGL.h
index f277bdb..52c8f4e 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.h
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.h
@@ -23,33 +23,46 @@
VertexArrayGL(const gl::VertexArray::Data &data, const FunctionsGL *functions, StateManagerGL *stateManager);
~VertexArrayGL() override;
- gl::Error syncDrawArraysState(const std::vector<GLuint> &activeAttribLoations, GLint first, GLsizei count) const;
- gl::Error syncDrawElementsState(const std::vector<GLuint> &activeAttribLoations, GLsizei count, GLenum type,
- const GLvoid *indices, const GLvoid **outIndices) const;
+ gl::Error syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
+ GLint first,
+ GLsizei count) const;
+ gl::Error syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const GLvoid **outIndices) const;
GLuint getVertexArrayID() const;
GLuint getAppliedElementArrayBufferID() const;
+ void syncState(const gl::VertexArray::DirtyBits &dirtyBits) override;
+
private:
- gl::Error syncDrawState(const std::vector<GLuint> &activeAttribLoations, GLint first, GLsizei count,
- GLenum type, const GLvoid *indices, const GLvoid **outIndices) const;
-
- // Check if any vertex attributes need to be streamed
- bool doAttributesNeedStreaming(const std::vector<GLuint> &activeAttribLoations) const;
-
- // Apply attribute state, returns the amount of space needed to stream all attributes that need streaming
- // and the data size of the largest attribute
- gl::Error syncAttributeState(const std::vector<GLuint> &activeAttribLoations, bool attributesNeedStreaming,
- const gl::RangeUI &indexRange, size_t *outStreamingDataSize,
- size_t *outMaxAttributeDataSize) const;
+ gl::Error syncDrawState(const gl::AttributesMask &activeAttributesMask,
+ GLint first,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const GLvoid **outIndices) const;
// Apply index data, only sets outIndexRange if attributesNeedStreaming is true
gl::Error syncIndexData(GLsizei count, GLenum type, const GLvoid *indices, bool attributesNeedStreaming,
gl::RangeUI *outIndexRange, const GLvoid **outIndices) const;
+ // Returns the amount of space needed to stream all attributes that need streaming
+ // and the data size of the largest attribute
+ void computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
+ const gl::RangeUI &indexRange,
+ size_t *outStreamingDataSize,
+ size_t *outMaxAttributeDataSize) const;
+
// Stream attributes that have client data
- gl::Error streamAttributes(const std::vector<GLuint> &activeAttribLoations, size_t streamingDataSize,
- size_t maxAttributeDataSize, const gl::RangeUI &indexRange) const;
+ gl::Error streamAttributes(const gl::AttributesMask &activeAttributesMask,
+ const gl::RangeUI &indexRange) const;
+
+ void updateNeedsStreaming(size_t attribIndex);
+ void updateAttribEnabled(size_t attribIndex);
+ void updateAttribPointer(size_t attribIndex);
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
@@ -64,6 +77,8 @@
mutable size_t mStreamingArrayBufferSize;
mutable GLuint mStreamingArrayBuffer;
+
+ gl::AttributesMask mAttributesNeedStreaming;
};
}