• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     : 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 
107 // VertexArray implementation.
VertexArray(rx::GLImplFactory * factory,VertexArrayID id,size_t maxAttribs,size_t maxAttribBindings)108 VertexArray::VertexArray(rx::GLImplFactory *factory,
109                          VertexArrayID id,
110                          size_t maxAttribs,
111                          size_t maxAttribBindings)
112     : mId(id),
113       mState(this, maxAttribs, maxAttribBindings),
114       mVertexArray(factory->createVertexArray(mState)),
115       mBufferAccessValidationEnabled(false),
116       mContentsObservers(this)
117 {
118     for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
119     {
120         mArrayBufferObserverBindings.emplace_back(this, attribIndex);
121     }
122 
123     mVertexArray->setContentsObservers(&mContentsObservers);
124 }
125 
onDestroy(const Context * context)126 void VertexArray::onDestroy(const Context *context)
127 {
128     bool isBound = context->isCurrentVertexArray(this);
129     for (size_t bindingIndex : mState.mBufferBindingMask)
130     {
131         VertexBinding &binding = mState.mVertexBindings[bindingIndex];
132         Buffer *buffer         = binding.getBuffer().get();
133         ASSERT(buffer != nullptr);
134         if (isBound)
135         {
136             buffer->onNonTFBindingChanged(-1);
137         }
138         else
139         {
140             // un-assigning to avoid assertion, since it was already removed from buffer's observer
141             // list.
142             mArrayBufferObserverBindings[bindingIndex].assignSubject(nullptr);
143         }
144         // Note: the non-contents observer is unbound in the ObserverBinding destructor.
145         buffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
146         binding.setBuffer(context, nullptr);
147     }
148     mState.mBufferBindingMask.reset();
149 
150     if (mState.mElementArrayBuffer.get())
151     {
152         if (isBound)
153         {
154             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
155         }
156         mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex);
157     }
158     mState.mElementArrayBuffer.bind(context, nullptr);
159 
160     mVertexArray->destroy(context);
161     SafeDelete(mVertexArray);
162     delete this;
163 }
164 
~VertexArray()165 VertexArray::~VertexArray()
166 {
167     ASSERT(!mVertexArray);
168 }
169 
setLabel(const Context * context,const std::string & label)170 angle::Result VertexArray::setLabel(const Context *context, const std::string &label)
171 {
172     mState.mLabel = label;
173 
174     if (mVertexArray)
175     {
176         return mVertexArray->onLabelUpdate(context);
177     }
178     return angle::Result::Continue;
179 }
180 
getLabel() const181 const std::string &VertexArray::getLabel() const
182 {
183     return mState.mLabel;
184 }
185 
detachBuffer(const Context * context,BufferID bufferID)186 bool VertexArray::detachBuffer(const Context *context, BufferID bufferID)
187 {
188     bool isBound           = context->isCurrentVertexArray(this);
189     bool anyBufferDetached = false;
190     for (size_t bindingIndex : mState.mBufferBindingMask)
191     {
192         VertexBinding &binding                      = mState.mVertexBindings[bindingIndex];
193         const BindingPointer<Buffer> &bufferBinding = binding.getBuffer();
194         if (bufferBinding.id() == bufferID)
195         {
196             if (isBound)
197             {
198                 if (bufferBinding.get())
199                     bufferBinding->onNonTFBindingChanged(-1);
200             }
201             bufferBinding->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
202             binding.setBuffer(context, nullptr);
203             mArrayBufferObserverBindings[bindingIndex].reset();
204             mState.mBufferBindingMask.reset(bindingIndex);
205 
206             if (context->getClientVersion() >= ES_3_1)
207             {
208                 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
209             }
210             else
211             {
212                 static_assert(MAX_VERTEX_ATTRIB_BINDINGS < 8 * sizeof(uint32_t),
213                               "Not enough bits in bindingIndex");
214                 // The redundant uint32_t cast here is required to avoid a warning on MSVC.
215                 ASSERT(binding.getBoundAttributesMask() ==
216                        AttributesMask(static_cast<uint32_t>(1 << bindingIndex)));
217                 setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER);
218             }
219 
220             anyBufferDetached = true;
221             mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask();
222         }
223     }
224 
225     if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferID)
226     {
227         if (isBound && mState.mElementArrayBuffer.get())
228             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
229         mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex);
230         mState.mElementArrayBuffer.bind(context, nullptr);
231         mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
232         anyBufferDetached = true;
233     }
234 
235     return anyBufferDetached;
236 }
237 
getVertexAttribute(size_t attribIndex) const238 const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
239 {
240     ASSERT(attribIndex < getMaxAttribs());
241     return mState.mVertexAttributes[attribIndex];
242 }
243 
getVertexBinding(size_t bindingIndex) const244 const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
245 {
246     ASSERT(bindingIndex < getMaxBindings());
247     return mState.mVertexBindings[bindingIndex];
248 }
249 
GetVertexIndexFromDirtyBit(size_t dirtyBit)250 size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
251 {
252     static_assert(MAX_VERTEX_ATTRIBS == MAX_VERTEX_ATTRIB_BINDINGS,
253                   "The stride of vertex attributes should equal to that of vertex bindings.");
254     ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
255     return (dirtyBit - DIRTY_BIT_ATTRIB_0) % MAX_VERTEX_ATTRIBS;
256 }
257 
setDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)258 ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex,
259                                                  DirtyAttribBitType dirtyAttribBit)
260 {
261     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
262     mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
263 }
264 
clearDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)265 ANGLE_INLINE void VertexArray::clearDirtyAttribBit(size_t attribIndex,
266                                                    DirtyAttribBitType dirtyAttribBit)
267 {
268     mDirtyAttribBits[attribIndex].set(dirtyAttribBit, false);
269     if (mDirtyAttribBits[attribIndex].any())
270     {
271         return;
272     }
273     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex, false);
274 }
275 
setDirtyBindingBit(size_t bindingIndex,DirtyBindingBitType dirtyBindingBit)276 ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex,
277                                                   DirtyBindingBitType dirtyBindingBit)
278 {
279     mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
280     mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
281 }
282 
updateCachedBufferBindingSize(VertexBinding * binding)283 ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
284 {
285     if (!mBufferAccessValidationEnabled)
286         return;
287 
288     for (size_t boundAttribute : binding->getBoundAttributesMask())
289     {
290         mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
291     }
292 }
293 
updateCachedArrayBuffersMasks(bool isMapped,bool isImmutable,bool isPersistent,const AttributesMask & boundAttributesMask)294 ANGLE_INLINE void VertexArray::updateCachedArrayBuffersMasks(
295     bool isMapped,
296     bool isImmutable,
297     bool isPersistent,
298     const AttributesMask &boundAttributesMask)
299 {
300     if (isMapped)
301     {
302         mState.mCachedMappedArrayBuffers |= boundAttributesMask;
303     }
304     else
305     {
306         mState.mCachedMappedArrayBuffers &= ~boundAttributesMask;
307     }
308 
309     if (!isImmutable || !isPersistent)
310     {
311         mState.mCachedMutableOrImpersistentArrayBuffers |= boundAttributesMask;
312     }
313     else
314     {
315         mState.mCachedMutableOrImpersistentArrayBuffers &= ~boundAttributesMask;
316     }
317 
318     mState.mCachedInvalidMappedArrayBuffer = mState.mCachedMappedArrayBuffers &
319                                              mState.mEnabledAttributesMask &
320                                              mState.mCachedMutableOrImpersistentArrayBuffers;
321 }
322 
updateCachedMappedArrayBuffersBinding(const VertexBinding & binding)323 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding)
324 {
325     const Buffer *buffer = binding.getBuffer().get();
326     bool isMapped        = buffer && buffer->isMapped();
327     bool isImmutable     = buffer && buffer->isImmutable();
328     bool isPersistent    = buffer && (buffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0;
329     return updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent,
330                                          binding.getBoundAttributesMask());
331 }
332 
updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,const Buffer * buffer)333 ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
334                                                                               const Buffer *buffer)
335 {
336     const bool hasConflict = buffer && buffer->hasWebGLXFBBindingConflict(true);
337     mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
338 }
339 
bindVertexBufferImpl(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)340 VertexArray::DirtyBindingBits VertexArray::bindVertexBufferImpl(const Context *context,
341                                                                 size_t bindingIndex,
342                                                                 Buffer *boundBuffer,
343                                                                 GLintptr offset,
344                                                                 GLsizei stride)
345 {
346     ASSERT(bindingIndex < getMaxBindings());
347     ASSERT(context->isCurrentVertexArray(this));
348 
349     VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
350 
351     Buffer *oldBuffer = binding->getBuffer().get();
352 
353     DirtyBindingBits dirtyBindingBits;
354     dirtyBindingBits.set(DIRTY_BINDING_BUFFER, oldBuffer != boundBuffer);
355     dirtyBindingBits.set(DIRTY_BINDING_STRIDE, static_cast<GLuint>(stride) != binding->getStride());
356     dirtyBindingBits.set(DIRTY_BINDING_OFFSET, offset != binding->getOffset());
357 
358     if (dirtyBindingBits.none())
359     {
360         return dirtyBindingBits;
361     }
362 
363     angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
364     observer->assignSubject(boundBuffer);
365 
366     // Several nullptr checks are combined here for optimization purposes.
367     if (oldBuffer)
368     {
369         oldBuffer->onNonTFBindingChanged(-1);
370         oldBuffer->removeObserver(observer);
371         oldBuffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex));
372         oldBuffer->release(context);
373         mState.mBufferBindingMask.reset(bindingIndex);
374     }
375 
376     binding->assignBuffer(boundBuffer);
377     binding->setOffset(offset);
378     binding->setStride(stride);
379     updateCachedBufferBindingSize(binding);
380 
381     // Update client memory attribute pointers. Affects all bound attributes.
382     if (boundBuffer)
383     {
384         boundBuffer->addRef();
385         boundBuffer->onNonTFBindingChanged(1);
386         boundBuffer->addObserver(observer);
387         if (context->isWebGL())
388         {
389             mCachedTransformFeedbackConflictedBindingsMask.set(
390                 bindingIndex, boundBuffer->hasWebGLXFBBindingConflict(true));
391         }
392         mState.mBufferBindingMask.set(bindingIndex);
393         mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask();
394 
395         bool isMapped     = boundBuffer->isMapped() == GL_TRUE;
396         bool isImmutable  = boundBuffer->isImmutable() == GL_TRUE;
397         bool isPersistent = (boundBuffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0;
398         updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent,
399                                       binding->getBoundAttributesMask());
400     }
401     else
402     {
403         if (context->isWebGL())
404         {
405             mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false);
406         }
407         mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask();
408         updateCachedArrayBuffersMasks(false, false, false, binding->getBoundAttributesMask());
409     }
410 
411     return dirtyBindingBits;
412 }
413 
bindVertexBuffer(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)414 void VertexArray::bindVertexBuffer(const Context *context,
415                                    size_t bindingIndex,
416                                    Buffer *boundBuffer,
417                                    GLintptr offset,
418                                    GLsizei stride)
419 {
420     const VertexArray::DirtyBindingBits dirtyBindingBits =
421         bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride);
422     if (dirtyBindingBits.any())
423     {
424         mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
425         mDirtyBindingBits[bindingIndex] |= dirtyBindingBits;
426     }
427 }
428 
setVertexAttribBinding(const Context * context,size_t attribIndex,GLuint bindingIndex)429 void VertexArray::setVertexAttribBinding(const Context *context,
430                                          size_t attribIndex,
431                                          GLuint bindingIndex)
432 {
433     ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
434 
435     if (mState.mVertexAttributes[attribIndex].bindingIndex == bindingIndex)
436     {
437         return;
438     }
439 
440     // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
441     ASSERT(context->getClientVersion() >= ES_3_1);
442 
443     mState.setAttribBinding(context, attribIndex, bindingIndex);
444 
445     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
446 
447     // Update client attribs mask.
448     bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
449     mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
450 }
451 
setVertexBindingDivisor(const Context * context,size_t bindingIndex,GLuint divisor)452 void VertexArray::setVertexBindingDivisor(const Context *context,
453                                           size_t bindingIndex,
454                                           GLuint divisor)
455 {
456     ASSERT(bindingIndex < getMaxBindings());
457 
458     VertexBinding &binding = mState.mVertexBindings[bindingIndex];
459 
460     if (binding.getDivisor() == divisor)
461     {
462         return;
463     }
464 
465     binding.setDivisor(divisor);
466     setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR);
467 
468     // Trigger updates in all bound attributes.
469     if (context->isBufferAccessValidationEnabled())
470     {
471         for (size_t attribIndex : binding.getBoundAttributesMask())
472         {
473             mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding);
474         }
475     }
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     // Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset
600     // which is handled within bindVertexBufferImpl and reflected in bufferDirty.
601     attrib.pointer  = pointer;
602     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
603     const VertexArray::DirtyBindingBits dirtyBindingBits =
604         bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
605 
606     if (attribDirty)
607     {
608         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
609     }
610     else if (dirtyBindingBits.any())
611     {
612         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
613     }
614 
615     mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
616                                                    boundBuffer == nullptr && pointer == nullptr);
617 }
618 
setVertexAttribPointer(const Context * context,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)619 void VertexArray::setVertexAttribPointer(const Context *context,
620                                          size_t attribIndex,
621                                          Buffer *boundBuffer,
622                                          GLint size,
623                                          VertexAttribType type,
624                                          bool normalized,
625                                          GLsizei stride,
626                                          const void *pointer)
627 {
628     setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size,
629                                type, normalized, stride, pointer);
630 }
631 
setVertexAttribIPointer(const Context * context,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,GLsizei stride,const void * pointer)632 void VertexArray::setVertexAttribIPointer(const Context *context,
633                                           size_t attribIndex,
634                                           Buffer *boundBuffer,
635                                           GLint size,
636                                           VertexAttribType type,
637                                           GLsizei stride,
638                                           const void *pointer)
639 {
640     ComponentType componentType = GetVertexAttributeComponentType(true, type);
641     setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type,
642                                false, stride, pointer);
643 }
644 
syncState(const Context * context)645 angle::Result VertexArray::syncState(const Context *context)
646 {
647     if (mDirtyBits.any())
648     {
649         mDirtyBitsGuard = mDirtyBits;
650         ANGLE_TRY(
651             mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits));
652         mDirtyBits.reset();
653         mDirtyBitsGuard.reset();
654 
655         // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
656         ASSERT(mDirtyAttribBits[0].none());
657         ASSERT(mDirtyBindingBits[0].none());
658         mState.mLastSyncedEnabledAttributesMask = mState.mEnabledAttributesMask;
659     }
660     return angle::Result::Continue;
661 }
662 
663 // This becomes current vertex array on the context
onBind(const Context * context)664 void VertexArray::onBind(const Context *context)
665 {
666     // This vertex array becoming current. Some of the bindings we may have removed from buffer's
667     // observer list. We need to add it back to the buffer's observer list and update dirty bits
668     // that we may have missed while we were not observing.
669     for (size_t bindingIndex : mState.getBufferBindingMask())
670     {
671         const VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
672         Buffer *bufferGL             = binding.getBuffer().get();
673         ASSERT(bufferGL != nullptr);
674 
675         bufferGL->addObserver(&mArrayBufferObserverBindings[bindingIndex]);
676         updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[bindingIndex]);
677 
678         if (mBufferAccessValidationEnabled)
679         {
680             for (size_t boundAttribute :
681                  mState.mVertexBindings[bindingIndex].getBoundAttributesMask())
682             {
683                 mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(
684                     mState.mVertexBindings[bindingIndex]);
685             }
686         }
687 
688         if (context->isWebGL())
689         {
690             updateCachedTransformFeedbackBindingValidation(bindingIndex, bufferGL);
691         }
692     }
693 
694     mDirtyBits.set(DIRTY_BIT_LOST_OBSERVATION);
695     onStateChange(angle::SubjectMessage::ContentsChanged);
696 }
697 
698 // This becomes non-current vertex array on the context
onUnbind(const Context * context)699 void VertexArray::onUnbind(const Context *context)
700 {
701     // This vertex array becoming non-current. For performance reason, we remove it from the
702     // buffers' observer list so that the cost of buffer sending signal to observers will not be too
703     // expensive.
704     for (size_t bindingIndex : mState.mBufferBindingMask)
705     {
706         const VertexBinding &binding = mState.getVertexBindings()[bindingIndex];
707         Buffer *bufferGL             = binding.getBuffer().get();
708         ASSERT(bufferGL != nullptr);
709         bufferGL->removeObserver(&mArrayBufferObserverBindings[bindingIndex]);
710     }
711 }
712 
onBindingChanged(const Context * context,int incr)713 void VertexArray::onBindingChanged(const Context *context, int incr)
714 {
715     // When vertex array gets unbound, we remove it from bound buffers' observer list so that when
716     // buffer changes, it wont has to loop over all these non-current vertex arrays and set dirty
717     // bit on them. To compensate for that, when we bind a vertex array, we have to check against
718     // each bound buffers and see if they have changed and needs to update vertex array's dirty bits
719     // accordingly
720     ASSERT(incr == 1 || incr == -1);
721     if (incr < 0)
722     {
723         onUnbind(context);
724     }
725     else
726     {
727         onBind(context);
728     }
729 
730     if (context->isWebGL())
731     {
732         if (mState.mElementArrayBuffer.get())
733         {
734             mState.mElementArrayBuffer->onNonTFBindingChanged(incr);
735         }
736         for (size_t bindingIndex : mState.mBufferBindingMask)
737         {
738             mState.mVertexBindings[bindingIndex].onContainerBindingChanged(context, incr);
739         }
740     }
741 }
742 
getDirtyBitFromIndex(bool contentsChanged,angle::SubjectIndex index) const743 VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
744                                                             angle::SubjectIndex index) const
745 {
746     if (IsElementArrayBufferSubjectIndex(index))
747     {
748         mIndexRangeCache.invalidate();
749         return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
750                                : DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
751     }
752     else
753     {
754         // Note: this currently just gets the top-level dirty bit.
755         ASSERT(index < mArrayBufferObserverBindings.size());
756         return static_cast<DirtyBitType>(
757             (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
758     }
759 }
760 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)761 void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
762 {
763     switch (message)
764     {
765         case angle::SubjectMessage::SubjectChanged:
766             if (!IsElementArrayBufferSubjectIndex(index))
767             {
768                 updateCachedBufferBindingSize(&mState.mVertexBindings[index]);
769             }
770             setDependentDirtyBit(false, index);
771             break;
772 
773         case angle::SubjectMessage::BindingChanged:
774             if (!IsElementArrayBufferSubjectIndex(index))
775             {
776                 const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get();
777                 updateCachedTransformFeedbackBindingValidation(index, buffer);
778             }
779             break;
780 
781         case angle::SubjectMessage::SubjectMapped:
782             if (!IsElementArrayBufferSubjectIndex(index))
783             {
784                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
785             }
786             onStateChange(angle::SubjectMessage::SubjectMapped);
787             break;
788 
789         case angle::SubjectMessage::SubjectUnmapped:
790             setDependentDirtyBit(true, index);
791 
792             if (!IsElementArrayBufferSubjectIndex(index))
793             {
794                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
795             }
796             onStateChange(angle::SubjectMessage::SubjectUnmapped);
797             break;
798 
799         case angle::SubjectMessage::InternalMemoryAllocationChanged:
800             setDependentDirtyBit(false, index);
801             break;
802 
803         default:
804             UNREACHABLE();
805             break;
806     }
807 }
808 
setDependentDirtyBit(bool contentsChanged,angle::SubjectIndex index)809 void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index)
810 {
811     DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
812     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
813     mDirtyBits.set(dirtyBit);
814     onStateChange(angle::SubjectMessage::ContentsChanged);
815 }
816 
hasTransformFeedbackBindingConflict(const Context * context) const817 bool VertexArray::hasTransformFeedbackBindingConflict(const Context *context) const
818 {
819     // Fast check first.
820     if (!mCachedTransformFeedbackConflictedBindingsMask.any())
821     {
822         return false;
823     }
824 
825     const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask();
826 
827     // Slow check. We must ensure that the conflicting attributes are enabled/active.
828     for (size_t attribIndex : activeAttribues)
829     {
830         const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
831         if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex])
832         {
833             return true;
834         }
835     }
836 
837     return false;
838 }
839 
getIndexRangeImpl(const Context * context,DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut) const840 angle::Result VertexArray::getIndexRangeImpl(const Context *context,
841                                              DrawElementsType type,
842                                              GLsizei indexCount,
843                                              const void *indices,
844                                              IndexRange *indexRangeOut) const
845 {
846     Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get();
847     if (!elementArrayBuffer)
848     {
849         *indexRangeOut = ComputeIndexRange(type, indices, indexCount,
850                                            context->getState().isPrimitiveRestartEnabled());
851         return angle::Result::Continue;
852     }
853 
854     size_t offset = reinterpret_cast<uintptr_t>(indices);
855     ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount,
856                                                 context->getState().isPrimitiveRestartEnabled(),
857                                                 indexRangeOut));
858 
859     mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut);
860     return angle::Result::Continue;
861 }
862 
863 VertexArray::IndexRangeCache::IndexRangeCache() = default;
864 
put(DrawElementsType type,GLsizei indexCount,size_t offset,const IndexRange & indexRange)865 void VertexArray::IndexRangeCache::put(DrawElementsType type,
866                                        GLsizei indexCount,
867                                        size_t offset,
868                                        const IndexRange &indexRange)
869 {
870     ASSERT(type != DrawElementsType::InvalidEnum);
871 
872     mTypeKey       = type;
873     mIndexCountKey = indexCount;
874     mOffsetKey     = offset;
875     mPayload       = indexRange;
876 }
877 
onBufferContentsChange(uint32_t bufferIndex)878 void VertexArray::onBufferContentsChange(uint32_t bufferIndex)
879 {
880     setDependentDirtyBit(true, bufferIndex);
881 }
882 
VertexArrayBufferContentsObservers(VertexArray * vertexArray)883 VertexArrayBufferContentsObservers::VertexArrayBufferContentsObservers(VertexArray *vertexArray)
884     : mVertexArray(vertexArray)
885 {}
886 
enableForBuffer(Buffer * buffer,uint32_t attribIndex)887 void VertexArrayBufferContentsObservers::enableForBuffer(Buffer *buffer, uint32_t attribIndex)
888 {
889     buffer->addContentsObserver(mVertexArray, attribIndex);
890     mBufferObserversBitMask.set(attribIndex);
891 }
892 
disableForBuffer(Buffer * buffer,uint32_t attribIndex)893 void VertexArrayBufferContentsObservers::disableForBuffer(Buffer *buffer, uint32_t attribIndex)
894 {
895     buffer->removeContentsObserver(mVertexArray, attribIndex);
896     mBufferObserversBitMask.reset(attribIndex);
897 }
898 }  // namespace gl
899