• 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 == MAX_VERTEX_ATTRIBS);
25 }
26 
27 constexpr angle::SubjectIndex kElementArrayBufferIndex = MAX_VERTEX_ATTRIBS;
28 }  // namespace
29 
30 // VertexArrayState implementation.
VertexArrayState(VertexArray * vertexArray,size_t maxAttribs,size_t maxAttribBindings)31 VertexArrayState::VertexArrayState(VertexArray *vertexArray,
32                                    size_t maxAttribs,
33                                    size_t maxAttribBindings)
34     : mElementArrayBuffer(vertexArray, kElementArrayBufferIndex)
35 {
36     ASSERT(maxAttribs <= maxAttribBindings);
37 
38     for (size_t i = 0; i < maxAttribs; i++)
39     {
40         mVertexAttributes.emplace_back(static_cast<GLuint>(i));
41         mVertexBindings.emplace_back(static_cast<GLuint>(i));
42     }
43 
44     // Initially all attributes start as "client" with no buffer bound.
45     mClientMemoryAttribsMask.set();
46 }
47 
~VertexArrayState()48 VertexArrayState::~VertexArrayState() {}
49 
hasEnabledNullPointerClientArray() const50 bool VertexArrayState::hasEnabledNullPointerClientArray() const
51 {
52     return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any();
53 }
54 
getBindingToAttributesMask(GLuint bindingIndex) const55 AttributesMask VertexArrayState::getBindingToAttributesMask(GLuint bindingIndex) const
56 {
57     ASSERT(bindingIndex < MAX_VERTEX_ATTRIB_BINDINGS);
58     return mVertexBindings[bindingIndex].getBoundAttributesMask();
59 }
60 
61 // Set an attribute using a new binding.
setAttribBinding(const Context * context,size_t attribIndex,GLuint newBindingIndex)62 void VertexArrayState::setAttribBinding(const Context *context,
63                                         size_t attribIndex,
64                                         GLuint newBindingIndex)
65 {
66     ASSERT(attribIndex < MAX_VERTEX_ATTRIBS && newBindingIndex < MAX_VERTEX_ATTRIB_BINDINGS);
67 
68     VertexAttribute &attrib = mVertexAttributes[attribIndex];
69 
70     // Update the binding-attribute map.
71     const GLuint oldBindingIndex = attrib.bindingIndex;
72     ASSERT(oldBindingIndex != newBindingIndex);
73 
74     VertexBinding &oldBinding = mVertexBindings[oldBindingIndex];
75     VertexBinding &newBinding = mVertexBindings[newBindingIndex];
76 
77     ASSERT(oldBinding.getBoundAttributesMask().test(attribIndex) &&
78            !newBinding.getBoundAttributesMask().test(attribIndex));
79 
80     oldBinding.resetBoundAttribute(attribIndex);
81     newBinding.setBoundAttribute(attribIndex);
82 
83     // Set the attribute using the new binding.
84     attrib.bindingIndex = newBindingIndex;
85 
86     if (context->isBufferAccessValidationEnabled())
87     {
88         attrib.updateCachedElementLimit(newBinding);
89     }
90 
91     bool isMapped = newBinding.getBuffer().get() && newBinding.getBuffer()->isMapped();
92     mCachedMappedArrayBuffers.set(attribIndex, isMapped);
93     mCachedEnabledMappedArrayBuffers.set(attribIndex, isMapped && attrib.enabled);
94 }
95 
96 // VertexArray implementation.
VertexArray(rx::GLImplFactory * factory,VertexArrayID id,size_t maxAttribs,size_t maxAttribBindings)97 VertexArray::VertexArray(rx::GLImplFactory *factory,
98                          VertexArrayID id,
99                          size_t maxAttribs,
100                          size_t maxAttribBindings)
101     : mId(id),
102       mState(this, maxAttribs, maxAttribBindings),
103       mVertexArray(factory->createVertexArray(mState)),
104       mBufferAccessValidationEnabled(false)
105 {
106     for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex)
107     {
108         mArrayBufferObserverBindings.emplace_back(this, attribIndex);
109     }
110 }
111 
onDestroy(const Context * context)112 void VertexArray::onDestroy(const Context *context)
113 {
114     bool isBound = context->isCurrentVertexArray(this);
115     for (VertexBinding &binding : mState.mVertexBindings)
116     {
117         if (isBound)
118         {
119             if (binding.getBuffer().get())
120                 binding.getBuffer()->onNonTFBindingChanged(-1);
121         }
122         binding.setBuffer(context, nullptr);
123     }
124     if (isBound && mState.mElementArrayBuffer.get())
125         mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
126     mState.mElementArrayBuffer.bind(context, nullptr);
127     mVertexArray->destroy(context);
128     SafeDelete(mVertexArray);
129     delete this;
130 }
131 
~VertexArray()132 VertexArray::~VertexArray()
133 {
134     ASSERT(!mVertexArray);
135 }
136 
setLabel(const Context * context,const std::string & label)137 void VertexArray::setLabel(const Context *context, const std::string &label)
138 {
139     mState.mLabel = label;
140 }
141 
getLabel() const142 const std::string &VertexArray::getLabel() const
143 {
144     return mState.mLabel;
145 }
146 
detachBuffer(const Context * context,BufferID bufferID)147 bool VertexArray::detachBuffer(const Context *context, BufferID bufferID)
148 {
149     bool isBound           = context->isCurrentVertexArray(this);
150     bool anyBufferDetached = false;
151     for (uint32_t bindingIndex = 0; bindingIndex < gl::MAX_VERTEX_ATTRIB_BINDINGS; ++bindingIndex)
152     {
153         VertexBinding &binding = mState.mVertexBindings[bindingIndex];
154         if (binding.getBuffer().id() == bufferID)
155         {
156             if (isBound)
157             {
158                 if (binding.getBuffer().get())
159                     binding.getBuffer()->onNonTFBindingChanged(-1);
160             }
161             binding.setBuffer(context, nullptr);
162             mArrayBufferObserverBindings[bindingIndex].reset();
163 
164             if (context->getClientVersion() >= ES_3_1)
165             {
166                 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
167             }
168             else
169             {
170                 static_assert(gl::MAX_VERTEX_ATTRIB_BINDINGS < 8 * sizeof(uint32_t),
171                               "Not enough bits in bindingIndex");
172                 // The redundant uint32_t cast here is required to avoid a warning on MSVC.
173                 ASSERT(binding.getBoundAttributesMask() ==
174                        AttributesMask(static_cast<uint32_t>(1 << bindingIndex)));
175                 setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER);
176             }
177 
178             anyBufferDetached = true;
179             mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask();
180         }
181     }
182 
183     if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferID)
184     {
185         if (isBound && mState.mElementArrayBuffer.get())
186             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
187         mState.mElementArrayBuffer.bind(context, nullptr);
188         mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
189         anyBufferDetached = true;
190     }
191 
192     return anyBufferDetached;
193 }
194 
getVertexAttribute(size_t attribIndex) const195 const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
196 {
197     ASSERT(attribIndex < getMaxAttribs());
198     return mState.mVertexAttributes[attribIndex];
199 }
200 
getVertexBinding(size_t bindingIndex) const201 const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
202 {
203     ASSERT(bindingIndex < getMaxBindings());
204     return mState.mVertexBindings[bindingIndex];
205 }
206 
GetVertexIndexFromDirtyBit(size_t dirtyBit)207 size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
208 {
209     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
210                   "The stride of vertex attributes should equal to that of vertex bindings.");
211     ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
212     return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS;
213 }
214 
setDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)215 ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex,
216                                                  DirtyAttribBitType dirtyAttribBit)
217 {
218     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
219     mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
220 }
221 
setDirtyBindingBit(size_t bindingIndex,DirtyBindingBitType dirtyBindingBit)222 ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex,
223                                                   DirtyBindingBitType dirtyBindingBit)
224 {
225     mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
226     mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
227 }
228 
updateCachedBufferBindingSize(VertexBinding * binding)229 ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
230 {
231     if (!mBufferAccessValidationEnabled)
232         return;
233 
234     for (size_t boundAttribute : binding->getBoundAttributesMask())
235     {
236         mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
237     }
238 }
239 
updateCachedMappedArrayBuffers(bool isMapped,const AttributesMask & boundAttributesMask)240 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers(
241     bool isMapped,
242     const AttributesMask &boundAttributesMask)
243 {
244     if (isMapped)
245     {
246         mState.mCachedMappedArrayBuffers |= boundAttributesMask;
247     }
248     else
249     {
250         mState.mCachedMappedArrayBuffers &= ~boundAttributesMask;
251     }
252 
253     mState.mCachedEnabledMappedArrayBuffers =
254         mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
255 }
256 
updateCachedMappedArrayBuffersBinding(const VertexBinding & binding)257 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding)
258 {
259     const Buffer *buffer = binding.getBuffer().get();
260     return updateCachedMappedArrayBuffers(buffer && buffer->isMapped(),
261                                           binding.getBoundAttributesMask());
262 }
263 
updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,const Buffer * buffer)264 ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
265                                                                               const Buffer *buffer)
266 {
267     const bool hasConflict = buffer && buffer->isBoundForTransformFeedbackAndOtherUse();
268     mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
269 }
270 
bindVertexBufferImpl(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)271 bool VertexArray::bindVertexBufferImpl(const Context *context,
272                                        size_t bindingIndex,
273                                        Buffer *boundBuffer,
274                                        GLintptr offset,
275                                        GLsizei stride)
276 {
277     ASSERT(bindingIndex < getMaxBindings());
278     ASSERT(context->isCurrentVertexArray(this));
279 
280     VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
281 
282     Buffer *oldBuffer = binding->getBuffer().get();
283 
284     const bool sameBuffer = oldBuffer == boundBuffer;
285     const bool sameStride = static_cast<GLuint>(stride) == binding->getStride();
286     const bool sameOffset = offset == binding->getOffset();
287 
288     if (sameBuffer && sameStride && sameOffset)
289     {
290         return false;
291     }
292 
293     angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
294     observer->assignSubject(boundBuffer);
295 
296     // Several nullptr checks are combined here for optimization purposes.
297     if (oldBuffer)
298     {
299         oldBuffer->onNonTFBindingChanged(-1);
300         oldBuffer->removeObserver(observer);
301         oldBuffer->release(context);
302     }
303 
304     binding->assignBuffer(boundBuffer);
305     binding->setOffset(offset);
306     binding->setStride(stride);
307     updateCachedBufferBindingSize(binding);
308 
309     // Update client memory attribute pointers. Affects all bound attributes.
310     if (boundBuffer)
311     {
312         boundBuffer->addRef();
313         boundBuffer->onNonTFBindingChanged(1);
314         boundBuffer->addObserver(observer);
315         mCachedTransformFeedbackConflictedBindingsMask.set(
316             bindingIndex, boundBuffer->isBoundForTransformFeedbackAndOtherUse());
317         mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask();
318         updateCachedMappedArrayBuffers((boundBuffer->isMapped() == GL_TRUE),
319                                        binding->getBoundAttributesMask());
320     }
321     else
322     {
323         mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false);
324         mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask();
325         updateCachedMappedArrayBuffers(false, binding->getBoundAttributesMask());
326     }
327 
328     return true;
329 }
330 
bindVertexBuffer(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)331 void VertexArray::bindVertexBuffer(const Context *context,
332                                    size_t bindingIndex,
333                                    Buffer *boundBuffer,
334                                    GLintptr offset,
335                                    GLsizei stride)
336 {
337     if (bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride))
338     {
339         setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
340     }
341 }
342 
setVertexAttribBinding(const Context * context,size_t attribIndex,GLuint bindingIndex)343 void VertexArray::setVertexAttribBinding(const Context *context,
344                                          size_t attribIndex,
345                                          GLuint bindingIndex)
346 {
347     ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
348 
349     if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex)
350     {
351         // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
352         ASSERT(context->getClientVersion() >= ES_3_1);
353 
354         mState.setAttribBinding(context, attribIndex, bindingIndex);
355 
356         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
357 
358         // Update client attribs mask.
359         bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
360         mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
361     }
362 }
363 
setVertexBindingDivisor(size_t bindingIndex,GLuint divisor)364 void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
365 {
366     ASSERT(bindingIndex < getMaxBindings());
367 
368     VertexBinding &binding = mState.mVertexBindings[bindingIndex];
369 
370     binding.setDivisor(divisor);
371     setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR);
372 
373     // Trigger updates in all bound attributes.
374     for (size_t attribIndex : binding.getBoundAttributesMask())
375     {
376         mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding);
377     }
378 }
379 
setVertexAttribFormatImpl(VertexAttribute * attrib,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)380 ANGLE_INLINE bool VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib,
381                                                          GLint size,
382                                                          VertexAttribType type,
383                                                          bool normalized,
384                                                          bool pureInteger,
385                                                          GLuint relativeOffset)
386 {
387     angle::FormatID formatID = gl::GetVertexFormatID(type, normalized, size, pureInteger);
388 
389     if (formatID != attrib->format->id || attrib->relativeOffset != relativeOffset)
390     {
391         attrib->relativeOffset = relativeOffset;
392         attrib->format         = &angle::Format::Get(formatID);
393         return true;
394     }
395 
396     return false;
397 }
398 
setVertexAttribFormat(size_t attribIndex,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)399 void VertexArray::setVertexAttribFormat(size_t attribIndex,
400                                         GLint size,
401                                         VertexAttribType type,
402                                         bool normalized,
403                                         bool pureInteger,
404                                         GLuint relativeOffset)
405 {
406     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
407 
408     ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type);
409     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
410 
411     if (setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, relativeOffset))
412     {
413         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT);
414     }
415 
416     attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]);
417 }
418 
setVertexAttribDivisor(const Context * context,size_t attribIndex,GLuint divisor)419 void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
420 {
421     ASSERT(attribIndex < getMaxAttribs());
422 
423     setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
424     setVertexBindingDivisor(attribIndex, divisor);
425 }
426 
enableAttribute(size_t attribIndex,bool enabledState)427 void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
428 {
429     ASSERT(attribIndex < getMaxAttribs());
430 
431     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
432 
433     if (mState.mEnabledAttributesMask.test(attribIndex) == enabledState)
434     {
435         return;
436     }
437 
438     attrib.enabled = enabledState;
439 
440     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED);
441 
442     // Update state cache
443     mState.mEnabledAttributesMask.set(attribIndex, enabledState);
444     mState.mCachedEnabledMappedArrayBuffers =
445         mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
446 }
447 
setVertexAttribPointerImpl(const Context * context,ComponentType componentType,bool pureInteger,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)448 ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context,
449                                                           ComponentType componentType,
450                                                           bool pureInteger,
451                                                           size_t attribIndex,
452                                                           Buffer *boundBuffer,
453                                                           GLint size,
454                                                           VertexAttribType type,
455                                                           bool normalized,
456                                                           GLsizei stride,
457                                                           const void *pointer)
458 {
459     ASSERT(attribIndex < getMaxAttribs());
460 
461     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
462 
463     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
464 
465     bool attribDirty = setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, 0);
466 
467     if (attrib.bindingIndex != attribIndex)
468     {
469         setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
470     }
471 
472     GLsizei effectiveStride =
473         stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
474 
475     if (attrib.vertexAttribArrayStride != static_cast<GLuint>(stride))
476     {
477         attribDirty = true;
478     }
479     attrib.vertexAttribArrayStride = stride;
480 
481     // If we switch from an array buffer to a client pointer(or vice-versa), we set the whole
482     // attribute dirty. This notifies the Vulkan back-end to update all its caches.
483     const VertexBinding &binding = mState.mVertexBindings[attribIndex];
484     if ((boundBuffer == nullptr) != (binding.getBuffer().get() == nullptr))
485     {
486         attribDirty = true;
487     }
488 
489     // Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset
490     // which is handled within bindVertexBufferImpl and reflected in bufferDirty.
491     attrib.pointer  = pointer;
492     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
493     const bool bufferDirty =
494         bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
495 
496     if (attribDirty)
497     {
498         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
499     }
500     else if (bufferDirty)
501     {
502         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
503     }
504 
505     mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
506                                                    boundBuffer == nullptr && pointer == nullptr);
507 }
508 
setVertexAttribPointer(const Context * context,size_t attribIndex,gl::Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)509 void VertexArray::setVertexAttribPointer(const Context *context,
510                                          size_t attribIndex,
511                                          gl::Buffer *boundBuffer,
512                                          GLint size,
513                                          VertexAttribType type,
514                                          bool normalized,
515                                          GLsizei stride,
516                                          const void *pointer)
517 {
518     setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size,
519                                type, normalized, stride, pointer);
520 }
521 
setVertexAttribIPointer(const Context * context,size_t attribIndex,gl::Buffer * boundBuffer,GLint size,VertexAttribType type,GLsizei stride,const void * pointer)522 void VertexArray::setVertexAttribIPointer(const Context *context,
523                                           size_t attribIndex,
524                                           gl::Buffer *boundBuffer,
525                                           GLint size,
526                                           VertexAttribType type,
527                                           GLsizei stride,
528                                           const void *pointer)
529 {
530     ComponentType componentType = GetVertexAttributeComponentType(true, type);
531     setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type,
532                                false, stride, pointer);
533 }
534 
syncState(const Context * context)535 angle::Result VertexArray::syncState(const Context *context)
536 {
537     if (mDirtyBits.any())
538     {
539         mDirtyBitsGuard = mDirtyBits;
540         ANGLE_TRY(
541             mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits));
542         mDirtyBits.reset();
543         mDirtyBitsGuard.reset();
544 
545         // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
546         ASSERT(mDirtyAttribBits[0].none());
547         ASSERT(mDirtyBindingBits[0].none());
548     }
549     return angle::Result::Continue;
550 }
551 
onBindingChanged(const Context * context,int incr)552 void VertexArray::onBindingChanged(const Context *context, int incr)
553 {
554     if (mState.mElementArrayBuffer.get())
555         mState.mElementArrayBuffer->onNonTFBindingChanged(incr);
556     for (auto &binding : mState.mVertexBindings)
557     {
558         binding.onContainerBindingChanged(context, incr);
559     }
560 }
561 
getDirtyBitFromIndex(bool contentsChanged,angle::SubjectIndex index) const562 VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
563                                                             angle::SubjectIndex index) const
564 {
565     if (IsElementArrayBufferSubjectIndex(index))
566     {
567         mIndexRangeCache.invalidate();
568         return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
569                                : DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
570     }
571     else
572     {
573         // Note: this currently just gets the top-level dirty bit.
574         ASSERT(index < mArrayBufferObserverBindings.size());
575         return static_cast<DirtyBitType>(
576             (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
577     }
578 }
579 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)580 void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
581 {
582     switch (message)
583     {
584         case angle::SubjectMessage::ContentsChanged:
585             setDependentDirtyBit(true, index);
586             break;
587 
588         case angle::SubjectMessage::SubjectChanged:
589             if (!IsElementArrayBufferSubjectIndex(index))
590             {
591                 updateCachedBufferBindingSize(&mState.mVertexBindings[index]);
592             }
593             setDependentDirtyBit(false, index);
594             break;
595 
596         case angle::SubjectMessage::BindingChanged:
597             if (!IsElementArrayBufferSubjectIndex(index))
598             {
599                 const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get();
600                 updateCachedTransformFeedbackBindingValidation(index, buffer);
601             }
602             break;
603 
604         case angle::SubjectMessage::SubjectMapped:
605             if (!IsElementArrayBufferSubjectIndex(index))
606             {
607                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
608             }
609             onStateChange(angle::SubjectMessage::SubjectMapped);
610             break;
611 
612         case angle::SubjectMessage::SubjectUnmapped:
613             setDependentDirtyBit(true, index);
614 
615             if (!IsElementArrayBufferSubjectIndex(index))
616             {
617                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
618             }
619             onStateChange(angle::SubjectMessage::SubjectUnmapped);
620             break;
621 
622         default:
623             UNREACHABLE();
624             break;
625     }
626 }
627 
setDependentDirtyBit(bool contentsChanged,angle::SubjectIndex index)628 void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index)
629 {
630     DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
631     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
632     mDirtyBits.set(dirtyBit);
633     onStateChange(angle::SubjectMessage::ContentsChanged);
634 }
635 
hasTransformFeedbackBindingConflict(const gl::Context * context) const636 bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const
637 {
638     // Fast check first.
639     if (!mCachedTransformFeedbackConflictedBindingsMask.any())
640     {
641         return false;
642     }
643 
644     const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask();
645 
646     // Slow check. We must ensure that the conflicting attributes are enabled/active.
647     for (size_t attribIndex : activeAttribues)
648     {
649         const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
650         if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex])
651         {
652             return true;
653         }
654     }
655 
656     return false;
657 }
658 
getIndexRangeImpl(const Context * context,DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut) const659 angle::Result VertexArray::getIndexRangeImpl(const Context *context,
660                                              DrawElementsType type,
661                                              GLsizei indexCount,
662                                              const void *indices,
663                                              IndexRange *indexRangeOut) const
664 {
665     Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get();
666     if (!elementArrayBuffer)
667     {
668         *indexRangeOut = ComputeIndexRange(type, indices, indexCount,
669                                            context->getState().isPrimitiveRestartEnabled());
670         return angle::Result::Continue;
671     }
672 
673     size_t offset = reinterpret_cast<uintptr_t>(indices);
674     ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount,
675                                                 context->getState().isPrimitiveRestartEnabled(),
676                                                 indexRangeOut));
677 
678     mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut);
679     return angle::Result::Continue;
680 }
681 
682 VertexArray::IndexRangeCache::IndexRangeCache() = default;
683 
put(DrawElementsType type,GLsizei indexCount,size_t offset,const IndexRange & indexRange)684 void VertexArray::IndexRangeCache::put(DrawElementsType type,
685                                        GLsizei indexCount,
686                                        size_t offset,
687                                        const IndexRange &indexRange)
688 {
689     ASSERT(type != DrawElementsType::InvalidEnum);
690 
691     mTypeKey       = type;
692     mIndexCountKey = indexCount;
693     mOffsetKey     = offset;
694     mPayload       = indexRange;
695 }
696 }  // namespace gl
697