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 {
31
GetNativeBufferID(const gl::Buffer * frontendBuffer)32 GLuint GetNativeBufferID(const gl::Buffer *frontendBuffer)
33 {
34 return frontendBuffer ? GetImplAs<BufferGL>(frontendBuffer)->getBufferID() : 0;
35 }
36
SameVertexAttribFormat(const VertexAttributeGL & a,const VertexAttribute & b)37 bool SameVertexAttribFormat(const VertexAttributeGL &a, const VertexAttribute &b)
38 {
39 return a.format == b.format && a.relativeOffset == b.relativeOffset;
40 }
41
SameVertexBuffer(const VertexBindingGL & a,const VertexBinding & b)42 bool SameVertexBuffer(const VertexBindingGL &a, const VertexBinding &b)
43 {
44 return a.stride == b.getStride() && a.offset == b.getOffset() &&
45 a.buffer == GetNativeBufferID(b.getBuffer().get());
46 }
47
SameIndexBuffer(const VertexArrayStateGL * a,const gl::Buffer * frontendBuffer)48 bool SameIndexBuffer(const VertexArrayStateGL *a, const gl::Buffer *frontendBuffer)
49 {
50 return a->elementArrayBuffer == GetNativeBufferID(frontendBuffer);
51 }
52
SameAttribPointer(const VertexAttributeGL & a,const VertexAttribute & b)53 bool SameAttribPointer(const VertexAttributeGL &a, const VertexAttribute &b)
54 {
55 return a.pointer == b.pointer;
56 }
57
IsVertexAttribPointerSupported(size_t attribIndex,const VertexAttribute & attrib)58 bool IsVertexAttribPointerSupported(size_t attribIndex, const VertexAttribute &attrib)
59 {
60 return (attribIndex == attrib.bindingIndex && attrib.relativeOffset == 0);
61 }
62
GetAdjustedDivisor(GLuint numViews,GLuint divisor)63 GLuint GetAdjustedDivisor(GLuint numViews, GLuint divisor)
64 {
65 return numViews * divisor;
66 }
67
ValidateStateHelperGetIntegerv(const gl::Context * context,const GLuint localValue,const GLenum pname,const char * localName,const char * driverName)68 static angle::Result ValidateStateHelperGetIntegerv(const gl::Context *context,
69 const GLuint localValue,
70 const GLenum pname,
71 const char *localName,
72 const char *driverName)
73 {
74 const FunctionsGL *functions = GetFunctionsGL(context);
75
76 GLint queryValue;
77 ANGLE_GL_TRY(context, functions->getIntegerv(pname, &queryValue));
78 if (localValue != static_cast<GLuint>(queryValue))
79 {
80 WARN() << localName << " (" << localValue << ") != " << driverName << " (" << queryValue
81 << ")";
82 // Re-add ASSERT: http://anglebug.com/42262547
83 // ASSERT(false);
84 }
85
86 return angle::Result::Continue;
87 }
88
ValidateStateHelperGetVertexAttribiv(const gl::Context * context,const GLint index,const GLuint localValue,const GLenum pname,const char * localName,const char * driverName)89 static angle::Result ValidateStateHelperGetVertexAttribiv(const gl::Context *context,
90 const GLint index,
91 const GLuint localValue,
92 const GLenum pname,
93 const char *localName,
94 const char *driverName)
95 {
96 const FunctionsGL *functions = GetFunctionsGL(context);
97
98 GLint queryValue;
99 ANGLE_GL_TRY(context, functions->getVertexAttribiv(index, pname, &queryValue));
100 if (localValue != static_cast<GLuint>(queryValue))
101 {
102 WARN() << localName << "[" << index << "] (" << localValue << ") != " << driverName << "["
103 << index << "] (" << queryValue << ")";
104 // Re-add ASSERT: http://anglebug.com/42262547
105 // ASSERT(false);
106 }
107
108 return angle::Result::Continue;
109 }
110 } // anonymous namespace
111
VertexArrayGL(const VertexArrayState & state,GLuint id)112 VertexArrayGL::VertexArrayGL(const VertexArrayState &state, GLuint id)
113 : VertexArrayImpl(state),
114 mVertexArrayID(id),
115 mOwnsNativeState(true),
116 mNativeState(new VertexArrayStateGL(state.getMaxAttribs(), state.getMaxBindings()))
117 {
118 mForcedStreamingAttributesFirstOffsets.fill(0);
119 }
120
VertexArrayGL(const gl::VertexArrayState & state,GLuint id,VertexArrayStateGL * sharedState)121 VertexArrayGL::VertexArrayGL(const gl::VertexArrayState &state,
122 GLuint id,
123 VertexArrayStateGL *sharedState)
124 : VertexArrayImpl(state), mVertexArrayID(id), mOwnsNativeState(false), mNativeState(sharedState)
125 {
126 ASSERT(mNativeState);
127 mForcedStreamingAttributesFirstOffsets.fill(0);
128 }
129
~VertexArrayGL()130 VertexArrayGL::~VertexArrayGL() {}
131
destroy(const gl::Context * context)132 void VertexArrayGL::destroy(const gl::Context *context)
133 {
134 StateManagerGL *stateManager = GetStateManagerGL(context);
135
136 if (mOwnsNativeState)
137 {
138 stateManager->deleteVertexArray(mVertexArrayID);
139 }
140 mVertexArrayID = 0;
141 mAppliedNumViews = 1;
142
143 mElementArrayBuffer.set(context, nullptr);
144 for (gl::BindingPointer<gl::Buffer> &binding : mArrayBuffers)
145 {
146 binding.set(context, nullptr);
147 }
148
149 stateManager->deleteBuffer(mStreamingElementArrayBuffer);
150 mStreamingElementArrayBufferSize = 0;
151 mStreamingElementArrayBuffer = 0;
152
153 stateManager->deleteBuffer(mStreamingArrayBuffer);
154 mStreamingArrayBufferSize = 0;
155 mStreamingArrayBuffer = 0;
156
157 if (mOwnsNativeState)
158 {
159 delete mNativeState;
160 }
161 mNativeState = nullptr;
162 }
163
syncClientSideData(const gl::Context * context,const gl::AttributesMask & activeAttributesMask,GLint first,GLsizei count,GLsizei instanceCount) const164 angle::Result VertexArrayGL::syncClientSideData(const gl::Context *context,
165 const gl::AttributesMask &activeAttributesMask,
166 GLint first,
167 GLsizei count,
168 GLsizei instanceCount) const
169 {
170 return syncDrawState(context, activeAttributesMask, first, count,
171 gl::DrawElementsType::InvalidEnum, nullptr, instanceCount, false, nullptr);
172 }
173
updateElementArrayBufferBinding(const gl::Context * context) const174 angle::Result VertexArrayGL::updateElementArrayBufferBinding(const gl::Context *context) const
175 {
176 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
177 if (!SameIndexBuffer(mNativeState, elementArrayBuffer))
178 {
179 GLuint elementArrayBufferId =
180 elementArrayBuffer ? GetNativeBufferID(elementArrayBuffer) : 0;
181
182 StateManagerGL *stateManager = GetStateManagerGL(context);
183 stateManager->bindBuffer(gl::BufferBinding::ElementArray, elementArrayBufferId);
184 mElementArrayBuffer.set(context, elementArrayBuffer);
185 mNativeState->elementArrayBuffer = elementArrayBufferId;
186 }
187
188 return angle::Result::Continue;
189 }
190
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) const191 angle::Result VertexArrayGL::syncDrawState(const gl::Context *context,
192 const gl::AttributesMask &activeAttributesMask,
193 GLint first,
194 GLsizei count,
195 gl::DrawElementsType type,
196 const void *indices,
197 GLsizei instanceCount,
198 bool primitiveRestartEnabled,
199 const void **outIndices) const
200 {
201 const FunctionsGL *functions = GetFunctionsGL(context);
202
203 // Check if any attributes need to be streamed, determines if the index range needs to be
204 // computed
205 gl::AttributesMask needsStreamingAttribs =
206 context->getStateCache().getActiveClientAttribsMask();
207 if (nativegl::CanUseClientSideArrays(functions, mVertexArrayID))
208 {
209 needsStreamingAttribs.reset();
210 }
211
212 // Determine if an index buffer needs to be streamed and the range of vertices that need to be
213 // copied
214 IndexRange indexRange;
215 const angle::FeaturesGL &features = GetFeaturesGL(context);
216 if (type != gl::DrawElementsType::InvalidEnum)
217 {
218 ANGLE_TRY(syncIndexData(context, count, type, indices, primitiveRestartEnabled,
219 needsStreamingAttribs.any(), &indexRange, outIndices));
220 }
221 else
222 {
223 // Not an indexed call, set the range to [first, first + count - 1]
224 indexRange.start = first;
225 indexRange.end = first + count - 1;
226
227 if (features.shiftInstancedArrayDataWithOffset.enabled && first > 0)
228 {
229 gl::AttributesMask updatedStreamingAttribsMask = needsStreamingAttribs;
230 auto candidateAttributesMask =
231 mInstancedAttributesMask & mProgramActiveAttribLocationsMask;
232 for (auto attribIndex : candidateAttributesMask)
233 {
234
235 if (mForcedStreamingAttributesFirstOffsets[attribIndex] != first)
236 {
237 updatedStreamingAttribsMask.set(attribIndex);
238 mForcedStreamingAttributesForDrawArraysInstancedMask.set(attribIndex);
239 mForcedStreamingAttributesFirstOffsets[attribIndex] = first;
240 }
241 }
242
243 // We need to recover attributes whose divisor used to be > 0 but is reset to 0 now if
244 // any
245 auto forcedStreamingAttributesNeedRecoverMask =
246 candidateAttributesMask ^ mForcedStreamingAttributesForDrawArraysInstancedMask;
247 if (forcedStreamingAttributesNeedRecoverMask.any())
248 {
249 ANGLE_TRY(recoverForcedStreamingAttributesForDrawArraysInstanced(
250 context, &forcedStreamingAttributesNeedRecoverMask));
251 mForcedStreamingAttributesForDrawArraysInstancedMask = candidateAttributesMask;
252 }
253
254 if (updatedStreamingAttribsMask.any())
255 {
256 ANGLE_TRY(streamAttributes(context, updatedStreamingAttribsMask, instanceCount,
257 indexRange, true));
258 }
259 return angle::Result::Continue;
260 }
261 }
262
263 if (needsStreamingAttribs.any())
264 {
265 ANGLE_TRY(
266 streamAttributes(context, needsStreamingAttribs, instanceCount, indexRange, false));
267 }
268
269 return angle::Result::Continue;
270 }
271
syncIndexData(const gl::Context * context,GLsizei count,gl::DrawElementsType type,const void * indices,bool primitiveRestartEnabled,bool attributesNeedStreaming,IndexRange * outIndexRange,const void ** outIndices) const272 angle::Result VertexArrayGL::syncIndexData(const gl::Context *context,
273 GLsizei count,
274 gl::DrawElementsType type,
275 const void *indices,
276 bool primitiveRestartEnabled,
277 bool attributesNeedStreaming,
278 IndexRange *outIndexRange,
279 const void **outIndices) const
280 {
281 ASSERT(outIndices);
282
283 const FunctionsGL *functions = GetFunctionsGL(context);
284
285 gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
286
287 // Need to check the range of indices if attributes need to be streamed
288 if (elementArrayBuffer)
289 {
290 ASSERT(SameIndexBuffer(mNativeState, elementArrayBuffer));
291 // Only compute the index range if the attributes also need to be streamed
292 if (attributesNeedStreaming)
293 {
294 ptrdiff_t elementArrayBufferOffset = reinterpret_cast<ptrdiff_t>(indices);
295 ANGLE_TRY(mState.getElementArrayBuffer()->getIndexRange(
296 context, type, elementArrayBufferOffset, count, primitiveRestartEnabled,
297 outIndexRange));
298 }
299
300 // Indices serves as an offset into the index buffer in this case, use the same value for
301 // the draw call
302 *outIndices = indices;
303 }
304 else if (nativegl::CanUseClientSideArrays(functions, mVertexArrayID))
305 {
306 ASSERT(SameIndexBuffer(mNativeState, nullptr));
307
308 // Use the client index data directly
309 *outIndices = indices;
310 }
311 else
312 {
313 StateManagerGL *stateManager = GetStateManagerGL(context);
314
315 // Need to stream the index buffer
316
317 // Only compute the index range if the attributes also need to be streamed
318 if (attributesNeedStreaming)
319 {
320 *outIndexRange = ComputeIndexRange(type, indices, count, primitiveRestartEnabled);
321 }
322
323 // Allocate the streaming element array buffer
324 if (mStreamingElementArrayBuffer == 0)
325 {
326 ANGLE_GL_TRY(context, functions->genBuffers(1, &mStreamingElementArrayBuffer));
327 mStreamingElementArrayBufferSize = 0;
328 }
329
330 stateManager->bindVertexArray(mVertexArrayID, mNativeState);
331
332 stateManager->bindBuffer(gl::BufferBinding::ElementArray, mStreamingElementArrayBuffer);
333 mElementArrayBuffer.set(context, nullptr);
334 mNativeState->elementArrayBuffer = mStreamingElementArrayBuffer;
335
336 // Make sure the element array buffer is large enough
337 const GLuint indexTypeBytes = gl::GetDrawElementsTypeSize(type);
338 size_t requiredStreamingBufferSize = indexTypeBytes * count;
339 if (requiredStreamingBufferSize > mStreamingElementArrayBufferSize)
340 {
341 // Copy the indices in while resizing the buffer
342 ANGLE_GL_TRY(context,
343 functions->bufferData(GL_ELEMENT_ARRAY_BUFFER, requiredStreamingBufferSize,
344 indices, GL_DYNAMIC_DRAW));
345 mStreamingElementArrayBufferSize = requiredStreamingBufferSize;
346 }
347 else
348 {
349 // Put the indices at the beginning of the buffer
350 ANGLE_GL_TRY(context, functions->bufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0,
351 requiredStreamingBufferSize, indices));
352 }
353
354 // Set the index offset for the draw call to zero since the supplied index pointer is to
355 // client data
356 *outIndices = nullptr;
357 }
358
359 return angle::Result::Continue;
360 }
361
computeStreamingAttributeSizes(const gl::AttributesMask & attribsToStream,GLsizei instanceCount,const gl::IndexRange & indexRange,size_t * outStreamingDataSize,size_t * outMaxAttributeDataSize) const362 void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &attribsToStream,
363 GLsizei instanceCount,
364 const gl::IndexRange &indexRange,
365 size_t *outStreamingDataSize,
366 size_t *outMaxAttributeDataSize) const
367 {
368 *outStreamingDataSize = 0;
369 *outMaxAttributeDataSize = 0;
370
371 ASSERT(attribsToStream.any());
372
373 const auto &attribs = mState.getVertexAttributes();
374 const auto &bindings = mState.getVertexBindings();
375
376 for (auto idx : attribsToStream)
377 {
378 const auto &attrib = attribs[idx];
379 const auto &binding = bindings[attrib.bindingIndex];
380
381 // If streaming is going to be required, compute the size of the required buffer
382 // and how much slack space at the beginning of the buffer will be required by determining
383 // the attribute with the largest data size.
384 size_t typeSize = ComputeVertexAttributeTypeSize(attrib);
385 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
386 *outStreamingDataSize +=
387 typeSize * ComputeVertexBindingElementCount(adjustedDivisor, indexRange.vertexCount(),
388 instanceCount);
389 *outMaxAttributeDataSize = std::max(*outMaxAttributeDataSize, typeSize);
390 }
391 }
392
streamAttributes(const gl::Context * context,const gl::AttributesMask & attribsToStream,GLsizei instanceCount,const gl::IndexRange & indexRange,bool applyExtraOffsetWorkaroundForInstancedAttributes) const393 angle::Result VertexArrayGL::streamAttributes(
394 const gl::Context *context,
395 const gl::AttributesMask &attribsToStream,
396 GLsizei instanceCount,
397 const gl::IndexRange &indexRange,
398 bool applyExtraOffsetWorkaroundForInstancedAttributes) const
399 {
400 const FunctionsGL *functions = GetFunctionsGL(context);
401 StateManagerGL *stateManager = GetStateManagerGL(context);
402
403 // Sync the vertex attribute state and track what data needs to be streamed
404 size_t streamingDataSize = 0;
405 size_t maxAttributeDataSize = 0;
406
407 computeStreamingAttributeSizes(attribsToStream, instanceCount, indexRange, &streamingDataSize,
408 &maxAttributeDataSize);
409
410 if (streamingDataSize == 0)
411 {
412 return angle::Result::Continue;
413 }
414
415 if (mStreamingArrayBuffer == 0)
416 {
417 ANGLE_GL_TRY(context, functions->genBuffers(1, &mStreamingArrayBuffer));
418 mStreamingArrayBufferSize = 0;
419 }
420
421 // If first is greater than zero, a slack space needs to be left at the beginning of the buffer
422 // for each attribute so that the same 'first' argument can be passed into the draw call.
423 const size_t bufferEmptySpace =
424 attribsToStream.count() * maxAttributeDataSize * indexRange.start;
425 const size_t requiredBufferSize = streamingDataSize + bufferEmptySpace;
426
427 stateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
428 if (requiredBufferSize > mStreamingArrayBufferSize)
429 {
430 ANGLE_GL_TRY(context, functions->bufferData(GL_ARRAY_BUFFER, requiredBufferSize, nullptr,
431 GL_DYNAMIC_DRAW));
432 mStreamingArrayBufferSize = requiredBufferSize;
433 }
434
435 stateManager->bindVertexArray(mVertexArrayID, mNativeState);
436
437 // Unmapping a buffer can return GL_FALSE to indicate that the system has corrupted the data
438 // somehow (such as by a screen change), retry writing the data a few times and return
439 // OUT_OF_MEMORY if that fails.
440 GLboolean unmapResult = GL_FALSE;
441 size_t unmapRetryAttempts = 5;
442 while (unmapResult != GL_TRUE && --unmapRetryAttempts > 0)
443 {
444 uint8_t *bufferPointer = MapBufferRangeWithFallback(functions, GL_ARRAY_BUFFER, 0,
445 requiredBufferSize, GL_MAP_WRITE_BIT);
446 size_t curBufferOffset = maxAttributeDataSize * indexRange.start;
447
448 const auto &attribs = mState.getVertexAttributes();
449 const auto &bindings = mState.getVertexBindings();
450
451 for (auto idx : attribsToStream)
452 {
453 const auto &attrib = attribs[idx];
454 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
455
456 const auto &binding = bindings[attrib.bindingIndex];
457
458 GLuint adjustedDivisor = GetAdjustedDivisor(mAppliedNumViews, binding.getDivisor());
459 // streamedVertexCount is only going to be modified by
460 // shiftInstancedArrayDataWithOffset workaround, otherwise it's const
461 size_t streamedVertexCount = ComputeVertexBindingElementCount(
462 adjustedDivisor, indexRange.vertexCount(), instanceCount);
463
464 const size_t sourceStride = ComputeVertexAttributeStride(attrib, binding);
465 const size_t destStride = ComputeVertexAttributeTypeSize(attrib);
466
467 // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
468 // a non-instanced draw call
469 const size_t firstIndex =
470 (adjustedDivisor == 0 || applyExtraOffsetWorkaroundForInstancedAttributes)
471 ? indexRange.start
472 : 0;
473
474 // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
475 // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
476 const uint8_t *inputPointer = static_cast<const uint8_t *>(attrib.pointer);
477 // store batchMemcpySize since streamedVertexCount could be changed by workaround
478 const size_t batchMemcpySize = destStride * streamedVertexCount;
479
480 size_t batchMemcpyInputOffset = sourceStride * firstIndex;
481 bool needsUnmapAndRebindStreamingAttributeBuffer = false;
482 size_t firstIndexForSeparateCopy = firstIndex;
483
484 if (applyExtraOffsetWorkaroundForInstancedAttributes && adjustedDivisor > 0)
485 {
486 const size_t originalStreamedVertexCount = streamedVertexCount;
487 streamedVertexCount =
488 (instanceCount + indexRange.start + adjustedDivisor - 1u) / adjustedDivisor;
489
490 const size_t copySize =
491 sourceStride *
492 originalStreamedVertexCount; // the real data in the buffer we are streaming
493
494 const gl::Buffer *bindingBufferPointer = binding.getBuffer().get();
495 if (!bindingBufferPointer)
496 {
497 if (!inputPointer)
498 {
499 continue;
500 }
501 inputPointer = static_cast<const uint8_t *>(attrib.pointer);
502 }
503 else
504 {
505 needsUnmapAndRebindStreamingAttributeBuffer = true;
506 const auto buffer = GetImplAs<BufferGL>(bindingBufferPointer);
507 stateManager->bindBuffer(gl::BufferBinding::Array, buffer->getBufferID());
508 // The workaround is only for latest Mac Intel so glMapBufferRange should be
509 // supported
510 ASSERT(CanMapBufferForRead(functions));
511 // Validate if there is OOB access of the input buffer.
512 angle::CheckedNumeric<GLint64> inputRequiredSize;
513 inputRequiredSize = copySize;
514 inputRequiredSize += static_cast<unsigned int>(binding.getOffset());
515 ANGLE_CHECK(GetImplAs<ContextGL>(context),
516 inputRequiredSize.IsValid() && inputRequiredSize.ValueOrDie() <=
517 bindingBufferPointer->getSize(),
518 "Failed to map buffer range of the attribute buffer.",
519 GL_OUT_OF_MEMORY);
520 uint8_t *inputBufferPointer = MapBufferRangeWithFallback(
521 functions, GL_ARRAY_BUFFER, binding.getOffset(), copySize, GL_MAP_READ_BIT);
522 ASSERT(inputBufferPointer);
523 inputPointer = inputBufferPointer;
524 }
525
526 batchMemcpyInputOffset = 0;
527 firstIndexForSeparateCopy = 0;
528 }
529
530 // Pack the data when copying it, user could have supplied a very large stride that
531 // would cause the buffer to be much larger than needed.
532 if (destStride == sourceStride)
533 {
534 // Can copy in one go, the data is packed
535 memcpy(bufferPointer + curBufferOffset, inputPointer + batchMemcpyInputOffset,
536 batchMemcpySize);
537 }
538 else
539 {
540 for (size_t vertexIdx = 0; vertexIdx < streamedVertexCount; vertexIdx++)
541 {
542 uint8_t *out = bufferPointer + curBufferOffset + (destStride * vertexIdx);
543 const uint8_t *in =
544 inputPointer + sourceStride * (vertexIdx + firstIndexForSeparateCopy);
545 memcpy(out, in, destStride);
546 }
547 }
548
549 if (needsUnmapAndRebindStreamingAttributeBuffer)
550 {
551 ANGLE_GL_TRY(context, functions->unmapBuffer(GL_ARRAY_BUFFER));
552 stateManager->bindBuffer(gl::BufferBinding::Array, mStreamingArrayBuffer);
553 }
554
555 // Compute where the 0-index vertex would be.
556 const size_t vertexStartOffset = curBufferOffset - (firstIndex * destStride);
557
558 ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(idx), attrib,
559 static_cast<GLsizei>(destStride),
560 static_cast<GLintptr>(vertexStartOffset)));
561
562 // Update the state to track the streamed attribute
563 mNativeState->attributes[idx].format = attrib.format;
564
565 mNativeState->attributes[idx].relativeOffset = 0;
566 mNativeState->attributes[idx].bindingIndex = static_cast<GLuint>(idx);
567
568 mNativeState->bindings[idx].stride = static_cast<GLsizei>(destStride);
569 mNativeState->bindings[idx].offset = static_cast<GLintptr>(vertexStartOffset);
570 mArrayBuffers[idx].set(context, nullptr);
571 mNativeState->bindings[idx].buffer = mStreamingArrayBuffer;
572
573 // There's maxAttributeDataSize * indexRange.start of empty space allocated for each
574 // streaming attributes
575 curBufferOffset +=
576 destStride * streamedVertexCount + maxAttributeDataSize * indexRange.start;
577 }
578
579 unmapResult = ANGLE_GL_TRY(context, functions->unmapBuffer(GL_ARRAY_BUFFER));
580 }
581
582 ANGLE_CHECK(GetImplAs<ContextGL>(context), unmapResult == GL_TRUE,
583 "Failed to unmap the client data streaming buffer.", GL_OUT_OF_MEMORY);
584 return angle::Result::Continue;
585 }
586
recoverForcedStreamingAttributesForDrawArraysInstanced(const gl::Context * context) const587 angle::Result VertexArrayGL::recoverForcedStreamingAttributesForDrawArraysInstanced(
588 const gl::Context *context) const
589 {
590 return recoverForcedStreamingAttributesForDrawArraysInstanced(
591 context, &mForcedStreamingAttributesForDrawArraysInstancedMask);
592 }
593
recoverForcedStreamingAttributesForDrawArraysInstanced(const gl::Context * context,gl::AttributesMask * attributeMask) const594 angle::Result VertexArrayGL::recoverForcedStreamingAttributesForDrawArraysInstanced(
595 const gl::Context *context,
596 gl::AttributesMask *attributeMask) const
597 {
598 if (attributeMask->none())
599 {
600 return angle::Result::Continue;
601 }
602
603 StateManagerGL *stateManager = GetStateManagerGL(context);
604
605 stateManager->bindVertexArray(mVertexArrayID, mNativeState);
606
607 const auto &attribs = mState.getVertexAttributes();
608 const auto &bindings = mState.getVertexBindings();
609 for (auto idx : *attributeMask)
610 {
611 const auto &attrib = attribs[idx];
612 ASSERT(IsVertexAttribPointerSupported(idx, attrib));
613
614 const auto &binding = bindings[attrib.bindingIndex];
615 const auto buffer = GetImplAs<BufferGL>(binding.getBuffer().get());
616 stateManager->bindBuffer(gl::BufferBinding::Array, buffer->getBufferID());
617
618 ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(idx), attrib,
619 static_cast<GLsizei>(binding.getStride()),
620 static_cast<GLintptr>(binding.getOffset())));
621
622 // Restore the state to track their original buffers
623 mNativeState->attributes[idx].format = attrib.format;
624
625 mNativeState->attributes[idx].relativeOffset = 0;
626 mNativeState->attributes[idx].bindingIndex = static_cast<GLuint>(attrib.bindingIndex);
627
628 mNativeState->bindings[idx].stride = binding.getStride();
629 mNativeState->bindings[idx].offset = binding.getOffset();
630 mArrayBuffers[idx].set(context, binding.getBuffer().get());
631 mNativeState->bindings[idx].buffer = buffer->getBufferID();
632 }
633
634 attributeMask->reset();
635 mForcedStreamingAttributesFirstOffsets.fill(0);
636
637 return angle::Result::Continue;
638 }
639
getVertexArrayID() const640 GLuint VertexArrayGL::getVertexArrayID() const
641 {
642 return mVertexArrayID;
643 }
644
getNativeState() const645 rx::VertexArrayStateGL *VertexArrayGL::getNativeState() const
646 {
647 return mNativeState;
648 }
649
updateAttribEnabled(const gl::Context * context,size_t attribIndex)650 angle::Result VertexArrayGL::updateAttribEnabled(const gl::Context *context, size_t attribIndex)
651 {
652 const bool enabled = mState.getVertexAttribute(attribIndex).enabled &&
653 mProgramActiveAttribLocationsMask.test(attribIndex);
654 if (mNativeState->attributes[attribIndex].enabled == enabled)
655 {
656 return angle::Result::Continue;
657 }
658
659 const FunctionsGL *functions = GetFunctionsGL(context);
660
661 if (enabled)
662 {
663 ANGLE_GL_TRY(context, functions->enableVertexAttribArray(static_cast<GLuint>(attribIndex)));
664 }
665 else
666 {
667 ANGLE_GL_TRY(context,
668 functions->disableVertexAttribArray(static_cast<GLuint>(attribIndex)));
669 }
670
671 mNativeState->attributes[attribIndex].enabled = enabled;
672 return angle::Result::Continue;
673 }
674
updateAttribPointer(const gl::Context * context,size_t attribIndex)675 angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
676 {
677 const angle::FeaturesGL &features = GetFeaturesGL(context);
678 const FunctionsGL *functions = GetFunctionsGL(context);
679
680 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
681
682 // According to SPEC, VertexAttribPointer should update the binding indexed attribIndex instead
683 // of the binding indexed attrib.bindingIndex (unless attribIndex == attrib.bindingIndex).
684 const VertexBinding &binding = mState.getVertexBinding(attribIndex);
685
686 const bool canUseClientArrays = nativegl::CanUseClientSideArrays(functions, mVertexArrayID);
687
688 // Early return when the vertex attribute isn't using a buffer object:
689 // - If we need to stream, defer the attribPointer to the draw call.
690 // - Skip the attribute that is disabled and uses a client memory pointer.
691 // - Skip the attribute whose buffer is detached by BindVertexBuffer. Since it cannot have a
692 // client memory pointer either, it must be disabled and shouldn't affect the draw.
693 const auto &bindingBuffer = binding.getBuffer();
694 gl::Buffer *arrayBuffer = bindingBuffer.get();
695 if (arrayBuffer == nullptr && !canUseClientArrays)
696 {
697 // Mark the applied binding isn't using a buffer by setting its buffer to nullptr so that if
698 // it starts to use a buffer later, there is no chance that the caching will skip it.
699
700 mArrayBuffers[attribIndex].set(context, nullptr);
701 mNativeState->bindings[attribIndex].buffer = 0;
702 return angle::Result::Continue;
703 }
704
705 // We do not need to compare attrib.pointer because when we use a different client memory
706 // pointer, we don't need to update mAttributesNeedStreaming by binding.buffer and we won't
707 // update attribPointer in this function.
708 if (SameVertexAttribFormat(mNativeState->attributes[attribIndex], attrib) &&
709 (mNativeState->attributes[attribIndex].bindingIndex == attrib.bindingIndex) &&
710 SameVertexBuffer(mNativeState->bindings[attribIndex], binding) &&
711 (!canUseClientArrays || SameAttribPointer(mNativeState->attributes[attribIndex], attrib)))
712 {
713 return angle::Result::Continue;
714 }
715
716 StateManagerGL *stateManager = GetStateManagerGL(context);
717 GLuint bufferId = 0;
718 if (arrayBuffer != nullptr)
719 {
720 // When ANGLE uses non-zero VAO, we cannot use a client memory pointer on it:
721 // [OpenGL ES 3.0.2] Section 2.8 page 24:
722 // An INVALID_OPERATION error is generated when a non-zero vertex array object is bound,
723 // zero is bound to the ARRAY_BUFFER buffer object binding point, and the pointer argument
724 // is not NULL.
725
726 BufferGL *bufferGL = GetImplAs<BufferGL>(arrayBuffer);
727 bufferId = bufferGL->getBufferID();
728 stateManager->bindBuffer(gl::BufferBinding::Array, bufferId);
729 if (features.ensureNonEmptyBufferIsBoundForDraw.enabled && bufferGL->getBufferSize() == 0)
730 {
731 constexpr uint32_t data = 0;
732 ANGLE_TRY(bufferGL->setData(context, gl::BufferBinding::Array, &data, sizeof(data),
733 gl::BufferUsage::StaticDraw));
734 ASSERT(bufferGL->getBufferSize() > 0);
735 }
736 ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib,
737 binding.getStride(), binding.getOffset()));
738 }
739 else
740 {
741 ASSERT(canUseClientArrays);
742 stateManager->bindBuffer(gl::BufferBinding::Array, 0);
743 ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib,
744 binding.getStride(),
745 reinterpret_cast<GLintptr>(attrib.pointer)));
746 }
747
748 mNativeState->attributes[attribIndex].format = attrib.format;
749
750 // After VertexAttribPointer, attrib.relativeOffset is set to 0 and attrib.bindingIndex is set
751 // to attribIndex in driver. If attrib.relativeOffset != 0 or attrib.bindingIndex !=
752 // attribIndex, they should be set in updateAttribFormat and updateAttribBinding. The cache
753 // should be consistent with driver so that we won't miss anything.
754 mNativeState->attributes[attribIndex].pointer = attrib.pointer;
755 mNativeState->attributes[attribIndex].relativeOffset = 0;
756 mNativeState->attributes[attribIndex].bindingIndex = static_cast<GLuint>(attribIndex);
757
758 mNativeState->bindings[attribIndex].stride = binding.getStride();
759 mNativeState->bindings[attribIndex].offset = binding.getOffset();
760 mArrayBuffers[attribIndex].set(context, arrayBuffer);
761 mNativeState->bindings[attribIndex].buffer = bufferId;
762
763 return angle::Result::Continue;
764 }
765
callVertexAttribPointer(const gl::Context * context,GLuint attribIndex,const VertexAttribute & attrib,GLsizei stride,GLintptr offset) const766 angle::Result VertexArrayGL::callVertexAttribPointer(const gl::Context *context,
767 GLuint attribIndex,
768 const VertexAttribute &attrib,
769 GLsizei stride,
770 GLintptr offset) const
771 {
772 const FunctionsGL *functions = GetFunctionsGL(context);
773 const GLvoid *pointer = reinterpret_cast<const GLvoid *>(offset);
774 const angle::Format &format = *attrib.format;
775 if (format.isPureInt())
776 {
777 ASSERT(!format.isNorm());
778 ANGLE_GL_TRY(context, functions->vertexAttribIPointer(attribIndex, format.channelCount,
779 gl::ToGLenum(format.vertexAttribType),
780 stride, pointer));
781 }
782 else
783 {
784 ANGLE_GL_TRY(context, functions->vertexAttribPointer(attribIndex, format.channelCount,
785 gl::ToGLenum(format.vertexAttribType),
786 format.isNorm(), stride, pointer));
787 }
788
789 return angle::Result::Continue;
790 }
791
supportVertexAttribBinding(const gl::Context * context) const792 bool VertexArrayGL::supportVertexAttribBinding(const gl::Context *context) const
793 {
794 const FunctionsGL *functions = GetFunctionsGL(context);
795 ASSERT(functions);
796 // Vertex attrib bindings are not supported on the default VAO so if we're syncing to the
797 // default VAO due to the feature, disable bindings.
798 return (functions->vertexAttribBinding != nullptr) && mVertexArrayID != 0;
799 }
800
updateAttribFormat(const gl::Context * context,size_t attribIndex)801 angle::Result VertexArrayGL::updateAttribFormat(const gl::Context *context, size_t attribIndex)
802 {
803 ASSERT(supportVertexAttribBinding(context));
804
805 const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
806 if (SameVertexAttribFormat(mNativeState->attributes[attribIndex], attrib))
807 {
808 return angle::Result::Continue;
809 }
810
811 const FunctionsGL *functions = GetFunctionsGL(context);
812
813 const angle::Format &format = *attrib.format;
814 if (format.isPureInt())
815 {
816 ASSERT(!format.isNorm());
817 ANGLE_GL_TRY(context, functions->vertexAttribIFormat(
818 static_cast<GLuint>(attribIndex), format.channelCount,
819 gl::ToGLenum(format.vertexAttribType), attrib.relativeOffset));
820 }
821 else
822 {
823 ANGLE_GL_TRY(context, functions->vertexAttribFormat(
824 static_cast<GLuint>(attribIndex), format.channelCount,
825 gl::ToGLenum(format.vertexAttribType), format.isNorm(),
826 attrib.relativeOffset));
827 }
828
829 mNativeState->attributes[attribIndex].format = attrib.format;
830 mNativeState->attributes[attribIndex].relativeOffset = attrib.relativeOffset;
831 return angle::Result::Continue;
832 }
833
updateAttribBinding(const gl::Context * context,size_t attribIndex)834 angle::Result VertexArrayGL::updateAttribBinding(const gl::Context *context, size_t attribIndex)
835 {
836 ASSERT(supportVertexAttribBinding(context));
837
838 GLuint bindingIndex = mState.getVertexAttribute(attribIndex).bindingIndex;
839 if (mNativeState->attributes[attribIndex].bindingIndex == bindingIndex)
840 {
841 return angle::Result::Continue;
842 }
843
844 const FunctionsGL *functions = GetFunctionsGL(context);
845 ANGLE_GL_TRY(context,
846 functions->vertexAttribBinding(static_cast<GLuint>(attribIndex), bindingIndex));
847
848 mNativeState->attributes[attribIndex].bindingIndex = bindingIndex;
849
850 return angle::Result::Continue;
851 }
852
updateBindingBuffer(const gl::Context * context,size_t bindingIndex)853 angle::Result VertexArrayGL::updateBindingBuffer(const gl::Context *context, size_t bindingIndex)
854 {
855 ASSERT(supportVertexAttribBinding(context));
856
857 const VertexBinding &binding = mState.getVertexBinding(bindingIndex);
858 if (SameVertexBuffer(mNativeState->bindings[bindingIndex], binding))
859 {
860 return angle::Result::Continue;
861 }
862
863 gl::Buffer *arrayBuffer = binding.getBuffer().get();
864 GLuint bufferId = GetNativeBufferID(arrayBuffer);
865
866 const FunctionsGL *functions = GetFunctionsGL(context);
867 ANGLE_GL_TRY(context, functions->bindVertexBuffer(static_cast<GLuint>(bindingIndex), bufferId,
868 binding.getOffset(), binding.getStride()));
869
870 mNativeState->bindings[bindingIndex].stride = binding.getStride();
871 mNativeState->bindings[bindingIndex].offset = binding.getOffset();
872 mArrayBuffers[bindingIndex].set(context, arrayBuffer);
873 mNativeState->bindings[bindingIndex].buffer = bufferId;
874
875 return angle::Result::Continue;
876 }
877
updateBindingDivisor(const gl::Context * context,size_t bindingIndex)878 angle::Result VertexArrayGL::updateBindingDivisor(const gl::Context *context, size_t bindingIndex)
879 {
880 GLuint adjustedDivisor =
881 GetAdjustedDivisor(mAppliedNumViews, mState.getVertexBinding(bindingIndex).getDivisor());
882 if (mNativeState->bindings[bindingIndex].divisor == adjustedDivisor)
883 {
884 return angle::Result::Continue;
885 }
886
887 const FunctionsGL *functions = GetFunctionsGL(context);
888 if (supportVertexAttribBinding(context))
889 {
890 ANGLE_GL_TRY(context, functions->vertexBindingDivisor(static_cast<GLuint>(bindingIndex),
891 adjustedDivisor));
892 }
893 else
894 {
895 // We can only use VertexAttribDivisor on platforms that don't support Vertex Attrib
896 // Binding.
897 ANGLE_GL_TRY(context, functions->vertexAttribDivisor(static_cast<GLuint>(bindingIndex),
898 adjustedDivisor));
899 }
900
901 if (adjustedDivisor > 0)
902 {
903 mInstancedAttributesMask.set(bindingIndex);
904 }
905 else if (mInstancedAttributesMask.test(bindingIndex))
906 {
907 // divisor is reset to 0
908 mInstancedAttributesMask.reset(bindingIndex);
909 }
910
911 mNativeState->bindings[bindingIndex].divisor = adjustedDivisor;
912
913 return angle::Result::Continue;
914 }
915
syncDirtyAttrib(const gl::Context * context,size_t attribIndex,const gl::VertexArray::DirtyAttribBits & dirtyAttribBits)916 angle::Result VertexArrayGL::syncDirtyAttrib(
917 const gl::Context *context,
918 size_t attribIndex,
919 const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
920 {
921 ASSERT(dirtyAttribBits.any());
922
923 for (size_t dirtyBit : dirtyAttribBits)
924 {
925 switch (dirtyBit)
926 {
927 case VertexArray::DIRTY_ATTRIB_ENABLED:
928 ANGLE_TRY(updateAttribEnabled(context, attribIndex));
929 break;
930
931 case VertexArray::DIRTY_ATTRIB_POINTER_BUFFER:
932 case VertexArray::DIRTY_ATTRIB_POINTER:
933 ANGLE_TRY(updateAttribPointer(context, attribIndex));
934 break;
935
936 case VertexArray::DIRTY_ATTRIB_FORMAT:
937 ASSERT(supportVertexAttribBinding(context));
938 ANGLE_TRY(updateAttribFormat(context, attribIndex));
939 break;
940
941 case VertexArray::DIRTY_ATTRIB_BINDING:
942 ASSERT(supportVertexAttribBinding(context));
943 ANGLE_TRY(updateAttribBinding(context, attribIndex));
944 break;
945
946 default:
947 UNREACHABLE();
948 break;
949 }
950 }
951 return angle::Result::Continue;
952 }
953
syncDirtyBinding(const gl::Context * context,size_t bindingIndex,const gl::VertexArray::DirtyBindingBits & dirtyBindingBits)954 angle::Result VertexArrayGL::syncDirtyBinding(
955 const gl::Context *context,
956 size_t bindingIndex,
957 const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
958 {
959 // Dependent state changes in buffers can trigger updates with no dirty bits set.
960
961 for (auto iter = dirtyBindingBits.begin(), endIter = dirtyBindingBits.end(); iter != endIter;
962 ++iter)
963 {
964 size_t dirtyBit = *iter;
965 switch (dirtyBit)
966 {
967 case VertexArray::DIRTY_BINDING_BUFFER:
968 case VertexArray::DIRTY_BINDING_STRIDE:
969 case VertexArray::DIRTY_BINDING_OFFSET:
970 ASSERT(supportVertexAttribBinding(context));
971 ANGLE_TRY(updateBindingBuffer(context, bindingIndex));
972 // Clear these bits to avoid repeated processing
973 iter.resetLaterBits(gl::VertexArray::DirtyBindingBits{
974 VertexArray::DIRTY_BINDING_BUFFER, VertexArray::DIRTY_BINDING_STRIDE,
975 VertexArray::DIRTY_BINDING_OFFSET});
976 break;
977
978 case VertexArray::DIRTY_BINDING_DIVISOR:
979 ANGLE_TRY(updateBindingDivisor(context, bindingIndex));
980 break;
981
982 default:
983 UNREACHABLE();
984 break;
985 }
986 }
987 return angle::Result::Continue;
988 }
989
990 #define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
991 case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
992 ANGLE_TRY(syncDirtyAttrib(context, INDEX, (*attribBits)[INDEX])); \
993 (*attribBits)[INDEX].reset(); \
994 break;
995
996 #define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
997 case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
998 ANGLE_TRY(syncDirtyBinding(context, INDEX, (*bindingBits)[INDEX])); \
999 (*bindingBits)[INDEX].reset(); \
1000 break;
1001
1002 #define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
1003 case VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
1004 break;
1005
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits,gl::VertexArray::DirtyAttribBitsArray * attribBits,gl::VertexArray::DirtyBindingBitsArray * bindingBits)1006 angle::Result VertexArrayGL::syncState(const gl::Context *context,
1007 const gl::VertexArray::DirtyBits &dirtyBits,
1008 gl::VertexArray::DirtyAttribBitsArray *attribBits,
1009 gl::VertexArray::DirtyBindingBitsArray *bindingBits)
1010 {
1011 StateManagerGL *stateManager = GetStateManagerGL(context);
1012 stateManager->bindVertexArray(mVertexArrayID, mNativeState);
1013
1014 for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
1015 {
1016 size_t dirtyBit = *iter;
1017 switch (dirtyBit)
1018 {
1019 case gl::VertexArray::DIRTY_BIT_LOST_OBSERVATION:
1020 {
1021 // If vertex array was not observing while unbound, we need to check buffer's
1022 // internal storage and take action if buffer has changed while not observing.
1023 // For now we just simply assume buffer storage has changed and always dirty all
1024 // binding points.
1025 iter.setLaterBits(
1026 gl::VertexArray::DirtyBits(mState.getBufferBindingMask().to_ulong()
1027 << gl::VertexArray::DIRTY_BIT_BINDING_0));
1028 break;
1029 }
1030
1031 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
1032 ANGLE_TRY(updateElementArrayBufferBinding(context));
1033 break;
1034
1035 case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
1036 break;
1037
1038 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_ATTRIB_FUNC)
1039 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BINDING_FUNC)
1040 ANGLE_VERTEX_INDEX_CASES(ANGLE_DIRTY_BUFFER_DATA_FUNC)
1041
1042 default:
1043 UNREACHABLE();
1044 break;
1045 }
1046 }
1047
1048 return angle::Result::Continue;
1049 }
1050
applyNumViewsToDivisor(const gl::Context * context,int numViews)1051 angle::Result VertexArrayGL::applyNumViewsToDivisor(const gl::Context *context, int numViews)
1052 {
1053 if (numViews != mAppliedNumViews)
1054 {
1055 StateManagerGL *stateManager = GetStateManagerGL(context);
1056 stateManager->bindVertexArray(mVertexArrayID, mNativeState);
1057 mAppliedNumViews = numViews;
1058 for (size_t index = 0u; index < mNativeState->bindings.size(); ++index)
1059 {
1060 ANGLE_TRY(updateBindingDivisor(context, index));
1061 }
1062 }
1063
1064 return angle::Result::Continue;
1065 }
1066
applyActiveAttribLocationsMask(const gl::Context * context,const gl::AttributesMask & activeMask)1067 angle::Result VertexArrayGL::applyActiveAttribLocationsMask(const gl::Context *context,
1068 const gl::AttributesMask &activeMask)
1069 {
1070 gl::AttributesMask updateMask = mProgramActiveAttribLocationsMask ^ activeMask;
1071 if (!updateMask.any())
1072 {
1073 return angle::Result::Continue;
1074 }
1075
1076 ASSERT(mVertexArrayID == GetStateManagerGL(context)->getVertexArrayID());
1077 mProgramActiveAttribLocationsMask = activeMask;
1078
1079 for (size_t attribIndex : updateMask)
1080 {
1081 ANGLE_TRY(updateAttribEnabled(context, attribIndex));
1082 }
1083
1084 return angle::Result::Continue;
1085 }
1086
validateState(const gl::Context * context) const1087 angle::Result VertexArrayGL::validateState(const gl::Context *context) const
1088 {
1089 const FunctionsGL *functions = GetFunctionsGL(context);
1090
1091 // Ensure this vao is currently bound
1092 ANGLE_TRY(ValidateStateHelperGetIntegerv(context, mVertexArrayID, GL_VERTEX_ARRAY_BINDING,
1093 "mVertexArrayID", "GL_VERTEX_ARRAY_BINDING"));
1094
1095 // Element array buffer
1096 ANGLE_TRY(ValidateStateHelperGetIntegerv(
1097 context, mNativeState->elementArrayBuffer, GL_ELEMENT_ARRAY_BUFFER_BINDING,
1098 "mNativeState->elementArrayBuffer", "GL_ELEMENT_ARRAY_BUFFER_BINDING"));
1099
1100 // ValidateStateHelperGetIntegerv but with > comparison instead of !=
1101 GLint queryValue;
1102 ANGLE_GL_TRY(context, functions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &queryValue));
1103 if (mNativeState->attributes.size() > static_cast<GLuint>(queryValue))
1104 {
1105 WARN() << "mNativeState->attributes.size() (" << mNativeState->attributes.size()
1106 << ") > GL_MAX_VERTEX_ATTRIBS (" << queryValue << ")";
1107 // Re-add ASSERT: http://anglebug.com/42262547
1108 // ASSERT(false);
1109 }
1110
1111 // Check each applied attribute/binding
1112 for (GLuint index = 0; index < mNativeState->attributes.size(); index++)
1113 {
1114 VertexAttributeGL &attribute = mNativeState->attributes[index];
1115 ASSERT(attribute.bindingIndex < mNativeState->bindings.size());
1116 VertexBindingGL &binding = mNativeState->bindings[attribute.bindingIndex];
1117
1118 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1119 context, index, attribute.enabled, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
1120 "mNativeState->attributes.enabled", "GL_VERTEX_ATTRIB_ARRAY_ENABLED"));
1121
1122 if (attribute.enabled)
1123 {
1124 // Applied attributes
1125 ASSERT(attribute.format);
1126 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1127 context, index, ToGLenum(attribute.format->vertexAttribType),
1128 GL_VERTEX_ATTRIB_ARRAY_TYPE, "mNativeState->attributes.format->vertexAttribType",
1129 "GL_VERTEX_ATTRIB_ARRAY_TYPE"));
1130 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1131 context, index, attribute.format->channelCount, GL_VERTEX_ATTRIB_ARRAY_SIZE,
1132 "attribute.format->channelCount", "GL_VERTEX_ATTRIB_ARRAY_SIZE"));
1133 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1134 context, index, attribute.format->isNorm(), GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
1135 "attribute.format->isNorm()", "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED"));
1136 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1137 context, index, attribute.format->isPureInt(), GL_VERTEX_ATTRIB_ARRAY_INTEGER,
1138 "attribute.format->isPureInt()", "GL_VERTEX_ATTRIB_ARRAY_INTEGER"));
1139 if (supportVertexAttribBinding(context))
1140 {
1141 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1142 context, index, attribute.relativeOffset, GL_VERTEX_ATTRIB_RELATIVE_OFFSET,
1143 "attribute.relativeOffset", "GL_VERTEX_ATTRIB_RELATIVE_OFFSET"));
1144 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1145 context, index, attribute.bindingIndex, GL_VERTEX_ATTRIB_BINDING,
1146 "attribute.bindingIndex", "GL_VERTEX_ATTRIB_BINDING"));
1147 }
1148
1149 // Applied bindings
1150 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1151 context, index, binding.buffer, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
1152 "binding.buffer", "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"));
1153 if (binding.buffer != 0)
1154 {
1155 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1156 context, index, binding.stride, GL_VERTEX_ATTRIB_ARRAY_STRIDE, "binding.stride",
1157 "GL_VERTEX_ATTRIB_ARRAY_STRIDE"));
1158 ANGLE_TRY(ValidateStateHelperGetVertexAttribiv(
1159 context, index, binding.divisor, GL_VERTEX_ATTRIB_ARRAY_DIVISOR,
1160 "binding.divisor", "GL_VERTEX_ATTRIB_ARRAY_DIVISOR"));
1161 }
1162 }
1163 }
1164 return angle::Result::Continue;
1165 }
1166
1167 } // namespace rx
1168