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