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 // This class contains prototypes for representing GLES 3 Vertex Array Objects: 7 // 8 // The buffer objects that are to be used by the vertex stage of the GL are collected 9 // together to form a vertex array object. All state related to the definition of data used 10 // by the vertex processor is encapsulated in a vertex array object. 11 // 12 13 #ifndef LIBANGLE_VERTEXARRAY_H_ 14 #define LIBANGLE_VERTEXARRAY_H_ 15 16 #include "common/Optional.h" 17 #include "libANGLE/Constants.h" 18 #include "libANGLE/Debug.h" 19 #include "libANGLE/Observer.h" 20 #include "libANGLE/RefCountObject.h" 21 #include "libANGLE/VertexAttribute.h" 22 23 #include <vector> 24 25 namespace rx 26 { 27 class GLImplFactory; 28 class VertexArrayImpl; 29 } // namespace rx 30 31 namespace gl 32 { 33 class Buffer; 34 35 constexpr uint32_t kElementArrayBufferIndex = MAX_VERTEX_ATTRIBS; 36 37 class VertexArrayState final : angle::NonCopyable 38 { 39 public: 40 VertexArrayState(VertexArray *vertexArray, size_t maxAttribs, size_t maxBindings); 41 ~VertexArrayState(); 42 getLabel()43 const std::string &getLabel() const { return mLabel; } 44 getElementArrayBuffer()45 Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } getMaxAttribs()46 size_t getMaxAttribs() const { return mVertexAttributes.size(); } getMaxBindings()47 size_t getMaxBindings() const { return mVertexBindings.size(); } getEnabledAttributesMask()48 const AttributesMask &getEnabledAttributesMask() const { return mEnabledAttributesMask; } getVertexAttributes()49 const std::vector<VertexAttribute> &getVertexAttributes() const { return mVertexAttributes; } getVertexAttribute(size_t attribIndex)50 const VertexAttribute &getVertexAttribute(size_t attribIndex) const 51 { 52 return mVertexAttributes[attribIndex]; 53 } getVertexBindings()54 const std::vector<VertexBinding> &getVertexBindings() const { return mVertexBindings; } getVertexBinding(size_t bindingIndex)55 const VertexBinding &getVertexBinding(size_t bindingIndex) const 56 { 57 return mVertexBindings[bindingIndex]; 58 } getBindingFromAttribIndex(size_t attribIndex)59 const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const 60 { 61 return mVertexBindings[mVertexAttributes[attribIndex].bindingIndex]; 62 } getBindingIndexFromAttribIndex(size_t attribIndex)63 size_t getBindingIndexFromAttribIndex(size_t attribIndex) const 64 { 65 return mVertexAttributes[attribIndex].bindingIndex; 66 } 67 68 void setAttribBinding(const Context *context, size_t attribIndex, GLuint newBindingIndex); 69 70 // Extra validation performed on the Vertex Array. 71 bool hasEnabledNullPointerClientArray() const; 72 73 // Get all the attributes in an AttributesMask that are using the given binding. 74 AttributesMask getBindingToAttributesMask(GLuint bindingIndex) const; 75 getVertexAttributesTypeMask()76 ComponentTypeMask getVertexAttributesTypeMask() const { return mVertexAttributesTypeMask; } 77 getClientMemoryAttribsMask()78 AttributesMask getClientMemoryAttribsMask() const { return mClientMemoryAttribsMask; } 79 getNullPointerClientMemoryAttribsMask()80 AttributesMask getNullPointerClientMemoryAttribsMask() const 81 { 82 return mNullPointerClientMemoryAttribsMask; 83 } 84 getBufferBindingMask()85 VertexArrayBufferBindingMask getBufferBindingMask() const { return mBufferBindingMask; } 86 id()87 VertexArrayID id() const { return mId; } 88 89 bool isDefault() const; 90 91 private: 92 void updateCachedMutableOrNonPersistentArrayBuffers(size_t index); 93 94 friend class VertexArray; 95 VertexArrayID mId; 96 std::string mLabel; 97 std::vector<VertexAttribute> mVertexAttributes; 98 SubjectBindingPointer<Buffer> mElementArrayBuffer; 99 std::vector<VertexBinding> mVertexBindings; 100 AttributesMask mEnabledAttributesMask; 101 ComponentTypeMask mVertexAttributesTypeMask; 102 AttributesMask mLastSyncedEnabledAttributesMask; 103 104 // Track which binding index has a buffer bound 105 VertexArrayBufferBindingMask mBufferBindingMask; 106 107 // This is a performance optimization for buffer binding. Allows element array buffer updates. 108 friend class State; 109 110 // From the GLES 3.1 spec: 111 // When a generic attribute array is sourced from client memory, the vertex attribute binding 112 // state is ignored. Thus we don't have to worry about binding state when using client memory 113 // attribs. 114 AttributesMask mClientMemoryAttribsMask; 115 AttributesMask mNullPointerClientMemoryAttribsMask; 116 117 // Used for validation cache. Indexed by attribute. 118 AttributesMask mCachedMappedArrayBuffers; 119 AttributesMask mCachedMutableOrImpersistentArrayBuffers; 120 AttributesMask mCachedInvalidMappedArrayBuffer; 121 }; 122 123 class VertexArrayBufferContentsObservers final : angle::NonCopyable 124 { 125 public: 126 VertexArrayBufferContentsObservers(VertexArray *vertexArray); 127 void enableForBuffer(Buffer *buffer, uint32_t bufferIndex); 128 void disableForBuffer(Buffer *buffer, uint32_t bufferIndex); any()129 bool any() const { return mBufferObserversBitMask.any(); } 130 131 private: 132 VertexArray *mVertexArray; 133 // Bit is set when it is observing the buffer content change 134 gl::AttributesMask mBufferObserversBitMask; 135 }; 136 137 class VertexArray final : public angle::ObserverInterface, 138 public LabeledObject, 139 public angle::Subject 140 { 141 public: 142 // Dirty bits for VertexArrays use a hierarchical design. At the top level, each attribute 143 // has a single dirty bit. Then an array of MAX_ATTRIBS dirty bits each has a dirty bit for 144 // enabled/pointer/format/binding. Bindings are handled similarly. Note that because the 145 // total number of dirty bits is 33, it will not be as fast on a 32-bit machine, which 146 // can't support the advanced 64-bit scanning intrinsics. We could consider packing the 147 // binding and attribute bits together if this becomes a problem. 148 // 149 // Special note on "DIRTY_ATTRIB_POINTER_BUFFER": this is a special case when the app 150 // calls glVertexAttribPointer but only changes a VBO and/or offset binding. This allows 151 // the Vulkan back-end to skip performing a pipeline change for performance. 152 enum DirtyBitType 153 { 154 // This vertex array has lost buffer observation. Check against actual buffer storage is 155 // required. 156 DIRTY_BIT_LOST_OBSERVATION, 157 158 DIRTY_BIT_ELEMENT_ARRAY_BUFFER, 159 DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA, 160 161 // Dirty bits for bindings. 162 DIRTY_BIT_BINDING_0, 163 DIRTY_BIT_BINDING_MAX = DIRTY_BIT_BINDING_0 + MAX_VERTEX_ATTRIB_BINDINGS, 164 165 // We keep separate dirty bits for bound buffers whose data changed since last update. 166 DIRTY_BIT_BUFFER_DATA_0 = DIRTY_BIT_BINDING_MAX, 167 DIRTY_BIT_BUFFER_DATA_MAX = DIRTY_BIT_BUFFER_DATA_0 + MAX_VERTEX_ATTRIB_BINDINGS, 168 169 // Dirty bits for attributes. 170 DIRTY_BIT_ATTRIB_0 = DIRTY_BIT_BUFFER_DATA_MAX, 171 DIRTY_BIT_ATTRIB_MAX = DIRTY_BIT_ATTRIB_0 + MAX_VERTEX_ATTRIBS, 172 173 DIRTY_BIT_UNKNOWN = DIRTY_BIT_ATTRIB_MAX, 174 DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, 175 }; 176 177 // We want to keep the number of dirty bits within 64 to keep iteration times fast. 178 static_assert(DIRTY_BIT_MAX <= 64, "Too many vertex array dirty bits."); 179 // The dirty bit processing has the logic to avoid redundant processing by removing other dirty 180 // bits when it processes dirtyBits. This assertion ensures these dirty bit order matches what 181 // VertexArrayVk::syncState expects. 182 static_assert(DIRTY_BIT_BINDING_0 < DIRTY_BIT_BUFFER_DATA_0, 183 "BINDING dirty bits should come before DATA."); 184 static_assert(DIRTY_BIT_BUFFER_DATA_0 < DIRTY_BIT_ATTRIB_0, 185 "DATA dirty bits should come before ATTRIB."); 186 static_assert(DIRTY_BIT_LOST_OBSERVATION < DIRTY_BIT_BINDING_0, 187 "LOST_OBSERVATION dirty bits should come before BINDING."); 188 189 enum DirtyAttribBitType 190 { 191 DIRTY_ATTRIB_ENABLED, 192 DIRTY_ATTRIB_POINTER, 193 DIRTY_ATTRIB_FORMAT, 194 DIRTY_ATTRIB_BINDING, 195 DIRTY_ATTRIB_POINTER_BUFFER, 196 DIRTY_ATTRIB_MAX, 197 }; 198 199 enum DirtyBindingBitType 200 { 201 DIRTY_BINDING_BUFFER, 202 DIRTY_BINDING_DIVISOR, 203 DIRTY_BINDING_STRIDE, 204 DIRTY_BINDING_OFFSET, 205 DIRTY_BINDING_MAX, 206 }; 207 208 using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>; 209 using DirtyAttribBits = angle::BitSet<DIRTY_ATTRIB_MAX>; 210 using DirtyBindingBits = angle::BitSet<DIRTY_BINDING_MAX>; 211 using DirtyAttribBitsArray = std::array<DirtyAttribBits, MAX_VERTEX_ATTRIBS>; 212 using DirtyBindingBitsArray = std::array<DirtyBindingBits, MAX_VERTEX_ATTRIB_BINDINGS>; 213 using DirtyObserverBindingBits = angle::BitSet<MAX_VERTEX_ATTRIB_BINDINGS>; 214 215 VertexArray(rx::GLImplFactory *factory, 216 VertexArrayID id, 217 size_t maxAttribs, 218 size_t maxAttribBindings); 219 220 void onDestroy(const Context *context); 221 id()222 VertexArrayID id() const { return mId; } 223 224 angle::Result setLabel(const Context *context, const std::string &label) override; 225 const std::string &getLabel() const override; 226 227 const VertexBinding &getVertexBinding(size_t bindingIndex) const; 228 const VertexAttribute &getVertexAttribute(size_t attribIndex) const; getBindingFromAttribIndex(size_t attribIndex)229 const VertexBinding &getBindingFromAttribIndex(size_t attribIndex) const 230 { 231 return mState.getBindingFromAttribIndex(attribIndex); 232 } 233 234 // Returns true if the function finds and detaches a bound buffer. 235 bool detachBuffer(const Context *context, BufferID bufferID); 236 237 void setVertexAttribDivisor(const Context *context, size_t index, GLuint divisor); 238 void enableAttribute(size_t attribIndex, bool enabledState); 239 240 void setVertexAttribPointer(const Context *context, 241 size_t attribIndex, 242 Buffer *boundBuffer, 243 GLint size, 244 VertexAttribType type, 245 bool normalized, 246 GLsizei stride, 247 const void *pointer); 248 249 void setVertexAttribIPointer(const Context *context, 250 size_t attribIndex, 251 Buffer *boundBuffer, 252 GLint size, 253 VertexAttribType type, 254 GLsizei stride, 255 const void *pointer); 256 257 void setVertexAttribFormat(size_t attribIndex, 258 GLint size, 259 VertexAttribType type, 260 bool normalized, 261 bool pureInteger, 262 GLuint relativeOffset); 263 void bindVertexBuffer(const Context *context, 264 size_t bindingIndex, 265 Buffer *boundBuffer, 266 GLintptr offset, 267 GLsizei stride); 268 void setVertexAttribBinding(const Context *context, size_t attribIndex, GLuint bindingIndex); 269 void setVertexBindingDivisor(const Context *context, size_t bindingIndex, GLuint divisor); 270 getElementArrayBuffer()271 Buffer *getElementArrayBuffer() const { return mState.getElementArrayBuffer(); } getMaxAttribs()272 size_t getMaxAttribs() const { return mState.getMaxAttribs(); } getMaxBindings()273 size_t getMaxBindings() const { return mState.getMaxBindings(); } 274 getVertexAttributes()275 const std::vector<VertexAttribute> &getVertexAttributes() const 276 { 277 return mState.getVertexAttributes(); 278 } getVertexBindings()279 const std::vector<VertexBinding> &getVertexBindings() const 280 { 281 return mState.getVertexBindings(); 282 } 283 getImplementation()284 rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } 285 getEnabledAttributesMask()286 const AttributesMask &getEnabledAttributesMask() const 287 { 288 return mState.getEnabledAttributesMask(); 289 } 290 getClientAttribsMask()291 AttributesMask getClientAttribsMask() const { return mState.mClientMemoryAttribsMask; } 292 hasEnabledNullPointerClientArray()293 bool hasEnabledNullPointerClientArray() const 294 { 295 return mState.hasEnabledNullPointerClientArray(); 296 } 297 hasInvalidMappedArrayBuffer()298 bool hasInvalidMappedArrayBuffer() const 299 { 300 return mState.mCachedInvalidMappedArrayBuffer.any(); 301 } 302 getState()303 const VertexArrayState &getState() const { return mState; } 304 isBufferAccessValidationEnabled()305 bool isBufferAccessValidationEnabled() const { return mBufferAccessValidationEnabled; } 306 307 // Observer implementation 308 void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override; 309 void onBufferContentsChange(uint32_t bufferIndex); 310 311 static size_t GetVertexIndexFromDirtyBit(size_t dirtyBit); 312 313 angle::Result syncState(const Context *context); hasAnyDirtyBit()314 bool hasAnyDirtyBit() const { return mDirtyBits.any(); } 315 getAttributesTypeMask()316 ComponentTypeMask getAttributesTypeMask() const { return mState.mVertexAttributesTypeMask; } getAttributesMask()317 AttributesMask getAttributesMask() const { return mState.mEnabledAttributesMask; } 318 319 void onBindingChanged(const Context *context, int incr); 320 bool hasTransformFeedbackBindingConflict(const Context *context) const; 321 getIndexRange(const Context * context,DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut)322 ANGLE_INLINE angle::Result getIndexRange(const Context *context, 323 DrawElementsType type, 324 GLsizei indexCount, 325 const void *indices, 326 IndexRange *indexRangeOut) const 327 { 328 Buffer *elementArrayBuffer = mState.mElementArrayBuffer.get(); 329 if (elementArrayBuffer && mIndexRangeCache.get(type, indexCount, indices, indexRangeOut)) 330 { 331 return angle::Result::Continue; 332 } 333 334 return getIndexRangeImpl(context, type, indexCount, indices, indexRangeOut); 335 } 336 setBufferAccessValidationEnabled(bool enabled)337 void setBufferAccessValidationEnabled(bool enabled) 338 { 339 mBufferAccessValidationEnabled = enabled; 340 } 341 342 private: 343 ~VertexArray() override; 344 345 // This is a performance optimization for buffer binding. Allows element array buffer updates. 346 friend class State; 347 348 void setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit); 349 void setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit); 350 void clearDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit); 351 352 DirtyBitType getDirtyBitFromIndex(bool contentsChanged, angle::SubjectIndex index) const; 353 void setDependentDirtyBit(bool contentsChanged, angle::SubjectIndex index); 354 355 // These are used to optimize draw call validation. 356 void updateCachedBufferBindingSize(VertexBinding *binding); 357 void updateCachedTransformFeedbackBindingValidation(size_t bindingIndex, const Buffer *buffer); 358 void updateCachedArrayBuffersMasks(bool isMapped, 359 bool isImmutable, 360 bool isPersistent, 361 const AttributesMask &boundAttributesMask); 362 void updateCachedMappedArrayBuffersBinding(const VertexBinding &binding); 363 364 angle::Result getIndexRangeImpl(const Context *context, 365 DrawElementsType type, 366 GLsizei indexCount, 367 const void *indices, 368 IndexRange *indexRangeOut) const; 369 370 void setVertexAttribPointerImpl(const Context *context, 371 ComponentType componentType, 372 bool pureInteger, 373 size_t attribIndex, 374 Buffer *boundBuffer, 375 GLint size, 376 VertexAttribType type, 377 bool normalized, 378 GLsizei stride, 379 const void *pointer); 380 381 // These two functions return true if the state was dirty. 382 bool setVertexAttribFormatImpl(VertexAttribute *attrib, 383 GLint size, 384 VertexAttribType type, 385 bool normalized, 386 bool pureInteger, 387 GLuint relativeOffset); 388 389 DirtyBindingBits bindVertexBufferImpl(const Context *context, 390 size_t bindingIndex, 391 Buffer *boundBuffer, 392 GLintptr offset, 393 GLsizei stride); 394 395 void onBind(const Context *context); 396 void onUnbind(const Context *context); 397 398 VertexArrayID mId; 399 400 VertexArrayState mState; 401 DirtyBits mDirtyBits; 402 DirtyAttribBitsArray mDirtyAttribBits; 403 DirtyBindingBitsArray mDirtyBindingBits; 404 Optional<DirtyBits> mDirtyBitsGuard; 405 406 rx::VertexArrayImpl *mVertexArray; 407 408 std::vector<angle::ObserverBinding> mArrayBufferObserverBindings; 409 410 AttributesMask mCachedTransformFeedbackConflictedBindingsMask; 411 412 class IndexRangeCache final : angle::NonCopyable 413 { 414 public: 415 IndexRangeCache(); 416 invalidate()417 void invalidate() { mTypeKey = DrawElementsType::InvalidEnum; } 418 get(DrawElementsType type,GLsizei indexCount,const void * indices,IndexRange * indexRangeOut)419 bool get(DrawElementsType type, 420 GLsizei indexCount, 421 const void *indices, 422 IndexRange *indexRangeOut) 423 { 424 size_t offset = reinterpret_cast<uintptr_t>(indices); 425 if (mTypeKey == type && mIndexCountKey == indexCount && mOffsetKey == offset) 426 { 427 *indexRangeOut = mPayload; 428 return true; 429 } 430 431 return false; 432 } 433 434 void put(DrawElementsType type, 435 GLsizei indexCount, 436 size_t offset, 437 const IndexRange &indexRange); 438 439 private: 440 DrawElementsType mTypeKey; 441 GLsizei mIndexCountKey; 442 size_t mOffsetKey; 443 IndexRange mPayload; 444 }; 445 446 mutable IndexRangeCache mIndexRangeCache; 447 bool mBufferAccessValidationEnabled; 448 VertexArrayBufferContentsObservers mContentsObservers; 449 }; 450 451 } // namespace gl 452 453 #endif // LIBANGLE_VERTEXARRAY_H_ 454