1 //
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
11 #include "common/bitset_utils.h"
12 #include "common/debug.h"
13 #include "common/mathutil.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Buffer.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/angletypes.h"
18 #include "libANGLE/formatutils.h"
19 #include "libANGLE/renderer/gl/BufferGL.h"
20 #include "libANGLE/renderer/gl/ContextGL.h"
21 #include "libANGLE/renderer/gl/FunctionsGL.h"
22 #include "libANGLE/renderer/gl/StateManagerGL.h"
23 #include "libANGLE/renderer/gl/renderergl_utils.h"
24
25 using namespace gl;
26
27 namespace rx
28 {
29 namespace
30 {
SameVertexAttribFormat(const VertexAttribute & a,const VertexAttribute & b)31 bool SameVertexAttribFormat(const VertexAttribute &a, const VertexAttribute &b)
32 {
33 return a.format == b.format && a.relativeOffset == b.relativeOffset;
34 }
35
SameVertexBuffer(const VertexBinding & a,const VertexBinding & b)36 bool SameVertexBuffer(const VertexBinding &a, const VertexBinding &b)
37 {
38 return a.getStride() == b.getStride() && a.getOffset() == b.getOffset() &&
39 a.getBuffer().get() == b.getBuffer().get();
40 }
41
IsVertexAttribPointerSupported(size_t attribIndex,const VertexAttribute & attrib)42 bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
43 {
44 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
45 }
46
GetAdjustedDivisor(GLuint numViews,GLuint divisor)47 GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
48 {
49 return numViews * divisor;
50 }
51
ValidateStateHelperGetIntegerv(const FunctionsGL * functions,const GLuint localValue,const GLenum pname,const char * localName,const char * driverName)52 static void ValidateStateHelperGetIntegerv(const FunctionsGL *functions,
53 const GLuint localValue,
54 const GLenum pname,
55 const char *localName,
56 const char *driverName)
57 {
58 GLint queryValue;
59 functions->getIntegerv(pname, &queryValue);
60 if (localValue != static_cast<GLuint>(queryValue))
61 {
62 WARN() << localName << " (" << localValue << ") != " << driverName << " (" << queryValue
63 << ")";
64 // Re-add ASSERT: http://anglebug.com/3900
65 // ASSERT(false);
66 }
67 }
68
ValidateStateHelperGetVertexAttribiv(const FunctionsGL * functions,const GLint index,const GLuint localValue,const GLenum pname,const char * localName,const char * driverName)69 static void ValidateStateHelperGetVertexAttribiv(const FunctionsGL *functions,
70 const GLint index,
71 const GLuint localValue,
72 const GLenum pname,
73 const char *localName,
74 const char *driverName)
75 {
76 GLint queryValue;
77 functions->getVertexAttribiv(index, pname, &queryValue);
78 if (localValue != static_cast<GLuint>(queryValue))
79 {
80 WARN() << localName << "[" << index << "] (" << localValue << ") != " << driverName << "["
81 << index << "] (" << queryValue << ")";
82 // Re-add ASSERT: http://anglebug.com/3900
83 // ASSERT(false);
84 }
85 }
86
87 } // anonymous namespace
88
VertexArrayGL(const VertexArrayState & state,const FunctionsGL * functions,StateManagerGL * stateManager)89 VertexArrayGL::VertexArrayGL(const VertexArrayState &state,
90 const FunctionsGL *functions,
91 StateManagerGL *stateManager)
92 : VertexArrayImpl(state),
93 mFunctions(functions),
94 mStateManager(stateManager),
95 mVertexArrayID(0),
96 mAppliedNumViews(1),
97 mAppliedElementArrayBuffer(),
98 mAppliedBindings(state.getMaxBindings()),
99 mStreamingElementArrayBufferSize(0),
100 mStreamingElementArrayBuffer(0),
101 mStreamingArrayBufferSize(0),
102 mStreamingArrayBuffer(0)
103 {
104 ASSERT(mFunctions);
105 ASSERT(mStateManager);
106 mFunctions->genVertexArrays(1, &mVertexArrayID);
107
108 // Set the cached vertex attribute array and vertex attribute binding array size
109 GLuint maxVertexAttribs = static_cast<GLuint>(state.getMaxAttribs());
110 for (GLuint i = 0; i < maxVertexAttribs; i++)
111 {
112 mAppliedAttributes.emplace_back(i);
113 }
114 }
115
~VertexArrayGL()116 VertexArrayGL::~VertexArrayGL() {}
117
destroy(const gl::Context * context)118 void VertexArrayGL::destroy(const gl::Context *context)
119 {
120 mStateManager->deleteVertexArray(mVertexArrayID);
121 mVertexArrayID = 0;
122 mAppliedNumViews = 1;
123
124 mStateManager->deleteBuffer(mStreamingElementArrayBuffer);
125 mStreamingElementArrayBufferSize = 0;
126 mStreamingElementArrayBuffer = 0;
127
128 mStateManager->deleteBuffer(mStreamingArrayBuffer);
129 mStreamingArrayBufferSize = 0;
130 mStreamingArrayBuffer = 0;
131
132 mAppliedElementArrayBuffer.set(context, nullptr);
133 for (auto &binding : mAppliedBindings)
134 {
135 binding.setBuffer(context, nullptr);
136 }
137 }
138
syncClientSideData(const gl::Context * context,const gl::AttributesMask & activeAttributesMask,GLint first,GLsizei count,GLsizei instanceCount) const139 angle::Result VertexArrayGL::syncClientSideData(const gl::Context *context,
140 const gl::AttributesMask &activeAttributesMask,
141 GLint first,
142 GLsizei count,
143 GLsizei instanceCount) const
144 {
145 return syncDrawState(context, activeAttributesMask, first, count,
146 gl::DrawElementsType::InvalidEnum, nullptr, instanceCount, false, nullptr);
147 }
148
updateElementArrayBufferBinding(const gl::Context * context) const149 void VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
150 {
151 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
152 if (elementArrayBuffer != nullptr && elementArrayBuffer != mAppliedElementArrayBuffer.get())
153 {
154 const BufferGL *bufferGL = GetImplAs<BufferGL>(elementArrayBuffer);
155 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, bufferGL->getBufferID());
156 mAppliedElementArrayBuffer.set(context, elementArrayBuffer);
157 }
158 }
159
syncDrawState(const gl::Context * context,const gl::AttributesMask & activeAttributesMask,GLint first,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instanceCount,bool primitiveRestartEnabled,const void ** outIndices) const160 angle::Result VertexArrayGL::syncDrawState(const gl::Context *context,
161 const gl::AttributesMask &activeAttributesMask,
162 GLint first,
163 GLsizei count,
164 gl::DrawElementsType type,
165 const void *indices,
166 GLsizei instanceCount,
167 bool primitiveRestartEnabled,
168 const void **outIndices) const
169 {
170 // Check if any attributes need to be streamed, determines if the index range needs to be
171 // computed
172 const gl::AttributesMask &needsStreamingAttribs =
173 context->getStateCache().getActiveClientAttribsMask();
174
175 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
176 // copied
177 IndexRange indexRange;
178 if (type != gl::DrawElementsType::InvalidEnum)
179 {
180 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
181 needsStreamingAttribs.any(), &indexRange, outIndices));
182 }
183 else
184 {
185 // Not an indexed call, set the range to [first, first + count - 1]
186 indexRange.start = first;
187 indexRange.end = first + count - 1;
188 }
189
190 if (needsStreamingAttribs.any())
191 {
192 ANGLE_TRY(streamAttributes(context, needsStreamingAttribs, instanceCount, indexRange));
193 }
194
195 return angle::Result::Continue;
196 }
197
syncIndexData(const gl::Context * context,GLsizei count,gl::DrawElementsType type,const void * indices,bool primitiveRestartEnabled,bool attributesNeedStreaming,IndexRange * outIndexRange,const void ** outIndices) const198 angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
199 GLsizei count,
200 gl::DrawElementsType type,
201 const void *indices,
202 bool primitiveRestartEnabled,
203 bool attributesNeedStreaming,
204 IndexRange *outIndexRange,
205 const void **outIndices) const
206 {
207 ASSERT(outIndices);
208
209 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
210
211 // Need to check the range of indices if attributes need to be streamed
212 if (elementArrayBuffer != nullptr)
213 {
214 ASSERT(elementArrayBuffer == mAppliedElementArrayBuffer.get());
215 // Only compute the index range if the attributes also need to be streamed
216 if (attributesNeedStreaming)
217 {
218 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
219 ANGLE_TRY(mState.getElementArrayBuffer()->getIndexRange(
220 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
221 outIndexRange));
222 }
223
224 // Indices serves as an offset into the index buffer in this case, use the same value for
225 // the draw call
226 *outIndices = indices;
227 }
228 else
229 {
230 // Need to stream the index buffer
231 // TODO: if GLES, nothing needs to be streamed
232
233 // Only compute the index range if the attributes also need to be streamed
234 if (attributesNeedStreaming)
235 {
236 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
237 }
238
239 // Allocate the streaming element array buffer
240 if (mStreamingElementArrayBuffer == 0)
241 {
242 mFunctions->genBuffers(1, &mStreamingElementArrayBuffer);
243 mStreamingElementArrayBufferSize = 0;
244 }
245
246 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
247
248 mStateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
249 mAppliedElementArrayBuffer.set(context, nullptr);
250
251 // Make sure the element array buffer is large enough
252 const GLuint indexTypeBytes = gl::GetDrawElementsTypeSize(type);
253 size_t requiredStreamingBufferSize = indexTypeBytes * count;
254 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
255 {
256 // Copy the indices in while resizing the buffer
257 mFunctions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize, indices,
258 GL_DYNAMIC_DRAW);
259 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
260 }
261 else
262 {
263 // Put the indices at the beginning of the buffer
264 mFunctions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, requiredStreamingBufferSize,
265 indices);
266 }
267
268 // Set the index offset for the draw call to zero since the supplied index pointer is to
269 // client data
270 *outIndices = nullptr;
271 }
272
273 return angle::Result::Continue;
274 }
275
computeStreamingAttributeSizes(const gl::AttributesMask & attribsToStream,GLsizei instanceCount,const gl::IndexRange & indexRange,size_t * outStreamingDataSize,size_t * outMaxAttributeDataSize) const276 void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &attribsToStream,
277 GLsizei instanceCount,
278 const gl::IndexRange &indexRange,
279 size_t *outStreamingDataSize,
280 size_t *outMaxAttributeDataSize) const
281 {
282 *outStreamingDataSize = 0;
283 *outMaxAttributeDataSize = 0;
284
285 ASSERT(attribsToStream.any());
286
287 const auto &attribs = mState.getVertexAttributes();
288 const auto &bindings = mState.getVertexBindings();
289
290 for (auto idx : attribsToStream)
291 {
292 const auto &attrib = attribs[idx];
293 const auto &binding = bindings[attrib.bindingIndex];
294
295 // If streaming is going to be required, compute the size of the required buffer
296 // and how much slack space at the beginning of the buffer will be required by determining
297 // the attribute with the largest data size.
298 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
299 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
300 *outStreamingDataSize +=
301 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
302 instanceCount);
303 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
304 }
305 }
306
streamAttributes(const gl::Context * context,const gl::AttributesMask & attribsToStream,GLsizei instanceCount,const gl::IndexRange & indexRange) const307 angle::Result VertexArrayGL::streamAttributes(const gl::Context *context,
308 const gl::AttributesMask &attribsToStream,
309 GLsizei instanceCount,
310 const gl::IndexRange &indexRange) const
311 {
312 // Sync the vertex attribute state and track what data needs to be streamed
313 size_t streamingDataSize = 0;
314 size_t maxAttributeDataSize = 0;
315
316 computeStreamingAttributeSizes(attribsToStream, instanceCount, indexRange, &streamingDataSize,
317 &maxAttributeDataSize);
318
319 if (streamingDataSize == 0)
320 {
321 return angle::Result::Continue;
322 }
323
324 if (mStreamingArrayBuffer == 0)
325 {
326 mFunctions->genBuffers(1, &mStreamingArrayBuffer);
327 mStreamingArrayBufferSize = 0;
328 }
329
330 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
331 // so that the same 'first' argument can be passed into the draw call.
332 const size_t bufferEmptySpace = maxAttributeDataSize * indexRange.start;
333 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
334
335 mStateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
336 if (requiredBufferSize > mStreamingArrayBufferSize)
337 {
338 mFunctions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr, GL_DYNAMIC_DRAW);
339 mStreamingArrayBufferSize = requiredBufferSize;
340 }
341
342 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
343
344 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
345 // somehow (such as by a screen change), retry writing the data a few times and return
346 // OUT_OF_MEMORY if that fails.
347 GLboolean unmapResult = GL_FALSE;
348 size_t unmapRetryAttempts = 5;
349 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
350 {
351 uint8_t *bufferPointer = MapBufferRangeWithFallback(mFunctions, GL_ARRAY_BUFFER, 0,
352 requiredBufferSize, GL_MAP_WRITE_BIT);
353 size_t curBufferOffset = bufferEmptySpace;
354
355 const auto &attribs = mState.getVertexAttributes();
356 const auto &bindings = mState.getVertexBindings();
357
358 for (auto idx : attribsToStream)
359 {
360 const auto &attrib = attribs[idx];
361 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
362
363 const auto &binding = bindings[attrib.bindingIndex];
364
365 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
366 const size_t streamedVertexCount = ComputeVertexBindingElementCount(
367 adjustedDivisor, indexRange.vertexCount(), instanceCount);
368
369 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
370 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
371
372 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
373 // a non-instanced draw call
374 const size_t firstIndex = adjustedDivisor == 0 ? indexRange.start : 0;
375
376 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
377 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
378 const uint8_t *inputPointer = static_cast<const uint8_t *>(attrib.pointer);
379
380 // Pack the data when copying it, user could have supplied a very large stride that
381 // would cause the buffer to be much larger than needed.
382 if (destStride == sourceStride)
383 {
384 // Can copy in one go, the data is packed
385 memcpy(bufferPointer + curBufferOffset, inputPointer + (sourceStride * firstIndex),
386 destStride * streamedVertexCount);
387 }
388 else
389 {
390 // Copy each vertex individually
391 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
392 {
393 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
394 const uint8_t *in = inputPointer + sourceStride * (vertexIdx + firstIndex);
395 memcpy(out, in, destStride);
396 }
397 }
398
399 // Compute where the 0-index vertex would be.
400 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
401
402 callVertexAttribPointer(static_cast<GLuint>(idx), attrib,
403 static_cast<GLsizei>(destStride),
404 static_cast<GLintptr>(vertexStartOffset));
405
406 // Update the state to track the streamed attribute
407 mAppliedAttributes[idx].format = attrib.format;
408
409 mAppliedAttributes[idx].relativeOffset = 0;
410 mAppliedAttributes[idx].bindingIndex = static_cast<GLuint>(idx);
411
412 mAppliedBindings[idx].setStride(static_cast<GLsizei>(destStride));
413 mAppliedBindings[idx].setOffset(static_cast<GLintptr>(vertexStartOffset));
414 mAppliedBindings[idx].setBuffer(context, nullptr);
415
416 curBufferOffset += destStride * streamedVertexCount;
417 }
418
419 unmapResult = mFunctions->unmapBuffer(GL_ARRAY_BUFFER);
420 }
421
422 ANGLE_CHECK(GetImplAs<ContextGL>(context), unmapResult == GL_TRUE,
423 "Failed to unmap the client data streaming buffer.", GL_OUT_OF_MEMORY);
424 return angle::Result::Continue;
425 }
426
getVertexArrayID() const427 GLuint VertexArrayGL::getVertexArrayID() const
428 {
429 return mVertexArrayID;
430 }
431
getAppliedElementArrayBufferID() const432 GLuint VertexArrayGL::getAppliedElementArrayBufferID() const
433 {
434 if (mAppliedElementArrayBuffer.get() == nullptr)
435 {
436 return mStreamingElementArrayBuffer;
437 }
438
439 return GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get())->getBufferID();
440 }
441
updateAttribEnabled(size_t attribIndex)442 void VertexArrayGL::updateAttribEnabled(size_t attribIndex)
443 {
444 const bool enabled = mState.getVertexAttribute(attribIndex).enabled &
445 mProgramActiveAttribLocationsMask.test(attribIndex);
446 if (mAppliedAttributes[attribIndex].enabled == enabled)
447 {
448 return;
449 }
450
451 if (enabled)
452 {
453 mFunctions->enableVertexAttribArray(static_cast<GLuint>(attribIndex));
454 }
455 else
456 {
457 mFunctions->disableVertexAttribArray(static_cast<GLuint>(attribIndex));
458 }
459
460 mAppliedAttributes[attribIndex].enabled = enabled;
461 }
462
updateAttribPointer(const gl::Context * context,size_t attribIndex)463 void VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
464 {
465 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
466
467 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
468 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
469 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
470
471 // Early return when the vertex attribute isn't using a buffer object:
472 // - If we need to stream, defer the attribPointer to the draw call.
473 // - Skip the attribute that is disabled and uses a client memory pointer.
474 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
475 // client memory pointer either, it must be disabled and shouldn't affect the draw.
476 const auto &bindingBuffer = binding.getBuffer();
477 const Buffer *arrayBuffer = bindingBuffer.get();
478 if (arrayBuffer == nullptr)
479 {
480 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
481 // it starts to use a buffer later, there is no chance that the caching will skip it.
482 mAppliedBindings[attribIndex].setBuffer(context, nullptr);
483 return;
484 }
485
486 // We do not need to compare attrib.pointer because when we use a different client memory
487 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
488 // update attribPointer in this function.
489 if ((SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib)) &&
490 (mAppliedAttributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
491 (SameVertexBuffer(mAppliedBindings[attribIndex], binding)))
492 {
493 return;
494 }
495
496 // Since ANGLE always uses a non-zero VAO, we cannot use a client memory pointer on it:
497 // [OpenGL ES 3.0.2] Section 2.8 page 24:
498 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
499 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
500 // is not NULL.
501
502 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(arrayBuffer);
503 mStateManager->bindBuffer(gl::BufferBinding::Array, arrayBufferGL->getBufferID());
504 callVertexAttribPointer(static_cast<GLuint>(attribIndex), attrib, binding.getStride(),
505 binding.getOffset());
506
507 mAppliedAttributes[attribIndex].format = attrib.format;
508
509 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
510 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
511 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
512 // should be consistent with driver so that we won't miss anything.
513 mAppliedAttributes[attribIndex].relativeOffset = 0;
514 mAppliedAttributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
515
516 mAppliedBindings[attribIndex].setStride(binding.getStride());
517 mAppliedBindings[attribIndex].setOffset(binding.getOffset());
518 mAppliedBindings[attribIndex].setBuffer(context, binding.getBuffer().get());
519 }
520
callVertexAttribPointer(GLuint attribIndex,const VertexAttribute & attrib,GLsizei stride,GLintptr offset) const521 void VertexArrayGL::callVertexAttribPointer(GLuint attribIndex,
522 const VertexAttribute &attrib,
523 GLsizei stride,
524 GLintptr offset) const
525 {
526 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
527 const angle::Format &format = *attrib.format;
528 if (format.isPureInt())
529 {
530 ASSERT(!format.isNorm());
531 mFunctions->vertexAttribIPointer(attribIndex, format.channelCount,
532 gl::ToGLenum(format.vertexAttribType), stride, pointer);
533 }
534 else
535 {
536 mFunctions->vertexAttribPointer(attribIndex, format.channelCount,
537 gl::ToGLenum(format.vertexAttribType), format.isNorm(),
538 stride, pointer);
539 }
540 }
541
supportVertexAttribBinding() const542 bool VertexArrayGL::supportVertexAttribBinding() const
543 {
544 ASSERT(mFunctions);
545 return (mFunctions->vertexAttribBinding != nullptr);
546 }
547
updateAttribFormat(size_t attribIndex)548 void VertexArrayGL::updateAttribFormat(size_t attribIndex)
549 {
550 ASSERT(supportVertexAttribBinding());
551
552 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
553 if (SameVertexAttribFormat(mAppliedAttributes[attribIndex], attrib))
554 {
555 return;
556 }
557
558 const angle::Format &format = *attrib.format;
559 if (format.isPureInt())
560 {
561 ASSERT(!format.isNorm());
562 mFunctions->vertexAttribIFormat(static_cast<GLuint>(attribIndex), format.channelCount,
563 gl::ToGLenum(format.vertexAttribType),
564 attrib.relativeOffset);
565 }
566 else
567 {
568 mFunctions->vertexAttribFormat(static_cast<GLuint>(attribIndex), format.channelCount,
569 gl::ToGLenum(format.vertexAttribType), format.isNorm(),
570 attrib.relativeOffset);
571 }
572
573 mAppliedAttributes[attribIndex].format = attrib.format;
574 mAppliedAttributes[attribIndex].relativeOffset = attrib.relativeOffset;
575 }
576
updateAttribBinding(size_t attribIndex)577 void VertexArrayGL::updateAttribBinding(size_t attribIndex)
578 {
579 ASSERT(supportVertexAttribBinding());
580
581 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
582 if (mAppliedAttributes[attribIndex].bindingIndex == bindingIndex)
583 {
584 return;
585 }
586
587 mFunctions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex);
588
589 mAppliedAttributes[attribIndex].bindingIndex = bindingIndex;
590 }
591
updateBindingBuffer(const gl::Context * context,size_t bindingIndex)592 void VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
593 {
594 ASSERT(supportVertexAttribBinding());
595
596 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
597 if (SameVertexBuffer(mAppliedBindings[bindingIndex], binding))
598 {
599 return;
600 }
601
602 const Buffer *arrayBuffer = binding.getBuffer().get();
603 GLuint bufferId = 0;
604 if (arrayBuffer != nullptr)
605 {
606 bufferId = GetImplAs<BufferGL>(arrayBuffer)->getBufferID();
607 }
608
609 mFunctions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId, binding.getOffset(),
610 binding.getStride());
611
612 mAppliedBindings[bindingIndex].setStride(binding.getStride());
613 mAppliedBindings[bindingIndex].setOffset(binding.getOffset());
614 mAppliedBindings[bindingIndex].setBuffer(context, binding.getBuffer().get());
615 }
616
updateBindingDivisor(size_t bindingIndex)617 void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
618 {
619 GLuint adjustedDivisor =
620 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
621 if (mAppliedBindings[bindingIndex].getDivisor() == adjustedDivisor)
622 {
623 return;
624 }
625
626 if (supportVertexAttribBinding())
627 {
628 mFunctions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
629 }
630 else
631 {
632 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
633 // Binding.
634 mFunctions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex), adjustedDivisor);
635 }
636
637 mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
638 }
639
syncDirtyAttrib(const gl::Context * context,size_t attribIndex,const gl::VertexArray::DirtyAttribBits & dirtyAttribBits)640 void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
641 size_t attribIndex,
642 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
643 {
644 ASSERT(dirtyAttribBits.any());
645
646 for (size_t dirtyBit : dirtyAttribBits)
647 {
648 switch (dirtyBit)
649 {
650 case VertexArray::DIRTY_ATTRIB_ENABLED:
651 updateAttribEnabled(attribIndex);
652 break;
653
654 case VertexArray::DIRTY_ATTRIB_POINTER_BUFFER:
655 case VertexArray::DIRTY_ATTRIB_POINTER:
656 updateAttribPointer(context, attribIndex);
657 break;
658
659 case VertexArray::DIRTY_ATTRIB_FORMAT:
660 ASSERT(supportVertexAttribBinding());
661 updateAttribFormat(attribIndex);
662 break;
663
664 case VertexArray::DIRTY_ATTRIB_BINDING:
665 ASSERT(supportVertexAttribBinding());
666 updateAttribBinding(attribIndex);
667 break;
668
669 default:
670 UNREACHABLE();
671 break;
672 }
673 }
674 }
675
syncDirtyBinding(const gl::Context * context,size_t bindingIndex,const gl::VertexArray::DirtyBindingBits & dirtyBindingBits)676 void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
677 size_t bindingIndex,
678 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
679 {
680 // Dependent state changes in buffers can trigger updates with no dirty bits set.
681
682 for (size_t dirtyBit : dirtyBindingBits)
683 {
684 switch (dirtyBit)
685 {
686 case VertexArray::DIRTY_BINDING_BUFFER:
687 ASSERT(supportVertexAttribBinding());
688 updateBindingBuffer(context, bindingIndex);
689 break;
690
691 case VertexArray::DIRTY_BINDING_DIVISOR:
692 updateBindingDivisor(bindingIndex);
693 break;
694
695 default:
696 UNREACHABLE();
697 break;
698 }
699 }
700 }
701
702 #define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
703 case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
704 syncDirtyAttrib(context, INDEX, (*attribBits)[INDEX]); \
705 (*attribBits)[INDEX].reset(); \
706 break;
707
708 #define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
709 case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
710 syncDirtyBinding(context, INDEX, (*bindingBits)[INDEX]); \
711 (*bindingBits)[INDEX].reset(); \
712 break;
713
714 #define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
715 case VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
716 break;
717
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits,gl::VertexArray::DirtyAttribBitsArray * attribBits,gl::VertexArray::DirtyBindingBitsArray * bindingBits)718 angle::Result VertexArrayGL::syncState(const gl::Context *context,
719 const gl::VertexArray::DirtyBits &dirtyBits,
720 gl::VertexArray::DirtyAttribBitsArray *attribBits,
721 gl::VertexArray::DirtyBindingBitsArray *bindingBits)
722 {
723 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
724
725 for (size_t dirtyBit : dirtyBits)
726 {
727 switch (dirtyBit)
728 {
729 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
730 updateElementArrayBufferBinding(context);
731 break;
732
733 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
734 break;
735
736 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC)
737 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC)
738 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC)
739
740 default:
741 UNREACHABLE();
742 break;
743 }
744 }
745
746 return angle::Result::Continue;
747 }
748
applyNumViewsToDivisor(int numViews)749 void VertexArrayGL::applyNumViewsToDivisor(int numViews)
750 {
751 if (numViews != mAppliedNumViews)
752 {
753 mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
754 mAppliedNumViews = numViews;
755 for (size_t index = 0u; index < mAppliedBindings.size(); ++index)
756 {
757 updateBindingDivisor(index);
758 }
759 }
760 }
761
applyActiveAttribLocationsMask(const gl::AttributesMask & activeMask)762 void VertexArrayGL::applyActiveAttribLocationsMask(const gl::AttributesMask &activeMask)
763 {
764 gl::AttributesMask updateMask = mProgramActiveAttribLocationsMask ^ activeMask;
765 if (!updateMask.any())
766 {
767 return;
768 }
769 ASSERT(mVertexArrayID == mStateManager->getVertexArrayID());
770 mProgramActiveAttribLocationsMask = activeMask;
771
772 for (size_t attribIndex : updateMask)
773 {
774 updateAttribEnabled(attribIndex);
775 }
776 }
777
validateState() const778 void VertexArrayGL::validateState() const
779 {
780 // Ensure this vao is currently bound
781 ValidateStateHelperGetIntegerv(mFunctions, mVertexArrayID, GL_VERTEX_ARRAY_BINDING,
782 "mVertexArrayID", "GL_VERTEX_ARRAY_BINDING");
783
784 // Element array buffer
785 if (mAppliedElementArrayBuffer.get() == nullptr)
786 {
787 ValidateStateHelperGetIntegerv(
788 mFunctions, mStreamingElementArrayBuffer, GL_ELEMENT_ARRAY_BUFFER_BINDING,
789 "mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
790 }
791 else
792 {
793 const BufferGL *bufferGL = GetImplAs<BufferGL>(mAppliedElementArrayBuffer.get());
794 ValidateStateHelperGetIntegerv(
795 mFunctions, bufferGL->getBufferID(), GL_ELEMENT_ARRAY_BUFFER_BINDING,
796 "mAppliedElementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING");
797 }
798
799 // ValidateStateHelperGetIntegerv but with > comparison instead of !=
800 GLint queryValue;
801 mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &queryValue);
802 if (mAppliedAttributes.size() > static_cast<GLuint>(queryValue))
803 {
804 WARN() << "mAppliedAttributes.size() (" << mAppliedAttributes.size()
805 << ") > GL_MAX_VERTEX_ATTRIBS (" << queryValue << ")";
806 // Re-add ASSERT: http://anglebug.com/3900
807 // ASSERT(false);
808 }
809
810 // Check each applied attribute/binding
811 for (GLuint index = 0; index < mAppliedAttributes.size(); index++)
812 {
813 VertexAttribute &attribute = mAppliedAttributes[index];
814 ASSERT(attribute.bindingIndex < mAppliedBindings.size());
815 VertexBinding &binding = mAppliedBindings[attribute.bindingIndex];
816
817 ValidateStateHelperGetVertexAttribiv(
818 mFunctions, index, attribute.enabled, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
819 "mAppliedAttributes.enabled", "GL_VERTEX_ATTRIB_ARRAY_ENABLED");
820
821 if (attribute.enabled)
822 {
823 // Applied attributes
824 ASSERT(attribute.format);
825 ValidateStateHelperGetVertexAttribiv(
826 mFunctions, index, ToGLenum(attribute.format->vertexAttribType),
827 GL_VERTEX_ATTRIB_ARRAY_TYPE, "mAppliedAttributes.format->vertexAttribType",
828 "GL_VERTEX_ATTRIB_ARRAY_TYPE");
829 ValidateStateHelperGetVertexAttribiv(
830 mFunctions, index, attribute.format->channelCount, GL_VERTEX_ATTRIB_ARRAY_SIZE,
831 "attribute.format->channelCount", "GL_VERTEX_ATTRIB_ARRAY_SIZE");
832 ValidateStateHelperGetVertexAttribiv(
833 mFunctions, index, attribute.format->isNorm(), GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
834 "attribute.format->isNorm()", "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED");
835 ValidateStateHelperGetVertexAttribiv(
836 mFunctions, index, attribute.format->isPureInt(), GL_VERTEX_ATTRIB_ARRAY_INTEGER,
837 "attribute.format->isPureInt()", "GL_VERTEX_ATTRIB_ARRAY_INTEGER");
838 if (supportVertexAttribBinding())
839 {
840 ValidateStateHelperGetVertexAttribiv(
841 mFunctions, index, attribute.relativeOffset, GL_VERTEX_ATTRIB_RELATIVE_OFFSET,
842 "attribute.relativeOffset", "GL_VERTEX_ATTRIB_RELATIVE_OFFSET");
843 ValidateStateHelperGetVertexAttribiv(
844 mFunctions, index, attribute.bindingIndex, GL_VERTEX_ATTRIB_BINDING,
845 "attribute.bindingIndex", "GL_VERTEX_ATTRIB_BINDING");
846 }
847
848 // Applied bindings
849 if (binding.getBuffer().get() == nullptr)
850 {
851 ValidateStateHelperGetVertexAttribiv(
852 mFunctions, index, mStreamingArrayBuffer, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
853 "mAppliedBindings.bufferID", "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
854 }
855 else
856 {
857 const BufferGL *arrayBufferGL = GetImplAs<BufferGL>(binding.getBuffer().get());
858 ASSERT(arrayBufferGL);
859 ValidateStateHelperGetVertexAttribiv(
860 mFunctions, index, arrayBufferGL->getBufferID(),
861 GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, "mAppliedBindings.bufferID",
862 "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING");
863 ValidateStateHelperGetVertexAttribiv(
864 mFunctions, index, binding.getStride(), GL_VERTEX_ATTRIB_ARRAY_STRIDE,
865 "binding.getStride()", "GL_VERTEX_ATTRIB_ARRAY_STRIDE");
866 ValidateStateHelperGetVertexAttribiv(
867 mFunctions, index, binding.getDivisor(), GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
868 "binding.getDivisor()", "GL_VERTEX_ATTRIB_ARRAY_DIVISOR");
869 }
870 }
871 }
872 }
873
874 } // namespace rx
875