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