• 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     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