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