Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
allocator_vk.cc
Go to the documentation of this file.
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
6
7#include <memory>
8#include <mutex>
9#include <utility>
10
11#include "flutter/fml/logging.h"
21#include "vulkan/vulkan_enums.hpp"
22
23namespace impeller {
24
25static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
27 switch (mode) {
29 return vk::MemoryPropertyFlagBits::eHostVisible;
31 return vk::MemoryPropertyFlagBits::eDeviceLocal;
33 return vk::MemoryPropertyFlagBits::eLazilyAllocated;
34 }
36}
37
38static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags(
39 StorageMode mode,
40 bool readback) {
41 VmaAllocationCreateFlags flags = 0;
42 switch (mode) {
44 if (!readback) {
45 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
46 } else {
47 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
48 }
49 flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
50 return flags;
52 FML_DCHECK(!readback);
53 return flags;
55 FML_DCHECK(!readback);
56 return flags;
57 }
59}
60
61static PoolVMA CreateBufferPool(VmaAllocator allocator) {
62 vk::BufferCreateInfo buffer_info;
63 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
64 vk::BufferUsageFlagBits::eIndexBuffer |
65 vk::BufferUsageFlagBits::eUniformBuffer |
66 vk::BufferUsageFlagBits::eStorageBuffer |
67 vk::BufferUsageFlagBits::eTransferSrc |
68 vk::BufferUsageFlagBits::eTransferDst;
69 buffer_info.size = 1u; // doesn't matter
70 buffer_info.sharingMode = vk::SharingMode::eExclusive;
71 auto buffer_info_native =
72 static_cast<vk::BufferCreateInfo::NativeType>(buffer_info);
73
74 VmaAllocationCreateInfo allocation_info = {};
75 allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
76 allocation_info.preferredFlags = static_cast<VkMemoryPropertyFlags>(
78 allocation_info.flags = ToVmaAllocationBufferCreateFlags(
79 StorageMode::kHostVisible, /*readback=*/false);
80
81 uint32_t memTypeIndex;
82 auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
83 allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
84 if (result != vk::Result::eSuccess) {
85 return {};
86 }
87
88 VmaPoolCreateInfo pool_create_info = {};
89 pool_create_info.memoryTypeIndex = memTypeIndex;
90 pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
91 pool_create_info.minBlockCount = 1;
92
93 VmaPool pool = {};
94 result = vk::Result{::vmaCreatePool(allocator, &pool_create_info, &pool)};
95 if (result != vk::Result::eSuccess) {
96 return {};
97 }
98 return {allocator, pool};
99}
100
101AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
102 uint32_t vulkan_api_version,
103 const vk::PhysicalDevice& physical_device,
104 const std::shared_ptr<DeviceHolderVK>& device_holder,
105 const vk::Instance& instance,
106 const CapabilitiesVK& capabilities)
107 : context_(std::move(context)), device_holder_(device_holder) {
108 auto limits = physical_device.getProperties().limits;
109 max_texture_size_.width = max_texture_size_.height =
110 limits.maxImageDimension2D;
111 physical_device.getMemoryProperties(&memory_properties_);
112
113 VmaVulkanFunctions proc_table = {};
114
115#define BIND_VMA_PROC(x) proc_table.x = VULKAN_HPP_DEFAULT_DISPATCHER.x;
116#define BIND_VMA_PROC_KHR(x) \
117 proc_table.x##KHR = VULKAN_HPP_DEFAULT_DISPATCHER.x \
118 ? VULKAN_HPP_DEFAULT_DISPATCHER.x \
119 : VULKAN_HPP_DEFAULT_DISPATCHER.x##KHR;
120 BIND_VMA_PROC(vkGetInstanceProcAddr);
121 BIND_VMA_PROC(vkGetDeviceProcAddr);
122 BIND_VMA_PROC(vkGetPhysicalDeviceProperties);
123 BIND_VMA_PROC(vkGetPhysicalDeviceMemoryProperties);
124 BIND_VMA_PROC(vkAllocateMemory);
125 BIND_VMA_PROC(vkFreeMemory);
126 BIND_VMA_PROC(vkMapMemory);
127 BIND_VMA_PROC(vkUnmapMemory);
128 BIND_VMA_PROC(vkFlushMappedMemoryRanges);
129 BIND_VMA_PROC(vkInvalidateMappedMemoryRanges);
130 BIND_VMA_PROC(vkBindBufferMemory);
131 BIND_VMA_PROC(vkBindImageMemory);
132 BIND_VMA_PROC(vkGetBufferMemoryRequirements);
133 BIND_VMA_PROC(vkGetImageMemoryRequirements);
134 BIND_VMA_PROC(vkCreateBuffer);
135 BIND_VMA_PROC(vkDestroyBuffer);
136 BIND_VMA_PROC(vkCreateImage);
137 BIND_VMA_PROC(vkDestroyImage);
138 BIND_VMA_PROC(vkCmdCopyBuffer);
139 BIND_VMA_PROC_KHR(vkGetBufferMemoryRequirements2);
140 BIND_VMA_PROC_KHR(vkGetImageMemoryRequirements2);
141 BIND_VMA_PROC_KHR(vkBindBufferMemory2);
142 BIND_VMA_PROC_KHR(vkBindImageMemory2);
143 BIND_VMA_PROC_KHR(vkGetPhysicalDeviceMemoryProperties2);
144#undef BIND_VMA_PROC_KHR
145#undef BIND_VMA_PROC
146
147 VmaAllocatorCreateInfo allocator_info = {};
148 allocator_info.vulkanApiVersion = vulkan_api_version;
149 allocator_info.physicalDevice = physical_device;
150 allocator_info.device = device_holder->GetDevice();
151 allocator_info.instance = instance;
152 // 4 MB, matching the default used by Skia Vulkan.
153 allocator_info.preferredLargeHeapBlockSize = 4 * 1024 * 1024;
154 allocator_info.pVulkanFunctions = &proc_table;
155
156 VmaAllocator allocator = {};
157 auto result = vk::Result{::vmaCreateAllocator(&allocator_info, &allocator)};
158 if (result != vk::Result::eSuccess) {
159 VALIDATION_LOG << "Could not create memory allocator";
160 return;
161 }
162 staging_buffer_pool_.reset(CreateBufferPool(allocator));
163 created_buffer_pool_ &= staging_buffer_pool_.is_valid();
164 allocator_.reset(allocator);
165 supports_memoryless_textures_ =
166 capabilities.SupportsDeviceTransientTextures();
167 is_valid_ = true;
168}
169
170AllocatorVK::~AllocatorVK() = default;
171
172// |Allocator|
173bool AllocatorVK::IsValid() const {
174 return is_valid_;
175}
176
177// |Allocator|
178ISize AllocatorVK::GetMaxTextureSizeSupported() const {
179 return max_texture_size_;
180}
181
182int32_t AllocatorVK::FindMemoryTypeIndex(
183 uint32_t memory_type_bits_requirement,
184 vk::PhysicalDeviceMemoryProperties& memory_properties) {
185 int32_t type_index = -1;
186 vk::MemoryPropertyFlagBits required_properties =
187 vk::MemoryPropertyFlagBits::eDeviceLocal;
188
189 const uint32_t memory_count = memory_properties.memoryTypeCount;
190 for (uint32_t memory_index = 0; memory_index < memory_count; ++memory_index) {
191 const uint32_t memory_type_bits = (1 << memory_index);
192 const bool is_required_memory_type =
193 memory_type_bits_requirement & memory_type_bits;
194
195 const auto properties =
196 memory_properties.memoryTypes[memory_index].propertyFlags;
197 const bool has_required_properties =
198 (properties & required_properties) == required_properties;
199
200 if (is_required_memory_type && has_required_properties) {
201 return static_cast<int32_t>(memory_index);
202 }
203 }
204
205 return type_index;
206}
207
208vk::ImageUsageFlags AllocatorVK::ToVKImageUsageFlags(
209 PixelFormat format,
210 TextureUsageMask usage,
211 StorageMode mode,
212 bool supports_memoryless_textures) {
213 vk::ImageUsageFlags vk_usage;
214
215 switch (mode) {
216 case StorageMode::kHostVisible:
217 case StorageMode::kDevicePrivate:
218 break;
219 case StorageMode::kDeviceTransient:
220 if (supports_memoryless_textures) {
221 vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
222 }
223 break;
224 }
225
226 if (usage & TextureUsage::kRenderTarget) {
228 vk_usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
229 } else {
230 vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
231 vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
232 }
233 }
234
235 if (usage & TextureUsage::kShaderRead) {
236 vk_usage |= vk::ImageUsageFlagBits::eSampled;
237 }
238
239 if (usage & TextureUsage::kShaderWrite) {
240 vk_usage |= vk::ImageUsageFlagBits::eStorage;
241 }
242
243 if (mode != StorageMode::kDeviceTransient) {
244 // Add transfer usage flags to support blit passes only if image isn't
245 // device transient.
246 vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
247 vk::ImageUsageFlagBits::eTransferDst;
248 }
249
250 return vk_usage;
251}
252
253static constexpr VmaMemoryUsage ToVMAMemoryUsage() {
254 return VMA_MEMORY_USAGE_AUTO;
255}
256
257static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
259 bool supports_memoryless_textures) {
260 switch (mode) {
261 case StorageMode::kHostVisible:
262 return vk::MemoryPropertyFlagBits::eHostVisible |
263 vk::MemoryPropertyFlagBits::eDeviceLocal;
264 case StorageMode::kDevicePrivate:
265 return vk::MemoryPropertyFlagBits::eDeviceLocal;
266 case StorageMode::kDeviceTransient:
267 if (supports_memoryless_textures) {
268 return vk::MemoryPropertyFlagBits::eLazilyAllocated |
269 vk::MemoryPropertyFlagBits::eDeviceLocal;
270 }
271 return vk::MemoryPropertyFlagBits::eDeviceLocal;
272 }
274}
275
276static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode) {
277 VmaAllocationCreateFlags flags = 0;
278 switch (mode) {
279 case StorageMode::kHostVisible:
280 return flags;
281 case StorageMode::kDevicePrivate:
282 return flags;
283 case StorageMode::kDeviceTransient:
284 return flags;
285 }
287}
288
290 public:
292 const TextureDescriptor& desc,
293 VmaAllocator allocator,
294 vk::Device device,
295 bool supports_memoryless_textures)
296 : TextureSourceVK(desc), resource_(context.GetResourceManager()) {
297 FML_DCHECK(desc.format != PixelFormat::kUnknown);
298 vk::StructureChain<vk::ImageCreateInfo, vk::ImageCompressionControlEXT>
299 image_info_chain;
300 auto& image_info = image_info_chain.get();
301 image_info.flags = ToVKImageCreateFlags(desc.type);
302 image_info.imageType = vk::ImageType::e2D;
303 image_info.format = ToVKImageFormat(desc.format);
304 image_info.extent = VkExtent3D{
305 static_cast<uint32_t>(desc.size.width), // width
306 static_cast<uint32_t>(desc.size.height), // height
307 1u // depth
308 };
309 image_info.samples = ToVKSampleCount(desc.sample_count);
310 image_info.mipLevels = desc.mip_count;
311 image_info.arrayLayers = ToArrayLayerCount(desc.type);
312 image_info.tiling = vk::ImageTiling::eOptimal;
313 image_info.initialLayout = vk::ImageLayout::eUndefined;
314 image_info.usage = AllocatorVK::ToVKImageUsageFlags(
315 desc.format, desc.usage, desc.storage_mode,
316 supports_memoryless_textures);
317 image_info.sharingMode = vk::SharingMode::eExclusive;
318
319 vk::ImageCompressionFixedRateFlagsEXT frc_rates[1] = {
320 vk::ImageCompressionFixedRateFlagBitsEXT::eNone};
321
322 const auto frc_rate =
323 CapabilitiesVK::Cast(*context.GetCapabilities())
324 .GetSupportedFRCRate(desc.compression_type,
325 FRCFormatDescriptor{image_info});
326 if (frc_rate.has_value()) {
327 // This array must not be in a temporary scope.
328 frc_rates[0] = frc_rate.value();
329
330 auto& compression_info =
331 image_info_chain.get<vk::ImageCompressionControlEXT>();
332 compression_info.pFixedRateFlags = frc_rates;
333 compression_info.compressionControlPlaneCount = 1u;
334 compression_info.flags =
335 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
336 } else {
337 image_info_chain.unlink<vk::ImageCompressionControlEXT>();
338 }
339
340 VmaAllocationCreateInfo alloc_nfo = {};
341
342 alloc_nfo.usage = ToVMAMemoryUsage();
343 alloc_nfo.preferredFlags =
344 static_cast<VkMemoryPropertyFlags>(ToVKTextureMemoryPropertyFlags(
345 desc.storage_mode, supports_memoryless_textures));
346 alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode);
347
348 VkImage vk_image = VK_NULL_HANDLE;
349 VmaAllocation allocation = {};
350 VmaAllocationInfo allocation_info = {};
351
352 // Performs the VMA image allocation using the current create-info chain.
353 // The native create-info is re-derived from the chain on each call, so an
354 // unlink of the compression-control struct between calls is reflected.
355 const auto try_create_image = [&]() -> vk::Result {
356 vk::ImageCreateInfo::NativeType create_info_native =
357 static_cast<vk::ImageCreateInfo::NativeType>(
358 image_info_chain.get<vk::ImageCreateInfo>());
359 return vk::Result{::vmaCreateImage(allocator, //
360 &create_info_native, //
361 &alloc_nfo, //
362 &vk_image, //
363 &allocation, //
364 &allocation_info //
365 )};
366 };
367
368 // Fixed-rate compression was requested iff a rate was selected above.
369 const bool requested_compression = frc_rate.has_value();
370 vk::Result alloc_result = try_create_image();
371
372 // Some drivers (e.g. PowerVR) can return VK_ERROR_COMPRESSION_EXHAUSTED_EXT
373 // when fixed-rate compression resources are depleted. Per the Vulkan spec
374 // this error is only returned for fixed-rate compression requests, so
375 // retrying without compression is a valid recovery. Without it the
376 // allocation fails, the texture is invalid, and the resulting null render
377 // target crashes the raster thread.
378 if (alloc_result == vk::Result::eErrorCompressionExhaustedEXT &&
379 requested_compression) {
380 static std::once_flag warn_once;
381 std::call_once(warn_once, [] {
382 FML_LOG(WARNING)
383 << "Fixed-rate image compression exhausted; falling back to "
384 "uncompressed image allocation. (This message is logged once.)";
385 });
386 // The compression-control struct is only present here because compression
387 // was requested above, so unlinking it once is safe (no double-unlink).
388 image_info_chain.unlink<vk::ImageCompressionControlEXT>();
389 alloc_result = try_create_image();
390 }
391
392 if (alloc_result != vk::Result::eSuccess) {
393 VALIDATION_LOG << "Unable to allocate Vulkan Image: "
394 << vk::to_string(alloc_result)
395 << " Type: " << TextureTypeToString(desc.type)
396 << " Mode: " << StorageModeToString(desc.storage_mode)
397 << " Usage: " << TextureUsageMaskToString(desc.usage)
398 << " [VK]Flags: " << vk::to_string(image_info.flags)
399 << " [VK]Format: " << vk::to_string(image_info.format)
400 << " [VK]Usage: " << vk::to_string(image_info.usage)
401 << " [VK]Mem. Flags: "
402 << vk::to_string(
403 vk::MemoryPropertyFlags(alloc_nfo.preferredFlags));
404 return;
405 }
406
407 auto image = vk::Image{vk_image};
408
409 vk::ImageViewCreateInfo view_info = {};
410 view_info.image = image;
411 view_info.viewType = ToVKImageViewType(desc.type);
412 view_info.format = image_info.format;
413 view_info.subresourceRange.aspectMask = ToVKImageAspectFlags(desc.format);
414 view_info.subresourceRange.levelCount = image_info.mipLevels;
415 view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type);
416
417 // Vulkan does not have an image format that is equivalent to
418 // `MTLPixelFormatA8Unorm`, so we use `R8Unorm` instead. Given that the
419 // shaders expect that alpha channel to be set in the cases, we swizzle.
420 // See: https://github.com/flutter/flutter/issues/115461 for more details.
421 if (desc.format == PixelFormat::kA8UNormInt) {
422 view_info.components.a = vk::ComponentSwizzle::eR;
423 view_info.components.r = vk::ComponentSwizzle::eA;
424 }
425
426 auto [result, image_view] = device.createImageViewUnique(view_info);
427 if (result != vk::Result::eSuccess) {
428 VALIDATION_LOG << "Unable to create an image view for allocation: "
429 << vk::to_string(result);
430 return;
431 }
432 // Create one 2D attachment view per (mip level, array layer) so a
433 // specific subresource can be rendered into. Render targets are usually a
434 // single 2D mip (one view); cube and mipmapped render targets get the
435 // full set. Non-render-target textures only need the base view.
436 view_info.viewType = vk::ImageViewType::e2D;
437 view_info.subresourceRange.levelCount = 1u;
438 view_info.subresourceRange.layerCount = 1u;
439 const bool is_render_target = !!(desc.usage & TextureUsage::kRenderTarget);
440 const uint32_t rt_mip_count = is_render_target ? image_info.mipLevels : 1u;
441 const uint32_t rt_layer_count =
442 is_render_target ? ToArrayLayerCount(desc.type) : 1u;
443 std::vector<vk::UniqueImageView> rt_image_views;
444 rt_image_views.reserve(rt_mip_count * rt_layer_count);
445 for (uint32_t mip = 0; mip < rt_mip_count; mip++) {
446 for (uint32_t layer = 0; layer < rt_layer_count; layer++) {
447 view_info.subresourceRange.baseMipLevel = mip;
448 view_info.subresourceRange.baseArrayLayer = layer;
449 auto [rt_result, rt_image_view] =
450 device.createImageViewUnique(view_info);
451 if (rt_result != vk::Result::eSuccess) {
452 VALIDATION_LOG << "Unable to create a render target image view: "
453 << vk::to_string(rt_result);
454 return;
455 }
456 rt_image_views.push_back(std::move(rt_image_view));
457 }
458 }
459
460 resource_.Swap(ImageResource(
461 ImageVMA{allocator, allocation, image}, std::move(image_view),
462 std::move(rt_image_views), context.GetResourceAllocator(),
463 context.GetDeviceHolder()));
464 is_valid_ = true;
465 }
466
468
469 bool IsValid() const { return is_valid_; }
470
471 vk::Image GetImage() const override { return resource_->image.get().image; }
472
473 vk::ImageView GetImageView() const override {
474 return resource_->image_view.get();
475 }
476
477 vk::ImageView GetRenderTargetView(uint32_t mip_level,
478 uint32_t array_layer) const override {
479 const auto& views = resource_->rt_image_views;
480 if (views.empty()) {
481 return VK_NULL_HANDLE;
482 }
483 const uint32_t layer_count = ToArrayLayerCount(GetTextureDescriptor().type);
484 const size_t index =
485 static_cast<size_t>(mip_level) * layer_count + array_layer;
486 return index < views.size() ? views[index].get() : views[0].get();
487 }
488
489 bool IsSwapchainImage() const override { return false; }
490
491 private:
492 struct ImageResource {
493 std::shared_ptr<DeviceHolderVK> device_holder;
494 std::shared_ptr<Allocator> allocator;
496 vk::UniqueImageView image_view;
497 // One attachment view per (mip level, array layer), row-major by mip.
498 std::vector<vk::UniqueImageView> rt_image_views;
499
500 ImageResource() = default;
501
502 ImageResource(ImageVMA p_image,
503 vk::UniqueImageView p_image_view,
504 std::vector<vk::UniqueImageView> p_rt_image_views,
505 std::shared_ptr<Allocator> allocator,
506 std::shared_ptr<DeviceHolderVK> device_holder)
507 : device_holder(std::move(device_holder)),
508 allocator(std::move(allocator)),
509 image(p_image),
510 image_view(std::move(p_image_view)),
511 rt_image_views(std::move(p_rt_image_views)) {}
512
513 ImageResource(ImageResource&& o) = default;
514
515 ImageResource(const ImageResource&) = delete;
516
517 ImageResource& operator=(const ImageResource&) = delete;
518 };
519
520 UniqueResourceVKT<ImageResource> resource_;
521 bool is_valid_ = false;
522
523 AllocatedTextureSourceVK(const AllocatedTextureSourceVK&) = delete;
524
525 AllocatedTextureSourceVK& operator=(const AllocatedTextureSourceVK&) = delete;
526};
527
528// |Allocator|
529std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
530 const TextureDescriptor& desc,
531 bool threadsafe) {
532 if (!IsValid()) {
533 return nullptr;
534 }
535 auto device_holder = device_holder_.lock();
536 if (!device_holder) {
537 return nullptr;
538 }
539 auto context = context_.lock();
540 if (!context) {
541 return nullptr;
542 }
543 auto source = std::make_shared<AllocatedTextureSourceVK>(
544 ContextVK::Cast(*context), //
545 desc, //
546 allocator_.get(), //
547 device_holder->GetDevice(), //
548 supports_memoryless_textures_ //
549 );
550 if (!source->IsValid()) {
551 return nullptr;
552 }
553 return std::make_shared<TextureVK>(context_, std::move(source));
554}
555
556// |Allocator|
557std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
558 const DeviceBufferDescriptor& desc) {
559 vk::BufferCreateInfo buffer_info;
560 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
561 vk::BufferUsageFlagBits::eIndexBuffer |
562 vk::BufferUsageFlagBits::eUniformBuffer |
563 vk::BufferUsageFlagBits::eStorageBuffer |
564 vk::BufferUsageFlagBits::eTransferSrc |
565 vk::BufferUsageFlagBits::eTransferDst;
566 buffer_info.size = desc.size;
567 buffer_info.sharingMode = vk::SharingMode::eExclusive;
568 auto buffer_info_native =
569 static_cast<vk::BufferCreateInfo::NativeType>(buffer_info);
570
571 VmaAllocationCreateInfo allocation_info = {};
572 allocation_info.usage = ToVMAMemoryUsage();
573 allocation_info.preferredFlags = static_cast<VkMemoryPropertyFlags>(
574 ToVKBufferMemoryPropertyFlags(desc.storage_mode));
575 allocation_info.flags =
576 ToVmaAllocationBufferCreateFlags(desc.storage_mode, desc.readback);
577 if (created_buffer_pool_ && desc.storage_mode == StorageMode::kHostVisible &&
578 !desc.readback) {
579 allocation_info.pool = staging_buffer_pool_.get().pool;
580 }
581 VkBuffer buffer = {};
582 VmaAllocation buffer_allocation = {};
583 VmaAllocationInfo buffer_allocation_info = {};
584 auto result = vk::Result{::vmaCreateBuffer(allocator_.get(), //
585 &buffer_info_native, //
586 &allocation_info, //
587 &buffer, //
588 &buffer_allocation, //
589 &buffer_allocation_info //
590 )};
591
592 auto type = memory_properties_.memoryTypes[buffer_allocation_info.memoryType];
593 bool is_host_coherent =
594 !!(type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent);
595
596 if (result != vk::Result::eSuccess) {
597 VALIDATION_LOG << "Unable to allocate a device buffer: "
598 << vk::to_string(result);
599 return {};
600 }
601
602 return std::make_shared<DeviceBufferVK>(
603 desc, //
604 context_, //
605 UniqueBufferVMA{BufferVMA{allocator_.get(), //
606 buffer_allocation, //
607 vk::Buffer{buffer}}}, //
608 buffer_allocation_info, //
609 is_host_coherent);
610}
611
612Bytes AllocatorVK::DebugGetHeapUsage() const {
613 auto count = memory_properties_.memoryHeapCount;
614 std::vector<VmaBudget> budgets(count);
615 vmaGetHeapBudgets(allocator_.get(), budgets.data());
616 size_t total_usage = 0;
617 for (auto i = 0u; i < count; i++) {
618 const VmaBudget& budget = budgets[i];
619 total_usage += budget.usage;
620 }
621 return Bytes{static_cast<double>(total_usage)};
622}
623
624void AllocatorVK::DebugTraceMemoryStatistics() const {
625#ifdef IMPELLER_DEBUG
626 FML_TRACE_COUNTER("flutter", "AllocatorVK",
627 reinterpret_cast<int64_t>(this), // Trace Counter ID
628 "MemoryBudgetUsageMB",
629 DebugGetHeapUsage().ConvertTo<MebiBytes>().GetSize());
630#endif // IMPELLER_DEBUG
631}
632
633} // namespace impeller
#define BIND_VMA_PROC_KHR(x)
#define BIND_VMA_PROC(x)
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(const ContextVK &context, const TextureDescriptor &desc, VmaAllocator allocator, vk::Device device, bool supports_memoryless_textures)
vk::ImageView GetRenderTargetView(uint32_t mip_level, uint32_t array_layer) const override
Retrieve the image view used to attach a specific subresource of this texture as a render target.
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.
FlutterVulkanImage * image
VkPhysicalDevice physical_device
Definition main.cc:67
VkDevice device
Definition main.cc:69
VkInstance instance
Definition main.cc:64
uint32_t uint32_t * format
#define FML_LOG(severity)
Definition logging.h:101
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
std::shared_ptr< ImpellerAllocator > allocator
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
static constexpr vk::Flags< vk::MemoryPropertyFlagBits > ToVKBufferMemoryPropertyFlags(StorageMode mode)
constexpr uint32_t ToArrayLayerCount(TextureType type)
Definition formats_vk.h:611
static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags(StorageMode mode, bool readback)
std::string TextureUsageMaskToString(TextureUsageMask mask)
Definition formats.cc:95
StorageMode
Specified where the allocation resides and how it is used.
Definition formats.h:32
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,...
Definition formats.h:99
constexpr bool PixelFormatIsDepthStencil(PixelFormat format)
Definition formats_vk.h:450
static constexpr VmaMemoryUsage ToVMAMemoryUsage()
constexpr vk::ImageViewType ToVKImageViewType(TextureType type)
Definition formats_vk.h:625
constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count)
Definition formats_vk.h:250
constexpr vk::Format ToVKImageFormat(PixelFormat format)
Definition formats_vk.h:146
static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode)
static PoolVMA CreateBufferPool(VmaAllocator allocator)
constexpr const char * TextureTypeToString(TextureType type)
Definition formats.h:457
ISize64 ISize
Definition size.h:162
constexpr const char * StorageModeToString(StorageMode mode)
Definition formats.h:60
constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type)
Definition formats_vk.h:639
constexpr vk::ImageAspectFlags ToVKImageAspectFlags(PixelFormat format)
Definition formats_vk.h:567
Definition ref_ptr.h:261
std::shared_ptr< ContextGLES > context
impeller::ShaderType type
FlutterVulkanImageHandle image
Definition embedder.h:938
A pixel format and usage that is sufficient to check if images of that format and usage are suitable ...
Type height
Definition size.h:29
Type width
Definition size.h:28
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,...)
Definition trace_event.h:85
#define VALIDATION_LOG
Definition validation.h:91