• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // VertexArrayVk.cpp:
7 //    Implements the class methods for VertexArrayVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/VertexArrayVk.h"
11 
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/renderer/vulkan/BufferVk.h"
16 #include "libANGLE/renderer/vulkan/CommandGraph.h"
17 #include "libANGLE/renderer/vulkan/ContextVk.h"
18 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
19 #include "libANGLE/renderer/vulkan/RendererVk.h"
20 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
21 #include "libANGLE/trace.h"
22 
23 namespace rx
24 {
25 namespace
26 {
27 constexpr size_t kDynamicVertexDataSize = 1024 * 1024;
28 constexpr size_t kDynamicIndexDataSize  = 1024 * 8;
29 
BindingIsAligned(const gl::VertexBinding & binding,const angle::Format & angleFormat,unsigned int attribSize,GLuint relativeOffset)30 ANGLE_INLINE bool BindingIsAligned(const gl::VertexBinding &binding,
31                                    const angle::Format &angleFormat,
32                                    unsigned int attribSize,
33                                    GLuint relativeOffset)
34 {
35     GLintptr totalOffset = binding.getOffset() + relativeOffset;
36     GLuint mask          = angleFormat.componentAlignmentMask;
37     if (mask != std::numeric_limits<GLuint>::max())
38     {
39         return ((totalOffset & mask) == 0 && (binding.getStride() & mask) == 0);
40     }
41     else
42     {
43         // To perform the GPU conversion for formats with components that aren't byte-aligned
44         // (for example, A2BGR10 or RGB10A2), one element has to be placed in 4 bytes to perform
45         // the compute shader. So, binding offset and stride has to be aligned to formatSize.
46         unsigned int formatSize = angleFormat.pixelBytes;
47         return (totalOffset % formatSize == 0) && (binding.getStride() % formatSize == 0);
48     }
49 }
50 
StreamVertexData(ContextVk * contextVk,vk::DynamicBuffer * dynamicBuffer,const uint8_t * sourceData,size_t bytesToAllocate,size_t destOffset,size_t vertexCount,size_t stride,VertexCopyFunction vertexLoadFunction,vk::BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut)51 angle::Result StreamVertexData(ContextVk *contextVk,
52                                vk::DynamicBuffer *dynamicBuffer,
53                                const uint8_t *sourceData,
54                                size_t bytesToAllocate,
55                                size_t destOffset,
56                                size_t vertexCount,
57                                size_t stride,
58                                VertexCopyFunction vertexLoadFunction,
59                                vk::BufferHelper **bufferOut,
60                                VkDeviceSize *bufferOffsetOut)
61 {
62     uint8_t *dst = nullptr;
63     ANGLE_TRY(dynamicBuffer->allocate(contextVk, bytesToAllocate, &dst, nullptr, bufferOffsetOut,
64                                       nullptr));
65     *bufferOut = dynamicBuffer->getCurrentBuffer();
66     dst += destOffset;
67     vertexLoadFunction(sourceData, stride, vertexCount, dst);
68 
69     ANGLE_TRY(dynamicBuffer->flush(contextVk));
70     return angle::Result::Continue;
71 }
72 
GetVertexCount(BufferVk * srcBuffer,const gl::VertexBinding & binding,uint32_t srcFormatSize)73 size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uint32_t srcFormatSize)
74 {
75     // Bytes usable for vertex data.
76     GLint64 bytes = srcBuffer->getSize() - binding.getOffset();
77     if (bytes < srcFormatSize)
78         return 0;
79 
80     // Count the last vertex.  It may occupy less than a full stride.
81     size_t numVertices = 1;
82     bytes -= srcFormatSize;
83 
84     // Count how many strides fit remaining space.
85     if (bytes > 0)
86         numVertices += static_cast<size_t>(bytes) / binding.getStride();
87 
88     return numVertices;
89 }
90 }  // anonymous namespace
91 
VertexArrayVk(ContextVk * contextVk,const gl::VertexArrayState & state)92 VertexArrayVk::VertexArrayVk(ContextVk *contextVk, const gl::VertexArrayState &state)
93     : VertexArrayImpl(state),
94       mCurrentArrayBufferHandles{},
95       mCurrentArrayBufferOffsets{},
96       mCurrentArrayBuffers{},
97       mCurrentElementArrayBufferOffset(0),
98       mCurrentElementArrayBuffer(nullptr),
99       mLineLoopHelper(contextVk->getRenderer()),
100       mDirtyLineLoopTranslation(true)
101 {
102     RendererVk *renderer = contextVk->getRenderer();
103 
104     VkBufferCreateInfo createInfo = {};
105     createInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
106     createInfo.size               = 16;
107     createInfo.usage              = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
108     (void)mTheNullBuffer.init(contextVk, createInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
109 
110     mCurrentArrayBufferHandles.fill(mTheNullBuffer.getBuffer().getHandle());
111     mCurrentArrayBufferOffsets.fill(0);
112     mCurrentArrayBuffers.fill(&mTheNullBuffer);
113 
114     mDynamicVertexData.init(renderer, vk::kVertexBufferUsageFlags, vk::kVertexBufferAlignment,
115                             kDynamicVertexDataSize, true);
116 
117     // We use an alignment of four for index data. This ensures that compute shaders can read index
118     // elements from "uint" aligned addresses.
119     mDynamicIndexData.init(renderer, vk::kIndexBufferUsageFlags, vk::kIndexBufferAlignment,
120                            kDynamicIndexDataSize, true);
121     mTranslatedByteIndexData.init(renderer, vk::kIndexBufferUsageFlags, vk::kIndexBufferAlignment,
122                                   kDynamicIndexDataSize, true);
123 }
124 
~VertexArrayVk()125 VertexArrayVk::~VertexArrayVk() {}
126 
destroy(const gl::Context * context)127 void VertexArrayVk::destroy(const gl::Context *context)
128 {
129     ContextVk *contextVk = vk::GetImpl(context);
130 
131     mTheNullBuffer.release(contextVk);
132 
133     mDynamicVertexData.release(contextVk);
134     mDynamicIndexData.release(contextVk);
135     mTranslatedByteIndexData.release(contextVk);
136     mLineLoopHelper.release(contextVk);
137 }
138 
convertIndexBufferGPU(ContextVk * contextVk,BufferVk * bufferVk,const void * indices)139 angle::Result VertexArrayVk::convertIndexBufferGPU(ContextVk *contextVk,
140                                                    BufferVk *bufferVk,
141                                                    const void *indices)
142 {
143     intptr_t offsetIntoSrcData = reinterpret_cast<intptr_t>(indices);
144     size_t srcDataSize         = static_cast<size_t>(bufferVk->getSize()) - offsetIntoSrcData;
145 
146     mTranslatedByteIndexData.releaseInFlightBuffers(contextVk);
147 
148     ANGLE_TRY(mTranslatedByteIndexData.allocate(contextVk, sizeof(GLushort) * srcDataSize, nullptr,
149                                                 nullptr, &mCurrentElementArrayBufferOffset,
150                                                 nullptr));
151     mCurrentElementArrayBuffer = mTranslatedByteIndexData.getCurrentBuffer();
152 
153     vk::BufferHelper *dest = mTranslatedByteIndexData.getCurrentBuffer();
154     vk::BufferHelper *src  = &bufferVk->getBuffer();
155 
156     // Copy relevant section of the source into destination at allocated offset.  Note that the
157     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
158     UtilsVk::ConvertIndexParameters params = {};
159     params.srcOffset                       = static_cast<uint32_t>(offsetIntoSrcData);
160     params.dstOffset = static_cast<uint32_t>(mCurrentElementArrayBufferOffset);
161     params.maxIndex  = static_cast<uint32_t>(bufferVk->getSize());
162 
163     return contextVk->getUtils().convertIndexBuffer(contextVk, dest, src, params);
164 }
165 
convertIndexBufferCPU(ContextVk * contextVk,gl::DrawElementsType indexType,size_t indexCount,const void * sourcePointer)166 angle::Result VertexArrayVk::convertIndexBufferCPU(ContextVk *contextVk,
167                                                    gl::DrawElementsType indexType,
168                                                    size_t indexCount,
169                                                    const void *sourcePointer)
170 {
171     ASSERT(!mState.getElementArrayBuffer() || indexType == gl::DrawElementsType::UnsignedByte);
172 
173     mDynamicIndexData.releaseInFlightBuffers(contextVk);
174 
175     size_t elementSize = gl::GetDrawElementsTypeSize(indexType);
176     if (indexType == gl::DrawElementsType::UnsignedByte)
177     {
178         // 8-bit indices are not supported by Vulkan, so they are promoted to
179         // 16-bit indices below
180         elementSize = sizeof(GLushort);
181     }
182 
183     const size_t amount = elementSize * indexCount;
184     GLubyte *dst        = nullptr;
185 
186     ANGLE_TRY(mDynamicIndexData.allocate(contextVk, amount, &dst, nullptr,
187                                          &mCurrentElementArrayBufferOffset, nullptr));
188     mCurrentElementArrayBuffer = mDynamicIndexData.getCurrentBuffer();
189     if (indexType == gl::DrawElementsType::UnsignedByte)
190     {
191         // Unsigned bytes don't have direct support in Vulkan so we have to expand the
192         // memory to a GLushort.
193         const GLubyte *in     = static_cast<const GLubyte *>(sourcePointer);
194         GLushort *expandedDst = reinterpret_cast<GLushort *>(dst);
195         bool primitiveRestart = contextVk->getState().isPrimitiveRestartEnabled();
196 
197         constexpr GLubyte kUnsignedByteRestartValue   = 0xFF;
198         constexpr GLushort kUnsignedShortRestartValue = 0xFFFF;
199 
200         if (primitiveRestart)
201         {
202             for (size_t index = 0; index < indexCount; index++)
203             {
204                 GLushort value = static_cast<GLushort>(in[index]);
205                 if (in[index] == kUnsignedByteRestartValue)
206                 {
207                     // Convert from 8-bit restart value to 16-bit restart value
208                     value = kUnsignedShortRestartValue;
209                 }
210                 expandedDst[index] = value;
211             }
212         }
213         else
214         {
215             // Fast path for common case.
216             for (size_t index = 0; index < indexCount; index++)
217             {
218                 expandedDst[index] = static_cast<GLushort>(in[index]);
219             }
220         }
221     }
222     else
223     {
224         // The primitive restart value is the same for OpenGL and Vulkan,
225         // so there's no need to perform any conversion.
226         memcpy(dst, sourcePointer, amount);
227     }
228     return mDynamicIndexData.flush(contextVk);
229 }
230 
231 // We assume the buffer is completely full of the same kind of data and convert
232 // and/or align it as we copy it to a DynamicBuffer. The assumption could be wrong
233 // but the alternative of copying it piecemeal on each draw would have a lot more
234 // overhead.
convertVertexBufferGPU(ContextVk * contextVk,BufferVk * srcBuffer,const gl::VertexBinding & binding,size_t attribIndex,const vk::Format & vertexFormat,ConversionBuffer * conversion,GLuint relativeOffset)235 angle::Result VertexArrayVk::convertVertexBufferGPU(ContextVk *contextVk,
236                                                     BufferVk *srcBuffer,
237                                                     const gl::VertexBinding &binding,
238                                                     size_t attribIndex,
239                                                     const vk::Format &vertexFormat,
240                                                     ConversionBuffer *conversion,
241                                                     GLuint relativeOffset)
242 {
243     const angle::Format &srcFormat  = vertexFormat.angleFormat();
244     const angle::Format &destFormat = vertexFormat.bufferFormat();
245 
246     ASSERT(binding.getStride() % (srcFormat.pixelBytes / srcFormat.channelCount) == 0);
247 
248     unsigned srcFormatSize  = srcFormat.pixelBytes;
249     unsigned destFormatSize = destFormat.pixelBytes;
250 
251     size_t numVertices = GetVertexCount(srcBuffer, binding, srcFormatSize);
252     if (numVertices == 0)
253     {
254         return angle::Result::Continue;
255     }
256 
257     ASSERT(GetVertexInputAlignment(vertexFormat) <= vk::kVertexBufferAlignment);
258 
259     // Allocate buffer for results
260     conversion->data.releaseInFlightBuffers(contextVk);
261     ANGLE_TRY(conversion->data.allocate(contextVk, numVertices * destFormatSize, nullptr, nullptr,
262                                         &conversion->lastAllocationOffset, nullptr));
263 
264     ASSERT(conversion->dirty);
265     conversion->dirty = false;
266 
267     UtilsVk::ConvertVertexParameters params;
268     params.vertexCount = numVertices;
269     params.srcFormat   = &srcFormat;
270     params.destFormat  = &destFormat;
271     params.srcStride   = binding.getStride();
272     params.srcOffset   = binding.getOffset() + relativeOffset;
273     params.destOffset  = static_cast<size_t>(conversion->lastAllocationOffset);
274 
275     ANGLE_TRY(contextVk->getUtils().convertVertexBuffer(
276         contextVk, conversion->data.getCurrentBuffer(), &srcBuffer->getBuffer(), params));
277 
278     return angle::Result::Continue;
279 }
280 
convertVertexBufferCPU(ContextVk * contextVk,BufferVk * srcBuffer,const gl::VertexBinding & binding,size_t attribIndex,const vk::Format & vertexFormat,ConversionBuffer * conversion,GLuint relativeOffset)281 angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
282                                                     BufferVk *srcBuffer,
283                                                     const gl::VertexBinding &binding,
284                                                     size_t attribIndex,
285                                                     const vk::Format &vertexFormat,
286                                                     ConversionBuffer *conversion,
287                                                     GLuint relativeOffset)
288 {
289     ANGLE_TRACE_EVENT0("gpu.angle", "VertexArrayVk::convertVertexBufferCpu");
290 
291     unsigned srcFormatSize = vertexFormat.angleFormat().pixelBytes;
292     unsigned dstFormatSize = vertexFormat.bufferFormat().pixelBytes;
293 
294     conversion->data.releaseInFlightBuffers(contextVk);
295 
296     size_t numVertices = GetVertexCount(srcBuffer, binding, srcFormatSize);
297     if (numVertices == 0)
298     {
299         return angle::Result::Continue;
300     }
301 
302     void *src = nullptr;
303     ANGLE_TRY(srcBuffer->mapImpl(contextVk, &src));
304     const uint8_t *srcBytes = reinterpret_cast<const uint8_t *>(src);
305     srcBytes += binding.getOffset() + relativeOffset;
306     ASSERT(GetVertexInputAlignment(vertexFormat) <= vk::kVertexBufferAlignment);
307     ANGLE_TRY(StreamVertexData(contextVk, &conversion->data, srcBytes, numVertices * dstFormatSize,
308                                0, numVertices, binding.getStride(), vertexFormat.vertexLoadFunction,
309                                &mCurrentArrayBuffers[attribIndex],
310                                &conversion->lastAllocationOffset));
311     srcBuffer->unmapImpl(contextVk);
312 
313     ASSERT(conversion->dirty);
314     conversion->dirty = false;
315 
316     return angle::Result::Continue;
317 }
318 
syncState(const gl::Context * context,const gl::VertexArray::DirtyBits & dirtyBits,gl::VertexArray::DirtyAttribBitsArray * attribBits,gl::VertexArray::DirtyBindingBitsArray * bindingBits)319 angle::Result VertexArrayVk::syncState(const gl::Context *context,
320                                        const gl::VertexArray::DirtyBits &dirtyBits,
321                                        gl::VertexArray::DirtyAttribBitsArray *attribBits,
322                                        gl::VertexArray::DirtyBindingBitsArray *bindingBits)
323 {
324     ASSERT(dirtyBits.any());
325 
326     ContextVk *contextVk = vk::GetImpl(context);
327 
328     const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
329     const std::vector<gl::VertexBinding> &bindings  = mState.getVertexBindings();
330 
331     for (size_t dirtyBit : dirtyBits)
332     {
333         switch (dirtyBit)
334         {
335             case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
336             {
337                 gl::Buffer *bufferGL = mState.getElementArrayBuffer();
338                 if (bufferGL)
339                 {
340                     BufferVk *bufferVk         = vk::GetImpl(bufferGL);
341                     mCurrentElementArrayBuffer = &bufferVk->getBuffer();
342                 }
343                 else
344                 {
345                     mCurrentElementArrayBuffer = nullptr;
346                 }
347 
348                 mLineLoopBufferFirstIndex.reset();
349                 mLineLoopBufferLastIndex.reset();
350                 contextVk->setIndexBufferDirty();
351                 mDirtyLineLoopTranslation = true;
352                 break;
353             }
354 
355             case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
356                 mLineLoopBufferFirstIndex.reset();
357                 mLineLoopBufferLastIndex.reset();
358                 contextVk->setIndexBufferDirty();
359                 mDirtyLineLoopTranslation = true;
360                 break;
361 
362 #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX)                                         \
363     case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX:                                 \
364         if ((*attribBits)[INDEX].to_ulong() ==                                        \
365             angle::Bit<unsigned long>(gl::VertexArray::DIRTY_ATTRIB_POINTER_BUFFER))  \
366         {                                                                             \
367             syncDirtyBuffer(contextVk, bindings[INDEX], INDEX);                       \
368         }                                                                             \
369         else                                                                          \
370         {                                                                             \
371             ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX],                      \
372                                       bindings[attribs[INDEX].bindingIndex], INDEX)); \
373         }                                                                             \
374         (*attribBits)[INDEX].reset();                                                 \
375         break;
376 
377                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
378 
379 #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX)                                                   \
380     case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX:                                           \
381         for (size_t attribIndex : bindings[INDEX].getBoundAttributesMask())                      \
382         {                                                                                        \
383             ANGLE_TRY(                                                                           \
384                 syncDirtyAttrib(contextVk, attribs[attribIndex], bindings[INDEX], attribIndex)); \
385         }                                                                                        \
386         (*bindingBits)[INDEX].reset();                                                           \
387         break;
388 
389                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
390 
391 #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX)                                \
392     case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX:                        \
393         ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX],                      \
394                                   bindings[attribs[INDEX].bindingIndex], INDEX)); \
395         break;
396 
397                 ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)
398 
399             default:
400                 UNREACHABLE();
401                 break;
402         }
403     }
404 
405     return angle::Result::Continue;
406 }
407 
408 #undef ANGLE_VERTEX_DIRTY_ATTRIB_FUNC
409 #undef ANGLE_VERTEX_DIRTY_BINDING_FUNC
410 #undef ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC
411 
setDefaultPackedInput(ContextVk * contextVk,size_t attribIndex)412 ANGLE_INLINE void VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex)
413 {
414     const gl::State &glState = contextVk->getState();
415     const gl::VertexAttribCurrentValueData &defaultValue =
416         glState.getVertexAttribCurrentValues()[attribIndex];
417 
418     angle::FormatID format = GetCurrentValueFormatID(defaultValue.Type);
419 
420     contextVk->onVertexAttributeChange(attribIndex, 0, 0, format, 0);
421 }
422 
syncDirtyAttrib(ContextVk * contextVk,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t attribIndex)423 angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
424                                              const gl::VertexAttribute &attrib,
425                                              const gl::VertexBinding &binding,
426                                              size_t attribIndex)
427 {
428     RendererVk *renderer               = contextVk->getRenderer();
429     bool anyVertexBufferConvertedOnGpu = false;
430 
431     if (attrib.enabled)
432     {
433         gl::Buffer *bufferGL           = binding.getBuffer().get();
434         const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
435         GLuint stride;
436 
437         if (bufferGL)
438         {
439             BufferVk *bufferVk               = vk::GetImpl(bufferGL);
440             const angle::Format &angleFormat = vertexFormat.angleFormat();
441             bool bindingIsAligned = BindingIsAligned(binding, angleFormat, angleFormat.channelCount,
442                                                      attrib.relativeOffset);
443 
444             if (vertexFormat.vertexLoadRequiresConversion || !bindingIsAligned)
445             {
446                 stride = vertexFormat.bufferFormat().pixelBytes;
447 
448                 ConversionBuffer *conversion = bufferVk->getVertexConversionBuffer(
449                     renderer, angleFormat.id, binding.getStride(),
450                     binding.getOffset() + attrib.relativeOffset);
451                 if (conversion->dirty)
452                 {
453                     if (bindingIsAligned)
454                     {
455                         ANGLE_TRY(convertVertexBufferGPU(contextVk, bufferVk, binding, attribIndex,
456                                                          vertexFormat, conversion,
457                                                          attrib.relativeOffset));
458                         anyVertexBufferConvertedOnGpu = true;
459                     }
460                     else
461                     {
462                         ANGLE_TRY(convertVertexBufferCPU(contextVk, bufferVk, binding, attribIndex,
463                                                          vertexFormat, conversion,
464                                                          attrib.relativeOffset));
465                     }
466                 }
467 
468                 mCurrentArrayBuffers[attribIndex] = conversion->data.getCurrentBuffer();
469                 mCurrentArrayBufferHandles[attribIndex] =
470                     mCurrentArrayBuffers[attribIndex]->getBuffer().getHandle();
471                 mCurrentArrayBufferOffsets[attribIndex] =
472                     conversion->lastAllocationOffset - attrib.relativeOffset;
473             }
474             else
475             {
476                 if (bufferVk->getSize() == 0)
477                 {
478                     mCurrentArrayBuffers[attribIndex] = &mTheNullBuffer;
479                     mCurrentArrayBufferHandles[attribIndex] =
480                         mTheNullBuffer.getBuffer().getHandle();
481                     mCurrentArrayBufferOffsets[attribIndex] = 0;
482                     stride                                  = 0;
483                 }
484                 else
485                 {
486                     vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
487 
488                     mCurrentArrayBuffers[attribIndex]       = &bufferHelper;
489                     mCurrentArrayBufferHandles[attribIndex] = bufferHelper.getBuffer().getHandle();
490                     mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset();
491                     stride                                  = binding.getStride();
492                 }
493             }
494         }
495         else
496         {
497             mCurrentArrayBuffers[attribIndex]       = &mTheNullBuffer;
498             mCurrentArrayBufferHandles[attribIndex] = mTheNullBuffer.getBuffer().getHandle();
499             mCurrentArrayBufferOffsets[attribIndex] = 0;
500             stride                                  = vertexFormat.bufferFormat().pixelBytes;
501         }
502 
503         contextVk->onVertexAttributeChange(attribIndex, stride, binding.getDivisor(),
504                                            attrib.format->id, attrib.relativeOffset);
505     }
506     else
507     {
508         contextVk->invalidateDefaultAttribute(attribIndex);
509 
510         // These will be filled out by the ContextVk.
511         mCurrentArrayBuffers[attribIndex]       = &mTheNullBuffer;
512         mCurrentArrayBufferHandles[attribIndex] = mTheNullBuffer.getBuffer().getHandle();
513         mCurrentArrayBufferOffsets[attribIndex] = 0;
514 
515         setDefaultPackedInput(contextVk, attribIndex);
516     }
517 
518     if (anyVertexBufferConvertedOnGpu && renderer->getFeatures().flushAfterVertexConversion.enabled)
519     {
520         ANGLE_TRY(contextVk->flushImpl(nullptr));
521     }
522 
523     return angle::Result::Continue;
524 }
525 
syncDirtyBuffer(ContextVk * contextVk,const gl::VertexBinding & binding,size_t bindingIndex)526 void VertexArrayVk::syncDirtyBuffer(ContextVk *contextVk,
527                                     const gl::VertexBinding &binding,
528                                     size_t bindingIndex)
529 {
530     gl::Buffer *bufferGL = binding.getBuffer().get();
531 
532     if (bufferGL)
533     {
534         BufferVk *bufferVk                       = vk::GetImpl(bufferGL);
535         vk::BufferHelper &bufferHelper           = bufferVk->getBuffer();
536         mCurrentArrayBuffers[bindingIndex]       = &bufferHelper;
537         mCurrentArrayBufferHandles[bindingIndex] = bufferHelper.getBuffer().getHandle();
538         mCurrentArrayBufferOffsets[bindingIndex] = binding.getOffset();
539     }
540     else
541     {
542         mCurrentArrayBuffers[bindingIndex]       = &mTheNullBuffer;
543         mCurrentArrayBufferHandles[bindingIndex] = mTheNullBuffer.getBuffer().getHandle();
544         mCurrentArrayBufferOffsets[bindingIndex] = 0;
545     }
546 
547     contextVk->invalidateVertexBuffers();
548 }
549 
updateClientAttribs(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,GLsizei instanceCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices)550 angle::Result VertexArrayVk::updateClientAttribs(const gl::Context *context,
551                                                  GLint firstVertex,
552                                                  GLsizei vertexOrIndexCount,
553                                                  GLsizei instanceCount,
554                                                  gl::DrawElementsType indexTypeOrInvalid,
555                                                  const void *indices)
556 {
557     ContextVk *contextVk                    = vk::GetImpl(context);
558     const gl::AttributesMask &clientAttribs = context->getStateCache().getActiveClientAttribsMask();
559 
560     ASSERT(clientAttribs.any());
561 
562     GLint startVertex;
563     size_t vertexCount;
564     ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid,
565                                  indices, 0, &startVertex, &vertexCount));
566 
567     RendererVk *renderer = contextVk->getRenderer();
568     mDynamicVertexData.releaseInFlightBuffers(contextVk);
569 
570     const auto &attribs  = mState.getVertexAttributes();
571     const auto &bindings = mState.getVertexBindings();
572 
573     // TODO(fjhenigman): When we have a bunch of interleaved attributes, they end up
574     // un-interleaved, wasting space and copying time.  Consider improving on that.
575     for (size_t attribIndex : clientAttribs)
576     {
577         const gl::VertexAttribute &attrib = attribs[attribIndex];
578         const gl::VertexBinding &binding  = bindings[attrib.bindingIndex];
579         ASSERT(attrib.enabled && binding.getBuffer().get() == nullptr);
580 
581         const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
582         GLuint stride                  = vertexFormat.bufferFormat().pixelBytes;
583 
584         ASSERT(GetVertexInputAlignment(vertexFormat) <= vk::kVertexBufferAlignment);
585 
586         const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer);
587         if (binding.getDivisor() > 0)
588         {
589             // instanced attrib
590             size_t count           = UnsignedCeilDivide(instanceCount, binding.getDivisor());
591             size_t bytesToAllocate = count * stride;
592 
593             ANGLE_TRY(StreamVertexData(contextVk, &mDynamicVertexData, src, bytesToAllocate, 0,
594                                        count, binding.getStride(), vertexFormat.vertexLoadFunction,
595                                        &mCurrentArrayBuffers[attribIndex],
596                                        &mCurrentArrayBufferOffsets[attribIndex]));
597         }
598         else
599         {
600             // Allocate space for startVertex + vertexCount so indexing will work.  If we don't
601             // start at zero all the indices will be off.
602             // Only vertexCount vertices will be used by the upcoming draw so that is all we copy.
603             size_t bytesToAllocate = (startVertex + vertexCount) * stride;
604             src += startVertex * binding.getStride();
605             size_t destOffset = startVertex * stride;
606 
607             ANGLE_TRY(StreamVertexData(
608                 contextVk, &mDynamicVertexData, src, bytesToAllocate, destOffset, vertexCount,
609                 binding.getStride(), vertexFormat.vertexLoadFunction,
610                 &mCurrentArrayBuffers[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
611         }
612 
613         mCurrentArrayBufferHandles[attribIndex] =
614             mCurrentArrayBuffers[attribIndex]->getBuffer().getHandle();
615     }
616 
617     return angle::Result::Continue;
618 }
619 
handleLineLoop(ContextVk * contextVk,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,uint32_t * indexCountOut)620 angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
621                                             GLint firstVertex,
622                                             GLsizei vertexOrIndexCount,
623                                             gl::DrawElementsType indexTypeOrInvalid,
624                                             const void *indices,
625                                             uint32_t *indexCountOut)
626 {
627     if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
628     {
629         // Handle GL_LINE_LOOP drawElements.
630         if (mDirtyLineLoopTranslation)
631         {
632             gl::Buffer *elementArrayBuffer = mState.getElementArrayBuffer();
633 
634             if (!elementArrayBuffer)
635             {
636                 ANGLE_TRY(mLineLoopHelper.streamIndices(
637                     contextVk, indexTypeOrInvalid, vertexOrIndexCount,
638                     reinterpret_cast<const uint8_t *>(indices), &mCurrentElementArrayBuffer,
639                     &mCurrentElementArrayBufferOffset, indexCountOut));
640             }
641             else
642             {
643                 // When using an element array buffer, 'indices' is an offset to the first element.
644                 intptr_t offset                = reinterpret_cast<intptr_t>(indices);
645                 BufferVk *elementArrayBufferVk = vk::GetImpl(elementArrayBuffer);
646                 ANGLE_TRY(mLineLoopHelper.getIndexBufferForElementArrayBuffer(
647                     contextVk, elementArrayBufferVk, indexTypeOrInvalid, vertexOrIndexCount, offset,
648                     &mCurrentElementArrayBuffer, &mCurrentElementArrayBufferOffset, indexCountOut));
649             }
650         }
651 
652         // If we've had a drawArrays call with a line loop before, we want to make sure this is
653         // invalidated the next time drawArrays is called since we use the same index buffer for
654         // both calls.
655         mLineLoopBufferFirstIndex.reset();
656         mLineLoopBufferLastIndex.reset();
657         return angle::Result::Continue;
658     }
659 
660     // Note: Vertex indexes can be arbitrarily large.
661     uint32_t clampedVertexCount = gl::clampCast<uint32_t>(vertexOrIndexCount);
662 
663     // Handle GL_LINE_LOOP drawArrays.
664     size_t lastVertex = static_cast<size_t>(firstVertex + clampedVertexCount);
665     if (!mLineLoopBufferFirstIndex.valid() || !mLineLoopBufferLastIndex.valid() ||
666         mLineLoopBufferFirstIndex != firstVertex || mLineLoopBufferLastIndex != lastVertex)
667     {
668         ANGLE_TRY(mLineLoopHelper.getIndexBufferForDrawArrays(
669             contextVk, clampedVertexCount, firstVertex, &mCurrentElementArrayBuffer,
670             &mCurrentElementArrayBufferOffset));
671 
672         mLineLoopBufferFirstIndex = firstVertex;
673         mLineLoopBufferLastIndex  = lastVertex;
674     }
675     *indexCountOut = vertexOrIndexCount + 1;
676 
677     return angle::Result::Continue;
678 }
679 
updateDefaultAttrib(ContextVk * contextVk,size_t attribIndex,VkBuffer bufferHandle,uint32_t offset)680 void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk,
681                                         size_t attribIndex,
682                                         VkBuffer bufferHandle,
683                                         uint32_t offset)
684 {
685     if (!mState.getEnabledAttributesMask().test(attribIndex))
686     {
687         mCurrentArrayBufferHandles[attribIndex] = bufferHandle;
688         mCurrentArrayBufferOffsets[attribIndex] = offset;
689         mCurrentArrayBuffers[attribIndex]       = nullptr;
690 
691         setDefaultPackedInput(contextVk, attribIndex);
692     }
693 }
694 }  // namespace rx
695