xref: /aosp_15_r20/external/angle/src/libANGLE/VertexArray.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2013 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // Implementation of the state class for mananging GLES 3 Vertex Array Objects.
7*8975f5c5SAndroid Build Coastguard Worker //
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/VertexArray.h"
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include "common/utilities.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Buffer.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/BufferImpl.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/GLImplFactory.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/VertexArrayImpl.h"
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker namespace gl
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker namespace
21*8975f5c5SAndroid Build Coastguard Worker {
IsElementArrayBufferSubjectIndex(angle::SubjectIndex subjectIndex)22*8975f5c5SAndroid Build Coastguard Worker bool IsElementArrayBufferSubjectIndex(angle::SubjectIndex subjectIndex)
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker     return (subjectIndex == kElementArrayBufferIndex);
25*8975f5c5SAndroid Build Coastguard Worker }
26*8975f5c5SAndroid Build Coastguard Worker }  // namespace
27*8975f5c5SAndroid Build Coastguard Worker 
28*8975f5c5SAndroid Build Coastguard Worker // VertexArrayState implementation.
VertexArrayState(VertexArray * vertexArray,size_t maxAttribs,size_t maxAttribBindings)29*8975f5c5SAndroid Build Coastguard Worker VertexArrayState::VertexArrayState(VertexArray *vertexArray,
30*8975f5c5SAndroid Build Coastguard Worker                                    size_t maxAttribs,
31*8975f5c5SAndroid Build Coastguard Worker                                    size_t maxAttribBindings)
32*8975f5c5SAndroid Build Coastguard Worker     : mId(vertexArray->id()), mElementArrayBuffer(vertexArray, kElementArrayBufferIndex)
33*8975f5c5SAndroid Build Coastguard Worker {
34*8975f5c5SAndroid Build Coastguard Worker     ASSERT(maxAttribs <= maxAttribBindings);
35*8975f5c5SAndroid Build Coastguard Worker 
36*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < maxAttribs; i++)
37*8975f5c5SAndroid Build Coastguard Worker     {
38*8975f5c5SAndroid Build Coastguard Worker         mVertexAttributes.emplace_back(static_cast<GLuint>(i));
39*8975f5c5SAndroid Build Coastguard Worker         mVertexBindings.emplace_back(static_cast<GLuint>(i));
40*8975f5c5SAndroid Build Coastguard Worker     }
41*8975f5c5SAndroid Build Coastguard Worker 
42*8975f5c5SAndroid Build Coastguard Worker     // Initially all attributes start as "client" with no buffer bound.
43*8975f5c5SAndroid Build Coastguard Worker     mClientMemoryAttribsMask.set();
44*8975f5c5SAndroid Build Coastguard Worker }
45*8975f5c5SAndroid Build Coastguard Worker 
~VertexArrayState()46*8975f5c5SAndroid Build Coastguard Worker VertexArrayState::~VertexArrayState() {}
47*8975f5c5SAndroid Build Coastguard Worker 
hasEnabledNullPointerClientArray() const48*8975f5c5SAndroid Build Coastguard Worker bool VertexArrayState::hasEnabledNullPointerClientArray() const
49*8975f5c5SAndroid Build Coastguard Worker {
50*8975f5c5SAndroid Build Coastguard Worker     return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any();
51*8975f5c5SAndroid Build Coastguard Worker }
52*8975f5c5SAndroid Build Coastguard Worker 
getBindingToAttributesMask(GLuint bindingIndex) const53*8975f5c5SAndroid Build Coastguard Worker AttributesMask VertexArrayState::getBindingToAttributesMask(GLuint bindingIndex) const
54*8975f5c5SAndroid Build Coastguard Worker {
55*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bindingIndex < mVertexBindings.size());
56*8975f5c5SAndroid Build Coastguard Worker     return mVertexBindings[bindingIndex].getBoundAttributesMask();
57*8975f5c5SAndroid Build Coastguard Worker }
58*8975f5c5SAndroid Build Coastguard Worker 
59*8975f5c5SAndroid Build Coastguard Worker // Set an attribute using a new binding.
setAttribBinding(const Context * context,size_t attribIndex,GLuint newBindingIndex)60*8975f5c5SAndroid Build Coastguard Worker void VertexArrayState::setAttribBinding(const Context *context,
61*8975f5c5SAndroid Build Coastguard Worker                                         size_t attribIndex,
62*8975f5c5SAndroid Build Coastguard Worker                                         GLuint newBindingIndex)
63*8975f5c5SAndroid Build Coastguard Worker {
64*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < mVertexAttributes.size() && newBindingIndex < mVertexBindings.size());
65*8975f5c5SAndroid Build Coastguard Worker 
66*8975f5c5SAndroid Build Coastguard Worker     VertexAttribute &attrib = mVertexAttributes[attribIndex];
67*8975f5c5SAndroid Build Coastguard Worker 
68*8975f5c5SAndroid Build Coastguard Worker     // Update the binding-attribute map.
69*8975f5c5SAndroid Build Coastguard Worker     const GLuint oldBindingIndex = attrib.bindingIndex;
70*8975f5c5SAndroid Build Coastguard Worker     ASSERT(oldBindingIndex != newBindingIndex);
71*8975f5c5SAndroid Build Coastguard Worker 
72*8975f5c5SAndroid Build Coastguard Worker     VertexBinding &oldBinding = mVertexBindings[oldBindingIndex];
73*8975f5c5SAndroid Build Coastguard Worker     VertexBinding &newBinding = mVertexBindings[newBindingIndex];
74*8975f5c5SAndroid Build Coastguard Worker 
75*8975f5c5SAndroid Build Coastguard Worker     ASSERT(oldBinding.getBoundAttributesMask().test(attribIndex) &&
76*8975f5c5SAndroid Build Coastguard Worker            !newBinding.getBoundAttributesMask().test(attribIndex));
77*8975f5c5SAndroid Build Coastguard Worker 
78*8975f5c5SAndroid Build Coastguard Worker     oldBinding.resetBoundAttribute(attribIndex);
79*8975f5c5SAndroid Build Coastguard Worker     newBinding.setBoundAttribute(attribIndex);
80*8975f5c5SAndroid Build Coastguard Worker 
81*8975f5c5SAndroid Build Coastguard Worker     // Set the attribute using the new binding.
82*8975f5c5SAndroid Build Coastguard Worker     attrib.bindingIndex = newBindingIndex;
83*8975f5c5SAndroid Build Coastguard Worker 
84*8975f5c5SAndroid Build Coastguard Worker     if (context->isBufferAccessValidationEnabled())
85*8975f5c5SAndroid Build Coastguard Worker     {
86*8975f5c5SAndroid Build Coastguard Worker         attrib.updateCachedElementLimit(newBinding);
87*8975f5c5SAndroid Build Coastguard Worker     }
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker     bool isMapped = newBinding.getBuffer().get() && newBinding.getBuffer()->isMapped();
90*8975f5c5SAndroid Build Coastguard Worker     mCachedMappedArrayBuffers.set(attribIndex, isMapped);
91*8975f5c5SAndroid Build Coastguard Worker     mEnabledAttributesMask.set(attribIndex, attrib.enabled);
92*8975f5c5SAndroid Build Coastguard Worker     updateCachedMutableOrNonPersistentArrayBuffers(attribIndex);
93*8975f5c5SAndroid Build Coastguard Worker     mCachedInvalidMappedArrayBuffer = mCachedMappedArrayBuffers & mEnabledAttributesMask &
94*8975f5c5SAndroid Build Coastguard Worker                                       mCachedMutableOrImpersistentArrayBuffers;
95*8975f5c5SAndroid Build Coastguard Worker }
96*8975f5c5SAndroid Build Coastguard Worker 
updateCachedMutableOrNonPersistentArrayBuffers(size_t index)97*8975f5c5SAndroid Build Coastguard Worker void VertexArrayState::updateCachedMutableOrNonPersistentArrayBuffers(size_t index)
98*8975f5c5SAndroid Build Coastguard Worker {
99*8975f5c5SAndroid Build Coastguard Worker     const VertexBinding &vertexBinding   = mVertexBindings[index];
100*8975f5c5SAndroid Build Coastguard Worker     const BindingPointer<Buffer> &buffer = vertexBinding.getBuffer();
101*8975f5c5SAndroid Build Coastguard Worker     bool isMutableOrImpersistentArrayBuffer =
102*8975f5c5SAndroid Build Coastguard Worker         buffer.get() &&
103*8975f5c5SAndroid Build Coastguard Worker         (!buffer->isImmutable() || (buffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) == 0);
104*8975f5c5SAndroid Build Coastguard Worker     mCachedMutableOrImpersistentArrayBuffers.set(index, isMutableOrImpersistentArrayBuffer);
105*8975f5c5SAndroid Build Coastguard Worker }
106*8975f5c5SAndroid Build Coastguard Worker 
isDefault() const107*8975f5c5SAndroid Build Coastguard Worker bool VertexArrayState::isDefault() const
108*8975f5c5SAndroid Build Coastguard Worker {
109*8975f5c5SAndroid Build Coastguard Worker     return mId.value == 0;
110*8975f5c5SAndroid Build Coastguard Worker }
111*8975f5c5SAndroid Build Coastguard Worker 
112*8975f5c5SAndroid Build Coastguard Worker // VertexArray implementation.
VertexArray(rx::GLImplFactory * factory,VertexArrayID id,size_t maxAttribs,size_t maxAttribBindings)113*8975f5c5SAndroid Build Coastguard Worker VertexArray::VertexArray(rx::GLImplFactory *factory,
114*8975f5c5SAndroid Build Coastguard Worker                          VertexArrayID id,
115*8975f5c5SAndroid Build Coastguard Worker                          size_t maxAttribs,
116*8975f5c5SAndroid Build Coastguard Worker                          size_t maxAttribBindings)
117*8975f5c5SAndroid Build Coastguard Worker     : mId(id),
118*8975f5c5SAndroid Build Coastguard Worker       mState(this, maxAttribs, maxAttribBindings),
119*8975f5c5SAndroid Build Coastguard Worker       mVertexArray(factory->createVertexArray(mState)),
120*8975f5c5SAndroid Build Coastguard Worker       mBufferAccessValidationEnabled(false),
121*8975f5c5SAndroid Build Coastguard Worker       mContentsObservers(this)
122*8975f5c5SAndroid Build Coastguard Worker {
123*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
124*8975f5c5SAndroid Build Coastguard Worker     {
125*8975f5c5SAndroid Build Coastguard Worker         mArrayBufferObserverBindings.emplace_back(this, attribIndex);
126*8975f5c5SAndroid Build Coastguard Worker     }
127*8975f5c5SAndroid Build Coastguard Worker 
128*8975f5c5SAndroid Build Coastguard Worker     mVertexArray->setContentsObservers(&mContentsObservers);
129*8975f5c5SAndroid Build Coastguard Worker }
130*8975f5c5SAndroid Build Coastguard Worker 
onDestroy(const Context * context)131*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onDestroy(const Context *context)
132*8975f5c5SAndroid Build Coastguard Worker {
133*8975f5c5SAndroid Build Coastguard Worker     bool isBound = context->isCurrentVertexArray(this);
134*8975f5c5SAndroid Build Coastguard Worker     for (size_t bindingIndex : mState.mBufferBindingMask)
135*8975f5c5SAndroid Build Coastguard Worker     {
136*8975f5c5SAndroid Build Coastguard Worker         VertexBinding &binding = mState.mVertexBindings[bindingIndex];
137*8975f5c5SAndroid Build Coastguard Worker         Buffer *buffer         = binding.getBuffer().get();
138*8975f5c5SAndroid Build Coastguard Worker         ASSERT(buffer != nullptr);
139*8975f5c5SAndroid Build Coastguard Worker         if (isBound)
140*8975f5c5SAndroid Build Coastguard Worker         {
141*8975f5c5SAndroid Build Coastguard Worker             buffer->onNonTFBindingChanged(-1);
142*8975f5c5SAndroid Build Coastguard Worker         }
143*8975f5c5SAndroid Build Coastguard Worker         else
144*8975f5c5SAndroid Build Coastguard Worker         {
145*8975f5c5SAndroid Build Coastguard Worker             // un-assigning to avoid assertion, since it was already removed from buffer's observer
146*8975f5c5SAndroid Build Coastguard Worker             // list.
147*8975f5c5SAndroid Build Coastguard Worker             mArrayBufferObserverBindings[bindingIndex].assignSubject(nullptr);
148*8975f5c5SAndroid Build Coastguard Worker         }
149*8975f5c5SAndroid Build Coastguard Worker         // Note: the non-contents observer is unbound in the ObserverBinding destructor.
150*8975f5c5SAndroid Build Coastguard Worker         buffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
151*8975f5c5SAndroid Build Coastguard Worker         binding.setBuffer(context, nullptr);
152*8975f5c5SAndroid Build Coastguard Worker     }
153*8975f5c5SAndroid Build Coastguard Worker     mState.mBufferBindingMask.reset();
154*8975f5c5SAndroid Build Coastguard Worker 
155*8975f5c5SAndroid Build Coastguard Worker     if (mState.mElementArrayBuffer.get())
156*8975f5c5SAndroid Build Coastguard Worker     {
157*8975f5c5SAndroid Build Coastguard Worker         if (isBound)
158*8975f5c5SAndroid Build Coastguard Worker         {
159*8975f5c5SAndroid Build Coastguard Worker             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
160*8975f5c5SAndroid Build Coastguard Worker         }
161*8975f5c5SAndroid Build Coastguard Worker         mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex);
162*8975f5c5SAndroid Build Coastguard Worker     }
163*8975f5c5SAndroid Build Coastguard Worker     mState.mElementArrayBuffer.bind(context, nullptr);
164*8975f5c5SAndroid Build Coastguard Worker 
165*8975f5c5SAndroid Build Coastguard Worker     mVertexArray->destroy(context);
166*8975f5c5SAndroid Build Coastguard Worker     SafeDelete(mVertexArray);
167*8975f5c5SAndroid Build Coastguard Worker     delete this;
168*8975f5c5SAndroid Build Coastguard Worker }
169*8975f5c5SAndroid Build Coastguard Worker 
~VertexArray()170*8975f5c5SAndroid Build Coastguard Worker VertexArray::~VertexArray()
171*8975f5c5SAndroid Build Coastguard Worker {
172*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mVertexArray);
173*8975f5c5SAndroid Build Coastguard Worker }
174*8975f5c5SAndroid Build Coastguard Worker 
setLabel(const Context * context,const std::string & label)175*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArray::setLabel(const Context *context, const std::string &label)
176*8975f5c5SAndroid Build Coastguard Worker {
177*8975f5c5SAndroid Build Coastguard Worker     mState.mLabel = label;
178*8975f5c5SAndroid Build Coastguard Worker 
179*8975f5c5SAndroid Build Coastguard Worker     if (mVertexArray)
180*8975f5c5SAndroid Build Coastguard Worker     {
181*8975f5c5SAndroid Build Coastguard Worker         return mVertexArray->onLabelUpdate(context);
182*8975f5c5SAndroid Build Coastguard Worker     }
183*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
184*8975f5c5SAndroid Build Coastguard Worker }
185*8975f5c5SAndroid Build Coastguard Worker 
getLabel() const186*8975f5c5SAndroid Build Coastguard Worker const std::string &VertexArray::getLabel() const
187*8975f5c5SAndroid Build Coastguard Worker {
188*8975f5c5SAndroid Build Coastguard Worker     return mState.mLabel;
189*8975f5c5SAndroid Build Coastguard Worker }
190*8975f5c5SAndroid Build Coastguard Worker 
detachBuffer(const Context * context,BufferID bufferID)191*8975f5c5SAndroid Build Coastguard Worker bool VertexArray::detachBuffer(const Context *context, BufferID bufferID)
192*8975f5c5SAndroid Build Coastguard Worker {
193*8975f5c5SAndroid Build Coastguard Worker     bool isBound           = context->isCurrentVertexArray(this);
194*8975f5c5SAndroid Build Coastguard Worker     bool anyBufferDetached = false;
195*8975f5c5SAndroid Build Coastguard Worker     for (size_t bindingIndex : mState.mBufferBindingMask)
196*8975f5c5SAndroid Build Coastguard Worker     {
197*8975f5c5SAndroid Build Coastguard Worker         VertexBinding &binding                      = mState.mVertexBindings[bindingIndex];
198*8975f5c5SAndroid Build Coastguard Worker         const BindingPointer<Buffer> &bufferBinding = binding.getBuffer();
199*8975f5c5SAndroid Build Coastguard Worker         if (bufferBinding.id() == bufferID)
200*8975f5c5SAndroid Build Coastguard Worker         {
201*8975f5c5SAndroid Build Coastguard Worker             if (isBound)
202*8975f5c5SAndroid Build Coastguard Worker             {
203*8975f5c5SAndroid Build Coastguard Worker                 if (bufferBinding.get())
204*8975f5c5SAndroid Build Coastguard Worker                     bufferBinding->onNonTFBindingChanged(-1);
205*8975f5c5SAndroid Build Coastguard Worker             }
206*8975f5c5SAndroid Build Coastguard Worker             bufferBinding->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
207*8975f5c5SAndroid Build Coastguard Worker             binding.setBuffer(context, nullptr);
208*8975f5c5SAndroid Build Coastguard Worker             mArrayBufferObserverBindings[bindingIndex].reset();
209*8975f5c5SAndroid Build Coastguard Worker             mState.mBufferBindingMask.reset(bindingIndex);
210*8975f5c5SAndroid Build Coastguard Worker 
211*8975f5c5SAndroid Build Coastguard Worker             if (context->getClientVersion() >= ES_3_1 && !mState.isDefault())
212*8975f5c5SAndroid Build Coastguard Worker             {
213*8975f5c5SAndroid Build Coastguard Worker                 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
214*8975f5c5SAndroid Build Coastguard Worker             }
215*8975f5c5SAndroid Build Coastguard Worker             else
216*8975f5c5SAndroid Build Coastguard Worker             {
217*8975f5c5SAndroid Build Coastguard Worker                 static_assert(MAX_VERTEX_ATTRIB_BINDINGS < 8 * sizeof(uint32_t),
218*8975f5c5SAndroid Build Coastguard Worker                               "Not enough bits in bindingIndex");
219*8975f5c5SAndroid Build Coastguard Worker                 // The redundant uint32_t cast here is required to avoid a warning on MSVC.
220*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(binding.getBoundAttributesMask() ==
221*8975f5c5SAndroid Build Coastguard Worker                        AttributesMask(static_cast<uint32_t>(1 << bindingIndex)));
222*8975f5c5SAndroid Build Coastguard Worker                 setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER);
223*8975f5c5SAndroid Build Coastguard Worker             }
224*8975f5c5SAndroid Build Coastguard Worker 
225*8975f5c5SAndroid Build Coastguard Worker             anyBufferDetached = true;
226*8975f5c5SAndroid Build Coastguard Worker             mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask();
227*8975f5c5SAndroid Build Coastguard Worker         }
228*8975f5c5SAndroid Build Coastguard Worker     }
229*8975f5c5SAndroid Build Coastguard Worker 
230*8975f5c5SAndroid Build Coastguard Worker     if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferID)
231*8975f5c5SAndroid Build Coastguard Worker     {
232*8975f5c5SAndroid Build Coastguard Worker         if (isBound && mState.mElementArrayBuffer.get())
233*8975f5c5SAndroid Build Coastguard Worker             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
234*8975f5c5SAndroid Build Coastguard Worker         mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex);
235*8975f5c5SAndroid Build Coastguard Worker         mState.mElementArrayBuffer.bind(context, nullptr);
236*8975f5c5SAndroid Build Coastguard Worker         mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
237*8975f5c5SAndroid Build Coastguard Worker         anyBufferDetached = true;
238*8975f5c5SAndroid Build Coastguard Worker     }
239*8975f5c5SAndroid Build Coastguard Worker 
240*8975f5c5SAndroid Build Coastguard Worker     return anyBufferDetached;
241*8975f5c5SAndroid Build Coastguard Worker }
242*8975f5c5SAndroid Build Coastguard Worker 
getVertexAttribute(size_t attribIndex) const243*8975f5c5SAndroid Build Coastguard Worker const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
244*8975f5c5SAndroid Build Coastguard Worker {
245*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < getMaxAttribs());
246*8975f5c5SAndroid Build Coastguard Worker     return mState.mVertexAttributes[attribIndex];
247*8975f5c5SAndroid Build Coastguard Worker }
248*8975f5c5SAndroid Build Coastguard Worker 
getVertexBinding(size_t bindingIndex) const249*8975f5c5SAndroid Build Coastguard Worker const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
250*8975f5c5SAndroid Build Coastguard Worker {
251*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bindingIndex < getMaxBindings());
252*8975f5c5SAndroid Build Coastguard Worker     return mState.mVertexBindings[bindingIndex];
253*8975f5c5SAndroid Build Coastguard Worker }
254*8975f5c5SAndroid Build Coastguard Worker 
GetVertexIndexFromDirtyBit(size_t dirtyBit)255*8975f5c5SAndroid Build Coastguard Worker size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
256*8975f5c5SAndroid Build Coastguard Worker {
257*8975f5c5SAndroid Build Coastguard Worker     static_assert(MAX_VERTEX_ATTRIBS == MAX_VERTEX_ATTRIB_BINDINGS,
258*8975f5c5SAndroid Build Coastguard Worker                   "The stride of vertex attributes should equal to that of vertex bindings.");
259*8975f5c5SAndroid Build Coastguard Worker     ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
260*8975f5c5SAndroid Build Coastguard Worker     return (dirtyBit - DIRTY_BIT_ATTRIB_0) % MAX_VERTEX_ATTRIBS;
261*8975f5c5SAndroid Build Coastguard Worker }
262*8975f5c5SAndroid Build Coastguard Worker 
setDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)263*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex,
264*8975f5c5SAndroid Build Coastguard Worker                                                  DirtyAttribBitType dirtyAttribBit)
265*8975f5c5SAndroid Build Coastguard Worker {
266*8975f5c5SAndroid Build Coastguard Worker     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
267*8975f5c5SAndroid Build Coastguard Worker     mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
268*8975f5c5SAndroid Build Coastguard Worker }
269*8975f5c5SAndroid Build Coastguard Worker 
clearDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)270*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::clearDirtyAttribBit(size_t attribIndex,
271*8975f5c5SAndroid Build Coastguard Worker                                                    DirtyAttribBitType dirtyAttribBit)
272*8975f5c5SAndroid Build Coastguard Worker {
273*8975f5c5SAndroid Build Coastguard Worker     mDirtyAttribBits[attribIndex].set(dirtyAttribBit, false);
274*8975f5c5SAndroid Build Coastguard Worker     if (mDirtyAttribBits[attribIndex].any())
275*8975f5c5SAndroid Build Coastguard Worker     {
276*8975f5c5SAndroid Build Coastguard Worker         return;
277*8975f5c5SAndroid Build Coastguard Worker     }
278*8975f5c5SAndroid Build Coastguard Worker     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex, false);
279*8975f5c5SAndroid Build Coastguard Worker }
280*8975f5c5SAndroid Build Coastguard Worker 
setDirtyBindingBit(size_t bindingIndex,DirtyBindingBitType dirtyBindingBit)281*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex,
282*8975f5c5SAndroid Build Coastguard Worker                                                   DirtyBindingBitType dirtyBindingBit)
283*8975f5c5SAndroid Build Coastguard Worker {
284*8975f5c5SAndroid Build Coastguard Worker     mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
285*8975f5c5SAndroid Build Coastguard Worker     mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
286*8975f5c5SAndroid Build Coastguard Worker }
287*8975f5c5SAndroid Build Coastguard Worker 
updateCachedBufferBindingSize(VertexBinding * binding)288*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
289*8975f5c5SAndroid Build Coastguard Worker {
290*8975f5c5SAndroid Build Coastguard Worker     if (!mBufferAccessValidationEnabled)
291*8975f5c5SAndroid Build Coastguard Worker         return;
292*8975f5c5SAndroid Build Coastguard Worker 
293*8975f5c5SAndroid Build Coastguard Worker     for (size_t boundAttribute : binding->getBoundAttributesMask())
294*8975f5c5SAndroid Build Coastguard Worker     {
295*8975f5c5SAndroid Build Coastguard Worker         mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
296*8975f5c5SAndroid Build Coastguard Worker     }
297*8975f5c5SAndroid Build Coastguard Worker }
298*8975f5c5SAndroid Build Coastguard Worker 
updateCachedArrayBuffersMasks(bool isMapped,bool isImmutable,bool isPersistent,const AttributesMask & boundAttributesMask)299*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::updateCachedArrayBuffersMasks(
300*8975f5c5SAndroid Build Coastguard Worker     bool isMapped,
301*8975f5c5SAndroid Build Coastguard Worker     bool isImmutable,
302*8975f5c5SAndroid Build Coastguard Worker     bool isPersistent,
303*8975f5c5SAndroid Build Coastguard Worker     const AttributesMask &boundAttributesMask)
304*8975f5c5SAndroid Build Coastguard Worker {
305*8975f5c5SAndroid Build Coastguard Worker     if (isMapped)
306*8975f5c5SAndroid Build Coastguard Worker     {
307*8975f5c5SAndroid Build Coastguard Worker         mState.mCachedMappedArrayBuffers |= boundAttributesMask;
308*8975f5c5SAndroid Build Coastguard Worker     }
309*8975f5c5SAndroid Build Coastguard Worker     else
310*8975f5c5SAndroid Build Coastguard Worker     {
311*8975f5c5SAndroid Build Coastguard Worker         mState.mCachedMappedArrayBuffers &= ~boundAttributesMask;
312*8975f5c5SAndroid Build Coastguard Worker     }
313*8975f5c5SAndroid Build Coastguard Worker 
314*8975f5c5SAndroid Build Coastguard Worker     if (!isImmutable || !isPersistent)
315*8975f5c5SAndroid Build Coastguard Worker     {
316*8975f5c5SAndroid Build Coastguard Worker         mState.mCachedMutableOrImpersistentArrayBuffers |= boundAttributesMask;
317*8975f5c5SAndroid Build Coastguard Worker     }
318*8975f5c5SAndroid Build Coastguard Worker     else
319*8975f5c5SAndroid Build Coastguard Worker     {
320*8975f5c5SAndroid Build Coastguard Worker         mState.mCachedMutableOrImpersistentArrayBuffers &= ~boundAttributesMask;
321*8975f5c5SAndroid Build Coastguard Worker     }
322*8975f5c5SAndroid Build Coastguard Worker 
323*8975f5c5SAndroid Build Coastguard Worker     mState.mCachedInvalidMappedArrayBuffer = mState.mCachedMappedArrayBuffers &
324*8975f5c5SAndroid Build Coastguard Worker                                              mState.mEnabledAttributesMask &
325*8975f5c5SAndroid Build Coastguard Worker                                              mState.mCachedMutableOrImpersistentArrayBuffers;
326*8975f5c5SAndroid Build Coastguard Worker }
327*8975f5c5SAndroid Build Coastguard Worker 
updateCachedMappedArrayBuffersBinding(const VertexBinding & binding)328*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding)
329*8975f5c5SAndroid Build Coastguard Worker {
330*8975f5c5SAndroid Build Coastguard Worker     const Buffer *buffer = binding.getBuffer().get();
331*8975f5c5SAndroid Build Coastguard Worker     bool isMapped        = buffer && buffer->isMapped();
332*8975f5c5SAndroid Build Coastguard Worker     bool isImmutable     = buffer && buffer->isImmutable();
333*8975f5c5SAndroid Build Coastguard Worker     bool isPersistent    = buffer && (buffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0;
334*8975f5c5SAndroid Build Coastguard Worker     return updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent,
335*8975f5c5SAndroid Build Coastguard Worker                                          binding.getBoundAttributesMask());
336*8975f5c5SAndroid Build Coastguard Worker }
337*8975f5c5SAndroid Build Coastguard Worker 
updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,const Buffer * buffer)338*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
339*8975f5c5SAndroid Build Coastguard Worker                                                                               const Buffer *buffer)
340*8975f5c5SAndroid Build Coastguard Worker {
341*8975f5c5SAndroid Build Coastguard Worker     const bool hasConflict = buffer && buffer->hasWebGLXFBBindingConflict(true);
342*8975f5c5SAndroid Build Coastguard Worker     mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
343*8975f5c5SAndroid Build Coastguard Worker }
344*8975f5c5SAndroid Build Coastguard Worker 
bindVertexBufferImpl(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)345*8975f5c5SAndroid Build Coastguard Worker VertexArray::DirtyBindingBits VertexArray::bindVertexBufferImpl(const Context *context,
346*8975f5c5SAndroid Build Coastguard Worker                                                                 size_t bindingIndex,
347*8975f5c5SAndroid Build Coastguard Worker                                                                 Buffer *boundBuffer,
348*8975f5c5SAndroid Build Coastguard Worker                                                                 GLintptr offset,
349*8975f5c5SAndroid Build Coastguard Worker                                                                 GLsizei stride)
350*8975f5c5SAndroid Build Coastguard Worker {
351*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bindingIndex < getMaxBindings());
352*8975f5c5SAndroid Build Coastguard Worker     ASSERT(context->isCurrentVertexArray(this));
353*8975f5c5SAndroid Build Coastguard Worker 
354*8975f5c5SAndroid Build Coastguard Worker     VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
355*8975f5c5SAndroid Build Coastguard Worker 
356*8975f5c5SAndroid Build Coastguard Worker     Buffer *oldBuffer = binding->getBuffer().get();
357*8975f5c5SAndroid Build Coastguard Worker 
358*8975f5c5SAndroid Build Coastguard Worker     DirtyBindingBits dirtyBindingBits;
359*8975f5c5SAndroid Build Coastguard Worker     dirtyBindingBits.set(DIRTY_BINDING_BUFFER, oldBuffer != boundBuffer);
360*8975f5c5SAndroid Build Coastguard Worker     dirtyBindingBits.set(DIRTY_BINDING_STRIDE, static_cast<GLuint>(stride) != binding->getStride());
361*8975f5c5SAndroid Build Coastguard Worker     dirtyBindingBits.set(DIRTY_BINDING_OFFSET, offset != binding->getOffset());
362*8975f5c5SAndroid Build Coastguard Worker 
363*8975f5c5SAndroid Build Coastguard Worker     if (dirtyBindingBits.none())
364*8975f5c5SAndroid Build Coastguard Worker     {
365*8975f5c5SAndroid Build Coastguard Worker         return dirtyBindingBits;
366*8975f5c5SAndroid Build Coastguard Worker     }
367*8975f5c5SAndroid Build Coastguard Worker 
368*8975f5c5SAndroid Build Coastguard Worker     if (boundBuffer != oldBuffer)
369*8975f5c5SAndroid Build Coastguard Worker     {
370*8975f5c5SAndroid Build Coastguard Worker         angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
371*8975f5c5SAndroid Build Coastguard Worker         observer->assignSubject(boundBuffer);
372*8975f5c5SAndroid Build Coastguard Worker 
373*8975f5c5SAndroid Build Coastguard Worker         // Several nullptr checks are combined here for optimization purposes.
374*8975f5c5SAndroid Build Coastguard Worker         if (oldBuffer)
375*8975f5c5SAndroid Build Coastguard Worker         {
376*8975f5c5SAndroid Build Coastguard Worker             oldBuffer->onNonTFBindingChanged(-1);
377*8975f5c5SAndroid Build Coastguard Worker             oldBuffer->removeObserver(observer);
378*8975f5c5SAndroid Build Coastguard Worker             oldBuffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
379*8975f5c5SAndroid Build Coastguard Worker             oldBuffer->release(context);
380*8975f5c5SAndroid Build Coastguard Worker             mState.mBufferBindingMask.reset(bindingIndex);
381*8975f5c5SAndroid Build Coastguard Worker         }
382*8975f5c5SAndroid Build Coastguard Worker 
383*8975f5c5SAndroid Build Coastguard Worker         binding->assignBuffer(boundBuffer);
384*8975f5c5SAndroid Build Coastguard Worker 
385*8975f5c5SAndroid Build Coastguard Worker         // Update client memory attribute pointers. Affects all bound attributes.
386*8975f5c5SAndroid Build Coastguard Worker         if (boundBuffer)
387*8975f5c5SAndroid Build Coastguard Worker         {
388*8975f5c5SAndroid Build Coastguard Worker             boundBuffer->addRef();
389*8975f5c5SAndroid Build Coastguard Worker             boundBuffer->onNonTFBindingChanged(1);
390*8975f5c5SAndroid Build Coastguard Worker             boundBuffer->addObserver(observer);
391*8975f5c5SAndroid Build Coastguard Worker             if (context->isWebGL())
392*8975f5c5SAndroid Build Coastguard Worker             {
393*8975f5c5SAndroid Build Coastguard Worker                 mCachedTransformFeedbackConflictedBindingsMask.set(
394*8975f5c5SAndroid Build Coastguard Worker                     bindingIndex, boundBuffer->hasWebGLXFBBindingConflict(true));
395*8975f5c5SAndroid Build Coastguard Worker             }
396*8975f5c5SAndroid Build Coastguard Worker             mState.mBufferBindingMask.set(bindingIndex);
397*8975f5c5SAndroid Build Coastguard Worker             mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask();
398*8975f5c5SAndroid Build Coastguard Worker 
399*8975f5c5SAndroid Build Coastguard Worker             bool isMapped     = boundBuffer->isMapped() == GL_TRUE;
400*8975f5c5SAndroid Build Coastguard Worker             bool isImmutable  = boundBuffer->isImmutable() == GL_TRUE;
401*8975f5c5SAndroid Build Coastguard Worker             bool isPersistent = (boundBuffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0;
402*8975f5c5SAndroid Build Coastguard Worker             updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent,
403*8975f5c5SAndroid Build Coastguard Worker                                           binding->getBoundAttributesMask());
404*8975f5c5SAndroid Build Coastguard Worker         }
405*8975f5c5SAndroid Build Coastguard Worker         else
406*8975f5c5SAndroid Build Coastguard Worker         {
407*8975f5c5SAndroid Build Coastguard Worker             if (context->isWebGL())
408*8975f5c5SAndroid Build Coastguard Worker             {
409*8975f5c5SAndroid Build Coastguard Worker                 mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false);
410*8975f5c5SAndroid Build Coastguard Worker             }
411*8975f5c5SAndroid Build Coastguard Worker             mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask();
412*8975f5c5SAndroid Build Coastguard Worker             updateCachedArrayBuffersMasks(false, false, false, binding->getBoundAttributesMask());
413*8975f5c5SAndroid Build Coastguard Worker         }
414*8975f5c5SAndroid Build Coastguard Worker     }
415*8975f5c5SAndroid Build Coastguard Worker 
416*8975f5c5SAndroid Build Coastguard Worker     binding->setOffset(offset);
417*8975f5c5SAndroid Build Coastguard Worker     binding->setStride(stride);
418*8975f5c5SAndroid Build Coastguard Worker     updateCachedBufferBindingSize(binding);
419*8975f5c5SAndroid Build Coastguard Worker 
420*8975f5c5SAndroid Build Coastguard Worker     return dirtyBindingBits;
421*8975f5c5SAndroid Build Coastguard Worker }
422*8975f5c5SAndroid Build Coastguard Worker 
bindVertexBuffer(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)423*8975f5c5SAndroid Build Coastguard Worker void VertexArray::bindVertexBuffer(const Context *context,
424*8975f5c5SAndroid Build Coastguard Worker                                    size_t bindingIndex,
425*8975f5c5SAndroid Build Coastguard Worker                                    Buffer *boundBuffer,
426*8975f5c5SAndroid Build Coastguard Worker                                    GLintptr offset,
427*8975f5c5SAndroid Build Coastguard Worker                                    GLsizei stride)
428*8975f5c5SAndroid Build Coastguard Worker {
429*8975f5c5SAndroid Build Coastguard Worker     const VertexArray::DirtyBindingBits dirtyBindingBits =
430*8975f5c5SAndroid Build Coastguard Worker         bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride);
431*8975f5c5SAndroid Build Coastguard Worker     if (dirtyBindingBits.any())
432*8975f5c5SAndroid Build Coastguard Worker     {
433*8975f5c5SAndroid Build Coastguard Worker         mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
434*8975f5c5SAndroid Build Coastguard Worker         mDirtyBindingBits[bindingIndex] |= dirtyBindingBits;
435*8975f5c5SAndroid Build Coastguard Worker     }
436*8975f5c5SAndroid Build Coastguard Worker }
437*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribBinding(const Context * context,size_t attribIndex,GLuint bindingIndex)438*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexAttribBinding(const Context *context,
439*8975f5c5SAndroid Build Coastguard Worker                                          size_t attribIndex,
440*8975f5c5SAndroid Build Coastguard Worker                                          GLuint bindingIndex)
441*8975f5c5SAndroid Build Coastguard Worker {
442*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
443*8975f5c5SAndroid Build Coastguard Worker 
444*8975f5c5SAndroid Build Coastguard Worker     if (mState.mVertexAttributes[attribIndex].bindingIndex == bindingIndex)
445*8975f5c5SAndroid Build Coastguard Worker     {
446*8975f5c5SAndroid Build Coastguard Worker         return;
447*8975f5c5SAndroid Build Coastguard Worker     }
448*8975f5c5SAndroid Build Coastguard Worker 
449*8975f5c5SAndroid Build Coastguard Worker     // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
450*8975f5c5SAndroid Build Coastguard Worker     ASSERT(context->getClientVersion() >= ES_3_1 && !mState.isDefault());
451*8975f5c5SAndroid Build Coastguard Worker 
452*8975f5c5SAndroid Build Coastguard Worker     mState.setAttribBinding(context, attribIndex, bindingIndex);
453*8975f5c5SAndroid Build Coastguard Worker 
454*8975f5c5SAndroid Build Coastguard Worker     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
455*8975f5c5SAndroid Build Coastguard Worker 
456*8975f5c5SAndroid Build Coastguard Worker     // Update client attribs mask.
457*8975f5c5SAndroid Build Coastguard Worker     bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
458*8975f5c5SAndroid Build Coastguard Worker     mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
459*8975f5c5SAndroid Build Coastguard Worker }
460*8975f5c5SAndroid Build Coastguard Worker 
setVertexBindingDivisor(const Context * context,size_t bindingIndex,GLuint divisor)461*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexBindingDivisor(const Context *context,
462*8975f5c5SAndroid Build Coastguard Worker                                           size_t bindingIndex,
463*8975f5c5SAndroid Build Coastguard Worker                                           GLuint divisor)
464*8975f5c5SAndroid Build Coastguard Worker {
465*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bindingIndex < getMaxBindings());
466*8975f5c5SAndroid Build Coastguard Worker 
467*8975f5c5SAndroid Build Coastguard Worker     VertexBinding &binding = mState.mVertexBindings[bindingIndex];
468*8975f5c5SAndroid Build Coastguard Worker 
469*8975f5c5SAndroid Build Coastguard Worker     if (binding.getDivisor() == divisor)
470*8975f5c5SAndroid Build Coastguard Worker     {
471*8975f5c5SAndroid Build Coastguard Worker         return;
472*8975f5c5SAndroid Build Coastguard Worker     }
473*8975f5c5SAndroid Build Coastguard Worker 
474*8975f5c5SAndroid Build Coastguard Worker     binding.setDivisor(divisor);
475*8975f5c5SAndroid Build Coastguard Worker     setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR);
476*8975f5c5SAndroid Build Coastguard Worker }
477*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribFormatImpl(VertexAttribute * attrib,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)478*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE bool VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib,
479*8975f5c5SAndroid Build Coastguard Worker                                                          GLint size,
480*8975f5c5SAndroid Build Coastguard Worker                                                          VertexAttribType type,
481*8975f5c5SAndroid Build Coastguard Worker                                                          bool normalized,
482*8975f5c5SAndroid Build Coastguard Worker                                                          bool pureInteger,
483*8975f5c5SAndroid Build Coastguard Worker                                                          GLuint relativeOffset)
484*8975f5c5SAndroid Build Coastguard Worker {
485*8975f5c5SAndroid Build Coastguard Worker     angle::FormatID formatID = GetVertexFormatID(type, normalized, size, pureInteger);
486*8975f5c5SAndroid Build Coastguard Worker 
487*8975f5c5SAndroid Build Coastguard Worker     if (formatID != attrib->format->id || attrib->relativeOffset != relativeOffset)
488*8975f5c5SAndroid Build Coastguard Worker     {
489*8975f5c5SAndroid Build Coastguard Worker         attrib->relativeOffset = relativeOffset;
490*8975f5c5SAndroid Build Coastguard Worker         attrib->format         = &angle::Format::Get(formatID);
491*8975f5c5SAndroid Build Coastguard Worker         return true;
492*8975f5c5SAndroid Build Coastguard Worker     }
493*8975f5c5SAndroid Build Coastguard Worker 
494*8975f5c5SAndroid Build Coastguard Worker     return false;
495*8975f5c5SAndroid Build Coastguard Worker }
496*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribFormat(size_t attribIndex,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)497*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexAttribFormat(size_t attribIndex,
498*8975f5c5SAndroid Build Coastguard Worker                                         GLint size,
499*8975f5c5SAndroid Build Coastguard Worker                                         VertexAttribType type,
500*8975f5c5SAndroid Build Coastguard Worker                                         bool normalized,
501*8975f5c5SAndroid Build Coastguard Worker                                         bool pureInteger,
502*8975f5c5SAndroid Build Coastguard Worker                                         GLuint relativeOffset)
503*8975f5c5SAndroid Build Coastguard Worker {
504*8975f5c5SAndroid Build Coastguard Worker     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
505*8975f5c5SAndroid Build Coastguard Worker 
506*8975f5c5SAndroid Build Coastguard Worker     ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type);
507*8975f5c5SAndroid Build Coastguard Worker     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
508*8975f5c5SAndroid Build Coastguard Worker 
509*8975f5c5SAndroid Build Coastguard Worker     if (setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, relativeOffset))
510*8975f5c5SAndroid Build Coastguard Worker     {
511*8975f5c5SAndroid Build Coastguard Worker         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT);
512*8975f5c5SAndroid Build Coastguard Worker     }
513*8975f5c5SAndroid Build Coastguard Worker 
514*8975f5c5SAndroid Build Coastguard Worker     attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]);
515*8975f5c5SAndroid Build Coastguard Worker }
516*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribDivisor(const Context * context,size_t attribIndex,GLuint divisor)517*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
518*8975f5c5SAndroid Build Coastguard Worker {
519*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < getMaxAttribs());
520*8975f5c5SAndroid Build Coastguard Worker 
521*8975f5c5SAndroid Build Coastguard Worker     setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
522*8975f5c5SAndroid Build Coastguard Worker     setVertexBindingDivisor(context, attribIndex, divisor);
523*8975f5c5SAndroid Build Coastguard Worker }
524*8975f5c5SAndroid Build Coastguard Worker 
enableAttribute(size_t attribIndex,bool enabledState)525*8975f5c5SAndroid Build Coastguard Worker void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
526*8975f5c5SAndroid Build Coastguard Worker {
527*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < getMaxAttribs());
528*8975f5c5SAndroid Build Coastguard Worker 
529*8975f5c5SAndroid Build Coastguard Worker     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
530*8975f5c5SAndroid Build Coastguard Worker 
531*8975f5c5SAndroid Build Coastguard Worker     if (mState.mEnabledAttributesMask.test(attribIndex) == enabledState)
532*8975f5c5SAndroid Build Coastguard Worker     {
533*8975f5c5SAndroid Build Coastguard Worker         return;
534*8975f5c5SAndroid Build Coastguard Worker     }
535*8975f5c5SAndroid Build Coastguard Worker 
536*8975f5c5SAndroid Build Coastguard Worker     attrib.enabled = enabledState;
537*8975f5c5SAndroid Build Coastguard Worker 
538*8975f5c5SAndroid Build Coastguard Worker     // Update state cache
539*8975f5c5SAndroid Build Coastguard Worker     mState.mEnabledAttributesMask.set(attribIndex, enabledState);
540*8975f5c5SAndroid Build Coastguard Worker     bool enableChanged = (mState.mEnabledAttributesMask.test(attribIndex) !=
541*8975f5c5SAndroid Build Coastguard Worker                           mState.mLastSyncedEnabledAttributesMask.test(attribIndex));
542*8975f5c5SAndroid Build Coastguard Worker 
543*8975f5c5SAndroid Build Coastguard Worker     if (enableChanged)
544*8975f5c5SAndroid Build Coastguard Worker     {
545*8975f5c5SAndroid Build Coastguard Worker         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED);
546*8975f5c5SAndroid Build Coastguard Worker     }
547*8975f5c5SAndroid Build Coastguard Worker     else
548*8975f5c5SAndroid Build Coastguard Worker     {
549*8975f5c5SAndroid Build Coastguard Worker         clearDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED);
550*8975f5c5SAndroid Build Coastguard Worker     }
551*8975f5c5SAndroid Build Coastguard Worker 
552*8975f5c5SAndroid Build Coastguard Worker     mState.updateCachedMutableOrNonPersistentArrayBuffers(attribIndex);
553*8975f5c5SAndroid Build Coastguard Worker     mState.mCachedInvalidMappedArrayBuffer = mState.mCachedMappedArrayBuffers &
554*8975f5c5SAndroid Build Coastguard Worker                                              mState.mEnabledAttributesMask &
555*8975f5c5SAndroid Build Coastguard Worker                                              mState.mCachedMutableOrImpersistentArrayBuffers;
556*8975f5c5SAndroid Build Coastguard Worker }
557*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribPointerImpl(const Context * context,ComponentType componentType,bool pureInteger,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)558*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context,
559*8975f5c5SAndroid Build Coastguard Worker                                                           ComponentType componentType,
560*8975f5c5SAndroid Build Coastguard Worker                                                           bool pureInteger,
561*8975f5c5SAndroid Build Coastguard Worker                                                           size_t attribIndex,
562*8975f5c5SAndroid Build Coastguard Worker                                                           Buffer *boundBuffer,
563*8975f5c5SAndroid Build Coastguard Worker                                                           GLint size,
564*8975f5c5SAndroid Build Coastguard Worker                                                           VertexAttribType type,
565*8975f5c5SAndroid Build Coastguard Worker                                                           bool normalized,
566*8975f5c5SAndroid Build Coastguard Worker                                                           GLsizei stride,
567*8975f5c5SAndroid Build Coastguard Worker                                                           const void *pointer)
568*8975f5c5SAndroid Build Coastguard Worker {
569*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attribIndex < getMaxAttribs());
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
572*8975f5c5SAndroid Build Coastguard Worker 
573*8975f5c5SAndroid Build Coastguard Worker     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
574*8975f5c5SAndroid Build Coastguard Worker 
575*8975f5c5SAndroid Build Coastguard Worker     bool attribDirty = setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, 0);
576*8975f5c5SAndroid Build Coastguard Worker 
577*8975f5c5SAndroid Build Coastguard Worker     if (attrib.bindingIndex != attribIndex)
578*8975f5c5SAndroid Build Coastguard Worker     {
579*8975f5c5SAndroid Build Coastguard Worker         setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
580*8975f5c5SAndroid Build Coastguard Worker     }
581*8975f5c5SAndroid Build Coastguard Worker 
582*8975f5c5SAndroid Build Coastguard Worker     GLsizei effectiveStride =
583*8975f5c5SAndroid Build Coastguard Worker         stride == 0 ? static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)) : stride;
584*8975f5c5SAndroid Build Coastguard Worker 
585*8975f5c5SAndroid Build Coastguard Worker     if (attrib.vertexAttribArrayStride != static_cast<GLuint>(stride))
586*8975f5c5SAndroid Build Coastguard Worker     {
587*8975f5c5SAndroid Build Coastguard Worker         attribDirty = true;
588*8975f5c5SAndroid Build Coastguard Worker     }
589*8975f5c5SAndroid Build Coastguard Worker     attrib.vertexAttribArrayStride = stride;
590*8975f5c5SAndroid Build Coastguard Worker 
591*8975f5c5SAndroid Build Coastguard Worker     // If we switch from an array buffer to a client pointer(or vice-versa), we set the whole
592*8975f5c5SAndroid Build Coastguard Worker     // attribute dirty. This notifies the Vulkan back-end to update all its caches.
593*8975f5c5SAndroid Build Coastguard Worker     const VertexBinding &binding = mState.mVertexBindings[attribIndex];
594*8975f5c5SAndroid Build Coastguard Worker     if ((boundBuffer == nullptr) != (binding.getBuffer().get() == nullptr))
595*8975f5c5SAndroid Build Coastguard Worker     {
596*8975f5c5SAndroid Build Coastguard Worker         attribDirty = true;
597*8975f5c5SAndroid Build Coastguard Worker     }
598*8975f5c5SAndroid Build Coastguard Worker 
599*8975f5c5SAndroid Build Coastguard Worker     // If using client arrays and the pointer changes, set the attribute as dirty
600*8975f5c5SAndroid Build Coastguard Worker     if (boundBuffer == nullptr && attrib.pointer != pointer)
601*8975f5c5SAndroid Build Coastguard Worker     {
602*8975f5c5SAndroid Build Coastguard Worker         attribDirty = true;
603*8975f5c5SAndroid Build Coastguard Worker     }
604*8975f5c5SAndroid Build Coastguard Worker 
605*8975f5c5SAndroid Build Coastguard Worker     // Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset
606*8975f5c5SAndroid Build Coastguard Worker     // which is handled within bindVertexBufferImpl and reflected in bufferDirty.
607*8975f5c5SAndroid Build Coastguard Worker     attrib.pointer  = pointer;
608*8975f5c5SAndroid Build Coastguard Worker     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
609*8975f5c5SAndroid Build Coastguard Worker     const VertexArray::DirtyBindingBits dirtyBindingBits =
610*8975f5c5SAndroid Build Coastguard Worker         bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
611*8975f5c5SAndroid Build Coastguard Worker 
612*8975f5c5SAndroid Build Coastguard Worker     if (attribDirty)
613*8975f5c5SAndroid Build Coastguard Worker     {
614*8975f5c5SAndroid Build Coastguard Worker         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
615*8975f5c5SAndroid Build Coastguard Worker     }
616*8975f5c5SAndroid Build Coastguard Worker     else if (dirtyBindingBits.any())
617*8975f5c5SAndroid Build Coastguard Worker     {
618*8975f5c5SAndroid Build Coastguard Worker         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
619*8975f5c5SAndroid Build Coastguard Worker     }
620*8975f5c5SAndroid Build Coastguard Worker 
621*8975f5c5SAndroid Build Coastguard Worker     mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
622*8975f5c5SAndroid Build Coastguard Worker                                                    boundBuffer == nullptr && pointer == nullptr);
623*8975f5c5SAndroid Build Coastguard Worker }
624*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribPointer(const Context * context,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)625*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexAttribPointer(const Context *context,
626*8975f5c5SAndroid Build Coastguard Worker                                          size_t attribIndex,
627*8975f5c5SAndroid Build Coastguard Worker                                          Buffer *boundBuffer,
628*8975f5c5SAndroid Build Coastguard Worker                                          GLint size,
629*8975f5c5SAndroid Build Coastguard Worker                                          VertexAttribType type,
630*8975f5c5SAndroid Build Coastguard Worker                                          bool normalized,
631*8975f5c5SAndroid Build Coastguard Worker                                          GLsizei stride,
632*8975f5c5SAndroid Build Coastguard Worker                                          const void *pointer)
633*8975f5c5SAndroid Build Coastguard Worker {
634*8975f5c5SAndroid Build Coastguard Worker     setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size,
635*8975f5c5SAndroid Build Coastguard Worker                                type, normalized, stride, pointer);
636*8975f5c5SAndroid Build Coastguard Worker }
637*8975f5c5SAndroid Build Coastguard Worker 
setVertexAttribIPointer(const Context * context,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,GLsizei stride,const void * pointer)638*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setVertexAttribIPointer(const Context *context,
639*8975f5c5SAndroid Build Coastguard Worker                                           size_t attribIndex,
640*8975f5c5SAndroid Build Coastguard Worker                                           Buffer *boundBuffer,
641*8975f5c5SAndroid Build Coastguard Worker                                           GLint size,
642*8975f5c5SAndroid Build Coastguard Worker                                           VertexAttribType type,
643*8975f5c5SAndroid Build Coastguard Worker                                           GLsizei stride,
644*8975f5c5SAndroid Build Coastguard Worker                                           const void *pointer)
645*8975f5c5SAndroid Build Coastguard Worker {
646*8975f5c5SAndroid Build Coastguard Worker     ComponentType componentType = GetVertexAttributeComponentType(true, type);
647*8975f5c5SAndroid Build Coastguard Worker     setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type,
648*8975f5c5SAndroid Build Coastguard Worker                                false, stride, pointer);
649*8975f5c5SAndroid Build Coastguard Worker }
650*8975f5c5SAndroid Build Coastguard Worker 
syncState(const Context * context)651*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArray::syncState(const Context *context)
652*8975f5c5SAndroid Build Coastguard Worker {
653*8975f5c5SAndroid Build Coastguard Worker     if (mDirtyBits.any())
654*8975f5c5SAndroid Build Coastguard Worker     {
655*8975f5c5SAndroid Build Coastguard Worker         mDirtyBitsGuard = mDirtyBits;
656*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(
657*8975f5c5SAndroid Build Coastguard Worker             mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits));
658*8975f5c5SAndroid Build Coastguard Worker         mDirtyBits.reset();
659*8975f5c5SAndroid Build Coastguard Worker         mDirtyBitsGuard.reset();
660*8975f5c5SAndroid Build Coastguard Worker 
661*8975f5c5SAndroid Build Coastguard Worker         // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
662*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mDirtyAttribBits[0].none());
663*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mDirtyBindingBits[0].none());
664*8975f5c5SAndroid Build Coastguard Worker         mState.mLastSyncedEnabledAttributesMask = mState.mEnabledAttributesMask;
665*8975f5c5SAndroid Build Coastguard Worker     }
666*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
667*8975f5c5SAndroid Build Coastguard Worker }
668*8975f5c5SAndroid Build Coastguard Worker 
669*8975f5c5SAndroid Build Coastguard Worker // This becomes current vertex array on the context
onBind(const Context * context)670*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onBind(const Context *context)
671*8975f5c5SAndroid Build Coastguard Worker {
672*8975f5c5SAndroid Build Coastguard Worker     // This vertex array becoming current. Some of the bindings we may have removed from buffer's
673*8975f5c5SAndroid Build Coastguard Worker     // observer list. We need to add it back to the buffer's observer list and update dirty bits
674*8975f5c5SAndroid Build Coastguard Worker     // that we may have missed while we were not observing.
675*8975f5c5SAndroid Build Coastguard Worker     for (size_t bindingIndex : mState.getBufferBindingMask())
676*8975f5c5SAndroid Build Coastguard Worker     {
677*8975f5c5SAndroid Build Coastguard Worker         const VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
678*8975f5c5SAndroid Build Coastguard Worker         Buffer *bufferGL             = binding.getBuffer().get();
679*8975f5c5SAndroid Build Coastguard Worker         ASSERT(bufferGL != nullptr);
680*8975f5c5SAndroid Build Coastguard Worker 
681*8975f5c5SAndroid Build Coastguard Worker         bufferGL->addObserver(&mArrayBufferObserverBindings[bindingIndex]);
682*8975f5c5SAndroid Build Coastguard Worker         updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[bindingIndex]);
683*8975f5c5SAndroid Build Coastguard Worker 
684*8975f5c5SAndroid Build Coastguard Worker         if (mBufferAccessValidationEnabled)
685*8975f5c5SAndroid Build Coastguard Worker         {
686*8975f5c5SAndroid Build Coastguard Worker             for (size_t boundAttribute :
687*8975f5c5SAndroid Build Coastguard Worker                  mState.mVertexBindings[bindingIndex].getBoundAttributesMask())
688*8975f5c5SAndroid Build Coastguard Worker             {
689*8975f5c5SAndroid Build Coastguard Worker                 mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(
690*8975f5c5SAndroid Build Coastguard Worker                     mState.mVertexBindings[bindingIndex]);
691*8975f5c5SAndroid Build Coastguard Worker             }
692*8975f5c5SAndroid Build Coastguard Worker         }
693*8975f5c5SAndroid Build Coastguard Worker 
694*8975f5c5SAndroid Build Coastguard Worker         if (context->isWebGL())
695*8975f5c5SAndroid Build Coastguard Worker         {
696*8975f5c5SAndroid Build Coastguard Worker             updateCachedTransformFeedbackBindingValidation(bindingIndex, bufferGL);
697*8975f5c5SAndroid Build Coastguard Worker         }
698*8975f5c5SAndroid Build Coastguard Worker     }
699*8975f5c5SAndroid Build Coastguard Worker 
700*8975f5c5SAndroid Build Coastguard Worker     mDirtyBits.set(DIRTY_BIT_LOST_OBSERVATION);
701*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::ContentsChanged);
702*8975f5c5SAndroid Build Coastguard Worker }
703*8975f5c5SAndroid Build Coastguard Worker 
704*8975f5c5SAndroid Build Coastguard Worker // This becomes non-current vertex array on the context
onUnbind(const Context * context)705*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onUnbind(const Context *context)
706*8975f5c5SAndroid Build Coastguard Worker {
707*8975f5c5SAndroid Build Coastguard Worker     // This vertex array becoming non-current. For performance reason, we remove it from the
708*8975f5c5SAndroid Build Coastguard Worker     // buffers' observer list so that the cost of buffer sending signal to observers will not be too
709*8975f5c5SAndroid Build Coastguard Worker     // expensive.
710*8975f5c5SAndroid Build Coastguard Worker     for (size_t bindingIndex : mState.mBufferBindingMask)
711*8975f5c5SAndroid Build Coastguard Worker     {
712*8975f5c5SAndroid Build Coastguard Worker         const VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
713*8975f5c5SAndroid Build Coastguard Worker         Buffer *bufferGL             = binding.getBuffer().get();
714*8975f5c5SAndroid Build Coastguard Worker         ASSERT(bufferGL != nullptr);
715*8975f5c5SAndroid Build Coastguard Worker         bufferGL->removeObserver(&mArrayBufferObserverBindings[bindingIndex]);
716*8975f5c5SAndroid Build Coastguard Worker     }
717*8975f5c5SAndroid Build Coastguard Worker }
718*8975f5c5SAndroid Build Coastguard Worker 
onBindingChanged(const Context * context,int incr)719*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onBindingChanged(const Context *context, int incr)
720*8975f5c5SAndroid Build Coastguard Worker {
721*8975f5c5SAndroid Build Coastguard Worker     // When vertex array gets unbound, we remove it from bound buffers' observer list so that when
722*8975f5c5SAndroid Build Coastguard Worker     // buffer changes, it wont has to loop over all these non-current vertex arrays and set dirty
723*8975f5c5SAndroid Build Coastguard Worker     // bit on them. To compensate for that, when we bind a vertex array, we have to check against
724*8975f5c5SAndroid Build Coastguard Worker     // each bound buffers and see if they have changed and needs to update vertex array's dirty bits
725*8975f5c5SAndroid Build Coastguard Worker     // accordingly
726*8975f5c5SAndroid Build Coastguard Worker     ASSERT(incr == 1 || incr == -1);
727*8975f5c5SAndroid Build Coastguard Worker     if (incr < 0)
728*8975f5c5SAndroid Build Coastguard Worker     {
729*8975f5c5SAndroid Build Coastguard Worker         onUnbind(context);
730*8975f5c5SAndroid Build Coastguard Worker     }
731*8975f5c5SAndroid Build Coastguard Worker     else
732*8975f5c5SAndroid Build Coastguard Worker     {
733*8975f5c5SAndroid Build Coastguard Worker         onBind(context);
734*8975f5c5SAndroid Build Coastguard Worker     }
735*8975f5c5SAndroid Build Coastguard Worker 
736*8975f5c5SAndroid Build Coastguard Worker     if (context->isWebGL())
737*8975f5c5SAndroid Build Coastguard Worker     {
738*8975f5c5SAndroid Build Coastguard Worker         if (mState.mElementArrayBuffer.get())
739*8975f5c5SAndroid Build Coastguard Worker         {
740*8975f5c5SAndroid Build Coastguard Worker             mState.mElementArrayBuffer->onNonTFBindingChanged(incr);
741*8975f5c5SAndroid Build Coastguard Worker         }
742*8975f5c5SAndroid Build Coastguard Worker         for (size_t bindingIndex : mState.mBufferBindingMask)
743*8975f5c5SAndroid Build Coastguard Worker         {
744*8975f5c5SAndroid Build Coastguard Worker             mState.mVertexBindings[bindingIndex].onContainerBindingChanged(context, incr);
745*8975f5c5SAndroid Build Coastguard Worker         }
746*8975f5c5SAndroid Build Coastguard Worker     }
747*8975f5c5SAndroid Build Coastguard Worker }
748*8975f5c5SAndroid Build Coastguard Worker 
getDirtyBitFromIndex(bool contentsChanged,angle::SubjectIndex index) const749*8975f5c5SAndroid Build Coastguard Worker VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
750*8975f5c5SAndroid Build Coastguard Worker                                                             angle::SubjectIndex index) const
751*8975f5c5SAndroid Build Coastguard Worker {
752*8975f5c5SAndroid Build Coastguard Worker     if (IsElementArrayBufferSubjectIndex(index))
753*8975f5c5SAndroid Build Coastguard Worker     {
754*8975f5c5SAndroid Build Coastguard Worker         mIndexRangeCache.invalidate();
755*8975f5c5SAndroid Build Coastguard Worker         return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
756*8975f5c5SAndroid Build Coastguard Worker                                : DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
757*8975f5c5SAndroid Build Coastguard Worker     }
758*8975f5c5SAndroid Build Coastguard Worker     else
759*8975f5c5SAndroid Build Coastguard Worker     {
760*8975f5c5SAndroid Build Coastguard Worker         // Note: this currently just gets the top-level dirty bit.
761*8975f5c5SAndroid Build Coastguard Worker         ASSERT(index < mArrayBufferObserverBindings.size());
762*8975f5c5SAndroid Build Coastguard Worker         return static_cast<DirtyBitType>(
763*8975f5c5SAndroid Build Coastguard Worker             (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
764*8975f5c5SAndroid Build Coastguard Worker     }
765*8975f5c5SAndroid Build Coastguard Worker }
766*8975f5c5SAndroid Build Coastguard Worker 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)767*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
768*8975f5c5SAndroid Build Coastguard Worker {
769*8975f5c5SAndroid Build Coastguard Worker     switch (message)
770*8975f5c5SAndroid Build Coastguard Worker     {
771*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::SubjectChanged:
772*8975f5c5SAndroid Build Coastguard Worker             if (!IsElementArrayBufferSubjectIndex(index))
773*8975f5c5SAndroid Build Coastguard Worker             {
774*8975f5c5SAndroid Build Coastguard Worker                 updateCachedBufferBindingSize(&mState.mVertexBindings[index]);
775*8975f5c5SAndroid Build Coastguard Worker             }
776*8975f5c5SAndroid Build Coastguard Worker             setDependentDirtyBit(false, index);
777*8975f5c5SAndroid Build Coastguard Worker             break;
778*8975f5c5SAndroid Build Coastguard Worker 
779*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::BindingChanged:
780*8975f5c5SAndroid Build Coastguard Worker             if (!IsElementArrayBufferSubjectIndex(index))
781*8975f5c5SAndroid Build Coastguard Worker             {
782*8975f5c5SAndroid Build Coastguard Worker                 const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get();
783*8975f5c5SAndroid Build Coastguard Worker                 updateCachedTransformFeedbackBindingValidation(index, buffer);
784*8975f5c5SAndroid Build Coastguard Worker             }
785*8975f5c5SAndroid Build Coastguard Worker             break;
786*8975f5c5SAndroid Build Coastguard Worker 
787*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::SubjectMapped:
788*8975f5c5SAndroid Build Coastguard Worker             if (!IsElementArrayBufferSubjectIndex(index))
789*8975f5c5SAndroid Build Coastguard Worker             {
790*8975f5c5SAndroid Build Coastguard Worker                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
791*8975f5c5SAndroid Build Coastguard Worker             }
792*8975f5c5SAndroid Build Coastguard Worker             onStateChange(angle::SubjectMessage::SubjectMapped);
793*8975f5c5SAndroid Build Coastguard Worker             break;
794*8975f5c5SAndroid Build Coastguard Worker 
795*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::SubjectUnmapped:
796*8975f5c5SAndroid Build Coastguard Worker             setDependentDirtyBit(true, index);
797*8975f5c5SAndroid Build Coastguard Worker 
798*8975f5c5SAndroid Build Coastguard Worker             if (!IsElementArrayBufferSubjectIndex(index))
799*8975f5c5SAndroid Build Coastguard Worker             {
800*8975f5c5SAndroid Build Coastguard Worker                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
801*8975f5c5SAndroid Build Coastguard Worker             }
802*8975f5c5SAndroid Build Coastguard Worker             onStateChange(angle::SubjectMessage::SubjectUnmapped);
803*8975f5c5SAndroid Build Coastguard Worker             break;
804*8975f5c5SAndroid Build Coastguard Worker 
805*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::InternalMemoryAllocationChanged:
806*8975f5c5SAndroid Build Coastguard Worker             setDependentDirtyBit(false, index);
807*8975f5c5SAndroid Build Coastguard Worker             break;
808*8975f5c5SAndroid Build Coastguard Worker 
809*8975f5c5SAndroid Build Coastguard Worker         default:
810*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
811*8975f5c5SAndroid Build Coastguard Worker             break;
812*8975f5c5SAndroid Build Coastguard Worker     }
813*8975f5c5SAndroid Build Coastguard Worker }
814*8975f5c5SAndroid Build Coastguard Worker 
setDependentDirtyBit(bool contentsChanged,angle::SubjectIndex index)815*8975f5c5SAndroid Build Coastguard Worker void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index)
816*8975f5c5SAndroid Build Coastguard Worker {
817*8975f5c5SAndroid Build Coastguard Worker     DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
818*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
819*8975f5c5SAndroid Build Coastguard Worker     mDirtyBits.set(dirtyBit);
820*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::ContentsChanged);
821*8975f5c5SAndroid Build Coastguard Worker }
822*8975f5c5SAndroid Build Coastguard Worker 
hasTransformFeedbackBindingConflict(const Context * context) const823*8975f5c5SAndroid Build Coastguard Worker bool VertexArray::hasTransformFeedbackBindingConflict(const Context *context) const
824*8975f5c5SAndroid Build Coastguard Worker {
825*8975f5c5SAndroid Build Coastguard Worker     // Fast check first.
826*8975f5c5SAndroid Build Coastguard Worker     if (!mCachedTransformFeedbackConflictedBindingsMask.any())
827*8975f5c5SAndroid Build Coastguard Worker     {
828*8975f5c5SAndroid Build Coastguard Worker         return false;
829*8975f5c5SAndroid Build Coastguard Worker     }
830*8975f5c5SAndroid Build Coastguard Worker 
831*8975f5c5SAndroid Build Coastguard Worker     const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask();
832*8975f5c5SAndroid Build Coastguard Worker 
833*8975f5c5SAndroid Build Coastguard Worker     // Slow check. We must ensure that the conflicting attributes are enabled/active.
834*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : activeAttribues)
835*8975f5c5SAndroid Build Coastguard Worker     {
836*8975f5c5SAndroid Build Coastguard Worker         const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
837*8975f5c5SAndroid Build Coastguard Worker         if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex])
838*8975f5c5SAndroid Build Coastguard Worker         {
839*8975f5c5SAndroid Build Coastguard Worker             return true;
840*8975f5c5SAndroid Build Coastguard Worker         }
841*8975f5c5SAndroid Build Coastguard Worker     }
842*8975f5c5SAndroid Build Coastguard Worker 
843*8975f5c5SAndroid Build Coastguard Worker     return false;
844*8975f5c5SAndroid Build Coastguard Worker }
845*8975f5c5SAndroid Build Coastguard Worker 
getIndexRangeImpl(const Context * context,DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut) const846*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArray::getIndexRangeImpl(const Context *context,
847*8975f5c5SAndroid Build Coastguard Worker                                              DrawElementsType type,
848*8975f5c5SAndroid Build Coastguard Worker                                              GLsizei indexCount,
849*8975f5c5SAndroid Build Coastguard Worker                                              const void *indices,
850*8975f5c5SAndroid Build Coastguard Worker                                              IndexRange *indexRangeOut) const
851*8975f5c5SAndroid Build Coastguard Worker {
852*8975f5c5SAndroid Build Coastguard Worker     Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get();
853*8975f5c5SAndroid Build Coastguard Worker     if (!elementArrayBuffer)
854*8975f5c5SAndroid Build Coastguard Worker     {
855*8975f5c5SAndroid Build Coastguard Worker         *indexRangeOut = ComputeIndexRange(type, indices, indexCount,
856*8975f5c5SAndroid Build Coastguard Worker                                            context->getState().isPrimitiveRestartEnabled());
857*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
858*8975f5c5SAndroid Build Coastguard Worker     }
859*8975f5c5SAndroid Build Coastguard Worker 
860*8975f5c5SAndroid Build Coastguard Worker     size_t offset = reinterpret_cast<uintptr_t>(indices);
861*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount,
862*8975f5c5SAndroid Build Coastguard Worker                                                 context->getState().isPrimitiveRestartEnabled(),
863*8975f5c5SAndroid Build Coastguard Worker                                                 indexRangeOut));
864*8975f5c5SAndroid Build Coastguard Worker 
865*8975f5c5SAndroid Build Coastguard Worker     mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut);
866*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
867*8975f5c5SAndroid Build Coastguard Worker }
868*8975f5c5SAndroid Build Coastguard Worker 
869*8975f5c5SAndroid Build Coastguard Worker VertexArray::IndexRangeCache::IndexRangeCache() = default;
870*8975f5c5SAndroid Build Coastguard Worker 
put(DrawElementsType type,GLsizei indexCount,size_t offset,const IndexRange & indexRange)871*8975f5c5SAndroid Build Coastguard Worker void VertexArray::IndexRangeCache::put(DrawElementsType type,
872*8975f5c5SAndroid Build Coastguard Worker                                        GLsizei indexCount,
873*8975f5c5SAndroid Build Coastguard Worker                                        size_t offset,
874*8975f5c5SAndroid Build Coastguard Worker                                        const IndexRange &indexRange)
875*8975f5c5SAndroid Build Coastguard Worker {
876*8975f5c5SAndroid Build Coastguard Worker     ASSERT(type != DrawElementsType::InvalidEnum);
877*8975f5c5SAndroid Build Coastguard Worker 
878*8975f5c5SAndroid Build Coastguard Worker     mTypeKey       = type;
879*8975f5c5SAndroid Build Coastguard Worker     mIndexCountKey = indexCount;
880*8975f5c5SAndroid Build Coastguard Worker     mOffsetKey     = offset;
881*8975f5c5SAndroid Build Coastguard Worker     mPayload       = indexRange;
882*8975f5c5SAndroid Build Coastguard Worker }
883*8975f5c5SAndroid Build Coastguard Worker 
onBufferContentsChange(uint32_t bufferIndex)884*8975f5c5SAndroid Build Coastguard Worker void VertexArray::onBufferContentsChange(uint32_t bufferIndex)
885*8975f5c5SAndroid Build Coastguard Worker {
886*8975f5c5SAndroid Build Coastguard Worker     setDependentDirtyBit(true, bufferIndex);
887*8975f5c5SAndroid Build Coastguard Worker }
888*8975f5c5SAndroid Build Coastguard Worker 
VertexArrayBufferContentsObservers(VertexArray * vertexArray)889*8975f5c5SAndroid Build Coastguard Worker VertexArrayBufferContentsObservers::VertexArrayBufferContentsObservers(VertexArray *vertexArray)
890*8975f5c5SAndroid Build Coastguard Worker     : mVertexArray(vertexArray)
891*8975f5c5SAndroid Build Coastguard Worker {}
892*8975f5c5SAndroid Build Coastguard Worker 
enableForBuffer(Buffer * buffer,uint32_t attribIndex)893*8975f5c5SAndroid Build Coastguard Worker void VertexArrayBufferContentsObservers::enableForBuffer(Buffer *buffer, uint32_t attribIndex)
894*8975f5c5SAndroid Build Coastguard Worker {
895*8975f5c5SAndroid Build Coastguard Worker     buffer->addContentsObserver(mVertexArray, attribIndex);
896*8975f5c5SAndroid Build Coastguard Worker     mBufferObserversBitMask.set(attribIndex);
897*8975f5c5SAndroid Build Coastguard Worker }
898*8975f5c5SAndroid Build Coastguard Worker 
disableForBuffer(Buffer * buffer,uint32_t attribIndex)899*8975f5c5SAndroid Build Coastguard Worker void VertexArrayBufferContentsObservers::disableForBuffer(Buffer *buffer, uint32_t attribIndex)
900*8975f5c5SAndroid Build Coastguard Worker {
901*8975f5c5SAndroid Build Coastguard Worker     if (mBufferObserversBitMask.test(attribIndex))
902*8975f5c5SAndroid Build Coastguard Worker     {
903*8975f5c5SAndroid Build Coastguard Worker         buffer->removeContentsObserver(mVertexArray, attribIndex);
904*8975f5c5SAndroid Build Coastguard Worker         mBufferObserversBitMask.reset(attribIndex);
905*8975f5c5SAndroid Build Coastguard Worker     }
906*8975f5c5SAndroid Build Coastguard Worker }
907*8975f5c5SAndroid Build Coastguard Worker }  // namespace gl
908