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