xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/VertexArrayGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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