xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 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 // VertexArrayVk.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //    Implements the class methods for VertexArrayVk.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "common/utilities.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/BufferVk.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/ContextVk.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/FramebufferVk.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_format_utils.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_renderer.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_resource.h"
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker namespace rx
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker namespace
25*8975f5c5SAndroid Build Coastguard Worker {
26*8975f5c5SAndroid Build Coastguard Worker constexpr int kStreamIndexBufferCachedIndexCount = 6;
27*8975f5c5SAndroid Build Coastguard Worker constexpr int kMaxCachedStreamIndexBuffers       = 4;
28*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kDefaultValueSize               = sizeof(gl::VertexAttribCurrentValueData::Values);
29*8975f5c5SAndroid Build Coastguard Worker 
BindingIsAligned(const angle::Format & angleFormat,VkDeviceSize offset,GLuint stride)30*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE bool BindingIsAligned(const angle::Format &angleFormat,
31*8975f5c5SAndroid Build Coastguard Worker                                    VkDeviceSize offset,
32*8975f5c5SAndroid Build Coastguard Worker                                    GLuint stride)
33*8975f5c5SAndroid Build Coastguard Worker {
34*8975f5c5SAndroid Build Coastguard Worker     ASSERT(stride != 0);
35*8975f5c5SAndroid Build Coastguard Worker     GLuint mask          = angleFormat.componentAlignmentMask;
36*8975f5c5SAndroid Build Coastguard Worker     if (mask != std::numeric_limits<GLuint>::max())
37*8975f5c5SAndroid Build Coastguard Worker     {
38*8975f5c5SAndroid Build Coastguard Worker         return ((offset & mask) == 0 && (stride & mask) == 0);
39*8975f5c5SAndroid Build Coastguard Worker     }
40*8975f5c5SAndroid Build Coastguard Worker     else
41*8975f5c5SAndroid Build Coastguard Worker     {
42*8975f5c5SAndroid Build Coastguard Worker         // To perform the GPU conversion for formats with components that aren't byte-aligned
43*8975f5c5SAndroid Build Coastguard Worker         // (for example, A2BGR10 or RGB10A2), one element has to be placed in 4 bytes to perform
44*8975f5c5SAndroid Build Coastguard Worker         // the compute shader. So, binding offset and stride has to be aligned to formatSize.
45*8975f5c5SAndroid Build Coastguard Worker         unsigned int formatSize = angleFormat.pixelBytes;
46*8975f5c5SAndroid Build Coastguard Worker         return (offset % formatSize == 0) && (stride % formatSize == 0);
47*8975f5c5SAndroid Build Coastguard Worker     }
48*8975f5c5SAndroid Build Coastguard Worker }
49*8975f5c5SAndroid Build Coastguard Worker 
ClientBindingAligned(const gl::VertexAttribute & attrib,GLuint stride,size_t alignment)50*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE bool ClientBindingAligned(const gl::VertexAttribute &attrib,
51*8975f5c5SAndroid Build Coastguard Worker                                        GLuint stride,
52*8975f5c5SAndroid Build Coastguard Worker                                        size_t alignment)
53*8975f5c5SAndroid Build Coastguard Worker {
54*8975f5c5SAndroid Build Coastguard Worker     return reinterpret_cast<intptr_t>(attrib.pointer) % alignment == 0 && stride % alignment == 0;
55*8975f5c5SAndroid Build Coastguard Worker }
56*8975f5c5SAndroid Build Coastguard Worker 
ShouldCombineAttributes(vk::Renderer * renderer,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)57*8975f5c5SAndroid Build Coastguard Worker bool ShouldCombineAttributes(vk::Renderer *renderer,
58*8975f5c5SAndroid Build Coastguard Worker                              const gl::VertexAttribute &attrib,
59*8975f5c5SAndroid Build Coastguard Worker                              const gl::VertexBinding &binding)
60*8975f5c5SAndroid Build Coastguard Worker {
61*8975f5c5SAndroid Build Coastguard Worker     if (!renderer->getFeatures().enableMergeClientAttribBuffer.enabled)
62*8975f5c5SAndroid Build Coastguard Worker     {
63*8975f5c5SAndroid Build Coastguard Worker         return false;
64*8975f5c5SAndroid Build Coastguard Worker     }
65*8975f5c5SAndroid Build Coastguard Worker     const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
66*8975f5c5SAndroid Build Coastguard Worker     return !vertexFormat.getVertexLoadRequiresConversion(false) && binding.getDivisor() == 0 &&
67*8975f5c5SAndroid Build Coastguard Worker            ClientBindingAligned(attrib, binding.getStride(),
68*8975f5c5SAndroid Build Coastguard Worker                                 vertexFormat.getVertexInputAlignment(false));
69*8975f5c5SAndroid Build Coastguard Worker }
70*8975f5c5SAndroid Build Coastguard Worker 
WarnOnVertexFormatConversion(ContextVk * contextVk,const vk::Format & vertexFormat,bool compressed,bool insertEventMarker)71*8975f5c5SAndroid Build Coastguard Worker void WarnOnVertexFormatConversion(ContextVk *contextVk,
72*8975f5c5SAndroid Build Coastguard Worker                                   const vk::Format &vertexFormat,
73*8975f5c5SAndroid Build Coastguard Worker                                   bool compressed,
74*8975f5c5SAndroid Build Coastguard Worker                                   bool insertEventMarker)
75*8975f5c5SAndroid Build Coastguard Worker {
76*8975f5c5SAndroid Build Coastguard Worker     if (!vertexFormat.getVertexLoadRequiresConversion(compressed))
77*8975f5c5SAndroid Build Coastguard Worker     {
78*8975f5c5SAndroid Build Coastguard Worker         return;
79*8975f5c5SAndroid Build Coastguard Worker     }
80*8975f5c5SAndroid Build Coastguard Worker 
81*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_PERF_WARNING(
82*8975f5c5SAndroid Build Coastguard Worker         contextVk, GL_DEBUG_SEVERITY_LOW,
83*8975f5c5SAndroid Build Coastguard Worker         "The Vulkan driver does not support vertex attribute format 0x%04X, emulating with 0x%04X",
84*8975f5c5SAndroid Build Coastguard Worker         vertexFormat.getIntendedFormat().glInternalFormat,
85*8975f5c5SAndroid Build Coastguard Worker         vertexFormat.getActualBufferFormat(compressed).glInternalFormat);
86*8975f5c5SAndroid Build Coastguard Worker }
87*8975f5c5SAndroid Build Coastguard Worker 
StreamVertexData(ContextVk * contextVk,vk::BufferHelper * dstBufferHelper,const uint8_t * srcData,size_t bytesToCopy,size_t dstOffset,size_t vertexCount,size_t srcStride,VertexCopyFunction vertexLoadFunction)88*8975f5c5SAndroid Build Coastguard Worker angle::Result StreamVertexData(ContextVk *contextVk,
89*8975f5c5SAndroid Build Coastguard Worker                                vk::BufferHelper *dstBufferHelper,
90*8975f5c5SAndroid Build Coastguard Worker                                const uint8_t *srcData,
91*8975f5c5SAndroid Build Coastguard Worker                                size_t bytesToCopy,
92*8975f5c5SAndroid Build Coastguard Worker                                size_t dstOffset,
93*8975f5c5SAndroid Build Coastguard Worker                                size_t vertexCount,
94*8975f5c5SAndroid Build Coastguard Worker                                size_t srcStride,
95*8975f5c5SAndroid Build Coastguard Worker                                VertexCopyFunction vertexLoadFunction)
96*8975f5c5SAndroid Build Coastguard Worker {
97*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
98*8975f5c5SAndroid Build Coastguard Worker 
99*8975f5c5SAndroid Build Coastguard Worker     // If the source pointer is null, it should not be accessed.
100*8975f5c5SAndroid Build Coastguard Worker     if (srcData == nullptr)
101*8975f5c5SAndroid Build Coastguard Worker     {
102*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
103*8975f5c5SAndroid Build Coastguard Worker     }
104*8975f5c5SAndroid Build Coastguard Worker 
105*8975f5c5SAndroid Build Coastguard Worker     uint8_t *dst = dstBufferHelper->getMappedMemory() + dstOffset;
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker     if (vertexLoadFunction != nullptr)
108*8975f5c5SAndroid Build Coastguard Worker     {
109*8975f5c5SAndroid Build Coastguard Worker         vertexLoadFunction(srcData, srcStride, vertexCount, dst);
110*8975f5c5SAndroid Build Coastguard Worker     }
111*8975f5c5SAndroid Build Coastguard Worker     else
112*8975f5c5SAndroid Build Coastguard Worker     {
113*8975f5c5SAndroid Build Coastguard Worker         memcpy(dst, srcData, bytesToCopy);
114*8975f5c5SAndroid Build Coastguard Worker     }
115*8975f5c5SAndroid Build Coastguard Worker 
116*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(dstBufferHelper->flush(renderer));
117*8975f5c5SAndroid Build Coastguard Worker 
118*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
119*8975f5c5SAndroid Build Coastguard Worker }
120*8975f5c5SAndroid Build Coastguard Worker 
StreamVertexDataWithDivisor(ContextVk * contextVk,vk::BufferHelper * dstBufferHelper,const uint8_t * srcData,size_t bytesToAllocate,size_t srcStride,size_t dstStride,VertexCopyFunction vertexLoadFunction,uint32_t divisor,size_t numSrcVertices)121*8975f5c5SAndroid Build Coastguard Worker angle::Result StreamVertexDataWithDivisor(ContextVk *contextVk,
122*8975f5c5SAndroid Build Coastguard Worker                                           vk::BufferHelper *dstBufferHelper,
123*8975f5c5SAndroid Build Coastguard Worker                                           const uint8_t *srcData,
124*8975f5c5SAndroid Build Coastguard Worker                                           size_t bytesToAllocate,
125*8975f5c5SAndroid Build Coastguard Worker                                           size_t srcStride,
126*8975f5c5SAndroid Build Coastguard Worker                                           size_t dstStride,
127*8975f5c5SAndroid Build Coastguard Worker                                           VertexCopyFunction vertexLoadFunction,
128*8975f5c5SAndroid Build Coastguard Worker                                           uint32_t divisor,
129*8975f5c5SAndroid Build Coastguard Worker                                           size_t numSrcVertices)
130*8975f5c5SAndroid Build Coastguard Worker {
131*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
132*8975f5c5SAndroid Build Coastguard Worker 
133*8975f5c5SAndroid Build Coastguard Worker     uint8_t *dst = dstBufferHelper->getMappedMemory();
134*8975f5c5SAndroid Build Coastguard Worker 
135*8975f5c5SAndroid Build Coastguard Worker     // Each source vertex is used `divisor` times before advancing. Clamp to avoid OOB reads.
136*8975f5c5SAndroid Build Coastguard Worker     size_t clampedSize = std::min(numSrcVertices * dstStride * divisor, bytesToAllocate);
137*8975f5c5SAndroid Build Coastguard Worker 
138*8975f5c5SAndroid Build Coastguard Worker     ASSERT(clampedSize % dstStride == 0);
139*8975f5c5SAndroid Build Coastguard Worker     ASSERT(divisor > 0);
140*8975f5c5SAndroid Build Coastguard Worker 
141*8975f5c5SAndroid Build Coastguard Worker     uint32_t srcVertexUseCount = 0;
142*8975f5c5SAndroid Build Coastguard Worker     for (size_t dataCopied = 0; dataCopied < clampedSize; dataCopied += dstStride)
143*8975f5c5SAndroid Build Coastguard Worker     {
144*8975f5c5SAndroid Build Coastguard Worker         vertexLoadFunction(srcData, srcStride, 1, dst);
145*8975f5c5SAndroid Build Coastguard Worker         srcVertexUseCount++;
146*8975f5c5SAndroid Build Coastguard Worker         if (srcVertexUseCount == divisor)
147*8975f5c5SAndroid Build Coastguard Worker         {
148*8975f5c5SAndroid Build Coastguard Worker             srcData += srcStride;
149*8975f5c5SAndroid Build Coastguard Worker             srcVertexUseCount = 0;
150*8975f5c5SAndroid Build Coastguard Worker         }
151*8975f5c5SAndroid Build Coastguard Worker         dst += dstStride;
152*8975f5c5SAndroid Build Coastguard Worker     }
153*8975f5c5SAndroid Build Coastguard Worker 
154*8975f5c5SAndroid Build Coastguard Worker     // Satisfy robustness constraints (only if extension enabled)
155*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getExtensions().robustnessAny())
156*8975f5c5SAndroid Build Coastguard Worker     {
157*8975f5c5SAndroid Build Coastguard Worker         if (clampedSize < bytesToAllocate)
158*8975f5c5SAndroid Build Coastguard Worker         {
159*8975f5c5SAndroid Build Coastguard Worker             memset(dst, 0, bytesToAllocate - clampedSize);
160*8975f5c5SAndroid Build Coastguard Worker         }
161*8975f5c5SAndroid Build Coastguard Worker     }
162*8975f5c5SAndroid Build Coastguard Worker 
163*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(dstBufferHelper->flush(renderer));
164*8975f5c5SAndroid Build Coastguard Worker 
165*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
166*8975f5c5SAndroid Build Coastguard Worker }
167*8975f5c5SAndroid Build Coastguard Worker 
GetVertexCountForRange(GLint64 srcBufferBytes,uint32_t srcFormatSize,uint32_t srcVertexStride)168*8975f5c5SAndroid Build Coastguard Worker size_t GetVertexCountForRange(GLint64 srcBufferBytes,
169*8975f5c5SAndroid Build Coastguard Worker                               uint32_t srcFormatSize,
170*8975f5c5SAndroid Build Coastguard Worker                               uint32_t srcVertexStride)
171*8975f5c5SAndroid Build Coastguard Worker {
172*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcVertexStride != 0);
173*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcFormatSize != 0);
174*8975f5c5SAndroid Build Coastguard Worker 
175*8975f5c5SAndroid Build Coastguard Worker     if (srcBufferBytes < srcFormatSize)
176*8975f5c5SAndroid Build Coastguard Worker     {
177*8975f5c5SAndroid Build Coastguard Worker         return 0;
178*8975f5c5SAndroid Build Coastguard Worker     }
179*8975f5c5SAndroid Build Coastguard Worker 
180*8975f5c5SAndroid Build Coastguard Worker     size_t numVertices =
181*8975f5c5SAndroid Build Coastguard Worker         static_cast<size_t>(srcBufferBytes + srcVertexStride - 1) / srcVertexStride;
182*8975f5c5SAndroid Build Coastguard Worker     return numVertices;
183*8975f5c5SAndroid Build Coastguard Worker }
184*8975f5c5SAndroid Build Coastguard Worker 
GetVertexCount(BufferVk * srcBuffer,const gl::VertexBinding & binding,uint32_t srcFormatSize)185*8975f5c5SAndroid Build Coastguard Worker size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uint32_t srcFormatSize)
186*8975f5c5SAndroid Build Coastguard Worker {
187*8975f5c5SAndroid Build Coastguard Worker     // Bytes usable for vertex data.
188*8975f5c5SAndroid Build Coastguard Worker     GLint64 bytes = srcBuffer->getSize() - binding.getOffset();
189*8975f5c5SAndroid Build Coastguard Worker     GLuint stride = binding.getStride();
190*8975f5c5SAndroid Build Coastguard Worker     if (stride == 0)
191*8975f5c5SAndroid Build Coastguard Worker     {
192*8975f5c5SAndroid Build Coastguard Worker         stride = srcFormatSize;
193*8975f5c5SAndroid Build Coastguard Worker     }
194*8975f5c5SAndroid Build Coastguard Worker     return GetVertexCountForRange(bytes, srcFormatSize, stride);
195*8975f5c5SAndroid Build Coastguard Worker }
196*8975f5c5SAndroid Build Coastguard Worker 
CalculateMaxVertexCountForConversion(ContextVk * contextVk,BufferVk * srcBuffer,VertexConversionBuffer * conversion,const angle::Format & srcFormat,const angle::Format & dstFormat,size_t * maxNumVerticesOut)197*8975f5c5SAndroid Build Coastguard Worker angle::Result CalculateMaxVertexCountForConversion(ContextVk *contextVk,
198*8975f5c5SAndroid Build Coastguard Worker                                                    BufferVk *srcBuffer,
199*8975f5c5SAndroid Build Coastguard Worker                                                    VertexConversionBuffer *conversion,
200*8975f5c5SAndroid Build Coastguard Worker                                                    const angle::Format &srcFormat,
201*8975f5c5SAndroid Build Coastguard Worker                                                    const angle::Format &dstFormat,
202*8975f5c5SAndroid Build Coastguard Worker                                                    size_t *maxNumVerticesOut)
203*8975f5c5SAndroid Build Coastguard Worker {
204*8975f5c5SAndroid Build Coastguard Worker     // Initialize numVertices to 0
205*8975f5c5SAndroid Build Coastguard Worker     *maxNumVerticesOut = 0;
206*8975f5c5SAndroid Build Coastguard Worker 
207*8975f5c5SAndroid Build Coastguard Worker     unsigned srcFormatSize = srcFormat.pixelBytes;
208*8975f5c5SAndroid Build Coastguard Worker     unsigned dstFormatSize = dstFormat.pixelBytes;
209*8975f5c5SAndroid Build Coastguard Worker 
210*8975f5c5SAndroid Build Coastguard Worker     uint32_t srcStride = conversion->getCacheKey().stride;
211*8975f5c5SAndroid Build Coastguard Worker     uint32_t dstStride = dstFormatSize;
212*8975f5c5SAndroid Build Coastguard Worker 
213*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcStride != 0);
214*8975f5c5SAndroid Build Coastguard Worker     ASSERT(conversion->dirty());
215*8975f5c5SAndroid Build Coastguard Worker 
216*8975f5c5SAndroid Build Coastguard Worker     // Start the range with the range from the the beginning of the buffer to the end of
217*8975f5c5SAndroid Build Coastguard Worker     // buffer. Then scissor it with the dirtyRange.
218*8975f5c5SAndroid Build Coastguard Worker     size_t srcOffset  = conversion->getCacheKey().offset;
219*8975f5c5SAndroid Build Coastguard Worker     GLint64 srcLength = srcBuffer->getSize() - srcOffset;
220*8975f5c5SAndroid Build Coastguard Worker 
221*8975f5c5SAndroid Build Coastguard Worker     // The max number of vertices from binding to the end of the buffer
222*8975f5c5SAndroid Build Coastguard Worker     size_t maxNumVertices = GetVertexCountForRange(srcLength, srcFormatSize, srcStride);
223*8975f5c5SAndroid Build Coastguard Worker     if (maxNumVertices == 0)
224*8975f5c5SAndroid Build Coastguard Worker     {
225*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
226*8975f5c5SAndroid Build Coastguard Worker     }
227*8975f5c5SAndroid Build Coastguard Worker 
228*8975f5c5SAndroid Build Coastguard Worker     // Allocate buffer for results
229*8975f5c5SAndroid Build Coastguard Worker     vk::MemoryHostVisibility hostVisible = conversion->getCacheKey().hostVisible
230*8975f5c5SAndroid Build Coastguard Worker                                                ? vk::MemoryHostVisibility::Visible
231*8975f5c5SAndroid Build Coastguard Worker                                                : vk::MemoryHostVisibility::NonVisible;
232*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->initBufferForVertexConversion(conversion, maxNumVertices * dstStride,
233*8975f5c5SAndroid Build Coastguard Worker                                                        hostVisible));
234*8975f5c5SAndroid Build Coastguard Worker 
235*8975f5c5SAndroid Build Coastguard Worker     // Calculate numVertices to convert
236*8975f5c5SAndroid Build Coastguard Worker     *maxNumVerticesOut = GetVertexCountForRange(srcLength, srcFormatSize, srcStride);
237*8975f5c5SAndroid Build Coastguard Worker 
238*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
239*8975f5c5SAndroid Build Coastguard Worker }
240*8975f5c5SAndroid Build Coastguard Worker 
CalculateOffsetAndVertexCountForDirtyRange(BufferVk * bufferVk,VertexConversionBuffer * conversion,const angle::Format & srcFormat,const angle::Format & dstFormat,const RangeDeviceSize & dirtyRange,uint32_t * srcOffsetOut,uint32_t * dstOffsetOut,uint32_t * numVerticesOut)241*8975f5c5SAndroid Build Coastguard Worker void CalculateOffsetAndVertexCountForDirtyRange(BufferVk *bufferVk,
242*8975f5c5SAndroid Build Coastguard Worker                                                 VertexConversionBuffer *conversion,
243*8975f5c5SAndroid Build Coastguard Worker                                                 const angle::Format &srcFormat,
244*8975f5c5SAndroid Build Coastguard Worker                                                 const angle::Format &dstFormat,
245*8975f5c5SAndroid Build Coastguard Worker                                                 const RangeDeviceSize &dirtyRange,
246*8975f5c5SAndroid Build Coastguard Worker                                                 uint32_t *srcOffsetOut,
247*8975f5c5SAndroid Build Coastguard Worker                                                 uint32_t *dstOffsetOut,
248*8975f5c5SAndroid Build Coastguard Worker                                                 uint32_t *numVerticesOut)
249*8975f5c5SAndroid Build Coastguard Worker {
250*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!dirtyRange.empty());
251*8975f5c5SAndroid Build Coastguard Worker     unsigned srcFormatSize = srcFormat.pixelBytes;
252*8975f5c5SAndroid Build Coastguard Worker     unsigned dstFormatSize = dstFormat.pixelBytes;
253*8975f5c5SAndroid Build Coastguard Worker 
254*8975f5c5SAndroid Build Coastguard Worker     uint32_t srcStride = conversion->getCacheKey().stride;
255*8975f5c5SAndroid Build Coastguard Worker     uint32_t dstStride = dstFormatSize;
256*8975f5c5SAndroid Build Coastguard Worker 
257*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcStride != 0);
258*8975f5c5SAndroid Build Coastguard Worker     ASSERT(conversion->dirty());
259*8975f5c5SAndroid Build Coastguard Worker 
260*8975f5c5SAndroid Build Coastguard Worker     // Start the range with the range from the the beginning of the buffer to the end of
261*8975f5c5SAndroid Build Coastguard Worker     // buffer. Then scissor it with the dirtyRange.
262*8975f5c5SAndroid Build Coastguard Worker     size_t srcOffset = conversion->getCacheKey().offset;
263*8975f5c5SAndroid Build Coastguard Worker     size_t dstOffset = 0;
264*8975f5c5SAndroid Build Coastguard Worker 
265*8975f5c5SAndroid Build Coastguard Worker     GLint64 srcLength = bufferVk->getSize() - srcOffset;
266*8975f5c5SAndroid Build Coastguard Worker 
267*8975f5c5SAndroid Build Coastguard Worker     // Adjust offset to the begining of the dirty range
268*8975f5c5SAndroid Build Coastguard Worker     if (dirtyRange.low() > srcOffset)
269*8975f5c5SAndroid Build Coastguard Worker     {
270*8975f5c5SAndroid Build Coastguard Worker         size_t vertexCountToSkip = (static_cast<size_t>(dirtyRange.low()) - srcOffset) / srcStride;
271*8975f5c5SAndroid Build Coastguard Worker         size_t srcBytesToSkip    = vertexCountToSkip * srcStride;
272*8975f5c5SAndroid Build Coastguard Worker         size_t dstBytesToSkip    = vertexCountToSkip * dstStride;
273*8975f5c5SAndroid Build Coastguard Worker         srcOffset += srcBytesToSkip;
274*8975f5c5SAndroid Build Coastguard Worker         srcLength -= srcBytesToSkip;
275*8975f5c5SAndroid Build Coastguard Worker         dstOffset += dstBytesToSkip;
276*8975f5c5SAndroid Build Coastguard Worker     }
277*8975f5c5SAndroid Build Coastguard Worker 
278*8975f5c5SAndroid Build Coastguard Worker     // Adjust dstOffset to align to 4 bytes. The GPU convert code path always write a uint32_t and
279*8975f5c5SAndroid Build Coastguard Worker     // must aligned at 4 bytes. We could possibly make it able to store at unaligned uint32_t but
280*8975f5c5SAndroid Build Coastguard Worker     // performance will be worse than just convert a few extra data.
281*8975f5c5SAndroid Build Coastguard Worker     while ((dstOffset % 4) != 0)
282*8975f5c5SAndroid Build Coastguard Worker     {
283*8975f5c5SAndroid Build Coastguard Worker         dstOffset -= dstStride;
284*8975f5c5SAndroid Build Coastguard Worker         srcOffset -= srcStride;
285*8975f5c5SAndroid Build Coastguard Worker         srcLength += srcStride;
286*8975f5c5SAndroid Build Coastguard Worker     }
287*8975f5c5SAndroid Build Coastguard Worker 
288*8975f5c5SAndroid Build Coastguard Worker     // Adjust length
289*8975f5c5SAndroid Build Coastguard Worker     if (dirtyRange.high() < static_cast<VkDeviceSize>(bufferVk->getSize()))
290*8975f5c5SAndroid Build Coastguard Worker     {
291*8975f5c5SAndroid Build Coastguard Worker         srcLength = dirtyRange.high() - srcOffset;
292*8975f5c5SAndroid Build Coastguard Worker     }
293*8975f5c5SAndroid Build Coastguard Worker 
294*8975f5c5SAndroid Build Coastguard Worker     // Calculate numVertices to convert
295*8975f5c5SAndroid Build Coastguard Worker     size_t numVertices = GetVertexCountForRange(srcLength, srcFormatSize, srcStride);
296*8975f5c5SAndroid Build Coastguard Worker 
297*8975f5c5SAndroid Build Coastguard Worker     *numVerticesOut = static_cast<uint32_t>(numVertices);
298*8975f5c5SAndroid Build Coastguard Worker     *srcOffsetOut   = static_cast<uint32_t>(srcOffset);
299*8975f5c5SAndroid Build Coastguard Worker     *dstOffsetOut   = static_cast<uint32_t>(dstOffset);
300*8975f5c5SAndroid Build Coastguard Worker }
301*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
302*8975f5c5SAndroid Build Coastguard Worker 
VertexArrayVk(ContextVk * contextVk,const gl::VertexArrayState & state)303*8975f5c5SAndroid Build Coastguard Worker VertexArrayVk::VertexArrayVk(ContextVk *contextVk, const gl::VertexArrayState &state)
304*8975f5c5SAndroid Build Coastguard Worker     : VertexArrayImpl(state),
305*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBufferHandles{},
306*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBufferOffsets{},
307*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBufferRelativeOffsets{},
308*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBuffers{},
309*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBufferStrides{},
310*8975f5c5SAndroid Build Coastguard Worker       mCurrentArrayBufferDivisors{},
311*8975f5c5SAndroid Build Coastguard Worker       mCurrentElementArrayBuffer(nullptr),
312*8975f5c5SAndroid Build Coastguard Worker       mLineLoopHelper(contextVk->getRenderer()),
313*8975f5c5SAndroid Build Coastguard Worker       mDirtyLineLoopTranslation(true)
314*8975f5c5SAndroid Build Coastguard Worker {
315*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper &emptyBuffer = contextVk->getEmptyBuffer();
316*8975f5c5SAndroid Build Coastguard Worker 
317*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBufferHandles.fill(emptyBuffer.getBuffer().getHandle());
318*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBufferOffsets.fill(0);
319*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBufferRelativeOffsets.fill(0);
320*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBuffers.fill(&emptyBuffer);
321*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBufferStrides.fill(0);
322*8975f5c5SAndroid Build Coastguard Worker     mCurrentArrayBufferDivisors.fill(0);
323*8975f5c5SAndroid Build Coastguard Worker 
324*8975f5c5SAndroid Build Coastguard Worker     mBindingDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_BINDING_DIVISOR);
325*8975f5c5SAndroid Build Coastguard Worker     if (!contextVk->getFeatures().useVertexInputBindingStrideDynamicState.enabled)
326*8975f5c5SAndroid Build Coastguard Worker     {
327*8975f5c5SAndroid Build Coastguard Worker         mBindingDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_BINDING_STRIDE);
328*8975f5c5SAndroid Build Coastguard Worker     }
329*8975f5c5SAndroid Build Coastguard Worker 
330*8975f5c5SAndroid Build Coastguard Worker     // All but DIRTY_ATTRIB_POINTER_BUFFER requires graphics pipeline update
331*8975f5c5SAndroid Build Coastguard Worker     mAttribDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_ATTRIB_ENABLED);
332*8975f5c5SAndroid Build Coastguard Worker     mAttribDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_ATTRIB_POINTER);
333*8975f5c5SAndroid Build Coastguard Worker     mAttribDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_ATTRIB_FORMAT);
334*8975f5c5SAndroid Build Coastguard Worker     mAttribDirtyBitsRequiresPipelineUpdate.set(gl::VertexArray::DIRTY_ATTRIB_BINDING);
335*8975f5c5SAndroid Build Coastguard Worker }
336*8975f5c5SAndroid Build Coastguard Worker 
~VertexArrayVk()337*8975f5c5SAndroid Build Coastguard Worker VertexArrayVk::~VertexArrayVk() {}
338*8975f5c5SAndroid Build Coastguard Worker 
destroy(const gl::Context * context)339*8975f5c5SAndroid Build Coastguard Worker void VertexArrayVk::destroy(const gl::Context *context)
340*8975f5c5SAndroid Build Coastguard Worker {
341*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
342*8975f5c5SAndroid Build Coastguard Worker 
343*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
344*8975f5c5SAndroid Build Coastguard Worker 
345*8975f5c5SAndroid Build Coastguard Worker     for (std::unique_ptr<vk::BufferHelper> &buffer : mCachedStreamIndexBuffers)
346*8975f5c5SAndroid Build Coastguard Worker     {
347*8975f5c5SAndroid Build Coastguard Worker         buffer->release(renderer);
348*8975f5c5SAndroid Build Coastguard Worker     }
349*8975f5c5SAndroid Build Coastguard Worker 
350*8975f5c5SAndroid Build Coastguard Worker     mStreamedIndexData.release(renderer);
351*8975f5c5SAndroid Build Coastguard Worker     mTranslatedByteIndexData.release(renderer);
352*8975f5c5SAndroid Build Coastguard Worker     mTranslatedByteIndirectData.release(renderer);
353*8975f5c5SAndroid Build Coastguard Worker     mLineLoopHelper.release(contextVk);
354*8975f5c5SAndroid Build Coastguard Worker }
355*8975f5c5SAndroid Build Coastguard Worker 
convertIndexBufferGPU(ContextVk * contextVk,BufferVk * bufferVk,const void * indices)356*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::convertIndexBufferGPU(ContextVk *contextVk,
357*8975f5c5SAndroid Build Coastguard Worker                                                    BufferVk *bufferVk,
358*8975f5c5SAndroid Build Coastguard Worker                                                    const void *indices)
359*8975f5c5SAndroid Build Coastguard Worker {
360*8975f5c5SAndroid Build Coastguard Worker     intptr_t offsetIntoSrcData = reinterpret_cast<intptr_t>(indices);
361*8975f5c5SAndroid Build Coastguard Worker     size_t srcDataSize         = static_cast<size_t>(bufferVk->getSize()) - offsetIntoSrcData;
362*8975f5c5SAndroid Build Coastguard Worker 
363*8975f5c5SAndroid Build Coastguard Worker     // Allocate buffer for results
364*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mTranslatedByteIndexData,
365*8975f5c5SAndroid Build Coastguard Worker                                                        sizeof(GLushort) * srcDataSize,
366*8975f5c5SAndroid Build Coastguard Worker                                                        vk::MemoryHostVisibility::NonVisible));
367*8975f5c5SAndroid Build Coastguard Worker     mCurrentElementArrayBuffer = mTranslatedByteIndexData.getBuffer();
368*8975f5c5SAndroid Build Coastguard Worker 
369*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *dst = mTranslatedByteIndexData.getBuffer();
370*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *src = &bufferVk->getBuffer();
371*8975f5c5SAndroid Build Coastguard Worker 
372*8975f5c5SAndroid Build Coastguard Worker     // Copy relevant section of the source into destination at allocated offset.  Note that the
373*8975f5c5SAndroid Build Coastguard Worker     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
374*8975f5c5SAndroid Build Coastguard Worker     UtilsVk::ConvertIndexParameters params = {};
375*8975f5c5SAndroid Build Coastguard Worker     params.srcOffset                       = static_cast<uint32_t>(offsetIntoSrcData);
376*8975f5c5SAndroid Build Coastguard Worker     params.dstOffset                       = 0;
377*8975f5c5SAndroid Build Coastguard Worker     params.maxIndex                        = static_cast<uint32_t>(bufferVk->getSize());
378*8975f5c5SAndroid Build Coastguard Worker 
379*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->getUtils().convertIndexBuffer(contextVk, dst, src, params));
380*8975f5c5SAndroid Build Coastguard Worker     mTranslatedByteIndexData.clearDirty();
381*8975f5c5SAndroid Build Coastguard Worker 
382*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
383*8975f5c5SAndroid Build Coastguard Worker }
384*8975f5c5SAndroid Build Coastguard Worker 
convertIndexBufferIndirectGPU(ContextVk * contextVk,vk::BufferHelper * srcIndirectBuf,VkDeviceSize srcIndirectBufOffset,vk::BufferHelper ** indirectBufferVkOut)385*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::convertIndexBufferIndirectGPU(ContextVk *contextVk,
386*8975f5c5SAndroid Build Coastguard Worker                                                            vk::BufferHelper *srcIndirectBuf,
387*8975f5c5SAndroid Build Coastguard Worker                                                            VkDeviceSize srcIndirectBufOffset,
388*8975f5c5SAndroid Build Coastguard Worker                                                            vk::BufferHelper **indirectBufferVkOut)
389*8975f5c5SAndroid Build Coastguard Worker {
390*8975f5c5SAndroid Build Coastguard Worker     size_t srcDataSize = static_cast<size_t>(mCurrentElementArrayBuffer->getSize());
391*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mCurrentElementArrayBuffer ==
392*8975f5c5SAndroid Build Coastguard Worker            &vk::GetImpl(getState().getElementArrayBuffer())->getBuffer());
393*8975f5c5SAndroid Build Coastguard Worker 
394*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *srcIndexBuf = mCurrentElementArrayBuffer;
395*8975f5c5SAndroid Build Coastguard Worker 
396*8975f5c5SAndroid Build Coastguard Worker     // Allocate buffer for results
397*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mTranslatedByteIndexData,
398*8975f5c5SAndroid Build Coastguard Worker                                                        sizeof(GLushort) * srcDataSize,
399*8975f5c5SAndroid Build Coastguard Worker                                                        vk::MemoryHostVisibility::NonVisible));
400*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *dstIndexBuf = mTranslatedByteIndexData.getBuffer();
401*8975f5c5SAndroid Build Coastguard Worker 
402*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mTranslatedByteIndirectData,
403*8975f5c5SAndroid Build Coastguard Worker                                                        sizeof(VkDrawIndexedIndirectCommand),
404*8975f5c5SAndroid Build Coastguard Worker                                                        vk::MemoryHostVisibility::NonVisible));
405*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *dstIndirectBuf = mTranslatedByteIndirectData.getBuffer();
406*8975f5c5SAndroid Build Coastguard Worker 
407*8975f5c5SAndroid Build Coastguard Worker     // Save new element array buffer
408*8975f5c5SAndroid Build Coastguard Worker     mCurrentElementArrayBuffer = dstIndexBuf;
409*8975f5c5SAndroid Build Coastguard Worker     // Tell caller what new indirect buffer is
410*8975f5c5SAndroid Build Coastguard Worker     *indirectBufferVkOut = dstIndirectBuf;
411*8975f5c5SAndroid Build Coastguard Worker 
412*8975f5c5SAndroid Build Coastguard Worker     // Copy relevant section of the source into destination at allocated offset.  Note that the
413*8975f5c5SAndroid Build Coastguard Worker     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
414*8975f5c5SAndroid Build Coastguard Worker     UtilsVk::ConvertIndexIndirectParameters params = {};
415*8975f5c5SAndroid Build Coastguard Worker     params.srcIndirectBufOffset                    = static_cast<uint32_t>(srcIndirectBufOffset);
416*8975f5c5SAndroid Build Coastguard Worker     params.srcIndexBufOffset                       = 0;
417*8975f5c5SAndroid Build Coastguard Worker     params.dstIndexBufOffset                       = 0;
418*8975f5c5SAndroid Build Coastguard Worker     params.maxIndex                                = static_cast<uint32_t>(srcDataSize);
419*8975f5c5SAndroid Build Coastguard Worker     params.dstIndirectBufOffset                    = 0;
420*8975f5c5SAndroid Build Coastguard Worker 
421*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->getUtils().convertIndexIndirectBuffer(
422*8975f5c5SAndroid Build Coastguard Worker         contextVk, srcIndirectBuf, srcIndexBuf, dstIndirectBuf, dstIndexBuf, params));
423*8975f5c5SAndroid Build Coastguard Worker 
424*8975f5c5SAndroid Build Coastguard Worker     mTranslatedByteIndexData.clearDirty();
425*8975f5c5SAndroid Build Coastguard Worker     mTranslatedByteIndirectData.clearDirty();
426*8975f5c5SAndroid Build Coastguard Worker 
427*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
428*8975f5c5SAndroid Build Coastguard Worker }
429*8975f5c5SAndroid Build Coastguard Worker 
handleLineLoopIndexIndirect(ContextVk * contextVk,gl::DrawElementsType glIndexType,vk::BufferHelper * srcIndexBuffer,vk::BufferHelper * srcIndirectBuffer,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indexBufferOut,vk::BufferHelper ** indirectBufferOut)430*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::handleLineLoopIndexIndirect(ContextVk *contextVk,
431*8975f5c5SAndroid Build Coastguard Worker                                                          gl::DrawElementsType glIndexType,
432*8975f5c5SAndroid Build Coastguard Worker                                                          vk::BufferHelper *srcIndexBuffer,
433*8975f5c5SAndroid Build Coastguard Worker                                                          vk::BufferHelper *srcIndirectBuffer,
434*8975f5c5SAndroid Build Coastguard Worker                                                          VkDeviceSize indirectBufferOffset,
435*8975f5c5SAndroid Build Coastguard Worker                                                          vk::BufferHelper **indexBufferOut,
436*8975f5c5SAndroid Build Coastguard Worker                                                          vk::BufferHelper **indirectBufferOut)
437*8975f5c5SAndroid Build Coastguard Worker {
438*8975f5c5SAndroid Build Coastguard Worker     return mLineLoopHelper.streamIndicesIndirect(contextVk, glIndexType, srcIndexBuffer,
439*8975f5c5SAndroid Build Coastguard Worker                                                  srcIndirectBuffer, indirectBufferOffset,
440*8975f5c5SAndroid Build Coastguard Worker                                                  indexBufferOut, indirectBufferOut);
441*8975f5c5SAndroid Build Coastguard Worker }
442*8975f5c5SAndroid Build Coastguard Worker 
handleLineLoopIndirectDraw(const gl::Context * context,vk::BufferHelper * indirectBufferVk,VkDeviceSize indirectBufferOffset,vk::BufferHelper ** indexBufferOut,vk::BufferHelper ** indirectBufferOut)443*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::handleLineLoopIndirectDraw(const gl::Context *context,
444*8975f5c5SAndroid Build Coastguard Worker                                                         vk::BufferHelper *indirectBufferVk,
445*8975f5c5SAndroid Build Coastguard Worker                                                         VkDeviceSize indirectBufferOffset,
446*8975f5c5SAndroid Build Coastguard Worker                                                         vk::BufferHelper **indexBufferOut,
447*8975f5c5SAndroid Build Coastguard Worker                                                         vk::BufferHelper **indirectBufferOut)
448*8975f5c5SAndroid Build Coastguard Worker {
449*8975f5c5SAndroid Build Coastguard Worker     size_t maxVertexCount = 0;
450*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk  = vk::GetImpl(context);
451*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask activeAttribs =
452*8975f5c5SAndroid Build Coastguard Worker         context->getStateCache().getActiveBufferedAttribsMask();
453*8975f5c5SAndroid Build Coastguard Worker 
454*8975f5c5SAndroid Build Coastguard Worker     const auto &attribs  = mState.getVertexAttributes();
455*8975f5c5SAndroid Build Coastguard Worker     const auto &bindings = mState.getVertexBindings();
456*8975f5c5SAndroid Build Coastguard Worker 
457*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : activeAttribs)
458*8975f5c5SAndroid Build Coastguard Worker     {
459*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = attribs[attribIndex];
460*8975f5c5SAndroid Build Coastguard Worker         ASSERT(attrib.enabled);
461*8975f5c5SAndroid Build Coastguard Worker         VkDeviceSize bufSize             = getCurrentArrayBuffers()[attribIndex]->getSize();
462*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
463*8975f5c5SAndroid Build Coastguard Worker         size_t stride                    = binding.getStride();
464*8975f5c5SAndroid Build Coastguard Worker         size_t vertexCount               = static_cast<size_t>(bufSize / stride);
465*8975f5c5SAndroid Build Coastguard Worker         if (vertexCount > maxVertexCount)
466*8975f5c5SAndroid Build Coastguard Worker         {
467*8975f5c5SAndroid Build Coastguard Worker             maxVertexCount = vertexCount;
468*8975f5c5SAndroid Build Coastguard Worker         }
469*8975f5c5SAndroid Build Coastguard Worker     }
470*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mLineLoopHelper.streamArrayIndirect(contextVk, maxVertexCount + 1, indirectBufferVk,
471*8975f5c5SAndroid Build Coastguard Worker                                                   indirectBufferOffset, indexBufferOut,
472*8975f5c5SAndroid Build Coastguard Worker                                                   indirectBufferOut));
473*8975f5c5SAndroid Build Coastguard Worker 
474*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
475*8975f5c5SAndroid Build Coastguard Worker }
476*8975f5c5SAndroid Build Coastguard Worker 
convertIndexBufferCPU(ContextVk * contextVk,gl::DrawElementsType indexType,size_t indexCount,const void * sourcePointer,BufferBindingDirty * bindingDirty)477*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::convertIndexBufferCPU(ContextVk *contextVk,
478*8975f5c5SAndroid Build Coastguard Worker                                                    gl::DrawElementsType indexType,
479*8975f5c5SAndroid Build Coastguard Worker                                                    size_t indexCount,
480*8975f5c5SAndroid Build Coastguard Worker                                                    const void *sourcePointer,
481*8975f5c5SAndroid Build Coastguard Worker                                                    BufferBindingDirty *bindingDirty)
482*8975f5c5SAndroid Build Coastguard Worker {
483*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mState.getElementArrayBuffer() || indexType == gl::DrawElementsType::UnsignedByte);
484*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
485*8975f5c5SAndroid Build Coastguard Worker     size_t elementSize     = contextVk->getVkIndexTypeSize(indexType);
486*8975f5c5SAndroid Build Coastguard Worker     const size_t amount    = elementSize * indexCount;
487*8975f5c5SAndroid Build Coastguard Worker 
488*8975f5c5SAndroid Build Coastguard Worker     // Applications often time draw a quad with two triangles. This is try to catch all the
489*8975f5c5SAndroid Build Coastguard Worker     // common used element array buffer with pre-created BufferHelper objects to improve
490*8975f5c5SAndroid Build Coastguard Worker     // performance.
491*8975f5c5SAndroid Build Coastguard Worker     if (indexCount == kStreamIndexBufferCachedIndexCount &&
492*8975f5c5SAndroid Build Coastguard Worker         indexType == gl::DrawElementsType::UnsignedShort)
493*8975f5c5SAndroid Build Coastguard Worker     {
494*8975f5c5SAndroid Build Coastguard Worker         for (std::unique_ptr<vk::BufferHelper> &buffer : mCachedStreamIndexBuffers)
495*8975f5c5SAndroid Build Coastguard Worker         {
496*8975f5c5SAndroid Build Coastguard Worker             void *ptr = buffer->getMappedMemory();
497*8975f5c5SAndroid Build Coastguard Worker             if (memcmp(sourcePointer, ptr, amount) == 0)
498*8975f5c5SAndroid Build Coastguard Worker             {
499*8975f5c5SAndroid Build Coastguard Worker                 // Found a matching cached buffer, use the cached internal index buffer.
500*8975f5c5SAndroid Build Coastguard Worker                 *bindingDirty              = mCurrentElementArrayBuffer == buffer.get()
501*8975f5c5SAndroid Build Coastguard Worker                                                  ? BufferBindingDirty::No
502*8975f5c5SAndroid Build Coastguard Worker                                                  : BufferBindingDirty::Yes;
503*8975f5c5SAndroid Build Coastguard Worker                 mCurrentElementArrayBuffer = buffer.get();
504*8975f5c5SAndroid Build Coastguard Worker                 return angle::Result::Continue;
505*8975f5c5SAndroid Build Coastguard Worker             }
506*8975f5c5SAndroid Build Coastguard Worker         }
507*8975f5c5SAndroid Build Coastguard Worker 
508*8975f5c5SAndroid Build Coastguard Worker         // If we still have capacity, cache this index buffer for future use.
509*8975f5c5SAndroid Build Coastguard Worker         if (mCachedStreamIndexBuffers.size() < kMaxCachedStreamIndexBuffers)
510*8975f5c5SAndroid Build Coastguard Worker         {
511*8975f5c5SAndroid Build Coastguard Worker             std::unique_ptr<vk::BufferHelper> buffer = std::make_unique<vk::BufferHelper>();
512*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(contextVk->initBufferAllocation(
513*8975f5c5SAndroid Build Coastguard Worker                 buffer.get(),
514*8975f5c5SAndroid Build Coastguard Worker                 renderer->getVertexConversionBufferMemoryTypeIndex(
515*8975f5c5SAndroid Build Coastguard Worker                     vk::MemoryHostVisibility::Visible),
516*8975f5c5SAndroid Build Coastguard Worker                 amount, renderer->getVertexConversionBufferAlignment(), BufferUsageType::Static));
517*8975f5c5SAndroid Build Coastguard Worker             memcpy(buffer->getMappedMemory(), sourcePointer, amount);
518*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(buffer->flush(renderer));
519*8975f5c5SAndroid Build Coastguard Worker 
520*8975f5c5SAndroid Build Coastguard Worker             mCachedStreamIndexBuffers.push_back(std::move(buffer));
521*8975f5c5SAndroid Build Coastguard Worker 
522*8975f5c5SAndroid Build Coastguard Worker             *bindingDirty              = BufferBindingDirty::Yes;
523*8975f5c5SAndroid Build Coastguard Worker             mCurrentElementArrayBuffer = mCachedStreamIndexBuffers.back().get();
524*8975f5c5SAndroid Build Coastguard Worker             return angle::Result::Continue;
525*8975f5c5SAndroid Build Coastguard Worker         }
526*8975f5c5SAndroid Build Coastguard Worker     }
527*8975f5c5SAndroid Build Coastguard Worker 
528*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mStreamedIndexData, amount,
529*8975f5c5SAndroid Build Coastguard Worker                                                        vk::MemoryHostVisibility::Visible));
530*8975f5c5SAndroid Build Coastguard Worker     mCurrentElementArrayBuffer = mStreamedIndexData.getBuffer();
531*8975f5c5SAndroid Build Coastguard Worker     GLubyte *dst               = mCurrentElementArrayBuffer->getMappedMemory();
532*8975f5c5SAndroid Build Coastguard Worker     *bindingDirty              = BufferBindingDirty::Yes;
533*8975f5c5SAndroid Build Coastguard Worker 
534*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->shouldConvertUint8VkIndexType(indexType))
535*8975f5c5SAndroid Build Coastguard Worker     {
536*8975f5c5SAndroid Build Coastguard Worker         // Unsigned bytes don't have direct support in Vulkan so we have to expand the
537*8975f5c5SAndroid Build Coastguard Worker         // memory to a GLushort.
538*8975f5c5SAndroid Build Coastguard Worker         const GLubyte *in     = static_cast<const GLubyte *>(sourcePointer);
539*8975f5c5SAndroid Build Coastguard Worker         GLushort *expandedDst = reinterpret_cast<GLushort *>(dst);
540*8975f5c5SAndroid Build Coastguard Worker         bool primitiveRestart = contextVk->getState().isPrimitiveRestartEnabled();
541*8975f5c5SAndroid Build Coastguard Worker 
542*8975f5c5SAndroid Build Coastguard Worker         constexpr GLubyte kUnsignedByteRestartValue   = 0xFF;
543*8975f5c5SAndroid Build Coastguard Worker         constexpr GLushort kUnsignedShortRestartValue = 0xFFFF;
544*8975f5c5SAndroid Build Coastguard Worker 
545*8975f5c5SAndroid Build Coastguard Worker         if (primitiveRestart)
546*8975f5c5SAndroid Build Coastguard Worker         {
547*8975f5c5SAndroid Build Coastguard Worker             for (size_t index = 0; index < indexCount; index++)
548*8975f5c5SAndroid Build Coastguard Worker             {
549*8975f5c5SAndroid Build Coastguard Worker                 GLushort value = static_cast<GLushort>(in[index]);
550*8975f5c5SAndroid Build Coastguard Worker                 if (in[index] == kUnsignedByteRestartValue)
551*8975f5c5SAndroid Build Coastguard Worker                 {
552*8975f5c5SAndroid Build Coastguard Worker                     // Convert from 8-bit restart value to 16-bit restart value
553*8975f5c5SAndroid Build Coastguard Worker                     value = kUnsignedShortRestartValue;
554*8975f5c5SAndroid Build Coastguard Worker                 }
555*8975f5c5SAndroid Build Coastguard Worker                 expandedDst[index] = value;
556*8975f5c5SAndroid Build Coastguard Worker             }
557*8975f5c5SAndroid Build Coastguard Worker         }
558*8975f5c5SAndroid Build Coastguard Worker         else
559*8975f5c5SAndroid Build Coastguard Worker         {
560*8975f5c5SAndroid Build Coastguard Worker             // Fast path for common case.
561*8975f5c5SAndroid Build Coastguard Worker             for (size_t index = 0; index < indexCount; index++)
562*8975f5c5SAndroid Build Coastguard Worker             {
563*8975f5c5SAndroid Build Coastguard Worker                 expandedDst[index] = static_cast<GLushort>(in[index]);
564*8975f5c5SAndroid Build Coastguard Worker             }
565*8975f5c5SAndroid Build Coastguard Worker         }
566*8975f5c5SAndroid Build Coastguard Worker     }
567*8975f5c5SAndroid Build Coastguard Worker     else
568*8975f5c5SAndroid Build Coastguard Worker     {
569*8975f5c5SAndroid Build Coastguard Worker         // The primitive restart value is the same for OpenGL and Vulkan,
570*8975f5c5SAndroid Build Coastguard Worker         // so there's no need to perform any conversion.
571*8975f5c5SAndroid Build Coastguard Worker         memcpy(dst, sourcePointer, amount);
572*8975f5c5SAndroid Build Coastguard Worker     }
573*8975f5c5SAndroid Build Coastguard Worker 
574*8975f5c5SAndroid Build Coastguard Worker     mStreamedIndexData.clearDirty();
575*8975f5c5SAndroid Build Coastguard Worker 
576*8975f5c5SAndroid Build Coastguard Worker     return mCurrentElementArrayBuffer->flush(contextVk->getRenderer());
577*8975f5c5SAndroid Build Coastguard Worker }
578*8975f5c5SAndroid Build Coastguard Worker 
579*8975f5c5SAndroid Build Coastguard Worker // We assume the buffer is completely full of the same kind of data and convert
580*8975f5c5SAndroid Build Coastguard Worker // and/or align it as we copy it to a buffer. The assumption could be wrong
581*8975f5c5SAndroid Build Coastguard Worker // but the alternative of copying it piecemeal on each draw would have a lot more
582*8975f5c5SAndroid Build Coastguard Worker // overhead.
convertVertexBufferGPU(ContextVk * contextVk,BufferVk * srcBuffer,VertexConversionBuffer * conversion,const angle::Format & srcFormat,const angle::Format & dstFormat)583*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::convertVertexBufferGPU(ContextVk *contextVk,
584*8975f5c5SAndroid Build Coastguard Worker                                                     BufferVk *srcBuffer,
585*8975f5c5SAndroid Build Coastguard Worker                                                     VertexConversionBuffer *conversion,
586*8975f5c5SAndroid Build Coastguard Worker                                                     const angle::Format &srcFormat,
587*8975f5c5SAndroid Build Coastguard Worker                                                     const angle::Format &dstFormat)
588*8975f5c5SAndroid Build Coastguard Worker {
589*8975f5c5SAndroid Build Coastguard Worker     uint32_t srcStride = conversion->getCacheKey().stride;
590*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcStride % (srcFormat.pixelBytes / srcFormat.channelCount) == 0);
591*8975f5c5SAndroid Build Coastguard Worker 
592*8975f5c5SAndroid Build Coastguard Worker     size_t maxNumVertices;
593*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(CalculateMaxVertexCountForConversion(contextVk, srcBuffer, conversion, srcFormat,
594*8975f5c5SAndroid Build Coastguard Worker                                                    dstFormat, &maxNumVertices));
595*8975f5c5SAndroid Build Coastguard Worker     if (maxNumVertices == 0)
596*8975f5c5SAndroid Build Coastguard Worker     {
597*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
598*8975f5c5SAndroid Build Coastguard Worker     }
599*8975f5c5SAndroid Build Coastguard Worker 
600*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *srcBufferHelper = &srcBuffer->getBuffer();
601*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper *dstBuffer       = conversion->getBuffer();
602*8975f5c5SAndroid Build Coastguard Worker 
603*8975f5c5SAndroid Build Coastguard Worker     UtilsVk::OffsetAndVertexCounts additionalOffsetVertexCounts;
604*8975f5c5SAndroid Build Coastguard Worker 
605*8975f5c5SAndroid Build Coastguard Worker     UtilsVk::ConvertVertexParameters params;
606*8975f5c5SAndroid Build Coastguard Worker     params.srcFormat   = &srcFormat;
607*8975f5c5SAndroid Build Coastguard Worker     params.dstFormat   = &dstFormat;
608*8975f5c5SAndroid Build Coastguard Worker     params.srcStride   = srcStride;
609*8975f5c5SAndroid Build Coastguard Worker     params.vertexCount = 0;
610*8975f5c5SAndroid Build Coastguard Worker 
611*8975f5c5SAndroid Build Coastguard Worker     if (conversion->isEntireBufferDirty())
612*8975f5c5SAndroid Build Coastguard Worker     {
613*8975f5c5SAndroid Build Coastguard Worker         params.vertexCount = static_cast<uint32_t>(maxNumVertices);
614*8975f5c5SAndroid Build Coastguard Worker         params.srcOffset   = static_cast<uint32_t>(conversion->getCacheKey().offset);
615*8975f5c5SAndroid Build Coastguard Worker         params.dstOffset   = 0;
616*8975f5c5SAndroid Build Coastguard Worker     }
617*8975f5c5SAndroid Build Coastguard Worker     else
618*8975f5c5SAndroid Build Coastguard Worker     {
619*8975f5c5SAndroid Build Coastguard Worker         // dirtyRanges may overlap with each other. Try to do a quick merge to reduce the number of
620*8975f5c5SAndroid Build Coastguard Worker         // dispatch calls as well as avoid redundant conversion in the overlapped area.
621*8975f5c5SAndroid Build Coastguard Worker         conversion->consolidateDirtyRanges();
622*8975f5c5SAndroid Build Coastguard Worker 
623*8975f5c5SAndroid Build Coastguard Worker         const std::vector<RangeDeviceSize> &dirtyRanges = conversion->getDirtyBufferRanges();
624*8975f5c5SAndroid Build Coastguard Worker         additionalOffsetVertexCounts.reserve(dirtyRanges.size());
625*8975f5c5SAndroid Build Coastguard Worker 
626*8975f5c5SAndroid Build Coastguard Worker         for (const RangeDeviceSize &dirtyRange : dirtyRanges)
627*8975f5c5SAndroid Build Coastguard Worker         {
628*8975f5c5SAndroid Build Coastguard Worker             if (dirtyRange.empty())
629*8975f5c5SAndroid Build Coastguard Worker             {
630*8975f5c5SAndroid Build Coastguard Worker                 // consolidateDirtyRanges may end up with invalid range if it gets merged.
631*8975f5c5SAndroid Build Coastguard Worker                 continue;
632*8975f5c5SAndroid Build Coastguard Worker             }
633*8975f5c5SAndroid Build Coastguard Worker 
634*8975f5c5SAndroid Build Coastguard Worker             uint32_t srcOffset, dstOffset, numVertices;
635*8975f5c5SAndroid Build Coastguard Worker             CalculateOffsetAndVertexCountForDirtyRange(srcBuffer, conversion, srcFormat, dstFormat,
636*8975f5c5SAndroid Build Coastguard Worker                                                        dirtyRange, &srcOffset, &dstOffset,
637*8975f5c5SAndroid Build Coastguard Worker                                                        &numVertices);
638*8975f5c5SAndroid Build Coastguard Worker             if (params.vertexCount == 0)
639*8975f5c5SAndroid Build Coastguard Worker             {
640*8975f5c5SAndroid Build Coastguard Worker                 params.vertexCount = numVertices;
641*8975f5c5SAndroid Build Coastguard Worker                 params.srcOffset   = srcOffset;
642*8975f5c5SAndroid Build Coastguard Worker                 params.dstOffset   = dstOffset;
643*8975f5c5SAndroid Build Coastguard Worker             }
644*8975f5c5SAndroid Build Coastguard Worker             else
645*8975f5c5SAndroid Build Coastguard Worker             {
646*8975f5c5SAndroid Build Coastguard Worker                 additionalOffsetVertexCounts.emplace_back();
647*8975f5c5SAndroid Build Coastguard Worker                 additionalOffsetVertexCounts.back().srcOffset   = srcOffset;
648*8975f5c5SAndroid Build Coastguard Worker                 additionalOffsetVertexCounts.back().dstOffset   = dstOffset;
649*8975f5c5SAndroid Build Coastguard Worker                 additionalOffsetVertexCounts.back().vertexCount = numVertices;
650*8975f5c5SAndroid Build Coastguard Worker             }
651*8975f5c5SAndroid Build Coastguard Worker         }
652*8975f5c5SAndroid Build Coastguard Worker     }
653*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->getUtils().convertVertexBuffer(contextVk, dstBuffer, srcBufferHelper,
654*8975f5c5SAndroid Build Coastguard Worker                                                         params, additionalOffsetVertexCounts));
655*8975f5c5SAndroid Build Coastguard Worker     conversion->clearDirty();
656*8975f5c5SAndroid Build Coastguard Worker 
657*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
658*8975f5c5SAndroid Build Coastguard Worker }
659*8975f5c5SAndroid Build Coastguard Worker 
convertVertexBufferCPU(ContextVk * contextVk,BufferVk * srcBuffer,VertexConversionBuffer * conversion,const angle::Format & srcFormat,const angle::Format & dstFormat,const VertexCopyFunction vertexLoadFunction)660*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
661*8975f5c5SAndroid Build Coastguard Worker                                                     BufferVk *srcBuffer,
662*8975f5c5SAndroid Build Coastguard Worker                                                     VertexConversionBuffer *conversion,
663*8975f5c5SAndroid Build Coastguard Worker                                                     const angle::Format &srcFormat,
664*8975f5c5SAndroid Build Coastguard Worker                                                     const angle::Format &dstFormat,
665*8975f5c5SAndroid Build Coastguard Worker                                                     const VertexCopyFunction vertexLoadFunction)
666*8975f5c5SAndroid Build Coastguard Worker {
667*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "VertexArrayVk::convertVertexBufferCpu");
668*8975f5c5SAndroid Build Coastguard Worker 
669*8975f5c5SAndroid Build Coastguard Worker     size_t maxNumVertices;
670*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(CalculateMaxVertexCountForConversion(contextVk, srcBuffer, conversion, srcFormat,
671*8975f5c5SAndroid Build Coastguard Worker                                                    dstFormat, &maxNumVertices));
672*8975f5c5SAndroid Build Coastguard Worker     if (maxNumVertices == 0)
673*8975f5c5SAndroid Build Coastguard Worker     {
674*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
675*8975f5c5SAndroid Build Coastguard Worker     }
676*8975f5c5SAndroid Build Coastguard Worker 
677*8975f5c5SAndroid Build Coastguard Worker     uint8_t *src = nullptr;
678*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(srcBuffer->mapImpl(contextVk, GL_MAP_READ_BIT, reinterpret_cast<void **>(&src)));
679*8975f5c5SAndroid Build Coastguard Worker     uint32_t srcStride      = conversion->getCacheKey().stride;
680*8975f5c5SAndroid Build Coastguard Worker 
681*8975f5c5SAndroid Build Coastguard Worker     if (conversion->isEntireBufferDirty())
682*8975f5c5SAndroid Build Coastguard Worker     {
683*8975f5c5SAndroid Build Coastguard Worker         size_t srcOffset        = conversion->getCacheKey().offset;
684*8975f5c5SAndroid Build Coastguard Worker         size_t dstOffset        = 0;
685*8975f5c5SAndroid Build Coastguard Worker         const uint8_t *srcBytes = src + srcOffset;
686*8975f5c5SAndroid Build Coastguard Worker         size_t bytesToCopy      = maxNumVertices * dstFormat.pixelBytes;
687*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(StreamVertexData(contextVk, conversion->getBuffer(), srcBytes, bytesToCopy,
688*8975f5c5SAndroid Build Coastguard Worker                                    dstOffset, maxNumVertices, srcStride, vertexLoadFunction));
689*8975f5c5SAndroid Build Coastguard Worker     }
690*8975f5c5SAndroid Build Coastguard Worker     else
691*8975f5c5SAndroid Build Coastguard Worker     {
692*8975f5c5SAndroid Build Coastguard Worker         // dirtyRanges may overlap with each other. Try to do a quick merge to avoid redundant
693*8975f5c5SAndroid Build Coastguard Worker         // conversion in the overlapped area.
694*8975f5c5SAndroid Build Coastguard Worker         conversion->consolidateDirtyRanges();
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker         const std::vector<RangeDeviceSize> &dirtyRanges = conversion->getDirtyBufferRanges();
697*8975f5c5SAndroid Build Coastguard Worker         for (const RangeDeviceSize &dirtyRange : dirtyRanges)
698*8975f5c5SAndroid Build Coastguard Worker         {
699*8975f5c5SAndroid Build Coastguard Worker             if (dirtyRange.empty())
700*8975f5c5SAndroid Build Coastguard Worker             {
701*8975f5c5SAndroid Build Coastguard Worker                 // consolidateDirtyRanges may end up with invalid range if it gets merged.
702*8975f5c5SAndroid Build Coastguard Worker                 continue;
703*8975f5c5SAndroid Build Coastguard Worker             }
704*8975f5c5SAndroid Build Coastguard Worker 
705*8975f5c5SAndroid Build Coastguard Worker             uint32_t srcOffset, dstOffset, numVertices;
706*8975f5c5SAndroid Build Coastguard Worker             CalculateOffsetAndVertexCountForDirtyRange(srcBuffer, conversion, srcFormat, dstFormat,
707*8975f5c5SAndroid Build Coastguard Worker                                                        dirtyRange, &srcOffset, &dstOffset,
708*8975f5c5SAndroid Build Coastguard Worker                                                        &numVertices);
709*8975f5c5SAndroid Build Coastguard Worker 
710*8975f5c5SAndroid Build Coastguard Worker             if (numVertices > 0)
711*8975f5c5SAndroid Build Coastguard Worker             {
712*8975f5c5SAndroid Build Coastguard Worker                 const uint8_t *srcBytes = src + srcOffset;
713*8975f5c5SAndroid Build Coastguard Worker                 size_t bytesToCopy      = maxNumVertices * dstFormat.pixelBytes;
714*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(StreamVertexData(contextVk, conversion->getBuffer(), srcBytes,
715*8975f5c5SAndroid Build Coastguard Worker                                            bytesToCopy, dstOffset, maxNumVertices, srcStride,
716*8975f5c5SAndroid Build Coastguard Worker                                            vertexLoadFunction));
717*8975f5c5SAndroid Build Coastguard Worker             }
718*8975f5c5SAndroid Build Coastguard Worker         }
719*8975f5c5SAndroid Build Coastguard Worker     }
720*8975f5c5SAndroid Build Coastguard Worker 
721*8975f5c5SAndroid Build Coastguard Worker     conversion->clearDirty();
722*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(srcBuffer->unmapImpl(contextVk));
723*8975f5c5SAndroid Build Coastguard Worker 
724*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
725*8975f5c5SAndroid Build Coastguard Worker }
726*8975f5c5SAndroid Build Coastguard Worker 
updateCurrentElementArrayBuffer()727*8975f5c5SAndroid Build Coastguard Worker void VertexArrayVk::updateCurrentElementArrayBuffer()
728*8975f5c5SAndroid Build Coastguard Worker {
729*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mState.getElementArrayBuffer() != nullptr);
730*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mState.getElementArrayBuffer()->getSize() > 0);
731*8975f5c5SAndroid Build Coastguard Worker 
732*8975f5c5SAndroid Build Coastguard Worker     BufferVk *bufferVk         = vk::GetImpl(mState.getElementArrayBuffer());
733*8975f5c5SAndroid Build Coastguard Worker     mCurrentElementArrayBuffer = &bufferVk->getBuffer();
734*8975f5c5SAndroid Build Coastguard Worker }
735*8975f5c5SAndroid Build Coastguard Worker 
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits,gl::VertexArray::DirtyAttribBitsArray * attribBits,gl::VertexArray::DirtyBindingBitsArray * bindingBits)736*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::syncState(const gl::Context *context,
737*8975f5c5SAndroid Build Coastguard Worker                                        const gl::VertexArray::DirtyBits &dirtyBits,
738*8975f5c5SAndroid Build Coastguard Worker                                        gl::VertexArray::DirtyAttribBitsArray *attribBits,
739*8975f5c5SAndroid Build Coastguard Worker                                        gl::VertexArray::DirtyBindingBitsArray *bindingBits)
740*8975f5c5SAndroid Build Coastguard Worker {
741*8975f5c5SAndroid Build Coastguard Worker     ASSERT(dirtyBits.any());
742*8975f5c5SAndroid Build Coastguard Worker 
743*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
744*8975f5c5SAndroid Build Coastguard Worker     contextVk->getPerfCounters().vertexArraySyncStateCalls++;
745*8975f5c5SAndroid Build Coastguard Worker 
746*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
747*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
748*8975f5c5SAndroid Build Coastguard Worker 
749*8975f5c5SAndroid Build Coastguard Worker     for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter)
750*8975f5c5SAndroid Build Coastguard Worker     {
751*8975f5c5SAndroid Build Coastguard Worker         size_t dirtyBit = *iter;
752*8975f5c5SAndroid Build Coastguard Worker         switch (dirtyBit)
753*8975f5c5SAndroid Build Coastguard Worker         {
754*8975f5c5SAndroid Build Coastguard Worker             case gl::VertexArray::DIRTY_BIT_LOST_OBSERVATION:
755*8975f5c5SAndroid Build Coastguard Worker             {
756*8975f5c5SAndroid Build Coastguard Worker                 // If vertex array was not observing while unbound, we need to check buffer's
757*8975f5c5SAndroid Build Coastguard Worker                 // internal storage and take action if buffer storage has changed while not
758*8975f5c5SAndroid Build Coastguard Worker                 // observing.
759*8975f5c5SAndroid Build Coastguard Worker                 if (contextVk->getFeatures().compressVertexData.enabled ||
760*8975f5c5SAndroid Build Coastguard Worker                     mContentsObservers->any())
761*8975f5c5SAndroid Build Coastguard Worker                 {
762*8975f5c5SAndroid Build Coastguard Worker                     // We may have lost buffer content change when it became non-current. In that
763*8975f5c5SAndroid Build Coastguard Worker                     // case we always assume buffer has changed. If compressVertexData.enabled is
764*8975f5c5SAndroid Build Coastguard Worker                     // true, it also depends on buffer usage which may have changed.
765*8975f5c5SAndroid Build Coastguard Worker                     iter.setLaterBits(
766*8975f5c5SAndroid Build Coastguard Worker                         gl::VertexArray::DirtyBits(mState.getBufferBindingMask().to_ulong()
767*8975f5c5SAndroid Build Coastguard Worker                                                    << gl::VertexArray::DIRTY_BIT_BINDING_0));
768*8975f5c5SAndroid Build Coastguard Worker                 }
769*8975f5c5SAndroid Build Coastguard Worker                 else
770*8975f5c5SAndroid Build Coastguard Worker                 {
771*8975f5c5SAndroid Build Coastguard Worker                     for (size_t bindingIndex : mState.getBufferBindingMask())
772*8975f5c5SAndroid Build Coastguard Worker                     {
773*8975f5c5SAndroid Build Coastguard Worker                         const gl::Buffer *bufferGL    = bindings[bindingIndex].getBuffer().get();
774*8975f5c5SAndroid Build Coastguard Worker                         vk::BufferSerial bufferSerial = vk::GetImpl(bufferGL)->getBufferSerial();
775*8975f5c5SAndroid Build Coastguard Worker                         for (size_t attribIndex : bindings[bindingIndex].getBoundAttributesMask())
776*8975f5c5SAndroid Build Coastguard Worker                         {
777*8975f5c5SAndroid Build Coastguard Worker                             if (attribs[attribIndex].enabled &&
778*8975f5c5SAndroid Build Coastguard Worker                                 (!bufferSerial.valid() ||
779*8975f5c5SAndroid Build Coastguard Worker                                  bufferSerial != mCurrentArrayBufferSerial[attribIndex]))
780*8975f5c5SAndroid Build Coastguard Worker                             {
781*8975f5c5SAndroid Build Coastguard Worker                                 iter.setLaterBit(gl::VertexArray::DIRTY_BIT_BINDING_0 +
782*8975f5c5SAndroid Build Coastguard Worker                                                  bindingIndex);
783*8975f5c5SAndroid Build Coastguard Worker                                 break;
784*8975f5c5SAndroid Build Coastguard Worker                             }
785*8975f5c5SAndroid Build Coastguard Worker                         }
786*8975f5c5SAndroid Build Coastguard Worker                     }
787*8975f5c5SAndroid Build Coastguard Worker                 }
788*8975f5c5SAndroid Build Coastguard Worker                 break;
789*8975f5c5SAndroid Build Coastguard Worker             }
790*8975f5c5SAndroid Build Coastguard Worker 
791*8975f5c5SAndroid Build Coastguard Worker             case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
792*8975f5c5SAndroid Build Coastguard Worker             case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
793*8975f5c5SAndroid Build Coastguard Worker             {
794*8975f5c5SAndroid Build Coastguard Worker                 gl::Buffer *bufferGL = mState.getElementArrayBuffer();
795*8975f5c5SAndroid Build Coastguard Worker                 if (bufferGL && bufferGL->getSize() > 0)
796*8975f5c5SAndroid Build Coastguard Worker                 {
797*8975f5c5SAndroid Build Coastguard Worker                     // Note that just updating buffer data may still result in a new
798*8975f5c5SAndroid Build Coastguard Worker                     // vk::BufferHelper allocation.
799*8975f5c5SAndroid Build Coastguard Worker                     updateCurrentElementArrayBuffer();
800*8975f5c5SAndroid Build Coastguard Worker                 }
801*8975f5c5SAndroid Build Coastguard Worker                 else
802*8975f5c5SAndroid Build Coastguard Worker                 {
803*8975f5c5SAndroid Build Coastguard Worker                     mCurrentElementArrayBuffer = nullptr;
804*8975f5c5SAndroid Build Coastguard Worker                 }
805*8975f5c5SAndroid Build Coastguard Worker 
806*8975f5c5SAndroid Build Coastguard Worker                 mLineLoopBufferFirstIndex.reset();
807*8975f5c5SAndroid Build Coastguard Worker                 mLineLoopBufferLastIndex.reset();
808*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(contextVk->onIndexBufferChange(mCurrentElementArrayBuffer));
809*8975f5c5SAndroid Build Coastguard Worker                 mDirtyLineLoopTranslation = true;
810*8975f5c5SAndroid Build Coastguard Worker                 break;
811*8975f5c5SAndroid Build Coastguard Worker             }
812*8975f5c5SAndroid Build Coastguard Worker 
813*8975f5c5SAndroid Build Coastguard Worker #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX)                                                 \
814*8975f5c5SAndroid Build Coastguard Worker     case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX:                                         \
815*8975f5c5SAndroid Build Coastguard Worker     {                                                                                         \
816*8975f5c5SAndroid Build Coastguard Worker         gl::VertexArray::DirtyAttribBits dirtyAttribBitsRequiresPipelineUpdate =              \
817*8975f5c5SAndroid Build Coastguard Worker             (*attribBits)[INDEX] & mAttribDirtyBitsRequiresPipelineUpdate;                    \
818*8975f5c5SAndroid Build Coastguard Worker         const bool bufferOnly = dirtyAttribBitsRequiresPipelineUpdate.none();                 \
819*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX],                                  \
820*8975f5c5SAndroid Build Coastguard Worker                                   bindings[attribs[INDEX].bindingIndex], INDEX, bufferOnly)); \
821*8975f5c5SAndroid Build Coastguard Worker         (*attribBits)[INDEX].reset();                                                         \
822*8975f5c5SAndroid Build Coastguard Worker         break;                                                                                \
823*8975f5c5SAndroid Build Coastguard Worker     }
824*8975f5c5SAndroid Build Coastguard Worker 
825*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
826*8975f5c5SAndroid Build Coastguard Worker 
827*8975f5c5SAndroid Build Coastguard Worker // Since BINDING already implies DATA and ATTRIB change, we remove these here to avoid redundant
828*8975f5c5SAndroid Build Coastguard Worker // processing.
829*8975f5c5SAndroid Build Coastguard Worker #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX)                                          \
830*8975f5c5SAndroid Build Coastguard Worker     case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX:                                  \
831*8975f5c5SAndroid Build Coastguard Worker     {                                                                                   \
832*8975f5c5SAndroid Build Coastguard Worker         gl::VertexArray::DirtyBindingBits dirtyBindingBitsRequirePipelineUpdate =       \
833*8975f5c5SAndroid Build Coastguard Worker             (*bindingBits)[INDEX] & mBindingDirtyBitsRequiresPipelineUpdate;            \
834*8975f5c5SAndroid Build Coastguard Worker                                                                                         \
835*8975f5c5SAndroid Build Coastguard Worker         for (size_t attribIndex : bindings[INDEX].getBoundAttributesMask())             \
836*8975f5c5SAndroid Build Coastguard Worker         {                                                                               \
837*8975f5c5SAndroid Build Coastguard Worker             gl::VertexArray::DirtyAttribBits dirtyAttribBitsRequiresPipelineUpdate =    \
838*8975f5c5SAndroid Build Coastguard Worker                 (*attribBits)[attribIndex] & mAttribDirtyBitsRequiresPipelineUpdate;    \
839*8975f5c5SAndroid Build Coastguard Worker             const bool bufferOnly = dirtyBindingBitsRequirePipelineUpdate.none() &&     \
840*8975f5c5SAndroid Build Coastguard Worker                                     dirtyAttribBitsRequiresPipelineUpdate.none();       \
841*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[attribIndex], bindings[INDEX], \
842*8975f5c5SAndroid Build Coastguard Worker                                       attribIndex, bufferOnly));                        \
843*8975f5c5SAndroid Build Coastguard Worker             iter.resetLaterBit(gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + attribIndex); \
844*8975f5c5SAndroid Build Coastguard Worker             iter.resetLaterBit(gl::VertexArray::DIRTY_BIT_ATTRIB_0 + attribIndex);      \
845*8975f5c5SAndroid Build Coastguard Worker             (*attribBits)[attribIndex].reset();                                         \
846*8975f5c5SAndroid Build Coastguard Worker         }                                                                               \
847*8975f5c5SAndroid Build Coastguard Worker         (*bindingBits)[INDEX].reset();                                                  \
848*8975f5c5SAndroid Build Coastguard Worker         break;                                                                          \
849*8975f5c5SAndroid Build Coastguard Worker     }
850*8975f5c5SAndroid Build Coastguard Worker 
851*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
852*8975f5c5SAndroid Build Coastguard Worker 
853*8975f5c5SAndroid Build Coastguard Worker #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX)                                       \
854*8975f5c5SAndroid Build Coastguard Worker     case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX:                               \
855*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX],                             \
856*8975f5c5SAndroid Build Coastguard Worker                                   bindings[attribs[INDEX].bindingIndex], INDEX, false)); \
857*8975f5c5SAndroid Build Coastguard Worker         iter.resetLaterBit(gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX);                 \
858*8975f5c5SAndroid Build Coastguard Worker         (*attribBits)[INDEX].reset();                                                    \
859*8975f5c5SAndroid Build Coastguard Worker         break;
860*8975f5c5SAndroid Build Coastguard Worker 
861*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)
862*8975f5c5SAndroid Build Coastguard Worker 
863*8975f5c5SAndroid Build Coastguard Worker             default:
864*8975f5c5SAndroid Build Coastguard Worker                 UNREACHABLE();
865*8975f5c5SAndroid Build Coastguard Worker                 break;
866*8975f5c5SAndroid Build Coastguard Worker         }
867*8975f5c5SAndroid Build Coastguard Worker     }
868*8975f5c5SAndroid Build Coastguard Worker 
869*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
870*8975f5c5SAndroid Build Coastguard Worker }  // namespace rx
871*8975f5c5SAndroid Build Coastguard Worker 
872*8975f5c5SAndroid Build Coastguard Worker #undef ANGLE_VERTEX_DIRTY_ATTRIB_FUNC
873*8975f5c5SAndroid Build Coastguard Worker #undef ANGLE_VERTEX_DIRTY_BINDING_FUNC
874*8975f5c5SAndroid Build Coastguard Worker #undef ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC
875*8975f5c5SAndroid Build Coastguard Worker 
setDefaultPackedInput(ContextVk * contextVk,size_t attribIndex,angle::FormatID * formatOut)876*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE angle::Result VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk,
877*8975f5c5SAndroid Build Coastguard Worker                                                                 size_t attribIndex,
878*8975f5c5SAndroid Build Coastguard Worker                                                                 angle::FormatID *formatOut)
879*8975f5c5SAndroid Build Coastguard Worker {
880*8975f5c5SAndroid Build Coastguard Worker     const gl::State &glState = contextVk->getState();
881*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexAttribCurrentValueData &defaultValue =
882*8975f5c5SAndroid Build Coastguard Worker         glState.getVertexAttribCurrentValues()[attribIndex];
883*8975f5c5SAndroid Build Coastguard Worker 
884*8975f5c5SAndroid Build Coastguard Worker     *formatOut = GetCurrentValueFormatID(defaultValue.Type);
885*8975f5c5SAndroid Build Coastguard Worker 
886*8975f5c5SAndroid Build Coastguard Worker     return contextVk->onVertexAttributeChange(attribIndex, 0, 0, *formatOut, false, 0, nullptr);
887*8975f5c5SAndroid Build Coastguard Worker }
888*8975f5c5SAndroid Build Coastguard Worker 
updateActiveAttribInfo(ContextVk * contextVk)889*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::updateActiveAttribInfo(ContextVk *contextVk)
890*8975f5c5SAndroid Build Coastguard Worker {
891*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
892*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
893*8975f5c5SAndroid Build Coastguard Worker 
894*8975f5c5SAndroid Build Coastguard Worker     // Update pipeline cache with current active attribute info
895*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : mState.getEnabledAttributesMask())
896*8975f5c5SAndroid Build Coastguard Worker     {
897*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = attribs[attribIndex];
898*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding  = bindings[attribs[attribIndex].bindingIndex];
899*8975f5c5SAndroid Build Coastguard Worker         const angle::FormatID format      = attrib.format->id;
900*8975f5c5SAndroid Build Coastguard Worker 
901*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->onVertexAttributeChange(
902*8975f5c5SAndroid Build Coastguard Worker             attribIndex, mCurrentArrayBufferStrides[attribIndex], binding.getDivisor(), format,
903*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferCompressed.test(attribIndex),
904*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferRelativeOffsets[attribIndex], mCurrentArrayBuffers[attribIndex]));
905*8975f5c5SAndroid Build Coastguard Worker 
906*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferFormats[attribIndex] = format;
907*8975f5c5SAndroid Build Coastguard Worker     }
908*8975f5c5SAndroid Build Coastguard Worker 
909*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
910*8975f5c5SAndroid Build Coastguard Worker }
911*8975f5c5SAndroid Build Coastguard Worker 
syncDirtyAttrib(ContextVk * contextVk,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t attribIndex,bool bufferOnly)912*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
913*8975f5c5SAndroid Build Coastguard Worker                                              const gl::VertexAttribute &attrib,
914*8975f5c5SAndroid Build Coastguard Worker                                              const gl::VertexBinding &binding,
915*8975f5c5SAndroid Build Coastguard Worker                                              size_t attribIndex,
916*8975f5c5SAndroid Build Coastguard Worker                                              bool bufferOnly)
917*8975f5c5SAndroid Build Coastguard Worker {
918*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
919*8975f5c5SAndroid Build Coastguard Worker     if (attrib.enabled)
920*8975f5c5SAndroid Build Coastguard Worker     {
921*8975f5c5SAndroid Build Coastguard Worker         const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
922*8975f5c5SAndroid Build Coastguard Worker 
923*8975f5c5SAndroid Build Coastguard Worker         // Init attribute offset to the front-end value
924*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferRelativeOffsets[attribIndex] = attrib.relativeOffset;
925*8975f5c5SAndroid Build Coastguard Worker         gl::Buffer *bufferGL                            = binding.getBuffer().get();
926*8975f5c5SAndroid Build Coastguard Worker         // Emulated and/or client-side attribs will be streamed
927*8975f5c5SAndroid Build Coastguard Worker         bool isStreamingVertexAttrib =
928*8975f5c5SAndroid Build Coastguard Worker             (binding.getDivisor() > renderer->getMaxVertexAttribDivisor()) || (bufferGL == nullptr);
929*8975f5c5SAndroid Build Coastguard Worker         // If we sre switching between streaming and buffer mode, set bufferOnly to false since we
930*8975f5c5SAndroid Build Coastguard Worker         // are actually changing the buffer.
931*8975f5c5SAndroid Build Coastguard Worker         if (bufferOnly && isStreamingVertexAttrib != mStreamingVertexAttribsMask.test(attribIndex))
932*8975f5c5SAndroid Build Coastguard Worker         {
933*8975f5c5SAndroid Build Coastguard Worker             bufferOnly = false;
934*8975f5c5SAndroid Build Coastguard Worker         }
935*8975f5c5SAndroid Build Coastguard Worker         mStreamingVertexAttribsMask.set(attribIndex, isStreamingVertexAttrib);
936*8975f5c5SAndroid Build Coastguard Worker         bool compressed = false;
937*8975f5c5SAndroid Build Coastguard Worker 
938*8975f5c5SAndroid Build Coastguard Worker         if (bufferGL)
939*8975f5c5SAndroid Build Coastguard Worker         {
940*8975f5c5SAndroid Build Coastguard Worker             mContentsObservers->disableForBuffer(bufferGL, static_cast<uint32_t>(attribIndex));
941*8975f5c5SAndroid Build Coastguard Worker         }
942*8975f5c5SAndroid Build Coastguard Worker 
943*8975f5c5SAndroid Build Coastguard Worker         if (!isStreamingVertexAttrib && bufferGL->getSize() > 0)
944*8975f5c5SAndroid Build Coastguard Worker         {
945*8975f5c5SAndroid Build Coastguard Worker             BufferVk *bufferVk                  = vk::GetImpl(bufferGL);
946*8975f5c5SAndroid Build Coastguard Worker             const angle::Format &srcFormat      = vertexFormat.getIntendedFormat();
947*8975f5c5SAndroid Build Coastguard Worker             unsigned srcFormatSize              = srcFormat.pixelBytes;
948*8975f5c5SAndroid Build Coastguard Worker             uint32_t srcStride    = binding.getStride() == 0 ? srcFormatSize : binding.getStride();
949*8975f5c5SAndroid Build Coastguard Worker             size_t numVertices    = GetVertexCount(bufferVk, binding, srcFormatSize);
950*8975f5c5SAndroid Build Coastguard Worker             bool bindingIsAligned =
951*8975f5c5SAndroid Build Coastguard Worker                 BindingIsAligned(srcFormat, binding.getOffset() + attrib.relativeOffset, srcStride);
952*8975f5c5SAndroid Build Coastguard Worker 
953*8975f5c5SAndroid Build Coastguard Worker             if (renderer->getFeatures().compressVertexData.enabled &&
954*8975f5c5SAndroid Build Coastguard Worker                 gl::IsStaticBufferUsage(bufferGL->getUsage()) &&
955*8975f5c5SAndroid Build Coastguard Worker                 vertexFormat.canCompressBufferData())
956*8975f5c5SAndroid Build Coastguard Worker             {
957*8975f5c5SAndroid Build Coastguard Worker                 compressed = true;
958*8975f5c5SAndroid Build Coastguard Worker             }
959*8975f5c5SAndroid Build Coastguard Worker 
960*8975f5c5SAndroid Build Coastguard Worker             bool needsConversion =
961*8975f5c5SAndroid Build Coastguard Worker                 numVertices > 0 &&
962*8975f5c5SAndroid Build Coastguard Worker                 (vertexFormat.getVertexLoadRequiresConversion(compressed) || !bindingIsAligned);
963*8975f5c5SAndroid Build Coastguard Worker 
964*8975f5c5SAndroid Build Coastguard Worker             if (needsConversion)
965*8975f5c5SAndroid Build Coastguard Worker             {
966*8975f5c5SAndroid Build Coastguard Worker                 const angle::Format &dstFormat = vertexFormat.getActualBufferFormat(compressed);
967*8975f5c5SAndroid Build Coastguard Worker                 // Converted buffer is tightly packed
968*8975f5c5SAndroid Build Coastguard Worker                 uint32_t dstStride = dstFormat.pixelBytes;
969*8975f5c5SAndroid Build Coastguard Worker 
970*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(vertexFormat.getVertexInputAlignment(compressed) <=
971*8975f5c5SAndroid Build Coastguard Worker                        vk::kVertexBufferAlignment);
972*8975f5c5SAndroid Build Coastguard Worker 
973*8975f5c5SAndroid Build Coastguard Worker                 mContentsObservers->enableForBuffer(bufferGL, static_cast<uint32_t>(attribIndex));
974*8975f5c5SAndroid Build Coastguard Worker 
975*8975f5c5SAndroid Build Coastguard Worker                 WarnOnVertexFormatConversion(contextVk, vertexFormat, compressed, true);
976*8975f5c5SAndroid Build Coastguard Worker 
977*8975f5c5SAndroid Build Coastguard Worker                 const VertexConversionBuffer::CacheKey cacheKey{
978*8975f5c5SAndroid Build Coastguard Worker                     srcFormat.id, srcStride,
979*8975f5c5SAndroid Build Coastguard Worker                     static_cast<size_t>(binding.getOffset()) + attrib.relativeOffset,
980*8975f5c5SAndroid Build Coastguard Worker                     !bindingIsAligned, false};
981*8975f5c5SAndroid Build Coastguard Worker 
982*8975f5c5SAndroid Build Coastguard Worker                 VertexConversionBuffer *conversion =
983*8975f5c5SAndroid Build Coastguard Worker                     bufferVk->getVertexConversionBuffer(renderer, cacheKey);
984*8975f5c5SAndroid Build Coastguard Worker 
985*8975f5c5SAndroid Build Coastguard Worker                 // Converted attribs are packed in their own VK buffer so offset is relative to the
986*8975f5c5SAndroid Build Coastguard Worker                 // binding and coversion's offset. The conversion buffer try to reuse the existing
987*8975f5c5SAndroid Build Coastguard Worker                 // buffer as much as possible to reduce the amount of data that has to be converted.
988*8975f5c5SAndroid Build Coastguard Worker                 // When binding's offset changes, it will check if new offset and existing buffer's
989*8975f5c5SAndroid Build Coastguard Worker                 // offset are multiple of strides apart. It yes it will reuse. If new offset is
990*8975f5c5SAndroid Build Coastguard Worker                 // larger, all existing data are still valid. If the new offset is smaller it will
991*8975f5c5SAndroid Build Coastguard Worker                 // mark the newly exposed range dirty and then rely on
992*8975f5c5SAndroid Build Coastguard Worker                 // ContextVk::initBufferForVertexConversion to decide buffer's size is big enough or
993*8975f5c5SAndroid Build Coastguard Worker                 // not and reallocate (and mark entire buffer dirty) if needed.
994*8975f5c5SAndroid Build Coastguard Worker                 //
995*8975f5c5SAndroid Build Coastguard Worker                 // bufferVk:-----------------------------------------------------------------------
996*8975f5c5SAndroid Build Coastguard Worker                 //                 |                   |
997*8975f5c5SAndroid Build Coastguard Worker                 //                 |                bingding.offset + attrib.relativeOffset.
998*8975f5c5SAndroid Build Coastguard Worker                 //          conversion->getCacheKey().offset
999*8975f5c5SAndroid Build Coastguard Worker                 //
1000*8975f5c5SAndroid Build Coastguard Worker                 // conversion.buffer: --------------------------------------------------------------
1001*8975f5c5SAndroid Build Coastguard Worker                 //                                     |
1002*8975f5c5SAndroid Build Coastguard Worker                 //                                   dstRelativeOffset
1003*8975f5c5SAndroid Build Coastguard Worker                 size_t srcRelativeOffset =
1004*8975f5c5SAndroid Build Coastguard Worker                     binding.getOffset() + attrib.relativeOffset - conversion->getCacheKey().offset;
1005*8975f5c5SAndroid Build Coastguard Worker                 size_t numberOfVerticesToSkip = srcRelativeOffset / srcStride;
1006*8975f5c5SAndroid Build Coastguard Worker                 size_t dstRelativeOffset      = numberOfVerticesToSkip * dstStride;
1007*8975f5c5SAndroid Build Coastguard Worker 
1008*8975f5c5SAndroid Build Coastguard Worker                 if (conversion->dirty())
1009*8975f5c5SAndroid Build Coastguard Worker                 {
1010*8975f5c5SAndroid Build Coastguard Worker                     if (compressed)
1011*8975f5c5SAndroid Build Coastguard Worker                     {
1012*8975f5c5SAndroid Build Coastguard Worker                         INFO() << "Compressing vertex data in buffer " << bufferGL->id().value
1013*8975f5c5SAndroid Build Coastguard Worker                                << " from " << ToUnderlying(srcFormat.id) << " to "
1014*8975f5c5SAndroid Build Coastguard Worker                                << ToUnderlying(dstFormat.id) << ".";
1015*8975f5c5SAndroid Build Coastguard Worker                     }
1016*8975f5c5SAndroid Build Coastguard Worker 
1017*8975f5c5SAndroid Build Coastguard Worker                     if (bindingIsAligned)
1018*8975f5c5SAndroid Build Coastguard Worker                     {
1019*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_TRY(convertVertexBufferGPU(contextVk, bufferVk, conversion, srcFormat,
1020*8975f5c5SAndroid Build Coastguard Worker                                                          dstFormat));
1021*8975f5c5SAndroid Build Coastguard Worker                     }
1022*8975f5c5SAndroid Build Coastguard Worker                     else
1023*8975f5c5SAndroid Build Coastguard Worker                     {
1024*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_VK_PERF_WARNING(
1025*8975f5c5SAndroid Build Coastguard Worker                             contextVk, GL_DEBUG_SEVERITY_HIGH,
1026*8975f5c5SAndroid Build Coastguard Worker                             "GPU stall due to vertex format conversion of unaligned data");
1027*8975f5c5SAndroid Build Coastguard Worker 
1028*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_TRY(convertVertexBufferCPU(
1029*8975f5c5SAndroid Build Coastguard Worker                             contextVk, bufferVk, conversion, srcFormat, dstFormat,
1030*8975f5c5SAndroid Build Coastguard Worker                             vertexFormat.getVertexLoadFunction(compressed)));
1031*8975f5c5SAndroid Build Coastguard Worker                     }
1032*8975f5c5SAndroid Build Coastguard Worker 
1033*8975f5c5SAndroid Build Coastguard Worker                     // If conversion happens, the destination buffer stride may be changed,
1034*8975f5c5SAndroid Build Coastguard Worker                     // therefore an attribute change needs to be called. Note that it may trigger
1035*8975f5c5SAndroid Build Coastguard Worker                     // unnecessary vulkan PSO update when the destination buffer stride does not
1036*8975f5c5SAndroid Build Coastguard Worker                     // change, but for simplicity just make it conservative
1037*8975f5c5SAndroid Build Coastguard Worker                     bufferOnly = false;
1038*8975f5c5SAndroid Build Coastguard Worker                 }
1039*8975f5c5SAndroid Build Coastguard Worker 
1040*8975f5c5SAndroid Build Coastguard Worker                 vk::BufferHelper *bufferHelper         = conversion->getBuffer();
1041*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBuffers[attribIndex]      = bufferHelper;
1042*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBufferSerial[attribIndex] = bufferHelper->getBufferSerial();
1043*8975f5c5SAndroid Build Coastguard Worker                 VkDeviceSize bufferOffset;
1044*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBufferHandles[attribIndex] =
1045*8975f5c5SAndroid Build Coastguard Worker                     bufferHelper
1046*8975f5c5SAndroid Build Coastguard Worker                         ->getBufferForVertexArray(contextVk, bufferHelper->getSize(), &bufferOffset)
1047*8975f5c5SAndroid Build Coastguard Worker                         .getHandle();
1048*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(BindingIsAligned(dstFormat, bufferOffset + dstRelativeOffset, dstStride));
1049*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBufferOffsets[attribIndex]         = bufferOffset + dstRelativeOffset;
1050*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBufferRelativeOffsets[attribIndex] = 0;
1051*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBufferStrides[attribIndex]         = dstStride;
1052*8975f5c5SAndroid Build Coastguard Worker             }
1053*8975f5c5SAndroid Build Coastguard Worker             else
1054*8975f5c5SAndroid Build Coastguard Worker             {
1055*8975f5c5SAndroid Build Coastguard Worker                 if (numVertices == 0)
1056*8975f5c5SAndroid Build Coastguard Worker                 {
1057*8975f5c5SAndroid Build Coastguard Worker                     vk::BufferHelper &emptyBuffer = contextVk->getEmptyBuffer();
1058*8975f5c5SAndroid Build Coastguard Worker 
1059*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBuffers[attribIndex]       = &emptyBuffer;
1060*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferSerial[attribIndex]  = emptyBuffer.getBufferSerial();
1061*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferHandles[attribIndex] = emptyBuffer.getBuffer().getHandle();
1062*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferOffsets[attribIndex] = emptyBuffer.getOffset();
1063*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferStrides[attribIndex] = 0;
1064*8975f5c5SAndroid Build Coastguard Worker                 }
1065*8975f5c5SAndroid Build Coastguard Worker                 else
1066*8975f5c5SAndroid Build Coastguard Worker                 {
1067*8975f5c5SAndroid Build Coastguard Worker                     vk::BufferHelper &bufferHelper         = bufferVk->getBuffer();
1068*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBuffers[attribIndex]      = &bufferHelper;
1069*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferSerial[attribIndex] = bufferHelper.getBufferSerial();
1070*8975f5c5SAndroid Build Coastguard Worker                     VkDeviceSize bufferOffset;
1071*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferHandles[attribIndex] =
1072*8975f5c5SAndroid Build Coastguard Worker                         bufferHelper
1073*8975f5c5SAndroid Build Coastguard Worker                             .getBufferForVertexArray(contextVk, bufferVk->getSize(), &bufferOffset)
1074*8975f5c5SAndroid Build Coastguard Worker                             .getHandle();
1075*8975f5c5SAndroid Build Coastguard Worker 
1076*8975f5c5SAndroid Build Coastguard Worker                     // Vulkan requires the offset is within the buffer. We use robust access
1077*8975f5c5SAndroid Build Coastguard Worker                     // behaviour to reset the offset if it starts outside the buffer.
1078*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferOffsets[attribIndex] =
1079*8975f5c5SAndroid Build Coastguard Worker                         binding.getOffset() < static_cast<GLint64>(bufferVk->getSize())
1080*8975f5c5SAndroid Build Coastguard Worker                             ? binding.getOffset() + bufferOffset
1081*8975f5c5SAndroid Build Coastguard Worker                             : bufferOffset;
1082*8975f5c5SAndroid Build Coastguard Worker 
1083*8975f5c5SAndroid Build Coastguard Worker                     mCurrentArrayBufferStrides[attribIndex] = binding.getStride();
1084*8975f5c5SAndroid Build Coastguard Worker                 }
1085*8975f5c5SAndroid Build Coastguard Worker             }
1086*8975f5c5SAndroid Build Coastguard Worker         }
1087*8975f5c5SAndroid Build Coastguard Worker         else
1088*8975f5c5SAndroid Build Coastguard Worker         {
1089*8975f5c5SAndroid Build Coastguard Worker             vk::BufferHelper &emptyBuffer           = contextVk->getEmptyBuffer();
1090*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBuffers[attribIndex]       = &emptyBuffer;
1091*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferSerial[attribIndex]  = emptyBuffer.getBufferSerial();
1092*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferHandles[attribIndex] = emptyBuffer.getBuffer().getHandle();
1093*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferOffsets[attribIndex] = emptyBuffer.getOffset();
1094*8975f5c5SAndroid Build Coastguard Worker 
1095*8975f5c5SAndroid Build Coastguard Worker             bool combined = ShouldCombineAttributes(renderer, attrib, binding);
1096*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferStrides[attribIndex] =
1097*8975f5c5SAndroid Build Coastguard Worker                 combined ? binding.getStride()
1098*8975f5c5SAndroid Build Coastguard Worker                          : vertexFormat.getActualBufferFormat(compressed).pixelBytes;
1099*8975f5c5SAndroid Build Coastguard Worker         }
1100*8975f5c5SAndroid Build Coastguard Worker 
1101*8975f5c5SAndroid Build Coastguard Worker         if (bufferOnly)
1102*8975f5c5SAndroid Build Coastguard Worker         {
1103*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(contextVk->onVertexBufferChange(mCurrentArrayBuffers[attribIndex]));
1104*8975f5c5SAndroid Build Coastguard Worker         }
1105*8975f5c5SAndroid Build Coastguard Worker         else
1106*8975f5c5SAndroid Build Coastguard Worker         {
1107*8975f5c5SAndroid Build Coastguard Worker             const angle::FormatID format = attrib.format->id;
1108*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(contextVk->onVertexAttributeChange(
1109*8975f5c5SAndroid Build Coastguard Worker                 attribIndex, mCurrentArrayBufferStrides[attribIndex], binding.getDivisor(), format,
1110*8975f5c5SAndroid Build Coastguard Worker                 compressed, mCurrentArrayBufferRelativeOffsets[attribIndex],
1111*8975f5c5SAndroid Build Coastguard Worker                 mCurrentArrayBuffers[attribIndex]));
1112*8975f5c5SAndroid Build Coastguard Worker 
1113*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferFormats[attribIndex]    = format;
1114*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferCompressed[attribIndex] = compressed;
1115*8975f5c5SAndroid Build Coastguard Worker             mCurrentArrayBufferDivisors[attribIndex]   = binding.getDivisor();
1116*8975f5c5SAndroid Build Coastguard Worker         }
1117*8975f5c5SAndroid Build Coastguard Worker     }
1118*8975f5c5SAndroid Build Coastguard Worker     else
1119*8975f5c5SAndroid Build Coastguard Worker     {
1120*8975f5c5SAndroid Build Coastguard Worker         contextVk->invalidateDefaultAttribute(attribIndex);
1121*8975f5c5SAndroid Build Coastguard Worker 
1122*8975f5c5SAndroid Build Coastguard Worker         // These will be filled out by the ContextVk.
1123*8975f5c5SAndroid Build Coastguard Worker         vk::BufferHelper &emptyBuffer                   = contextVk->getEmptyBuffer();
1124*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBuffers[attribIndex]               = &emptyBuffer;
1125*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferSerial[attribIndex]          = emptyBuffer.getBufferSerial();
1126*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferHandles[attribIndex]         = emptyBuffer.getBuffer().getHandle();
1127*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferOffsets[attribIndex]         = emptyBuffer.getOffset();
1128*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferStrides[attribIndex]         = 0;
1129*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferDivisors[attribIndex]        = 0;
1130*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferCompressed[attribIndex]      = false;
1131*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferRelativeOffsets[attribIndex] = 0;
1132*8975f5c5SAndroid Build Coastguard Worker 
1133*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(setDefaultPackedInput(contextVk, attribIndex,
1134*8975f5c5SAndroid Build Coastguard Worker                                         &mCurrentArrayBufferFormats[attribIndex]));
1135*8975f5c5SAndroid Build Coastguard Worker     }
1136*8975f5c5SAndroid Build Coastguard Worker 
1137*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1138*8975f5c5SAndroid Build Coastguard Worker }
1139*8975f5c5SAndroid Build Coastguard Worker 
mergeClientAttribsRange(vk::Renderer * renderer,const gl::AttributesMask activeStreamedAttribs,size_t startVertex,size_t endVertex,std::array<AttributeRange,gl::MAX_VERTEX_ATTRIBS> & mergeRangesOut,std::array<size_t,gl::MAX_VERTEX_ATTRIBS> & mergedIndexesOut) const1140*8975f5c5SAndroid Build Coastguard Worker gl::AttributesMask VertexArrayVk::mergeClientAttribsRange(
1141*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer,
1142*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask activeStreamedAttribs,
1143*8975f5c5SAndroid Build Coastguard Worker     size_t startVertex,
1144*8975f5c5SAndroid Build Coastguard Worker     size_t endVertex,
1145*8975f5c5SAndroid Build Coastguard Worker     std::array<AttributeRange, gl::MAX_VERTEX_ATTRIBS> &mergeRangesOut,
1146*8975f5c5SAndroid Build Coastguard Worker     std::array<size_t, gl::MAX_VERTEX_ATTRIBS> &mergedIndexesOut) const
1147*8975f5c5SAndroid Build Coastguard Worker {
1148*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
1149*8975f5c5SAndroid Build Coastguard Worker     const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
1150*8975f5c5SAndroid Build Coastguard Worker     gl::AttributesMask attributeMaskCanCombine;
1151*8975f5c5SAndroid Build Coastguard Worker     angle::FixedVector<size_t, gl::MAX_VERTEX_ATTRIBS> combinedIndexes;
1152*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : activeStreamedAttribs)
1153*8975f5c5SAndroid Build Coastguard Worker     {
1154*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = attribs[attribIndex];
1155*8975f5c5SAndroid Build Coastguard Worker         ASSERT(attrib.enabled);
1156*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
1157*8975f5c5SAndroid Build Coastguard Worker         const vk::Format &vertexFormat   = renderer->getFormat(attrib.format->id);
1158*8975f5c5SAndroid Build Coastguard Worker         bool combined                    = ShouldCombineAttributes(renderer, attrib, binding);
1159*8975f5c5SAndroid Build Coastguard Worker         attributeMaskCanCombine.set(attribIndex, combined);
1160*8975f5c5SAndroid Build Coastguard Worker         if (combined)
1161*8975f5c5SAndroid Build Coastguard Worker         {
1162*8975f5c5SAndroid Build Coastguard Worker             combinedIndexes.push_back(attribIndex);
1163*8975f5c5SAndroid Build Coastguard Worker         }
1164*8975f5c5SAndroid Build Coastguard Worker         GLuint pixelBytes      = vertexFormat.getActualBufferFormat(false).pixelBytes;
1165*8975f5c5SAndroid Build Coastguard Worker         size_t destStride      = combined ? binding.getStride() : pixelBytes;
1166*8975f5c5SAndroid Build Coastguard Worker         uintptr_t startAddress = reinterpret_cast<uintptr_t>(attrib.pointer);
1167*8975f5c5SAndroid Build Coastguard Worker         mergeRangesOut[attribIndex].startAddr = startAddress;
1168*8975f5c5SAndroid Build Coastguard Worker         mergeRangesOut[attribIndex].endAddr =
1169*8975f5c5SAndroid Build Coastguard Worker             startAddress + (endVertex - 1) * destStride + pixelBytes;
1170*8975f5c5SAndroid Build Coastguard Worker         mergeRangesOut[attribIndex].copyStartAddr =
1171*8975f5c5SAndroid Build Coastguard Worker             startAddress + startVertex * binding.getStride();
1172*8975f5c5SAndroid Build Coastguard Worker         mergedIndexesOut[attribIndex] = attribIndex;
1173*8975f5c5SAndroid Build Coastguard Worker     }
1174*8975f5c5SAndroid Build Coastguard Worker     if (attributeMaskCanCombine.none())
1175*8975f5c5SAndroid Build Coastguard Worker     {
1176*8975f5c5SAndroid Build Coastguard Worker         return attributeMaskCanCombine;
1177*8975f5c5SAndroid Build Coastguard Worker     }
1178*8975f5c5SAndroid Build Coastguard Worker     auto comp = [&mergeRangesOut](size_t a, size_t b) -> bool {
1179*8975f5c5SAndroid Build Coastguard Worker         return mergeRangesOut[a] < mergeRangesOut[b];
1180*8975f5c5SAndroid Build Coastguard Worker     };
1181*8975f5c5SAndroid Build Coastguard Worker     // Only sort combined range indexes.
1182*8975f5c5SAndroid Build Coastguard Worker     std::sort(combinedIndexes.begin(), combinedIndexes.end(), comp);
1183*8975f5c5SAndroid Build Coastguard Worker     // Merge combined range span.
1184*8975f5c5SAndroid Build Coastguard Worker     auto next = combinedIndexes.begin();
1185*8975f5c5SAndroid Build Coastguard Worker     auto cur  = next++;
1186*8975f5c5SAndroid Build Coastguard Worker     while (next != combinedIndexes.end() || (cur != next))
1187*8975f5c5SAndroid Build Coastguard Worker     {
1188*8975f5c5SAndroid Build Coastguard Worker         // Cur and next overlaps: merge next into cur and move next.
1189*8975f5c5SAndroid Build Coastguard Worker         if (next != combinedIndexes.end() &&
1190*8975f5c5SAndroid Build Coastguard Worker             mergeRangesOut[*cur].endAddr >= mergeRangesOut[*next].startAddr)
1191*8975f5c5SAndroid Build Coastguard Worker         {
1192*8975f5c5SAndroid Build Coastguard Worker             mergeRangesOut[*cur].endAddr =
1193*8975f5c5SAndroid Build Coastguard Worker                 std::max(mergeRangesOut[*cur].endAddr, mergeRangesOut[*next].endAddr);
1194*8975f5c5SAndroid Build Coastguard Worker             mergeRangesOut[*cur].copyStartAddr =
1195*8975f5c5SAndroid Build Coastguard Worker                 std::min(mergeRangesOut[*cur].copyStartAddr, mergeRangesOut[*next].copyStartAddr);
1196*8975f5c5SAndroid Build Coastguard Worker             mergedIndexesOut[*next] = mergedIndexesOut[*cur];
1197*8975f5c5SAndroid Build Coastguard Worker             ++next;
1198*8975f5c5SAndroid Build Coastguard Worker         }
1199*8975f5c5SAndroid Build Coastguard Worker         else
1200*8975f5c5SAndroid Build Coastguard Worker         {
1201*8975f5c5SAndroid Build Coastguard Worker             ++cur;
1202*8975f5c5SAndroid Build Coastguard Worker             if (cur != next)
1203*8975f5c5SAndroid Build Coastguard Worker             {
1204*8975f5c5SAndroid Build Coastguard Worker                 mergeRangesOut[*cur] = mergeRangesOut[*(cur - 1)];
1205*8975f5c5SAndroid Build Coastguard Worker             }
1206*8975f5c5SAndroid Build Coastguard Worker             else if (next != combinedIndexes.end())
1207*8975f5c5SAndroid Build Coastguard Worker             {
1208*8975f5c5SAndroid Build Coastguard Worker                 ++next;
1209*8975f5c5SAndroid Build Coastguard Worker             }
1210*8975f5c5SAndroid Build Coastguard Worker         }
1211*8975f5c5SAndroid Build Coastguard Worker     }
1212*8975f5c5SAndroid Build Coastguard Worker     return attributeMaskCanCombine;
1213*8975f5c5SAndroid Build Coastguard Worker }
1214*8975f5c5SAndroid Build Coastguard Worker 
1215*8975f5c5SAndroid Build Coastguard Worker // Handle copying client attribs and/or expanding attrib buffer in case where attribute
1216*8975f5c5SAndroid Build Coastguard Worker // divisor value has to be emulated.
updateStreamedAttribs(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices)1217*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::updateStreamedAttribs(const gl::Context *context,
1218*8975f5c5SAndroid Build Coastguard Worker                                                    GLint firstVertex,
1219*8975f5c5SAndroid Build Coastguard Worker                                                    GLsizei vertexOrIndexCount,
1220*8975f5c5SAndroid Build Coastguard Worker                                                    GLsizei instanceCount,
1221*8975f5c5SAndroid Build Coastguard Worker                                                    gl::DrawElementsType indexTypeOrInvalid,
1222*8975f5c5SAndroid Build Coastguard Worker                                                    const void *indices)
1223*8975f5c5SAndroid Build Coastguard Worker {
1224*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk   = vk::GetImpl(context);
1225*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
1226*8975f5c5SAndroid Build Coastguard Worker 
1227*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask activeAttribs =
1228*8975f5c5SAndroid Build Coastguard Worker         context->getStateCache().getActiveClientAttribsMask() |
1229*8975f5c5SAndroid Build Coastguard Worker         context->getStateCache().getActiveBufferedAttribsMask();
1230*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask activeStreamedAttribs = mStreamingVertexAttribsMask & activeAttribs;
1231*8975f5c5SAndroid Build Coastguard Worker 
1232*8975f5c5SAndroid Build Coastguard Worker     // Early return for corner case where emulated buffered attribs are not active
1233*8975f5c5SAndroid Build Coastguard Worker     if (!activeStreamedAttribs.any())
1234*8975f5c5SAndroid Build Coastguard Worker     {
1235*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1236*8975f5c5SAndroid Build Coastguard Worker     }
1237*8975f5c5SAndroid Build Coastguard Worker 
1238*8975f5c5SAndroid Build Coastguard Worker     GLint startVertex;
1239*8975f5c5SAndroid Build Coastguard Worker     size_t vertexCount;
1240*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
1241*8975f5c5SAndroid Build Coastguard Worker                                  indices, 0, &startVertex, &vertexCount));
1242*8975f5c5SAndroid Build Coastguard Worker 
1243*8975f5c5SAndroid Build Coastguard Worker     ASSERT(vertexCount > 0);
1244*8975f5c5SAndroid Build Coastguard Worker     const auto &attribs  = mState.getVertexAttributes();
1245*8975f5c5SAndroid Build Coastguard Worker     const auto &bindings = mState.getVertexBindings();
1246*8975f5c5SAndroid Build Coastguard Worker 
1247*8975f5c5SAndroid Build Coastguard Worker     std::array<size_t, gl::MAX_VERTEX_ATTRIBS> mergedIndexes;
1248*8975f5c5SAndroid Build Coastguard Worker     std::array<AttributeRange, gl::MAX_VERTEX_ATTRIBS> mergeRanges;
1249*8975f5c5SAndroid Build Coastguard Worker     std::array<vk::BufferHelper *, gl::MAX_VERTEX_ATTRIBS> attribBufferHelper = {};
1250*8975f5c5SAndroid Build Coastguard Worker     auto mergeAttribMask =
1251*8975f5c5SAndroid Build Coastguard Worker         mergeClientAttribsRange(renderer, activeStreamedAttribs, startVertex,
1252*8975f5c5SAndroid Build Coastguard Worker                                 startVertex + vertexCount, mergeRanges, mergedIndexes);
1253*8975f5c5SAndroid Build Coastguard Worker 
1254*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex : activeStreamedAttribs)
1255*8975f5c5SAndroid Build Coastguard Worker     {
1256*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribute &attrib = attribs[attribIndex];
1257*8975f5c5SAndroid Build Coastguard Worker         ASSERT(attrib.enabled);
1258*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexBinding &binding = bindings[attrib.bindingIndex];
1259*8975f5c5SAndroid Build Coastguard Worker 
1260*8975f5c5SAndroid Build Coastguard Worker         const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
1261*8975f5c5SAndroid Build Coastguard Worker         const angle::Format &dstFormat = vertexFormat.getActualBufferFormat(false);
1262*8975f5c5SAndroid Build Coastguard Worker         GLuint pixelBytes              = dstFormat.pixelBytes;
1263*8975f5c5SAndroid Build Coastguard Worker 
1264*8975f5c5SAndroid Build Coastguard Worker         const bool compressed = false;
1265*8975f5c5SAndroid Build Coastguard Worker         ASSERT(vertexFormat.getVertexInputAlignment(false) <= vk::kVertexBufferAlignment);
1266*8975f5c5SAndroid Build Coastguard Worker 
1267*8975f5c5SAndroid Build Coastguard Worker         vk::BufferHelper *vertexDataBuffer = nullptr;
1268*8975f5c5SAndroid Build Coastguard Worker         const uint8_t *src                 = static_cast<const uint8_t *>(attrib.pointer);
1269*8975f5c5SAndroid Build Coastguard Worker         const uint32_t divisor             = binding.getDivisor();
1270*8975f5c5SAndroid Build Coastguard Worker 
1271*8975f5c5SAndroid Build Coastguard Worker         bool combined            = mergeAttribMask.test(attribIndex);
1272*8975f5c5SAndroid Build Coastguard Worker         GLuint stride            = combined ? binding.getStride() : pixelBytes;
1273*8975f5c5SAndroid Build Coastguard Worker         VkDeviceSize startOffset = 0;
1274*8975f5c5SAndroid Build Coastguard Worker         if (divisor > 0)
1275*8975f5c5SAndroid Build Coastguard Worker         {
1276*8975f5c5SAndroid Build Coastguard Worker             // Instanced attrib
1277*8975f5c5SAndroid Build Coastguard Worker             if (divisor > renderer->getMaxVertexAttribDivisor())
1278*8975f5c5SAndroid Build Coastguard Worker             {
1279*8975f5c5SAndroid Build Coastguard Worker                 // Divisor will be set to 1 & so update buffer to have 1 attrib per instance
1280*8975f5c5SAndroid Build Coastguard Worker                 size_t bytesToAllocate = instanceCount * stride;
1281*8975f5c5SAndroid Build Coastguard Worker 
1282*8975f5c5SAndroid Build Coastguard Worker                 // Allocate buffer for results
1283*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(contextVk->allocateStreamedVertexBuffer(attribIndex, bytesToAllocate,
1284*8975f5c5SAndroid Build Coastguard Worker                                                                   &vertexDataBuffer));
1285*8975f5c5SAndroid Build Coastguard Worker 
1286*8975f5c5SAndroid Build Coastguard Worker                 gl::Buffer *bufferGL = binding.getBuffer().get();
1287*8975f5c5SAndroid Build Coastguard Worker                 if (bufferGL != nullptr)
1288*8975f5c5SAndroid Build Coastguard Worker                 {
1289*8975f5c5SAndroid Build Coastguard Worker                     // Only do the data copy if src buffer is valid.
1290*8975f5c5SAndroid Build Coastguard Worker                     if (bufferGL->getSize() > 0)
1291*8975f5c5SAndroid Build Coastguard Worker                     {
1292*8975f5c5SAndroid Build Coastguard Worker                         // Map buffer to expand attribs for divisor emulation
1293*8975f5c5SAndroid Build Coastguard Worker                         BufferVk *bufferVk = vk::GetImpl(binding.getBuffer().get());
1294*8975f5c5SAndroid Build Coastguard Worker                         void *buffSrc      = nullptr;
1295*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_TRY(bufferVk->mapImpl(contextVk, GL_MAP_READ_BIT, &buffSrc));
1296*8975f5c5SAndroid Build Coastguard Worker                         src = reinterpret_cast<const uint8_t *>(buffSrc) + binding.getOffset();
1297*8975f5c5SAndroid Build Coastguard Worker 
1298*8975f5c5SAndroid Build Coastguard Worker                         uint32_t srcAttributeSize =
1299*8975f5c5SAndroid Build Coastguard Worker                             static_cast<uint32_t>(ComputeVertexAttributeTypeSize(attrib));
1300*8975f5c5SAndroid Build Coastguard Worker 
1301*8975f5c5SAndroid Build Coastguard Worker                         size_t numVertices = GetVertexCount(bufferVk, binding, srcAttributeSize);
1302*8975f5c5SAndroid Build Coastguard Worker 
1303*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_TRY(StreamVertexDataWithDivisor(
1304*8975f5c5SAndroid Build Coastguard Worker                             contextVk, vertexDataBuffer, src, bytesToAllocate, binding.getStride(),
1305*8975f5c5SAndroid Build Coastguard Worker                             stride, vertexFormat.getVertexLoadFunction(compressed), divisor,
1306*8975f5c5SAndroid Build Coastguard Worker                             numVertices));
1307*8975f5c5SAndroid Build Coastguard Worker 
1308*8975f5c5SAndroid Build Coastguard Worker                         ANGLE_TRY(bufferVk->unmapImpl(contextVk));
1309*8975f5c5SAndroid Build Coastguard Worker                     }
1310*8975f5c5SAndroid Build Coastguard Worker                     else if (contextVk->getExtensions().robustnessAny())
1311*8975f5c5SAndroid Build Coastguard Worker                     {
1312*8975f5c5SAndroid Build Coastguard Worker                         // Satisfy robustness constraints (only if extension enabled)
1313*8975f5c5SAndroid Build Coastguard Worker                         uint8_t *dst = vertexDataBuffer->getMappedMemory();
1314*8975f5c5SAndroid Build Coastguard Worker                         memset(dst, 0, bytesToAllocate);
1315*8975f5c5SAndroid Build Coastguard Worker                     }
1316*8975f5c5SAndroid Build Coastguard Worker                 }
1317*8975f5c5SAndroid Build Coastguard Worker                 else
1318*8975f5c5SAndroid Build Coastguard Worker                 {
1319*8975f5c5SAndroid Build Coastguard Worker                     size_t numVertices = instanceCount;
1320*8975f5c5SAndroid Build Coastguard Worker                     ANGLE_TRY(StreamVertexDataWithDivisor(
1321*8975f5c5SAndroid Build Coastguard Worker                         contextVk, vertexDataBuffer, src, bytesToAllocate, binding.getStride(),
1322*8975f5c5SAndroid Build Coastguard Worker                         stride, vertexFormat.getVertexLoadFunction(compressed), divisor,
1323*8975f5c5SAndroid Build Coastguard Worker                         numVertices));
1324*8975f5c5SAndroid Build Coastguard Worker                 }
1325*8975f5c5SAndroid Build Coastguard Worker             }
1326*8975f5c5SAndroid Build Coastguard Worker             else
1327*8975f5c5SAndroid Build Coastguard Worker             {
1328*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(binding.getBuffer().get() == nullptr);
1329*8975f5c5SAndroid Build Coastguard Worker                 size_t count           = UnsignedCeilDivide(instanceCount, divisor);
1330*8975f5c5SAndroid Build Coastguard Worker                 size_t bytesToAllocate = count * stride;
1331*8975f5c5SAndroid Build Coastguard Worker 
1332*8975f5c5SAndroid Build Coastguard Worker                 // Allocate buffer for results
1333*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(contextVk->allocateStreamedVertexBuffer(attribIndex, bytesToAllocate,
1334*8975f5c5SAndroid Build Coastguard Worker                                                                   &vertexDataBuffer));
1335*8975f5c5SAndroid Build Coastguard Worker 
1336*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(StreamVertexData(contextVk, vertexDataBuffer, src, bytesToAllocate, 0,
1337*8975f5c5SAndroid Build Coastguard Worker                                            count, binding.getStride(),
1338*8975f5c5SAndroid Build Coastguard Worker                                            vertexFormat.getVertexLoadFunction(compressed)));
1339*8975f5c5SAndroid Build Coastguard Worker             }
1340*8975f5c5SAndroid Build Coastguard Worker         }
1341*8975f5c5SAndroid Build Coastguard Worker         else
1342*8975f5c5SAndroid Build Coastguard Worker         {
1343*8975f5c5SAndroid Build Coastguard Worker             ASSERT(binding.getBuffer().get() == nullptr);
1344*8975f5c5SAndroid Build Coastguard Worker             size_t mergedAttribIdx      = mergedIndexes[attribIndex];
1345*8975f5c5SAndroid Build Coastguard Worker             const AttributeRange &range = mergeRanges[attribIndex];
1346*8975f5c5SAndroid Build Coastguard Worker             if (attribBufferHelper[mergedAttribIdx] == nullptr)
1347*8975f5c5SAndroid Build Coastguard Worker             {
1348*8975f5c5SAndroid Build Coastguard Worker                 size_t destOffset =
1349*8975f5c5SAndroid Build Coastguard Worker                     combined ? range.copyStartAddr - range.startAddr : startVertex * stride;
1350*8975f5c5SAndroid Build Coastguard Worker                 size_t bytesToAllocate = range.endAddr - range.startAddr;
1351*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(contextVk->allocateStreamedVertexBuffer(
1352*8975f5c5SAndroid Build Coastguard Worker                     mergedAttribIdx, bytesToAllocate, &attribBufferHelper[mergedAttribIdx]));
1353*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(StreamVertexData(
1354*8975f5c5SAndroid Build Coastguard Worker                     contextVk, attribBufferHelper[mergedAttribIdx],
1355*8975f5c5SAndroid Build Coastguard Worker                     (const uint8_t *)range.copyStartAddr, bytesToAllocate - destOffset, destOffset,
1356*8975f5c5SAndroid Build Coastguard Worker                     vertexCount, binding.getStride(),
1357*8975f5c5SAndroid Build Coastguard Worker                     combined ? nullptr : vertexFormat.getVertexLoadFunction(compressed)));
1358*8975f5c5SAndroid Build Coastguard Worker             }
1359*8975f5c5SAndroid Build Coastguard Worker             vertexDataBuffer = attribBufferHelper[mergedAttribIdx];
1360*8975f5c5SAndroid Build Coastguard Worker             startOffset      = combined ? (uintptr_t)attrib.pointer - range.startAddr : 0;
1361*8975f5c5SAndroid Build Coastguard Worker         }
1362*8975f5c5SAndroid Build Coastguard Worker         ASSERT(vertexDataBuffer != nullptr);
1363*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBuffers[attribIndex]      = vertexDataBuffer;
1364*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferSerial[attribIndex] = vertexDataBuffer->getBufferSerial();
1365*8975f5c5SAndroid Build Coastguard Worker         VkDeviceSize bufferOffset;
1366*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferHandles[attribIndex] =
1367*8975f5c5SAndroid Build Coastguard Worker             vertexDataBuffer
1368*8975f5c5SAndroid Build Coastguard Worker                 ->getBufferForVertexArray(contextVk, vertexDataBuffer->getSize(), &bufferOffset)
1369*8975f5c5SAndroid Build Coastguard Worker                 .getHandle();
1370*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferOffsets[attribIndex]  = bufferOffset + startOffset;
1371*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferStrides[attribIndex]  = stride;
1372*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferDivisors[attribIndex] = divisor;
1373*8975f5c5SAndroid Build Coastguard Worker         ASSERT(BindingIsAligned(dstFormat, mCurrentArrayBufferOffsets[attribIndex],
1374*8975f5c5SAndroid Build Coastguard Worker                                 mCurrentArrayBufferStrides[attribIndex]));
1375*8975f5c5SAndroid Build Coastguard Worker     }
1376*8975f5c5SAndroid Build Coastguard Worker 
1377*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1378*8975f5c5SAndroid Build Coastguard Worker }
1379*8975f5c5SAndroid Build Coastguard Worker 
handleLineLoop(ContextVk * contextVk,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,vk::BufferHelper ** indexBufferOut,uint32_t * indexCountOut)1380*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
1381*8975f5c5SAndroid Build Coastguard Worker                                             GLint firstVertex,
1382*8975f5c5SAndroid Build Coastguard Worker                                             GLsizei vertexOrIndexCount,
1383*8975f5c5SAndroid Build Coastguard Worker                                             gl::DrawElementsType indexTypeOrInvalid,
1384*8975f5c5SAndroid Build Coastguard Worker                                             const void *indices,
1385*8975f5c5SAndroid Build Coastguard Worker                                             vk::BufferHelper **indexBufferOut,
1386*8975f5c5SAndroid Build Coastguard Worker                                             uint32_t *indexCountOut)
1387*8975f5c5SAndroid Build Coastguard Worker {
1388*8975f5c5SAndroid Build Coastguard Worker     if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
1389*8975f5c5SAndroid Build Coastguard Worker     {
1390*8975f5c5SAndroid Build Coastguard Worker         // Handle GL_LINE_LOOP drawElements.
1391*8975f5c5SAndroid Build Coastguard Worker         if (mDirtyLineLoopTranslation)
1392*8975f5c5SAndroid Build Coastguard Worker         {
1393*8975f5c5SAndroid Build Coastguard Worker             gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
1394*8975f5c5SAndroid Build Coastguard Worker 
1395*8975f5c5SAndroid Build Coastguard Worker             if (!elementArrayBuffer)
1396*8975f5c5SAndroid Build Coastguard Worker             {
1397*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(mLineLoopHelper.streamIndices(
1398*8975f5c5SAndroid Build Coastguard Worker                     contextVk, indexTypeOrInvalid, vertexOrIndexCount,
1399*8975f5c5SAndroid Build Coastguard Worker                     reinterpret_cast<const uint8_t *>(indices), indexBufferOut, indexCountOut));
1400*8975f5c5SAndroid Build Coastguard Worker             }
1401*8975f5c5SAndroid Build Coastguard Worker             else
1402*8975f5c5SAndroid Build Coastguard Worker             {
1403*8975f5c5SAndroid Build Coastguard Worker                 // When using an element array buffer, 'indices' is an offset to the first element.
1404*8975f5c5SAndroid Build Coastguard Worker                 intptr_t offset                = reinterpret_cast<intptr_t>(indices);
1405*8975f5c5SAndroid Build Coastguard Worker                 BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
1406*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(mLineLoopHelper.getIndexBufferForElementArrayBuffer(
1407*8975f5c5SAndroid Build Coastguard Worker                     contextVk, elementArrayBufferVk, indexTypeOrInvalid, vertexOrIndexCount, offset,
1408*8975f5c5SAndroid Build Coastguard Worker                     indexBufferOut, indexCountOut));
1409*8975f5c5SAndroid Build Coastguard Worker             }
1410*8975f5c5SAndroid Build Coastguard Worker         }
1411*8975f5c5SAndroid Build Coastguard Worker 
1412*8975f5c5SAndroid Build Coastguard Worker         // If we've had a drawArrays call with a line loop before, we want to make sure this is
1413*8975f5c5SAndroid Build Coastguard Worker         // invalidated the next time drawArrays is called since we use the same index buffer for
1414*8975f5c5SAndroid Build Coastguard Worker         // both calls.
1415*8975f5c5SAndroid Build Coastguard Worker         mLineLoopBufferFirstIndex.reset();
1416*8975f5c5SAndroid Build Coastguard Worker         mLineLoopBufferLastIndex.reset();
1417*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1418*8975f5c5SAndroid Build Coastguard Worker     }
1419*8975f5c5SAndroid Build Coastguard Worker 
1420*8975f5c5SAndroid Build Coastguard Worker     // Note: Vertex indexes can be arbitrarily large.
1421*8975f5c5SAndroid Build Coastguard Worker     uint32_t clampedVertexCount = gl::clampCast<uint32_t>(vertexOrIndexCount);
1422*8975f5c5SAndroid Build Coastguard Worker 
1423*8975f5c5SAndroid Build Coastguard Worker     // Handle GL_LINE_LOOP drawArrays.
1424*8975f5c5SAndroid Build Coastguard Worker     size_t lastVertex = static_cast<size_t>(firstVertex + clampedVertexCount);
1425*8975f5c5SAndroid Build Coastguard Worker     if (!mLineLoopBufferFirstIndex.valid() || !mLineLoopBufferLastIndex.valid() ||
1426*8975f5c5SAndroid Build Coastguard Worker         mLineLoopBufferFirstIndex != firstVertex || mLineLoopBufferLastIndex != lastVertex)
1427*8975f5c5SAndroid Build Coastguard Worker     {
1428*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mLineLoopHelper.getIndexBufferForDrawArrays(contextVk, clampedVertexCount,
1429*8975f5c5SAndroid Build Coastguard Worker                                                               firstVertex, indexBufferOut));
1430*8975f5c5SAndroid Build Coastguard Worker 
1431*8975f5c5SAndroid Build Coastguard Worker         mLineLoopBufferFirstIndex = firstVertex;
1432*8975f5c5SAndroid Build Coastguard Worker         mLineLoopBufferLastIndex  = lastVertex;
1433*8975f5c5SAndroid Build Coastguard Worker     }
1434*8975f5c5SAndroid Build Coastguard Worker     else
1435*8975f5c5SAndroid Build Coastguard Worker     {
1436*8975f5c5SAndroid Build Coastguard Worker         *indexBufferOut = mLineLoopHelper.getCurrentIndexBuffer();
1437*8975f5c5SAndroid Build Coastguard Worker     }
1438*8975f5c5SAndroid Build Coastguard Worker     *indexCountOut = vertexOrIndexCount + 1;
1439*8975f5c5SAndroid Build Coastguard Worker 
1440*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1441*8975f5c5SAndroid Build Coastguard Worker }
1442*8975f5c5SAndroid Build Coastguard Worker 
updateDefaultAttrib(ContextVk * contextVk,size_t attribIndex)1443*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk, size_t attribIndex)
1444*8975f5c5SAndroid Build Coastguard Worker {
1445*8975f5c5SAndroid Build Coastguard Worker     if (!mState.getEnabledAttributesMask().test(attribIndex))
1446*8975f5c5SAndroid Build Coastguard Worker     {
1447*8975f5c5SAndroid Build Coastguard Worker         vk::BufferHelper *bufferHelper;
1448*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(
1449*8975f5c5SAndroid Build Coastguard Worker             contextVk->allocateStreamedVertexBuffer(attribIndex, kDefaultValueSize, &bufferHelper));
1450*8975f5c5SAndroid Build Coastguard Worker 
1451*8975f5c5SAndroid Build Coastguard Worker         const gl::VertexAttribCurrentValueData &defaultValue =
1452*8975f5c5SAndroid Build Coastguard Worker             contextVk->getState().getVertexAttribCurrentValues()[attribIndex];
1453*8975f5c5SAndroid Build Coastguard Worker         uint8_t *ptr = bufferHelper->getMappedMemory();
1454*8975f5c5SAndroid Build Coastguard Worker         memcpy(ptr, &defaultValue.Values, kDefaultValueSize);
1455*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(bufferHelper->flush(contextVk->getRenderer()));
1456*8975f5c5SAndroid Build Coastguard Worker 
1457*8975f5c5SAndroid Build Coastguard Worker         VkDeviceSize bufferOffset;
1458*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferHandles[attribIndex] =
1459*8975f5c5SAndroid Build Coastguard Worker             bufferHelper->getBufferForVertexArray(contextVk, kDefaultValueSize, &bufferOffset)
1460*8975f5c5SAndroid Build Coastguard Worker                 .getHandle();
1461*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferOffsets[attribIndex]  = bufferOffset;
1462*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBuffers[attribIndex]        = bufferHelper;
1463*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferSerial[attribIndex]   = bufferHelper->getBufferSerial();
1464*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferStrides[attribIndex]  = 0;
1465*8975f5c5SAndroid Build Coastguard Worker         mCurrentArrayBufferDivisors[attribIndex] = 0;
1466*8975f5c5SAndroid Build Coastguard Worker 
1467*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(setDefaultPackedInput(contextVk, attribIndex,
1468*8975f5c5SAndroid Build Coastguard Worker                                         &mCurrentArrayBufferFormats[attribIndex]));
1469*8975f5c5SAndroid Build Coastguard Worker     }
1470*8975f5c5SAndroid Build Coastguard Worker 
1471*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1472*8975f5c5SAndroid Build Coastguard Worker }
1473*8975f5c5SAndroid Build Coastguard Worker }  // namespace rx
1474