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