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, ©Region));
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, ©Region));
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 ©Region);
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