Commit cf9383ed by Jamie Madill Committed by Commit Bot

Optimize VertexArray::bindVertexBufferImpl.

Reduces the buffer nullptr checks to a single location. Also optimizes how the transform feedback binding counter is changed. Improves the score of the draw call vertex array change test. Bug: angleproject:3014 Change-Id: I08ff341e08194a407c24143965a3d568e92b97b7 Reviewed-on: https://chromium-review.googlesource.com/c/1406891 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 1a07524d
......@@ -98,9 +98,4 @@ void ObserverBinding::onSubjectReset()
{
mSubject = nullptr;
}
const Subject *ObserverBinding::getSubject() const
{
return mSubject;
}
} // namespace angle
......@@ -115,7 +115,9 @@ class ObserverBinding final : public ObserverBindingBase
void onStateChange(const gl::Context *context, SubjectMessage message) const;
void onSubjectReset() override;
const Subject *getSubject() const;
ANGLE_INLINE const Subject *getSubject() const { return mSubject; }
ANGLE_INLINE void assignSubject(Subject *subject) { mSubject = subject; }
private:
Subject *mSubject;
......
......@@ -140,7 +140,12 @@ void VertexArray::onDestroy(const Context *context)
bool isBound = context->isCurrentVertexArray(this);
for (VertexBinding &binding : mState.mVertexBindings)
{
binding.setBuffer(context, nullptr, isBound);
if (isBound)
{
if (binding.getBuffer().get())
binding.getBuffer()->onNonTFBindingChanged(-1);
}
binding.setBuffer(context, nullptr);
}
if (isBound && mState.mElementArrayBuffer.get())
mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
......@@ -168,11 +173,18 @@ const std::string &VertexArray::getLabel() const
void VertexArray::detachBuffer(const Context *context, GLuint bufferName)
{
bool isBound = context->isCurrentVertexArray(this);
for (auto &binding : mState.mVertexBindings)
for (size_t bindingIndex = 0; bindingIndex < gl::MAX_VERTEX_ATTRIB_BINDINGS; ++bindingIndex)
{
VertexBinding &binding = mState.mVertexBindings[bindingIndex];
if (binding.getBuffer().id() == bufferName)
{
binding.setBuffer(context, nullptr, isBound);
if (isBound)
{
if (binding.getBuffer().get())
binding.getBuffer()->onNonTFBindingChanged(-1);
}
binding.setBuffer(context, nullptr);
mArrayBufferObserverBindings[bindingIndex].reset();
}
}
......@@ -230,22 +242,30 @@ ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(const Context *cont
}
}
ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers(VertexBinding *binding)
ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers(
bool isMapped,
const AttributesMask &boundAttributesMask)
{
Buffer *buffer = binding->getBuffer().get();
if (buffer && buffer->isMapped())
if (isMapped)
{
mState.mCachedMappedArrayBuffers |= binding->getBoundAttributesMask();
mState.mCachedMappedArrayBuffers |= boundAttributesMask;
}
else
{
mState.mCachedMappedArrayBuffers &= ~binding->getBoundAttributesMask();
mState.mCachedMappedArrayBuffers &= ~boundAttributesMask;
}
mState.mCachedEnabledMappedArrayBuffers =
mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
}
ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding)
{
const Buffer *buffer = binding.getBuffer().get();
return updateCachedMappedArrayBuffers(buffer && buffer->isMapped(),
binding.getBoundAttributesMask());
}
ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
const Buffer *buffer)
{
......@@ -260,27 +280,43 @@ void VertexArray::bindVertexBufferImpl(const Context *context,
GLsizei stride)
{
ASSERT(bindingIndex < getMaxBindings());
bool isBound = context->isCurrentVertexArray(this);
ASSERT(context->isCurrentVertexArray(this));
VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
binding->setBuffer(context, boundBuffer, isBound);
Buffer *oldBuffer = binding->getBuffer().get();
angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
observer->assignSubject(boundBuffer);
// Several nullptr checks are combined here for optimization purposes.
if (oldBuffer)
{
oldBuffer->onNonTFBindingChanged(-1);
oldBuffer->removeObserver(observer);
oldBuffer->release(context);
}
binding->assignBuffer(boundBuffer);
binding->setOffset(offset);
binding->setStride(stride);
updateObserverBinding(bindingIndex);
updateCachedBufferBindingSize(context, binding);
updateCachedTransformFeedbackBindingValidation(bindingIndex, boundBuffer);
updateCachedMappedArrayBuffers(binding);
// Update client memory attribute pointers. Affects all bound attributes.
if (boundBuffer)
{
boundBuffer->addRef();
boundBuffer->onNonTFBindingChanged(1);
boundBuffer->addObserver(observer);
mCachedTransformFeedbackConflictedBindingsMask.set(
bindingIndex, boundBuffer->isBoundForTransformFeedbackAndOtherUse());
mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask();
updateCachedMappedArrayBuffers(boundBuffer->isMapped(), binding->getBoundAttributesMask());
}
else
{
mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false);
mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask();
updateCachedMappedArrayBuffers(false, binding->getBoundAttributesMask());
}
}
......@@ -527,7 +563,7 @@ void VertexArray::onSubjectStateChange(const gl::Context *context,
case angle::SubjectMessage::RESOURCE_MAPPED:
if (!IsElementArrayBufferSubjectIndex(index))
{
updateCachedMappedArrayBuffers(&mState.mVertexBindings[index]);
updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
}
onStateChange(context, angle::SubjectMessage::RESOURCE_MAPPED);
break;
......@@ -537,7 +573,7 @@ void VertexArray::onSubjectStateChange(const gl::Context *context,
if (!IsElementArrayBufferSubjectIndex(index))
{
updateCachedMappedArrayBuffers(&mState.mVertexBindings[index]);
updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
}
onStateChange(context, angle::SubjectMessage::RESOURCE_UNMAPPED);
break;
......@@ -558,12 +594,6 @@ void VertexArray::setDependentDirtyBit(const gl::Context *context,
onStateChange(context, angle::SubjectMessage::CONTENTS_CHANGED);
}
void VertexArray::updateObserverBinding(size_t bindingIndex)
{
Buffer *boundBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get();
mArrayBufferObserverBindings[bindingIndex].bind(boundBuffer);
}
bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const
{
// Fast check first.
......
......@@ -287,7 +287,6 @@ class VertexArray final : public angle::ObserverInterface,
void setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit);
void setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit);
void updateObserverBinding(size_t bindingIndex);
DirtyBitType getDirtyBitFromIndex(bool contentsChanged, angle::SubjectIndex index) const;
void setDependentDirtyBit(const gl::Context *context,
bool contentsChanged,
......@@ -296,7 +295,8 @@ class VertexArray final : public angle::ObserverInterface,
// These are used to optimize draw call validation.
void updateCachedBufferBindingSize(const Context *context, VertexBinding *binding);
void updateCachedTransformFeedbackBindingValidation(size_t bindingIndex, const Buffer *buffer);
void updateCachedMappedArrayBuffers(VertexBinding *binding);
void updateCachedMappedArrayBuffers(bool isMapped, const AttributesMask &boundAttributesMask);
void updateCachedMappedArrayBuffersBinding(const VertexBinding &binding);
angle::Result getIndexRangeImpl(const Context *context,
DrawElementsType type,
......
......@@ -40,18 +40,14 @@ class VertexBinding final : angle::NonCopyable
const BindingPointer<Buffer> &getBuffer() const { return mBuffer; }
ANGLE_INLINE void setBuffer(const gl::Context *context, Buffer *bufferIn, bool containerIsBound)
ANGLE_INLINE void setBuffer(const gl::Context *context, Buffer *bufferIn)
{
if (containerIsBound)
{
if (mBuffer.get())
mBuffer->onNonTFBindingChanged(-1);
if (bufferIn)
bufferIn->onNonTFBindingChanged(1);
}
mBuffer.set(context, bufferIn);
}
// Skips ref counting for better inlined performance.
ANGLE_INLINE void assignBuffer(Buffer *bufferIn) { mBuffer.assign(bufferIn); }
void onContainerBindingChanged(const Context *context, int incr) const;
const AttributesMask &getBoundAttributesMask() const { return mBoundAttributesMask; }
......
......@@ -98,7 +98,7 @@ void VertexArrayGL::destroy(const gl::Context *context)
mAppliedElementArrayBuffer.set(context, nullptr);
for (auto &binding : mAppliedBindings)
{
binding.setBuffer(context, nullptr, false);
binding.setBuffer(context, nullptr);
}
}
......@@ -435,7 +435,7 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri
{
// Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
// it starts to use a buffer later, there is no chance that the caching will skip it.
mAppliedBindings[attribIndex].setBuffer(context, nullptr, false);
mAppliedBindings[attribIndex].setBuffer(context, nullptr);
return;
}
......@@ -474,7 +474,7 @@ void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attri
mAppliedBindings[attribIndex].setStride(binding.getStride());
mAppliedBindings[attribIndex].setOffset(binding.getOffset());
mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get(), false);
mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
}
void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
......@@ -569,7 +569,7 @@ void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindi
mAppliedBindings[bindingIndex].setStride(binding.getStride());
mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get(), false);
mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get());
}
void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
......
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