VertexArray.cpp (33340B)
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 { 22 constexpr size_t kMaxObserverCountToTriggerUnobserve = 20; 23 24 bool IsElementArrayBufferSubjectIndex(angle::SubjectIndex subjectIndex) 25 { 26 return (subjectIndex == kElementArrayBufferIndex); 27 } 28 } // namespace 29 30 // VertexArrayState implementation. 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 48 VertexArrayState::~VertexArrayState() {} 49 50 bool VertexArrayState::hasEnabledNullPointerClientArray() const 51 { 52 return (mNullPointerClientMemoryAttribsMask & mEnabledAttributesMask).any(); 53 } 54 55 AttributesMask VertexArrayState::getBindingToAttributesMask(GLuint bindingIndex) const 56 { 57 ASSERT(bindingIndex < mVertexBindings.size()); 58 return mVertexBindings[bindingIndex].getBoundAttributesMask(); 59 } 60 61 // Set an attribute using a new binding. 62 void VertexArrayState::setAttribBinding(const Context *context, 63 size_t attribIndex, 64 GLuint newBindingIndex) 65 { 66 ASSERT(attribIndex < mVertexAttributes.size() && newBindingIndex < mVertexBindings.size()); 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 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. 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 mContentsObservers(this) 119 { 120 for (size_t attribIndex = 0; attribIndex < maxAttribBindings; ++attribIndex) 121 { 122 mArrayBufferObserverBindings.emplace_back(this, attribIndex); 123 } 124 125 mVertexArray->setContentsObservers(&mContentsObservers); 126 } 127 128 void VertexArray::onDestroy(const Context *context) 129 { 130 bool isBound = context->isCurrentVertexArray(this); 131 for (uint32_t bindingIndex = 0; bindingIndex < mState.mVertexBindings.size(); ++bindingIndex) 132 { 133 VertexBinding &binding = mState.mVertexBindings[bindingIndex]; 134 Buffer *buffer = binding.getBuffer().get(); 135 if (isBound) 136 { 137 if (buffer) 138 { 139 buffer->onNonTFBindingChanged(-1); 140 } 141 } 142 if (buffer) 143 { 144 // Note: the non-contents observer is unbound in the ObserverBinding destructor. 145 buffer->removeContentsObserver(this, bindingIndex); 146 } 147 binding.setBuffer(context, nullptr); 148 } 149 if (mState.mElementArrayBuffer.get()) 150 { 151 if (isBound) 152 { 153 mState.mElementArrayBuffer->onNonTFBindingChanged(-1); 154 } 155 mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex); 156 } 157 mState.mElementArrayBuffer.bind(context, nullptr); 158 159 // If mDirtyObserverBindingBits is set, it means we have removed it from the buffer's observer 160 // list. We should unassign subject to avoid assertion. 161 for (size_t bindingIndex : mDirtyObserverBindingBits) 162 { 163 angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex]; 164 observer->assignSubject(nullptr); 165 } 166 167 mVertexArray->destroy(context); 168 SafeDelete(mVertexArray); 169 delete this; 170 } 171 172 VertexArray::~VertexArray() 173 { 174 ASSERT(!mVertexArray); 175 } 176 177 angle::Result VertexArray::setLabel(const Context *context, const std::string &label) 178 { 179 mState.mLabel = label; 180 181 if (mVertexArray) 182 { 183 return mVertexArray->onLabelUpdate(context); 184 } 185 return angle::Result::Continue; 186 } 187 188 const std::string &VertexArray::getLabel() const 189 { 190 return mState.mLabel; 191 } 192 193 bool VertexArray::detachBuffer(const Context *context, BufferID bufferID) 194 { 195 bool isBound = context->isCurrentVertexArray(this); 196 bool anyBufferDetached = false; 197 for (uint32_t bindingIndex = 0; bindingIndex < mState.mVertexBindings.size(); ++bindingIndex) 198 { 199 VertexBinding &binding = mState.mVertexBindings[bindingIndex]; 200 const BindingPointer<Buffer> &bufferBinding = binding.getBuffer(); 201 if (bufferBinding.id() == bufferID) 202 { 203 if (isBound) 204 { 205 if (bufferBinding.get()) 206 bufferBinding->onNonTFBindingChanged(-1); 207 } 208 bufferBinding->removeContentsObserver(this, bindingIndex); 209 binding.setBuffer(context, nullptr); 210 mArrayBufferObserverBindings[bindingIndex].reset(); 211 212 if (context->getClientVersion() >= ES_3_1) 213 { 214 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER); 215 } 216 else 217 { 218 static_assert(gl::MAX_VERTEX_ATTRIB_BINDINGS < 8 * sizeof(uint32_t), 219 "Not enough bits in bindingIndex"); 220 // The redundant uint32_t cast here is required to avoid a warning on MSVC. 221 ASSERT(binding.getBoundAttributesMask() == 222 AttributesMask(static_cast<uint32_t>(1 << bindingIndex))); 223 setDirtyAttribBit(bindingIndex, DIRTY_ATTRIB_POINTER); 224 } 225 226 anyBufferDetached = true; 227 mState.mClientMemoryAttribsMask |= binding.getBoundAttributesMask(); 228 } 229 } 230 231 if (mState.mElementArrayBuffer.get() && mState.mElementArrayBuffer->id() == bufferID) 232 { 233 if (isBound && mState.mElementArrayBuffer.get()) 234 mState.mElementArrayBuffer->onNonTFBindingChanged(-1); 235 mState.mElementArrayBuffer->removeContentsObserver(this, kElementArrayBufferIndex); 236 mState.mElementArrayBuffer.bind(context, nullptr); 237 mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER); 238 anyBufferDetached = true; 239 } 240 241 return anyBufferDetached; 242 } 243 244 const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const 245 { 246 ASSERT(attribIndex < getMaxAttribs()); 247 return mState.mVertexAttributes[attribIndex]; 248 } 249 250 const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const 251 { 252 ASSERT(bindingIndex < getMaxBindings()); 253 return mState.mVertexBindings[bindingIndex]; 254 } 255 256 size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit) 257 { 258 static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, 259 "The stride of vertex attributes should equal to that of vertex bindings."); 260 ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER); 261 return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS; 262 } 263 264 ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex, 265 DirtyAttribBitType dirtyAttribBit) 266 { 267 mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex); 268 mDirtyAttribBits[attribIndex].set(dirtyAttribBit); 269 } 270 271 ANGLE_INLINE void VertexArray::clearDirtyAttribBit(size_t attribIndex, 272 DirtyAttribBitType dirtyAttribBit) 273 { 274 mDirtyAttribBits[attribIndex].set(dirtyAttribBit, false); 275 if (mDirtyAttribBits[attribIndex].any()) 276 { 277 return; 278 } 279 mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex, false); 280 } 281 282 ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex, 283 DirtyBindingBitType dirtyBindingBit) 284 { 285 mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex); 286 mDirtyBindingBits[bindingIndex].set(dirtyBindingBit); 287 } 288 289 ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding) 290 { 291 if (!mBufferAccessValidationEnabled) 292 return; 293 294 for (size_t boundAttribute : binding->getBoundAttributesMask()) 295 { 296 mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding); 297 } 298 } 299 300 ANGLE_INLINE void VertexArray::updateCachedArrayBuffersMasks( 301 bool isMapped, 302 bool isImmutable, 303 bool isPersistent, 304 const AttributesMask &boundAttributesMask) 305 { 306 if (isMapped) 307 { 308 mState.mCachedMappedArrayBuffers |= boundAttributesMask; 309 } 310 else 311 { 312 mState.mCachedMappedArrayBuffers &= ~boundAttributesMask; 313 } 314 315 if (!isImmutable || !isPersistent) 316 { 317 mState.mCachedMutableOrImpersistentArrayBuffers |= boundAttributesMask; 318 } 319 else 320 { 321 mState.mCachedMutableOrImpersistentArrayBuffers &= ~boundAttributesMask; 322 } 323 324 mState.mCachedInvalidMappedArrayBuffer = mState.mCachedMappedArrayBuffers & 325 mState.mEnabledAttributesMask & 326 mState.mCachedMutableOrImpersistentArrayBuffers; 327 } 328 329 ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffersBinding(const VertexBinding &binding) 330 { 331 const Buffer *buffer = binding.getBuffer().get(); 332 bool isMapped = buffer && buffer->isMapped(); 333 bool isImmutable = buffer && buffer->isImmutable(); 334 bool isPersistent = buffer && (buffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0; 335 return updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent, 336 binding.getBoundAttributesMask()); 337 } 338 339 ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex, 340 const Buffer *buffer) 341 { 342 const bool hasConflict = buffer && buffer->hasWebGLXFBBindingConflict(true); 343 mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict); 344 } 345 346 bool VertexArray::bindVertexBufferImpl(const Context *context, 347 size_t bindingIndex, 348 Buffer *boundBuffer, 349 GLintptr offset, 350 GLsizei stride) 351 { 352 ASSERT(bindingIndex < getMaxBindings()); 353 ASSERT(context->isCurrentVertexArray(this)); 354 355 VertexBinding *binding = &mState.mVertexBindings[bindingIndex]; 356 357 Buffer *oldBuffer = binding->getBuffer().get(); 358 359 const bool sameBuffer = oldBuffer == boundBuffer; 360 const bool sameStride = static_cast<GLuint>(stride) == binding->getStride(); 361 const bool sameOffset = offset == binding->getOffset(); 362 363 if (sameBuffer && sameStride && sameOffset) 364 { 365 return false; 366 } 367 368 angle::ObserverBinding *observer = &mArrayBufferObserverBindings[bindingIndex]; 369 observer->assignSubject(boundBuffer); 370 371 // Several nullptr checks are combined here for optimization purposes. 372 if (oldBuffer) 373 { 374 oldBuffer->onNonTFBindingChanged(-1); 375 oldBuffer->removeObserver(observer); 376 oldBuffer->removeContentsObserver(this, static_cast<uint32_t>(bindingIndex)); 377 oldBuffer->release(context); 378 } 379 380 binding->assignBuffer(boundBuffer); 381 binding->setOffset(offset); 382 binding->setStride(stride); 383 updateCachedBufferBindingSize(binding); 384 385 // Update client memory attribute pointers. Affects all bound attributes. 386 if (boundBuffer) 387 { 388 boundBuffer->addRef(); 389 boundBuffer->onNonTFBindingChanged(1); 390 boundBuffer->addObserver(observer); 391 if (context->isWebGL()) 392 { 393 mCachedTransformFeedbackConflictedBindingsMask.set( 394 bindingIndex, boundBuffer->hasWebGLXFBBindingConflict(true)); 395 } 396 mState.mClientMemoryAttribsMask &= ~binding->getBoundAttributesMask(); 397 398 bool isMapped = boundBuffer->isMapped() == GL_TRUE; 399 bool isImmutable = boundBuffer->isImmutable() == GL_TRUE; 400 bool isPersistent = (boundBuffer->getAccessFlags() & GL_MAP_PERSISTENT_BIT_EXT) != 0; 401 updateCachedArrayBuffersMasks(isMapped, isImmutable, isPersistent, 402 binding->getBoundAttributesMask()); 403 } 404 else 405 { 406 if (context->isWebGL()) 407 { 408 mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, false); 409 } 410 mState.mClientMemoryAttribsMask |= binding->getBoundAttributesMask(); 411 updateCachedArrayBuffersMasks(false, false, false, binding->getBoundAttributesMask()); 412 } 413 414 return true; 415 } 416 417 void VertexArray::bindVertexBuffer(const Context *context, 418 size_t bindingIndex, 419 Buffer *boundBuffer, 420 GLintptr offset, 421 GLsizei stride) 422 { 423 if (bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride)) 424 { 425 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER); 426 } 427 } 428 429 void VertexArray::setVertexAttribBinding(const Context *context, 430 size_t attribIndex, 431 GLuint bindingIndex) 432 { 433 ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings()); 434 435 if (mState.mVertexAttributes[attribIndex].bindingIndex == bindingIndex) 436 { 437 return; 438 } 439 440 // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable. 441 ASSERT(context->getClientVersion() >= ES_3_1); 442 443 mState.setAttribBinding(context, attribIndex, bindingIndex); 444 445 setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING); 446 447 // Update client attribs mask. 448 bool hasBuffer = mState.mVertexBindings[bindingIndex].getBuffer().get() != nullptr; 449 mState.mClientMemoryAttribsMask.set(attribIndex, !hasBuffer); 450 } 451 452 void VertexArray::setVertexBindingDivisor(const Context *context, 453 size_t bindingIndex, 454 GLuint divisor) 455 { 456 ASSERT(bindingIndex < getMaxBindings()); 457 458 VertexBinding &binding = mState.mVertexBindings[bindingIndex]; 459 460 if (binding.getDivisor() == divisor) 461 { 462 return; 463 } 464 465 binding.setDivisor(divisor); 466 setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR); 467 468 // Trigger updates in all bound attributes. 469 if (context->isBufferAccessValidationEnabled()) 470 { 471 for (size_t attribIndex : binding.getBoundAttributesMask()) 472 { 473 mState.mVertexAttributes[attribIndex].updateCachedElementLimit(binding); 474 } 475 } 476 } 477 478 ANGLE_INLINE bool VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib, 479 GLint size, 480 VertexAttribType type, 481 bool normalized, 482 bool pureInteger, 483 GLuint relativeOffset) 484 { 485 angle::FormatID formatID = gl::GetVertexFormatID(type, normalized, size, pureInteger); 486 487 if (formatID != attrib->format->id || attrib->relativeOffset != relativeOffset) 488 { 489 attrib->relativeOffset = relativeOffset; 490 attrib->format = &angle::Format::Get(formatID); 491 return true; 492 } 493 494 return false; 495 } 496 497 void VertexArray::setVertexAttribFormat(size_t attribIndex, 498 GLint size, 499 VertexAttribType type, 500 bool normalized, 501 bool pureInteger, 502 GLuint relativeOffset) 503 { 504 VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; 505 506 ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type); 507 SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask); 508 509 if (setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, relativeOffset)) 510 { 511 setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT); 512 } 513 514 attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]); 515 } 516 517 void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor) 518 { 519 ASSERT(attribIndex < getMaxAttribs()); 520 521 setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex)); 522 setVertexBindingDivisor(context, attribIndex, divisor); 523 } 524 525 void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) 526 { 527 ASSERT(attribIndex < getMaxAttribs()); 528 529 VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; 530 531 if (mState.mEnabledAttributesMask.test(attribIndex) == enabledState) 532 { 533 return; 534 } 535 536 attrib.enabled = enabledState; 537 538 // Update state cache 539 mState.mEnabledAttributesMask.set(attribIndex, enabledState); 540 bool enableChanged = (mState.mEnabledAttributesMask.test(attribIndex) != 541 mState.mLastSyncedEnabledAttributesMask.test(attribIndex)); 542 543 if (enableChanged) 544 { 545 setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED); 546 } 547 else 548 { 549 clearDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED); 550 } 551 552 mState.updateCachedMutableOrNonPersistentArrayBuffers(attribIndex); 553 mState.mCachedInvalidMappedArrayBuffer = mState.mCachedMappedArrayBuffers & 554 mState.mEnabledAttributesMask & 555 mState.mCachedMutableOrImpersistentArrayBuffers; 556 } 557 558 ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context, 559 ComponentType componentType, 560 bool pureInteger, 561 size_t attribIndex, 562 Buffer *boundBuffer, 563 GLint size, 564 VertexAttribType type, 565 bool normalized, 566 GLsizei stride, 567 const void *pointer) 568 { 569 ASSERT(attribIndex < getMaxAttribs()); 570 571 VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; 572 573 SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask); 574 575 bool attribDirty = setVertexAttribFormatImpl(&attrib, size, type, normalized, pureInteger, 0); 576 577 if (attrib.bindingIndex != attribIndex) 578 { 579 setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex)); 580 } 581 582 GLsizei effectiveStride = 583 stride == 0 ? static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)) : stride; 584 585 if (attrib.vertexAttribArrayStride != static_cast<GLuint>(stride)) 586 { 587 attribDirty = true; 588 } 589 attrib.vertexAttribArrayStride = stride; 590 591 // If we switch from an array buffer to a client pointer(or vice-versa), we set the whole 592 // attribute dirty. This notifies the Vulkan back-end to update all its caches. 593 const VertexBinding &binding = mState.mVertexBindings[attribIndex]; 594 if ((boundBuffer == nullptr) != (binding.getBuffer().get() == nullptr)) 595 { 596 attribDirty = true; 597 } 598 599 // Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset 600 // which is handled within bindVertexBufferImpl and reflected in bufferDirty. 601 attrib.pointer = pointer; 602 GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0; 603 const bool bufferDirty = 604 bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride); 605 606 if (attribDirty) 607 { 608 setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER); 609 } 610 else if (bufferDirty) 611 { 612 setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER); 613 } 614 615 mState.mNullPointerClientMemoryAttribsMask.set(attribIndex, 616 boundBuffer == nullptr && pointer == nullptr); 617 } 618 619 void VertexArray::setVertexAttribPointer(const Context *context, 620 size_t attribIndex, 621 gl::Buffer *boundBuffer, 622 GLint size, 623 VertexAttribType type, 624 bool normalized, 625 GLsizei stride, 626 const void *pointer) 627 { 628 setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size, 629 type, normalized, stride, pointer); 630 } 631 632 void VertexArray::setVertexAttribIPointer(const Context *context, 633 size_t attribIndex, 634 gl::Buffer *boundBuffer, 635 GLint size, 636 VertexAttribType type, 637 GLsizei stride, 638 const void *pointer) 639 { 640 ComponentType componentType = GetVertexAttributeComponentType(true, type); 641 setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type, 642 false, stride, pointer); 643 } 644 645 angle::Result VertexArray::syncState(const Context *context) 646 { 647 if (mDirtyBits.any()) 648 { 649 mDirtyBitsGuard = mDirtyBits; 650 ANGLE_TRY( 651 mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits)); 652 mDirtyBits.reset(); 653 mDirtyBitsGuard.reset(); 654 655 // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0. 656 ASSERT(mDirtyAttribBits[0].none()); 657 ASSERT(mDirtyBindingBits[0].none()); 658 mState.mLastSyncedEnabledAttributesMask = mState.mEnabledAttributesMask; 659 } 660 return angle::Result::Continue; 661 } 662 663 // This becomes current vertex array on the context 664 void VertexArray::onBind(const Context *context) 665 { 666 if (mDirtyObserverBindingBits.none()) 667 { 668 return; 669 } 670 671 // This vertex array becoming current. Some of the bindings we may have removed from buffer's 672 // observer list. We need to add it back to the buffer's observer list and update dirty bits 673 // that we may have missed while we were not observing. 674 for (size_t bindingIndex : mDirtyObserverBindingBits) 675 { 676 const gl::VertexBinding &binding = mState.getVertexBindings()[bindingIndex]; 677 gl::Buffer *bufferGL = binding.getBuffer().get(); 678 ASSERT(bufferGL != nullptr); 679 680 bufferGL->addObserver(&mArrayBufferObserverBindings[bindingIndex]); 681 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[bindingIndex]); 682 683 // Assume both data and internal storage has been dirtied. 684 mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex); 685 686 if (mBufferAccessValidationEnabled) 687 { 688 for (size_t boundAttribute : 689 mState.mVertexBindings[bindingIndex].getBoundAttributesMask()) 690 { 691 mState.mVertexAttributes[boundAttribute].updateCachedElementLimit( 692 mState.mVertexBindings[bindingIndex]); 693 } 694 } 695 696 if (context->isWebGL()) 697 { 698 updateCachedTransformFeedbackBindingValidation(bindingIndex, bufferGL); 699 } 700 } 701 mDirtyObserverBindingBits.reset(); 702 703 onStateChange(angle::SubjectMessage::ContentsChanged); 704 } 705 706 // This becomes non-current vertex array on the context 707 void VertexArray::onUnbind(const Context *context) 708 { 709 // This vertex array becoming non-current. For performance reason, if there are too many 710 // observers in the buffer, we remove it from the buffers' observer list so that the cost of 711 // buffer sending signal to observers will be too expensive. 712 for (uint32_t bindingIndex = 0; bindingIndex < mArrayBufferObserverBindings.size(); 713 ++bindingIndex) 714 { 715 const gl::VertexBinding &binding = mState.getVertexBindings()[bindingIndex]; 716 gl::Buffer *bufferGL = binding.getBuffer().get(); 717 if (bufferGL && bufferGL->getObserversCount() > kMaxObserverCountToTriggerUnobserve) 718 { 719 bufferGL->removeObserver(&mArrayBufferObserverBindings[bindingIndex]); 720 mDirtyObserverBindingBits.set(bindingIndex); 721 } 722 } 723 } 724 725 void VertexArray::onBindingChanged(const Context *context, int incr) 726 { 727 // When vertex array gets unbound, we remove it from bound buffers' observer list so that when 728 // buffer changes, it wont has to loop over all these non-current vertex arrays and set dirty 729 // bit on them. To compensate for that, when we bind a vertex array, we have to check against 730 // each bound buffers and see if they have changed and needs to update vertex array's dirty bits 731 // accordingly 732 ASSERT(incr == 1 || incr == -1); 733 if (incr < 0) 734 { 735 onUnbind(context); 736 } 737 else 738 { 739 onBind(context); 740 } 741 742 if (context->isWebGL()) 743 { 744 if (mState.mElementArrayBuffer.get()) 745 mState.mElementArrayBuffer->onNonTFBindingChanged(incr); 746 for (auto &binding : mState.mVertexBindings) 747 { 748 binding.onContainerBindingChanged(context, incr); 749 } 750 } 751 } 752 753 VertexArray::DirtyBitType VertexArray::getDirtyBitFromIndex(bool contentsChanged, 754 angle::SubjectIndex index) const 755 { 756 if (IsElementArrayBufferSubjectIndex(index)) 757 { 758 mIndexRangeCache.invalidate(); 759 return contentsChanged ? DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA 760 : DIRTY_BIT_ELEMENT_ARRAY_BUFFER; 761 } 762 else 763 { 764 // Note: this currently just gets the top-level dirty bit. 765 ASSERT(index < mArrayBufferObserverBindings.size()); 766 return static_cast<DirtyBitType>( 767 (contentsChanged ? DIRTY_BIT_BUFFER_DATA_0 : DIRTY_BIT_BINDING_0) + index); 768 } 769 } 770 771 void VertexArray::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) 772 { 773 switch (message) 774 { 775 case angle::SubjectMessage::SubjectChanged: 776 if (!IsElementArrayBufferSubjectIndex(index)) 777 { 778 updateCachedBufferBindingSize(&mState.mVertexBindings[index]); 779 } 780 setDependentDirtyBit(false, index); 781 break; 782 783 case angle::SubjectMessage::BindingChanged: 784 if (!IsElementArrayBufferSubjectIndex(index)) 785 { 786 const Buffer *buffer = mState.mVertexBindings[index].getBuffer().get(); 787 updateCachedTransformFeedbackBindingValidation(index, buffer); 788 } 789 break; 790 791 case angle::SubjectMessage::SubjectMapped: 792 if (!IsElementArrayBufferSubjectIndex(index)) 793 { 794 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]); 795 } 796 onStateChange(angle::SubjectMessage::SubjectMapped); 797 break; 798 799 case angle::SubjectMessage::SubjectUnmapped: 800 setDependentDirtyBit(true, index); 801 802 if (!IsElementArrayBufferSubjectIndex(index)) 803 { 804 updateCachedMappedArrayBuffersBinding(mState.mVertexBindings[index]); 805 } 806 onStateChange(angle::SubjectMessage::SubjectUnmapped); 807 break; 808 809 case angle::SubjectMessage::InternalMemoryAllocationChanged: 810 setDependentDirtyBit(false, index); 811 break; 812 813 default: 814 UNREACHABLE(); 815 break; 816 } 817 } 818 819 void VertexArray::setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index) 820 { 821 DirtyBitType dirtyBit = getDirtyBitFromIndex(contentsChanged, index); 822 ASSERT(!mDirtyBitsGuard.valid() || mDirtyBitsGuard.value().test(dirtyBit)); 823 mDirtyBits.set(dirtyBit); 824 onStateChange(angle::SubjectMessage::ContentsChanged); 825 } 826 827 bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const 828 { 829 // Fast check first. 830 if (!mCachedTransformFeedbackConflictedBindingsMask.any()) 831 { 832 return false; 833 } 834 835 const AttributesMask &activeAttribues = context->getStateCache().getActiveBufferedAttribsMask(); 836 837 // Slow check. We must ensure that the conflicting attributes are enabled/active. 838 for (size_t attribIndex : activeAttribues) 839 { 840 const VertexAttribute &attrib = mState.mVertexAttributes[attribIndex]; 841 if (mCachedTransformFeedbackConflictedBindingsMask[attrib.bindingIndex]) 842 { 843 return true; 844 } 845 } 846 847 return false; 848 } 849 850 angle::Result VertexArray::getIndexRangeImpl(const Context *context, 851 DrawElementsType type, 852 GLsizei indexCount, 853 const void *indices, 854 IndexRange *indexRangeOut) const 855 { 856 Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get(); 857 if (!elementArrayBuffer) 858 { 859 *indexRangeOut = ComputeIndexRange(type, indices, indexCount, 860 context->getState().isPrimitiveRestartEnabled()); 861 return angle::Result::Continue; 862 } 863 864 size_t offset = reinterpret_cast<uintptr_t>(indices); 865 ANGLE_TRY(elementArrayBuffer->getIndexRange(context, type, offset, indexCount, 866 context->getState().isPrimitiveRestartEnabled(), 867 indexRangeOut)); 868 869 mIndexRangeCache.put(type, indexCount, offset, *indexRangeOut); 870 return angle::Result::Continue; 871 } 872 873 VertexArray::IndexRangeCache::IndexRangeCache() = default; 874 875 void VertexArray::IndexRangeCache::put(DrawElementsType type, 876 GLsizei indexCount, 877 size_t offset, 878 const IndexRange &indexRange) 879 { 880 ASSERT(type != DrawElementsType::InvalidEnum); 881 882 mTypeKey = type; 883 mIndexCountKey = indexCount; 884 mOffsetKey = offset; 885 mPayload = indexRange; 886 } 887 888 void VertexArray::onBufferContentsChange(uint32_t bufferIndex) 889 { 890 setDependentDirtyBit(true, bufferIndex); 891 } 892 893 VertexArrayBufferContentsObservers::VertexArrayBufferContentsObservers(VertexArray *vertexArray) 894 : mVertexArray(vertexArray) 895 {} 896 897 void VertexArrayBufferContentsObservers::enableForBuffer(Buffer *buffer, uint32_t bufferIndex) 898 { 899 buffer->addContentsObserver(mVertexArray, bufferIndex); 900 } 901 902 void VertexArrayBufferContentsObservers::disableForBuffer(Buffer *buffer, uint32_t bufferIndex) 903 { 904 buffer->removeContentsObserver(mVertexArray, bufferIndex); 905 } 906 } // namespace gl