Commit cd0a0a3c by Jamie Madill

Introduce SubjectBindingPointer.

We can share the same pointer for the subject binding and the binding pointer. This further allows us to optimize buffer re-binding. The shared memory increases cache coherency and reduces the number of instructions needed. Bug: angleproject:2891 Change-Id: Id3162fa79de203f75989e7289ea02cb2ea1bec73 Reviewed-on: https://chromium-review.googlesource.com/c/1270217 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent 472ddc82
......@@ -82,6 +82,9 @@ class FastVector final
void resize(size_type count);
void resize(size_type count, const value_type &value);
// Specialty function that removes a known element and might shuffle the list.
void remove_and_permute(const value_type &element);
private:
void assign_from_initializer_list(std::initializer_list<value_type> init);
void ensure_capacity(size_t capacity);
......@@ -384,6 +387,21 @@ void FastVector<T, N, Storage>::assign_from_initializer_list(std::initializer_li
}
template <class T, size_t N, class Storage>
ANGLE_INLINE void FastVector<T, N, Storage>::remove_and_permute(const value_type &element)
{
size_t len = mSize - 1;
for (size_t index = 0; index < len; ++index)
{
if (mData[index] == element)
{
mData[index] = std::move(mData[len]);
break;
}
}
pop_back();
}
template <class T, size_t N, class Storage>
void FastVector<T, N, Storage>::ensure_capacity(size_t capacity)
{
// We have a minimum capacity of N.
......
......@@ -20,11 +20,6 @@ namespace angle
{
namespace
{
template <typename HaystackT, typename NeedleT>
bool IsInContainer(const HaystackT &haystack, const NeedleT &needle)
{
return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
}
} // anonymous namespace
// Observer implementation.
......@@ -45,50 +40,29 @@ bool Subject::hasObservers() const
return !mObservers.empty();
}
ANGLE_INLINE void Subject::addObserver(ObserverBinding *observer)
{
ASSERT(!IsInContainer(mObservers, observer));
mObservers.push_back(observer);
}
ANGLE_INLINE void Subject::removeObserver(ObserverBinding *observer)
{
ASSERT(IsInContainer(mObservers, observer));
size_t len = mObservers.size() - 1;
for (size_t index = 0; index < len; ++index)
{
if (mObservers[index] == observer)
{
mObservers[index] = mObservers[len];
break;
}
}
mObservers.pop_back();
}
void Subject::onStateChange(const gl::Context *context, SubjectMessage message) const
{
if (mObservers.empty())
return;
for (const angle::ObserverBinding *receiver : mObservers)
for (const ObserverBindingBase *binding : mObservers)
{
receiver->onStateChange(context, message);
binding->getObserver()->onSubjectStateChange(context, binding->getSubjectIndex(), message);
}
}
void Subject::resetObservers()
{
for (angle::ObserverBinding *observer : mObservers)
for (angle::ObserverBindingBase *binding : mObservers)
{
observer->onSubjectReset();
binding->onSubjectReset();
}
mObservers.clear();
}
// ObserverBinding implementation.
ObserverBinding::ObserverBinding(ObserverInterface *observer, SubjectIndex index)
: mSubject(nullptr), mObserver(observer), mIndex(index)
: ObserverBindingBase(observer, index), mSubject(nullptr)
{
ASSERT(observer);
}
......@@ -104,7 +78,7 @@ ObserverBinding &ObserverBinding::operator=(const ObserverBinding &other) = defa
void ObserverBinding::bind(Subject *subject)
{
ASSERT(mObserver);
ASSERT(getObserver());
if (mSubject)
{
mSubject->removeObserver(this);
......@@ -120,7 +94,7 @@ void ObserverBinding::bind(Subject *subject)
void ObserverBinding::onStateChange(const gl::Context *context, SubjectMessage message) const
{
mObserver->onSubjectStateChange(context, mIndex, message);
getObserver()->onSubjectStateChange(context, getSubjectIndex(), message);
}
void ObserverBinding::onSubjectReset()
......
......@@ -23,6 +23,11 @@ class Context;
namespace angle
{
template <typename HaystackT, typename NeedleT>
bool IsInContainer(const HaystackT &haystack, const NeedleT &needle)
{
return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
}
using SubjectIndex = size_t;
......@@ -46,7 +51,24 @@ class ObserverInterface
SubjectMessage message) = 0;
};
class ObserverBinding;
class ObserverBindingBase
{
public:
ObserverBindingBase(ObserverInterface *observer, SubjectIndex subjectIndex)
: mObserver(observer), mIndex(subjectIndex)
{
}
virtual ~ObserverBindingBase() {}
ObserverInterface *getObserver() const { return mObserver; }
SubjectIndex getSubjectIndex() const { return mIndex; }
virtual void onSubjectReset() {}
private:
ObserverInterface *mObserver;
SubjectIndex mIndex;
};
// Maintains a list of observer bindings. Sends update messages to the observer.
class Subject : NonCopyable
......@@ -59,24 +81,32 @@ class Subject : NonCopyable
bool hasObservers() const;
void resetObservers();
ANGLE_INLINE void addObserver(ObserverBindingBase *observer)
{
ASSERT(!IsInContainer(mObservers, observer));
mObservers.push_back(observer);
}
ANGLE_INLINE void removeObserver(ObserverBindingBase *observer)
{
ASSERT(IsInContainer(mObservers, observer));
mObservers.remove_and_permute(observer);
}
private:
// Only the ObserverBinding class should add or remove observers.
friend class ObserverBinding;
void addObserver(ObserverBinding *observer);
void removeObserver(ObserverBinding *observer);
// Keep a short list of observers so we can allocate/free them quickly. But since we support
// unlimited bindings, have a spill-over list of that uses dynamic allocation.
static constexpr size_t kMaxFixedObservers = 8;
angle::FastVector<ObserverBinding *, kMaxFixedObservers> mObservers;
angle::FastVector<ObserverBindingBase *, kMaxFixedObservers> mObservers;
};
// Keeps a binding between a Subject and Observer, with a specific subject index.
class ObserverBinding final
class ObserverBinding final : public ObserverBindingBase
{
public:
ObserverBinding(ObserverInterface *observer, SubjectIndex index);
~ObserverBinding();
~ObserverBinding() override;
ObserverBinding(const ObserverBinding &other);
ObserverBinding &operator=(const ObserverBinding &other);
......@@ -85,14 +115,12 @@ class ObserverBinding final
ANGLE_INLINE void reset() { bind(nullptr); }
void onStateChange(const gl::Context *context, SubjectMessage message) const;
void onSubjectReset();
void onSubjectReset() override;
const Subject *getSubject() const;
private:
Subject *mSubject;
ObserverInterface *mObserver;
SubjectIndex mIndex;
};
} // namespace angle
......
......@@ -15,6 +15,7 @@
#include "angle_gl.h"
#include "common/debug.h"
#include "libANGLE/Error.h"
#include "libANGLE/Observer.h"
#include <cstddef>
......@@ -119,6 +120,9 @@ class BindingPointer
bool operator!=(const BindingPointer &other) const { return !(*this == other); }
protected:
ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; }
private:
ObjectType *mObject;
};
......@@ -168,11 +172,11 @@ class BindingPointer : public angle::BindingPointer<ObjectType, Context, Error>
};
template <class ObjectType>
class OffsetBindingPointer : public gl::BindingPointer<ObjectType>
class OffsetBindingPointer : public BindingPointer<ObjectType>
{
public:
using ContextType = typename gl::BindingPointer<ObjectType>::ContextType;
using ErrorType = typename gl::BindingPointer<ObjectType>::ErrorType;
using ContextType = typename BindingPointer<ObjectType>::ContextType;
using ErrorType = typename BindingPointer<ObjectType>::ErrorType;
OffsetBindingPointer() : mOffset(0), mSize(0) { }
......@@ -214,6 +218,42 @@ class OffsetBindingPointer : public gl::BindingPointer<ObjectType>
GLintptr mOffset;
GLsizeiptr mSize;
};
template <typename SubjectT>
class SubjectBindingPointer : protected BindingPointer<SubjectT>, public angle::ObserverBindingBase
{
public:
SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
: ObserverBindingBase(observer, index)
{
}
~SubjectBindingPointer() {}
SubjectBindingPointer(const SubjectBindingPointer &other) = default;
SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
void bind(const Context *context, SubjectT *subject)
{
// AddRef first in case subject == get()
if (subject)
{
subject->addObserver(this);
subject->addRef();
}
if (get())
{
get()->removeObserver(this);
get()->release(context);
}
this->setImpl(subject);
}
using BindingPointer<SubjectT>::get;
using BindingPointer<SubjectT>::operator->;
friend class State;
};
} // namespace gl
namespace egl
......
......@@ -14,6 +14,7 @@
#include "common/bitset_utils.h"
#include "common/mathutil.h"
#include "common/matrix_utils.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Caps.h"
#include "libANGLE/Context.h"
#include "libANGLE/Debug.h"
......@@ -162,13 +163,14 @@ void State::setGenericBufferBinding<BufferBinding::ElementArray>(const Context *
Buffer *oldBuffer = mVertexArray->mState.mElementArrayBuffer.get();
if (oldBuffer)
{
oldBuffer->removeObserver(&mVertexArray->mState.mElementArrayBuffer);
oldBuffer->onNonTFBindingChanged(-1);
oldBuffer->release(context);
}
mVertexArray->mState.mElementArrayBuffer.assign(buffer);
mVertexArray->mElementArrayBufferObserverBinding.bind(buffer);
if (buffer)
{
buffer->addObserver(&mVertexArray->mState.mElementArrayBuffer);
buffer->onNonTFBindingChanged(1);
buffer->addRef();
}
......@@ -1638,7 +1640,7 @@ Buffer *State::getTargetBuffer(BufferBinding target) const
switch (target)
{
case BufferBinding::ElementArray:
return getVertexArray()->getElementArrayBuffer().get();
return getVertexArray()->getElementArrayBuffer();
default:
return mBoundBuffers[target].get();
}
......@@ -2232,8 +2234,11 @@ Error State::getIntegerv(const Context *context, GLenum pname, GLint *params)
*params = mBoundBuffers[BufferBinding::DrawIndirect].id();
break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
*params = getVertexArray()->getElementArrayBuffer().id();
{
Buffer *elementArrayBuffer = getVertexArray()->getElementArrayBuffer();
*params = elementArrayBuffer ? elementArrayBuffer->id() : 0;
break;
}
case GL_DRAW_FRAMEBUFFER_BINDING:
static_assert(GL_DRAW_FRAMEBUFFER_BINDING == GL_DRAW_FRAMEBUFFER_BINDING_ANGLE,
"Enum mismatch");
......
......@@ -21,11 +21,15 @@ bool IsElementArrayBufferSubjectIndex(angle::SubjectIndex subjectIndex)
{
return (subjectIndex == MAX_VERTEX_ATTRIBS);
}
constexpr angle::SubjectIndex kElementArrayBufferIndex = MAX_VERTEX_ATTRIBS;
} // anonymous namespce
// VertexArrayState implementation.
VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings)
: mLabel(), mVertexBindings()
VertexArrayState::VertexArrayState(VertexArray *vertexArray,
size_t maxAttribs,
size_t maxAttribBindings)
: mElementArrayBuffer(vertexArray, kElementArrayBufferIndex)
{
ASSERT(maxAttribs <= maxAttribBindings);
......@@ -89,9 +93,8 @@ VertexArray::VertexArray(rx::GLImplFactory *factory,
size_t maxAttribs,
size_t maxAttribBindings)
: mId(id),
mState(maxAttribs, maxAttribBindings),
mVertexArray(factory->createVertexArray(mState)),
mElementArrayBufferObserverBinding(this, MAX_VERTEX_ATTRIBS)
mState(this, maxAttribs, maxAttribBindings),
mVertexArray(factory->createVertexArray(mState))
{
for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
{
......@@ -108,7 +111,7 @@ void VertexArray::onDestroy(const Context *context)
}
if (isBound && mState.mElementArrayBuffer.get())
mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
mState.mElementArrayBuffer.set(context, nullptr);
mState.mElementArrayBuffer.bind(context, nullptr);
mVertexArray->destroy(context);
SafeDelete(mVertexArray);
delete this;
......@@ -145,11 +148,11 @@ void VertexArray::detachBuffer(const Context *context, GLuint bufferName)
}
}
if (mState.mElementArrayBuffer.id() == bufferName)
if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferName)
{
if (isBound && mState.mElementArrayBuffer.get())
mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
mState.mElementArrayBuffer.set(context, nullptr);
mState.mElementArrayBuffer.bind(context, nullptr);
}
}
......
......@@ -35,12 +35,12 @@ class Buffer;
class VertexArrayState final : angle::NonCopyable
{
public:
VertexArrayState(size_t maxAttribs, size_t maxBindings);
VertexArrayState(VertexArray *vertexArray, size_t maxAttribs, size_t maxBindings);
~VertexArrayState();
const std::string &getLabel() const { return mLabel; }
const BindingPointer<Buffer> &getElementArrayBuffer() const { return mElementArrayBuffer; }
Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); }
size_t getMaxAttribs() const { return mVertexAttributes.size(); }
size_t getMaxBindings() const { return mVertexBindings.size(); }
const AttributesMask &getEnabledAttributesMask() const { return mEnabledAttributesMask; }
......@@ -75,7 +75,7 @@ class VertexArrayState final : angle::NonCopyable
friend class VertexArray;
std::string mLabel;
std::vector<VertexAttribute> mVertexAttributes;
BindingPointer<Buffer> mElementArrayBuffer;
SubjectBindingPointer<Buffer> mElementArrayBuffer;
std::vector<VertexBinding> mVertexBindings;
AttributesMask mEnabledAttributesMask;
ComponentTypeMask mVertexAttributesTypeMask;
......@@ -153,10 +153,7 @@ class VertexArray final : public angle::ObserverInterface,
GLintptr offset,
GLsizei stride);
const BindingPointer<Buffer> &getElementArrayBuffer() const
{
return mState.getElementArrayBuffer();
}
Buffer *getElementArrayBuffer() const { return mState.getElementArrayBuffer(); }
size_t getMaxAttribs() const { return mState.getMaxAttribs(); }
size_t getMaxBindings() const { return mState.getMaxBindings(); }
......@@ -289,7 +286,6 @@ class VertexArray final : public angle::ObserverInterface,
rx::VertexArrayImpl *mVertexArray;
std::vector<angle::ObserverBinding> mArrayBufferObserverBindings;
angle::ObserverBinding mElementArrayBufferObserverBinding;
AttributesMask mCachedTransformFeedbackConflictedBindingsMask;
};
......
......@@ -97,7 +97,7 @@ Error DrawCallParams::ensureIndexRangeResolved(const Context *context) const
const State &state = context->getGLState();
const gl::VertexArray *vao = state.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
if (elementArrayBuffer)
{
......
......@@ -60,7 +60,7 @@ bool DrawCallHasStreamingVertexArrays(const gl::Context *context, gl::PrimitiveM
bool DrawCallHasStreamingElementArray(const gl::Context *context, GLenum srcType)
{
const gl::State &glState = context->getGLState();
gl::Buffer *elementArrayBuffer = glState.getVertexArray()->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = glState.getVertexArray()->getElementArrayBuffer();
bool primitiveRestartWorkaround =
UsePrimitiveRestartWorkaround(glState.isPrimitiveRestartEnabled(), srcType);
......
......@@ -1667,7 +1667,7 @@ angle::Result Renderer11::drawLineLoop(const gl::Context *context,
{
const gl::State &glState = context->getGLState();
gl::VertexArray *vao = glState.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
const void *indices = indexPointer;
......@@ -1744,7 +1744,7 @@ angle::Result Renderer11::drawTriangleFan(const gl::Context *context,
{
const gl::State &glState = context->getGLState();
gl::VertexArray *vao = glState.getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
const void *indexPointer = indices;
......
......@@ -2978,7 +2978,7 @@ angle::Result StateManager11::applyIndexBuffer(const gl::Context *context,
}
GLenum destElementType = mVertexArray11->getCachedDestinationIndexType();
gl::Buffer *elementArrayBuffer = mVertexArray11->getState().getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = mVertexArray11->getState().getElementArrayBuffer();
TranslatedIndexData indexInfo;
ANGLE_TRY(mIndexDataManager.prepareIndexData(context, params.type(), destElementType,
......
......@@ -199,7 +199,7 @@ angle::Result VertexArray11::updateElementArrayStorage(const gl::Context *contex
static_cast<unsigned int>(reinterpret_cast<uintptr_t>(drawCallParams.indices()));
mCurrentElementArrayStorage =
ClassifyIndexStorage(context->getGLState(), mState.getElementArrayBuffer().get(),
ClassifyIndexStorage(context->getGLState(), mState.getElementArrayBuffer(),
drawCallParams.type(), mCachedDestinationIndexType, offset);
return angle::Result::Continue();
......
......@@ -1299,7 +1299,7 @@ angle::Result Renderer9::applyIndexBuffer(const gl::Context *context,
TranslatedIndexData *indexInfo)
{
gl::VertexArray *vao = context->getGLState().getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
const gl::DrawCallParams &drawCallParams = context->getParams<gl::DrawCallParams>();
GLenum dstType = GL_NONE;
......@@ -1387,7 +1387,7 @@ angle::Result Renderer9::drawElementsImpl(const gl::Context *context,
int minIndex = static_cast<int>(indexRange.start);
gl::VertexArray *vao = context->getGLState().getVertexArray();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
if (mode == gl::PrimitiveMode::Points)
{
......
......@@ -129,7 +129,7 @@ angle::Result VertexArrayGL::syncDrawElementsState(const gl::Context *context,
void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
{
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
{
const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
......@@ -187,7 +187,7 @@ angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
{
ASSERT(outIndices);
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
// Need to check the range of indices if attributes need to be streamed
if (elementArrayBuffer != nullptr)
......
......@@ -321,7 +321,7 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
mCurrentDrawElementsType = drawCallParams.type();
}
const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer().get();
const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer();
if (!elementArrayBuffer)
{
mDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
......
......@@ -123,7 +123,7 @@ angle::Result VertexArrayVk::streamIndexData(ContextVk *contextVk,
const void *sourcePointer,
vk::DynamicBuffer *dynamicBuffer)
{
ASSERT(!mState.getElementArrayBuffer().get() || indexType == GL_UNSIGNED_BYTE);
ASSERT(!mState.getElementArrayBuffer() || indexType == GL_UNSIGNED_BYTE);
dynamicBuffer->releaseRetainedBuffers(contextVk->getRenderer());
......@@ -251,7 +251,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
{
case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
{
gl::Buffer *bufferGL = mState.getElementArrayBuffer().get();
gl::Buffer *bufferGL = mState.getElementArrayBuffer();
if (bufferGL)
{
BufferVk *bufferVk = vk::GetImpl(bufferGL);
......@@ -485,7 +485,7 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
// Handle GL_LINE_LOOP drawElements.
if (mDirtyLineLoopTranslation)
{
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer().get();
gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
if (!elementArrayBuffer)
{
......@@ -540,7 +540,7 @@ angle::Result VertexArrayVk::updateIndexTranslation(ContextVk *contextVk,
ASSERT(drawCallParams.isDrawElements());
ASSERT(drawCallParams.mode() != gl::PrimitiveMode::LineLoop);
gl::Buffer *glBuffer = mState.getElementArrayBuffer().get();
gl::Buffer *glBuffer = mState.getElementArrayBuffer();
if (!glBuffer)
{
......
......@@ -3011,7 +3011,7 @@ bool ValidateDrawElementsCommon(Context *context,
}
const VertexArray *vao = state.getVertexArray();
Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
GLuint typeBytes = GetTypeInfo(type).bytes;
......
......@@ -537,7 +537,7 @@ bool ValidateDrawElementsIndirect(Context *context,
const State &state = context->getGLState();
const VertexArray *vao = state.getVertexArray();
Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
if (!elementArrayBuffer)
{
context->handleError(InvalidOperation() << "zero is bound to ELEMENT_ARRAY_BUFFER");
......
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