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