blob: e43cb7ad17cdad4578c6fce7d17116b345331b5d [file] [log] [blame]
Geoff Langf9a6f082015-01-22 13:32:49 -05001//
2// Copyright 2015 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
7// VertexArrayGL.cpp: Implements the class methods for VertexArrayGL.
8
9#include "libANGLE/renderer/gl/VertexArrayGL.h"
10
Jamie Madill0b9e9032015-08-17 11:51:52 +000011#include "common/BitSetIterator.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050012#include "common/debug.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040013#include "common/mathutil.h"
Geoff Lang831b1952015-05-05 11:02:27 -040014#include "common/utilities.h"
Geoff Lang6ae6efc2015-03-09 14:42:35 -040015#include "libANGLE/Buffer.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050016#include "libANGLE/angletypes.h"
Geoff Lang7c82bc42015-03-09 16:18:08 -040017#include "libANGLE/formatutils.h"
Geoff Langba4c4a82015-02-24 12:38:46 -050018#include "libANGLE/renderer/gl/BufferGL.h"
19#include "libANGLE/renderer/gl/FunctionsGL.h"
20#include "libANGLE/renderer/gl/StateManagerGL.h"
Geoff Langf9a6f082015-01-22 13:32:49 -050021
Jamie Madill0b9e9032015-08-17 11:51:52 +000022using namespace gl;
23
Geoff Langf9a6f082015-01-22 13:32:49 -050024namespace rx
25{
Jamie Madill0b9e9032015-08-17 11:51:52 +000026namespace
27{
28bool AttributeNeedsStreaming(const VertexAttribute &attribute)
29{
30 return (attribute.enabled && attribute.buffer.get() == nullptr);
31}
Geoff Langf9a6f082015-01-22 13:32:49 -050032
Jamie Madill0b9e9032015-08-17 11:51:52 +000033} // anonymous namespace
34
35VertexArrayGL::VertexArrayGL(const VertexArray::Data &data,
Jamie Madill77a90c22015-08-11 16:33:17 -040036 const FunctionsGL *functions,
37 StateManagerGL *stateManager)
Jamie Madill8e344942015-07-09 14:22:07 -040038 : VertexArrayImpl(data),
Geoff Langba4c4a82015-02-24 12:38:46 -050039 mFunctions(functions),
40 mStateManager(stateManager),
41 mVertexArrayID(0),
Jamie Madill77a90c22015-08-11 16:33:17 -040042 mAppliedElementArrayBuffer(),
Geoff Lang7c82bc42015-03-09 16:18:08 -040043 mStreamingElementArrayBufferSize(0),
44 mStreamingElementArrayBuffer(0),
45 mStreamingArrayBufferSize(0),
46 mStreamingArrayBuffer(0)
Geoff Langba4c4a82015-02-24 12:38:46 -050047{
48 ASSERT(mFunctions);
49 ASSERT(mStateManager);
50 mFunctions->genVertexArrays(1, &mVertexArrayID);
51
52 // Set the cached vertex attribute array size
53 GLint maxVertexAttribs;
54 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
55 mAppliedAttributes.resize(maxVertexAttribs);
56}
Geoff Langf9a6f082015-01-22 13:32:49 -050057
58VertexArrayGL::~VertexArrayGL()
Geoff Langba4c4a82015-02-24 12:38:46 -050059{
Geoff Lang1eb708e2015-05-04 14:58:23 -040060 mStateManager->deleteVertexArray(mVertexArrayID);
61 mVertexArrayID = 0;
Geoff Langba4c4a82015-02-24 12:38:46 -050062
Geoff Lang1eb708e2015-05-04 14:58:23 -040063 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
64 mStreamingElementArrayBufferSize = 0;
65 mStreamingElementArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040066
Geoff Lang1eb708e2015-05-04 14:58:23 -040067 mStateManager->deleteBuffer(mStreamingArrayBuffer);
68 mStreamingArrayBufferSize = 0;
69 mStreamingArrayBuffer = 0;
Geoff Lang7c82bc42015-03-09 16:18:08 -040070
Jamie Madill77a90c22015-08-11 16:33:17 -040071 mAppliedElementArrayBuffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050072 for (size_t idx = 0; idx < mAppliedAttributes.size(); idx++)
73 {
Jamie Madill8e344942015-07-09 14:22:07 -040074 mAppliedAttributes[idx].buffer.set(nullptr);
Geoff Langba4c4a82015-02-24 12:38:46 -050075 }
76}
Geoff Langf9a6f082015-01-22 13:32:49 -050077
Jamie Madill0b9e9032015-08-17 11:51:52 +000078gl::Error VertexArrayGL::syncDrawArraysState(const gl::AttributesMask &activeAttributesMask,
79 GLint first,
80 GLsizei count) const
Geoff Lang7c82bc42015-03-09 16:18:08 -040081{
Jamie Madill0b9e9032015-08-17 11:51:52 +000082 return syncDrawState(activeAttributesMask, first, count, GL_NONE, nullptr, nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -040083}
84
Jamie Madill0b9e9032015-08-17 11:51:52 +000085gl::Error VertexArrayGL::syncDrawElementsState(const gl::AttributesMask &activeAttributesMask,
86 GLsizei count,
87 GLenum type,
88 const GLvoid *indices,
89 const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -040090{
Jamie Madill0b9e9032015-08-17 11:51:52 +000091 return syncDrawState(activeAttributesMask, 0, count, type, indices, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -040092}
93
Jamie Madill0b9e9032015-08-17 11:51:52 +000094gl::Error VertexArrayGL::syncDrawState(const gl::AttributesMask &activeAttributesMask,
95 GLint first,
96 GLsizei count,
97 GLenum type,
98 const GLvoid *indices,
99 const GLvoid **outIndices) const
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400100{
Jamie Madill77a90c22015-08-11 16:33:17 -0400101 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
Geoff Lang6ae6efc2015-03-09 14:42:35 -0400102
Geoff Lang7c82bc42015-03-09 16:18:08 -0400103 // Check if any attributes need to be streamed, determines if the index range needs to be computed
Jamie Madill0b9e9032015-08-17 11:51:52 +0000104 bool attributesNeedStreaming = mAttributesNeedStreaming.any();
Geoff Lang7c82bc42015-03-09 16:18:08 -0400105
106 // Determine if an index buffer needs to be streamed and the range of vertices that need to be copied
Jamie Madill0b9e9032015-08-17 11:51:52 +0000107 RangeUI indexRange(0, 0);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400108 if (type != GL_NONE)
Geoff Langba4c4a82015-02-24 12:38:46 -0500109 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000110 Error error =
111 syncIndexData(count, type, indices, attributesNeedStreaming, &indexRange, outIndices);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400112 if (error.isError())
113 {
114 return error;
115 }
116 }
117 else
118 {
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400119 // Not an indexed call, set the range to [first, first + count - 1]
Geoff Lang7c82bc42015-03-09 16:18:08 -0400120 indexRange.start = first;
Corentin Wallez2c34a4b2015-08-25 16:26:02 -0400121 indexRange.end = first + count - 1;
Geoff Langba4c4a82015-02-24 12:38:46 -0500122 }
123
Jamie Madill0b9e9032015-08-17 11:51:52 +0000124 if (attributesNeedStreaming)
Geoff Langba4c4a82015-02-24 12:38:46 -0500125 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000126 Error error = streamAttributes(activeAttributesMask, indexRange);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400127 if (error.isError())
128 {
129 return error;
130 }
131 }
132
Jamie Madill0b9e9032015-08-17 11:51:52 +0000133 return Error(GL_NO_ERROR);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400134}
135
Jamie Madill0b9e9032015-08-17 11:51:52 +0000136Error VertexArrayGL::syncIndexData(GLsizei count,
137 GLenum type,
138 const GLvoid *indices,
139 bool attributesNeedStreaming,
140 RangeUI *outIndexRange,
141 const GLvoid **outIndices) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400142{
143 ASSERT(outIndices);
144
Jamie Madill8e344942015-07-09 14:22:07 -0400145 gl::Buffer *elementArrayBuffer = mData.getElementArrayBuffer().get();
146
Geoff Lang7c82bc42015-03-09 16:18:08 -0400147 // Need to check the range of indices if attributes need to be streamed
Jamie Madill8e344942015-07-09 14:22:07 -0400148 if (elementArrayBuffer != nullptr)
Geoff Lang7c82bc42015-03-09 16:18:08 -0400149 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400150 if (elementArrayBuffer != mAppliedElementArrayBuffer.get())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400151 {
Jamie Madill77a90c22015-08-11 16:33:17 -0400152 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
153 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferGL->getBufferID());
154 mAppliedElementArrayBuffer.set(elementArrayBuffer);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400155 }
156
157 // Only compute the index range if the attributes also need to be streamed
158 if (attributesNeedStreaming)
159 {
160 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000161 Error error = mData.getElementArrayBuffer()->getIndexRange(
162 type, static_cast<size_t>(elementArrayBufferOffset), count, outIndexRange);
Geoff Lang520c4ae2015-05-05 13:12:36 -0400163 if (error.isError())
Geoff Lang7c82bc42015-03-09 16:18:08 -0400164 {
Geoff Lang520c4ae2015-05-05 13:12:36 -0400165 return error;
Geoff Lang7c82bc42015-03-09 16:18:08 -0400166 }
167 }
168
169 // Indices serves as an offset into the index buffer in this case, use the same value for the draw call
170 *outIndices = indices;
171 }
172 else
173 {
174 // Need to stream the index buffer
175 // TODO: if GLES, nothing needs to be streamed
176
177 // Only compute the index range if the attributes also need to be streamed
178 if (attributesNeedStreaming)
179 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000180 *outIndexRange = ComputeIndexRange(type, indices, count);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400181 }
182
183 // Allocate the streaming element array buffer
184 if (mStreamingElementArrayBuffer == 0)
185 {
186 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
187 mStreamingElementArrayBufferSize = 0;
188 }
189
190 mStateManager->bindBuffer(GL_ELEMENT_ARRAY_BUFFER, mStreamingElementArrayBuffer);
Jamie Madill77a90c22015-08-11 16:33:17 -0400191 mAppliedElementArrayBuffer.set(nullptr);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400192
193 // Make sure the element array buffer is large enough
Jamie Madill0b9e9032015-08-17 11:51:52 +0000194 const Type &indexTypeInfo = GetTypeInfo(type);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400195 size_t requiredStreamingBufferSize = indexTypeInfo.bytes * count;
196 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
197 {
198 // Copy the indices in while resizing the buffer
199 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices, GL_DYNAMIC_DRAW);
200 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
201 }
202 else
203 {
204 // Put the indices at the beginning of the buffer
205 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize, indices);
206 }
207
208 // Set the index offset for the draw call to zero since the supplied index pointer is to client data
209 *outIndices = nullptr;
210 }
211
Jamie Madill0b9e9032015-08-17 11:51:52 +0000212 return Error(GL_NO_ERROR);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400213}
214
Jamie Madill0b9e9032015-08-17 11:51:52 +0000215void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &activeAttributesMask,
216 const gl::RangeUI &indexRange,
217 size_t *outStreamingDataSize,
218 size_t *outMaxAttributeDataSize) const
Geoff Lang7c82bc42015-03-09 16:18:08 -0400219{
Jamie Madill0b9e9032015-08-17 11:51:52 +0000220 *outStreamingDataSize = 0;
221 *outMaxAttributeDataSize = 0;
222
223 ASSERT(mAttributesNeedStreaming.any());
224
225 const auto &attribs = mData.getVertexAttributes();
226 for (unsigned int idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
227 {
228 const auto &attrib = attribs[idx];
229 ASSERT(AttributeNeedsStreaming(attrib));
230
231 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
232
233 // If streaming is going to be required, compute the size of the required buffer
234 // and how much slack space at the beginning of the buffer will be required by determining
235 // the attribute with the largest data size.
236 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
237 *outStreamingDataSize += typeSize * streamedVertexCount;
238 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
239 }
240}
241
242gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttributesMask,
243 const gl::RangeUI &indexRange) const
244{
245 // Sync the vertex attribute state and track what data needs to be streamed
246 size_t streamingDataSize = 0;
247 size_t maxAttributeDataSize = 0;
248
249 computeStreamingAttributeSizes(activeAttributesMask, indexRange, &streamingDataSize,
250 &maxAttributeDataSize);
251
252 if (streamingDataSize == 0)
253 {
254 return gl::Error(GL_NO_ERROR);
255 }
256
Geoff Lang7c82bc42015-03-09 16:18:08 -0400257 if (mStreamingArrayBuffer == 0)
258 {
259 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
260 mStreamingArrayBufferSize = 0;
261 }
262
263 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer so that
264 // the same 'first' argument can be passed into the draw call.
265 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
266 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
267
268 mStateManager->bindBuffer(GL_ARRAY_BUFFER, mStreamingArrayBuffer);
269 if (requiredBufferSize > mStreamingArrayBufferSize)
270 {
271 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
272 mStreamingArrayBufferSize = requiredBufferSize;
273 }
274
275 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
276 // somehow (such as by a screen change), retry writing the data a few times and return OUT_OF_MEMORY
277 // if that fails.
278 GLboolean unmapResult = GL_FALSE;
279 size_t unmapRetryAttempts = 5;
280 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
281 {
282 uint8_t *bufferPointer = reinterpret_cast<uint8_t*>(mFunctions->mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
283 size_t curBufferOffset = bufferEmptySpace;
284
285 const size_t streamedVertexCount = indexRange.end - indexRange.start + 1;
286
Jamie Madill8e344942015-07-09 14:22:07 -0400287 const auto &attribs = mData.getVertexAttributes();
Jamie Madill0b9e9032015-08-17 11:51:52 +0000288 for (unsigned int idx :
289 angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
Geoff Lang7c82bc42015-03-09 16:18:08 -0400290 {
Jamie Madill8e344942015-07-09 14:22:07 -0400291 const auto &attrib = attribs[idx];
Jamie Madill0b9e9032015-08-17 11:51:52 +0000292 ASSERT(AttributeNeedsStreaming(attrib));
Geoff Lang7c82bc42015-03-09 16:18:08 -0400293
Jamie Madill0b9e9032015-08-17 11:51:52 +0000294 const size_t sourceStride = ComputeVertexAttributeStride(attrib);
295 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
296
297 const uint8_t *inputPointer = reinterpret_cast<const uint8_t *>(attrib.pointer);
298
299 // Pack the data when copying it, user could have supplied a very large stride that
300 // would cause the buffer to be much larger than needed.
301 if (destStride == sourceStride)
Jamie Madill8e344942015-07-09 14:22:07 -0400302 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000303 // Can copy in one go, the data is packed
304 memcpy(bufferPointer + curBufferOffset,
305 inputPointer + (sourceStride * indexRange.start),
306 destStride * streamedVertexCount);
Jamie Madill6d51c702015-08-14 10:38:10 -0400307 }
Jamie Madill0b9e9032015-08-17 11:51:52 +0000308 else
309 {
310 // Copy each vertex individually
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400311 for (size_t vertexIdx = 0; vertexIdx <= streamedVertexCount; vertexIdx++)
Jamie Madill0b9e9032015-08-17 11:51:52 +0000312 {
Corentin Wallez4d5362d2015-08-25 11:25:14 -0400313 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
314 const uint8_t *in =
315 inputPointer + sourceStride * (vertexIdx + indexRange.start);
316 memcpy(out, in, destStride);
Jamie Madill0b9e9032015-08-17 11:51:52 +0000317 }
318 }
319
320 // Compute where the 0-index vertex would be.
321 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
322
323 mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type, attrib.normalized,
324 static_cast<GLsizei>(destStride),
325 reinterpret_cast<const GLvoid *>(vertexStartOffset));
326
327 curBufferOffset += destStride * streamedVertexCount;
328
329 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
330 // need to be streamed later, there is no chance that the caching will skip it.
331 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400332 }
333
334 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
335 }
336
337 if (unmapResult != GL_TRUE)
338 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000339 return Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
Geoff Lang7c82bc42015-03-09 16:18:08 -0400340 }
341
Jamie Madill0b9e9032015-08-17 11:51:52 +0000342 return Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500343}
344
345GLuint VertexArrayGL::getVertexArrayID() const
346{
347 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500348}
349
Geoff Lang294cad92015-05-26 15:11:23 -0400350GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
351{
Jamie Madill77a90c22015-08-11 16:33:17 -0400352 if (mAppliedElementArrayBuffer.get() == nullptr)
353 {
354 return mStreamingElementArrayBuffer;
355 }
356
357 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400358}
359
Jamie Madill0b9e9032015-08-17 11:51:52 +0000360void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
361{
362 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
363 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib));
Geoff Langf9a6f082015-01-22 13:32:49 -0500364}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000365
366void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
367{
368 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
369 if (mAppliedAttributes[attribIndex].enabled == attrib.enabled)
370 {
371 return;
372 }
373
374 updateNeedsStreaming(attribIndex);
375
376 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
377 if (attrib.enabled)
378 {
379 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
380 }
381 else
382 {
383 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
384 }
385 mAppliedAttributes[attribIndex].enabled = attrib.enabled;
386}
387
388void VertexArrayGL::updateAttribPointer(size_t attribIndex)
389{
390 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
391 if (mAppliedAttributes[attribIndex] == attrib)
392 {
393 return;
394 }
395
396 updateNeedsStreaming(attribIndex);
397 mAppliedAttributes[attribIndex] = attrib;
398
399 // If we need to stream, defer the attribPointer to the draw call.
400 if (mAttributesNeedStreaming[attribIndex])
401 {
402 return;
403 }
404
405 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
406 const Buffer *arrayBuffer = attrib.buffer.get();
407 if (arrayBuffer != nullptr)
408 {
409 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
410 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
411 }
412 else
413 {
414 mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
415 }
416
417 if (attrib.pureInteger)
418 {
419 mFunctions->vertexAttribIPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
420 attrib.stride, attrib.pointer);
421 }
422 else
423 {
424 mFunctions->vertexAttribPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
425 attrib.normalized, attrib.stride, attrib.pointer);
426 }
427}
428
429void VertexArrayGL::syncState(const VertexArray::DirtyBits &dirtyBits)
430{
431 for (unsigned long dirtyBit : angle::IterateBitSet(dirtyBits))
432 {
433 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
434 {
435 // TODO(jmadill): Element array buffer bindings
436 }
437 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
438 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
439 {
440 size_t attribIndex =
441 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED;
442 updateAttribEnabled(attribIndex);
443 }
444 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
445 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
446 {
447 size_t attribIndex =
448 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_POINTER;
449 updateAttribPointer(attribIndex);
450 }
451 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR &&
452 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_DIVISOR)
453 {
454 size_t attribIndex =
455 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR;
456 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
457
458 if (mAppliedAttributes[attribIndex].divisor != attrib.divisor)
459 {
460 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
461 mFunctions->vertexAttribDivisor(static_cast<GLuint>(attribIndex), attrib.divisor);
462 mAppliedAttributes[attribIndex].divisor = attrib.divisor;
463 }
464 }
465 else
466 UNREACHABLE();
467 }
468}
469
470} // rx