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