diff --git a/impeller/core/allocator.cc b/impeller/core/allocator.cc index be380b671ec27..075a738fe5b4f 100644 --- a/impeller/core/allocator.cc +++ b/impeller/core/allocator.cc @@ -61,4 +61,6 @@ uint16_t Allocator::MinimumBytesPerRow(PixelFormat format) const { return BytesPerPixelForPixelFormat(format); } +void Allocator::DidAcquireSurfaceFrame() {} + } // namespace impeller diff --git a/impeller/core/allocator.h b/impeller/core/allocator.h index 25b3dae07a22c..62b86b72b047f 100644 --- a/impeller/core/allocator.h +++ b/impeller/core/allocator.h @@ -45,6 +45,10 @@ class Allocator { virtual ISize GetMaxTextureSizeSupported() const = 0; + /// @brief Increment an internal frame used to cycle through a ring buffer of + /// allocation pools. + virtual void DidAcquireSurfaceFrame(); + protected: Allocator(); diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 6ce8ea7e6812f..07d7fc23ea797 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -93,6 +93,10 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } + for (auto i = 0u; i < kPoolCount; i++) { + created_buffer_pools_ &= + CreateBufferPool(allocator, &staging_buffer_pools_[i]); + } allocator_ = allocator; supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; @@ -101,6 +105,11 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, AllocatorVK::~AllocatorVK() { TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { + for (auto i = 0u; i < kPoolCount; i++) { + if (staging_buffer_pools_[i]) { + ::vmaDestroyPool(allocator_, staging_buffer_pools_[i]); + } + } ::vmaDestroyAllocator(allocator_); } } @@ -177,35 +186,51 @@ static constexpr VmaMemoryUsage ToVMAMemoryUsage() { return VMA_MEMORY_USAGE_AUTO; } -static constexpr VkMemoryPropertyFlags ToVKTextureMemoryPropertyFlags( - StorageMode mode, - bool supports_memoryless_textures) { +static constexpr vk::Flags +ToVKTextureMemoryPropertyFlags(StorageMode mode, + bool supports_memoryless_textures) { switch (mode) { case StorageMode::kHostVisible: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + return vk::MemoryPropertyFlagBits::eHostVisible | + vk::MemoryPropertyFlagBits::eDeviceLocal | + vk::MemoryPropertyFlagBits::eHostCoherent; case StorageMode::kDevicePrivate: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + return vk::MemoryPropertyFlagBits::eDeviceLocal; case StorageMode::kDeviceTransient: if (supports_memoryless_textures) { - return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT | - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + return vk::MemoryPropertyFlagBits::eLazilyAllocated | + vk::MemoryPropertyFlagBits::eDeviceLocal; } - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + return vk::MemoryPropertyFlagBits::eDeviceLocal; + } + FML_UNREACHABLE(); +} + +static constexpr vk::Flags +ToVKBufferMemoryPropertyFlags(StorageMode mode) { + switch (mode) { + case StorageMode::kHostVisible: + return vk::MemoryPropertyFlagBits::eHostVisible; + case StorageMode::kDevicePrivate: + return vk::MemoryPropertyFlagBits::eDeviceLocal; + case StorageMode::kDeviceTransient: + return vk::MemoryPropertyFlagBits::eLazilyAllocated; } FML_UNREACHABLE(); } -static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags( +static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags( StorageMode mode) { + VmaAllocationCreateFlags flags = 0; switch (mode) { case StorageMode::kHostVisible: - return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + return flags; case StorageMode::kDevicePrivate: - return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + return flags; case StorageMode::kDeviceTransient: - return VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + return flags; } FML_UNREACHABLE(); } @@ -269,8 +294,9 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { VmaAllocationCreateInfo alloc_nfo = {}; alloc_nfo.usage = ToVMAMemoryUsage(); - alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( - desc.storage_mode, supports_memoryless_textures); + alloc_nfo.preferredFlags = + static_cast(ToVKTextureMemoryPropertyFlags( + desc.storage_mode, supports_memoryless_textures)); alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, desc.GetByteSizeOfBaseMipLevel()); @@ -388,6 +414,11 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return std::make_shared(context_, std::move(source)); } +void AllocatorVK::DidAcquireSurfaceFrame() { + frame_count_++; + raster_thread_id_ = std::this_thread::get_id(); +} + // |Allocator| std::shared_ptr AllocatorVK::OnCreateBuffer( const DeviceBufferDescriptor& desc) { @@ -406,10 +437,13 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( VmaAllocationCreateInfo allocation_info = {}; allocation_info.usage = ToVMAMemoryUsage(); - allocation_info.preferredFlags = - ToVKBufferMemoryPropertyFlags(desc.storage_mode); - allocation_info.flags = ToVmaAllocationCreateFlags( - desc.storage_mode, /*is_texture=*/false, desc.size); + allocation_info.preferredFlags = static_cast( + ToVKBufferMemoryPropertyFlags(desc.storage_mode)); + allocation_info.flags = ToVmaAllocationBufferCreateFlags(desc.storage_mode); + if (created_buffer_pools_ && desc.storage_mode == StorageMode::kHostVisible && + raster_thread_id_ == std::this_thread::get_id()) { + allocation_info.pool = staging_buffer_pools_[frame_count_ % kPoolCount]; + } VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; @@ -437,4 +471,44 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( ); } +// static +bool AllocatorVK::CreateBufferPool(VmaAllocator allocator, VmaPool* pool) { + vk::BufferCreateInfo buffer_info; + buffer_info.usage = vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eStorageBuffer | + vk::BufferUsageFlagBits::eTransferSrc | + vk::BufferUsageFlagBits::eTransferDst; + buffer_info.size = 1u; // doesn't matter + buffer_info.sharingMode = vk::SharingMode::eExclusive; + auto buffer_info_native = + static_cast(buffer_info); + + VmaAllocationCreateInfo allocation_info = {}; + allocation_info.usage = VMA_MEMORY_USAGE_AUTO; + allocation_info.preferredFlags = static_cast( + ToVKBufferMemoryPropertyFlags(StorageMode::kHostVisible)); + allocation_info.flags = + ToVmaAllocationBufferCreateFlags(StorageMode::kHostVisible); + + uint32_t memTypeIndex; + auto result = vk::Result{vmaFindMemoryTypeIndexForBufferInfo( + allocator, &buffer_info_native, &allocation_info, &memTypeIndex)}; + if (result != vk::Result::eSuccess) { + return false; + } + + VmaPoolCreateInfo pool_create_info = {}; + pool_create_info.memoryTypeIndex = memTypeIndex; + pool_create_info.flags = VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT | + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT; + + result = vk::Result{vmaCreatePool(allocator, &pool_create_info, pool)}; + if (result != vk::Result::eSuccess) { + return false; + } + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.h b/impeller/renderer/backend/vulkan/allocator_vk.h index fba13f2b7cf12..abb65ba836778 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -25,13 +25,20 @@ class AllocatorVK final : public Allocator { private: friend class ContextVK; + static constexpr size_t kPoolCount = 3; + fml::RefPtr vk_; VmaAllocator allocator_ = {}; + VmaPool staging_buffer_pools_[kPoolCount] = {}; std::weak_ptr context_; std::weak_ptr device_holder_; ISize max_texture_size_; bool is_valid_ = false; bool supports_memoryless_textures_ = false; + // TODO(jonahwilliams): figure out why CI can't create these buffer pools. + bool created_buffer_pools_ = true; + uint32_t frame_count_ = 0; + std::thread::id raster_thread_id_; AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, @@ -45,6 +52,9 @@ class AllocatorVK final : public Allocator { // |Allocator| bool IsValid() const; + // |Allocator| + void DidAcquireSurfaceFrame() override; + // |Allocator| std::shared_ptr OnCreateBuffer( const DeviceBufferDescriptor& desc) override; @@ -56,6 +66,8 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; + static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool); + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 0b1fc69001e33..676da85fbe608 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -481,6 +481,9 @@ std::unique_ptr ContextVK::AcquireNextSurface() { if (surface && pipeline_library_) { pipeline_library_->DidAcquireSurfaceFrame(); } + if (allocator_) { + allocator_->DidAcquireSurfaceFrame(); + } return surface; }