9 #include "flutter/fml/memory/ref_ptr.h"
10 #include "flutter/fml/trace_event.h"
15 #include "vulkan/vulkan_enums.hpp"
19 static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
23 return vk::MemoryPropertyFlagBits::eHostVisible;
25 return vk::MemoryPropertyFlagBits::eDeviceLocal;
27 return vk::MemoryPropertyFlagBits::eLazilyAllocated;
34 VmaAllocationCreateFlags flags = 0;
37 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
38 flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
49 vk::BufferCreateInfo buffer_info;
50 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
51 vk::BufferUsageFlagBits::eIndexBuffer |
52 vk::BufferUsageFlagBits::eUniformBuffer |
53 vk::BufferUsageFlagBits::eStorageBuffer |
54 vk::BufferUsageFlagBits::eTransferSrc |
55 vk::BufferUsageFlagBits::eTransferDst;
56 buffer_info.size = 1u;
57 buffer_info.sharingMode = vk::SharingMode::eExclusive;
58 auto buffer_info_native =
59 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
61 VmaAllocationCreateInfo allocation_info = {};
62 allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
63 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
65 allocation_info.flags =
68 uint32_t memTypeIndex;
69 auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
70 allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
71 if (result != vk::Result::eSuccess) {
75 VmaPoolCreateInfo pool_create_info = {};
76 pool_create_info.memoryTypeIndex = memTypeIndex;
77 pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
80 result = vk::Result{::vmaCreatePool(allocator, &pool_create_info, &pool)};
81 if (result != vk::Result::eSuccess) {
84 return {allocator, pool};
87 AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
88 uint32_t vulkan_api_version,
89 const vk::PhysicalDevice& physical_device,
90 const std::shared_ptr<DeviceHolder>& device_holder,
91 const vk::Instance& instance,
92 const CapabilitiesVK& capabilities)
93 : context_(
std::move(context)), device_holder_(device_holder) {
94 auto limits = physical_device.getProperties().limits;
95 max_texture_size_.width = max_texture_size_.height =
96 limits.maxImageDimension2D;
98 VmaVulkanFunctions proc_table = {};
100 #define BIND_VMA_PROC(x) proc_table.x = VULKAN_HPP_DEFAULT_DISPATCHER.x;
101 #define BIND_VMA_PROC_KHR(x) \
102 proc_table.x##KHR = VULKAN_HPP_DEFAULT_DISPATCHER.x \
103 ? VULKAN_HPP_DEFAULT_DISPATCHER.x \
104 : VULKAN_HPP_DEFAULT_DISPATCHER.x##KHR;
129 #undef BIND_VMA_PROC_KHR
132 VmaAllocatorCreateInfo allocator_info = {};
133 allocator_info.vulkanApiVersion = vulkan_api_version;
134 allocator_info.physicalDevice = physical_device;
135 allocator_info.device = device_holder->GetDevice();
136 allocator_info.instance = instance;
137 allocator_info.pVulkanFunctions = &proc_table;
139 VmaAllocator allocator = {};
140 auto result = vk::Result{::vmaCreateAllocator(&allocator_info, &allocator)};
141 if (result != vk::Result::eSuccess) {
146 created_buffer_pool_ &= staging_buffer_pool_.is_valid();
147 allocator_.reset(allocator);
148 supports_memoryless_textures_ =
149 capabilities.SupportsDeviceTransientTextures();
150 supports_framebuffer_fetch_ = capabilities.SupportsFramebufferFetch();
154 AllocatorVK::~AllocatorVK() =
default;
157 bool AllocatorVK::IsValid()
const {
162 ISize AllocatorVK::GetMaxTextureSizeSupported()
const {
163 return max_texture_size_;
170 bool supports_memoryless_textures,
171 bool supports_framebuffer_fetch) {
172 vk::ImageUsageFlags vk_usage;
175 case StorageMode::kHostVisible:
176 case StorageMode::kDevicePrivate:
178 case StorageMode::kDeviceTransient:
179 if (supports_memoryless_textures) {
180 vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
187 vk_usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
189 vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
191 if (supports_framebuffer_fetch) {
192 vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
197 vk_usage |= vk::ImageUsageFlagBits::eSampled;
202 if (mode == StorageMode::kDeviceTransient) {
203 vk_usage &= ~vk::ImageUsageFlagBits::eTransientAttachment;
208 vk_usage |= vk::ImageUsageFlagBits::eStorage;
213 if (mode == StorageMode::kDeviceTransient) {
214 vk_usage &= ~vk::ImageUsageFlagBits::eTransientAttachment;
218 if (mode != StorageMode::kDeviceTransient) {
221 vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
222 vk::ImageUsageFlagBits::eTransferDst;
229 return VMA_MEMORY_USAGE_AUTO;
232 static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
234 bool supports_memoryless_textures) {
236 case StorageMode::kHostVisible:
237 return vk::MemoryPropertyFlagBits::eHostVisible |
238 vk::MemoryPropertyFlagBits::eDeviceLocal;
239 case StorageMode::kDevicePrivate:
240 return vk::MemoryPropertyFlagBits::eDeviceLocal;
241 case StorageMode::kDeviceTransient:
242 if (supports_memoryless_textures) {
243 return vk::MemoryPropertyFlagBits::eLazilyAllocated |
244 vk::MemoryPropertyFlagBits::eDeviceLocal;
246 return vk::MemoryPropertyFlagBits::eDeviceLocal;
252 VmaAllocationCreateFlags flags = 0;
254 case StorageMode::kHostVisible:
256 case StorageMode::kDevicePrivate:
258 case StorageMode::kDeviceTransient:
268 VmaAllocator allocator,
270 bool supports_memoryless_textures,
271 bool supports_framebuffer_fetch)
273 FML_DCHECK(desc.
format != PixelFormat::kUnknown);
274 vk::ImageCreateInfo image_info;
276 image_info.imageType = vk::ImageType::e2D;
278 image_info.extent = VkExtent3D{
286 image_info.tiling = vk::ImageTiling::eOptimal;
287 image_info.initialLayout = vk::ImageLayout::eUndefined;
290 supports_memoryless_textures, supports_framebuffer_fetch);
291 image_info.sharingMode = vk::SharingMode::eExclusive;
293 VmaAllocationCreateInfo alloc_nfo = {};
296 alloc_nfo.preferredFlags =
301 auto create_info_native =
302 static_cast<vk::ImageCreateInfo::NativeType
>(image_info);
304 VkImage vk_image = VK_NULL_HANDLE;
305 VmaAllocation allocation = {};
306 VmaAllocationInfo allocation_info = {};
308 auto result = vk::Result{::vmaCreateImage(allocator,
315 if (result != vk::Result::eSuccess) {
317 << vk::to_string(result)
321 <<
" [VK]Flags: " << vk::to_string(image_info.flags)
322 <<
" [VK]Format: " << vk::to_string(image_info.format)
323 <<
" [VK]Usage: " << vk::to_string(image_info.usage)
324 <<
" [VK]Mem. Flags: "
325 << vk::to_string(vk::MemoryPropertyFlags(
326 alloc_nfo.preferredFlags));
331 auto image = vk::Image{vk_image};
333 vk::ImageViewCreateInfo view_info = {};
334 view_info.image = image;
336 view_info.format = image_info.format;
338 view_info.subresourceRange.levelCount = image_info.mipLevels;
345 if (desc.
format == PixelFormat::kA8UNormInt) {
346 view_info.components.a = vk::ComponentSwizzle::eR;
347 view_info.components.r = vk::ComponentSwizzle::eA;
350 auto [result, image_view] = device.createImageViewUnique(view_info);
351 if (result != vk::Result::eSuccess) {
352 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
353 << vk::to_string(result);
356 resource_.Swap(ImageResource(
ImageVMA{allocator, allocation, image},
357 std::move(image_view)));
365 vk::Image
GetImage()
const override {
return resource_->image.get().image; }
368 return resource_->image_view.get();
372 struct ImageResource {
374 vk::UniqueImageView image_view;
376 ImageResource() =
default;
378 ImageResource(
ImageVMA p_image, vk::UniqueImageView p_image_view)
379 : image(p_image), image_view(
std::move(p_image_view)) {}
381 ImageResource(ImageResource&& o) {
382 std::swap(image, o.image);
383 std::swap(image_view, o.image_view);
386 ImageResource(
const ImageResource&) =
delete;
388 ImageResource& operator=(
const ImageResource&) =
delete;
391 UniqueResourceVKT<ImageResource> resource_;
392 bool is_valid_ =
false;
394 AllocatedTextureSourceVK(
const AllocatedTextureSourceVK&) =
delete;
396 AllocatedTextureSourceVK& operator=(
const AllocatedTextureSourceVK&) =
delete;
400 std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
401 const TextureDescriptor& desc) {
405 auto device_holder = device_holder_.lock();
406 if (!device_holder) {
409 auto context = context_.lock();
413 auto source = std::make_shared<AllocatedTextureSourceVK>(
414 ContextVK::Cast(*context).GetResourceManager(),
417 device_holder->GetDevice(),
418 supports_memoryless_textures_,
419 supports_framebuffer_fetch_
421 if (!source->IsValid()) {
424 return std::make_shared<TextureVK>(context_, std::move(source));
427 void AllocatorVK::DidAcquireSurfaceFrame() {
429 raster_thread_id_ = std::this_thread::get_id();
433 std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
434 const DeviceBufferDescriptor& desc) {
435 vk::BufferCreateInfo buffer_info;
436 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
437 vk::BufferUsageFlagBits::eIndexBuffer |
438 vk::BufferUsageFlagBits::eUniformBuffer |
439 vk::BufferUsageFlagBits::eStorageBuffer |
440 vk::BufferUsageFlagBits::eTransferSrc |
441 vk::BufferUsageFlagBits::eTransferDst;
442 buffer_info.size = desc.size;
443 buffer_info.sharingMode = vk::SharingMode::eExclusive;
444 auto buffer_info_native =
445 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
447 VmaAllocationCreateInfo allocation_info = {};
449 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
452 if (created_buffer_pool_ && desc.storage_mode == StorageMode::kHostVisible &&
453 raster_thread_id_ == std::this_thread::get_id()) {
454 allocation_info.pool = staging_buffer_pool_.get().pool;
457 VkBuffer buffer = {};
458 VmaAllocation buffer_allocation = {};
459 VmaAllocationInfo buffer_allocation_info = {};
460 auto result = vk::Result{::vmaCreateBuffer(allocator_.get(),
465 &buffer_allocation_info
468 if (result != vk::Result::eSuccess) {
470 << vk::to_string(result);
474 return std::make_shared<DeviceBufferVK>(
479 vk::Buffer{buffer}}},
480 buffer_allocation_info