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