blob: 0da7375d3f494d855f28db0d1000b6048ba552c0 [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 {
119 // Not an indexed call, set the range to [first, first + count)
120 indexRange.start = first;
121 indexRange.end = first + count;
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
311 for (size_t vertexIdx = indexRange.start; vertexIdx <= indexRange.end; vertexIdx++)
312 {
313 memcpy(bufferPointer + curBufferOffset + (destStride * vertexIdx),
314 inputPointer + (sourceStride * vertexIdx), destStride);
315 }
316 }
317
318 // Compute where the 0-index vertex would be.
319 const size_t vertexStartOffset = curBufferOffset - (indexRange.start * destStride);
320
321 mFunctions->vertexAttribPointer(idx, attrib.size, attrib.type, attrib.normalized,
322 static_cast<GLsizei>(destStride),
323 reinterpret_cast<const GLvoid *>(vertexStartOffset));
324
325 curBufferOffset += destStride * streamedVertexCount;
326
327 // Mark the applied attribute as dirty by setting an invalid size so that if it doesn't
328 // need to be streamed later, there is no chance that the caching will skip it.
329 mAppliedAttributes[idx].size = static_cast<GLuint>(-1);
Geoff Lang7c82bc42015-03-09 16:18:08 -0400330 }
331
332 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
333 }
334
335 if (unmapResult != GL_TRUE)
336 {
Jamie Madill0b9e9032015-08-17 11:51:52 +0000337 return Error(GL_OUT_OF_MEMORY, "Failed to unmap the client data streaming buffer.");
Geoff Lang7c82bc42015-03-09 16:18:08 -0400338 }
339
Jamie Madill0b9e9032015-08-17 11:51:52 +0000340 return Error(GL_NO_ERROR);
Geoff Langba4c4a82015-02-24 12:38:46 -0500341}
342
343GLuint VertexArrayGL::getVertexArrayID() const
344{
345 return mVertexArrayID;
Geoff Langf9a6f082015-01-22 13:32:49 -0500346}
347
Geoff Lang294cad92015-05-26 15:11:23 -0400348GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
349{
Jamie Madill77a90c22015-08-11 16:33:17 -0400350 if (mAppliedElementArrayBuffer.get() == nullptr)
351 {
352 return mStreamingElementArrayBuffer;
353 }
354
355 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
Geoff Lang294cad92015-05-26 15:11:23 -0400356}
357
Jamie Madill0b9e9032015-08-17 11:51:52 +0000358void VertexArrayGL::updateNeedsStreaming(size_t attribIndex)
359{
360 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
361 mAttributesNeedStreaming.set(attribIndex, AttributeNeedsStreaming(attrib));
Geoff Langf9a6f082015-01-22 13:32:49 -0500362}
Jamie Madill0b9e9032015-08-17 11:51:52 +0000363
364void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
365{
366 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
367 if (mAppliedAttributes[attribIndex].enabled == attrib.enabled)
368 {
369 return;
370 }
371
372 updateNeedsStreaming(attribIndex);
373
374 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
375 if (attrib.enabled)
376 {
377 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
378 }
379 else
380 {
381 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
382 }
383 mAppliedAttributes[attribIndex].enabled = attrib.enabled;
384}
385
386void VertexArrayGL::updateAttribPointer(size_t attribIndex)
387{
388 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
389 if (mAppliedAttributes[attribIndex] == attrib)
390 {
391 return;
392 }
393
394 updateNeedsStreaming(attribIndex);
395 mAppliedAttributes[attribIndex] = attrib;
396
397 // If we need to stream, defer the attribPointer to the draw call.
398 if (mAttributesNeedStreaming[attribIndex])
399 {
400 return;
401 }
402
403 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
404 const Buffer *arrayBuffer = attrib.buffer.get();
405 if (arrayBuffer != nullptr)
406 {
407 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
408 mStateManager->bindBuffer(GL_ARRAY_BUFFER, arrayBufferGL->getBufferID());
409 }
410 else
411 {
412 mStateManager->bindBuffer(GL_ARRAY_BUFFER, 0);
413 }
414
415 if (attrib.pureInteger)
416 {
417 mFunctions->vertexAttribIPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
418 attrib.stride, attrib.pointer);
419 }
420 else
421 {
422 mFunctions->vertexAttribPointer(static_cast<GLuint>(attribIndex), attrib.size, attrib.type,
423 attrib.normalized, attrib.stride, attrib.pointer);
424 }
425}
426
427void VertexArrayGL::syncState(const VertexArray::DirtyBits &dirtyBits)
428{
429 for (unsigned long dirtyBit : angle::IterateBitSet(dirtyBits))
430 {
431 if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
432 {
433 // TODO(jmadill): Element array buffer bindings
434 }
435 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED &&
436 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)
437 {
438 size_t attribIndex =
439 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED;
440 updateAttribEnabled(attribIndex);
441 }
442 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
443 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
444 {
445 size_t attribIndex =
446 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_POINTER;
447 updateAttribPointer(attribIndex);
448 }
449 else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR &&
450 dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_DIVISOR)
451 {
452 size_t attribIndex =
453 static_cast<size_t>(dirtyBit) - VertexArray::DIRTY_BIT_ATTRIB_0_DIVISOR;
454 const VertexAttribute &attrib = mData.getVertexAttribute(attribIndex);
455
456 if (mAppliedAttributes[attribIndex].divisor != attrib.divisor)
457 {
458 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
459 mFunctions->vertexAttribDivisor(static_cast<GLuint>(attribIndex), attrib.divisor);
460 mAppliedAttributes[attribIndex].divisor = attrib.divisor;
461 }
462 }
463 else
464 UNREACHABLE();
465 }
466}
467
468} // rx