Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit ff05a31

Browse files
authored
[Impeller] Wire Flutter's own VulkanMemoryAllocator implementation (#37018)
1 parent d4aec01 commit ff05a31

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+804
-171
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ FILE: ../../../flutter/flow/surface_frame.cc
831831
FILE: ../../../flutter/flow/surface_frame.h
832832
FILE: ../../../flutter/flow/surface_frame_unittests.cc
833833
FILE: ../../../flutter/flow/texture_unittests.cc
834+
FILE: ../../../flutter/flutter_vma/flutter_skia_vma.cc
835+
FILE: ../../../flutter/flutter_vma/flutter_skia_vma.h
836+
FILE: ../../../flutter/flutter_vma/flutter_vma.cc
837+
FILE: ../../../flutter/flutter_vma/flutter_vma.h
834838
FILE: ../../../flutter/fml/ascii_trie.cc
835839
FILE: ../../../flutter/fml/ascii_trie.h
836840
FILE: ../../../flutter/fml/ascii_trie_unittests.cc
@@ -3256,6 +3260,12 @@ FILE: ../../../flutter/third_party/txt/src/txt/platform_fuchsia.cc
32563260
FILE: ../../../flutter/third_party/txt/src/txt/platform_linux.cc
32573261
FILE: ../../../flutter/third_party/txt/src/txt/platform_mac.mm
32583262
FILE: ../../../flutter/third_party/txt/src/txt/platform_windows.cc
3263+
FILE: ../../../flutter/vulkan/procs/vulkan_handle.cc
3264+
FILE: ../../../flutter/vulkan/procs/vulkan_handle.h
3265+
FILE: ../../../flutter/vulkan/procs/vulkan_interface.cc
3266+
FILE: ../../../flutter/vulkan/procs/vulkan_interface.h
3267+
FILE: ../../../flutter/vulkan/procs/vulkan_proc_table.cc
3268+
FILE: ../../../flutter/vulkan/procs/vulkan_proc_table.h
32593269
FILE: ../../../flutter/vulkan/vulkan_application.cc
32603270
FILE: ../../../flutter/vulkan/vulkan_application.h
32613271
FILE: ../../../flutter/vulkan/vulkan_backbuffer.cc
@@ -3266,20 +3276,16 @@ FILE: ../../../flutter/vulkan/vulkan_debug_report.cc
32663276
FILE: ../../../flutter/vulkan/vulkan_debug_report.h
32673277
FILE: ../../../flutter/vulkan/vulkan_device.cc
32683278
FILE: ../../../flutter/vulkan/vulkan_device.h
3269-
FILE: ../../../flutter/vulkan/vulkan_handle.cc
3270-
FILE: ../../../flutter/vulkan/vulkan_handle.h
32713279
FILE: ../../../flutter/vulkan/vulkan_image.cc
32723280
FILE: ../../../flutter/vulkan/vulkan_image.h
3273-
FILE: ../../../flutter/vulkan/vulkan_interface.cc
3274-
FILE: ../../../flutter/vulkan/vulkan_interface.h
32753281
FILE: ../../../flutter/vulkan/vulkan_native_surface.cc
32763282
FILE: ../../../flutter/vulkan/vulkan_native_surface.h
32773283
FILE: ../../../flutter/vulkan/vulkan_native_surface_android.cc
32783284
FILE: ../../../flutter/vulkan/vulkan_native_surface_android.h
3279-
FILE: ../../../flutter/vulkan/vulkan_proc_table.cc
3280-
FILE: ../../../flutter/vulkan/vulkan_proc_table.h
32813285
FILE: ../../../flutter/vulkan/vulkan_provider.cc
32823286
FILE: ../../../flutter/vulkan/vulkan_provider.h
3287+
FILE: ../../../flutter/vulkan/vulkan_skia_proc_table.cc
3288+
FILE: ../../../flutter/vulkan/vulkan_skia_proc_table.h
32833289
FILE: ../../../flutter/vulkan/vulkan_surface.cc
32843290
FILE: ../../../flutter/vulkan/vulkan_surface.h
32853291
FILE: ../../../flutter/vulkan/vulkan_swapchain.cc

flutter_vma/BUILD.gn

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2013 The Flutter Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
import("//flutter/flutter_vma/config.gni")
6+
7+
source_set("flutter_vma") {
8+
sources = [
9+
"flutter_vma.cc",
10+
"flutter_vma.h",
11+
]
12+
13+
if (disable_vma_stl_shared_mutex) {
14+
defines = [ "VMA_USE_STL_SHARED_MUTEX=0" ]
15+
}
16+
17+
deps = [
18+
"//third_party/vulkan-deps/vulkan-headers/src:vulkan_headers",
19+
"//third_party/vulkan_memory_allocator",
20+
]
21+
22+
public_configs = [ "//flutter:config" ]
23+
}
24+
25+
source_set("flutter_skia_vma") {
26+
sources = [
27+
"flutter_skia_vma.cc",
28+
"flutter_skia_vma.h",
29+
]
30+
31+
public_deps = [ ":flutter_vma" ]
32+
33+
deps = [
34+
"//flutter/fml",
35+
"//flutter/vulkan/procs",
36+
"//third_party/skia",
37+
"//third_party/vulkan-deps/vulkan-headers/src:vulkan_headers",
38+
"//third_party/vulkan_memory_allocator",
39+
]
40+
}

flutter_vma/config.gni

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright 2013 The Flutter Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style license that can be
3+
# found in the LICENSE file.
4+
5+
declare_args() {
6+
disable_vma_stl_shared_mutex = false
7+
}

flutter_vma/flutter_skia_vma.cc

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/flutter_vma/flutter_skia_vma.h"
6+
7+
#include "flutter/fml/memory/ref_ptr.h"
8+
#include "flutter/vulkan/procs/vulkan_handle.h"
9+
#include "flutter/vulkan/procs/vulkan_proc_table.h"
10+
11+
namespace flutter {
12+
13+
sk_sp<skgpu::VulkanMemoryAllocator> FlutterSkiaVulkanMemoryAllocator::Make(
14+
uint32_t vulkan_api_version,
15+
VkInstance instance,
16+
VkPhysicalDevice physicalDevice,
17+
VkDevice device,
18+
const fml::RefPtr<vulkan::VulkanProcTable>& vk,
19+
bool mustUseCoherentHostVisibleMemory) {
20+
#define PROVIDE_PROC(tbl, proc, provider) tbl.vk##proc = provider->proc;
21+
22+
VmaVulkanFunctions proc_table = {};
23+
proc_table.vkGetInstanceProcAddr = vk->NativeGetInstanceProcAddr();
24+
PROVIDE_PROC(proc_table, GetDeviceProcAddr, vk);
25+
PROVIDE_PROC(proc_table, GetPhysicalDeviceProperties, vk);
26+
PROVIDE_PROC(proc_table, GetPhysicalDeviceMemoryProperties, vk);
27+
PROVIDE_PROC(proc_table, AllocateMemory, vk);
28+
PROVIDE_PROC(proc_table, FreeMemory, vk);
29+
PROVIDE_PROC(proc_table, MapMemory, vk);
30+
PROVIDE_PROC(proc_table, UnmapMemory, vk);
31+
PROVIDE_PROC(proc_table, FlushMappedMemoryRanges, vk);
32+
PROVIDE_PROC(proc_table, InvalidateMappedMemoryRanges, vk);
33+
PROVIDE_PROC(proc_table, BindBufferMemory, vk);
34+
PROVIDE_PROC(proc_table, BindImageMemory, vk);
35+
PROVIDE_PROC(proc_table, GetBufferMemoryRequirements, vk);
36+
PROVIDE_PROC(proc_table, GetImageMemoryRequirements, vk);
37+
PROVIDE_PROC(proc_table, CreateBuffer, vk);
38+
PROVIDE_PROC(proc_table, DestroyBuffer, vk);
39+
PROVIDE_PROC(proc_table, CreateImage, vk);
40+
PROVIDE_PROC(proc_table, DestroyImage, vk);
41+
PROVIDE_PROC(proc_table, CmdCopyBuffer, vk);
42+
43+
#define PROVIDE_PROC_COALESCE(tbl, proc, provider) \
44+
tbl.vk##proc##KHR = provider->proc ? provider->proc : provider->proc##KHR;
45+
// See the following link for why we have to pick either KHR version or
46+
// promoted non-KHR version:
47+
// https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/issues/203
48+
PROVIDE_PROC_COALESCE(proc_table, GetBufferMemoryRequirements2, vk);
49+
PROVIDE_PROC_COALESCE(proc_table, GetImageMemoryRequirements2, vk);
50+
PROVIDE_PROC_COALESCE(proc_table, BindBufferMemory2, vk);
51+
PROVIDE_PROC_COALESCE(proc_table, BindImageMemory2, vk);
52+
PROVIDE_PROC_COALESCE(proc_table, GetPhysicalDeviceMemoryProperties2, vk);
53+
#undef PROVIDE_PROC_COALESCE
54+
55+
#undef PROVIDE_PROC
56+
57+
VmaAllocatorCreateInfo allocator_info = {};
58+
allocator_info.vulkanApiVersion = vulkan_api_version;
59+
allocator_info.physicalDevice = physicalDevice;
60+
allocator_info.device = device;
61+
allocator_info.instance = instance;
62+
allocator_info.pVulkanFunctions = &proc_table;
63+
64+
VmaAllocator allocator;
65+
vmaCreateAllocator(&allocator_info, &allocator);
66+
67+
return sk_sp<FlutterSkiaVulkanMemoryAllocator>(
68+
new FlutterSkiaVulkanMemoryAllocator(vk, allocator,
69+
mustUseCoherentHostVisibleMemory));
70+
}
71+
72+
FlutterSkiaVulkanMemoryAllocator::FlutterSkiaVulkanMemoryAllocator(
73+
fml::RefPtr<vulkan::VulkanProcTable> vk_proc_table,
74+
VmaAllocator allocator,
75+
bool mustUseCoherentHostVisibleMemory)
76+
: vk_proc_table_(std::move(vk_proc_table)),
77+
allocator_(allocator),
78+
must_use_coherent_host_visible_memory_(mustUseCoherentHostVisibleMemory) {
79+
}
80+
81+
FlutterSkiaVulkanMemoryAllocator::~FlutterSkiaVulkanMemoryAllocator() {
82+
vmaDestroyAllocator(allocator_);
83+
allocator_ = VK_NULL_HANDLE;
84+
}
85+
86+
VkResult FlutterSkiaVulkanMemoryAllocator::allocateImageMemory(
87+
VkImage image,
88+
uint32_t allocationPropertyFlags,
89+
skgpu::VulkanBackendMemory* backendMemory) {
90+
VmaAllocationCreateInfo info;
91+
info.flags = 0;
92+
info.usage = VMA_MEMORY_USAGE_UNKNOWN;
93+
info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
94+
info.preferredFlags = 0;
95+
info.memoryTypeBits = 0;
96+
info.pool = VK_NULL_HANDLE;
97+
info.pUserData = nullptr;
98+
99+
if (kDedicatedAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
100+
info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
101+
}
102+
if (kLazyAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
103+
info.requiredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
104+
}
105+
if (kProtected_AllocationPropertyFlag & allocationPropertyFlags) {
106+
info.requiredFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
107+
}
108+
109+
VmaAllocation allocation;
110+
VkResult result =
111+
vmaAllocateMemoryForImage(allocator_, image, &info, &allocation, nullptr);
112+
if (VK_SUCCESS == result) {
113+
*backendMemory = reinterpret_cast<skgpu::VulkanBackendMemory>(allocation);
114+
}
115+
return result;
116+
}
117+
118+
VkResult FlutterSkiaVulkanMemoryAllocator::allocateBufferMemory(
119+
VkBuffer buffer,
120+
BufferUsage usage,
121+
uint32_t allocationPropertyFlags,
122+
skgpu::VulkanBackendMemory* backendMemory) {
123+
VmaAllocationCreateInfo info;
124+
info.flags = 0;
125+
info.usage = VMA_MEMORY_USAGE_UNKNOWN;
126+
info.memoryTypeBits = 0;
127+
info.pool = VK_NULL_HANDLE;
128+
info.pUserData = nullptr;
129+
130+
switch (usage) {
131+
case BufferUsage::kGpuOnly:
132+
info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
133+
info.preferredFlags = 0;
134+
break;
135+
case BufferUsage::kCpuWritesGpuReads:
136+
// When doing cpu writes and gpu reads the general rule of thumb is to use
137+
// coherent memory. Though this depends on the fact that we are not doing
138+
// any cpu reads and the cpu writes are sequential. For sparse writes we'd
139+
// want cpu cached memory, however we don't do these types of writes in
140+
// Skia.
141+
//
142+
// TODO (kaushikiska): In the future there may be times where specific
143+
// types of memory could benefit from a coherent and cached memory.
144+
// Typically these allow for the gpu to read cpu writes from the cache
145+
// without needing to flush the writes throughout the cache. The reverse
146+
// is not true and GPU writes tend to invalidate the cache regardless.
147+
// Also these gpu cache read access are typically lower bandwidth than
148+
// non-cached memory. For now Skia doesn't really have a need or want of
149+
// this type of memory. But if we ever do we could pass in an
150+
// AllocationPropertyFlag that requests the cached property.
151+
info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
152+
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
153+
info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
154+
break;
155+
case BufferUsage::kTransfersFromCpuToGpu:
156+
info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
157+
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
158+
info.preferredFlags = 0;
159+
break;
160+
case BufferUsage::kTransfersFromGpuToCpu:
161+
info.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
162+
info.preferredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
163+
break;
164+
}
165+
166+
if (must_use_coherent_host_visible_memory_ &&
167+
(info.requiredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
168+
info.requiredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
169+
}
170+
if (kDedicatedAllocation_AllocationPropertyFlag & allocationPropertyFlags) {
171+
info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
172+
}
173+
if ((kLazyAllocation_AllocationPropertyFlag & allocationPropertyFlags) &&
174+
BufferUsage::kGpuOnly == usage) {
175+
info.preferredFlags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
176+
}
177+
178+
if (kPersistentlyMapped_AllocationPropertyFlag & allocationPropertyFlags) {
179+
SkASSERT(BufferUsage::kGpuOnly != usage);
180+
info.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
181+
}
182+
183+
VmaAllocation allocation;
184+
VkResult result = vmaAllocateMemoryForBuffer(allocator_, buffer, &info,
185+
&allocation, nullptr);
186+
if (VK_SUCCESS == result) {
187+
*backendMemory = reinterpret_cast<skgpu::VulkanBackendMemory>(allocation);
188+
}
189+
190+
return result;
191+
}
192+
193+
void FlutterSkiaVulkanMemoryAllocator::freeMemory(
194+
const skgpu::VulkanBackendMemory& memoryHandle) {
195+
const VmaAllocation allocation =
196+
reinterpret_cast<const VmaAllocation>(memoryHandle);
197+
vmaFreeMemory(allocator_, allocation);
198+
}
199+
200+
void FlutterSkiaVulkanMemoryAllocator::getAllocInfo(
201+
const skgpu::VulkanBackendMemory& memoryHandle,
202+
skgpu::VulkanAlloc* alloc) const {
203+
const VmaAllocation allocation =
204+
reinterpret_cast<const VmaAllocation>(memoryHandle);
205+
VmaAllocationInfo vmaInfo;
206+
vmaGetAllocationInfo(allocator_, allocation, &vmaInfo);
207+
208+
VkMemoryPropertyFlags memFlags;
209+
vmaGetMemoryTypeProperties(allocator_, vmaInfo.memoryType, &memFlags);
210+
211+
uint32_t flags = 0;
212+
if (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT & memFlags) {
213+
flags |= skgpu::VulkanAlloc::kMappable_Flag;
214+
}
215+
if (!SkToBool(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT & memFlags)) {
216+
flags |= skgpu::VulkanAlloc::kNoncoherent_Flag;
217+
}
218+
if (VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT & memFlags) {
219+
flags |= skgpu::VulkanAlloc::kLazilyAllocated_Flag;
220+
}
221+
222+
alloc->fMemory = vmaInfo.deviceMemory;
223+
alloc->fOffset = vmaInfo.offset;
224+
alloc->fSize = vmaInfo.size;
225+
alloc->fFlags = flags;
226+
alloc->fBackendMemory = memoryHandle;
227+
}
228+
229+
VkResult FlutterSkiaVulkanMemoryAllocator::mapMemory(
230+
const skgpu::VulkanBackendMemory& memoryHandle,
231+
void** data) {
232+
const VmaAllocation allocation =
233+
reinterpret_cast<const VmaAllocation>(memoryHandle);
234+
return vmaMapMemory(allocator_, allocation, data);
235+
}
236+
237+
void FlutterSkiaVulkanMemoryAllocator::unmapMemory(
238+
const skgpu::VulkanBackendMemory& memoryHandle) {
239+
const VmaAllocation allocation =
240+
reinterpret_cast<const VmaAllocation>(memoryHandle);
241+
vmaUnmapMemory(allocator_, allocation);
242+
}
243+
244+
VkResult FlutterSkiaVulkanMemoryAllocator::flushMemory(
245+
const skgpu::VulkanBackendMemory& memoryHandle,
246+
VkDeviceSize offset,
247+
VkDeviceSize size) {
248+
const VmaAllocation allocation =
249+
reinterpret_cast<const VmaAllocation>(memoryHandle);
250+
return vmaFlushAllocation(allocator_, allocation, offset, size);
251+
}
252+
253+
VkResult FlutterSkiaVulkanMemoryAllocator::invalidateMemory(
254+
const skgpu::VulkanBackendMemory& memoryHandle,
255+
VkDeviceSize offset,
256+
VkDeviceSize size) {
257+
const VmaAllocation allocation =
258+
reinterpret_cast<const VmaAllocation>(memoryHandle);
259+
return vmaInvalidateAllocation(allocator_, allocation, offset, size);
260+
}
261+
262+
uint64_t FlutterSkiaVulkanMemoryAllocator::totalUsedMemory() const {
263+
VmaTotalStatistics stats;
264+
vmaCalculateStatistics(allocator_, &stats);
265+
return stats.total.statistics.allocationBytes;
266+
}
267+
268+
uint64_t FlutterSkiaVulkanMemoryAllocator::totalAllocatedMemory() const {
269+
VmaTotalStatistics stats;
270+
vmaCalculateStatistics(allocator_, &stats);
271+
return stats.total.statistics.blockBytes;
272+
}
273+
274+
} // namespace flutter

0 commit comments

Comments
 (0)