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