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