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