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