diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/angle/checkout/src/libANGLE/VertexArray.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/VertexArray.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/VertexArray.cpp | 686 |
1 files changed, 686 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/VertexArray.cpp b/gfx/angle/checkout/src/libANGLE/VertexArray.cpp new file mode 100644 index 0000000000..e653399e6d --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/VertexArray.cpp @@ -0,0 +1,686 @@ +// +// Copyright (c) 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. +// + +#include "libANGLE/VertexArray.h" + +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/VertexArrayImpl.h" + +namespace gl +{ +namespace +{ +bool IsElementArrayBufferSubjectIndex(angle::SubjectIndex subjectIndex) +{ + return (subjectIndex == MAX_VERTEX_ATTRIBS); +} + +constexpr angle::SubjectIndex kElementArrayBufferIndex = MAX_VERTEX_ATTRIBS; +} // namespace + +// VertexArrayState implementation. +VertexArrayState::VertexArrayState(VertexArray *vertexArray, + size_t maxAttribs, + size_t maxAttribBindings) + : mElementArrayBuffer(vertexArray, kElementArrayBufferIndex) +{ + ASSERT(maxAttribs <= maxAttribBindings); + + 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(); +} + +VertexArrayState::~VertexArrayState() {} + +bool VertexArrayState::hasEnabledNullPointerClientArray() const +{ + return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any(); +} + +AttributesMask VertexArrayState::getBindingToAttributesMask(GLuint bindingIndex) const +{ + ASSERT(bindingIndex < MAX_VERTEX_ATTRIB_BINDINGS); + return mVertexBindings[bindingIndex].getBoundAttributesMask(); +} + +// Set an attribute using a new binding. +void VertexArrayState::setAttribBinding(const Context *context, + size_t attribIndex, + GLuint newBindingIndex) +{ + ASSERT(attribIndex < MAX_VERTEX_ATTRIBS && newBindingIndex < MAX_VERTEX_ATTRIB_BINDINGS); + + VertexAttribute &attrib = mVertexAttributes[attribIndex]; + + // Update the binding-attribute map. + const GLuint oldBindingIndex = attrib.bindingIndex; + ASSERT(oldBindingIndex != newBindingIndex); + + VertexBinding &oldBinding = mVertexBindings[oldBindingIndex]; + VertexBinding &newBinding = mVertexBindings[newBindingIndex]; + + ASSERT(oldBinding.getBoundAttributesMask().test(attribIndex) && + !newBinding.getBoundAttributesMask().test(attribIndex)); + + oldBinding.resetBoundAttribute(attribIndex); + newBinding.setBoundAttribute(attribIndex); + + // Set the attribute using the new binding. + attrib.bindingIndex = newBindingIndex; + + if (context->isBufferAccessValidationEnabled()) + { + attrib.updateCachedElementLimit(newBinding); + } + + bool isMapped = newBinding.getBuffer().get() && newBinding.getBuffer()->isMapped(); + mCachedMappedArrayBuffers.set(attribIndex, isMapped); + mCachedEnabledMappedArrayBuffers.set(attribIndex, isMapped && attrib.enabled); +} + +// VertexArray implementation. +VertexArray::VertexArray(rx::GLImplFactory *factory, + GLuint id, + size_t maxAttribs, + size_t maxAttribBindings) + : mId(id), + mState(this, maxAttribs, maxAttribBindings), + mVertexArray(factory->createVertexArray(mState)), + mBufferAccessValidationEnabled(false) +{ + for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex) + { + mArrayBufferObserverBindings.emplace_back(this, attribIndex); + } +} + +void VertexArray::onDestroy(const Context *context) +{ + bool isBound = context->isCurrentVertexArray(this); + for (VertexBinding &binding : mState.mVertexBindings) + { + if (isBound) + { + if (binding.getBuffer().get()) + binding.getBuffer()->onNonTFBindingChanged(-1); + } + binding.setBuffer(context, nullptr); + } + if (isBound && mState.mElementArrayBuffer.get()) + mState.mElementArrayBuffer->onNonTFBindingChanged(-1); + mState.mElementArrayBuffer.bind(context, nullptr); + mVertexArray->destroy(context); + SafeDelete(mVertexArray); + delete this; +} + +VertexArray::~VertexArray() +{ + ASSERT(!mVertexArray); +} + +void VertexArray::setLabel(const Context *context, const std::string &label) +{ + mState.mLabel = label; +} + +const std::string &VertexArray::getLabel() const +{ + return mState.mLabel; +} + +bool VertexArray::detachBuffer(const Context *context, GLuint bufferName) +{ + bool isBound = context->isCurrentVertexArray(this); + bool anyBufferDetached = false; + for (size_t bindingIndex = 0; bindingIndex < gl::MAX_VERTEX_ATTRIB_BINDINGS; ++bindingIndex) + { + VertexBinding &binding = mState.mVertexBindings[bindingIndex]; + if (binding.getBuffer().id() == bufferName) + { + if (isBound) + { + if (binding.getBuffer().get()) + binding.getBuffer()->onNonTFBindingChanged(-1); + } + binding.setBuffer(context, nullptr); + mArrayBufferObserverBindings[bindingIndex].reset(); + + if (context->getClientVersion() >= ES_3_1) + { + setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER); + } + else + { + ASSERT(binding.getBoundAttributesMask() == AttributesMask(1ull << bindingIndex)); + setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER); + } + + anyBufferDetached = true; + mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask(); + } + } + + if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferName) + { + if (isBound && mState.mElementArrayBuffer.get()) + mState.mElementArrayBuffer->onNonTFBindingChanged(-1); + mState.mElementArrayBuffer.bind(context, nullptr); + mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER); + anyBufferDetached = true; + } + + return anyBufferDetached; +} + +const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const +{ + ASSERT(attribIndex < getMaxAttribs()); + return mState.mVertexAttributes[attribIndex]; +} + +const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const +{ + ASSERT(bindingIndex < getMaxBindings()); + return mState.mVertexBindings[bindingIndex]; +} + +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; +} + +ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex, + DirtyAttribBitType dirtyAttribBit) +{ + mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex); + mDirtyAttribBits[attribIndex].set(dirtyAttribBit); +} + +ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex, + DirtyBindingBitType dirtyBindingBit) +{ + mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex); + mDirtyBindingBits[bindingIndex].set(dirtyBindingBit); +} + +ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding) +{ + if (!mBufferAccessValidationEnabled) + return; + + for (size_t boundAttribute : binding->getBoundAttributesMask()) + { + mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding); + } +} + +ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers( + bool isMapped, + const AttributesMask &boundAttributesMask) +{ + if (isMapped) + { + mState.mCachedMappedArrayBuffers |= boundAttributesMask; + } + else + { + 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) +{ + const bool hasConflict = buffer && buffer->isBoundForTransformFeedbackAndOtherUse(); + mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict); +} + +bool VertexArray::bindVertexBufferImpl(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + ASSERT(bindingIndex < getMaxBindings()); + ASSERT(context->isCurrentVertexArray(this)); + + VertexBinding *binding = &mState.mVertexBindings[bindingIndex]; + + Buffer *oldBuffer = binding->getBuffer().get(); + + const bool sameBuffer = oldBuffer == boundBuffer; + const bool sameStride = static_cast<GLuint>(stride) == binding->getStride(); + const bool sameOffset = offset == binding->getOffset(); + + if (sameBuffer && sameStride && sameOffset) + { + return false; + } + + 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); + updateCachedBufferBindingSize(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()); + } + + return true; +} + +void VertexArray::bindVertexBuffer(const Context *context, + size_t bindingIndex, + Buffer *boundBuffer, + GLintptr offset, + GLsizei stride) +{ + if (bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride)) + { + setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER); + } +} + +void VertexArray::setVertexAttribBinding(const Context *context, + size_t attribIndex, + GLuint bindingIndex) +{ + ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings()); + + if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex) + { + // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable. + ASSERT(context->getClientVersion() >= ES_3_1); + + mState.setAttribBinding(context, attribIndex, bindingIndex); + + setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING); + + // Update client attribs mask. + bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr; + mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer); + } +} + +void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) +{ + ASSERT(bindingIndex < getMaxBindings()); + + VertexBinding &binding = mState.mVertexBindings[bindingIndex]; + + binding.setDivisor(divisor); + setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR); + + // Trigger updates in all bound attributes. + for (size_t attribIndex : binding.getBoundAttributesMask()) + { + mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding); + } +} + +ANGLE_INLINE bool VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib, + GLint size, + VertexAttribType type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) +{ + angle::FormatID formatID = gl::GetVertexFormatID(type, normalized, size, pureInteger); + + if (formatID != attrib->format->id || attrib->relativeOffset != relativeOffset) + { + attrib->relativeOffset = relativeOffset; + attrib->format = &angle::Format::Get(formatID); + return true; + } + + return false; +} + +void VertexArray::setVertexAttribFormat(size_t attribIndex, + GLint size, + VertexAttribType type, + bool normalized, + bool pureInteger, + GLuint relativeOffset) +{ + VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; + + ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type); + SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask); + + if (setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, relativeOffset)) + { + setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT); + } + + attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]); +} + +void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor) +{ + ASSERT(attribIndex < getMaxAttribs()); + + setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex)); + setVertexBindingDivisor(attribIndex, divisor); +} + +void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) +{ + ASSERT(attribIndex < getMaxAttribs()); + + VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; + + if (mState.mEnabledAttributesMask.test(attribIndex) == enabledState) + { + return; + } + + attrib.enabled = enabledState; + + setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED); + + // Update state cache + mState.mEnabledAttributesMask.set(attribIndex, enabledState); + mState.mCachedEnabledMappedArrayBuffers = + mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask; +} + +ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context, + ComponentType componentType, + bool pureInteger, + size_t attribIndex, + Buffer *boundBuffer, + GLint size, + VertexAttribType type, + bool normalized, + GLsizei stride, + const void *pointer) +{ + ASSERT(attribIndex < getMaxAttribs()); + + GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0; + + VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; + + SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask); + + bool attribDirty = setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, 0); + + if (attrib.bindingIndex != attribIndex) + { + setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex)); + } + + GLsizei effectiveStride = + stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)); + + if (pointer != attrib.pointer || attrib.vertexAttribArrayStride != static_cast<GLuint>(stride)) + { + attribDirty = true; + } + + attrib.pointer = pointer; + attrib.vertexAttribArrayStride = stride; + + // "Pointer buffer" dirty bit disabled because of a bug. http://anglebug.com/3256 + bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride); + setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER); + ANGLE_UNUSED_VARIABLE(attribDirty); + + // if (bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride) && + // !attribDirty) + //{ + // setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER); + //} + // else if (attribDirty) + //{ + // setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER); + //} + + mState.mNullPointerClientMemoryAttribsMask.set(attribIndex, + boundBuffer == nullptr && pointer == nullptr); +} + +void VertexArray::setVertexAttribPointer(const Context *context, + size_t attribIndex, + gl::Buffer *boundBuffer, + GLint size, + VertexAttribType type, + bool normalized, + GLsizei stride, + const void *pointer) +{ + setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size, + type, normalized, stride, pointer); +} + +void VertexArray::setVertexAttribIPointer(const Context *context, + size_t attribIndex, + gl::Buffer *boundBuffer, + GLint size, + VertexAttribType type, + GLsizei stride, + const void *pointer) +{ + ComponentType componentType = GetVertexAttributeComponentType(true, type); + setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type, + false, stride, pointer); +} + +angle::Result VertexArray::syncState(const Context *context) +{ + if (mDirtyBits.any()) + { + mDirtyBitsGuard = mDirtyBits; + ANGLE_TRY( + mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits)); + mDirtyBits.reset(); + mDirtyBitsGuard.reset(); + + // 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()); + } + return angle::Result::Continue; +} + +void VertexArray::onBindingChanged(const Context *context, int incr) +{ + 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()); + return static_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::ContentsChanged: + setDependentDirtyBit(true, index); + break; + + 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; + + default: + UNREACHABLE(); + break; + } +} + +void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index) +{ + DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index); + ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit)); + mDirtyBits.set(dirtyBit); + onStateChange(angle::SubjectMessage::ContentsChanged); +} + +bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const +{ + // Fast check first. + if (!mCachedTransformFeedbackConflictedBindingsMask.any()) + { + return false; + } + + const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask(); + + // 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]) + { + return true; + } + } + + return false; +} + +angle::Result VertexArray::getIndexRangeImpl(const Context *context, + DrawElementsType type, + GLsizei indexCount, + const void *indices, + IndexRange *indexRangeOut) const +{ + Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get(); + if (!elementArrayBuffer) + { + *indexRangeOut = ComputeIndexRange(type, indices, indexCount, + context->getState().isPrimitiveRestartEnabled()); + return angle::Result::Continue; + } + + size_t offset = reinterpret_cast<uintptr_t>(indices); + ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount, + context->getState().isPrimitiveRestartEnabled(), + indexRangeOut)); + + mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut); + return angle::Result::Continue; +} + +VertexArray::IndexRangeCache::IndexRangeCache() = default; + +void VertexArray::IndexRangeCache::put(DrawElementsType type, + GLsizei indexCount, + size_t offset, + const IndexRange &indexRange) +{ + ASSERT(type != DrawElementsType::InvalidEnum); + + mTypeKey = type; + mIndexCountKey = indexCount; + mOffsetKey = offset; + mPayload = indexRange; +} +} // namespace gl |