• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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