xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/BufferVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // BufferVk.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //    Implements the class methods for BufferVk.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/BufferVk.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "common/FixedVector.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "common/mathutil.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "common/utilities.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/ContextVk.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_renderer.h"
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker namespace rx
21*8975f5c5SAndroid Build Coastguard Worker {
GetDefaultBufferUsageFlags(vk::Renderer * renderer)22*8975f5c5SAndroid Build Coastguard Worker VkBufferUsageFlags GetDefaultBufferUsageFlags(vk::Renderer *renderer)
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker     // We could potentially use multiple backing buffers for different usages.
25*8975f5c5SAndroid Build Coastguard Worker     // For now keep a single buffer with all relevant usage flags.
26*8975f5c5SAndroid Build Coastguard Worker     VkBufferUsageFlags defaultBufferUsageFlags =
27*8975f5c5SAndroid Build Coastguard Worker         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
28*8975f5c5SAndroid Build Coastguard Worker         VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
29*8975f5c5SAndroid Build Coastguard Worker         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
30*8975f5c5SAndroid Build Coastguard Worker         VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
31*8975f5c5SAndroid Build Coastguard Worker         VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
32*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsTransformFeedbackExtension.enabled)
33*8975f5c5SAndroid Build Coastguard Worker     {
34*8975f5c5SAndroid Build Coastguard Worker         defaultBufferUsageFlags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT |
35*8975f5c5SAndroid Build Coastguard Worker                                    VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
36*8975f5c5SAndroid Build Coastguard Worker     }
37*8975f5c5SAndroid Build Coastguard Worker     return defaultBufferUsageFlags;
38*8975f5c5SAndroid Build Coastguard Worker }
39*8975f5c5SAndroid Build Coastguard Worker 
40*8975f5c5SAndroid Build Coastguard Worker namespace
41*8975f5c5SAndroid Build Coastguard Worker {
42*8975f5c5SAndroid Build Coastguard Worker constexpr VkMemoryPropertyFlags kDeviceLocalFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
43*8975f5c5SAndroid Build Coastguard Worker constexpr VkMemoryPropertyFlags kDeviceLocalHostCoherentFlags =
44*8975f5c5SAndroid Build Coastguard Worker     (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
45*8975f5c5SAndroid Build Coastguard Worker      VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
46*8975f5c5SAndroid Build Coastguard Worker constexpr VkMemoryPropertyFlags kHostCachedFlags =
47*8975f5c5SAndroid Build Coastguard Worker     (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
48*8975f5c5SAndroid Build Coastguard Worker      VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
49*8975f5c5SAndroid Build Coastguard Worker constexpr VkMemoryPropertyFlags kHostUncachedFlags =
50*8975f5c5SAndroid Build Coastguard Worker     (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
51*8975f5c5SAndroid Build Coastguard Worker constexpr VkMemoryPropertyFlags kHostCachedNonCoherentFlags =
52*8975f5c5SAndroid Build Coastguard Worker     (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker // Vertex attribute buffers are used as storage buffers for conversion in compute, where access to
55*8975f5c5SAndroid Build Coastguard Worker // the buffer is made in 4-byte chunks.  Assume the size of the buffer is 4k+n where n is in [0, 3).
56*8975f5c5SAndroid Build Coastguard Worker // On some hardware, reading 4 bytes from address 4k returns 0, making it impossible to read the
57*8975f5c5SAndroid Build Coastguard Worker // last n bytes.  By rounding up the buffer sizes to a multiple of 4, the problem is alleviated.
58*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kBufferSizeGranularity = 4;
59*8975f5c5SAndroid Build Coastguard Worker static_assert(gl::isPow2(kBufferSizeGranularity), "use as alignment, must be power of two");
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker // Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
62*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kConvertedArrayBufferInitialSize = 1024 * 8;
63*8975f5c5SAndroid Build Coastguard Worker 
64*8975f5c5SAndroid Build Coastguard Worker // Buffers that have a static usage pattern will be allocated in
65*8975f5c5SAndroid Build Coastguard Worker // device local memory to speed up access to and from the GPU.
66*8975f5c5SAndroid Build Coastguard Worker // Dynamic usage patterns or that are frequently mapped
67*8975f5c5SAndroid Build Coastguard Worker // will now request host cached memory to speed up access from the CPU.
GetPreferredMemoryType(vk::Renderer * renderer,gl::BufferBinding target,gl::BufferUsage usage)68*8975f5c5SAndroid Build Coastguard Worker VkMemoryPropertyFlags GetPreferredMemoryType(vk::Renderer *renderer,
69*8975f5c5SAndroid Build Coastguard Worker                                              gl::BufferBinding target,
70*8975f5c5SAndroid Build Coastguard Worker                                              gl::BufferUsage usage)
71*8975f5c5SAndroid Build Coastguard Worker {
72*8975f5c5SAndroid Build Coastguard Worker     if (target == gl::BufferBinding::PixelUnpack)
73*8975f5c5SAndroid Build Coastguard Worker     {
74*8975f5c5SAndroid Build Coastguard Worker         return kHostCachedFlags;
75*8975f5c5SAndroid Build Coastguard Worker     }
76*8975f5c5SAndroid Build Coastguard Worker 
77*8975f5c5SAndroid Build Coastguard Worker     switch (usage)
78*8975f5c5SAndroid Build Coastguard Worker     {
79*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StaticCopy:
80*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StaticDraw:
81*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StaticRead:
82*8975f5c5SAndroid Build Coastguard Worker             // For static usage, request a device local memory
83*8975f5c5SAndroid Build Coastguard Worker             return renderer->getFeatures().preferDeviceLocalMemoryHostVisible.enabled
84*8975f5c5SAndroid Build Coastguard Worker                        ? kDeviceLocalHostCoherentFlags
85*8975f5c5SAndroid Build Coastguard Worker                        : kDeviceLocalFlags;
86*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::DynamicDraw:
87*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StreamDraw:
88*8975f5c5SAndroid Build Coastguard Worker             // For non-static usage where the CPU performs a write-only access, request
89*8975f5c5SAndroid Build Coastguard Worker             // a host uncached memory
90*8975f5c5SAndroid Build Coastguard Worker             return renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled
91*8975f5c5SAndroid Build Coastguard Worker                        ? kHostCachedFlags
92*8975f5c5SAndroid Build Coastguard Worker                        : kHostUncachedFlags;
93*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::DynamicCopy:
94*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::DynamicRead:
95*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StreamCopy:
96*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::StreamRead:
97*8975f5c5SAndroid Build Coastguard Worker             // For all other types of usage, request a host cached memory
98*8975f5c5SAndroid Build Coastguard Worker             return renderer->getFeatures()
99*8975f5c5SAndroid Build Coastguard Worker                            .preferCachedNoncoherentForDynamicStreamBufferUsage.enabled
100*8975f5c5SAndroid Build Coastguard Worker                        ? kHostCachedNonCoherentFlags
101*8975f5c5SAndroid Build Coastguard Worker                        : kHostCachedFlags;
102*8975f5c5SAndroid Build Coastguard Worker         default:
103*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
104*8975f5c5SAndroid Build Coastguard Worker             return kHostCachedFlags;
105*8975f5c5SAndroid Build Coastguard Worker     }
106*8975f5c5SAndroid Build Coastguard Worker }
107*8975f5c5SAndroid Build Coastguard Worker 
GetStorageMemoryType(vk::Renderer * renderer,GLbitfield storageFlags,bool externalBuffer)108*8975f5c5SAndroid Build Coastguard Worker VkMemoryPropertyFlags GetStorageMemoryType(vk::Renderer *renderer,
109*8975f5c5SAndroid Build Coastguard Worker                                            GLbitfield storageFlags,
110*8975f5c5SAndroid Build Coastguard Worker                                            bool externalBuffer)
111*8975f5c5SAndroid Build Coastguard Worker {
112*8975f5c5SAndroid Build Coastguard Worker     const bool hasMapAccess =
113*8975f5c5SAndroid Build Coastguard Worker         (storageFlags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT)) != 0;
114*8975f5c5SAndroid Build Coastguard Worker 
115*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().preferDeviceLocalMemoryHostVisible.enabled)
116*8975f5c5SAndroid Build Coastguard Worker     {
117*8975f5c5SAndroid Build Coastguard Worker         const bool canUpdate = (storageFlags & GL_DYNAMIC_STORAGE_BIT_EXT) != 0;
118*8975f5c5SAndroid Build Coastguard Worker         if (canUpdate || hasMapAccess || externalBuffer)
119*8975f5c5SAndroid Build Coastguard Worker         {
120*8975f5c5SAndroid Build Coastguard Worker             // We currently allocate coherent memory for persistently mapped buffers.
121*8975f5c5SAndroid Build Coastguard Worker             // GL_EXT_buffer_storage allows non-coherent memory, but currently the implementation of
122*8975f5c5SAndroid Build Coastguard Worker             // |glMemoryBarrier(CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT)| relies on the mapping being
123*8975f5c5SAndroid Build Coastguard Worker             // coherent.
124*8975f5c5SAndroid Build Coastguard Worker             //
125*8975f5c5SAndroid Build Coastguard Worker             // If persistently mapped buffers ever use non-coherent memory, then said
126*8975f5c5SAndroid Build Coastguard Worker             // |glMemoryBarrier| call must result in |vkInvalidateMappedMemoryRanges| for all
127*8975f5c5SAndroid Build Coastguard Worker             // persistently mapped buffers.
128*8975f5c5SAndroid Build Coastguard Worker             return kDeviceLocalHostCoherentFlags;
129*8975f5c5SAndroid Build Coastguard Worker         }
130*8975f5c5SAndroid Build Coastguard Worker         return kDeviceLocalFlags;
131*8975f5c5SAndroid Build Coastguard Worker     }
132*8975f5c5SAndroid Build Coastguard Worker 
133*8975f5c5SAndroid Build Coastguard Worker     return hasMapAccess ? kHostCachedFlags : kDeviceLocalFlags;
134*8975f5c5SAndroid Build Coastguard Worker }
135*8975f5c5SAndroid Build Coastguard Worker 
ShouldAllocateNewMemoryForUpdate(ContextVk * contextVk,size_t subDataSize,size_t bufferSize)136*8975f5c5SAndroid Build Coastguard Worker bool ShouldAllocateNewMemoryForUpdate(ContextVk *contextVk, size_t subDataSize, size_t bufferSize)
137*8975f5c5SAndroid Build Coastguard Worker {
138*8975f5c5SAndroid Build Coastguard Worker     // A sub-data update with size > 50% of buffer size meets the threshold to acquire a new
139*8975f5c5SAndroid Build Coastguard Worker     // BufferHelper from the pool.
140*8975f5c5SAndroid Build Coastguard Worker     size_t halfBufferSize = bufferSize / 2;
141*8975f5c5SAndroid Build Coastguard Worker     if (subDataSize > halfBufferSize)
142*8975f5c5SAndroid Build Coastguard Worker     {
143*8975f5c5SAndroid Build Coastguard Worker         return true;
144*8975f5c5SAndroid Build Coastguard Worker     }
145*8975f5c5SAndroid Build Coastguard Worker 
146*8975f5c5SAndroid Build Coastguard Worker     // If the GPU is busy, it is possible to use the CPU for updating sub-data instead, but since it
147*8975f5c5SAndroid Build Coastguard Worker     // would need to create a duplicate of the buffer, a large enough buffer copy could result in a
148*8975f5c5SAndroid Build Coastguard Worker     // performance regression.
149*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().preferCPUForBufferSubData.enabled)
150*8975f5c5SAndroid Build Coastguard Worker     {
151*8975f5c5SAndroid Build Coastguard Worker         // If the buffer is small enough, the cost of barrier associated with the GPU copy likely
152*8975f5c5SAndroid Build Coastguard Worker         // exceeds the overhead with the CPU copy. Duplicating the buffer allows the CPU to write to
153*8975f5c5SAndroid Build Coastguard Worker         // the buffer immediately, thus avoiding the barrier that prevents parallel operation.
154*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kCpuCopyBufferSizeThreshold = 32 * 1024;
155*8975f5c5SAndroid Build Coastguard Worker         if (bufferSize < kCpuCopyBufferSizeThreshold)
156*8975f5c5SAndroid Build Coastguard Worker         {
157*8975f5c5SAndroid Build Coastguard Worker             return true;
158*8975f5c5SAndroid Build Coastguard Worker         }
159*8975f5c5SAndroid Build Coastguard Worker 
160*8975f5c5SAndroid Build Coastguard Worker         // To use CPU for the sub-data update in larger buffers, the update should be sizable enough
161*8975f5c5SAndroid Build Coastguard Worker         // compared to the whole buffer size. The threshold is chosen based on perf data collected
162*8975f5c5SAndroid Build Coastguard Worker         // from Pixel devices. At 1/8 of buffer size, the CPU overhead associated with extra data
163*8975f5c5SAndroid Build Coastguard Worker         // copy weighs less than serialization caused by barriers.
164*8975f5c5SAndroid Build Coastguard Worker         size_t subDataThreshold = bufferSize / 8;
165*8975f5c5SAndroid Build Coastguard Worker         if (subDataSize > subDataThreshold)
166*8975f5c5SAndroid Build Coastguard Worker         {
167*8975f5c5SAndroid Build Coastguard Worker             return true;
168*8975f5c5SAndroid Build Coastguard Worker         }
169*8975f5c5SAndroid Build Coastguard Worker     }
170*8975f5c5SAndroid Build Coastguard Worker 
171*8975f5c5SAndroid Build Coastguard Worker     return false;
172*8975f5c5SAndroid Build Coastguard Worker }
173*8975f5c5SAndroid Build Coastguard Worker 
ShouldUseCPUToCopyData(ContextVk * contextVk,const vk::BufferHelper & buffer,size_t copySize,size_t bufferSize)174*8975f5c5SAndroid Build Coastguard Worker bool ShouldUseCPUToCopyData(ContextVk *contextVk,
175*8975f5c5SAndroid Build Coastguard Worker                             const vk::BufferHelper &buffer,
176*8975f5c5SAndroid Build Coastguard Worker                             size_t copySize,
177*8975f5c5SAndroid Build Coastguard Worker                             size_t bufferSize)
178*8975f5c5SAndroid Build Coastguard Worker {
179*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
180*8975f5c5SAndroid Build Coastguard Worker 
181*8975f5c5SAndroid Build Coastguard Worker     // If the buffer is not host-visible, or if it's busy on the GPU, can't read from it from the
182*8975f5c5SAndroid Build Coastguard Worker     // CPU
183*8975f5c5SAndroid Build Coastguard Worker     if (!buffer.isHostVisible() || !renderer->hasResourceUseFinished(buffer.getWriteResourceUse()))
184*8975f5c5SAndroid Build Coastguard Worker     {
185*8975f5c5SAndroid Build Coastguard Worker         return false;
186*8975f5c5SAndroid Build Coastguard Worker     }
187*8975f5c5SAndroid Build Coastguard Worker 
188*8975f5c5SAndroid Build Coastguard Worker     // For some GPUs (e.g. ARM) we always prefer using CPU to do copy instead of using the GPU to
189*8975f5c5SAndroid Build Coastguard Worker     // avoid pipeline bubbles. If the GPU is currently busy and data copy size is less than certain
190*8975f5c5SAndroid Build Coastguard Worker     // threshold, we choose to use CPU to do the copy over GPU to achieve better parallelism.
191*8975f5c5SAndroid Build Coastguard Worker     return renderer->getFeatures().preferCPUForBufferSubData.enabled ||
192*8975f5c5SAndroid Build Coastguard Worker            (renderer->isCommandQueueBusy() &&
193*8975f5c5SAndroid Build Coastguard Worker             copySize < renderer->getMaxCopyBytesUsingCPUWhenPreservingBufferData());
194*8975f5c5SAndroid Build Coastguard Worker }
195*8975f5c5SAndroid Build Coastguard Worker 
RenderPassUsesBufferForReadOnly(ContextVk * contextVk,const vk::BufferHelper & buffer)196*8975f5c5SAndroid Build Coastguard Worker bool RenderPassUsesBufferForReadOnly(ContextVk *contextVk, const vk::BufferHelper &buffer)
197*8975f5c5SAndroid Build Coastguard Worker {
198*8975f5c5SAndroid Build Coastguard Worker     if (!contextVk->hasActiveRenderPass())
199*8975f5c5SAndroid Build Coastguard Worker     {
200*8975f5c5SAndroid Build Coastguard Worker         return false;
201*8975f5c5SAndroid Build Coastguard Worker     }
202*8975f5c5SAndroid Build Coastguard Worker 
203*8975f5c5SAndroid Build Coastguard Worker     vk::RenderPassCommandBufferHelper &renderPassCommands =
204*8975f5c5SAndroid Build Coastguard Worker         contextVk->getStartedRenderPassCommands();
205*8975f5c5SAndroid Build Coastguard Worker     return renderPassCommands.usesBuffer(buffer) && !renderPassCommands.usesBufferForWrite(buffer);
206*8975f5c5SAndroid Build Coastguard Worker }
207*8975f5c5SAndroid Build Coastguard Worker 
208*8975f5c5SAndroid Build Coastguard Worker // If a render pass is open which uses the buffer in read-only mode, render pass break can be
209*8975f5c5SAndroid Build Coastguard Worker // avoided by using acquireAndUpdate.  This can be costly however if the update is very small, and
210*8975f5c5SAndroid Build Coastguard Worker // is limited to platforms where render pass break is itself costly (i.e. tiled-based renderers).
ShouldAvoidRenderPassBreakOnUpdate(ContextVk * contextVk,const vk::BufferHelper & buffer,size_t bufferSize)211*8975f5c5SAndroid Build Coastguard Worker bool ShouldAvoidRenderPassBreakOnUpdate(ContextVk *contextVk,
212*8975f5c5SAndroid Build Coastguard Worker                                         const vk::BufferHelper &buffer,
213*8975f5c5SAndroid Build Coastguard Worker                                         size_t bufferSize)
214*8975f5c5SAndroid Build Coastguard Worker {
215*8975f5c5SAndroid Build Coastguard Worker     // Only avoid breaking the render pass if the buffer is not so big such that duplicating it
216*8975f5c5SAndroid Build Coastguard Worker     // would outweight the cost of breaking the render pass.  A value of 1KB is temporary chosen as
217*8975f5c5SAndroid Build Coastguard Worker     // a heuristic, and can be adjusted when such a situation is encountered.
218*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kPreferDuplicateOverRenderPassBreakMaxBufferSize = 1024;
219*8975f5c5SAndroid Build Coastguard Worker     if (!contextVk->getFeatures().preferCPUForBufferSubData.enabled ||
220*8975f5c5SAndroid Build Coastguard Worker         bufferSize > kPreferDuplicateOverRenderPassBreakMaxBufferSize)
221*8975f5c5SAndroid Build Coastguard Worker     {
222*8975f5c5SAndroid Build Coastguard Worker         return false;
223*8975f5c5SAndroid Build Coastguard Worker     }
224*8975f5c5SAndroid Build Coastguard Worker 
225*8975f5c5SAndroid Build Coastguard Worker     return RenderPassUsesBufferForReadOnly(contextVk, buffer);
226*8975f5c5SAndroid Build Coastguard Worker }
227*8975f5c5SAndroid Build Coastguard Worker 
GetBufferUsageType(gl::BufferUsage usage)228*8975f5c5SAndroid Build Coastguard Worker BufferUsageType GetBufferUsageType(gl::BufferUsage usage)
229*8975f5c5SAndroid Build Coastguard Worker {
230*8975f5c5SAndroid Build Coastguard Worker     return (usage == gl::BufferUsage::DynamicDraw || usage == gl::BufferUsage::DynamicCopy ||
231*8975f5c5SAndroid Build Coastguard Worker             usage == gl::BufferUsage::DynamicRead)
232*8975f5c5SAndroid Build Coastguard Worker                ? BufferUsageType::Dynamic
233*8975f5c5SAndroid Build Coastguard Worker                : BufferUsageType::Static;
234*8975f5c5SAndroid Build Coastguard Worker }
235*8975f5c5SAndroid Build Coastguard Worker 
GetMemoryTypeIndex(ContextVk * contextVk,VkDeviceSize size,VkMemoryPropertyFlags memoryPropertyFlags,uint32_t * memoryTypeIndexOut)236*8975f5c5SAndroid Build Coastguard Worker angle::Result GetMemoryTypeIndex(ContextVk *contextVk,
237*8975f5c5SAndroid Build Coastguard Worker                                  VkDeviceSize size,
238*8975f5c5SAndroid Build Coastguard Worker                                  VkMemoryPropertyFlags memoryPropertyFlags,
239*8975f5c5SAndroid Build Coastguard Worker                                  uint32_t *memoryTypeIndexOut)
240*8975f5c5SAndroid Build Coastguard Worker {
241*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer         = contextVk->getRenderer();
242*8975f5c5SAndroid Build Coastguard Worker     const vk::Allocator &allocator = renderer->getAllocator();
243*8975f5c5SAndroid Build Coastguard Worker 
244*8975f5c5SAndroid Build Coastguard Worker     bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
245*8975f5c5SAndroid Build Coastguard Worker     VkBufferUsageFlags defaultBufferUsageFlags = GetDefaultBufferUsageFlags(renderer);
246*8975f5c5SAndroid Build Coastguard Worker 
247*8975f5c5SAndroid Build Coastguard Worker     VkBufferCreateInfo createInfo    = {};
248*8975f5c5SAndroid Build Coastguard Worker     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
249*8975f5c5SAndroid Build Coastguard Worker     createInfo.flags                 = 0;
250*8975f5c5SAndroid Build Coastguard Worker     createInfo.size                  = size;
251*8975f5c5SAndroid Build Coastguard Worker     createInfo.usage                 = defaultBufferUsageFlags;
252*8975f5c5SAndroid Build Coastguard Worker     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
253*8975f5c5SAndroid Build Coastguard Worker     createInfo.queueFamilyIndexCount = 0;
254*8975f5c5SAndroid Build Coastguard Worker     createInfo.pQueueFamilyIndices   = nullptr;
255*8975f5c5SAndroid Build Coastguard Worker 
256*8975f5c5SAndroid Build Coastguard Worker     // Host visible is required, all other bits are preferred, (i.e., optional)
257*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags requiredFlags =
258*8975f5c5SAndroid Build Coastguard Worker         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
259*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags preferredFlags =
260*8975f5c5SAndroid Build Coastguard Worker         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
261*8975f5c5SAndroid Build Coastguard Worker 
262*8975f5c5SAndroid Build Coastguard Worker     // Check that the allocation is not too large.
263*8975f5c5SAndroid Build Coastguard Worker     uint32_t memoryTypeIndex = 0;
264*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(contextVk, allocator.findMemoryTypeIndexForBufferInfo(
265*8975f5c5SAndroid Build Coastguard Worker                                 createInfo, requiredFlags, preferredFlags, persistentlyMapped,
266*8975f5c5SAndroid Build Coastguard Worker                                 &memoryTypeIndex));
267*8975f5c5SAndroid Build Coastguard Worker     *memoryTypeIndexOut = memoryTypeIndex;
268*8975f5c5SAndroid Build Coastguard Worker 
269*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
270*8975f5c5SAndroid Build Coastguard Worker }
271*8975f5c5SAndroid Build Coastguard Worker 
IsSelfCopy(const BufferDataSource & dataSource,const vk::BufferHelper & destination)272*8975f5c5SAndroid Build Coastguard Worker bool IsSelfCopy(const BufferDataSource &dataSource, const vk::BufferHelper &destination)
273*8975f5c5SAndroid Build Coastguard Worker {
274*8975f5c5SAndroid Build Coastguard Worker     return dataSource.data == nullptr &&
275*8975f5c5SAndroid Build Coastguard Worker            dataSource.buffer->getBufferSerial() == destination.getBufferSerial();
276*8975f5c5SAndroid Build Coastguard Worker }
277*8975f5c5SAndroid Build Coastguard Worker 
CopyBuffers(ContextVk * contextVk,vk::BufferHelper * srcBuffer,vk::BufferHelper * dstBuffer,uint32_t regionCount,const VkBufferCopy * copyRegions)278*8975f5c5SAndroid Build Coastguard Worker angle::Result CopyBuffers(ContextVk *contextVk,
279*8975f5c5SAndroid Build Coastguard Worker                           vk::BufferHelper *srcBuffer,
280*8975f5c5SAndroid Build Coastguard Worker                           vk::BufferHelper *dstBuffer,
281*8975f5c5SAndroid Build Coastguard Worker                           uint32_t regionCount,
282*8975f5c5SAndroid Build Coastguard Worker                           const VkBufferCopy *copyRegions)
283*8975f5c5SAndroid Build Coastguard Worker {
284*8975f5c5SAndroid Build Coastguard Worker     ASSERT(srcBuffer->valid() && dstBuffer->valid());
285*8975f5c5SAndroid Build Coastguard Worker 
286*8975f5c5SAndroid Build Coastguard Worker     // Enqueue a copy command on the GPU
287*8975f5c5SAndroid Build Coastguard Worker     vk::CommandBufferAccess access;
288*8975f5c5SAndroid Build Coastguard Worker     if (srcBuffer->getBufferSerial() == dstBuffer->getBufferSerial())
289*8975f5c5SAndroid Build Coastguard Worker     {
290*8975f5c5SAndroid Build Coastguard Worker         access.onBufferSelfCopy(srcBuffer);
291*8975f5c5SAndroid Build Coastguard Worker     }
292*8975f5c5SAndroid Build Coastguard Worker     else
293*8975f5c5SAndroid Build Coastguard Worker     {
294*8975f5c5SAndroid Build Coastguard Worker         access.onBufferTransferRead(srcBuffer);
295*8975f5c5SAndroid Build Coastguard Worker         access.onBufferTransferWrite(dstBuffer);
296*8975f5c5SAndroid Build Coastguard Worker     }
297*8975f5c5SAndroid Build Coastguard Worker 
298*8975f5c5SAndroid Build Coastguard Worker     vk::OutsideRenderPassCommandBuffer *commandBuffer;
299*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
300*8975f5c5SAndroid Build Coastguard Worker 
301*8975f5c5SAndroid Build Coastguard Worker     commandBuffer->copyBuffer(srcBuffer->getBuffer(), dstBuffer->getBuffer(), regionCount,
302*8975f5c5SAndroid Build Coastguard Worker                               copyRegions);
303*8975f5c5SAndroid Build Coastguard Worker 
304*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
305*8975f5c5SAndroid Build Coastguard Worker }
306*8975f5c5SAndroid Build Coastguard Worker }  // namespace
307*8975f5c5SAndroid Build Coastguard Worker 
308*8975f5c5SAndroid Build Coastguard Worker // ConversionBuffer implementation.
ConversionBuffer(vk::Renderer * renderer,VkBufferUsageFlags usageFlags,size_t initialSize,size_t alignment,bool hostVisible)309*8975f5c5SAndroid Build Coastguard Worker ConversionBuffer::ConversionBuffer(vk::Renderer *renderer,
310*8975f5c5SAndroid Build Coastguard Worker                                    VkBufferUsageFlags usageFlags,
311*8975f5c5SAndroid Build Coastguard Worker                                    size_t initialSize,
312*8975f5c5SAndroid Build Coastguard Worker                                    size_t alignment,
313*8975f5c5SAndroid Build Coastguard Worker                                    bool hostVisible)
314*8975f5c5SAndroid Build Coastguard Worker     : mEntireBufferDirty(true)
315*8975f5c5SAndroid Build Coastguard Worker {
316*8975f5c5SAndroid Build Coastguard Worker     mData = std::make_unique<vk::BufferHelper>();
317*8975f5c5SAndroid Build Coastguard Worker     mDirtyRanges.reserve(32);
318*8975f5c5SAndroid Build Coastguard Worker }
319*8975f5c5SAndroid Build Coastguard Worker 
~ConversionBuffer()320*8975f5c5SAndroid Build Coastguard Worker ConversionBuffer::~ConversionBuffer()
321*8975f5c5SAndroid Build Coastguard Worker {
322*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mData || !mData->valid());
323*8975f5c5SAndroid Build Coastguard Worker     mDirtyRanges.clear();
324*8975f5c5SAndroid Build Coastguard Worker }
325*8975f5c5SAndroid Build Coastguard Worker 
326*8975f5c5SAndroid Build Coastguard Worker ConversionBuffer::ConversionBuffer(ConversionBuffer &&other) = default;
327*8975f5c5SAndroid Build Coastguard Worker 
328*8975f5c5SAndroid Build Coastguard Worker // dirtyRanges may be overlap or continuous. In order to reduce the redunant conversion, we try to
329*8975f5c5SAndroid Build Coastguard Worker // consolidate the dirty ranges. First we sort it by the range's low. Then we walk the range again
330*8975f5c5SAndroid Build Coastguard Worker // and check it with previous range and merge them if possible. That merge will remove the
331*8975f5c5SAndroid Build Coastguard Worker // overlapped area as well as reduce the number of ranges.
consolidateDirtyRanges()332*8975f5c5SAndroid Build Coastguard Worker void ConversionBuffer::consolidateDirtyRanges()
333*8975f5c5SAndroid Build Coastguard Worker {
334*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mEntireBufferDirty);
335*8975f5c5SAndroid Build Coastguard Worker 
336*8975f5c5SAndroid Build Coastguard Worker     auto comp = [](const RangeDeviceSize &a, const RangeDeviceSize &b) -> bool {
337*8975f5c5SAndroid Build Coastguard Worker         return a.low() < b.low();
338*8975f5c5SAndroid Build Coastguard Worker     };
339*8975f5c5SAndroid Build Coastguard Worker     std::sort(mDirtyRanges.begin(), mDirtyRanges.end(), comp);
340*8975f5c5SAndroid Build Coastguard Worker 
341*8975f5c5SAndroid Build Coastguard Worker     size_t prev = 0;
342*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 1; i < mDirtyRanges.size(); i++)
343*8975f5c5SAndroid Build Coastguard Worker     {
344*8975f5c5SAndroid Build Coastguard Worker         if (mDirtyRanges[prev].intersectsOrContinuous(mDirtyRanges[i]))
345*8975f5c5SAndroid Build Coastguard Worker         {
346*8975f5c5SAndroid Build Coastguard Worker             mDirtyRanges[prev].merge(mDirtyRanges[i]);
347*8975f5c5SAndroid Build Coastguard Worker             mDirtyRanges[i].invalidate();
348*8975f5c5SAndroid Build Coastguard Worker         }
349*8975f5c5SAndroid Build Coastguard Worker         else
350*8975f5c5SAndroid Build Coastguard Worker         {
351*8975f5c5SAndroid Build Coastguard Worker             prev = i;
352*8975f5c5SAndroid Build Coastguard Worker         }
353*8975f5c5SAndroid Build Coastguard Worker     }
354*8975f5c5SAndroid Build Coastguard Worker }
355*8975f5c5SAndroid Build Coastguard Worker 
356*8975f5c5SAndroid Build Coastguard Worker // VertexConversionBuffer implementation.
VertexConversionBuffer(vk::Renderer * renderer,const CacheKey & cacheKey)357*8975f5c5SAndroid Build Coastguard Worker VertexConversionBuffer::VertexConversionBuffer(vk::Renderer *renderer, const CacheKey &cacheKey)
358*8975f5c5SAndroid Build Coastguard Worker     : ConversionBuffer(renderer,
359*8975f5c5SAndroid Build Coastguard Worker                        vk::kVertexBufferUsageFlags,
360*8975f5c5SAndroid Build Coastguard Worker                        kConvertedArrayBufferInitialSize,
361*8975f5c5SAndroid Build Coastguard Worker                        vk::kVertexBufferAlignment,
362*8975f5c5SAndroid Build Coastguard Worker                        cacheKey.hostVisible),
363*8975f5c5SAndroid Build Coastguard Worker       mCacheKey(cacheKey)
364*8975f5c5SAndroid Build Coastguard Worker {}
365*8975f5c5SAndroid Build Coastguard Worker 
366*8975f5c5SAndroid Build Coastguard Worker VertexConversionBuffer::VertexConversionBuffer(VertexConversionBuffer &&other) = default;
367*8975f5c5SAndroid Build Coastguard Worker 
368*8975f5c5SAndroid Build Coastguard Worker VertexConversionBuffer::~VertexConversionBuffer() = default;
369*8975f5c5SAndroid Build Coastguard Worker 
370*8975f5c5SAndroid Build Coastguard Worker // BufferVk implementation.
BufferVk(const gl::BufferState & state)371*8975f5c5SAndroid Build Coastguard Worker BufferVk::BufferVk(const gl::BufferState &state)
372*8975f5c5SAndroid Build Coastguard Worker     : BufferImpl(state),
373*8975f5c5SAndroid Build Coastguard Worker       mClientBuffer(nullptr),
374*8975f5c5SAndroid Build Coastguard Worker       mMemoryTypeIndex(0),
375*8975f5c5SAndroid Build Coastguard Worker       mMemoryPropertyFlags(0),
376*8975f5c5SAndroid Build Coastguard Worker       mIsStagingBufferMapped(false),
377*8975f5c5SAndroid Build Coastguard Worker       mHasValidData(false),
378*8975f5c5SAndroid Build Coastguard Worker       mIsMappedForWrite(false),
379*8975f5c5SAndroid Build Coastguard Worker       mUsageType(BufferUsageType::Static)
380*8975f5c5SAndroid Build Coastguard Worker {
381*8975f5c5SAndroid Build Coastguard Worker     mMappedRange.invalidate();
382*8975f5c5SAndroid Build Coastguard Worker }
383*8975f5c5SAndroid Build Coastguard Worker 
~BufferVk()384*8975f5c5SAndroid Build Coastguard Worker BufferVk::~BufferVk() {}
385*8975f5c5SAndroid Build Coastguard Worker 
destroy(const gl::Context * context)386*8975f5c5SAndroid Build Coastguard Worker void BufferVk::destroy(const gl::Context *context)
387*8975f5c5SAndroid Build Coastguard Worker {
388*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
389*8975f5c5SAndroid Build Coastguard Worker 
390*8975f5c5SAndroid Build Coastguard Worker     (void)release(contextVk);
391*8975f5c5SAndroid Build Coastguard Worker }
392*8975f5c5SAndroid Build Coastguard Worker 
releaseConversionBuffers(vk::Renderer * renderer)393*8975f5c5SAndroid Build Coastguard Worker void BufferVk::releaseConversionBuffers(vk::Renderer *renderer)
394*8975f5c5SAndroid Build Coastguard Worker {
395*8975f5c5SAndroid Build Coastguard Worker     for (ConversionBuffer &buffer : mVertexConversionBuffers)
396*8975f5c5SAndroid Build Coastguard Worker     {
397*8975f5c5SAndroid Build Coastguard Worker         buffer.release(renderer);
398*8975f5c5SAndroid Build Coastguard Worker     }
399*8975f5c5SAndroid Build Coastguard Worker     mVertexConversionBuffers.clear();
400*8975f5c5SAndroid Build Coastguard Worker }
401*8975f5c5SAndroid Build Coastguard Worker 
release(ContextVk * contextVk)402*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::release(ContextVk *contextVk)
403*8975f5c5SAndroid Build Coastguard Worker {
404*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
405*8975f5c5SAndroid Build Coastguard Worker     if (mBuffer.valid())
406*8975f5c5SAndroid Build Coastguard Worker     {
407*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->releaseBufferAllocation(&mBuffer));
408*8975f5c5SAndroid Build Coastguard Worker     }
409*8975f5c5SAndroid Build Coastguard Worker     if (mStagingBuffer.valid())
410*8975f5c5SAndroid Build Coastguard Worker     {
411*8975f5c5SAndroid Build Coastguard Worker         mStagingBuffer.release(renderer);
412*8975f5c5SAndroid Build Coastguard Worker     }
413*8975f5c5SAndroid Build Coastguard Worker 
414*8975f5c5SAndroid Build Coastguard Worker     releaseConversionBuffers(renderer);
415*8975f5c5SAndroid Build Coastguard Worker 
416*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
417*8975f5c5SAndroid Build Coastguard Worker }
418*8975f5c5SAndroid Build Coastguard Worker 
setExternalBufferData(const gl::Context * context,gl::BufferBinding target,GLeglClientBufferEXT clientBuffer,size_t size,VkMemoryPropertyFlags memoryPropertyFlags)419*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setExternalBufferData(const gl::Context *context,
420*8975f5c5SAndroid Build Coastguard Worker                                               gl::BufferBinding target,
421*8975f5c5SAndroid Build Coastguard Worker                                               GLeglClientBufferEXT clientBuffer,
422*8975f5c5SAndroid Build Coastguard Worker                                               size_t size,
423*8975f5c5SAndroid Build Coastguard Worker                                               VkMemoryPropertyFlags memoryPropertyFlags)
424*8975f5c5SAndroid Build Coastguard Worker {
425*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
426*8975f5c5SAndroid Build Coastguard Worker 
427*8975f5c5SAndroid Build Coastguard Worker     // Release and re-create the memory and buffer.
428*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(release(contextVk));
429*8975f5c5SAndroid Build Coastguard Worker 
430*8975f5c5SAndroid Build Coastguard Worker     VkBufferCreateInfo createInfo    = {};
431*8975f5c5SAndroid Build Coastguard Worker     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
432*8975f5c5SAndroid Build Coastguard Worker     createInfo.flags                 = 0;
433*8975f5c5SAndroid Build Coastguard Worker     createInfo.size                  = size;
434*8975f5c5SAndroid Build Coastguard Worker     createInfo.usage                 = GetDefaultBufferUsageFlags(contextVk->getRenderer());
435*8975f5c5SAndroid Build Coastguard Worker     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
436*8975f5c5SAndroid Build Coastguard Worker     createInfo.queueFamilyIndexCount = 0;
437*8975f5c5SAndroid Build Coastguard Worker     createInfo.pQueueFamilyIndices   = nullptr;
438*8975f5c5SAndroid Build Coastguard Worker 
439*8975f5c5SAndroid Build Coastguard Worker     return mBuffer.initExternal(contextVk, memoryPropertyFlags, createInfo, clientBuffer);
440*8975f5c5SAndroid Build Coastguard Worker }
441*8975f5c5SAndroid Build Coastguard Worker 
setDataWithUsageFlags(const gl::Context * context,gl::BufferBinding target,GLeglClientBufferEXT clientBuffer,const void * data,size_t size,gl::BufferUsage usage,GLbitfield flags)442*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setDataWithUsageFlags(const gl::Context *context,
443*8975f5c5SAndroid Build Coastguard Worker                                               gl::BufferBinding target,
444*8975f5c5SAndroid Build Coastguard Worker                                               GLeglClientBufferEXT clientBuffer,
445*8975f5c5SAndroid Build Coastguard Worker                                               const void *data,
446*8975f5c5SAndroid Build Coastguard Worker                                               size_t size,
447*8975f5c5SAndroid Build Coastguard Worker                                               gl::BufferUsage usage,
448*8975f5c5SAndroid Build Coastguard Worker                                               GLbitfield flags)
449*8975f5c5SAndroid Build Coastguard Worker {
450*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk                      = vk::GetImpl(context);
451*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags memoryPropertyFlags = 0;
452*8975f5c5SAndroid Build Coastguard Worker     bool persistentMapRequired                = false;
453*8975f5c5SAndroid Build Coastguard Worker     const bool isExternalBuffer               = clientBuffer != nullptr;
454*8975f5c5SAndroid Build Coastguard Worker 
455*8975f5c5SAndroid Build Coastguard Worker     switch (usage)
456*8975f5c5SAndroid Build Coastguard Worker     {
457*8975f5c5SAndroid Build Coastguard Worker         case gl::BufferUsage::InvalidEnum:
458*8975f5c5SAndroid Build Coastguard Worker         {
459*8975f5c5SAndroid Build Coastguard Worker             // glBufferStorage API call
460*8975f5c5SAndroid Build Coastguard Worker             memoryPropertyFlags =
461*8975f5c5SAndroid Build Coastguard Worker                 GetStorageMemoryType(contextVk->getRenderer(), flags, isExternalBuffer);
462*8975f5c5SAndroid Build Coastguard Worker             persistentMapRequired = (flags & GL_MAP_PERSISTENT_BIT_EXT) != 0;
463*8975f5c5SAndroid Build Coastguard Worker             break;
464*8975f5c5SAndroid Build Coastguard Worker         }
465*8975f5c5SAndroid Build Coastguard Worker         default:
466*8975f5c5SAndroid Build Coastguard Worker         {
467*8975f5c5SAndroid Build Coastguard Worker             // glBufferData API call
468*8975f5c5SAndroid Build Coastguard Worker             memoryPropertyFlags = GetPreferredMemoryType(contextVk->getRenderer(), target, usage);
469*8975f5c5SAndroid Build Coastguard Worker             break;
470*8975f5c5SAndroid Build Coastguard Worker         }
471*8975f5c5SAndroid Build Coastguard Worker     }
472*8975f5c5SAndroid Build Coastguard Worker 
473*8975f5c5SAndroid Build Coastguard Worker     if (isExternalBuffer)
474*8975f5c5SAndroid Build Coastguard Worker     {
475*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(setExternalBufferData(context, target, clientBuffer, size, memoryPropertyFlags));
476*8975f5c5SAndroid Build Coastguard Worker         if (!mBuffer.isHostVisible())
477*8975f5c5SAndroid Build Coastguard Worker         {
478*8975f5c5SAndroid Build Coastguard Worker             // If external buffer's memory does not support host visible memory property, we cannot
479*8975f5c5SAndroid Build Coastguard Worker             // support a persistent map request.
480*8975f5c5SAndroid Build Coastguard Worker             ANGLE_VK_CHECK(contextVk, !persistentMapRequired, VK_ERROR_MEMORY_MAP_FAILED);
481*8975f5c5SAndroid Build Coastguard Worker         }
482*8975f5c5SAndroid Build Coastguard Worker 
483*8975f5c5SAndroid Build Coastguard Worker         mClientBuffer = clientBuffer;
484*8975f5c5SAndroid Build Coastguard Worker 
485*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
486*8975f5c5SAndroid Build Coastguard Worker     }
487*8975f5c5SAndroid Build Coastguard Worker     return setDataWithMemoryType(context, target, data, size, memoryPropertyFlags, usage);
488*8975f5c5SAndroid Build Coastguard Worker }
489*8975f5c5SAndroid Build Coastguard Worker 
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage usage)490*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setData(const gl::Context *context,
491*8975f5c5SAndroid Build Coastguard Worker                                 gl::BufferBinding target,
492*8975f5c5SAndroid Build Coastguard Worker                                 const void *data,
493*8975f5c5SAndroid Build Coastguard Worker                                 size_t size,
494*8975f5c5SAndroid Build Coastguard Worker                                 gl::BufferUsage usage)
495*8975f5c5SAndroid Build Coastguard Worker {
496*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
497*8975f5c5SAndroid Build Coastguard Worker     // Assume host visible/coherent memory available.
498*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags memoryPropertyFlags =
499*8975f5c5SAndroid Build Coastguard Worker         GetPreferredMemoryType(contextVk->getRenderer(), target, usage);
500*8975f5c5SAndroid Build Coastguard Worker     return setDataWithMemoryType(context, target, data, size, memoryPropertyFlags, usage);
501*8975f5c5SAndroid Build Coastguard Worker }
502*8975f5c5SAndroid Build Coastguard Worker 
setDataWithMemoryType(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,VkMemoryPropertyFlags memoryPropertyFlags,gl::BufferUsage usage)503*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setDataWithMemoryType(const gl::Context *context,
504*8975f5c5SAndroid Build Coastguard Worker                                               gl::BufferBinding target,
505*8975f5c5SAndroid Build Coastguard Worker                                               const void *data,
506*8975f5c5SAndroid Build Coastguard Worker                                               size_t size,
507*8975f5c5SAndroid Build Coastguard Worker                                               VkMemoryPropertyFlags memoryPropertyFlags,
508*8975f5c5SAndroid Build Coastguard Worker                                               gl::BufferUsage usage)
509*8975f5c5SAndroid Build Coastguard Worker {
510*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk   = vk::GetImpl(context);
511*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
512*8975f5c5SAndroid Build Coastguard Worker 
513*8975f5c5SAndroid Build Coastguard Worker     // Since the buffer is being entirely reinitialized, reset the valid-data flag. If the caller
514*8975f5c5SAndroid Build Coastguard Worker     // passed in data to fill the buffer, the flag will be updated when the data is copied to the
515*8975f5c5SAndroid Build Coastguard Worker     // buffer.
516*8975f5c5SAndroid Build Coastguard Worker     mHasValidData = false;
517*8975f5c5SAndroid Build Coastguard Worker 
518*8975f5c5SAndroid Build Coastguard Worker     if (size == 0)
519*8975f5c5SAndroid Build Coastguard Worker     {
520*8975f5c5SAndroid Build Coastguard Worker         // Nothing to do.
521*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
522*8975f5c5SAndroid Build Coastguard Worker     }
523*8975f5c5SAndroid Build Coastguard Worker 
524*8975f5c5SAndroid Build Coastguard Worker     if (!mVertexConversionBuffers.empty())
525*8975f5c5SAndroid Build Coastguard Worker     {
526*8975f5c5SAndroid Build Coastguard Worker         for (ConversionBuffer &buffer : mVertexConversionBuffers)
527*8975f5c5SAndroid Build Coastguard Worker         {
528*8975f5c5SAndroid Build Coastguard Worker             buffer.clearDirty();
529*8975f5c5SAndroid Build Coastguard Worker         }
530*8975f5c5SAndroid Build Coastguard Worker     }
531*8975f5c5SAndroid Build Coastguard Worker 
532*8975f5c5SAndroid Build Coastguard Worker     const BufferUsageType usageType = GetBufferUsageType(usage);
533*8975f5c5SAndroid Build Coastguard Worker     const BufferUpdateType updateType =
534*8975f5c5SAndroid Build Coastguard Worker         calculateBufferUpdateTypeOnFullUpdate(renderer, size, memoryPropertyFlags, usageType, data);
535*8975f5c5SAndroid Build Coastguard Worker 
536*8975f5c5SAndroid Build Coastguard Worker     if (updateType == BufferUpdateType::StorageRedefined)
537*8975f5c5SAndroid Build Coastguard Worker     {
538*8975f5c5SAndroid Build Coastguard Worker         mUsageType           = usageType;
539*8975f5c5SAndroid Build Coastguard Worker         mMemoryPropertyFlags = memoryPropertyFlags;
540*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(GetMemoryTypeIndex(contextVk, size, memoryPropertyFlags, &mMemoryTypeIndex));
541*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(acquireBufferHelper(contextVk, size, mUsageType));
542*8975f5c5SAndroid Build Coastguard Worker     }
543*8975f5c5SAndroid Build Coastguard Worker     else if (size != static_cast<size_t>(mState.getSize()))
544*8975f5c5SAndroid Build Coastguard Worker     {
545*8975f5c5SAndroid Build Coastguard Worker         if (mBuffer.onBufferUserSizeChange(renderer))
546*8975f5c5SAndroid Build Coastguard Worker         {
547*8975f5c5SAndroid Build Coastguard Worker             // If we have a dedicated VkBuffer created with user size, even if the storage is
548*8975f5c5SAndroid Build Coastguard Worker             // reused, we have to recreate that VkBuffer with user size when user size changes.
549*8975f5c5SAndroid Build Coastguard Worker             // When this happens, we must notify other objects that observing this buffer, such as
550*8975f5c5SAndroid Build Coastguard Worker             // vertex array. The reason vertex array is observing the buffer's storage change is
551*8975f5c5SAndroid Build Coastguard Worker             // because they uses VkBuffer. Now VkBuffer have changed, vertex array needs to
552*8975f5c5SAndroid Build Coastguard Worker             // re-process it just like storage has been reallocated.
553*8975f5c5SAndroid Build Coastguard Worker             onStateChange(angle::SubjectMessage::InternalMemoryAllocationChanged);
554*8975f5c5SAndroid Build Coastguard Worker         }
555*8975f5c5SAndroid Build Coastguard Worker     }
556*8975f5c5SAndroid Build Coastguard Worker 
557*8975f5c5SAndroid Build Coastguard Worker     if (data != nullptr)
558*8975f5c5SAndroid Build Coastguard Worker     {
559*8975f5c5SAndroid Build Coastguard Worker         BufferDataSource dataSource = {};
560*8975f5c5SAndroid Build Coastguard Worker         dataSource.data             = data;
561*8975f5c5SAndroid Build Coastguard Worker 
562*8975f5c5SAndroid Build Coastguard Worker         // Handle full-buffer updates similarly to glBufferSubData
563*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(setDataImpl(contextVk, size, dataSource, size, 0, updateType));
564*8975f5c5SAndroid Build Coastguard Worker     }
565*8975f5c5SAndroid Build Coastguard Worker 
566*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
567*8975f5c5SAndroid Build Coastguard Worker }
568*8975f5c5SAndroid Build Coastguard Worker 
setSubData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,size_t offset)569*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setSubData(const gl::Context *context,
570*8975f5c5SAndroid Build Coastguard Worker                                    gl::BufferBinding target,
571*8975f5c5SAndroid Build Coastguard Worker                                    const void *data,
572*8975f5c5SAndroid Build Coastguard Worker                                    size_t size,
573*8975f5c5SAndroid Build Coastguard Worker                                    size_t offset)
574*8975f5c5SAndroid Build Coastguard Worker {
575*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
576*8975f5c5SAndroid Build Coastguard Worker 
577*8975f5c5SAndroid Build Coastguard Worker     BufferDataSource dataSource = {};
578*8975f5c5SAndroid Build Coastguard Worker     dataSource.data             = data;
579*8975f5c5SAndroid Build Coastguard Worker 
580*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
581*8975f5c5SAndroid Build Coastguard Worker     return setDataImpl(contextVk, static_cast<size_t>(mState.getSize()), dataSource, size, offset,
582*8975f5c5SAndroid Build Coastguard Worker                        BufferUpdateType::ContentsUpdate);
583*8975f5c5SAndroid Build Coastguard Worker }
584*8975f5c5SAndroid Build Coastguard Worker 
copySubData(const gl::Context * context,BufferImpl * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)585*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::copySubData(const gl::Context *context,
586*8975f5c5SAndroid Build Coastguard Worker                                     BufferImpl *source,
587*8975f5c5SAndroid Build Coastguard Worker                                     GLintptr sourceOffset,
588*8975f5c5SAndroid Build Coastguard Worker                                     GLintptr destOffset,
589*8975f5c5SAndroid Build Coastguard Worker                                     GLsizeiptr size)
590*8975f5c5SAndroid Build Coastguard Worker {
591*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
592*8975f5c5SAndroid Build Coastguard Worker 
593*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
594*8975f5c5SAndroid Build Coastguard Worker     BufferVk *sourceVk   = GetAs<BufferVk>(source);
595*8975f5c5SAndroid Build Coastguard Worker 
596*8975f5c5SAndroid Build Coastguard Worker     BufferDataSource dataSource = {};
597*8975f5c5SAndroid Build Coastguard Worker     dataSource.buffer           = &sourceVk->getBuffer();
598*8975f5c5SAndroid Build Coastguard Worker     dataSource.bufferOffset     = static_cast<VkDeviceSize>(sourceOffset);
599*8975f5c5SAndroid Build Coastguard Worker 
600*8975f5c5SAndroid Build Coastguard Worker     ASSERT(dataSource.buffer->valid());
601*8975f5c5SAndroid Build Coastguard Worker 
602*8975f5c5SAndroid Build Coastguard Worker     return setDataImpl(contextVk, static_cast<size_t>(mState.getSize()), dataSource, size,
603*8975f5c5SAndroid Build Coastguard Worker                        destOffset, BufferUpdateType::ContentsUpdate);
604*8975f5c5SAndroid Build Coastguard Worker }
605*8975f5c5SAndroid Build Coastguard Worker 
allocStagingBuffer(ContextVk * contextVk,vk::MemoryCoherency coherency,VkDeviceSize size,uint8_t ** mapPtr)606*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::allocStagingBuffer(ContextVk *contextVk,
607*8975f5c5SAndroid Build Coastguard Worker                                            vk::MemoryCoherency coherency,
608*8975f5c5SAndroid Build Coastguard Worker                                            VkDeviceSize size,
609*8975f5c5SAndroid Build Coastguard Worker                                            uint8_t **mapPtr)
610*8975f5c5SAndroid Build Coastguard Worker {
611*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mIsStagingBufferMapped);
612*8975f5c5SAndroid Build Coastguard Worker 
613*8975f5c5SAndroid Build Coastguard Worker     if (mStagingBuffer.valid())
614*8975f5c5SAndroid Build Coastguard Worker     {
615*8975f5c5SAndroid Build Coastguard Worker         if (size <= mStagingBuffer.getSize() && IsCached(coherency) == mStagingBuffer.isCached() &&
616*8975f5c5SAndroid Build Coastguard Worker             contextVk->getRenderer()->hasResourceUseFinished(mStagingBuffer.getResourceUse()))
617*8975f5c5SAndroid Build Coastguard Worker         {
618*8975f5c5SAndroid Build Coastguard Worker             // If size is big enough and it is idle, then just reuse the existing staging buffer
619*8975f5c5SAndroid Build Coastguard Worker             *mapPtr                = mStagingBuffer.getMappedMemory();
620*8975f5c5SAndroid Build Coastguard Worker             mIsStagingBufferMapped = true;
621*8975f5c5SAndroid Build Coastguard Worker             return angle::Result::Continue;
622*8975f5c5SAndroid Build Coastguard Worker         }
623*8975f5c5SAndroid Build Coastguard Worker         mStagingBuffer.release(contextVk->getRenderer());
624*8975f5c5SAndroid Build Coastguard Worker     }
625*8975f5c5SAndroid Build Coastguard Worker 
626*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(
627*8975f5c5SAndroid Build Coastguard Worker         contextVk->initBufferForBufferCopy(&mStagingBuffer, static_cast<size_t>(size), coherency));
628*8975f5c5SAndroid Build Coastguard Worker     *mapPtr                = mStagingBuffer.getMappedMemory();
629*8975f5c5SAndroid Build Coastguard Worker     mIsStagingBufferMapped = true;
630*8975f5c5SAndroid Build Coastguard Worker 
631*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
632*8975f5c5SAndroid Build Coastguard Worker }
633*8975f5c5SAndroid Build Coastguard Worker 
flushStagingBuffer(ContextVk * contextVk,VkDeviceSize offset,VkDeviceSize size)634*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::flushStagingBuffer(ContextVk *contextVk,
635*8975f5c5SAndroid Build Coastguard Worker                                            VkDeviceSize offset,
636*8975f5c5SAndroid Build Coastguard Worker                                            VkDeviceSize size)
637*8975f5c5SAndroid Build Coastguard Worker {
638*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
639*8975f5c5SAndroid Build Coastguard Worker 
640*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mIsStagingBufferMapped);
641*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mStagingBuffer.valid());
642*8975f5c5SAndroid Build Coastguard Worker 
643*8975f5c5SAndroid Build Coastguard Worker     if (!mStagingBuffer.isCoherent())
644*8975f5c5SAndroid Build Coastguard Worker     {
645*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mStagingBuffer.flush(renderer));
646*8975f5c5SAndroid Build Coastguard Worker     }
647*8975f5c5SAndroid Build Coastguard Worker 
648*8975f5c5SAndroid Build Coastguard Worker     VkBufferCopy copyRegion = {mStagingBuffer.getOffset(), mBuffer.getOffset() + offset, size};
649*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(CopyBuffers(contextVk, &mStagingBuffer, &mBuffer, 1, &copyRegion));
650*8975f5c5SAndroid Build Coastguard Worker 
651*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
652*8975f5c5SAndroid Build Coastguard Worker }
653*8975f5c5SAndroid Build Coastguard Worker 
handleDeviceLocalBufferMap(ContextVk * contextVk,VkDeviceSize offset,VkDeviceSize size,uint8_t ** mapPtr)654*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::handleDeviceLocalBufferMap(ContextVk *contextVk,
655*8975f5c5SAndroid Build Coastguard Worker                                                    VkDeviceSize offset,
656*8975f5c5SAndroid Build Coastguard Worker                                                    VkDeviceSize size,
657*8975f5c5SAndroid Build Coastguard Worker                                                    uint8_t **mapPtr)
658*8975f5c5SAndroid Build Coastguard Worker {
659*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
660*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(
661*8975f5c5SAndroid Build Coastguard Worker         allocStagingBuffer(contextVk, vk::MemoryCoherency::CachedPreferCoherent, size, mapPtr));
662*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mStagingBuffer.flush(renderer));
663*8975f5c5SAndroid Build Coastguard Worker 
664*8975f5c5SAndroid Build Coastguard Worker     // Copy data from device local buffer to host visible staging buffer.
665*8975f5c5SAndroid Build Coastguard Worker     VkBufferCopy copyRegion = {mBuffer.getOffset() + offset, mStagingBuffer.getOffset(), size};
666*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(CopyBuffers(contextVk, &mBuffer, &mStagingBuffer, 1, &copyRegion));
667*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mStagingBuffer.waitForIdle(contextVk, "GPU stall due to mapping device local buffer",
668*8975f5c5SAndroid Build Coastguard Worker                                          RenderPassClosureReason::DeviceLocalBufferMap));
669*8975f5c5SAndroid Build Coastguard Worker     // Since coherent is prefer, we may end up getting non-coherent. Always call invalidate here (it
670*8975f5c5SAndroid Build Coastguard Worker     // will check memory flag before it actually calls into driver).
671*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mStagingBuffer.invalidate(renderer));
672*8975f5c5SAndroid Build Coastguard Worker 
673*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
674*8975f5c5SAndroid Build Coastguard Worker }
675*8975f5c5SAndroid Build Coastguard Worker 
mapHostVisibleBuffer(ContextVk * contextVk,VkDeviceSize offset,GLbitfield access,uint8_t ** mapPtr)676*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::mapHostVisibleBuffer(ContextVk *contextVk,
677*8975f5c5SAndroid Build Coastguard Worker                                              VkDeviceSize offset,
678*8975f5c5SAndroid Build Coastguard Worker                                              GLbitfield access,
679*8975f5c5SAndroid Build Coastguard Worker                                              uint8_t **mapPtr)
680*8975f5c5SAndroid Build Coastguard Worker {
681*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mBuffer.mapWithOffset(contextVk, mapPtr, static_cast<size_t>(offset)));
682*8975f5c5SAndroid Build Coastguard Worker 
683*8975f5c5SAndroid Build Coastguard Worker     // Invalidate non-coherent for READ case.
684*8975f5c5SAndroid Build Coastguard Worker     if (!mBuffer.isCoherent() && (access & GL_MAP_READ_BIT) != 0)
685*8975f5c5SAndroid Build Coastguard Worker     {
686*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mBuffer.invalidate(contextVk->getRenderer()));
687*8975f5c5SAndroid Build Coastguard Worker     }
688*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
689*8975f5c5SAndroid Build Coastguard Worker }
690*8975f5c5SAndroid Build Coastguard Worker 
map(const gl::Context * context,GLenum access,void ** mapPtr)691*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::map(const gl::Context *context, GLenum access, void **mapPtr)
692*8975f5c5SAndroid Build Coastguard Worker {
693*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
694*8975f5c5SAndroid Build Coastguard Worker     ASSERT(access == GL_WRITE_ONLY_OES);
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker     return mapImpl(vk::GetImpl(context), GL_MAP_WRITE_BIT, mapPtr);
697*8975f5c5SAndroid Build Coastguard Worker }
698*8975f5c5SAndroid Build Coastguard Worker 
mapRange(const gl::Context * context,size_t offset,size_t length,GLbitfield access,void ** mapPtr)699*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::mapRange(const gl::Context *context,
700*8975f5c5SAndroid Build Coastguard Worker                                  size_t offset,
701*8975f5c5SAndroid Build Coastguard Worker                                  size_t length,
702*8975f5c5SAndroid Build Coastguard Worker                                  GLbitfield access,
703*8975f5c5SAndroid Build Coastguard Worker                                  void **mapPtr)
704*8975f5c5SAndroid Build Coastguard Worker {
705*8975f5c5SAndroid Build Coastguard Worker     return mapRangeImpl(vk::GetImpl(context), offset, length, access, mapPtr);
706*8975f5c5SAndroid Build Coastguard Worker }
707*8975f5c5SAndroid Build Coastguard Worker 
mapImpl(ContextVk * contextVk,GLbitfield access,void ** mapPtr)708*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::mapImpl(ContextVk *contextVk, GLbitfield access, void **mapPtr)
709*8975f5c5SAndroid Build Coastguard Worker {
710*8975f5c5SAndroid Build Coastguard Worker     return mapRangeImpl(contextVk, 0, static_cast<VkDeviceSize>(mState.getSize()), access, mapPtr);
711*8975f5c5SAndroid Build Coastguard Worker }
712*8975f5c5SAndroid Build Coastguard Worker 
ghostMappedBuffer(ContextVk * contextVk,VkDeviceSize offset,VkDeviceSize length,GLbitfield access,void ** mapPtr)713*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::ghostMappedBuffer(ContextVk *contextVk,
714*8975f5c5SAndroid Build Coastguard Worker                                           VkDeviceSize offset,
715*8975f5c5SAndroid Build Coastguard Worker                                           VkDeviceSize length,
716*8975f5c5SAndroid Build Coastguard Worker                                           GLbitfield access,
717*8975f5c5SAndroid Build Coastguard Worker                                           void **mapPtr)
718*8975f5c5SAndroid Build Coastguard Worker {
719*8975f5c5SAndroid Build Coastguard Worker     // We shouldn't get here if it is external memory
720*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isExternalBuffer());
721*8975f5c5SAndroid Build Coastguard Worker 
722*8975f5c5SAndroid Build Coastguard Worker     ++contextVk->getPerfCounters().buffersGhosted;
723*8975f5c5SAndroid Build Coastguard Worker 
724*8975f5c5SAndroid Build Coastguard Worker     // If we are creating a new buffer because the GPU is using it as read-only, then we
725*8975f5c5SAndroid Build Coastguard Worker     // also need to copy the contents of the previous buffer into the new buffer, in
726*8975f5c5SAndroid Build Coastguard Worker     // case the caller only updates a portion of the new buffer.
727*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper src = std::move(mBuffer);
728*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(acquireBufferHelper(contextVk, static_cast<size_t>(mState.getSize()),
729*8975f5c5SAndroid Build Coastguard Worker                                   BufferUsageType::Dynamic));
730*8975f5c5SAndroid Build Coastguard Worker 
731*8975f5c5SAndroid Build Coastguard Worker     // Before returning the new buffer, map the previous buffer and copy its entire
732*8975f5c5SAndroid Build Coastguard Worker     // contents into the new buffer.
733*8975f5c5SAndroid Build Coastguard Worker     uint8_t *srcMapPtr = nullptr;
734*8975f5c5SAndroid Build Coastguard Worker     uint8_t *dstMapPtr = nullptr;
735*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(src.map(contextVk, &srcMapPtr));
736*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mBuffer.map(contextVk, &dstMapPtr));
737*8975f5c5SAndroid Build Coastguard Worker 
738*8975f5c5SAndroid Build Coastguard Worker     ASSERT(src.isCoherent());
739*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.isCoherent());
740*8975f5c5SAndroid Build Coastguard Worker 
741*8975f5c5SAndroid Build Coastguard Worker     // No need to copy over [offset, offset + length), just around it
742*8975f5c5SAndroid Build Coastguard Worker     if ((access & GL_MAP_INVALIDATE_RANGE_BIT) != 0)
743*8975f5c5SAndroid Build Coastguard Worker     {
744*8975f5c5SAndroid Build Coastguard Worker         if (offset != 0)
745*8975f5c5SAndroid Build Coastguard Worker         {
746*8975f5c5SAndroid Build Coastguard Worker             memcpy(dstMapPtr, srcMapPtr, static_cast<size_t>(offset));
747*8975f5c5SAndroid Build Coastguard Worker         }
748*8975f5c5SAndroid Build Coastguard Worker         size_t totalSize      = static_cast<size_t>(mState.getSize());
749*8975f5c5SAndroid Build Coastguard Worker         size_t remainingStart = static_cast<size_t>(offset + length);
750*8975f5c5SAndroid Build Coastguard Worker         size_t remainingSize  = totalSize - remainingStart;
751*8975f5c5SAndroid Build Coastguard Worker         if (remainingSize != 0)
752*8975f5c5SAndroid Build Coastguard Worker         {
753*8975f5c5SAndroid Build Coastguard Worker             memcpy(dstMapPtr + remainingStart, srcMapPtr + remainingStart, remainingSize);
754*8975f5c5SAndroid Build Coastguard Worker         }
755*8975f5c5SAndroid Build Coastguard Worker     }
756*8975f5c5SAndroid Build Coastguard Worker     else
757*8975f5c5SAndroid Build Coastguard Worker     {
758*8975f5c5SAndroid Build Coastguard Worker         memcpy(dstMapPtr, srcMapPtr, static_cast<size_t>(mState.getSize()));
759*8975f5c5SAndroid Build Coastguard Worker     }
760*8975f5c5SAndroid Build Coastguard Worker 
761*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->releaseBufferAllocation(&src));
762*8975f5c5SAndroid Build Coastguard Worker 
763*8975f5c5SAndroid Build Coastguard Worker     // Return the already mapped pointer with the offset adjustment to avoid the call to unmap().
764*8975f5c5SAndroid Build Coastguard Worker     *mapPtr = dstMapPtr + offset;
765*8975f5c5SAndroid Build Coastguard Worker 
766*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
767*8975f5c5SAndroid Build Coastguard Worker }
768*8975f5c5SAndroid Build Coastguard Worker 
mapRangeImpl(ContextVk * contextVk,VkDeviceSize offset,VkDeviceSize length,GLbitfield access,void ** mapPtr)769*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::mapRangeImpl(ContextVk *contextVk,
770*8975f5c5SAndroid Build Coastguard Worker                                      VkDeviceSize offset,
771*8975f5c5SAndroid Build Coastguard Worker                                      VkDeviceSize length,
772*8975f5c5SAndroid Build Coastguard Worker                                      GLbitfield access,
773*8975f5c5SAndroid Build Coastguard Worker                                      void **mapPtr)
774*8975f5c5SAndroid Build Coastguard Worker {
775*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
776*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
777*8975f5c5SAndroid Build Coastguard Worker 
778*8975f5c5SAndroid Build Coastguard Worker     // Record map call parameters in case this call is from angle internal (the access/offset/length
779*8975f5c5SAndroid Build Coastguard Worker     // will be inconsistent from mState).
780*8975f5c5SAndroid Build Coastguard Worker     mIsMappedForWrite = (access & GL_MAP_WRITE_BIT) != 0;
781*8975f5c5SAndroid Build Coastguard Worker     mMappedRange      = RangeDeviceSize(offset, offset + length);
782*8975f5c5SAndroid Build Coastguard Worker 
783*8975f5c5SAndroid Build Coastguard Worker     uint8_t **mapPtrBytes = reinterpret_cast<uint8_t **>(mapPtr);
784*8975f5c5SAndroid Build Coastguard Worker     bool hostVisible      = mBuffer.isHostVisible();
785*8975f5c5SAndroid Build Coastguard Worker 
786*8975f5c5SAndroid Build Coastguard Worker     // MAP_UNSYNCHRONIZED_BIT, so immediately map.
787*8975f5c5SAndroid Build Coastguard Worker     if ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0)
788*8975f5c5SAndroid Build Coastguard Worker     {
789*8975f5c5SAndroid Build Coastguard Worker         if (hostVisible)
790*8975f5c5SAndroid Build Coastguard Worker         {
791*8975f5c5SAndroid Build Coastguard Worker             return mapHostVisibleBuffer(contextVk, offset, access, mapPtrBytes);
792*8975f5c5SAndroid Build Coastguard Worker         }
793*8975f5c5SAndroid Build Coastguard Worker         return handleDeviceLocalBufferMap(contextVk, offset, length, mapPtrBytes);
794*8975f5c5SAndroid Build Coastguard Worker     }
795*8975f5c5SAndroid Build Coastguard Worker 
796*8975f5c5SAndroid Build Coastguard Worker     // Read case
797*8975f5c5SAndroid Build Coastguard Worker     if ((access & GL_MAP_WRITE_BIT) == 0)
798*8975f5c5SAndroid Build Coastguard Worker     {
799*8975f5c5SAndroid Build Coastguard Worker         // If app is not going to write, all we need is to ensure GPU write is finished.
800*8975f5c5SAndroid Build Coastguard Worker         // Concurrent reads from CPU and GPU is allowed.
801*8975f5c5SAndroid Build Coastguard Worker         if (!renderer->hasResourceUseFinished(mBuffer.getWriteResourceUse()))
802*8975f5c5SAndroid Build Coastguard Worker         {
803*8975f5c5SAndroid Build Coastguard Worker             // If there are unflushed write commands for the resource, flush them.
804*8975f5c5SAndroid Build Coastguard Worker             if (contextVk->hasUnsubmittedUse(mBuffer.getWriteResourceUse()))
805*8975f5c5SAndroid Build Coastguard Worker             {
806*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(contextVk->flushAndSubmitCommands(
807*8975f5c5SAndroid Build Coastguard Worker                     nullptr, nullptr, RenderPassClosureReason::BufferWriteThenMap));
808*8975f5c5SAndroid Build Coastguard Worker             }
809*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(renderer->finishResourceUse(contextVk, mBuffer.getWriteResourceUse()));
810*8975f5c5SAndroid Build Coastguard Worker         }
811*8975f5c5SAndroid Build Coastguard Worker         if (hostVisible)
812*8975f5c5SAndroid Build Coastguard Worker         {
813*8975f5c5SAndroid Build Coastguard Worker             return mapHostVisibleBuffer(contextVk, offset, access, mapPtrBytes);
814*8975f5c5SAndroid Build Coastguard Worker         }
815*8975f5c5SAndroid Build Coastguard Worker         return handleDeviceLocalBufferMap(contextVk, offset, length, mapPtrBytes);
816*8975f5c5SAndroid Build Coastguard Worker     }
817*8975f5c5SAndroid Build Coastguard Worker 
818*8975f5c5SAndroid Build Coastguard Worker     // Write case
819*8975f5c5SAndroid Build Coastguard Worker     if (!hostVisible)
820*8975f5c5SAndroid Build Coastguard Worker     {
821*8975f5c5SAndroid Build Coastguard Worker         return handleDeviceLocalBufferMap(contextVk, offset, length, mapPtrBytes);
822*8975f5c5SAndroid Build Coastguard Worker     }
823*8975f5c5SAndroid Build Coastguard Worker 
824*8975f5c5SAndroid Build Coastguard Worker     // Write case, buffer not in use.
825*8975f5c5SAndroid Build Coastguard Worker     if (isExternalBuffer() || !isCurrentlyInUse(contextVk->getRenderer()))
826*8975f5c5SAndroid Build Coastguard Worker     {
827*8975f5c5SAndroid Build Coastguard Worker         return mapHostVisibleBuffer(contextVk, offset, access, mapPtrBytes);
828*8975f5c5SAndroid Build Coastguard Worker     }
829*8975f5c5SAndroid Build Coastguard Worker 
830*8975f5c5SAndroid Build Coastguard Worker     // Write case, buffer in use.
831*8975f5c5SAndroid Build Coastguard Worker     //
832*8975f5c5SAndroid Build Coastguard Worker     // Here, we try to map the buffer, but it's busy. Instead of waiting for the GPU to
833*8975f5c5SAndroid Build Coastguard Worker     // finish, we just allocate a new buffer if:
834*8975f5c5SAndroid Build Coastguard Worker     // 1.) Caller has told us it doesn't care about previous contents, or
835*8975f5c5SAndroid Build Coastguard Worker     // 2.) The GPU won't write to the buffer.
836*8975f5c5SAndroid Build Coastguard Worker 
837*8975f5c5SAndroid Build Coastguard Worker     bool rangeInvalidate = (access & GL_MAP_INVALIDATE_RANGE_BIT) != 0;
838*8975f5c5SAndroid Build Coastguard Worker     bool entireBufferInvalidated =
839*8975f5c5SAndroid Build Coastguard Worker         ((access & GL_MAP_INVALIDATE_BUFFER_BIT) != 0) ||
840*8975f5c5SAndroid Build Coastguard Worker         (rangeInvalidate && offset == 0 && static_cast<VkDeviceSize>(mState.getSize()) == length);
841*8975f5c5SAndroid Build Coastguard Worker 
842*8975f5c5SAndroid Build Coastguard Worker     if (entireBufferInvalidated)
843*8975f5c5SAndroid Build Coastguard Worker     {
844*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(acquireBufferHelper(contextVk, static_cast<size_t>(mState.getSize()),
845*8975f5c5SAndroid Build Coastguard Worker                                       BufferUsageType::Dynamic));
846*8975f5c5SAndroid Build Coastguard Worker         return mapHostVisibleBuffer(contextVk, offset, access, mapPtrBytes);
847*8975f5c5SAndroid Build Coastguard Worker     }
848*8975f5c5SAndroid Build Coastguard Worker 
849*8975f5c5SAndroid Build Coastguard Worker     bool smallMapRange = (length < static_cast<VkDeviceSize>(mState.getSize()) / 2);
850*8975f5c5SAndroid Build Coastguard Worker 
851*8975f5c5SAndroid Build Coastguard Worker     if (smallMapRange && rangeInvalidate)
852*8975f5c5SAndroid Build Coastguard Worker     {
853*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(allocStagingBuffer(contextVk, vk::MemoryCoherency::CachedNonCoherent,
854*8975f5c5SAndroid Build Coastguard Worker                                      static_cast<size_t>(length), mapPtrBytes));
855*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
856*8975f5c5SAndroid Build Coastguard Worker     }
857*8975f5c5SAndroid Build Coastguard Worker 
858*8975f5c5SAndroid Build Coastguard Worker     if (renderer->hasResourceUseFinished(mBuffer.getWriteResourceUse()))
859*8975f5c5SAndroid Build Coastguard Worker     {
860*8975f5c5SAndroid Build Coastguard Worker         // This will keep the new buffer mapped and update mapPtr, so return immediately.
861*8975f5c5SAndroid Build Coastguard Worker         return ghostMappedBuffer(contextVk, offset, length, access, mapPtr);
862*8975f5c5SAndroid Build Coastguard Worker     }
863*8975f5c5SAndroid Build Coastguard Worker 
864*8975f5c5SAndroid Build Coastguard Worker     // Write case (worst case, buffer in use for write)
865*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mBuffer.waitForIdle(contextVk, "GPU stall due to mapping buffer in use by the GPU",
866*8975f5c5SAndroid Build Coastguard Worker                                   RenderPassClosureReason::BufferInUseWhenSynchronizedMap));
867*8975f5c5SAndroid Build Coastguard Worker     return mapHostVisibleBuffer(contextVk, offset, access, mapPtrBytes);
868*8975f5c5SAndroid Build Coastguard Worker }
869*8975f5c5SAndroid Build Coastguard Worker 
unmap(const gl::Context * context,GLboolean * result)870*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::unmap(const gl::Context *context, GLboolean *result)
871*8975f5c5SAndroid Build Coastguard Worker {
872*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(unmapImpl(vk::GetImpl(context)));
873*8975f5c5SAndroid Build Coastguard Worker 
874*8975f5c5SAndroid Build Coastguard Worker     // This should be false if the contents have been corrupted through external means.  Vulkan
875*8975f5c5SAndroid Build Coastguard Worker     // doesn't provide such information.
876*8975f5c5SAndroid Build Coastguard Worker     *result = true;
877*8975f5c5SAndroid Build Coastguard Worker 
878*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
879*8975f5c5SAndroid Build Coastguard Worker }
880*8975f5c5SAndroid Build Coastguard Worker 
unmapImpl(ContextVk * contextVk)881*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::unmapImpl(ContextVk *contextVk)
882*8975f5c5SAndroid Build Coastguard Worker {
883*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
884*8975f5c5SAndroid Build Coastguard Worker 
885*8975f5c5SAndroid Build Coastguard Worker     if (mIsStagingBufferMapped)
886*8975f5c5SAndroid Build Coastguard Worker     {
887*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mStagingBuffer.valid());
888*8975f5c5SAndroid Build Coastguard Worker         // The buffer is device local or optimization of small range map.
889*8975f5c5SAndroid Build Coastguard Worker         if (mIsMappedForWrite)
890*8975f5c5SAndroid Build Coastguard Worker         {
891*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(flushStagingBuffer(contextVk, mMappedRange.low(), mMappedRange.length()));
892*8975f5c5SAndroid Build Coastguard Worker         }
893*8975f5c5SAndroid Build Coastguard Worker 
894*8975f5c5SAndroid Build Coastguard Worker         mIsStagingBufferMapped = false;
895*8975f5c5SAndroid Build Coastguard Worker     }
896*8975f5c5SAndroid Build Coastguard Worker     else
897*8975f5c5SAndroid Build Coastguard Worker     {
898*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mBuffer.isHostVisible());
899*8975f5c5SAndroid Build Coastguard Worker         vk::Renderer *renderer = contextVk->getRenderer();
900*8975f5c5SAndroid Build Coastguard Worker         if (!mBuffer.isCoherent())
901*8975f5c5SAndroid Build Coastguard Worker         {
902*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(mBuffer.flush(renderer));
903*8975f5c5SAndroid Build Coastguard Worker         }
904*8975f5c5SAndroid Build Coastguard Worker         mBuffer.unmap(renderer);
905*8975f5c5SAndroid Build Coastguard Worker     }
906*8975f5c5SAndroid Build Coastguard Worker 
907*8975f5c5SAndroid Build Coastguard Worker     if (mIsMappedForWrite)
908*8975f5c5SAndroid Build Coastguard Worker     {
909*8975f5c5SAndroid Build Coastguard Worker         if (mMappedRange == RangeDeviceSize(0, static_cast<VkDeviceSize>(getSize())))
910*8975f5c5SAndroid Build Coastguard Worker         {
911*8975f5c5SAndroid Build Coastguard Worker             dataUpdated();
912*8975f5c5SAndroid Build Coastguard Worker         }
913*8975f5c5SAndroid Build Coastguard Worker         else
914*8975f5c5SAndroid Build Coastguard Worker         {
915*8975f5c5SAndroid Build Coastguard Worker             dataRangeUpdated(mMappedRange);
916*8975f5c5SAndroid Build Coastguard Worker         }
917*8975f5c5SAndroid Build Coastguard Worker     }
918*8975f5c5SAndroid Build Coastguard Worker 
919*8975f5c5SAndroid Build Coastguard Worker     // Reset the mapping parameters
920*8975f5c5SAndroid Build Coastguard Worker     mIsMappedForWrite = false;
921*8975f5c5SAndroid Build Coastguard Worker     mMappedRange.invalidate();
922*8975f5c5SAndroid Build Coastguard Worker 
923*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
924*8975f5c5SAndroid Build Coastguard Worker }
925*8975f5c5SAndroid Build Coastguard Worker 
getSubData(const gl::Context * context,GLintptr offset,GLsizeiptr size,void * outData)926*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::getSubData(const gl::Context *context,
927*8975f5c5SAndroid Build Coastguard Worker                                    GLintptr offset,
928*8975f5c5SAndroid Build Coastguard Worker                                    GLsizeiptr size,
929*8975f5c5SAndroid Build Coastguard Worker                                    void *outData)
930*8975f5c5SAndroid Build Coastguard Worker {
931*8975f5c5SAndroid Build Coastguard Worker     ASSERT(offset + size <= getSize());
932*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
933*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
934*8975f5c5SAndroid Build Coastguard Worker     void *mapPtr;
935*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mapRangeImpl(contextVk, offset, size, GL_MAP_READ_BIT, &mapPtr));
936*8975f5c5SAndroid Build Coastguard Worker     memcpy(outData, mapPtr, size);
937*8975f5c5SAndroid Build Coastguard Worker     return unmapImpl(contextVk);
938*8975f5c5SAndroid Build Coastguard Worker }
939*8975f5c5SAndroid Build Coastguard Worker 
getIndexRange(const gl::Context * context,gl::DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,gl::IndexRange * outRange)940*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::getIndexRange(const gl::Context *context,
941*8975f5c5SAndroid Build Coastguard Worker                                       gl::DrawElementsType type,
942*8975f5c5SAndroid Build Coastguard Worker                                       size_t offset,
943*8975f5c5SAndroid Build Coastguard Worker                                       size_t count,
944*8975f5c5SAndroid Build Coastguard Worker                                       bool primitiveRestartEnabled,
945*8975f5c5SAndroid Build Coastguard Worker                                       gl::IndexRange *outRange)
946*8975f5c5SAndroid Build Coastguard Worker {
947*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk   = vk::GetImpl(context);
948*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
949*8975f5c5SAndroid Build Coastguard Worker 
950*8975f5c5SAndroid Build Coastguard Worker     // This is a workaround for the mock ICD not implementing buffer memory state.
951*8975f5c5SAndroid Build Coastguard Worker     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
952*8975f5c5SAndroid Build Coastguard Worker     if (renderer->isMockICDEnabled())
953*8975f5c5SAndroid Build Coastguard Worker     {
954*8975f5c5SAndroid Build Coastguard Worker         outRange->start = 0;
955*8975f5c5SAndroid Build Coastguard Worker         outRange->end   = 0;
956*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
957*8975f5c5SAndroid Build Coastguard Worker     }
958*8975f5c5SAndroid Build Coastguard Worker 
959*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "BufferVk::getIndexRange");
960*8975f5c5SAndroid Build Coastguard Worker 
961*8975f5c5SAndroid Build Coastguard Worker     void *mapPtr;
962*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mapRangeImpl(contextVk, offset, getSize(), GL_MAP_READ_BIT, &mapPtr));
963*8975f5c5SAndroid Build Coastguard Worker     *outRange = gl::ComputeIndexRange(type, mapPtr, count, primitiveRestartEnabled);
964*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(unmapImpl(contextVk));
965*8975f5c5SAndroid Build Coastguard Worker 
966*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
967*8975f5c5SAndroid Build Coastguard Worker }
968*8975f5c5SAndroid Build Coastguard Worker 
updateBuffer(ContextVk * contextVk,size_t bufferSize,const BufferDataSource & dataSource,size_t updateSize,size_t updateOffset)969*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::updateBuffer(ContextVk *contextVk,
970*8975f5c5SAndroid Build Coastguard Worker                                      size_t bufferSize,
971*8975f5c5SAndroid Build Coastguard Worker                                      const BufferDataSource &dataSource,
972*8975f5c5SAndroid Build Coastguard Worker                                      size_t updateSize,
973*8975f5c5SAndroid Build Coastguard Worker                                      size_t updateOffset)
974*8975f5c5SAndroid Build Coastguard Worker {
975*8975f5c5SAndroid Build Coastguard Worker     // To copy on the CPU, destination must be host-visible.  The source should also be either a CPU
976*8975f5c5SAndroid Build Coastguard Worker     // pointer or other a host-visible buffer that is not being written to by the GPU.
977*8975f5c5SAndroid Build Coastguard Worker     const bool shouldCopyOnCPU =
978*8975f5c5SAndroid Build Coastguard Worker         mBuffer.isHostVisible() &&
979*8975f5c5SAndroid Build Coastguard Worker         (dataSource.data != nullptr ||
980*8975f5c5SAndroid Build Coastguard Worker          ShouldUseCPUToCopyData(contextVk, *dataSource.buffer, updateSize, bufferSize));
981*8975f5c5SAndroid Build Coastguard Worker 
982*8975f5c5SAndroid Build Coastguard Worker     if (shouldCopyOnCPU)
983*8975f5c5SAndroid Build Coastguard Worker     {
984*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(directUpdate(contextVk, dataSource, updateSize, updateOffset));
985*8975f5c5SAndroid Build Coastguard Worker     }
986*8975f5c5SAndroid Build Coastguard Worker     else
987*8975f5c5SAndroid Build Coastguard Worker     {
988*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(stagedUpdate(contextVk, dataSource, updateSize, updateOffset));
989*8975f5c5SAndroid Build Coastguard Worker     }
990*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
991*8975f5c5SAndroid Build Coastguard Worker }
992*8975f5c5SAndroid Build Coastguard Worker 
directUpdate(ContextVk * contextVk,const BufferDataSource & dataSource,size_t size,size_t offset)993*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::directUpdate(ContextVk *contextVk,
994*8975f5c5SAndroid Build Coastguard Worker                                      const BufferDataSource &dataSource,
995*8975f5c5SAndroid Build Coastguard Worker                                      size_t size,
996*8975f5c5SAndroid Build Coastguard Worker                                      size_t offset)
997*8975f5c5SAndroid Build Coastguard Worker {
998*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer    = contextVk->getRenderer();
999*8975f5c5SAndroid Build Coastguard Worker     uint8_t *srcPointerMapped = nullptr;
1000*8975f5c5SAndroid Build Coastguard Worker     const uint8_t *srcPointer = nullptr;
1001*8975f5c5SAndroid Build Coastguard Worker     uint8_t *dstPointer       = nullptr;
1002*8975f5c5SAndroid Build Coastguard Worker 
1003*8975f5c5SAndroid Build Coastguard Worker     // Map the destination buffer.
1004*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.isHostVisible());
1005*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mBuffer.mapWithOffset(contextVk, &dstPointer, offset));
1006*8975f5c5SAndroid Build Coastguard Worker     ASSERT(dstPointer);
1007*8975f5c5SAndroid Build Coastguard Worker 
1008*8975f5c5SAndroid Build Coastguard Worker     // If source data is coming from a buffer, map it.  If this is a self-copy, avoid double-mapping
1009*8975f5c5SAndroid Build Coastguard Worker     // the buffer.
1010*8975f5c5SAndroid Build Coastguard Worker     if (dataSource.data != nullptr)
1011*8975f5c5SAndroid Build Coastguard Worker     {
1012*8975f5c5SAndroid Build Coastguard Worker         srcPointer = static_cast<const uint8_t *>(dataSource.data);
1013*8975f5c5SAndroid Build Coastguard Worker     }
1014*8975f5c5SAndroid Build Coastguard Worker     else
1015*8975f5c5SAndroid Build Coastguard Worker     {
1016*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(dataSource.buffer->mapWithOffset(contextVk, &srcPointerMapped,
1017*8975f5c5SAndroid Build Coastguard Worker                                                    static_cast<size_t>(dataSource.bufferOffset)));
1018*8975f5c5SAndroid Build Coastguard Worker         srcPointer = srcPointerMapped;
1019*8975f5c5SAndroid Build Coastguard Worker     }
1020*8975f5c5SAndroid Build Coastguard Worker 
1021*8975f5c5SAndroid Build Coastguard Worker     memcpy(dstPointer, srcPointer, size);
1022*8975f5c5SAndroid Build Coastguard Worker 
1023*8975f5c5SAndroid Build Coastguard Worker     // External memory may end up with noncoherent
1024*8975f5c5SAndroid Build Coastguard Worker     if (!mBuffer.isCoherent())
1025*8975f5c5SAndroid Build Coastguard Worker     {
1026*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mBuffer.flush(renderer, offset, size));
1027*8975f5c5SAndroid Build Coastguard Worker     }
1028*8975f5c5SAndroid Build Coastguard Worker 
1029*8975f5c5SAndroid Build Coastguard Worker     // Unmap the destination and source buffers if applicable.
1030*8975f5c5SAndroid Build Coastguard Worker     //
1031*8975f5c5SAndroid Build Coastguard Worker     // If the buffer has dynamic usage then the intent is frequent client side updates to the
1032*8975f5c5SAndroid Build Coastguard Worker     // buffer. Don't CPU unmap the buffer, we will take care of unmapping when releasing the buffer
1033*8975f5c5SAndroid Build Coastguard Worker     // to either the renderer or mBufferFreeList.
1034*8975f5c5SAndroid Build Coastguard Worker     if (GetBufferUsageType(mState.getUsage()) == BufferUsageType::Static)
1035*8975f5c5SAndroid Build Coastguard Worker     {
1036*8975f5c5SAndroid Build Coastguard Worker         mBuffer.unmap(renderer);
1037*8975f5c5SAndroid Build Coastguard Worker     }
1038*8975f5c5SAndroid Build Coastguard Worker 
1039*8975f5c5SAndroid Build Coastguard Worker     if (srcPointerMapped != nullptr)
1040*8975f5c5SAndroid Build Coastguard Worker     {
1041*8975f5c5SAndroid Build Coastguard Worker         dataSource.buffer->unmap(renderer);
1042*8975f5c5SAndroid Build Coastguard Worker     }
1043*8975f5c5SAndroid Build Coastguard Worker 
1044*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1045*8975f5c5SAndroid Build Coastguard Worker }
1046*8975f5c5SAndroid Build Coastguard Worker 
stagedUpdate(ContextVk * contextVk,const BufferDataSource & dataSource,size_t size,size_t offset)1047*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::stagedUpdate(ContextVk *contextVk,
1048*8975f5c5SAndroid Build Coastguard Worker                                      const BufferDataSource &dataSource,
1049*8975f5c5SAndroid Build Coastguard Worker                                      size_t size,
1050*8975f5c5SAndroid Build Coastguard Worker                                      size_t offset)
1051*8975f5c5SAndroid Build Coastguard Worker {
1052*8975f5c5SAndroid Build Coastguard Worker     // If data is coming from a CPU pointer, stage it in a temporary staging buffer.
1053*8975f5c5SAndroid Build Coastguard Worker     // Otherwise, do a GPU copy directly from the given buffer.
1054*8975f5c5SAndroid Build Coastguard Worker     if (dataSource.data != nullptr)
1055*8975f5c5SAndroid Build Coastguard Worker     {
1056*8975f5c5SAndroid Build Coastguard Worker         uint8_t *mapPointer = nullptr;
1057*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(allocStagingBuffer(contextVk, vk::MemoryCoherency::CachedNonCoherent, size,
1058*8975f5c5SAndroid Build Coastguard Worker                                      &mapPointer));
1059*8975f5c5SAndroid Build Coastguard Worker         memcpy(mapPointer, dataSource.data, size);
1060*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(flushStagingBuffer(contextVk, offset, size));
1061*8975f5c5SAndroid Build Coastguard Worker         mIsStagingBufferMapped = false;
1062*8975f5c5SAndroid Build Coastguard Worker     }
1063*8975f5c5SAndroid Build Coastguard Worker     else
1064*8975f5c5SAndroid Build Coastguard Worker     {
1065*8975f5c5SAndroid Build Coastguard Worker         // Check for self-dependency.
1066*8975f5c5SAndroid Build Coastguard Worker         vk::CommandBufferAccess access;
1067*8975f5c5SAndroid Build Coastguard Worker         if (dataSource.buffer->getBufferSerial() == mBuffer.getBufferSerial())
1068*8975f5c5SAndroid Build Coastguard Worker         {
1069*8975f5c5SAndroid Build Coastguard Worker             access.onBufferSelfCopy(&mBuffer);
1070*8975f5c5SAndroid Build Coastguard Worker         }
1071*8975f5c5SAndroid Build Coastguard Worker         else
1072*8975f5c5SAndroid Build Coastguard Worker         {
1073*8975f5c5SAndroid Build Coastguard Worker             access.onBufferTransferRead(dataSource.buffer);
1074*8975f5c5SAndroid Build Coastguard Worker             access.onBufferTransferWrite(&mBuffer);
1075*8975f5c5SAndroid Build Coastguard Worker         }
1076*8975f5c5SAndroid Build Coastguard Worker 
1077*8975f5c5SAndroid Build Coastguard Worker         vk::OutsideRenderPassCommandBuffer *commandBuffer;
1078*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1079*8975f5c5SAndroid Build Coastguard Worker 
1080*8975f5c5SAndroid Build Coastguard Worker         // Enqueue a copy command on the GPU.
1081*8975f5c5SAndroid Build Coastguard Worker         const VkBufferCopy copyRegion = {dataSource.bufferOffset + dataSource.buffer->getOffset(),
1082*8975f5c5SAndroid Build Coastguard Worker                                          static_cast<VkDeviceSize>(offset) + mBuffer.getOffset(),
1083*8975f5c5SAndroid Build Coastguard Worker                                          static_cast<VkDeviceSize>(size)};
1084*8975f5c5SAndroid Build Coastguard Worker 
1085*8975f5c5SAndroid Build Coastguard Worker         commandBuffer->copyBuffer(dataSource.buffer->getBuffer(), mBuffer.getBuffer(), 1,
1086*8975f5c5SAndroid Build Coastguard Worker                                   &copyRegion);
1087*8975f5c5SAndroid Build Coastguard Worker     }
1088*8975f5c5SAndroid Build Coastguard Worker 
1089*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1090*8975f5c5SAndroid Build Coastguard Worker }
1091*8975f5c5SAndroid Build Coastguard Worker 
acquireAndUpdate(ContextVk * contextVk,size_t bufferSize,const BufferDataSource & dataSource,size_t updateSize,size_t updateOffset,BufferUpdateType updateType)1092*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::acquireAndUpdate(ContextVk *contextVk,
1093*8975f5c5SAndroid Build Coastguard Worker                                          size_t bufferSize,
1094*8975f5c5SAndroid Build Coastguard Worker                                          const BufferDataSource &dataSource,
1095*8975f5c5SAndroid Build Coastguard Worker                                          size_t updateSize,
1096*8975f5c5SAndroid Build Coastguard Worker                                          size_t updateOffset,
1097*8975f5c5SAndroid Build Coastguard Worker                                          BufferUpdateType updateType)
1098*8975f5c5SAndroid Build Coastguard Worker {
1099*8975f5c5SAndroid Build Coastguard Worker     // We shouldn't get here if this is external memory
1100*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isExternalBuffer());
1101*8975f5c5SAndroid Build Coastguard Worker     // If StorageRedefined, we cannot use mState.getSize() to allocate a new buffer.
1102*8975f5c5SAndroid Build Coastguard Worker     ASSERT(updateType != BufferUpdateType::StorageRedefined);
1103*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.valid());
1104*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBuffer.getSize() >= bufferSize);
1105*8975f5c5SAndroid Build Coastguard Worker 
1106*8975f5c5SAndroid Build Coastguard Worker     // Here we acquire a new BufferHelper and directUpdate() the new buffer.
1107*8975f5c5SAndroid Build Coastguard Worker     // If the subData size was less than the buffer's size we additionally enqueue
1108*8975f5c5SAndroid Build Coastguard Worker     // a GPU copy of the remaining regions from the old mBuffer to the new one.
1109*8975f5c5SAndroid Build Coastguard Worker     vk::BufferHelper prevBuffer;
1110*8975f5c5SAndroid Build Coastguard Worker     size_t offsetAfterSubdata      = (updateOffset + updateSize);
1111*8975f5c5SAndroid Build Coastguard Worker     bool updateRegionBeforeSubData = mHasValidData && (updateOffset > 0);
1112*8975f5c5SAndroid Build Coastguard Worker     bool updateRegionAfterSubData  = mHasValidData && (offsetAfterSubdata < bufferSize);
1113*8975f5c5SAndroid Build Coastguard Worker 
1114*8975f5c5SAndroid Build Coastguard Worker     uint8_t *prevMapPtrBeforeSubData = nullptr;
1115*8975f5c5SAndroid Build Coastguard Worker     uint8_t *prevMapPtrAfterSubData  = nullptr;
1116*8975f5c5SAndroid Build Coastguard Worker     if (updateRegionBeforeSubData || updateRegionAfterSubData)
1117*8975f5c5SAndroid Build Coastguard Worker     {
1118*8975f5c5SAndroid Build Coastguard Worker         prevBuffer = std::move(mBuffer);
1119*8975f5c5SAndroid Build Coastguard Worker 
1120*8975f5c5SAndroid Build Coastguard Worker         // The total bytes that we need to copy from old buffer to new buffer
1121*8975f5c5SAndroid Build Coastguard Worker         size_t copySize = bufferSize - updateSize;
1122*8975f5c5SAndroid Build Coastguard Worker 
1123*8975f5c5SAndroid Build Coastguard Worker         // If the buffer is host visible and the GPU is not writing to it, we use the CPU to do the
1124*8975f5c5SAndroid Build Coastguard Worker         // copy. We need to save the source buffer pointer before we acquire a new buffer.
1125*8975f5c5SAndroid Build Coastguard Worker         if (ShouldUseCPUToCopyData(contextVk, prevBuffer, copySize, bufferSize))
1126*8975f5c5SAndroid Build Coastguard Worker         {
1127*8975f5c5SAndroid Build Coastguard Worker             uint8_t *mapPointer = nullptr;
1128*8975f5c5SAndroid Build Coastguard Worker             // prevBuffer buffer will be recycled (or released and unmapped) by acquireBufferHelper
1129*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(prevBuffer.map(contextVk, &mapPointer));
1130*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mapPointer);
1131*8975f5c5SAndroid Build Coastguard Worker             prevMapPtrBeforeSubData = mapPointer;
1132*8975f5c5SAndroid Build Coastguard Worker             prevMapPtrAfterSubData  = mapPointer + offsetAfterSubdata;
1133*8975f5c5SAndroid Build Coastguard Worker         }
1134*8975f5c5SAndroid Build Coastguard Worker     }
1135*8975f5c5SAndroid Build Coastguard Worker 
1136*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(acquireBufferHelper(contextVk, bufferSize, BufferUsageType::Dynamic));
1137*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(updateBuffer(contextVk, bufferSize, dataSource, updateSize, updateOffset));
1138*8975f5c5SAndroid Build Coastguard Worker 
1139*8975f5c5SAndroid Build Coastguard Worker     constexpr int kMaxCopyRegions = 2;
1140*8975f5c5SAndroid Build Coastguard Worker     angle::FixedVector<VkBufferCopy, kMaxCopyRegions> copyRegions;
1141*8975f5c5SAndroid Build Coastguard Worker 
1142*8975f5c5SAndroid Build Coastguard Worker     if (updateRegionBeforeSubData)
1143*8975f5c5SAndroid Build Coastguard Worker     {
1144*8975f5c5SAndroid Build Coastguard Worker         if (prevMapPtrBeforeSubData)
1145*8975f5c5SAndroid Build Coastguard Worker         {
1146*8975f5c5SAndroid Build Coastguard Worker             BufferDataSource beforeSrc = {};
1147*8975f5c5SAndroid Build Coastguard Worker             beforeSrc.data             = prevMapPtrBeforeSubData;
1148*8975f5c5SAndroid Build Coastguard Worker 
1149*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(directUpdate(contextVk, beforeSrc, updateOffset, 0));
1150*8975f5c5SAndroid Build Coastguard Worker         }
1151*8975f5c5SAndroid Build Coastguard Worker         else
1152*8975f5c5SAndroid Build Coastguard Worker         {
1153*8975f5c5SAndroid Build Coastguard Worker             copyRegions.push_back({prevBuffer.getOffset(), mBuffer.getOffset(), updateOffset});
1154*8975f5c5SAndroid Build Coastguard Worker         }
1155*8975f5c5SAndroid Build Coastguard Worker     }
1156*8975f5c5SAndroid Build Coastguard Worker 
1157*8975f5c5SAndroid Build Coastguard Worker     if (updateRegionAfterSubData)
1158*8975f5c5SAndroid Build Coastguard Worker     {
1159*8975f5c5SAndroid Build Coastguard Worker         size_t copySize = bufferSize - offsetAfterSubdata;
1160*8975f5c5SAndroid Build Coastguard Worker         if (prevMapPtrAfterSubData)
1161*8975f5c5SAndroid Build Coastguard Worker         {
1162*8975f5c5SAndroid Build Coastguard Worker             BufferDataSource afterSrc = {};
1163*8975f5c5SAndroid Build Coastguard Worker             afterSrc.data             = prevMapPtrAfterSubData;
1164*8975f5c5SAndroid Build Coastguard Worker 
1165*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(directUpdate(contextVk, afterSrc, copySize, offsetAfterSubdata));
1166*8975f5c5SAndroid Build Coastguard Worker         }
1167*8975f5c5SAndroid Build Coastguard Worker         else
1168*8975f5c5SAndroid Build Coastguard Worker         {
1169*8975f5c5SAndroid Build Coastguard Worker             copyRegions.push_back({prevBuffer.getOffset() + offsetAfterSubdata,
1170*8975f5c5SAndroid Build Coastguard Worker                                    mBuffer.getOffset() + offsetAfterSubdata, copySize});
1171*8975f5c5SAndroid Build Coastguard Worker         }
1172*8975f5c5SAndroid Build Coastguard Worker     }
1173*8975f5c5SAndroid Build Coastguard Worker 
1174*8975f5c5SAndroid Build Coastguard Worker     if (!copyRegions.empty())
1175*8975f5c5SAndroid Build Coastguard Worker     {
1176*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(CopyBuffers(contextVk, &prevBuffer, &mBuffer,
1177*8975f5c5SAndroid Build Coastguard Worker                               static_cast<uint32_t>(copyRegions.size()), copyRegions.data()));
1178*8975f5c5SAndroid Build Coastguard Worker     }
1179*8975f5c5SAndroid Build Coastguard Worker 
1180*8975f5c5SAndroid Build Coastguard Worker     if (prevBuffer.valid())
1181*8975f5c5SAndroid Build Coastguard Worker     {
1182*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->releaseBufferAllocation(&prevBuffer));
1183*8975f5c5SAndroid Build Coastguard Worker     }
1184*8975f5c5SAndroid Build Coastguard Worker 
1185*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1186*8975f5c5SAndroid Build Coastguard Worker }
1187*8975f5c5SAndroid Build Coastguard Worker 
setDataImpl(ContextVk * contextVk,size_t bufferSize,const BufferDataSource & dataSource,size_t updateSize,size_t updateOffset,BufferUpdateType updateType)1188*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::setDataImpl(ContextVk *contextVk,
1189*8975f5c5SAndroid Build Coastguard Worker                                     size_t bufferSize,
1190*8975f5c5SAndroid Build Coastguard Worker                                     const BufferDataSource &dataSource,
1191*8975f5c5SAndroid Build Coastguard Worker                                     size_t updateSize,
1192*8975f5c5SAndroid Build Coastguard Worker                                     size_t updateOffset,
1193*8975f5c5SAndroid Build Coastguard Worker                                     BufferUpdateType updateType)
1194*8975f5c5SAndroid Build Coastguard Worker {
1195*8975f5c5SAndroid Build Coastguard Worker     // if the buffer is currently in use
1196*8975f5c5SAndroid Build Coastguard Worker     //     if it isn't an external buffer and not a self-copy and sub data size meets threshold
1197*8975f5c5SAndroid Build Coastguard Worker     //          acquire a new BufferHelper from the pool
1198*8975f5c5SAndroid Build Coastguard Worker     //     else stage the update
1199*8975f5c5SAndroid Build Coastguard Worker     // else update the buffer directly
1200*8975f5c5SAndroid Build Coastguard Worker     if (isCurrentlyInUse(contextVk->getRenderer()))
1201*8975f5c5SAndroid Build Coastguard Worker     {
1202*8975f5c5SAndroid Build Coastguard Worker         // The acquire-and-update path creates a new buffer, which is sometimes more efficient than
1203*8975f5c5SAndroid Build Coastguard Worker         // trying to update the existing one.  Firstly, this is not done in the following
1204*8975f5c5SAndroid Build Coastguard Worker         // situations:
1205*8975f5c5SAndroid Build Coastguard Worker         //
1206*8975f5c5SAndroid Build Coastguard Worker         // - For external buffers, the underlying storage cannot be reallocated.
1207*8975f5c5SAndroid Build Coastguard Worker         // - If storage has just been redefined, this path is not taken because a new buffer has
1208*8975f5c5SAndroid Build Coastguard Worker         //   already been created by the caller. Besides, this path uses mState.getSize(), which the
1209*8975f5c5SAndroid Build Coastguard Worker         //   frontend updates only after this call in situations where the storage may be redefined.
1210*8975f5c5SAndroid Build Coastguard Worker         //   This could happen if the buffer memory is DEVICE_LOCAL and
1211*8975f5c5SAndroid Build Coastguard Worker         //   renderer->getFeatures().allocateNonZeroMemory.enabled is true. In this case a
1212*8975f5c5SAndroid Build Coastguard Worker         //   copyToBuffer is immediately issued after allocation and isCurrentlyInUse will be true.
1213*8975f5c5SAndroid Build Coastguard Worker         // - If this is a self copy through glCopyBufferSubData, |dataSource| will contain a
1214*8975f5c5SAndroid Build Coastguard Worker         //   reference to |mBuffer|, in which case source information is lost after acquiring a new
1215*8975f5c5SAndroid Build Coastguard Worker         //   buffer.
1216*8975f5c5SAndroid Build Coastguard Worker         //
1217*8975f5c5SAndroid Build Coastguard Worker         // Additionally, this path is taken only if either of the following conditions are true:
1218*8975f5c5SAndroid Build Coastguard Worker         //
1219*8975f5c5SAndroid Build Coastguard Worker         // - If BufferVk does not have any valid data.  This means that there is no data to be
1220*8975f5c5SAndroid Build Coastguard Worker         //   copied from the old buffer to the new one after acquiring it.  This could happen when
1221*8975f5c5SAndroid Build Coastguard Worker         //   the application calls glBufferData with the same size and we reuse the existing buffer
1222*8975f5c5SAndroid Build Coastguard Worker         //   storage.
1223*8975f5c5SAndroid Build Coastguard Worker         // - If the buffer is used read-only in the current render pass.  In this case, acquiring a
1224*8975f5c5SAndroid Build Coastguard Worker         //   new buffer is preferred to avoid breaking the render pass.
1225*8975f5c5SAndroid Build Coastguard Worker         // - The update modifies a significant portion of the buffer
1226*8975f5c5SAndroid Build Coastguard Worker         // - The preferCPUForBufferSubData feature is enabled.
1227*8975f5c5SAndroid Build Coastguard Worker         //
1228*8975f5c5SAndroid Build Coastguard Worker         const bool canAcquireAndUpdate = !isExternalBuffer() &&
1229*8975f5c5SAndroid Build Coastguard Worker                                          updateType != BufferUpdateType::StorageRedefined &&
1230*8975f5c5SAndroid Build Coastguard Worker                                          !IsSelfCopy(dataSource, mBuffer);
1231*8975f5c5SAndroid Build Coastguard Worker         if (canAcquireAndUpdate &&
1232*8975f5c5SAndroid Build Coastguard Worker             (!mHasValidData || ShouldAvoidRenderPassBreakOnUpdate(contextVk, mBuffer, bufferSize) ||
1233*8975f5c5SAndroid Build Coastguard Worker              ShouldAllocateNewMemoryForUpdate(contextVk, updateSize, bufferSize)))
1234*8975f5c5SAndroid Build Coastguard Worker         {
1235*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(acquireAndUpdate(contextVk, bufferSize, dataSource, updateSize, updateOffset,
1236*8975f5c5SAndroid Build Coastguard Worker                                        updateType));
1237*8975f5c5SAndroid Build Coastguard Worker         }
1238*8975f5c5SAndroid Build Coastguard Worker         else
1239*8975f5c5SAndroid Build Coastguard Worker         {
1240*8975f5c5SAndroid Build Coastguard Worker             if (canAcquireAndUpdate && RenderPassUsesBufferForReadOnly(contextVk, mBuffer))
1241*8975f5c5SAndroid Build Coastguard Worker             {
1242*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1243*8975f5c5SAndroid Build Coastguard Worker                                       "Breaking the render pass on small upload to large buffer");
1244*8975f5c5SAndroid Build Coastguard Worker             }
1245*8975f5c5SAndroid Build Coastguard Worker 
1246*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(stagedUpdate(contextVk, dataSource, updateSize, updateOffset));
1247*8975f5c5SAndroid Build Coastguard Worker         }
1248*8975f5c5SAndroid Build Coastguard Worker     }
1249*8975f5c5SAndroid Build Coastguard Worker     else
1250*8975f5c5SAndroid Build Coastguard Worker     {
1251*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(updateBuffer(contextVk, bufferSize, dataSource, updateSize, updateOffset));
1252*8975f5c5SAndroid Build Coastguard Worker     }
1253*8975f5c5SAndroid Build Coastguard Worker 
1254*8975f5c5SAndroid Build Coastguard Worker     // Update conversions.
1255*8975f5c5SAndroid Build Coastguard Worker     if (updateOffset == 0 && updateSize == bufferSize)
1256*8975f5c5SAndroid Build Coastguard Worker     {
1257*8975f5c5SAndroid Build Coastguard Worker         dataUpdated();
1258*8975f5c5SAndroid Build Coastguard Worker     }
1259*8975f5c5SAndroid Build Coastguard Worker     else
1260*8975f5c5SAndroid Build Coastguard Worker     {
1261*8975f5c5SAndroid Build Coastguard Worker         dataRangeUpdated(RangeDeviceSize(updateOffset, updateOffset + updateSize));
1262*8975f5c5SAndroid Build Coastguard Worker     }
1263*8975f5c5SAndroid Build Coastguard Worker 
1264*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1265*8975f5c5SAndroid Build Coastguard Worker }
1266*8975f5c5SAndroid Build Coastguard Worker 
getVertexConversionBuffer(vk::Renderer * renderer,const VertexConversionBuffer::CacheKey & cacheKey)1267*8975f5c5SAndroid Build Coastguard Worker VertexConversionBuffer *BufferVk::getVertexConversionBuffer(
1268*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer,
1269*8975f5c5SAndroid Build Coastguard Worker     const VertexConversionBuffer::CacheKey &cacheKey)
1270*8975f5c5SAndroid Build Coastguard Worker {
1271*8975f5c5SAndroid Build Coastguard Worker     for (VertexConversionBuffer &buffer : mVertexConversionBuffers)
1272*8975f5c5SAndroid Build Coastguard Worker     {
1273*8975f5c5SAndroid Build Coastguard Worker         if (buffer.match(cacheKey))
1274*8975f5c5SAndroid Build Coastguard Worker         {
1275*8975f5c5SAndroid Build Coastguard Worker             ASSERT(buffer.valid());
1276*8975f5c5SAndroid Build Coastguard Worker             return &buffer;
1277*8975f5c5SAndroid Build Coastguard Worker         }
1278*8975f5c5SAndroid Build Coastguard Worker     }
1279*8975f5c5SAndroid Build Coastguard Worker 
1280*8975f5c5SAndroid Build Coastguard Worker     mVertexConversionBuffers.emplace_back(renderer, cacheKey);
1281*8975f5c5SAndroid Build Coastguard Worker     return &mVertexConversionBuffers.back();
1282*8975f5c5SAndroid Build Coastguard Worker }
1283*8975f5c5SAndroid Build Coastguard Worker 
dataRangeUpdated(const RangeDeviceSize & range)1284*8975f5c5SAndroid Build Coastguard Worker void BufferVk::dataRangeUpdated(const RangeDeviceSize &range)
1285*8975f5c5SAndroid Build Coastguard Worker {
1286*8975f5c5SAndroid Build Coastguard Worker     for (VertexConversionBuffer &buffer : mVertexConversionBuffers)
1287*8975f5c5SAndroid Build Coastguard Worker     {
1288*8975f5c5SAndroid Build Coastguard Worker         buffer.addDirtyBufferRange(range);
1289*8975f5c5SAndroid Build Coastguard Worker     }
1290*8975f5c5SAndroid Build Coastguard Worker     // Now we have valid data
1291*8975f5c5SAndroid Build Coastguard Worker     mHasValidData = true;
1292*8975f5c5SAndroid Build Coastguard Worker }
1293*8975f5c5SAndroid Build Coastguard Worker 
dataUpdated()1294*8975f5c5SAndroid Build Coastguard Worker void BufferVk::dataUpdated()
1295*8975f5c5SAndroid Build Coastguard Worker {
1296*8975f5c5SAndroid Build Coastguard Worker     for (VertexConversionBuffer &buffer : mVertexConversionBuffers)
1297*8975f5c5SAndroid Build Coastguard Worker     {
1298*8975f5c5SAndroid Build Coastguard Worker         buffer.setEntireBufferDirty();
1299*8975f5c5SAndroid Build Coastguard Worker     }
1300*8975f5c5SAndroid Build Coastguard Worker     // Now we have valid data
1301*8975f5c5SAndroid Build Coastguard Worker     mHasValidData = true;
1302*8975f5c5SAndroid Build Coastguard Worker }
1303*8975f5c5SAndroid Build Coastguard Worker 
onDataChanged()1304*8975f5c5SAndroid Build Coastguard Worker void BufferVk::onDataChanged()
1305*8975f5c5SAndroid Build Coastguard Worker {
1306*8975f5c5SAndroid Build Coastguard Worker     dataUpdated();
1307*8975f5c5SAndroid Build Coastguard Worker }
1308*8975f5c5SAndroid Build Coastguard Worker 
acquireBufferHelper(ContextVk * contextVk,size_t sizeInBytes,BufferUsageType usageType)1309*8975f5c5SAndroid Build Coastguard Worker angle::Result BufferVk::acquireBufferHelper(ContextVk *contextVk,
1310*8975f5c5SAndroid Build Coastguard Worker                                             size_t sizeInBytes,
1311*8975f5c5SAndroid Build Coastguard Worker                                             BufferUsageType usageType)
1312*8975f5c5SAndroid Build Coastguard Worker {
1313*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
1314*8975f5c5SAndroid Build Coastguard Worker     size_t size            = roundUpPow2(sizeInBytes, kBufferSizeGranularity);
1315*8975f5c5SAndroid Build Coastguard Worker     size_t alignment       = renderer->getDefaultBufferAlignment();
1316*8975f5c5SAndroid Build Coastguard Worker 
1317*8975f5c5SAndroid Build Coastguard Worker     if (mBuffer.valid())
1318*8975f5c5SAndroid Build Coastguard Worker     {
1319*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->releaseBufferAllocation(&mBuffer));
1320*8975f5c5SAndroid Build Coastguard Worker     }
1321*8975f5c5SAndroid Build Coastguard Worker 
1322*8975f5c5SAndroid Build Coastguard Worker     // Allocate the buffer directly
1323*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(
1324*8975f5c5SAndroid Build Coastguard Worker         contextVk->initBufferAllocation(&mBuffer, mMemoryTypeIndex, size, alignment, usageType));
1325*8975f5c5SAndroid Build Coastguard Worker 
1326*8975f5c5SAndroid Build Coastguard Worker     // Tell the observers (front end) that a new buffer was created, so the necessary
1327*8975f5c5SAndroid Build Coastguard Worker     // dirty bits can be set. This allows the buffer views pointing to the old buffer to
1328*8975f5c5SAndroid Build Coastguard Worker     // be recreated and point to the new buffer, along with updating the descriptor sets
1329*8975f5c5SAndroid Build Coastguard Worker     // to use the new buffer.
1330*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::InternalMemoryAllocationChanged);
1331*8975f5c5SAndroid Build Coastguard Worker 
1332*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1333*8975f5c5SAndroid Build Coastguard Worker }
1334*8975f5c5SAndroid Build Coastguard Worker 
isCurrentlyInUse(vk::Renderer * renderer) const1335*8975f5c5SAndroid Build Coastguard Worker bool BufferVk::isCurrentlyInUse(vk::Renderer *renderer) const
1336*8975f5c5SAndroid Build Coastguard Worker {
1337*8975f5c5SAndroid Build Coastguard Worker     return !renderer->hasResourceUseFinished(mBuffer.getResourceUse());
1338*8975f5c5SAndroid Build Coastguard Worker }
1339*8975f5c5SAndroid Build Coastguard Worker 
1340*8975f5c5SAndroid Build Coastguard Worker // When a buffer is being completely changed, calculate whether it's better to allocate a new buffer
1341*8975f5c5SAndroid Build Coastguard Worker // or overwrite the existing one.
calculateBufferUpdateTypeOnFullUpdate(vk::Renderer * renderer,size_t size,VkMemoryPropertyFlags memoryPropertyFlags,BufferUsageType usageType,const void * data) const1342*8975f5c5SAndroid Build Coastguard Worker BufferUpdateType BufferVk::calculateBufferUpdateTypeOnFullUpdate(
1343*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer,
1344*8975f5c5SAndroid Build Coastguard Worker     size_t size,
1345*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags memoryPropertyFlags,
1346*8975f5c5SAndroid Build Coastguard Worker     BufferUsageType usageType,
1347*8975f5c5SAndroid Build Coastguard Worker     const void *data) const
1348*8975f5c5SAndroid Build Coastguard Worker {
1349*8975f5c5SAndroid Build Coastguard Worker     // 0-sized updates should be no-op'd before this call.
1350*8975f5c5SAndroid Build Coastguard Worker     ASSERT(size > 0);
1351*8975f5c5SAndroid Build Coastguard Worker 
1352*8975f5c5SAndroid Build Coastguard Worker     // If there is no existing buffer, this cannot be a content update.
1353*8975f5c5SAndroid Build Coastguard Worker     if (!mBuffer.valid())
1354*8975f5c5SAndroid Build Coastguard Worker     {
1355*8975f5c5SAndroid Build Coastguard Worker         return BufferUpdateType::StorageRedefined;
1356*8975f5c5SAndroid Build Coastguard Worker     }
1357*8975f5c5SAndroid Build Coastguard Worker 
1358*8975f5c5SAndroid Build Coastguard Worker     const bool inUseAndRespecifiedWithoutData = data == nullptr && isCurrentlyInUse(renderer);
1359*8975f5c5SAndroid Build Coastguard Worker     bool redefineStorage = shouldRedefineStorage(renderer, usageType, memoryPropertyFlags, size);
1360*8975f5c5SAndroid Build Coastguard Worker 
1361*8975f5c5SAndroid Build Coastguard Worker     // Create a new buffer if the buffer is busy and it's being redefined without data.
1362*8975f5c5SAndroid Build Coastguard Worker     // Additionally, a new buffer is created if any of the parameters change (memory type, usage,
1363*8975f5c5SAndroid Build Coastguard Worker     // size).
1364*8975f5c5SAndroid Build Coastguard Worker     return redefineStorage || inUseAndRespecifiedWithoutData ? BufferUpdateType::StorageRedefined
1365*8975f5c5SAndroid Build Coastguard Worker                                                              : BufferUpdateType::ContentsUpdate;
1366*8975f5c5SAndroid Build Coastguard Worker }
1367*8975f5c5SAndroid Build Coastguard Worker 
shouldRedefineStorage(vk::Renderer * renderer,BufferUsageType usageType,VkMemoryPropertyFlags memoryPropertyFlags,size_t size) const1368*8975f5c5SAndroid Build Coastguard Worker bool BufferVk::shouldRedefineStorage(vk::Renderer *renderer,
1369*8975f5c5SAndroid Build Coastguard Worker                                      BufferUsageType usageType,
1370*8975f5c5SAndroid Build Coastguard Worker                                      VkMemoryPropertyFlags memoryPropertyFlags,
1371*8975f5c5SAndroid Build Coastguard Worker                                      size_t size) const
1372*8975f5c5SAndroid Build Coastguard Worker {
1373*8975f5c5SAndroid Build Coastguard Worker     if (mUsageType != usageType)
1374*8975f5c5SAndroid Build Coastguard Worker     {
1375*8975f5c5SAndroid Build Coastguard Worker         return true;
1376*8975f5c5SAndroid Build Coastguard Worker     }
1377*8975f5c5SAndroid Build Coastguard Worker 
1378*8975f5c5SAndroid Build Coastguard Worker     if (mMemoryPropertyFlags != memoryPropertyFlags)
1379*8975f5c5SAndroid Build Coastguard Worker     {
1380*8975f5c5SAndroid Build Coastguard Worker         return true;
1381*8975f5c5SAndroid Build Coastguard Worker     }
1382*8975f5c5SAndroid Build Coastguard Worker 
1383*8975f5c5SAndroid Build Coastguard Worker     if (size > mBuffer.getSize())
1384*8975f5c5SAndroid Build Coastguard Worker     {
1385*8975f5c5SAndroid Build Coastguard Worker         return true;
1386*8975f5c5SAndroid Build Coastguard Worker     }
1387*8975f5c5SAndroid Build Coastguard Worker     else
1388*8975f5c5SAndroid Build Coastguard Worker     {
1389*8975f5c5SAndroid Build Coastguard Worker         size_t paddedBufferSize =
1390*8975f5c5SAndroid Build Coastguard Worker             (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
1391*8975f5c5SAndroid Build Coastguard Worker                 ? (size + static_cast<size_t>(renderer->getMaxVertexAttribStride()))
1392*8975f5c5SAndroid Build Coastguard Worker                 : size;
1393*8975f5c5SAndroid Build Coastguard Worker         size_t sizeInBytes = roundUpPow2(paddedBufferSize, kBufferSizeGranularity);
1394*8975f5c5SAndroid Build Coastguard Worker         size_t alignedSize = roundUp(sizeInBytes, renderer->getDefaultBufferAlignment());
1395*8975f5c5SAndroid Build Coastguard Worker         if (alignedSize > mBuffer.getSize())
1396*8975f5c5SAndroid Build Coastguard Worker         {
1397*8975f5c5SAndroid Build Coastguard Worker             return true;
1398*8975f5c5SAndroid Build Coastguard Worker         }
1399*8975f5c5SAndroid Build Coastguard Worker     }
1400*8975f5c5SAndroid Build Coastguard Worker 
1401*8975f5c5SAndroid Build Coastguard Worker     return false;
1402*8975f5c5SAndroid Build Coastguard Worker }
1403*8975f5c5SAndroid Build Coastguard Worker }  // namespace rx
1404