9#include "flutter/fml/memory/ref_ptr.h"
10#include "flutter/fml/trace_event.h"
15#include "vulkan/vulkan_enums.hpp"
19static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
23 return vk::MemoryPropertyFlagBits::eHostVisible;
25 return vk::MemoryPropertyFlagBits::eDeviceLocal;
27 return vk::MemoryPropertyFlagBits::eLazilyAllocated;
35 VmaAllocationCreateFlags
flags = 0;
39 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
41 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
43 flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
56 vk::BufferCreateInfo buffer_info;
57 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
58 vk::BufferUsageFlagBits::eIndexBuffer |
59 vk::BufferUsageFlagBits::eUniformBuffer |
60 vk::BufferUsageFlagBits::eStorageBuffer |
61 vk::BufferUsageFlagBits::eTransferSrc |
62 vk::BufferUsageFlagBits::eTransferDst;
63 buffer_info.size = 1u;
64 buffer_info.sharingMode = vk::SharingMode::eExclusive;
65 auto buffer_info_native =
66 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
68 VmaAllocationCreateInfo allocation_info = {};
69 allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
75 uint32_t memTypeIndex;
76 auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
77 allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
78 if (
result != vk::Result::eSuccess) {
82 VmaPoolCreateInfo pool_create_info = {};
83 pool_create_info.memoryTypeIndex = memTypeIndex;
84 pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
87 result = vk::Result{::vmaCreatePool(allocator, &pool_create_info, &
pool)};
88 if (
result != vk::Result::eSuccess) {
91 return {allocator,
pool};
94AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
95 uint32_t vulkan_api_version,
97 const std::shared_ptr<DeviceHolderVK>& device_holder,
99 const CapabilitiesVK& capabilities)
100 : context_(
std::move(context)), device_holder_(device_holder) {
102 max_texture_size_.width = max_texture_size_.height =
103 limits.maxImageDimension2D;
106 VmaVulkanFunctions proc_table = {};
108#define BIND_VMA_PROC(x) proc_table.x = VULKAN_HPP_DEFAULT_DISPATCHER.x;
109#define BIND_VMA_PROC_KHR(x) \
110 proc_table.x##KHR = VULKAN_HPP_DEFAULT_DISPATCHER.x \
111 ? VULKAN_HPP_DEFAULT_DISPATCHER.x \
112 : VULKAN_HPP_DEFAULT_DISPATCHER.x##KHR;
137#undef BIND_VMA_PROC_KHR
140 VmaAllocatorCreateInfo allocator_info = {};
141 allocator_info.vulkanApiVersion = vulkan_api_version;
143 allocator_info.device = device_holder->GetDevice();
145 allocator_info.pVulkanFunctions = &proc_table;
147 VmaAllocator allocator = {};
148 auto result = vk::Result{::vmaCreateAllocator(&allocator_info, &allocator)};
149 if (
result != vk::Result::eSuccess) {
154 created_buffer_pool_ &= staging_buffer_pool_.is_valid();
155 allocator_.reset(allocator);
156 supports_memoryless_textures_ =
157 capabilities.SupportsDeviceTransientTextures();
161AllocatorVK::~AllocatorVK() =
default;
164bool AllocatorVK::IsValid()
const {
169ISize AllocatorVK::GetMaxTextureSizeSupported()
const {
170 return max_texture_size_;
173int32_t AllocatorVK::FindMemoryTypeIndex(
174 uint32_t memory_type_bits_requirement,
175 vk::PhysicalDeviceMemoryProperties& memory_properties) {
176 int32_t type_index = -1;
177 vk::MemoryPropertyFlagBits required_properties =
178 vk::MemoryPropertyFlagBits::eDeviceLocal;
180 const uint32_t memory_count = memory_properties.memoryTypeCount;
181 for (uint32_t memory_index = 0; memory_index < memory_count; ++memory_index) {
182 const uint32_t memory_type_bits = (1 << memory_index);
183 const bool is_required_memory_type =
184 memory_type_bits_requirement & memory_type_bits;
186 const auto properties =
187 memory_properties.memoryTypes[memory_index].propertyFlags;
188 const bool has_required_properties =
189 (properties & required_properties) == required_properties;
191 if (is_required_memory_type && has_required_properties) {
192 return static_cast<int32_t
>(memory_index);
199vk::ImageUsageFlags AllocatorVK::ToVKImageUsageFlags(
203 bool supports_memoryless_textures) {
204 vk::ImageUsageFlags vk_usage;
207 case StorageMode::kHostVisible:
208 case StorageMode::kDevicePrivate:
210 case StorageMode::kDeviceTransient:
211 if (supports_memoryless_textures) {
212 vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
217 if (
usage & TextureUsage::kRenderTarget) {
219 vk_usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
221 vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
222 vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
226 if (
usage & TextureUsage::kShaderRead) {
227 vk_usage |= vk::ImageUsageFlagBits::eSampled;
230 if (
usage & TextureUsage::kShaderWrite) {
231 vk_usage |= vk::ImageUsageFlagBits::eStorage;
234 if (
mode != StorageMode::kDeviceTransient) {
237 vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
238 vk::ImageUsageFlagBits::eTransferDst;
245 return VMA_MEMORY_USAGE_AUTO;
248static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
250 bool supports_memoryless_textures) {
252 case StorageMode::kHostVisible:
253 return vk::MemoryPropertyFlagBits::eHostVisible |
254 vk::MemoryPropertyFlagBits::eDeviceLocal;
255 case StorageMode::kDevicePrivate:
256 return vk::MemoryPropertyFlagBits::eDeviceLocal;
257 case StorageMode::kDeviceTransient:
258 if (supports_memoryless_textures) {
259 return vk::MemoryPropertyFlagBits::eLazilyAllocated |
260 vk::MemoryPropertyFlagBits::eDeviceLocal;
262 return vk::MemoryPropertyFlagBits::eDeviceLocal;
268 VmaAllocationCreateFlags
flags = 0;
270 case StorageMode::kHostVisible:
272 case StorageMode::kDevicePrivate:
274 case StorageMode::kDeviceTransient:
284 VmaAllocator allocator,
286 bool supports_memoryless_textures)
289 vk::ImageCreateInfo image_info;
291 image_info.imageType = vk::ImageType::e2D;
294 static_cast<uint32_t
>(
desc.size.width),
295 static_cast<uint32_t
>(
desc.size.height),
299 image_info.mipLevels =
desc.mip_count;
301 image_info.tiling = vk::ImageTiling::eOptimal;
302 image_info.initialLayout = vk::ImageLayout::eUndefined;
303 image_info.usage = AllocatorVK::ToVKImageUsageFlags(
305 supports_memoryless_textures);
306 image_info.sharingMode = vk::SharingMode::eExclusive;
308 VmaAllocationCreateInfo alloc_nfo = {};
311 alloc_nfo.preferredFlags =
313 desc.storage_mode, supports_memoryless_textures));
316 auto create_info_native =
317 static_cast<vk::ImageCreateInfo::NativeType
>(image_info);
320 VmaAllocation allocation = {};
321 VmaAllocationInfo allocation_info = {};
323 auto result = vk::Result{::vmaCreateImage(allocator,
330 if (
result != vk::Result::eSuccess) {
339 <<
" [VK]Mem. Flags: "
341 alloc_nfo.preferredFlags));
348 vk::ImageViewCreateInfo view_info = {};
351 view_info.format = image_info.format;
353 view_info.subresourceRange.levelCount = image_info.mipLevels;
360 if (
desc.format == PixelFormat::kA8UNormInt) {
361 view_info.components.a = vk::ComponentSwizzle::eR;
362 view_info.components.r = vk::ComponentSwizzle::eA;
365 auto [
result, image_view] =
device.createImageViewUnique(view_info);
366 if (
result != vk::Result::eSuccess) {
367 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
372 view_info.subresourceRange.levelCount = 1u;
373 auto [rt_result, rt_image_view] =
device.createImageViewUnique(view_info);
374 if (rt_result != vk::Result::eSuccess) {
375 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
380 resource_.Swap(ImageResource(
ImageVMA{allocator, allocation,
image},
381 std::move(image_view),
382 std::move(rt_image_view)));
393 return resource_->image_view.get();
397 return resource_->rt_image_view.get();
403 struct ImageResource {
405 vk::UniqueImageView image_view;
406 vk::UniqueImageView rt_image_view;
408 ImageResource() =
default;
411 vk::UniqueImageView p_image_view,
412 vk::UniqueImageView p_rt_image_view)
414 image_view(
std::move(p_image_view)),
415 rt_image_view(
std::move(p_rt_image_view)) {}
417 ImageResource(ImageResource&& o) =
default;
419 ImageResource(
const ImageResource&) =
delete;
421 ImageResource& operator=(
const ImageResource&) =
delete;
424 UniqueResourceVKT<ImageResource> resource_;
425 bool is_valid_ =
false;
427 AllocatedTextureSourceVK(
const AllocatedTextureSourceVK&) =
delete;
429 AllocatedTextureSourceVK& operator=(
const AllocatedTextureSourceVK&) =
delete;
433std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
434 const TextureDescriptor&
desc) {
438 auto device_holder = device_holder_.lock();
439 if (!device_holder) {
442 auto context = context_.lock();
446 auto source = std::make_shared<AllocatedTextureSourceVK>(
447 ContextVK::Cast(*context).GetResourceManager(),
450 device_holder->GetDevice(),
451 supports_memoryless_textures_
456 return std::make_shared<TextureVK>(context_, std::move(
source));
460std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
461 const DeviceBufferDescriptor&
desc) {
462 vk::BufferCreateInfo buffer_info;
463 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
464 vk::BufferUsageFlagBits::eIndexBuffer |
465 vk::BufferUsageFlagBits::eUniformBuffer |
466 vk::BufferUsageFlagBits::eStorageBuffer |
467 vk::BufferUsageFlagBits::eTransferSrc |
468 vk::BufferUsageFlagBits::eTransferDst;
469 buffer_info.size =
desc.size;
470 buffer_info.sharingMode = vk::SharingMode::eExclusive;
471 auto buffer_info_native =
472 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
474 VmaAllocationCreateInfo allocation_info = {};
478 allocation_info.flags =
480 if (created_buffer_pool_ &&
desc.storage_mode == StorageMode::kHostVisible &&
482 allocation_info.pool = staging_buffer_pool_.get().pool;
486 VmaAllocation buffer_allocation = {};
487 VmaAllocationInfo buffer_allocation_info = {};
488 auto result = vk::Result{::vmaCreateBuffer(allocator_.get(),
493 &buffer_allocation_info
496 if (
result != vk::Result::eSuccess) {
502 return std::make_shared<DeviceBufferVK>(
508 buffer_allocation_info
512size_t AllocatorVK::DebugGetHeapUsage()
const {
513 auto count = memory_properties_.memoryHeapCount;
514 std::vector<VmaBudget> budgets(
count);
515 vmaGetHeapBudgets(allocator_.get(), budgets.data());
516 size_t total_usage = 0;
518 const VmaBudget& budget = budgets[
i];
519 total_usage += budget.usage;
526void AllocatorVK::DebugTraceMemoryStatistics()
const {
529 reinterpret_cast<int64_t
>(
this),
530 "MemoryBudgetUsageMB", DebugGetHeapUsage());
static void readback(const SkBitmap &src, int *result, int resultCount)
#define BIND_VMA_PROC_KHR(x)
sk_sp< DlImage > image() const
vk::ImageView GetRenderTargetView() const override
Retrieve the image view used for render target attachments with this texture source.
vk::Image GetImage() const override
Get the image handle for this texture source.
vk::ImageView GetImageView() const override
Retrieve the image view used for sampling/blitting/compute with this texture source.
~AllocatedTextureSourceVK()=default
AllocatedTextureSourceVK(std::weak_ptr< ResourceManagerVK > resource_manager, const TextureDescriptor &desc, VmaAllocator allocator, vk::Device device, bool supports_memoryless_textures)
bool IsSwapchainImage() const override
Determines if swapchain image. That is, an image used as the root render target.
Abstract base class that represents a vkImage and an vkImageView.
VkPhysicalDevice physical_device
FlutterSemanticsFlag flags
uint32_t uint32_t * format
#define FML_UNREACHABLE()
#define FML_DCHECK(condition)
sk_sp< const SkImage > image
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
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 mode
static constexpr vk::Flags< vk::MemoryPropertyFlagBits > ToVKBufferMemoryPropertyFlags(StorageMode mode)
constexpr uint32_t ToArrayLayerCount(TextureType type)
static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags(StorageMode mode, bool readback)
std::string TextureUsageMaskToString(TextureUsageMask mask)
StorageMode
Specified where the allocation resides and how it is used.
static constexpr vk::Flags< vk::MemoryPropertyFlagBits > ToVKTextureMemoryPropertyFlags(StorageMode mode, bool supports_memoryless_textures)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
constexpr bool PixelFormatIsDepthStencil(PixelFormat format)
static constexpr VmaMemoryUsage ToVMAMemoryUsage()
constexpr vk::ImageViewType ToVKImageViewType(TextureType type)
constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count)
constexpr vk::Format ToVKImageFormat(PixelFormat format)
static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode)
static PoolVMA CreateBufferPool(VmaAllocator allocator)
constexpr const char * TextureTypeToString(TextureType type)
constexpr const char * StorageModeToString(StorageMode mode)
constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type)
constexpr vk::ImageAspectFlags ToVKImageAspectFlags(PixelFormat format)
fml::UniqueObject< BufferVMA, BufferVMATraits > UniqueBufferVMA
static SkString to_string(int n)
static void usage(char *argv0)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)
VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName)
VkFlags VkMemoryPropertyFlags
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory)
VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements)
VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements)
VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *pName)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage)
VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR void VKAPI_CALL vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties)
VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData)
VKAPI_ATTR VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges)
VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory)
VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges)
VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos)
VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos)
VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset)