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