19#include "vulkan/vulkan_enums.hpp"
23static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
27 return vk::MemoryPropertyFlagBits::eHostVisible;
29 return vk::MemoryPropertyFlagBits::eDeviceLocal;
31 return vk::MemoryPropertyFlagBits::eLazilyAllocated;
39 VmaAllocationCreateFlags flags = 0;
43 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
45 flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
47 flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT;
60 vk::BufferCreateInfo buffer_info;
61 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
62 vk::BufferUsageFlagBits::eIndexBuffer |
63 vk::BufferUsageFlagBits::eUniformBuffer |
64 vk::BufferUsageFlagBits::eStorageBuffer |
65 vk::BufferUsageFlagBits::eTransferSrc |
66 vk::BufferUsageFlagBits::eTransferDst;
67 buffer_info.size = 1u;
68 buffer_info.sharingMode = vk::SharingMode::eExclusive;
69 auto buffer_info_native =
70 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
72 VmaAllocationCreateInfo allocation_info = {};
73 allocation_info.usage = VMA_MEMORY_USAGE_AUTO;
74 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
79 uint32_t memTypeIndex;
80 auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo(
81 allocator, &buffer_info_native, &allocation_info, &memTypeIndex)};
82 if (result != vk::Result::eSuccess) {
86 VmaPoolCreateInfo pool_create_info = {};
87 pool_create_info.memoryTypeIndex = memTypeIndex;
88 pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT;
89 pool_create_info.minBlockCount = 1;
92 result = vk::Result{::vmaCreatePool(allocator, &pool_create_info, &pool)};
93 if (result != vk::Result::eSuccess) {
96 return {allocator, pool};
99AllocatorVK::AllocatorVK(std::weak_ptr<Context> context,
100 uint32_t vulkan_api_version,
102 const std::shared_ptr<DeviceHolderVK>& device_holder,
104 const CapabilitiesVK& capabilities)
105 : context_(
std::move(context)), device_holder_(device_holder) {
107 max_texture_size_.width = max_texture_size_.height =
108 limits.maxImageDimension2D;
111 VmaVulkanFunctions proc_table = {};
113#define BIND_VMA_PROC(x) proc_table.x = VULKAN_HPP_DEFAULT_DISPATCHER.x;
114#define BIND_VMA_PROC_KHR(x) \
115 proc_table.x##KHR = VULKAN_HPP_DEFAULT_DISPATCHER.x \
116 ? VULKAN_HPP_DEFAULT_DISPATCHER.x \
117 : VULKAN_HPP_DEFAULT_DISPATCHER.x##KHR;
142#undef BIND_VMA_PROC_KHR
145 VmaAllocatorCreateInfo allocator_info = {};
146 allocator_info.vulkanApiVersion = vulkan_api_version;
148 allocator_info.device = device_holder->GetDevice();
151 allocator_info.preferredLargeHeapBlockSize = 4 * 1024 * 1024;
152 allocator_info.pVulkanFunctions = &proc_table;
154 VmaAllocator allocator = {};
155 auto result = vk::Result{::vmaCreateAllocator(&allocator_info, &allocator)};
156 if (result != vk::Result::eSuccess) {
161 created_buffer_pool_ &= staging_buffer_pool_.is_valid();
162 allocator_.reset(allocator);
163 supports_memoryless_textures_ =
164 capabilities.SupportsDeviceTransientTextures();
168AllocatorVK::~AllocatorVK() =
default;
171bool AllocatorVK::IsValid()
const {
176ISize AllocatorVK::GetMaxTextureSizeSupported()
const {
177 return max_texture_size_;
180int32_t AllocatorVK::FindMemoryTypeIndex(
181 uint32_t memory_type_bits_requirement,
182 vk::PhysicalDeviceMemoryProperties& memory_properties) {
183 int32_t type_index = -1;
184 vk::MemoryPropertyFlagBits required_properties =
185 vk::MemoryPropertyFlagBits::eDeviceLocal;
187 const uint32_t memory_count = memory_properties.memoryTypeCount;
188 for (uint32_t memory_index = 0; memory_index < memory_count; ++memory_index) {
189 const uint32_t memory_type_bits = (1 << memory_index);
190 const bool is_required_memory_type =
191 memory_type_bits_requirement & memory_type_bits;
193 const auto properties =
194 memory_properties.memoryTypes[memory_index].propertyFlags;
195 const bool has_required_properties =
196 (properties & required_properties) == required_properties;
198 if (is_required_memory_type && has_required_properties) {
199 return static_cast<int32_t
>(memory_index);
206vk::ImageUsageFlags AllocatorVK::ToVKImageUsageFlags(
210 bool supports_memoryless_textures) {
211 vk::ImageUsageFlags vk_usage;
214 case StorageMode::kHostVisible:
215 case StorageMode::kDevicePrivate:
217 case StorageMode::kDeviceTransient:
218 if (supports_memoryless_textures) {
219 vk_usage |= vk::ImageUsageFlagBits::eTransientAttachment;
224 if (usage & TextureUsage::kRenderTarget) {
226 vk_usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
228 vk_usage |= vk::ImageUsageFlagBits::eColorAttachment;
229 vk_usage |= vk::ImageUsageFlagBits::eInputAttachment;
233 if (usage & TextureUsage::kShaderRead) {
234 vk_usage |= vk::ImageUsageFlagBits::eSampled;
237 if (usage & TextureUsage::kShaderWrite) {
238 vk_usage |= vk::ImageUsageFlagBits::eStorage;
241 if (mode != StorageMode::kDeviceTransient) {
244 vk_usage |= vk::ImageUsageFlagBits::eTransferSrc |
245 vk::ImageUsageFlagBits::eTransferDst;
252 return VMA_MEMORY_USAGE_AUTO;
255static constexpr vk::Flags<vk::MemoryPropertyFlagBits>
257 bool supports_memoryless_textures) {
259 case StorageMode::kHostVisible:
260 return vk::MemoryPropertyFlagBits::eHostVisible |
261 vk::MemoryPropertyFlagBits::eDeviceLocal;
262 case StorageMode::kDevicePrivate:
263 return vk::MemoryPropertyFlagBits::eDeviceLocal;
264 case StorageMode::kDeviceTransient:
265 if (supports_memoryless_textures) {
266 return vk::MemoryPropertyFlagBits::eLazilyAllocated |
267 vk::MemoryPropertyFlagBits::eDeviceLocal;
269 return vk::MemoryPropertyFlagBits::eDeviceLocal;
275 VmaAllocationCreateFlags flags = 0;
277 case StorageMode::kHostVisible:
279 case StorageMode::kDevicePrivate:
281 case StorageMode::kDeviceTransient:
291 VmaAllocator allocator,
293 bool supports_memoryless_textures)
296 vk::StructureChain<vk::ImageCreateInfo, vk::ImageCompressionControlEXT>
298 auto& image_info = image_info_chain.get();
300 image_info.imageType = vk::ImageType::e2D;
302 image_info.extent = VkExtent3D{
310 image_info.tiling = vk::ImageTiling::eOptimal;
311 image_info.initialLayout = vk::ImageLayout::eUndefined;
312 image_info.usage = AllocatorVK::ToVKImageUsageFlags(
314 supports_memoryless_textures);
315 image_info.sharingMode = vk::SharingMode::eExclusive;
317 vk::ImageCompressionFixedRateFlagsEXT frc_rates[1] = {
318 vk::ImageCompressionFixedRateFlagBitsEXT::eNone};
320 const auto frc_rate =
324 if (frc_rate.has_value()) {
326 frc_rates[0] = frc_rate.value();
328 auto& compression_info =
329 image_info_chain.get<vk::ImageCompressionControlEXT>();
330 compression_info.pFixedRateFlags = frc_rates;
331 compression_info.compressionControlPlaneCount = 1u;
332 compression_info.flags =
333 vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
335 image_info_chain.unlink<vk::ImageCompressionControlEXT>();
338 VmaAllocationCreateInfo alloc_nfo = {};
341 alloc_nfo.preferredFlags =
346 auto create_info_native =
347 static_cast<vk::ImageCreateInfo::NativeType
>(image_info);
349 VkImage vk_image = VK_NULL_HANDLE;
350 VmaAllocation allocation = {};
351 VmaAllocationInfo allocation_info = {};
353 auto result = vk::Result{::vmaCreateImage(allocator,
360 if (result != vk::Result::eSuccess) {
362 << vk::to_string(result)
366 <<
" [VK]Flags: " << vk::to_string(image_info.flags)
367 <<
" [VK]Format: " << vk::to_string(image_info.format)
368 <<
" [VK]Usage: " << vk::to_string(image_info.usage)
369 <<
" [VK]Mem. Flags: "
370 << vk::to_string(vk::MemoryPropertyFlags(
371 alloc_nfo.preferredFlags));
376 auto image = vk::Image{vk_image};
378 vk::ImageViewCreateInfo view_info = {};
381 view_info.format = image_info.format;
383 view_info.subresourceRange.levelCount = image_info.mipLevels;
390 if (desc.
format == PixelFormat::kA8UNormInt) {
391 view_info.components.a = vk::ComponentSwizzle::eR;
392 view_info.components.r = vk::ComponentSwizzle::eA;
395 auto [result, image_view] =
device.createImageViewUnique(view_info);
396 if (result != vk::Result::eSuccess) {
397 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
398 << vk::to_string(result);
402 view_info.subresourceRange.levelCount = 1u;
403 auto [rt_result, rt_image_view] =
device.createImageViewUnique(view_info);
404 if (rt_result != vk::Result::eSuccess) {
405 VALIDATION_LOG <<
"Unable to create an image view for allocation: "
406 << vk::to_string(rt_result);
410 resource_.Swap(ImageResource(
411 ImageVMA{allocator, allocation,
image}, std::move(image_view),
421 vk::Image
GetImage()
const override {
return resource_->image.get().image; }
424 return resource_->image_view.get();
428 return resource_->rt_image_view.get();
434 struct ImageResource {
435 std::shared_ptr<DeviceHolderVK> device_holder;
436 std::shared_ptr<Allocator> allocator;
438 vk::UniqueImageView image_view;
439 vk::UniqueImageView rt_image_view;
441 ImageResource() =
default;
444 vk::UniqueImageView p_image_view,
445 vk::UniqueImageView p_rt_image_view,
446 std::shared_ptr<Allocator> allocator,
447 std::shared_ptr<DeviceHolderVK> device_holder)
448 : device_holder(
std::move(device_holder)),
449 allocator(
std::move(allocator)),
451 image_view(
std::move(p_image_view)),
452 rt_image_view(
std::move(p_rt_image_view)) {}
454 ImageResource(ImageResource&& o) =
default;
456 ImageResource(
const ImageResource&) =
delete;
458 ImageResource& operator=(
const ImageResource&) =
delete;
461 UniqueResourceVKT<ImageResource> resource_;
462 bool is_valid_ =
false;
464 AllocatedTextureSourceVK(
const AllocatedTextureSourceVK&) =
delete;
466 AllocatedTextureSourceVK& operator=(
const AllocatedTextureSourceVK&) =
delete;
470std::shared_ptr<Texture> AllocatorVK::OnCreateTexture(
471 const TextureDescriptor& desc,
476 auto device_holder = device_holder_.lock();
477 if (!device_holder) {
480 auto context = context_.lock();
484 auto source = std::make_shared<AllocatedTextureSourceVK>(
485 ContextVK::Cast(*context),
488 device_holder->GetDevice(),
489 supports_memoryless_textures_
491 if (!source->IsValid()) {
494 return std::make_shared<TextureVK>(context_, std::move(source));
498std::shared_ptr<DeviceBuffer> AllocatorVK::OnCreateBuffer(
499 const DeviceBufferDescriptor& desc) {
500 vk::BufferCreateInfo buffer_info;
501 buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer |
502 vk::BufferUsageFlagBits::eIndexBuffer |
503 vk::BufferUsageFlagBits::eUniformBuffer |
504 vk::BufferUsageFlagBits::eStorageBuffer |
505 vk::BufferUsageFlagBits::eTransferSrc |
506 vk::BufferUsageFlagBits::eTransferDst;
507 buffer_info.size = desc.size;
508 buffer_info.sharingMode = vk::SharingMode::eExclusive;
509 auto buffer_info_native =
510 static_cast<vk::BufferCreateInfo::NativeType
>(buffer_info);
512 VmaAllocationCreateInfo allocation_info = {};
514 allocation_info.preferredFlags =
static_cast<VkMemoryPropertyFlags
>(
516 allocation_info.flags =
518 if (created_buffer_pool_ && desc.storage_mode == StorageMode::kHostVisible &&
520 allocation_info.pool = staging_buffer_pool_.get().pool;
523 VmaAllocation buffer_allocation = {};
524 VmaAllocationInfo buffer_allocation_info = {};
525 auto result = vk::Result{::vmaCreateBuffer(allocator_.get(),
530 &buffer_allocation_info
533 auto type = memory_properties_.memoryTypes[buffer_allocation_info.memoryType];
534 bool is_host_coherent =
535 !!(
type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent);
537 if (result != vk::Result::eSuccess) {
539 << vk::to_string(result);
543 return std::make_shared<DeviceBufferVK>(
546 UniqueBufferVMA{BufferVMA{allocator_.get(),
549 buffer_allocation_info,
553Bytes AllocatorVK::DebugGetHeapUsage()
const {
554 auto count = memory_properties_.memoryHeapCount;
555 std::vector<VmaBudget> budgets(count);
556 vmaGetHeapBudgets(allocator_.get(), budgets.data());
557 size_t total_usage = 0;
558 for (
auto i = 0u;
i < count;
i++) {
559 const VmaBudget& budget = budgets[
i];
560 total_usage += budget.usage;
562 return Bytes{
static_cast<double>(total_usage)};
565void AllocatorVK::DebugTraceMemoryStatistics()
const {
568 reinterpret_cast<int64_t
>(
this),
569 "MemoryBudgetUsageMB",
570 DebugGetHeapUsage().ConvertTo<MebiBytes>().GetSize());
#define BIND_VMA_PROC_KHR(x)
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(const ContextVK &context, const TextureDescriptor &desc, VmaAllocator allocator, vk::Device device, bool supports_memoryless_textures)
~AllocatedTextureSourceVK()=default
bool IsSwapchainImage() const override
Determines if swapchain image. That is, an image used as the root render target.
std::shared_ptr< Allocator > GetResourceAllocator() const override
Returns the allocator used to create textures and buffers on the device.
std::shared_ptr< DeviceHolderVK > GetDeviceHolder() const
const std::shared_ptr< const Capabilities > & GetCapabilities() const override
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
Abstract base class that represents a vkImage and an vkImageView.
FlutterVulkanImage * image
VkPhysicalDevice physical_device
uint32_t uint32_t * format
#define FML_UNREACHABLE()
#define FML_DCHECK(condition)
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
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)
FlutterVulkanImageHandle image
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
CompressionType compression_type
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)