Flutter Engine
The Flutter Engine
VkTestMemoryAllocator.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
13
14namespace sk_gpu_test {
15
17 VkInstance instance,
18 VkPhysicalDevice physicalDevice,
19 VkDevice device,
20 uint32_t physicalDeviceVersion,
22 const skgpu::VulkanInterface* interface) {
23#define SKGPU_COPY_FUNCTION(NAME) functions.vk##NAME = interface->fFunctions.f##NAME
24#define SKGPU_COPY_FUNCTION_KHR(NAME) functions.vk##NAME##KHR = interface->fFunctions.f##NAME
25
26 VmaVulkanFunctions functions;
27 // We should be setting all the required functions (at least through vulkan 1.1), but this is
28 // just extra belt and suspenders to make sure there isn't unitialized values here.
29 memset(&functions, 0, sizeof(VmaVulkanFunctions));
30
31 // We don't use dynamic function getting in the allocator so we set the getProc functions to
32 // null.
33 functions.vkGetInstanceProcAddr = nullptr;
34 functions.vkGetDeviceProcAddr = nullptr;
35 SKGPU_COPY_FUNCTION(GetPhysicalDeviceProperties);
36 SKGPU_COPY_FUNCTION(GetPhysicalDeviceMemoryProperties);
37 SKGPU_COPY_FUNCTION(AllocateMemory);
38 SKGPU_COPY_FUNCTION(FreeMemory);
39 SKGPU_COPY_FUNCTION(MapMemory);
40 SKGPU_COPY_FUNCTION(UnmapMemory);
41 SKGPU_COPY_FUNCTION(FlushMappedMemoryRanges);
42 SKGPU_COPY_FUNCTION(InvalidateMappedMemoryRanges);
43 SKGPU_COPY_FUNCTION(BindBufferMemory);
44 SKGPU_COPY_FUNCTION(BindImageMemory);
45 SKGPU_COPY_FUNCTION(GetBufferMemoryRequirements);
46 SKGPU_COPY_FUNCTION(GetImageMemoryRequirements);
47 SKGPU_COPY_FUNCTION(CreateBuffer);
48 SKGPU_COPY_FUNCTION(DestroyBuffer);
49 SKGPU_COPY_FUNCTION(CreateImage);
50 SKGPU_COPY_FUNCTION(DestroyImage);
51 SKGPU_COPY_FUNCTION(CmdCopyBuffer);
52 SKGPU_COPY_FUNCTION_KHR(GetBufferMemoryRequirements2);
53 SKGPU_COPY_FUNCTION_KHR(GetImageMemoryRequirements2);
54 SKGPU_COPY_FUNCTION_KHR(BindBufferMemory2);
55 SKGPU_COPY_FUNCTION_KHR(BindImageMemory2);
56 SKGPU_COPY_FUNCTION_KHR(GetPhysicalDeviceMemoryProperties2);
57
58 VmaAllocatorCreateInfo info;
59 info.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
60 if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
63 info.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
64 }
65
66 info.physicalDevice = physicalDevice;
67 info.device = device;
68 // 4MB was picked for the size here by looking at memory usage of Android apps and runs of DM.
69 // It seems to be a good compromise of not wasting unused allocated space and not making too
70 // many small allocations. The AMD allocator will start making blocks at 1/8 the max size and
71 // builds up block size as needed before capping at the max set here.
72 info.preferredLargeHeapBlockSize = 4 * 1024 * 1024;
73 info.pAllocationCallbacks = nullptr;
74 info.pDeviceMemoryCallbacks = nullptr;
75 info.pHeapSizeLimit = nullptr;
76 info.pVulkanFunctions = &functions;
77 info.instance = instance;
78 // TODO: Update our interface and headers to support vulkan 1.3 and add in the new required
79 // functions for 1.3 that the allocator needs. Until then we just clamp the version to 1.1.
80 info.vulkanApiVersion = std::min(physicalDeviceVersion, VK_MAKE_VERSION(1, 1, 0));
81 info.pTypeExternalMemoryHandleTypes = nullptr;
82
83 VmaAllocator allocator;
84 vmaCreateAllocator(&info, &allocator);
85
87}
88
89VkTestMemoryAllocator::VkTestMemoryAllocator(VmaAllocator allocator) : fAllocator(allocator) {}
90
92 vmaDestroyAllocator(fAllocator);
93 fAllocator = VK_NULL_HANDLE;
94}
95
97 uint32_t allocationPropertyFlags,
98 skgpu::VulkanBackendMemory* backendMemory) {
100 VmaAllocationCreateInfo info;
101 info.flags = 0;
102 info.usage = VMA_MEMORY_USAGE_UNKNOWN;
104 info.preferredFlags = 0;
105 info.memoryTypeBits = 0;
106 info.pool = VK_NULL_HANDLE;
107 info.pUserData = nullptr;
108
109 if (kDedicatedAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
110 info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
111 }
112 if (kLazyAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
114 }
115 if (kProtected_AllocationPropertyFlag & allocationPropertyFlags) {
116 info.requiredFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
117 }
118
119 VmaAllocation allocation;
120 VkResult result = vmaAllocateMemoryForImage(fAllocator, image, &info, &allocation, nullptr);
121 if (VK_SUCCESS == result) {
122 *backendMemory = (skgpu::VulkanBackendMemory)allocation;
123 }
124 return result;
125}
126
129 uint32_t allocationPropertyFlags,
130 skgpu::VulkanBackendMemory* backendMemory) {
131 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
132 VmaAllocationCreateInfo info;
133 info.flags = 0;
134 info.usage = VMA_MEMORY_USAGE_UNKNOWN;
135 info.memoryTypeBits = 0;
136 info.pool = VK_NULL_HANDLE;
137 info.pUserData = nullptr;
138
139 switch (usage) {
142 info.preferredFlags = 0;
143 break;
145 // When doing cpu writes and gpu reads the general rule of thumb is to use coherent
146 // memory. Though this depends on the fact that we are not doing any cpu reads and the
147 // cpu writes are sequential. For sparse writes we'd want cpu cached memory, however we
148 // don't do these types of writes in Skia.
149 //
150 // TODO: In the future there may be times where specific types of memory could benefit
151 // from a coherent and cached memory. Typically these allow for the gpu to read cpu
152 // writes from the cache without needing to flush the writes throughout the cache. The
153 // reverse is not true and GPU writes tend to invalidate the cache regardless. Also
154 // these gpu cache read access are typically lower bandwidth than non-cached memory.
155 // For now Skia doesn't really have a need or want of this type of memory. But if we
156 // ever do we could pass in an AllocationPropertyFlag that requests the cached property.
157 info.requiredFlags =
160 break;
162 info.requiredFlags =
164 info.preferredFlags = 0;
165 break;
169 break;
170 }
171
172 if (kDedicatedAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
173 info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
174 }
175 if ((kLazyAllocation_AllocationPropertyFlag & allocationPropertyFlags) &&
178 }
179
180 if (kPersistentlyMapped_AllocationPropertyFlag & allocationPropertyFlags) {
182 info.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
183 }
184
185 VmaAllocation allocation;
186 VkResult result = vmaAllocateMemoryForBuffer(fAllocator, buffer, &info, &allocation, nullptr);
187 if (VK_SUCCESS == result) {
188 *backendMemory = (skgpu::VulkanBackendMemory)allocation;
189 }
190
191 return result;
192}
193
195 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
196 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
197 vmaFreeMemory(fAllocator, allocation);
198}
199
201 skgpu::VulkanAlloc* alloc) const {
202 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
203 VmaAllocationInfo vmaInfo;
204 vmaGetAllocationInfo(fAllocator, allocation, &vmaInfo);
205
206 VkMemoryPropertyFlags memFlags;
207 vmaGetMemoryTypeProperties(fAllocator, vmaInfo.memoryType, &memFlags);
208
209 uint32_t flags = 0;
212 }
215 }
218 }
219
220 alloc->fMemory = vmaInfo.deviceMemory;
221 alloc->fOffset = vmaInfo.offset;
222 alloc->fSize = vmaInfo.size;
223 alloc->fFlags = flags;
224 alloc->fBackendMemory = memoryHandle;
225}
226
228 void** data) {
229 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
230 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
231 return vmaMapMemory(fAllocator, allocation, data);
232}
233
235 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
236 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
237 vmaUnmapMemory(fAllocator, allocation);
238}
239
243 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
244 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
245 return vmaFlushAllocation(fAllocator, allocation, offset, size);
246}
247
251 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
252 const VmaAllocation allocation = (VmaAllocation)memoryHandle;
253 return vmaInvalidateAllocation(fAllocator, allocation, offset, size);
254}
255
256std::pair<uint64_t, uint64_t> VkTestMemoryAllocator::totalAllocatedAndUsedMemory() const {
257 VmaTotalStatistics stats;
258 vmaCalculateStatistics(fAllocator, &stats);
259 return {stats.total.statistics.blockBytes, stats.total.statistics.allocationBytes};
260}
261
262} // namespace sk_gpu_test
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define TRACE_EVENT0_ALWAYS(category_group, name)
#define TRACE_FUNC
Definition: SkTraceEvent.h:30
#define SKGPU_COPY_FUNCTION_KHR(NAME)
#define SKGPU_COPY_FUNCTION(NAME)
void unmapMemory(const skgpu::VulkanBackendMemory &) override
VkResult invalidateMemory(const skgpu::VulkanBackendMemory &, VkDeviceSize offset, VkDeviceSize size) override
VkResult flushMemory(const skgpu::VulkanBackendMemory &, VkDeviceSize offset, VkDeviceSize size) override
static sk_sp< VulkanMemoryAllocator > Make(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device, uint32_t physicalDeviceVersion, const skgpu::VulkanExtensions *extensions, const skgpu::VulkanInterface *interface)
VkResult allocateBufferMemory(VkBuffer buffer, BufferUsage usage, uint32_t allocationPropertyFlags, skgpu::VulkanBackendMemory *) override
std::pair< uint64_t, uint64_t > totalAllocatedAndUsedMemory() const override
void getAllocInfo(const skgpu::VulkanBackendMemory &, skgpu::VulkanAlloc *) const override
VkResult mapMemory(const skgpu::VulkanBackendMemory &, void **data) override
VkResult allocateImageMemory(VkImage image, uint32_t allocationPropertyFlags, skgpu::VulkanBackendMemory *) override
void freeMemory(const skgpu::VulkanBackendMemory &) override
VkDevice device
Definition: main.cc:53
VkInstance instance
Definition: main.cc:48
FlutterSemanticsFlag flags
GAsyncResult * result
static float min(float r, float g, float b)
Definition: hsl.cpp:48
sk_sp< const SkImage > image
Definition: SkRecords.h:269
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dictionary stats
Definition: malisc.py:20
intptr_t VulkanBackendMemory
Definition: VulkanTypes.h:32
static void usage(char *argv0)
SeparatedVector2 offset
VkDeviceSize fSize
Definition: VulkanTypes.h:41
VulkanBackendMemory fBackendMemory
Definition: VulkanTypes.h:44
VkDeviceMemory fMemory
Definition: VulkanTypes.h:39
VkDeviceSize fOffset
Definition: VulkanTypes.h:40
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131
VkFlags VkMemoryPropertyFlags
Definition: vulkan_core.h:2410
@ VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
Definition: vulkan_core.h:2403
@ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
Definition: vulkan_core.h:2401
@ VK_MEMORY_PROPERTY_PROTECTED_BIT
Definition: vulkan_core.h:2404
@ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
Definition: vulkan_core.h:2399
@ VK_MEMORY_PROPERTY_HOST_CACHED_BIT
Definition: vulkan_core.h:2402
@ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
Definition: vulkan_core.h:2400
uint64_t VkDeviceSize
Definition: vulkan_core.h:96
#define VK_MAKE_VERSION(major, minor, patch)
Definition: vulkan_core.h:78
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
Definition: vulkan_core.h:9396
VkResult
Definition: vulkan_core.h:140
@ VK_SUCCESS
Definition: vulkan_core.h:141
#define VK_NULL_HANDLE
Definition: vulkan_core.h:46
#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME
Definition: vulkan_core.h:9374