1 //
2 // Copyright (c) 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 // Implementation of the state class for mananging GLES 3 Vertex Array Objects.
7 //
8 
9 #include "libANGLE/VertexArray.h"
10 #include "libANGLE/Buffer.h"
11 #include "libANGLE/Context.h"
12 #include "libANGLE/renderer/GLImplFactory.h"
13 #include "libANGLE/renderer/VertexArrayImpl.h"
14 
15 namespace gl
16 {
17 
VertexArrayState(size_t maxAttribs,size_t maxAttribBindings)18 VertexArrayState::VertexArrayState(size_t maxAttribs, size_t maxAttribBindings)
19     : mLabel(), mVertexBindings(maxAttribBindings), mMaxEnabledAttribute(0)
20 {
21     ASSERT(maxAttribs <= maxAttribBindings);
22 
23     for (size_t i = 0; i < maxAttribs; i++)
24     {
25         mVertexAttributes.emplace_back(static_cast<GLuint>(i));
26     }
27 }
28 
~VertexArrayState()29 VertexArrayState::~VertexArrayState()
30 {
31 }
32 
VertexArray(rx::GLImplFactory * factory,GLuint id,size_t maxAttribs,size_t maxAttribBindings)33 VertexArray::VertexArray(rx::GLImplFactory *factory,
34                          GLuint id,
35                          size_t maxAttribs,
36                          size_t maxAttribBindings)
37     : mId(id),
38       mState(maxAttribs, maxAttribBindings),
39       mVertexArray(factory->createVertexArray(mState))
40 {
41 }
42 
onDestroy(const Context * context)43 void VertexArray::onDestroy(const Context *context)
44 {
45     for (auto &binding : mState.mVertexBindings)
46     {
47         binding.setBuffer(context, nullptr);
48     }
49     mState.mElementArrayBuffer.set(context, nullptr);
50     mVertexArray->destroy(context);
51     SafeDelete(mVertexArray);
52     delete this;
53 }
54 
~VertexArray()55 VertexArray::~VertexArray()
56 {
57     ASSERT(!mVertexArray);
58 }
59 
id() const60 GLuint VertexArray::id() const
61 {
62     return mId;
63 }
64 
setLabel(const std::string & label)65 void VertexArray::setLabel(const std::string &label)
66 {
67     mState.mLabel = label;
68 }
69 
getLabel() const70 const std::string &VertexArray::getLabel() const
71 {
72     return mState.mLabel;
73 }
74 
detachBuffer(const Context * context,GLuint bufferName)75 void VertexArray::detachBuffer(const Context *context, GLuint bufferName)
76 {
77     for (auto &binding : mState.mVertexBindings)
78     {
79         if (binding.getBuffer().id() == bufferName)
80         {
81             binding.setBuffer(context, nullptr);
82         }
83     }
84 
85     if (mState.mElementArrayBuffer.id() == bufferName)
86     {
87         mState.mElementArrayBuffer.set(context, nullptr);
88     }
89 }
90 
getVertexAttribute(size_t attribIndex) const91 const VertexAttribute &VertexArray::getVertexAttribute(size_t attribIndex) const
92 {
93     ASSERT(attribIndex < getMaxAttribs());
94     return mState.mVertexAttributes[attribIndex];
95 }
96 
getVertexBinding(size_t bindingIndex) const97 const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
98 {
99     ASSERT(bindingIndex < getMaxBindings());
100     return mState.mVertexBindings[bindingIndex];
101 }
102 
GetVertexIndexFromDirtyBit(size_t dirtyBit)103 size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
104 {
105     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
106                   "The stride of vertex attributes should equal to that of vertex bindings.");
107     ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
108     return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS;
109 }
110 
bindVertexBufferImpl(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)111 void VertexArray::bindVertexBufferImpl(const Context *context,
112                                        size_t bindingIndex,
113                                        Buffer *boundBuffer,
114                                        GLintptr offset,
115                                        GLsizei stride)
116 {
117     ASSERT(bindingIndex < getMaxBindings());
118 
119     VertexBinding *binding = &mState.mVertexBindings[bindingIndex];
120 
121     binding->setBuffer(context, boundBuffer);
122     binding->setOffset(offset);
123     binding->setStride(stride);
124 }
125 
bindVertexBuffer(const Context * context,size_t bindingIndex,Buffer * boundBuffer,GLintptr offset,GLsizei stride)126 void VertexArray::bindVertexBuffer(const Context *context,
127                                    size_t bindingIndex,
128                                    Buffer *boundBuffer,
129                                    GLintptr offset,
130                                    GLsizei stride)
131 {
132     bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride);
133 
134     mDirtyBits.set(DIRTY_BIT_BINDING_0_BUFFER + bindingIndex);
135 }
136 
setVertexAttribBinding(const Context * context,size_t attribIndex,GLuint bindingIndex)137 void VertexArray::setVertexAttribBinding(const Context *context,
138                                          size_t attribIndex,
139                                          GLuint bindingIndex)
140 {
141     ASSERT(attribIndex < getMaxAttribs() && bindingIndex < getMaxBindings());
142 
143     if (mState.mVertexAttributes[attribIndex].bindingIndex != bindingIndex)
144     {
145         // In ES 3.0 contexts, the binding cannot change, hence the code below is unreachable.
146         ASSERT(context->getClientVersion() >= ES_3_1);
147         mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex;
148 
149         mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex);
150     }
151 }
152 
setVertexBindingDivisor(size_t bindingIndex,GLuint divisor)153 void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
154 {
155     ASSERT(bindingIndex < getMaxBindings());
156 
157     mState.mVertexBindings[bindingIndex].setDivisor(divisor);
158 
159     mDirtyBits.set(DIRTY_BIT_BINDING_0_DIVISOR + bindingIndex);
160 }
161 
setVertexAttribFormatImpl(size_t attribIndex,GLint size,GLenum type,bool normalized,bool pureInteger,GLuint relativeOffset)162 void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
163                                             GLint size,
164                                             GLenum type,
165                                             bool normalized,
166                                             bool pureInteger,
167                                             GLuint relativeOffset)
168 {
169     ASSERT(attribIndex < getMaxAttribs());
170 
171     VertexAttribute *attrib = &mState.mVertexAttributes[attribIndex];
172 
173     attrib->size           = size;
174     attrib->type           = type;
175     attrib->normalized     = normalized;
176     attrib->pureInteger    = pureInteger;
177     attrib->relativeOffset = relativeOffset;
178 }
179 
setVertexAttribFormat(size_t attribIndex,GLint size,GLenum type,bool normalized,bool pureInteger,GLuint relativeOffset)180 void VertexArray::setVertexAttribFormat(size_t attribIndex,
181                                         GLint size,
182                                         GLenum type,
183                                         bool normalized,
184                                         bool pureInteger,
185                                         GLuint relativeOffset)
186 {
187     setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset);
188 
189     mDirtyBits.set(DIRTY_BIT_ATTRIB_0_FORMAT + attribIndex);
190 }
191 
setVertexAttribDivisor(const Context * context,size_t attribIndex,GLuint divisor)192 void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
193 {
194     ASSERT(attribIndex < getMaxAttribs());
195 
196     setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
197     setVertexBindingDivisor(attribIndex, divisor);
198 }
199 
enableAttribute(size_t attribIndex,bool enabledState)200 void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
201 {
202     ASSERT(attribIndex < getMaxAttribs());
203 
204     mState.mVertexAttributes[attribIndex].enabled = enabledState;
205 
206     mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex);
207 
208     // Update state cache
209     if (enabledState)
210     {
211         mState.mMaxEnabledAttribute = std::max(attribIndex + 1, mState.mMaxEnabledAttribute);
212     }
213     else if (mState.mMaxEnabledAttribute == attribIndex + 1)
214     {
215         while (mState.mMaxEnabledAttribute > 0 &&
216                !mState.mVertexAttributes[mState.mMaxEnabledAttribute - 1].enabled)
217         {
218             --mState.mMaxEnabledAttribute;
219         }
220     }
221 }
222 
setVertexAttribPointer(const Context * context,size_t attribIndex,gl::Buffer * boundBuffer,GLint size,GLenum type,bool normalized,bool pureInteger,GLsizei stride,const void * pointer)223 void VertexArray::setVertexAttribPointer(const Context *context,
224                                          size_t attribIndex,
225                                          gl::Buffer *boundBuffer,
226                                          GLint size,
227                                          GLenum type,
228                                          bool normalized,
229                                          bool pureInteger,
230                                          GLsizei stride,
231                                          const void *pointer)
232 {
233     ASSERT(attribIndex < getMaxAttribs());
234 
235     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
236 
237     setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, 0);
238     setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
239 
240     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
241 
242     GLsizei effectiveStride =
243         stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
244     attrib.pointer                 = pointer;
245     attrib.vertexAttribArrayStride = stride;
246 
247     bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
248 
249     mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attribIndex);
250 }
251 
setElementArrayBuffer(const Context * context,Buffer * buffer)252 void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer)
253 {
254     mState.mElementArrayBuffer.set(context, buffer);
255     mDirtyBits.set(DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
256 }
257 
syncState(const Context * context)258 void VertexArray::syncState(const Context *context)
259 {
260     if (mDirtyBits.any())
261     {
262         mVertexArray->syncState(context, mDirtyBits);
263         mDirtyBits.reset();
264     }
265 }
266 
267 }  // namespace gl
268