// // Copyright 2013 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. // // Implementation of the state class for mananging GLES 3 Vertex Array Objects. //
for (size_t i = 0; i < maxAttribs; i++)
{
mVertexAttributes.emplace_back(static_cast<GLuint>(i));
mVertexBindings.emplace_back(static_cast<GLuint>(i));
}
// Initially all attributes start as "client" with no buffer bound.
mClientMemoryAttribsMask.set();
}
// Set an attribute using a new binding. void VertexArrayState::setAttribBinding(const Context *context,
size_t attribIndex,
GLuint newBindingIndex)
{
ASSERT(attribIndex < mVertexAttributes.size() && newBindingIndex < mVertexBindings.size());
void VertexArray::onDestroy(const Context *context)
{ bool isBound = context->isCurrentVertexArray(this); for (uint32_t bindingIndex = 0; bindingIndex < mState.mVertexBindings.size(); ++bindingIndex)
{
VertexBinding &binding = mState.mVertexBindings[bindingIndex];
Buffer *buffer = binding.getBuffer().get(); if (isBound)
{ if (buffer)
{
buffer->onNonTFBindingChanged(-1);
}
} if (buffer)
{ // Note: the non-contents observer is unbound in the ObserverBinding destructor.
buffer->removeContentsObserver(this, bindingIndex);
}
binding.setBuffer(context, nullptr);
} if (mState.mElementArrayBuffer.get())
{ if (isBound)
{
mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
}
mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex);
}
mState.mElementArrayBuffer.bind(context, nullptr);
// If mDirtyObserverBindingBits is set, it means we have removed it from the buffer's observer // list. We should unassign subject to avoid assertion. for (size_t bindingIndex : mDirtyObserverBindingBits)
{
angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
observer->assignSubject(nullptr);
}
size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
{
static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, "The stride of vertex attributes should equal to that of vertex bindings.");
ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER); return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS;
}
// Several nullptr checks are combined here for optimization purposes. if (oldBuffer)
{
oldBuffer->onNonTFBindingChanged(-1);
oldBuffer->removeObserver(observer);
oldBuffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
oldBuffer->release(context);
}
// Trigger updates in all bound attributes. if (context->isBufferAccessValidationEnabled())
{ for (size_t attribIndex : binding.getBoundAttributesMask())
{
mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding);
}
}
}
// If we switch from an array buffer to a client pointer(or vice-versa), we set the whole // attribute dirty. This notifies the Vulkan back-end to update all its caches. const VertexBinding &binding = mState.mVertexBindings[attribIndex]; if ((boundBuffer == nullptr) != (binding.getBuffer().get() == nullptr))
{
attribDirty = true;
}
// Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset // which is handled within bindVertexBufferImpl and reflected in bufferDirty.
attrib.pointer = pointer;
GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0; constbool bufferDirty =
bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
// The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
ASSERT(mDirtyAttribBits[0].none());
ASSERT(mDirtyBindingBits[0].none());
mState.mLastSyncedEnabledAttributesMask = mState.mEnabledAttributesMask;
} return angle::Result::Continue;
}
// This becomes current vertex array on the context void VertexArray::onBind(const Context *context)
{ if (mDirtyObserverBindingBits.none())
{ return;
}
// This vertex array becoming current. Some of the bindings we may have removed from buffer's // observer list. We need to add it back to the buffer's observer list and update dirty bits // that we may have missed while we were not observing. for (size_t bindingIndex : mDirtyObserverBindingBits)
{ const gl::VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
gl::Buffer *bufferGL = binding.getBuffer().get();
ASSERT(bufferGL != nullptr);
// This becomes non-current vertex array on the context void VertexArray::onUnbind(const Context *context)
{ // This vertex array becoming non-current. For performance reason, if there are too many // observers in the buffer, we remove it from the buffers' observer list so that the cost of // buffer sending signal to observers will be too expensive. for (uint32_t bindingIndex = 0; bindingIndex < mArrayBufferObserverBindings.size();
++bindingIndex)
{ const gl::VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
gl::Buffer *bufferGL = binding.getBuffer().get(); if (bufferGL && bufferGL->getObserversCount() > kMaxObserverCountToTriggerUnobserve)
{
bufferGL->removeObserver(&mArrayBufferObserverBindings[bindingIndex]);
mDirtyObserverBindingBits.set(bindingIndex);
}
}
}
void VertexArray::onBindingChanged(const Context *context, int incr)
{ // When vertex array gets unbound, we remove it from bound buffers' observer list so that when // buffer changes, it wont has to loop over all these non-current vertex arrays and set dirty // bit on them. To compensate for that, when we bind a vertex array, we have to check against // each bound buffers and see if they have changed and needs to update vertex array's dirty bits // accordingly
ASSERT(incr == 1 || incr == -1); if (incr < 0)
{
onUnbind(context);
} else
{
onBind(context);
}
if (context->isWebGL())
{ if (mState.mElementArrayBuffer.get())
mState.mElementArrayBuffer->onNonTFBindingChanged(incr); for (auto &binding : mState.mVertexBindings)
{
binding.onContainerBindingChanged(context, incr);
}
}
}
VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
angle::SubjectIndex index) const
{ if (IsElementArrayBufferSubjectIndex(index))
{
mIndexRangeCache.invalidate(); return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
: DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
} else
{ // Note: this currently just gets the top-level dirty bit.
ASSERT(index < mArrayBufferObserverBindings.size()); returnstatic_cast<DirtyBitType>(
(contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
}
}
void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{ switch (message)
{ case angle::SubjectMessage::SubjectChanged: if (!IsElementArrayBufferSubjectIndex(index))
{
updateCachedBufferBindingSize(&mState.mVertexBindings[index]);
}
setDependentDirtyBit(false, index); break;
case angle::SubjectMessage::BindingChanged: if (!IsElementArrayBufferSubjectIndex(index))
{ const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get();
updateCachedTransformFeedbackBindingValidation(index, buffer);
} break;
case angle::SubjectMessage::SubjectMapped: if (!IsElementArrayBufferSubjectIndex(index))
{
updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
}
onStateChange(angle::SubjectMessage::SubjectMapped); break;
case angle::SubjectMessage::SubjectUnmapped:
setDependentDirtyBit(true, index);
if (!IsElementArrayBufferSubjectIndex(index))
{
updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
}
onStateChange(angle::SubjectMessage::SubjectUnmapped); break;
case angle::SubjectMessage::InternalMemoryAllocationChanged:
setDependentDirtyBit(false, index); break;
// Slow check. We must ensure that the conflicting attributes are enabled/active. for (size_t attribIndex : activeAttribues)
{ const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex])
{ returntrue;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.