From a19efe54818e2545f197364b36f516b71315114d Mon Sep 17 00:00:00 2001 From: Dragos Tiselice Date: Fri, 20 Nov 2020 09:07:19 +0100 Subject: [PATCH] Switched engine to use buffer collection. The old way of allocating images meant that one would have to make sure that Scenic and Flutter were using exactly the same pixel formats. This patch removes the old image allocation and replaces it with a sysmem API that uses buffer collections instead. This permits a smooth negotiation of formats between the two systems. --- .../fuchsia/flutter/compositor_context.cc | 2 +- .../flutter/fuchsia_external_view_embedder.cc | 6 +- .../fuchsia/flutter/vulkan_surface.cc | 315 ++++++++---------- .../platform/fuchsia/flutter/vulkan_surface.h | 42 +-- .../fuchsia/flutter/vulkan_surface_pool.cc | 67 +--- .../fuchsia/flutter/vulkan_surface_pool.h | 2 + vulkan/vulkan_device.cc | 1 + vulkan/vulkan_proc_table.cc | 2 + vulkan/vulkan_proc_table.h | 2 + 9 files changed, 173 insertions(+), 266 deletions(-) diff --git a/shell/platform/fuchsia/flutter/compositor_context.cc b/shell/platform/fuchsia/flutter/compositor_context.cc index da27e102d96a5..b53297d1a9a96 100644 --- a/shell/platform/fuchsia/flutter/compositor_context.cc +++ b/shell/platform/fuchsia/flutter/compositor_context.cc @@ -93,7 +93,7 @@ class ScopedFrame final : public flutter::CompositorContext::ScopedFrame { "of size: " << physical_size.width() << "x" << physical_size.height(); } else { - task.material.SetTexture(*(surface->GetImage())); + task.material.SetTexture(surface->GetImageId()); } frame_surfaces.emplace_back(std::move(surface)); diff --git a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc index afebc157dcbd1..7effe497324b2 100644 --- a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc @@ -299,8 +299,8 @@ void FuchsiaExternalViewEmbedder::SubmitFrame( if (layer->second.canvas_spy->DidDrawIntoCanvas()) { const auto& surface_index = frame_surface_indices.find(layer_id); FML_DCHECK(surface_index != frame_surface_indices.end()); - scenic::Image* surface_image = - frame_surfaces[surface_index->second]->GetImage(); + uint32_t surface_image_id = + frame_surfaces[surface_index->second]->GetImageId(); // Create a new layer if needed for the surface. FML_DCHECK(scenic_layer_index <= scenic_layers_.size()); @@ -363,7 +363,7 @@ void FuchsiaExternalViewEmbedder::SubmitFrame( layer->second.surface_size.height() * 0.5f, -layer_elevation); scenic_layer.material.SetColor(SK_AlphaOPAQUE, SK_AlphaOPAQUE, SK_AlphaOPAQUE, SK_AlphaOPAQUE - 1); - scenic_layer.material.SetTexture(*surface_image); + scenic_layer.material.SetTexture(surface_image_id); // Only the first (i.e. the bottom-most) layer should receive input. // TODO: Workaround for invisible overlays stealing input. Remove when diff --git a/shell/platform/fuchsia/flutter/vulkan_surface.cc b/shell/platform/fuchsia/flutter/vulkan_surface.cc index a28b4dad7293c..0ba60f4b1b518 100644 --- a/shell/platform/fuchsia/flutter/vulkan_surface.cc +++ b/shell/platform/fuchsia/flutter/vulkan_surface.cc @@ -5,6 +5,7 @@ #include "vulkan_surface.h" #include +#include #include @@ -15,52 +16,51 @@ #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrDirectContext.h" +#define LOG_AND_RETURN(cond, msg) \ + if (cond) { \ + FML_DLOG(ERROR) << msg; \ + return false; \ + } + namespace flutter_runner { namespace { -// Immutable format is technically limited to R8G8B8A8_SRGB but -// R8G8B8A8_UNORM works with existing ARM drivers so we allow that -// until we have a more reliable API for creating external Vulkan -// images using sysmem. TODO(fxb/52835) -#if defined(__aarch64__) constexpr SkColorType kSkiaColorType = kRGBA_8888_SkColorType; -constexpr fuchsia::images::PixelFormat kPixelFormat = - fuchsia::images::PixelFormat::R8G8B8A8; +constexpr fuchsia::sysmem::PixelFormatType kSysmemPixelFormat = + fuchsia::sysmem::PixelFormatType::R8G8B8A8; constexpr VkFormat kVulkanFormat = VK_FORMAT_R8G8B8A8_UNORM; constexpr VkImageCreateFlags kVulkanImageCreateFlags = 0; -#else -constexpr SkColorType kSkiaColorType = kBGRA_8888_SkColorType; -constexpr fuchsia::images::PixelFormat kPixelFormat = - fuchsia::images::PixelFormat::BGRA_8; -constexpr VkFormat kVulkanFormat = VK_FORMAT_B8G8R8A8_UNORM; -constexpr VkImageCreateFlags kVulkanImageCreateFlags = - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; -#endif +// TODO: We should only keep usages that are actually required by Skia. +constexpr VkImageUsageFlags kVkImageUsage = + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; +constexpr uint32_t kSysmemImageUsage = + fuchsia::sysmem::VULKAN_IMAGE_USAGE_COLOR_ATTACHMENT | + fuchsia::sysmem::VULKAN_IMAGE_USAGE_TRANSFER_DST | + fuchsia::sysmem::VULKAN_IMAGE_USAGE_TRANSFER_SRC | + fuchsia::sysmem::VULKAN_IMAGE_USAGE_SAMPLED; } // namespace -bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, - const SkISize& size, - VulkanImage* out_vulkan_image) { +bool VulkanSurface::CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, + const SkISize& size, + VulkanImage* out_vulkan_image) { TRACE_EVENT0("flutter", "CreateVulkanImage"); FML_DCHECK(!size.isEmpty()); FML_DCHECK(out_vulkan_image != nullptr); - // The image creation parameters need to be the same as those in scenic - // (src/ui/scenic/lib/gfx/resources/gpu_image.cc and - // src/ui/lib/escher/util/image_utils.cc) or else the different vulkan - // devices may interpret the bytes differently. - // TODO(SCN-1369): Use API to coordinate this with scenic. - out_vulkan_image->vk_external_image_create_info = { - .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, + out_vulkan_image->vk_collection_image_create_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA, .pNext = nullptr, - .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA, + .collection = collection_, + .index = 0, }; + out_vulkan_image->vk_image_create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &out_vulkan_image->vk_external_image_create_info, + .pNext = &out_vulkan_image->vk_collection_image_create_info, .flags = kVulkanImageCreateFlags, .imageType = VK_IMAGE_TYPE_2D, .format = kVulkanFormat, @@ -70,18 +70,22 @@ bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .usage = kVkImageUsage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }; + if (VK_CALL_LOG_ERROR( + vulkan_provider.vk().SetBufferCollectionConstraintsFUCHSIA( + vulkan_provider.vk_device(), collection_, + &out_vulkan_image->vk_image_create_info)) != VK_SUCCESS) { + return false; + } + { VkImage vk_image = VK_NULL_HANDLE; - if (VK_CALL_LOG_ERROR(vulkan_provider.vk().CreateImage( vulkan_provider.vk_device(), &out_vulkan_image->vk_image_create_info, nullptr, &vk_image)) != @@ -103,35 +107,30 @@ bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, return true; } -VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, - sk_sp context, - scenic::Session* session, - const SkISize& size) - : vulkan_provider_(vulkan_provider), session_(session), wait_(this) { +VulkanSurface::VulkanSurface( + vulkan::VulkanProvider& vulkan_provider, + fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, + sk_sp context, + scenic::Session* session, + const SkISize& size, + uint32_t buffer_id) + : vulkan_provider_(vulkan_provider), + session_(session), + buffer_id_(buffer_id), + wait_(this) { FML_DCHECK(session_); - zx::vmo exported_vmo; - if (!AllocateDeviceMemory(std::move(context), size, exported_vmo)) { + if (!AllocateDeviceMemory(sysmem_allocator, std::move(context), size)) { FML_DLOG(INFO) << "Could not allocate device memory."; return; } - uint64_t vmo_size; - zx_status_t status = exported_vmo.get_size(&vmo_size); - FML_DCHECK(status == ZX_OK); - if (!CreateFences()) { FML_DLOG(INFO) << "Could not create signal fences."; return; } - scenic_memory_ = std::make_unique( - session, std::move(exported_vmo), vmo_size, - fuchsia::images::MemoryType::VK_DEVICE_MEMORY); - if (!PushSessionImageSetupOps(session)) { - FML_DLOG(INFO) << "Could not push session image setup ops."; - return; - } + PushSessionImageSetupOps(session); std::fill(size_history_.begin(), size_history_.end(), SkISize::MakeEmpty()); @@ -226,57 +225,100 @@ bool VulkanSurface::CreateFences() { return true; } -bool VulkanSurface::AllocateDeviceMemory(sk_sp context, - const SkISize& size, - zx::vmo& exported_vmo) { +bool VulkanSurface::AllocateDeviceMemory( + fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, + sk_sp context, + const SkISize& size) { if (size.isEmpty()) { return false; } - VulkanImage vulkan_image; - if (!CreateVulkanImage(vulkan_provider_, size, &vulkan_image)) { - FML_DLOG(ERROR) << "Failed to create VkImage"; + fuchsia::sysmem::BufferCollectionTokenSyncPtr local_token; + zx_status_t status = + sysmem_allocator->AllocateSharedCollection(local_token.NewRequest()); + LOG_AND_RETURN(status != ZX_OK, "Failed to allocate collection"); + fuchsia::sysmem::BufferCollectionTokenSyncPtr scenic_token; + status = local_token->Duplicate(std::numeric_limits::max(), + scenic_token.NewRequest()); + LOG_AND_RETURN(status != ZX_OK, "Failed to duplicate token"); + status = local_token->Sync(); + LOG_AND_RETURN(status != ZX_OK, "Failed to sync token"); + fuchsia::sysmem::BufferCollectionTokenSyncPtr vulkan_token; + status = local_token->Duplicate(std::numeric_limits::max(), + vulkan_token.NewRequest()); + LOG_AND_RETURN(status != ZX_OK, "Failed to duplicate token"); + status = local_token->Sync(); + LOG_AND_RETURN(status != ZX_OK, "Failed to sync token"); + + session_->RegisterBufferCollection(buffer_id_, std::move(scenic_token)); + + fuchsia::sysmem::BufferCollectionSyncPtr buffer_collection; + status = sysmem_allocator->BindSharedCollection( + std::move(local_token), buffer_collection.NewRequest()); + LOG_AND_RETURN(status != ZX_OK, "Failed to bind collection"); + + fuchsia::sysmem::BufferCollectionConstraints constraints; + constraints.min_buffer_count = 1; + constraints.usage.vulkan = kSysmemImageUsage; + + constraints.image_format_constraints_count = 1; + fuchsia::sysmem::ImageFormatConstraints& image_constraints = + constraints.image_format_constraints[0]; + image_constraints = fuchsia::sysmem::ImageFormatConstraints(); + image_constraints.min_coded_width = size.width(); + image_constraints.min_coded_height = size.height(); + image_constraints.max_coded_width = size.width(); + image_constraints.max_coded_height = size.height(); + image_constraints.min_bytes_per_row = 0; + image_constraints.pixel_format.type = kSysmemPixelFormat; + image_constraints.color_spaces_count = 1; + image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB; + + status = buffer_collection->SetConstraints(true, constraints); + LOG_AND_RETURN(status != ZX_OK, "Failed to set constraints"); + + VkBufferCollectionCreateInfoFUCHSIA import_info; + import_info.collectionToken = vulkan_token.Unbind().TakeChannel().release(); + if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().CreateBufferCollectionFUCHSIA( + vulkan_provider_.vk_device(), &import_info, nullptr, &collection_)) != + VK_SUCCESS) { return false; } + VulkanImage vulkan_image; + LOG_AND_RETURN(!CreateVulkanImage(vulkan_provider_, size, &vulkan_image), + "Failed to create VkImage"); + + status = buffer_collection->Close(); + LOG_AND_RETURN(status != ZX_OK, "Failed to close collection"); + vulkan_image_ = std::move(vulkan_image); - const VkMemoryRequirements& memory_reqs = + const VkMemoryRequirements& memory_requirements = vulkan_image_.vk_memory_requirements; - const VkImageCreateInfo& image_create_info = - vulkan_image_.vk_image_create_info; - - uint32_t memory_type = 0; - for (; memory_type < 32; memory_type++) { - if ((memory_reqs.memoryTypeBits & (1 << memory_type))) { - break; - } - } + VkImageCreateInfo& image_create_info = vulkan_image_.vk_image_create_info; - VkMemoryDedicatedAllocateInfo dedicated_allocate_info = { - .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + VkImportMemoryBufferCollectionFUCHSIA import_memory_info = { + .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA, .pNext = nullptr, - .image = vulkan_image_.vk_image, - .buffer = VK_NULL_HANDLE}; - VkExportMemoryAllocateInfoKHR export_allocate_info = { - .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, - .pNext = &dedicated_allocate_info, - .handleTypes = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA}; - - const VkMemoryAllocateInfo alloc_info = { + .collection = collection_, + .index = 0, + }; + auto bits = memory_requirements.memoryTypeBits; + FML_DCHECK(bits != 0); + VkMemoryAllocateInfo allocation_info = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &export_allocate_info, - .allocationSize = memory_reqs.size, - .memoryTypeIndex = memory_type, + .pNext = &import_memory_info, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = static_cast(__builtin_ctz(bits)), }; { TRACE_EVENT1("flutter", "vkAllocateMemory", "allocationSize", - alloc_info.allocationSize); + allocation_info.allocationSize); VkDeviceMemory vk_memory = VK_NULL_HANDLE; if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().AllocateMemory( - vulkan_provider_.vk_device(), &alloc_info, NULL, &vk_memory)) != - VK_SUCCESS) { + vulkan_provider_.vk_device(), &allocation_info, NULL, + &vk_memory)) != VK_SUCCESS) { return false; } @@ -286,7 +328,7 @@ bool VulkanSurface::AllocateDeviceMemory(sk_sp context, memory, NULL); }}; - vk_memory_info_ = alloc_info; + vk_memory_info_ = allocation_info; } // Bind image memory. @@ -296,31 +338,8 @@ bool VulkanSurface::AllocateDeviceMemory(sk_sp context, return false; } - { - // Acquire the VMO for the device memory. - uint32_t vmo_handle = 0; - - VkMemoryGetZirconHandleInfoFUCHSIA get_handle_info = { - VK_STRUCTURE_TYPE_TEMP_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA, nullptr, - vk_memory_, VK_EXTERNAL_MEMORY_HANDLE_TYPE_TEMP_ZIRCON_VMO_BIT_FUCHSIA}; - if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().GetMemoryZirconHandleFUCHSIA( - vulkan_provider_.vk_device(), &get_handle_info, &vmo_handle)) != - VK_SUCCESS) { - return false; - } - - exported_vmo.reset(static_cast(vmo_handle)); - } - - // Assert that the VMO size was sufficient. - size_t vmo_size = 0; - if (exported_vmo.get_size(&vmo_size) != ZX_OK || - vmo_size < memory_reqs.size) { - return false; - } - return SetupSkiaSurface(std::move(context), size, kSkiaColorType, - image_create_info, memory_reqs); + image_create_info, memory_requirements); } bool VulkanSurface::SetupSkiaSurface(sk_sp context, @@ -370,89 +389,21 @@ bool VulkanSurface::SetupSkiaSurface(sk_sp context, return true; } -bool VulkanSurface::PushSessionImageSetupOps(scenic::Session* session) { - FML_DCHECK(scenic_memory_ != nullptr); - - if (sk_surface_ == nullptr) { - return false; - } - - fuchsia::images::ImageInfo image_info; - image_info.width = sk_surface_->width(); - image_info.height = sk_surface_->height(); - image_info.stride = 4 * sk_surface_->width(); - image_info.pixel_format = kPixelFormat; - image_info.color_space = fuchsia::images::ColorSpace::SRGB; - switch (vulkan_image_.vk_image_create_info.tiling) { - case VK_IMAGE_TILING_OPTIMAL: - image_info.tiling = fuchsia::images::Tiling::GPU_OPTIMAL; - break; - case VK_IMAGE_TILING_LINEAR: - image_info.tiling = fuchsia::images::Tiling::LINEAR; - break; - default: - FML_DLOG(ERROR) << "Bad image tiling: " - << vulkan_image_.vk_image_create_info.tiling; - return false; - } - - session_image_ = std::make_unique( - *scenic_memory_, 0 /* memory offset */, std::move(image_info)); - - return session_image_ != nullptr; +void VulkanSurface::PushSessionImageSetupOps(scenic::Session* session) { + if (image_id_ == 0) + image_id_ = session->AllocResourceId(); + session->Enqueue(scenic::NewCreateImage2Cmd( + image_id_, sk_surface_->width(), sk_surface_->height(), buffer_id_, 0)); } -scenic::Image* VulkanSurface::GetImage() { - if (!valid_) { - return 0; - } - return session_image_.get(); +uint32_t VulkanSurface::GetImageId() { + return image_id_; } sk_sp VulkanSurface::GetSkiaSurface() const { return valid_ ? sk_surface_ : nullptr; } -bool VulkanSurface::BindToImage(sk_sp context, - VulkanImage vulkan_image) { - FML_DCHECK(vulkan_image.vk_memory_requirements.size <= - vk_memory_info_.allocationSize); - - vulkan_image_ = std::move(vulkan_image); - - // Bind image memory. - if (VK_CALL_LOG_ERROR(vulkan_provider_.vk().BindImageMemory( - vulkan_provider_.vk_device(), vulkan_image_.vk_image, vk_memory_, - 0)) != VK_SUCCESS) { - valid_ = false; - return false; - } - - const auto& extent = vulkan_image.vk_image_create_info.extent; - auto size = SkISize::Make(extent.width, extent.height); - - if (!SetupSkiaSurface(std::move(context), size, kSkiaColorType, - vulkan_image.vk_image_create_info, - vulkan_image.vk_memory_requirements)) { - FML_DLOG(ERROR) << "Failed to setup skia surface"; - valid_ = false; - return false; - } - - if (sk_surface_ == nullptr) { - valid_ = false; - return false; - } - - if (!PushSessionImageSetupOps(session_)) { - FML_DLOG(ERROR) << "Could not push session image setup ops."; - valid_ = false; - return false; - } - - return true; -} - size_t VulkanSurface::AdvanceAndGetAge() { size_history_[size_history_index_] = GetSize(); size_history_index_ = (size_history_index_ + 1) % kSizeHistorySize; diff --git a/shell/platform/fuchsia/flutter/vulkan_surface.h b/shell/platform/fuchsia/flutter/vulkan_surface.h index bff2713a011c9..45ad52a45f5b2 100644 --- a/shell/platform/fuchsia/flutter/vulkan_surface.h +++ b/shell/platform/fuchsia/flutter/vulkan_surface.h @@ -37,7 +37,7 @@ class SurfaceProducerSurface { virtual void SignalWritesFinished( const std::function& on_writes_committed) = 0; - virtual scenic::Image* GetImage() = 0; + virtual uint32_t GetImageId() = 0; virtual sk_sp GetSkiaSurface() const = 0; }; @@ -59,7 +59,7 @@ struct VulkanImage { VulkanImage(VulkanImage&&) = default; VulkanImage& operator=(VulkanImage&&) = default; - VkExternalMemoryImageCreateInfo vk_external_image_create_info; + VkBufferCollectionImageCreateInfoFUCHSIA vk_collection_image_create_info; VkImageCreateInfo vk_image_create_info; VkMemoryRequirements vk_memory_requirements; vulkan::VulkanHandle vk_image; @@ -67,19 +67,14 @@ struct VulkanImage { FML_DISALLOW_COPY_AND_ASSIGN(VulkanImage); }; -// Create a new |VulkanImage| of size |size|, stored in -// |out_vulkan_image|. Returns whether creation of the |VkImage| was -// successful. -bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, - const SkISize& size, - VulkanImage* out_vulkan_image); - class VulkanSurface final : public SurfaceProducerSurface { public: VulkanSurface(vulkan::VulkanProvider& vulkan_provider, + fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, sk_sp context, scenic::Session* session, - const SkISize& size); + const SkISize& size, + uint32_t buffer_id); ~VulkanSurface() override; @@ -101,7 +96,7 @@ class VulkanSurface final : public SurfaceProducerSurface { const std::function& on_writes_committed) override; // |SurfaceProducerSurface| - scenic::Image* GetImage() override; + uint32_t GetImageId() override; // |SurfaceProducerSurface| sk_sp GetSkiaSurface() const override; @@ -141,13 +136,6 @@ class VulkanSurface final : public SurfaceProducerSurface { size_history_.begin()); } - // Bind |vulkan_image| to |vk_memory_| and create a new skia surface, - // replacing the previous |vk_image_|. |vulkan_image| MUST require less - // than or equal the amount of memory contained in |vk_memory_|. Returns - // whether the swap was successful. The |VulkanSurface| will become invalid - // if the swap was not successful. - bool BindToImage(sk_sp context, VulkanImage vulkan_image); - private: static constexpr int kSizeHistorySize = 4; @@ -156,9 +144,13 @@ class VulkanSurface final : public SurfaceProducerSurface { zx_status_t status, const zx_packet_signal_t* signal); - bool AllocateDeviceMemory(sk_sp context, - const SkISize& size, - zx::vmo& exported_vmo); + bool AllocateDeviceMemory(fuchsia::sysmem::AllocatorSyncPtr& sysmem_allocator, + sk_sp context, + const SkISize& size); + + bool CreateVulkanImage(vulkan::VulkanProvider& vulkan_provider, + const SkISize& size, + VulkanImage* out_vulkan_image); bool SetupSkiaSurface(sk_sp context, const SkISize& size, @@ -168,7 +160,7 @@ class VulkanSurface final : public SurfaceProducerSurface { bool CreateFences(); - bool PushSessionImageSetupOps(scenic::Session* session); + void PushSessionImageSetupOps(scenic::Session* session); void Reset(); @@ -182,9 +174,9 @@ class VulkanSurface final : public SurfaceProducerSurface { VkMemoryAllocateInfo vk_memory_info_; vulkan::VulkanHandle command_buffer_fence_; sk_sp sk_surface_; - // TODO: Don't heap allocate this once SCN-268 is resolved. - std::unique_ptr scenic_memory_; - std::unique_ptr session_image_; + const uint32_t buffer_id_; + uint32_t image_id_ = 0; + VkBufferCollectionFUCHSIA collection_; zx::event acquire_event_; vulkan::VulkanHandle acquire_semaphore_; std::unique_ptr command_buffer_; diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc b/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc index 1b85a957898bd..bd3ffb4810da6 100644 --- a/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc +++ b/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc @@ -4,6 +4,8 @@ #include "vulkan_surface_pool.h" +#include + #include #include @@ -12,21 +14,17 @@ namespace flutter_runner { -namespace { - -std::string ToString(const SkISize& size) { - return "{width: " + std::to_string(size.width()) + - ", height: " + std::to_string(size.height()) + "}"; -} - -} // namespace - VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider, sk_sp context, scenic::Session* scenic_session) : vulkan_provider_(vulkan_provider), context_(std::move(context)), - scenic_session_(scenic_session) {} + scenic_session_(scenic_session) { + zx_status_t status = fdio_service_connect( + "/svc/fuchsia.sysmem.Allocator", + sysmem_allocator_.NewRequest().TakeChannel().release()); + FML_DCHECK(status != ZX_OK); +} VulkanSurfacePool::~VulkanSurfacePool() {} @@ -66,49 +64,7 @@ std::unique_ptr VulkanSurfacePool::GetCachedOrCreateSurface( } } - // Then, look for a surface that has enough |VkDeviceMemory| to hold a - // |VkImage| of size |size|, but is currently holding a |VkImage| of a - // different size. - VulkanImage vulkan_image; - if (!CreateVulkanImage(vulkan_provider_, size, &vulkan_image)) { - FML_DLOG(ERROR) << "Failed to create a VkImage of size: " << ToString(size); - return nullptr; - } - - auto best_it = available_surfaces_.end(); - for (auto it = available_surfaces_.begin(); it != available_surfaces_.end(); - ++it) { - const auto& surface = *it; - if (!surface->IsValid() || surface->GetAllocationSize() < - vulkan_image.vk_memory_requirements.size) { - continue; - } - if (best_it == available_surfaces_.end() || - surface->GetAllocationSize() < (*best_it)->GetAllocationSize()) { - best_it = it; - } - } - - // If no such surface exists, then create a new one. - if (best_it == available_surfaces_.end()) { - TRACE_EVENT_INSTANT0("flutter", "No available surfaces"); - return CreateSurface(size); - } - - auto acquired_surface = std::move(*best_it); - available_surfaces_.erase(best_it); - bool swap_succeeded = - acquired_surface->BindToImage(context_, std::move(vulkan_image)); - if (!swap_succeeded) { - FML_DLOG(ERROR) << "Failed to swap VulkanSurface to new VkImage of size: " - << ToString(size); - TRACE_EVENT_INSTANT0("flutter", "failed to swap, making new"); - return CreateSurface(size); - } - TRACE_EVENT_INSTANT0("flutter", "Using differently sized image"); - FML_DCHECK(acquired_surface->IsValid()); - trace_surfaces_reused_++; - return acquired_surface; + return CreateSurface(size); } void VulkanSurfacePool::SubmitSurface( @@ -140,8 +96,9 @@ std::unique_ptr VulkanSurfacePool::CreateSurface( const SkISize& size) { TRACE_EVENT2("flutter", "VulkanSurfacePool::CreateSurface", "width", size.width(), "height", size.height()); - auto surface = std::make_unique(vulkan_provider_, context_, - scenic_session_, size); + auto surface = std::make_unique( + vulkan_provider_, sysmem_allocator_, context_, scenic_session_, size, + buffer_id_++); if (!surface->IsValid()) { return nullptr; } diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_pool.h b/shell/platform/fuchsia/flutter/vulkan_surface_pool.h index f98d45216f4a6..00686f54183ac 100644 --- a/shell/platform/fuchsia/flutter/vulkan_surface_pool.h +++ b/shell/platform/fuchsia/flutter/vulkan_surface_pool.h @@ -41,9 +41,11 @@ class VulkanSurfacePool final { vulkan::VulkanProvider& vulkan_provider_; sk_sp context_; scenic::Session* scenic_session_; + fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator_; std::vector> available_surfaces_; std::unordered_map> pending_surfaces_; + uint32_t buffer_id_ = 1; size_t trace_surfaces_created_ = 0; size_t trace_surfaces_reused_ = 0; diff --git a/vulkan/vulkan_device.cc b/vulkan/vulkan_device.cc index e2d45bb5e1f2d..fbc9aaa13e862 100644 --- a/vulkan/vulkan_device.cc +++ b/vulkan/vulkan_device.cc @@ -69,6 +69,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME, #endif }; diff --git a/vulkan/vulkan_proc_table.cc b/vulkan/vulkan_proc_table.cc index 9ed7c40b5c9ae..6d8d93686a883 100644 --- a/vulkan/vulkan_proc_table.cc +++ b/vulkan/vulkan_proc_table.cc @@ -137,8 +137,10 @@ bool VulkanProcTable::SetupDeviceProcAddresses( ACQUIRE_PROC(QueuePresentKHR, handle); #endif // OS_ANDROID #if OS_FUCHSIA + ACQUIRE_PROC(CreateBufferCollectionFUCHSIA, handle); ACQUIRE_PROC(GetMemoryZirconHandleFUCHSIA, handle); ACQUIRE_PROC(ImportSemaphoreZirconHandleFUCHSIA, handle); + ACQUIRE_PROC(SetBufferCollectionConstraintsFUCHSIA, handle); #endif // OS_FUCHSIA device_ = {handle, nullptr}; return true; diff --git a/vulkan/vulkan_proc_table.h b/vulkan/vulkan_proc_table.h index b9d000887ca19..b6f90b758ecaa 100644 --- a/vulkan/vulkan_proc_table.h +++ b/vulkan/vulkan_proc_table.h @@ -115,8 +115,10 @@ class VulkanProcTable : public fml::RefCountedThreadSafe { DEFINE_PROC(CreateAndroidSurfaceKHR); #endif // OS_ANDROID #if OS_FUCHSIA + DEFINE_PROC(CreateBufferCollectionFUCHSIA); DEFINE_PROC(GetMemoryZirconHandleFUCHSIA); DEFINE_PROC(ImportSemaphoreZirconHandleFUCHSIA); + DEFINE_PROC(SetBufferCollectionConstraintsFUCHSIA); #endif // OS_FUCHSIA #undef DEFINE_PROC