diff --git a/impeller/aiks/picture.cc b/impeller/aiks/picture.cc index 7ad91fb63ef0c..3ca4dc2cdde7d 100644 --- a/impeller/aiks/picture.cc +++ b/impeller/aiks/picture.cc @@ -61,7 +61,8 @@ std::shared_ptr Picture::RenderToTexture( size, // size "Picture Snapshot MSAA", // label RenderTarget:: - kDefaultColorAttachmentConfigMSAA // color_attachment_config + kDefaultColorAttachmentConfigMSAA, // color_attachment_config + true // persistent #ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan. , std::nullopt // stencil_attachment_config @@ -69,10 +70,11 @@ std::shared_ptr Picture::RenderToTexture( ); } else { target = RenderTarget::CreateOffscreen( - *impeller_context, // context - size, // size - "Picture Snapshot", // label - RenderTarget::kDefaultColorAttachmentConfig // color_attachment_config + *impeller_context, // context + size, // size + "Picture Snapshot", // label + RenderTarget::kDefaultColorAttachmentConfig, // color_attachment_config + true // persistent #ifndef FML_OS_ANDROID // Reduce PSO variants for Vulkan. , std::nullopt // stencil_attachment_config diff --git a/impeller/core/allocator.h b/impeller/core/allocator.h index 25b3dae07a22c..031dcad34d50e 100644 --- a/impeller/core/allocator.h +++ b/impeller/core/allocator.h @@ -45,6 +45,8 @@ class Allocator { virtual ISize GetMaxTextureSizeSupported() const = 0; + virtual void IncrementFrameIndex() {} + protected: Allocator(); diff --git a/impeller/core/texture_descriptor.h b/impeller/core/texture_descriptor.h index 7d99d20408da5..548bc2b53cf0a 100644 --- a/impeller/core/texture_descriptor.h +++ b/impeller/core/texture_descriptor.h @@ -46,6 +46,7 @@ struct TextureDescriptor { static_cast(TextureUsage::kShaderRead); SampleCount sample_count = SampleCount::kCount1; CompressionType compression_type = CompressionType::kLossless; + bool persistent = false; constexpr size_t GetByteSizeOfBaseMipLevel() const { if (!IsValid()) { diff --git a/impeller/entity/contents/scene_contents.cc b/impeller/entity/contents/scene_contents.cc index bb00ff923e26e..1834f5d32d490 100644 --- a/impeller/entity/contents/scene_contents.cc +++ b/impeller/entity/contents/scene_contents.cc @@ -54,6 +54,7 @@ bool SceneContents::Render(const ContentContext& renderer, .load_action = LoadAction::kClear, .store_action = StoreAction::kMultisampleResolve, }, // color_attachment_config + false, RenderTarget::AttachmentConfig{ .storage_mode = StorageMode::kDeviceTransient, .load_action = LoadAction::kDontCare, diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 19b1a2efd1a33..8b901baf97904 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -214,7 +214,8 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .resolve_storage_mode = StorageMode::kDevicePrivate, .load_action = LoadAction::kDontCare, .store_action = StoreAction::kMultisampleResolve, - .clear_color = clear_color}, // color_attachment_config + .clear_color = clear_color}, // color_attachment_config + false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); } else { @@ -227,7 +228,8 @@ static EntityPassTarget CreateRenderTarget(ContentContext& renderer, .load_action = LoadAction::kDontCare, .store_action = StoreAction::kDontCare, .clear_color = clear_color, - }, // color_attachment_config + }, // color_attachment_config + false, GetDefaultStencilConfig(readable) // stencil_attachment_config ); } diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 36a53d2ce04e1..997fc9f40dab8 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -93,6 +93,16 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, VALIDATION_LOG << "Could not create memory allocator"; return; } + + for (auto i = 0u; i < 3u; i++) { + if (!CreateBufferPool(allocator, &staging_buffer_pools_[i])) { + return; + } + if (!CreateRenderTargetPool(allocator, &render_target_buffer_pools_[i])) { + return; + } + } + allocator_ = allocator; supports_memoryless_textures_ = capabilities.SupportsMemorylessTextures(); is_valid_ = true; @@ -101,6 +111,15 @@ AllocatorVK::AllocatorVK(std::weak_ptr context, AllocatorVK::~AllocatorVK() { TRACE_EVENT0("impeller", "DestroyAllocatorVK"); if (allocator_) { + for (auto i = 0u; i < 3u; i++) { + if (staging_buffer_pools_[i]) { + ::vmaDestroyPool(allocator_, staging_buffer_pools_[i]); + } + if (render_target_buffer_pools_[i]) { + ::vmaDestroyPool(allocator_, render_target_buffer_pools_[i]); + } + } + ::vmaDestroyAllocator(allocator_); } } @@ -211,25 +230,16 @@ static constexpr VkMemoryPropertyFlags ToVKBufferMemoryPropertyFlags( } static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, - bool is_texture, - size_t size) { + bool dedicated) { VmaAllocationCreateFlags flags = 0; switch (mode) { case StorageMode::kHostVisible: - if (is_texture) { - if (size >= kImageSizeThresholdForDedicatedMemoryAllocation) { - flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; - } else { - flags |= {}; - } - } else { - flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + if (dedicated) { + flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } return flags; case StorageMode::kDevicePrivate: - if (is_texture && - size >= kImageSizeThresholdForDedicatedMemoryAllocation) { + if (dedicated) { flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } return flags; @@ -239,11 +249,28 @@ static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode, FML_UNREACHABLE(); } +static VmaAllocationCreateFlags ToVmaAllocationBufferCreateFlags( + StorageMode mode) { + VmaAllocationCreateFlags flags = 0; + switch (mode) { + case StorageMode::kHostVisible: + flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT; + return flags; + case StorageMode::kDevicePrivate: + return flags; + case StorageMode::kDeviceTransient: + return flags; + } + FML_UNREACHABLE(); +} + class AllocatedTextureSourceVK final : public TextureSourceVK { public: AllocatedTextureSourceVK(const TextureDescriptor& desc, VmaAllocator allocator, vk::Device device, + VmaPool pool, bool supports_memoryless_textures) : TextureSourceVK(desc) { TRACE_EVENT0("impeller", "CreateDeviceTexture"); @@ -268,12 +295,24 @@ class AllocatedTextureSourceVK final : public TextureSourceVK { VmaAllocationCreateInfo alloc_nfo = {}; + auto use_dedicated = desc.GetByteSizeOfBaseMipLevel() > + kImageSizeThresholdForDedicatedMemoryAllocation; + alloc_nfo.usage = ToVMAMemoryUsage(); alloc_nfo.preferredFlags = ToVKTextureMemoryPropertyFlags( desc.storage_mode, supports_memoryless_textures); + if (desc.usage & + static_cast(TextureUsage::kRenderTarget) && + !desc.persistent) { + if (desc.storage_mode == StorageMode::kDevicePrivate || + (desc.storage_mode == StorageMode::kDeviceTransient && + !supports_memoryless_textures)) { + alloc_nfo.pool = pool; + use_dedicated = false; + } + } alloc_nfo.flags = - ToVmaAllocationCreateFlags(desc.storage_mode, /*is_texture=*/true, - desc.GetByteSizeOfBaseMipLevel()); + ToVmaAllocationCreateFlags(desc.storage_mode, use_dedicated); auto create_info_native = static_cast(image_info); @@ -377,10 +416,11 @@ std::shared_ptr AllocatorVK::OnCreateTexture( return nullptr; } auto source = std::make_shared( - desc, // - allocator_, // - device_holder->GetDevice(), // - supports_memoryless_textures_ // + desc, // + allocator_, // + device_holder->GetDevice(), // + render_target_buffer_pools_[frame_index_ % 3u], // + supports_memoryless_textures_ // ); if (!source->IsValid()) { return nullptr; @@ -408,8 +448,10 @@ std::shared_ptr AllocatorVK::OnCreateBuffer( 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.flags = ToVmaAllocationBufferCreateFlags(desc.storage_mode); + if (desc.storage_mode == StorageMode::kHostVisible) { + allocation_info.pool = staging_buffer_pools_[frame_index_ % 3u]; + } VkBuffer buffer = {}; VmaAllocation buffer_allocation = {}; @@ -437,4 +479,90 @@ 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 = + 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) { + VALIDATION_LOG << "Could not find memory type for buffer pool."; + 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) { + VALIDATION_LOG << "Could not create buffer pool."; + return false; + } + return true; +} + +bool AllocatorVK::CreateRenderTargetPool(VmaAllocator allocator, + VmaPool* pool) { + vk::ImageCreateInfo image_info; + image_info.flags = {}; + image_info.imageType = vk::ImageType::e2D; + image_info.format = vk::Format::eR8G8B8A8Unorm; + image_info.extent = VkExtent3D{1u, 1u, 1u}; + image_info.samples = vk::SampleCountFlagBits::e1; + image_info.mipLevels = 1u; + image_info.arrayLayers = 1u; + image_info.tiling = vk::ImageTiling::eOptimal; + image_info.initialLayout = vk::ImageLayout::eUndefined; + image_info.usage = + vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; + image_info.sharingMode = vk::SharingMode::eExclusive; + + auto create_info_native = + static_cast(image_info); + + VmaAllocationCreateInfo allocation_info = {}; + allocation_info.usage = VMA_MEMORY_USAGE_AUTO; + allocation_info.preferredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + uint32_t memTypeIndex; + auto result = vk::Result{vmaFindMemoryTypeIndexForImageInfo( + allocator, &create_info_native, &allocation_info, &memTypeIndex)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Could not find memory type for buffer pool."; + 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) { + VALIDATION_LOG << "Could not create render target pool."; + 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..673ae3dbb0f48 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -27,11 +27,18 @@ class AllocatorVK final : public Allocator { fml::RefPtr vk_; VmaAllocator allocator_ = {}; + + // Staging buffer pools. + VmaPool staging_buffer_pools_[3] = {}; + // Render target buffer pools. + VmaPool render_target_buffer_pools_[3] = {}; + std::weak_ptr context_; std::weak_ptr device_holder_; ISize max_texture_size_; bool is_valid_ = false; bool supports_memoryless_textures_ = false; + uint32_t frame_index_ = 0u; AllocatorVK(std::weak_ptr context, uint32_t vulkan_api_version, @@ -56,6 +63,13 @@ class AllocatorVK final : public Allocator { // |Allocator| ISize GetMaxTextureSizeSupported() const override; + // |Allocator| + void IncrementFrameIndex() override { frame_index_ += 1; } + + static bool CreateBufferPool(VmaAllocator allocator, VmaPool* pool); + + static bool CreateRenderTargetPool(VmaAllocator allocator, VmaPool* pool); + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 25f1ff6890d17..5a9aa9d4a2dc5 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -50,6 +50,8 @@ class ContextVK final : public Context, uint64_t GetHash() const { return hash_; } + uint32_t GetFrameIndex() const { return frame_index_; } + // |Context| ~ContextVK() override; @@ -163,6 +165,7 @@ class ContextVK final : public Context, std::string device_name_; std::shared_ptr raster_message_loop_; const uint64_t hash_; + uint32_t frame_index_ = 0u; bool is_valid_ = false; diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index ab1100664d470..40222d32e30fe 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -31,6 +31,7 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( msaa_tex_desc.format = swapchain_image->GetPixelFormat(); msaa_tex_desc.size = swapchain_image->GetSize(); msaa_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + msaa_tex_desc.persistent = !supports_memoryless; std::shared_ptr msaa_tex; if (supports_memoryless || !swapchain_image->HasMSAATexture()) { diff --git a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc index 85b39a756699e..31bea4c7f2c04 100644 --- a/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_impl_vk.cc @@ -389,6 +389,7 @@ bool SwapchainImplVK::Present(const std::shared_ptr& image, } const auto& context = ContextVK::Cast(*context_strong); + context.GetResourceAllocator()->IncrementFrameIndex(); const auto& sync = synchronizers_[current_frame_]; diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 46ca72b0a815b..3a392777224f8 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -212,6 +212,7 @@ RenderTarget RenderTarget::CreateOffscreen( ISize size, const std::string& label, AttachmentConfig color_attachment_config, + bool persistent, std::optional stencil_attachment_config) { if (size.IsEmpty()) { return {}; @@ -230,6 +231,7 @@ RenderTarget RenderTarget::CreateOffscreen( color_tex0.size = size; color_tex0.usage = static_cast(TextureUsage::kRenderTarget) | static_cast(TextureUsage::kShaderRead); + color_tex0.persistent = persistent; ColorAttachment color0; color0.clear_color = color_attachment_config.clear_color; @@ -258,6 +260,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( ISize size, const std::string& label, AttachmentConfigMSAA color_attachment_config, + bool persistent, std::optional stencil_attachment_config) { if (size.IsEmpty()) { return {}; @@ -280,6 +283,7 @@ RenderTarget RenderTarget::CreateOffscreenMSAA( color0_tex_desc.format = pixel_format; color0_tex_desc.size = size; color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); + color0_tex_desc.persistent = persistent; auto color0_msaa_tex = context.GetResourceAllocator()->CreateTexture(color0_tex_desc); diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index bc54976a030a8..001e2f59aba9c 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -58,6 +58,7 @@ class RenderTarget final { ISize size, const std::string& label = "Offscreen", AttachmentConfig color_attachment_config = kDefaultColorAttachmentConfig, + bool persistent = false, std::optional stencil_attachment_config = kDefaultStencilAttachmentConfig); @@ -67,6 +68,7 @@ class RenderTarget final { const std::string& label = "Offscreen MSAA", AttachmentConfigMSAA color_attachment_config = kDefaultColorAttachmentConfigMSAA, + bool persistent = false, std::optional stencil_attachment_config = kDefaultStencilAttachmentConfig); diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index af111c6ff0341..2c3fa11ccd901 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -268,6 +268,7 @@ static std::pair, std::string> UnsafeUploadTextureToPrivate( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = texture_descriptor.size.MipCount(); texture_descriptor.compression_type = impeller::CompressionType::kLossy; + texture_descriptor.persistent = true; auto dest_texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor); @@ -371,6 +372,7 @@ ImageDecoderImpeller::UploadTextureToShared( texture_descriptor.size = {image_info.width(), image_info.height()}; texture_descriptor.mip_count = create_mips ? texture_descriptor.size.MipCount() : 1; + texture_descriptor.persistent = true; auto texture = context->GetResourceAllocator()->CreateTexture(texture_descriptor);