9 #include "flutter/fml/memory/ref_ptr.h"
10 #include "flutter/fml/trace_event.h"
18 static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
22 return vk::MemoryPropertyFlagBits::eHostVisible;
24 return vk::MemoryPropertyFlagBits::eDeviceLocal;
26 return vk::MemoryPropertyFlagBits::eLazilyAllocated;
33 VmaAllocationCreateFlags flags = 0;
36 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
37 flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
48 vk::BufferCreateInfo buffer_info;
49 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
50 vk::BufferUsageFlagBits::eIndexBuffer |
51 vk::BufferUsageFlagBits::eUniformBuffer |
52 vk::BufferUsageFlagBits::eStorageBuffer |
53 vk::BufferUsageFlagBits::eTransferSrc |
54 vk::BufferUsageFlagBits::eTransferDst;
55 buffer_info.size = 1u;
56 buffer_info.sharingMode = vk::SharingMode::eExclusive;
57 auto buffer_info_native =
58 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
60 VmaAllocationCreateInfo allocation_info = {};
61 allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
62 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
64 allocation_info.flags =
67 uint32_t memTypeIndex;
68 auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
69 allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
70 if (result != vk::Result::eSuccess) {
74 VmaPoolCreateInfo pool_create_info = {};
75 pool_create_info.memoryTypeIndex = memTypeIndex;
76 pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
79 result = vk::Result{::vmaCreatePool(allocator, &pool_create_info, &pool)};
80 if (result != vk::Result::eSuccess) {
83 return {allocator, pool};
86 AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
87 uint32_t vulkan_api_version,
88 const vk::PhysicalDevice& physical_device,
89 const std::shared_ptr<DeviceHolder>& device_holder,
90 const vk::Instance& instance,
91 const CapabilitiesVK& capabilities)
92 : context_(
std::move(context)), device_holder_(device_holder) {
93 TRACE_EVENT0(
"impeller",
"CreateAllocatorVK");
95 auto limits = physical_device.getProperties().limits;
96 max_texture_size_.width = max_texture_size_.height =
97 limits.maxImageDimension2D;
99 VmaVulkanFunctions proc_table = {};
101 #define BIND_VMA_PROC(x) proc_table.x = VULKAN_HPP_DEFAULT_DISPATCHER.x;
102 #define BIND_VMA_PROC_KHR(x) \
103 proc_table.x##KHR = VULKAN_HPP_DEFAULT_DISPATCHER.x \
104 ? VULKAN_HPP_DEFAULT_DISPATCHER.x \
105 : VULKAN_HPP_DEFAULT_DISPATCHER.x##KHR;
130 #undef BIND_VMA_PROC_KHR
133 VmaAllocatorCreateInfo allocator_info = {};
134 allocator_info.vulkanApiVersion = vulkan_api_version;
135 allocator_info.physicalDevice = physical_device;
136 allocator_info.device = device_holder->GetDevice();
137 allocator_info.instance = instance;
138 allocator_info.pVulkanFunctions = &proc_table;
140 VmaAllocator allocator = {};
141 auto result = vk::Result{::vmaCreateAllocator(&allocator_info, &allocator)};
142 if (result != vk::Result::eSuccess) {
147 created_buffer_pool_ &= staging_buffer_pool_.is_valid();
148 allocator_.reset(allocator);
149 supports_memoryless_textures_ =
150 capabilities.SupportsDeviceTransientTextures();
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 vk::ImageUsageFlags vk_usage;
174 case StorageMode::kHostVisible:
175 case StorageMode::kDevicePrivate:
177 case StorageMode::kDeviceTransient:
178 if (supports_memoryless_textures) {
179 vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
186 vk_usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
188 vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
193 vk_usage |= vk::ImageUsageFlagBits::eSampled;
198 if (mode == StorageMode::kDeviceTransient) {
199 vk_usage &= ~vk::ImageUsageFlagBits::eTransientAttachment;
204 vk_usage |= vk::ImageUsageFlagBits::eStorage;
209 if (mode == StorageMode::kDeviceTransient) {
210 vk_usage &= ~vk::ImageUsageFlagBits::eTransientAttachment;
214 if (mode != StorageMode::kDeviceTransient) {
217 vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
218 vk::ImageUsageFlagBits::eTransferDst;
225 return VMA_MEMORY_USAGE_AUTO;
228 static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
230 bool supports_memoryless_textures) {
232 case StorageMode::kHostVisible:
233 return vk::MemoryPropertyFlagBits::eHostVisible |
234 vk::MemoryPropertyFlagBits::eDeviceLocal;
235 case StorageMode::kDevicePrivate:
236 return vk::MemoryPropertyFlagBits::eDeviceLocal;
237 case StorageMode::kDeviceTransient:
238 if (supports_memoryless_textures) {
239 return vk::MemoryPropertyFlagBits::eLazilyAllocated |
240 vk::MemoryPropertyFlagBits::eDeviceLocal;
242 return vk::MemoryPropertyFlagBits::eDeviceLocal;
248 VmaAllocationCreateFlags flags = 0;
250 case StorageMode::kHostVisible:
252 case StorageMode::kDevicePrivate:
254 case StorageMode::kDeviceTransient:
264 VmaAllocator allocator,
266 bool supports_memoryless_textures)
268 TRACE_EVENT0(
"impeller",
"CreateDeviceTexture");
269 vk::ImageCreateInfo image_info;
271 image_info.imageType = vk::ImageType::e2D;
273 image_info.extent = VkExtent3D{
281 image_info.tiling = vk::ImageTiling::eOptimal;
282 image_info.initialLayout = vk::ImageLayout::eUndefined;
285 supports_memoryless_textures);
286 image_info.sharingMode = vk::SharingMode::eExclusive;
288 VmaAllocationCreateInfo alloc_nfo = {};
291 alloc_nfo.preferredFlags =
296 auto create_info_native =
297 static_cast<vk::ImageCreateInfo::NativeType
>(image_info);
299 VkImage vk_image = VK_NULL_HANDLE;
300 VmaAllocation allocation = {};
301 VmaAllocationInfo allocation_info = {};
303 auto result = vk::Result{::vmaCreateImage(allocator,
310 if (result != vk::Result::eSuccess) {
312 << vk::to_string(result)
316 <<
" [VK]Flags: " << vk::to_string(image_info.flags)
317 <<
" [VK]Format: " << vk::to_string(image_info.format)
318 <<
" [VK]Usage: " << vk::to_string(image_info.usage)
319 <<
" [VK]Mem. Flags: "
320 << vk::to_string(vk::MemoryPropertyFlags(
321 alloc_nfo.preferredFlags));
326 auto image = vk::Image{vk_image};
328 vk::ImageViewCreateInfo view_info = {};
329 view_info.image = image;
331 view_info.format = image_info.format;
333 view_info.subresourceRange.levelCount = image_info.mipLevels;
340 if (desc.
format == PixelFormat::kA8UNormInt) {
341 view_info.components.a = vk::ComponentSwizzle::eR;
342 view_info.components.r = vk::ComponentSwizzle::eA;
345 auto [result, image_view] = device.createImageViewUnique(view_info);
346 if (result != vk::Result::eSuccess) {
347 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
348 << vk::to_string(result);
351 resource_.Swap(ImageResource(
ImageVMA{allocator, allocation, image},
352 std::move(image_view)));
360 vk::Image
GetImage()
const override {
return resource_->image.get().image; }
363 return resource_->image_view.get();
367 struct ImageResource {
369 vk::UniqueImageView image_view;
371 ImageResource() =
default;
373 ImageResource(
ImageVMA p_image, vk::UniqueImageView p_image_view)
374 : image(p_image), image_view(
std::move(p_image_view)) {}
376 ImageResource(ImageResource&& o) {
377 std::swap(image, o.image);
378 std::swap(image_view, o.image_view);
381 FML_DISALLOW_COPY_AND_ASSIGN(ImageResource);
384 UniqueResourceVKT<ImageResource> resource_;
385 bool is_valid_ =
false;
387 FML_DISALLOW_COPY_AND_ASSIGN(AllocatedTextureSourceVK);
391 std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
392 const TextureDescriptor& desc) {
393 TRACE_EVENT0(
"impeller",
"AllocatorVK::OnCreateTexture");
397 auto device_holder = device_holder_.lock();
398 if (!device_holder) {
401 auto context = context_.lock();
405 auto source = std::make_shared<AllocatedTextureSourceVK>(
406 ContextVK::Cast(*context).GetResourceManager(),
409 device_holder->GetDevice(),
410 supports_memoryless_textures_
412 if (!source->IsValid()) {
415 return std::make_shared<TextureVK>(context_, std::move(source));
418 void AllocatorVK::DidAcquireSurfaceFrame() {
420 raster_thread_id_ = std::this_thread::get_id();
424 std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
425 const DeviceBufferDescriptor& desc) {
426 TRACE_EVENT0(
"impeller",
"AllocatorVK::OnCreateBuffer");
427 vk::BufferCreateInfo buffer_info;
428 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
429 vk::BufferUsageFlagBits::eIndexBuffer |
430 vk::BufferUsageFlagBits::eUniformBuffer |
431 vk::BufferUsageFlagBits::eStorageBuffer |
432 vk::BufferUsageFlagBits::eTransferSrc |
433 vk::BufferUsageFlagBits::eTransferDst;
434 buffer_info.size = desc.size;
435 buffer_info.sharingMode = vk::SharingMode::eExclusive;
436 auto buffer_info_native =
437 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
439 VmaAllocationCreateInfo allocation_info = {};
441 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
444 if (created_buffer_pool_ && desc.storage_mode == StorageMode::kHostVisible &&
445 raster_thread_id_ == std::this_thread::get_id()) {
446 allocation_info.pool = staging_buffer_pool_.get().pool;
449 VkBuffer buffer = {};
450 VmaAllocation buffer_allocation = {};
451 VmaAllocationInfo buffer_allocation_info = {};
452 auto result = vk::Result{::vmaCreateBuffer(allocator_.get(),
457 &buffer_allocation_info
460 if (result != vk::Result::eSuccess) {
462 << vk::to_string(result);
466 return std::make_shared<DeviceBufferVK>(
471 vk::Buffer{buffer}}},
472 buffer_allocation_info