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