diff --git a/content_handler/BUILD.gn b/content_handler/BUILD.gn index cb799cfd9078a..78cc3a3990ccd 100644 --- a/content_handler/BUILD.gn +++ b/content_handler/BUILD.gn @@ -6,6 +6,7 @@ assert(is_fuchsia) declare_args() { flutter_enable_vulkan = false + flutter_use_vulkan_native_surface = false } executable("content_handler") { @@ -66,16 +67,23 @@ executable("content_handler") { ] if (flutter_enable_vulkan) { - defines += [ "FLUTTER_ENABLE_VULKAN" ] + defines += [ "FLUTTER_ENABLE_VULKAN=1" ] - libs += [ "hid" ] - - sources += [ - "direct_input.cc", - "direct_input.h", - "vulkan_rasterizer.cc", - "vulkan_rasterizer.h", - ] + if (flutter_use_vulkan_native_surface) { + defines += [ "FLUTTER_USE_VULKAN_NATIVE_SURFACE=1" ] + sources += [ + "direct_input.cc", + "direct_input.h", + "vulkan_native_rasterizer.cc", + "vulkan_native_rasterizer.h", + ] + libs += [ "hid" ] + } else { + sources += [ + "vulkan_rasterizer.cc", + "vulkan_rasterizer.h", + ] + } deps += [ "//flutter/vulkan", diff --git a/content_handler/rasterizer.cc b/content_handler/rasterizer.cc index 6d42665606b4e..e0ea43f513a5e 100644 --- a/content_handler/rasterizer.cc +++ b/content_handler/rasterizer.cc @@ -7,7 +7,11 @@ #include "flutter/content_handler/software_rasterizer.h" #if FLUTTER_ENABLE_VULKAN +#if FLUTTER_USE_VULKAN_NATIVE_SURFACE +#include "flutter/content_handler/vulkan_native_rasterizer.h" +#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE #include "flutter/content_handler/vulkan_rasterizer.h" +#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE #endif // FLUTTER_ENABLE_VULKAN namespace flutter_runner { @@ -16,7 +20,11 @@ Rasterizer::~Rasterizer() = default; std::unique_ptr Rasterizer::Create() { #if FLUTTER_ENABLE_VULKAN +#if FLUTTER_USE_VULKAN_NATIVE_SURFACE + auto vulkan_rasterizer = std::make_unique(); +#else // FLUTTER_USE_VULKAN_NATIVE_SURFACE auto vulkan_rasterizer = std::make_unique(); +#endif // FLUTTER_USE_VULKAN_NATIVE_SURFACE if (!vulkan_rasterizer->IsValid()) { FTL_DLOG(INFO) << "Could not initialize a valid vulkan rasterizer. " diff --git a/content_handler/runtime_holder.cc b/content_handler/runtime_holder.cc index d6a53c92a3207..aeb46a999a84c 100644 --- a/content_handler/runtime_holder.cc +++ b/content_handler/runtime_holder.cc @@ -140,14 +140,14 @@ void RuntimeHolder::CreateView( input_listener_binding_.Bind(GetProxy(&input_listener)); input_connection_->SetEventListener(std::move(input_listener)); -#if FLUTTER_ENABLE_VULKAN +#if FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE direct_input_ = std::make_unique( [this](const blink::PointerDataPacket& packet) -> void { runtime_->DispatchPointerDataPacket(packet); }); FTL_DCHECK(direct_input_->IsValid()); direct_input_->WaitForReadAvailability(); -#endif // FLUTTER_ENABLE_VULKAN +#endif // FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE mozart::ScenePtr scene; view_->CreateScene(fidl::GetProxy(&scene)); @@ -158,9 +158,9 @@ void RuntimeHolder::CreateView( runtime_ = blink::RuntimeController::Create(this); runtime_->CreateDartController(script_uri); runtime_->SetViewportMetrics(viewport_metrics_); -#if FLUTTER_ENABLE_VULKAN +#if FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE direct_input_->SetViewportMetrics(viewport_metrics_); -#endif // FLUTTER_ENABLE_VULKAN +#endif // FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE if (!kernel.empty()) { runtime_->dart_controller()->RunFromKernel(kernel.data(), kernel.size()); } else { @@ -377,11 +377,11 @@ void RuntimeHolder::OnInvalidation(mozart::ViewInvalidationPtr invalidation, // TODO(abarth): Use view_properties_->display_metrics->device_pixel_ratio // once that's reasonable. runtime_->SetViewportMetrics(viewport_metrics_); -#if FLUTTER_ENABLE_VULKAN +#if FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE if (direct_input_) { direct_input_->SetViewportMetrics(viewport_metrics_); } -#endif // FLUTTER_ENABLE_VULKAN +#endif // FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE } // Remember the scene version for rendering. diff --git a/content_handler/runtime_holder.h b/content_handler/runtime_holder.h index ffb58ae24a292..628f8501ffb31 100644 --- a/content_handler/runtime_holder.h +++ b/content_handler/runtime_holder.h @@ -24,9 +24,9 @@ #include "lib/ftl/macros.h" #include "lib/ftl/memory/weak_ptr.h" -#if FLUTTER_ENABLE_VULKAN +#if FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE #include "flutter/content_handler/direct_input.h" -#endif // FLUTTER_ENABLE_VULKAN +#endif // FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE namespace flutter_runner { class Rasterizer; @@ -92,9 +92,9 @@ class RuntimeHolder : public blink::RuntimeDelegate, mozart::ViewManagerPtr view_manager_; fidl::Binding view_listener_binding_; fidl::Binding input_listener_binding_; -#if FLUTTER_ENABLE_VULKAN +#if FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE std::unique_ptr direct_input_; -#endif // FLUTTER_ENABLE_VULKAN +#endif // FLUTTER_ENABLE_VULKAN && FLUTTER_USE_VULKAN_NATIVE_SURFACE mozart::InputConnectionPtr input_connection_; mozart::ViewPtr view_; mozart::ViewPropertiesPtr view_properties_; diff --git a/content_handler/software_rasterizer.cc b/content_handler/software_rasterizer.cc index 21f1bd2768c68..9fd288dfc6198 100644 --- a/content_handler/software_rasterizer.cc +++ b/content_handler/software_rasterizer.cc @@ -13,13 +13,23 @@ namespace flutter_runner { +SoftwareRasterizer::RasterSurfaceProducer::RasterSurfaceProducer() { + buffer_producer_.reset(new mozart::BufferProducer()); +} + +sk_sp SoftwareRasterizer::RasterSurfaceProducer::ProduceSurface( + SkISize size, + mozart::ImagePtr* out_image) { + return mozart::MakeSkSurface(size, buffer_producer_.get(), out_image); +} + SoftwareRasterizer::SoftwareRasterizer() : compositor_context_(nullptr) {} SoftwareRasterizer::~SoftwareRasterizer() = default; void SoftwareRasterizer::SetScene(fidl::InterfaceHandle scene) { scene_.Bind(std::move(scene)); - buffer_producer_.reset(new mozart::BufferProducer()); + surface_producer_.reset(new RasterSurfaceProducer()); } void SoftwareRasterizer::Draw(std::unique_ptr layer_tree, @@ -54,7 +64,7 @@ void SoftwareRasterizer::Draw(std::unique_ptr layer_tree, layer_tree->Preroll(frame); - flow::SceneUpdateContext context(update.get(), buffer_producer_.get()); + flow::SceneUpdateContext context(update.get(), surface_producer_.get()); auto root_node = mozart::Node::New(); root_node->hit_test_behavior = mozart::HitTestBehavior::New(); layer_tree->UpdateScene(context, root_node.get()); @@ -72,7 +82,7 @@ void SoftwareRasterizer::Draw(std::unique_ptr layer_tree, // The image buffer's fence is signalled automatically when the surface // goes out of scope. context.ExecutePaintTasks(frame); - buffer_producer_->Tick(); + surface_producer_->Tick(); callback(); } diff --git a/content_handler/software_rasterizer.h b/content_handler/software_rasterizer.h index c08aa429fade8..50dab87b64749 100644 --- a/content_handler/software_rasterizer.h +++ b/content_handler/software_rasterizer.h @@ -26,8 +26,20 @@ class SoftwareRasterizer : public Rasterizer { ftl::Closure callback) override; private: + class RasterSurfaceProducer + : public flow::SceneUpdateContext::SurfaceProducer { + public: + RasterSurfaceProducer(); + sk_sp ProduceSurface(SkISize size, + mozart::ImagePtr* out_image) override; + void Tick() { buffer_producer_->Tick(); } + + private: + std::unique_ptr buffer_producer_; + }; + mozart::ScenePtr scene_; - std::unique_ptr buffer_producer_; + std::unique_ptr surface_producer_; flow::CompositorContext compositor_context_; FTL_DISALLOW_COPY_AND_ASSIGN(SoftwareRasterizer); diff --git a/content_handler/vulkan_native_rasterizer.cc b/content_handler/vulkan_native_rasterizer.cc new file mode 100644 index 0000000000000..40985c36cc0bb --- /dev/null +++ b/content_handler/vulkan_native_rasterizer.cc @@ -0,0 +1,90 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/vulkan_native_rasterizer.h" + +#include + +#include "flutter/vulkan/vulkan_native_surface_magma.h" + +namespace flutter_runner { + +VulkanNativeRasterizer::VulkanNativeRasterizer() + : compositor_context_(nullptr) { + auto proc_table = ftl::MakeRefCounted(); + + if (!proc_table->HasAcquiredMandatoryProcAddresses()) { + return; + } + + auto native_surface = std::make_unique(); + + if (!native_surface->IsValid()) { + return; + } + + auto window = std::make_unique( + proc_table, std::move(native_surface)); + + if (!window->IsValid()) { + return; + } + + window_ = std::move(window); +} + +VulkanNativeRasterizer::~VulkanNativeRasterizer() = default; + +bool VulkanNativeRasterizer::IsValid() const { + return window_ == nullptr ? false : window_->IsValid(); +} + +void VulkanNativeRasterizer::SetScene( + fidl::InterfaceHandle scene) { + // TODO: Composition is currently unsupported using the Vulkan backend. +} + +void VulkanNativeRasterizer::Draw(std::unique_ptr layer_tree, + ftl::Closure callback) { + Draw(std::move(layer_tree)); + callback(); +} + +bool VulkanNativeRasterizer::Draw(std::unique_ptr layer_tree) { + if (layer_tree == nullptr) { + FTL_DLOG(INFO) << "Layer tree was not valid."; + return false; + } + + if (!window_->IsValid()) { + FTL_DLOG(INFO) << "Vulkan window was not valid."; + return false; + } + + auto surface = window_->AcquireSurface(); + + if (!surface && surface->getCanvas() != nullptr) { + FTL_DLOG(INFO) << "Could not acquire a vulkan surface."; + return false; + } + + { + auto compositor_frame = compositor_context_.AcquireFrame( + window_->GetSkiaGrContext(), // GrContext* + surface->getCanvas(), // SkCanvas + true // instrumentation + ); + + layer_tree->Raster(compositor_frame); + } + + if (!window_->SwapBuffers()) { + FTL_DLOG(INFO) << "Could not swap buffers successfully."; + return false; + } + + return true; +} + +} // namespace flutter_runner diff --git a/content_handler/vulkan_native_rasterizer.h b/content_handler/vulkan_native_rasterizer.h new file mode 100644 index 0000000000000..bf54f2d765208 --- /dev/null +++ b/content_handler/vulkan_native_rasterizer.h @@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ +#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ + +#include + +#include "flutter/content_handler/rasterizer.h" +#include "flutter/flow/compositor_context.h" +#include "flutter/vulkan/vulkan_window.h" +#include "lib/ftl/macros.h" + +namespace flutter_runner { + +class VulkanNativeRasterizer : public Rasterizer { + public: + VulkanNativeRasterizer(); + + ~VulkanNativeRasterizer() override; + + bool IsValid() const; + + void SetScene(fidl::InterfaceHandle scene) override; + + void Draw(std::unique_ptr layer_tree, + ftl::Closure callback) override; + + private: + std::unique_ptr window_; + flow::CompositorContext compositor_context_; + + bool Draw(std::unique_ptr layer_tree); + + FTL_DISALLOW_COPY_AND_ASSIGN(VulkanNativeRasterizer); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ \ No newline at end of file diff --git a/content_handler/vulkan_rasterizer.cc b/content_handler/vulkan_rasterizer.cc index f45c6024b4410..a7ebed68bc3f7 100644 --- a/content_handler/vulkan_rasterizer.cc +++ b/content_handler/vulkan_rasterizer.cc @@ -6,41 +6,295 @@ #include -#include "flutter/vulkan/vulkan_native_surface_magma.h" +#include +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/vk/GrVkTypes.h" +#include "third_party/skia/src/gpu/vk/GrVkUtil.h" namespace flutter_runner { -VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) { - auto proc_table = ftl::MakeRefCounted(); +VulkanRasterizer::VulkanSurfaceProducer::VulkanSurfaceProducer() { + valid_ = Initialize(); + if (!valid_) + FTL_DLOG(INFO) << "VulkanSurfaceProducer failed to initialize"; +} - if (!proc_table->HasAcquiredMandatoryProcAddresses()) { - return; +sk_sp VulkanRasterizer::VulkanSurfaceProducer::ProduceSurface( + SkISize size, + mozart::ImagePtr* out_image) { + if (size.isEmpty()) { + FTL_DLOG(INFO) << "Attempting to create surface with empty size"; + return nullptr; } - auto native_surface = std::make_unique(); + // these casts are safe because of the early out on frame_size.isEmpty() + auto width = static_cast(size.width()); + auto height = static_cast(size.height()); + + VkResult vk_result; + + VkImageCreateInfo image_create_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, + .imageType = VK_IMAGE_TYPE_2D, + .format = VK_FORMAT_B8G8R8A8_UNORM, + .extent = VkExtent3D{width, height, 1}, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VkImage vk_image; + vk_result = VK_CALL_LOG_ERROR(vkCreateImage( + backend_context_->fDevice, &image_create_info, nullptr, &vk_image)); + if (vk_result) + return nullptr; + + VkMemoryRequirements memory_reqs; + vkGetImageMemoryRequirements(backend_context_->fDevice, vk_image, + &memory_reqs); - if (!native_surface->IsValid()) { - return; + uint32_t memory_type = 0; + for (; memory_type < 32; memory_type++) { + if ((memory_reqs.memoryTypeBits & (1 << memory_type))) + break; } - auto window = std::make_unique( - proc_table, std::move(native_surface)); + VkMemoryAllocateInfo alloc_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = memory_reqs.size, + .memoryTypeIndex = memory_type, + }; + + VkDeviceMemory vk_memory; + vk_result = VK_CALL_LOG_ERROR(vkAllocateMemory( + backend_context_->fDevice, &alloc_info, NULL, &vk_memory)); + if (vk_result) + return nullptr; + + vk_result = VK_CALL_LOG_ERROR( + vkBindImageMemory(backend_context_->fDevice, vk_image, vk_memory, 0)); + if (vk_result) + return nullptr; + + const GrVkImageInfo image_info = { + .fImage = vk_image, + .fAlloc = {vk_memory, 0, memory_reqs.size, 0}, + .fImageTiling = image_create_info.tiling, + .fImageLayout = image_create_info.initialLayout, + .fFormat = image_create_info.format, + .fLevelCount = image_create_info.mipLevels, + }; + + GrBackendRenderTargetDesc desc; + desc.fWidth = width; + desc.fHeight = height; + desc.fConfig = kSBGRA_8888_GrPixelConfig; + desc.fOrigin = kTopLeft_GrSurfaceOrigin; + desc.fSampleCnt = 0; + desc.fStencilBits = 0; + + desc.fRenderTargetHandle = reinterpret_cast(&image_info); - if (!window->IsValid()) { - return; + SkSurfaceProps props(SkSurfaceProps::InitType::kLegacyFontHost_InitType); + + auto sk_surface = SkSurface::MakeFromBackendRenderTarget( + context_.get(), desc, SkColorSpace::MakeSRGB(), &props); + if (!sk_surface) { + FTL_DLOG(INFO) << "MakeFromBackendRenderTarget Failed"; + return nullptr; } - window_ = std::move(window); + uint32_t vmo_handle; + vk_result = VK_CALL_LOG_ERROR(vkExportDeviceMemoryMAGMA( + backend_context_->fDevice, vk_memory, &vmo_handle)); + if (vk_result) + return nullptr; + + mx::eventpair retention_events[2]; + auto mx_status = + mx::eventpair::create(0, &retention_events[0], &retention_events[1]); + if (mx_status) { + FTL_DLOG(INFO) << "Failed to create retention eventpair"; + return nullptr; + } + + if (!sk_surface || sk_surface->getCanvas() == nullptr) { + FTL_DLOG(INFO) << "surface invalid"; + return nullptr; + } + + surfaces_.emplace_back( + sk_surface, // sk_sp sk_surface + mx::vmo(vmo_handle), // mx::vmo vmo + std::move(retention_events[0]), // mx::eventpair local_retention_event; + std::move(retention_events[1]), // mx::eventpair remote_retention_event; + mx::eventpair(), // mx::eventpair fence_event + vk_image, vk_memory); + + auto surface = &surfaces_.back(); + + size_t vmo_size; + surface->vmo.get_size(&vmo_size); + + if (vmo_size < memory_reqs.size) { + FTL_DLOG(INFO) << "Failed to allocate sufficiently large vmo"; + return nullptr; + } + + mx_status_t status; + auto buffer = mozart::Buffer::New(); + status = surface->vmo.duplicate(MX_RIGHT_SAME_RIGHTS, &buffer->vmo); + if (status) { + FTL_DLOG(INFO) << "failed to duplicate vmo"; + return nullptr; + } + + buffer->memory_type = mozart::Buffer::MemoryType::VK_DEVICE_MEMORY; + + status = mx::eventpair::create(0, &surface->fence_event, &buffer->fence); + if (status) { + FTL_DLOG(INFO) << "failed to create fence eventpair"; + return nullptr; + } + + status = surface->remote_retention_event.duplicate(MX_RIGHT_SAME_RIGHTS, + &buffer->retention); + if (status) { + FTL_DLOG(INFO) << "failed to duplicate retention eventpair"; + return nullptr; + } + + auto image = mozart::Image::New(); + image->size = mozart::Size::New(); + image->size->width = width; + image->size->height = height; + image->stride = 4 * width; + image->pixel_format = mozart::Image::PixelFormat::B8G8R8A8; + image->alpha_format = mozart::Image::AlphaFormat::OPAQUE; + image->color_space = mozart::Image::ColorSpace::SRGB; + image->buffer = std::move(buffer); + *out_image = std::move(image); + + return sk_surface; } +bool VulkanRasterizer::VulkanSurfaceProducer::Tick() { + mx_status_t status; + + for (auto& surface : surfaces_) { + GrVkImageInfo* image_info = nullptr; + if (!surface.sk_surface->getRenderTargetHandle( + reinterpret_cast(&image_info), + SkSurface::kFlushRead_BackendHandleAccess)) { + FTL_DLOG(INFO) << "Could not get render target handle."; + return false; + } + (void)image_info; + + status = surface.fence_event.signal_peer(0u, MX_EPAIR_SIGNALED); + if (status) { + FTL_DLOG(INFO) << "failed to signal fence event"; + return false; + } + + vkFreeMemory(backend_context_->fDevice, surface.vk_memory, NULL); + + vkDestroyImage(backend_context_->fDevice, surface.vk_image, NULL); + } + + surfaces_.clear(); + return true; +} + +bool VulkanRasterizer::VulkanSurfaceProducer::Initialize() { + auto vk = ftl::MakeRefCounted(); + + std::vector extensions = {VK_KHR_SURFACE_EXTENSION_NAME}; + application_ = std::make_unique( + *vk, "Flutter", std::move(extensions)); + + if (!application_->IsValid() || !vk->AreInstanceProcsSetup()) { + // Make certain the application instance was created and it setup the + // instance proc table entries. + FTL_DLOG(INFO) << "Instance proc addresses have not been setup."; + return false; + } + + // Create the device. + + logical_device_ = application_->AcquireFirstCompatibleLogicalDevice(); + + if (logical_device_ == nullptr || !logical_device_->IsValid() || + !vk->AreDeviceProcsSetup()) { + // Make certain the device was created and it setup the device proc table + // entries. + FTL_DLOG(INFO) << "Device proc addresses have not been setup."; + return false; + } + + if (!vk->HasAcquiredMandatoryProcAddresses()) { + FTL_DLOG(INFO) << "Failed to acquire mandatory proc addresses"; + return false; + } + + if (!vk->IsValid()) { + FTL_DLOG(INFO) << "VulkanProcTable invalid"; + return false; + } + + auto interface = vk->CreateSkiaInterface(); + + if (interface == nullptr || !interface->validate(0)) { + FTL_DLOG(INFO) << "interface invalid"; + return false; + } + + uint32_t skia_features = 0; + if (!logical_device_->GetPhysicalDeviceFeaturesSkia(&skia_features)) { + FTL_DLOG(INFO) << "Failed to get physical device features"; + + return false; + } + + backend_context_ = sk_make_sp(); + backend_context_->fInstance = application_->GetInstance(); + backend_context_->fPhysicalDevice = + logical_device_->GetPhysicalDeviceHandle(); + backend_context_->fDevice = logical_device_->GetHandle(); + backend_context_->fQueue = logical_device_->GetQueueHandle(); + backend_context_->fGraphicsQueueIndex = + logical_device_->GetGraphicsQueueIndex(); + backend_context_->fMinAPIVersion = application_->GetAPIVersion(); + backend_context_->fFeatures = skia_features; + backend_context_->fInterface.reset(interface.release()); + + context_.reset(GrContext::Create( + kVulkan_GrBackend, + reinterpret_cast(backend_context_.get()))); + + return true; +} + +VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) {} + VulkanRasterizer::~VulkanRasterizer() = default; bool VulkanRasterizer::IsValid() const { - return window_ == nullptr ? false : window_->IsValid(); + return !surface_producer_ || surface_producer_->IsValid(); } void VulkanRasterizer::SetScene(fidl::InterfaceHandle scene) { - // TODO: Composition is currently unsupported using the Vulkan backend. + scene_.Bind(std::move(scene)); + surface_producer_.reset(new VulkanSurfaceProducer()); } void VulkanRasterizer::Draw(std::unique_ptr layer_tree, @@ -55,30 +309,54 @@ bool VulkanRasterizer::Draw(std::unique_ptr layer_tree) { return false; } - if (!window_->IsValid()) { - FTL_DLOG(INFO) << "Vulkan window was not valid."; + if (!scene_) { + FTL_DLOG(INFO) << "Scene was not valid."; return false; } - auto surface = window_->AcquireSurface(); + const SkISize& frame_size = layer_tree->frame_size(); + + auto update = mozart::SceneUpdate::New(); + // TODO(abarth): Support incremental updates. + update->clear_resources = true; + update->clear_nodes = true; + + if (frame_size.isEmpty()) { + update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New()); + // Publish the updated scene contents. + // TODO(jeffbrown): We should set the metadata's presentation_time here too. + scene_->Update(std::move(update)); + auto metadata = mozart::SceneMetadata::New(); + metadata->version = layer_tree->scene_version(); + scene_->Publish(std::move(metadata)); + FTL_DLOG(INFO) << "Publishing empty node"; - if (!surface && surface->getCanvas() != nullptr) { - FTL_DLOG(INFO) << "Could not acquire a vulkan surface."; return false; } - { - auto compositor_frame = compositor_context_.AcquireFrame( - window_->GetSkiaGrContext(), // GrContext* - surface->getCanvas(), // SkCanvas - true // instrumentation - ); + flow::CompositorContext::ScopedFrame frame = + compositor_context_.AcquireFrame(nullptr, nullptr); - layer_tree->Raster(compositor_frame); - } + layer_tree->Preroll(frame); + + flow::SceneUpdateContext context(update.get(), surface_producer_.get()); + auto root_node = mozart::Node::New(); + root_node->hit_test_behavior = mozart::HitTestBehavior::New(); + layer_tree->UpdateScene(context, root_node.get()); + update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node)); + + // Publish the updated scene contents. + // TODO(jeffbrown): We should set the metadata's presentation_time here too. + scene_->Update(std::move(update)); + auto metadata = mozart::SceneMetadata::New(); + metadata->version = layer_tree->scene_version(); + scene_->Publish(std::move(metadata)); - if (!window_->SwapBuffers()) { - FTL_DLOG(INFO) << "Could not swap buffers successfully."; + // Draw the contents of the scene to a surface. + // We do this after publishing to take advantage of pipelining. + context.ExecutePaintTasks(frame); + if (!surface_producer_->Tick()) { + FTL_DLOG(INFO) << "Failed to tick surface producer"; return false; } diff --git a/content_handler/vulkan_rasterizer.h b/content_handler/vulkan_rasterizer.h index dd8ee58004d22..6a0f389dfb251 100644 --- a/content_handler/vulkan_rasterizer.h +++ b/content_handler/vulkan_rasterizer.h @@ -7,10 +7,13 @@ #include +#include "apps/mozart/services/buffers/cpp/buffer_producer.h" #include "flutter/content_handler/rasterizer.h" #include "flutter/flow/compositor_context.h" -#include "flutter/vulkan/vulkan_window.h" +#include "flutter/vulkan/vulkan_application.h" +#include "flutter/vulkan/vulkan_device.h" #include "lib/ftl/macros.h" +#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" namespace flutter_runner { @@ -28,9 +31,57 @@ class VulkanRasterizer : public Rasterizer { ftl::Closure callback) override; private: - std::unique_ptr window_; + class VulkanSurfaceProducer + : public flow::SceneUpdateContext::SurfaceProducer { + public: + VulkanSurfaceProducer(); + sk_sp ProduceSurface(SkISize size, + mozart::ImagePtr* out_image) override; + bool Tick(); + bool IsValid() const { return valid_; } + + private: + struct Surface { + sk_sp sk_surface; + mx::vmo vmo; + mx::eventpair local_retention_event; + mx::eventpair remote_retention_event; + mx::eventpair fence_event; + VkImage vk_image; + VkDeviceMemory vk_memory; + + Surface(sk_sp sk_surface, + mx::vmo vmo, + mx::eventpair local_retention_event, + mx::eventpair remote_retention_event, + mx::eventpair fence_event, + VkImage vk_image, + VkDeviceMemory vk_memory) + : sk_surface(std::move(sk_surface)), + vmo(std::move(vmo)), + local_retention_event(std::move(local_retention_event)), + remote_retention_event(std::move(remote_retention_event)), + fence_event(std::move(fence_event)), + vk_image(vk_image), + vk_memory(vk_memory) {} + }; + std::vector surfaces_; + + sk_sp context_; + sk_sp backend_context_; + std::unique_ptr application_; + std::unique_ptr logical_device_; + bool valid_; + + bool Initialize(); + }; + flow::CompositorContext compositor_context_; + mozart::ScenePtr scene_; + bool valid_; + std::unique_ptr surface_producer_; + bool CreateOrRecreateSurfaces(uint32_t width, uint32_t height); bool Draw(std::unique_ptr layer_tree); FTL_DISALLOW_COPY_AND_ASSIGN(VulkanRasterizer); diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index 0abf6d4c18bf1..09ec25766e74b 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -23,8 +23,8 @@ void SceneUpdateContext::CurrentPaintTask::Clear() { } SceneUpdateContext::SceneUpdateContext(mozart::SceneUpdate* update, - mozart::BufferProducer* buffer_producer) - : update_(update), buffer_producer_(buffer_producer) {} + SurfaceProducer* surface_producer) + : update_(update), surface_producer_(surface_producer) {} SceneUpdateContext::~SceneUpdateContext() = default; @@ -60,7 +60,7 @@ mozart::NodePtr SceneUpdateContext::FinalizeCurrentPaintTask( mozart::ImagePtr image; PaintTask task; - task.surface = mozart::MakeSkSurface(physical_size, buffer_producer_, &image); + task.surface = surface_producer_->ProduceSurface(physical_size, &image); task.left = bounds.left(); task.top = bounds.top(); task.scaleX = scaleX; diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h index 4ced4d88b76a9..34ac3f86d05a3 100644 --- a/flow/scene_update_context.h +++ b/flow/scene_update_context.h @@ -35,8 +35,15 @@ class SceneUpdateContext; class SceneUpdateContext { public: + class SurfaceProducer { + public: + virtual ~SurfaceProducer() {} + virtual sk_sp ProduceSurface(SkISize size, + mozart::ImagePtr* out_image) = 0; + }; + SceneUpdateContext(mozart::SceneUpdate* update, - mozart::BufferProducer* buffer_producer); + SurfaceProducer* surface_producer); ~SceneUpdateContext(); mozart::SceneUpdate* update() const { return update_; } @@ -71,7 +78,7 @@ class SceneUpdateContext { }; mozart::SceneUpdate* update_; - mozart::BufferProducer* buffer_producer_; + SurfaceProducer* surface_producer_; CurrentPaintTask current_paint_task_; std::vector paint_tasks_; diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index be88f57571b7a..ad0b5617cbefd 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1362,6 +1362,8 @@ FILE: ../../../flutter/content_handler/service_protocol_hooks.cc FILE: ../../../flutter/content_handler/service_protocol_hooks.h FILE: ../../../flutter/content_handler/software_rasterizer.cc FILE: ../../../flutter/content_handler/software_rasterizer.h +FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.cc +FILE: ../../../flutter/content_handler/vulkan_native_rasterizer.h FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc FILE: ../../../flutter/content_handler/vulkan_rasterizer.h FILE: ../../../flutter/flow/layers/physical_model_layer.cc diff --git a/vulkan/vulkan_proc_table.cc b/vulkan/vulkan_proc_table.cc index 5b6a3edc7ff3e..2584c2861c761 100644 --- a/vulkan/vulkan_proc_table.cc +++ b/vulkan/vulkan_proc_table.cc @@ -90,8 +90,12 @@ bool VulkanProcTable::SetupInstanceProcAddresses( #endif // OS_ANDROID #if OS_FUCHSIA - ACQUIRE_PROC(CreateMagmaSurfaceKHR, handle); - ACQUIRE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR, handle); + [this, &handle]() -> bool { + ACQUIRE_PROC(CreateMagmaSurfaceKHR, handle); + ACQUIRE_PROC(GetPhysicalDeviceMagmaPresentationSupportKHR, handle); + return true; + }(); + #endif // OS_FUCHSIA // The debug report functions are optional. We don't want proc acquisition to