• 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,GLuint id,size_t maxAttribs,size_t maxAttribBindings)97 VertexArray::VertexArray(rx::GLImplFactory *factory,
98                          GLuint 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,GLuint bufferName)147 bool VertexArray::detachBuffer(const Context *context, GLuint bufferName)
148 {
149     bool isBound           = context->isCurrentVertexArray(this);
150     bool anyBufferDetached = false;
151     for (size_t bindingIndex = 0; bindingIndex < gl::MAX_VERTEX_ATTRIB_BINDINGS; ++bindingIndex)
152     {
153         VertexBinding &binding = mState.mVertexBindings[bindingIndex];
154         if (binding.getBuffer().id() == bufferName)
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                 ASSERT(binding.getBoundAttributesMask() ==
171                        AttributesMask(static_cast<size_t>(1) << bindingIndex));
172                 setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER);
173             }
174 
175             anyBufferDetached = true;
176             mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask();
177         }
178     }
179 
180     if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferName)
181     {
182         if (isBound && mState.mElementArrayBuffer.get())
183             mState.mElementArrayBuffer->onNonTFBindingChanged(-1);
184         mState.mElementArrayBuffer.bind(context, nullptr);
185         mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
186         anyBufferDetached = true;
187     }
188 
189     return anyBufferDetached;
190 }
191 
getVertexAttribute(size_t attribIndex) const192 const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
193 {
194     ASSERT(attribIndex < getMaxAttribs());
195     return mState.mVertexAttributes[attribIndex];
196 }
197 
getVertexBinding(size_t bindingIndex) const198 const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
199 {
200     ASSERT(bindingIndex < getMaxBindings());
201     return mState.mVertexBindings[bindingIndex];
202 }
203 
GetVertexIndexFromDirtyBit(size_t dirtyBit)204 size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
205 {
206     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
207                   "The stride of vertex attributes should equal to that of vertex bindings.");
208     ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
209     return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS;
210 }
211 
setDirtyAttribBit(size_t attribIndex,DirtyAttribBitType dirtyAttribBit)212 ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex,
213                                                  DirtyAttribBitType dirtyAttribBit)
214 {
215     mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
216     mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
217 }
218 
setDirtyBindingBit(size_t bindingIndex,DirtyBindingBitType dirtyBindingBit)219 ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex,
220                                                   DirtyBindingBitType dirtyBindingBit)
221 {
222     mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
223     mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
224 }
225 
updateCachedBufferBindingSize(VertexBinding * binding)226 ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
227 {
228     if (!mBufferAccessValidationEnabled)
229         return;
230 
231     for (size_t boundAttribute : binding->getBoundAttributesMask())
232     {
233         mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
234     }
235 }
236 
updateCachedMappedArrayBuffers(bool isMapped,const AttributesMask & boundAttributesMask)237 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers(
238     bool isMapped,
239     const AttributesMask &boundAttributesMask)
240 {
241     if (isMapped)
242     {
243         mState.mCachedMappedArrayBuffers |= boundAttributesMask;
244     }
245     else
246     {
247         mState.mCachedMappedArrayBuffers &= ~boundAttributesMask;
248     }
249 
250     mState.mCachedEnabledMappedArrayBuffers =
251         mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
252 }
253 
updateCachedMappedArrayBuffersBinding(const VertexBinding & binding)254 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding)
255 {
256     const Buffer *buffer = binding.getBuffer().get();
257     return updateCachedMappedArrayBuffers(buffer && buffer->isMapped(),
258                                           binding.getBoundAttributesMask());
259 }
260 
updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,const Buffer * buffer)261 ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
262                                                                               const Buffer *buffer)
263 {
264     const bool hasConflict = buffer && buffer->isBoundForTransformFeedbackAndOtherUse();
265     mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
266 }
267 
bindVertexBufferImpl(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)268 bool VertexArray::bindVertexBufferImpl(const Context *context,
269                                        size_t bindingIndex,
270                                        Buffer *boundBuffer,
271                                        GLintptr offset,
272                                        GLsizei stride)
273 {
274     ASSERT(bindingIndex < getMaxBindings());
275     ASSERT(context->isCurrentVertexArray(this));
276 
277     VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
278 
279     Buffer *oldBuffer = binding->getBuffer().get();
280 
281     const bool sameBuffer = oldBuffer == boundBuffer;
282     const bool sameStride = static_cast<GLuint>(stride) == binding->getStride();
283     const bool sameOffset = offset == binding->getOffset();
284 
285     if (sameBuffer && sameStride && sameOffset)
286     {
287         return false;
288     }
289 
290     angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex];
291     observer->assignSubject(boundBuffer);
292 
293     // Several nullptr checks are combined here for optimization purposes.
294     if (oldBuffer)
295     {
296         oldBuffer->onNonTFBindingChanged(-1);
297         oldBuffer->removeObserver(observer);
298         oldBuffer->release(context);
299     }
300 
301     binding->assignBuffer(boundBuffer);
302     binding->setOffset(offset);
303     binding->setStride(stride);
304     updateCachedBufferBindingSize(binding);
305 
306     // Update client memory attribute pointers. Affects all bound attributes.
307     if (boundBuffer)
308     {
309         boundBuffer->addRef();
310         boundBuffer->onNonTFBindingChanged(1);
311         boundBuffer->addObserver(observer);
312         mCachedTransformFeedbackConflictedBindingsMask.set(
313             bindingIndex, boundBuffer->isBoundForTransformFeedbackAndOtherUse());
314         mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask();
315         updateCachedMappedArrayBuffers(boundBuffer->isMapped(), binding->getBoundAttributesMask());
316     }
317     else
318     {
319         mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false);
320         mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask();
321         updateCachedMappedArrayBuffers(false, binding->getBoundAttributesMask());
322     }
323 
324     return true;
325 }
326 
bindVertexBuffer(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)327 void VertexArray::bindVertexBuffer(const Context *context,
328                                    size_t bindingIndex,
329                                    Buffer *boundBuffer,
330                                    GLintptr offset,
331                                    GLsizei stride)
332 {
333     if (bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride))
334     {
335         setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
336     }
337 }
338 
setVertexAttribBinding(const Context * context,size_t attribIndex,GLuint bindingIndex)339 void VertexArray::setVertexAttribBinding(const Context *context,
340                                          size_t attribIndex,
341                                          GLuint bindingIndex)
342 {
343     ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
344 
345     if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex)
346     {
347         // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
348         ASSERT(context->getClientVersion() >= ES_3_1);
349 
350         mState.setAttribBinding(context, attribIndex, bindingIndex);
351 
352         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
353 
354         // Update client attribs mask.
355         bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr;
356         mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer);
357     }
358 }
359 
setVertexBindingDivisor(size_t bindingIndex,GLuint divisor)360 void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
361 {
362     ASSERT(bindingIndex < getMaxBindings());
363 
364     VertexBinding &binding = mState.mVertexBindings[bindingIndex];
365 
366     binding.setDivisor(divisor);
367     setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR);
368 
369     // Trigger updates in all bound attributes.
370     for (size_t attribIndex : binding.getBoundAttributesMask())
371     {
372         mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding);
373     }
374 }
375 
setVertexAttribFormatImpl(VertexAttribute * attrib,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)376 ANGLE_INLINE bool VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib,
377                                                          GLint size,
378                                                          VertexAttribType type,
379                                                          bool normalized,
380                                                          bool pureInteger,
381                                                          GLuint relativeOffset)
382 {
383     angle::FormatID formatID = gl::GetVertexFormatID(type, normalized, size, pureInteger);
384 
385     if (formatID != attrib->format->id || attrib->relativeOffset != relativeOffset)
386     {
387         attrib->relativeOffset = relativeOffset;
388         attrib->format         = &angle::Format::Get(formatID);
389         return true;
390     }
391 
392     return false;
393 }
394 
setVertexAttribFormat(size_t attribIndex,GLint size,VertexAttribType type,bool normalized,bool pureInteger,GLuint relativeOffset)395 void VertexArray::setVertexAttribFormat(size_t attribIndex,
396                                         GLint size,
397                                         VertexAttribType type,
398                                         bool normalized,
399                                         bool pureInteger,
400                                         GLuint relativeOffset)
401 {
402     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
403 
404     ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type);
405     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
406 
407     if (setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, relativeOffset))
408     {
409         setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT);
410     }
411 
412     attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]);
413 }
414 
setVertexAttribDivisor(const Context * context,size_t attribIndex,GLuint divisor)415 void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
416 {
417     ASSERT(attribIndex < getMaxAttribs());
418 
419     setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
420     setVertexBindingDivisor(attribIndex, divisor);
421 }
422 
enableAttribute(size_t attribIndex,bool enabledState)423 void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
424 {
425     ASSERT(attribIndex < getMaxAttribs());
426 
427     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
428 
429     if (mState.mEnabledAttributesMask.test(attribIndex) == enabledState)
430     {
431         return;
432     }
433 
434     attrib.enabled = enabledState;
435 
436     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED);
437 
438     // Update state cache
439     mState.mEnabledAttributesMask.set(attribIndex, enabledState);
440     mState.mCachedEnabledMappedArrayBuffers =
441         mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
442 }
443 
setVertexAttribPointerImpl(const Context * context,ComponentType componentType,bool pureInteger,size_t attribIndex,Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)444 ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context,
445                                                           ComponentType componentType,
446                                                           bool pureInteger,
447                                                           size_t attribIndex,
448                                                           Buffer *boundBuffer,
449                                                           GLint size,
450                                                           VertexAttribType type,
451                                                           bool normalized,
452                                                           GLsizei stride,
453                                                           const void *pointer)
454 {
455     ASSERT(attribIndex < getMaxAttribs());
456 
457     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
458 
459     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
460 
461     SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
462 
463     bool attribDirty = setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, 0);
464 
465     if (attrib.bindingIndex != attribIndex)
466     {
467         setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
468     }
469 
470     GLsizei effectiveStride =
471         stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
472 
473     if (pointer != attrib.pointer || attrib.vertexAttribArrayStride != static_cast<GLuint>(stride))
474     {
475         attribDirty = true;
476     }
477 
478     attrib.pointer                 = pointer;
479     attrib.vertexAttribArrayStride = stride;
480 
481     // "Pointer buffer" dirty bit disabled because of a bug. http://anglebug.com/3256
482     bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
483     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
484     ANGLE_UNUSED_VARIABLE(attribDirty);
485 
486     // if (bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride) &&
487     //    !attribDirty)
488     //{
489     //    setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
490     //}
491     // else if (attribDirty)
492     //{
493     //    setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
494     //}
495 
496     mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
497                                                    boundBuffer == nullptr && pointer == nullptr);
498 }
499 
setVertexAttribPointer(const Context * context,size_t attribIndex,gl::Buffer * boundBuffer,GLint size,VertexAttribType type,bool normalized,GLsizei stride,const void * pointer)500 void VertexArray::setVertexAttribPointer(const Context *context,
501                                          size_t attribIndex,
502                                          gl::Buffer *boundBuffer,
503                                          GLint size,
504                                          VertexAttribType type,
505                                          bool normalized,
506                                          GLsizei stride,
507                                          const void *pointer)
508 {
509     setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size,
510                                type, normalized, stride, pointer);
511 }
512 
setVertexAttribIPointer(const Context * context,size_t attribIndex,gl::Buffer * boundBuffer,GLint size,VertexAttribType type,GLsizei stride,const void * pointer)513 void VertexArray::setVertexAttribIPointer(const Context *context,
514                                           size_t attribIndex,
515                                           gl::Buffer *boundBuffer,
516                                           GLint size,
517                                           VertexAttribType type,
518                                           GLsizei stride,
519                                           const void *pointer)
520 {
521     ComponentType componentType = GetVertexAttributeComponentType(true, type);
522     setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type,
523                                false, stride, pointer);
524 }
525 
syncState(const Context * context)526 angle::Result VertexArray::syncState(const Context *context)
527 {
528     if (mDirtyBits.any())
529     {
530         mDirtyBitsGuard = mDirtyBits;
531         ANGLE_TRY(
532             mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits));
533         mDirtyBits.reset();
534         mDirtyBitsGuard.reset();
535 
536         // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
537         ASSERT(mDirtyAttribBits[0].none());
538         ASSERT(mDirtyBindingBits[0].none());
539     }
540     return angle::Result::Continue;
541 }
542 
onBindingChanged(const Context * context,int incr)543 void VertexArray::onBindingChanged(const Context *context, int incr)
544 {
545     if (mState.mElementArrayBuffer.get())
546         mState.mElementArrayBuffer->onNonTFBindingChanged(incr);
547     for (auto &binding : mState.mVertexBindings)
548     {
549         binding.onContainerBindingChanged(context, incr);
550     }
551 }
552 
getDirtyBitFromIndex(bool contentsChanged,angle::SubjectIndex index) const553 VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged,
554                                                             angle::SubjectIndex index) const
555 {
556     if (IsElementArrayBufferSubjectIndex(index))
557     {
558         mIndexRangeCache.invalidate();
559         return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA
560                                : DIRTY_BIT_ELEMENT_ARRAY_BUFFER;
561     }
562     else
563     {
564         // Note: this currently just gets the top-level dirty bit.
565         ASSERT(index < mArrayBufferObserverBindings.size());
566         return static_cast<DirtyBitType>(
567             (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index);
568     }
569 }
570 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)571 void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
572 {
573     switch (message)
574     {
575         case angle::SubjectMessage::ContentsChanged:
576             setDependentDirtyBit(true, index);
577             break;
578 
579         case angle::SubjectMessage::SubjectChanged:
580             if (!IsElementArrayBufferSubjectIndex(index))
581             {
582                 updateCachedBufferBindingSize(&mState.mVertexBindings[index]);
583             }
584             setDependentDirtyBit(false, index);
585             break;
586 
587         case angle::SubjectMessage::BindingChanged:
588             if (!IsElementArrayBufferSubjectIndex(index))
589             {
590                 const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get();
591                 updateCachedTransformFeedbackBindingValidation(index, buffer);
592             }
593             break;
594 
595         case angle::SubjectMessage::SubjectMapped:
596             if (!IsElementArrayBufferSubjectIndex(index))
597             {
598                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
599             }
600             onStateChange(angle::SubjectMessage::SubjectMapped);
601             break;
602 
603         case angle::SubjectMessage::SubjectUnmapped:
604             setDependentDirtyBit(true, index);
605 
606             if (!IsElementArrayBufferSubjectIndex(index))
607             {
608                 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]);
609             }
610             onStateChange(angle::SubjectMessage::SubjectUnmapped);
611             break;
612 
613         default:
614             UNREACHABLE();
615             break;
616     }
617 }
618 
setDependentDirtyBit(bool contentsChanged,angle::SubjectIndex index)619 void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index)
620 {
621     DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index);
622     ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit));
623     mDirtyBits.set(dirtyBit);
624     onStateChange(angle::SubjectMessage::ContentsChanged);
625 }
626 
hasTransformFeedbackBindingConflict(const gl::Context * context) const627 bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const
628 {
629     // Fast check first.
630     if (!mCachedTransformFeedbackConflictedBindingsMask.any())
631     {
632         return false;
633     }
634 
635     const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask();
636 
637     // Slow check. We must ensure that the conflicting attributes are enabled/active.
638     for (size_t attribIndex : activeAttribues)
639     {
640         const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
641         if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex])
642         {
643             return true;
644         }
645     }
646 
647     return false;
648 }
649 
getIndexRangeImpl(const Context * context,DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut) const650 angle::Result VertexArray::getIndexRangeImpl(const Context *context,
651                                              DrawElementsType type,
652                                              GLsizei indexCount,
653                                              const void *indices,
654                                              IndexRange *indexRangeOut) const
655 {
656     Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get();
657     if (!elementArrayBuffer)
658     {
659         *indexRangeOut = ComputeIndexRange(type, indices, indexCount,
660                                            context->getState().isPrimitiveRestartEnabled());
661         return angle::Result::Continue;
662     }
663 
664     size_t offset = reinterpret_cast<uintptr_t>(indices);
665     ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount,
666                                                 context->getState().isPrimitiveRestartEnabled(),
667                                                 indexRangeOut));
668 
669     mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut);
670     return angle::Result::Continue;
671 }
672 
673 VertexArray::IndexRangeCache::IndexRangeCache() = default;
674 
put(DrawElementsType type,GLsizei indexCount,size_t offset,const IndexRange & indexRange)675 void VertexArray::IndexRangeCache::put(DrawElementsType type,
676                                        GLsizei indexCount,
677                                        size_t offset,
678                                        const IndexRange &indexRange)
679 {
680     ASSERT(type != DrawElementsType::InvalidEnum);
681 
682     mTypeKey       = type;
683     mIndexCountKey = indexCount;
684     mOffsetKey     = offset;
685     mPayload       = indexRange;
686 }
687 }  // namespace gl
688