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