From 23641d582a73eb85a524c12b5ffdd2d3ee5afdc8 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 28 Oct 2024 13:20:17 -0700 Subject: [PATCH] [Impeller] add basic Impeller+Vulkan support to embedder API. (flutter/engine#55490) Works on GLFW example app with no validation errors. --- .../ci/licenses_golden/licenses_flutter | 4 + .../backend/vulkan/capabilities_vk.cc | 89 ++++-- .../renderer/backend/vulkan/capabilities_vk.h | 11 +- .../renderer/backend/vulkan/context_vk.cc | 43 ++- .../renderer/backend/vulkan/context_vk.h | 21 ++ .../backend/vulkan/context_vk_unittests.cc | 43 +++ .../renderer/backend/vulkan/formats_vk.h | 12 + .../renderer/backend/vulkan/queue_vk.cc | 34 ++- .../renderer/backend/vulkan/queue_vk.h | 15 +- .../backend/vulkan/surface_context_vk.cc | 6 +- .../backend/vulkan/surface_context_vk.h | 6 + .../backend/vulkan/test/mock_vulkan.cc | 1 + .../backend/vulkan/test/mock_vulkan.h | 7 + .../renderer/backend/vulkan/texture_vk.cc | 1 + .../flutter/shell/gpu/gpu_surface_vulkan.cc | 10 +- .../shell/gpu/gpu_surface_vulkan_impeller.cc | 261 +++++++++++++++--- .../shell/gpu/gpu_surface_vulkan_impeller.h | 6 +- .../android/android_surface_vk_impeller.cc | 4 +- .../flutter/shell/platform/embedder/BUILD.gn | 7 + .../shell/platform/embedder/embedder.cc | 100 ++++++- .../embedder_surface_vulkan_impeller.cc | 124 +++++++++ .../embedder_surface_vulkan_impeller.h | 81 ++++++ .../embedder/platform_view_embedder.h | 3 + .../src/flutter/shell/testing/tester_main.cc | 2 +- 24 files changed, 777 insertions(+), 114 deletions(-) create mode 100644 engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc create mode 100644 engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 8eef52296b..fef1ebe597 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -44764,6 +44764,8 @@ ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc + ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_software.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_task_runner.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_task_runner.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc + ../../../flutter/LICENSE @@ -47655,6 +47657,8 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.h FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.h +FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.cc FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.h FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc index 7e68a23bef..eb77f78e6d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc @@ -16,27 +16,39 @@ namespace impeller { static constexpr const char* kInstanceLayer = "ImpellerInstance"; CapabilitiesVK::CapabilitiesVK(bool enable_validations, - bool fatal_missing_validations) { - auto extensions = vk::enumerateInstanceExtensionProperties(); - auto layers = vk::enumerateInstanceLayerProperties(); + bool fatal_missing_validations, + bool use_embedder_extensions, + std::vector instance_extensions, + std::vector device_extensions) + : use_embedder_extensions_(use_embedder_extensions), + embedder_instance_extensions_(std::move(instance_extensions)), + embedder_device_extensions_(std::move(device_extensions)) { + if (!use_embedder_extensions_) { + auto extensions = vk::enumerateInstanceExtensionProperties(); + auto layers = vk::enumerateInstanceLayerProperties(); - if (extensions.result != vk::Result::eSuccess || - layers.result != vk::Result::eSuccess) { - return; - } - - for (const auto& ext : extensions.value) { - exts_[kInstanceLayer].insert(ext.extensionName); - } - - for (const auto& layer : layers.value) { - const std::string layer_name = layer.layerName; - auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name); - if (layer_exts.result != vk::Result::eSuccess) { + if (extensions.result != vk::Result::eSuccess || + layers.result != vk::Result::eSuccess) { return; } - for (const auto& layer_ext : layer_exts.value) { - exts_[layer_name].insert(layer_ext.extensionName); + + for (const auto& ext : extensions.value) { + exts_[kInstanceLayer].insert(ext.extensionName); + } + + for (const auto& layer : layers.value) { + const std::string layer_name = layer.layerName; + auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name); + if (layer_exts.result != vk::Result::eSuccess) { + return; + } + for (const auto& layer_ext : layer_exts.value) { + exts_[layer_name].insert(layer_ext.extensionName); + } + } + } else { + for (const auto& ext : embedder_instance_extensions_) { + exts_[kInstanceLayer].insert(ext); } } @@ -239,17 +251,25 @@ static std::optional> GetSupportedDeviceExtensions( std::optional> CapabilitiesVK::GetEnabledDeviceExtensions( const vk::PhysicalDevice& physical_device) const { - auto exts = GetSupportedDeviceExtensions(physical_device); + std::set exts; - if (!exts.has_value()) { - return std::nullopt; + if (!use_embedder_extensions_) { + auto maybe_exts = GetSupportedDeviceExtensions(physical_device); + + if (!maybe_exts.has_value()) { + return std::nullopt; + } + exts = maybe_exts.value(); + } else { + exts = std::set(embedder_device_extensions_.begin(), + embedder_device_extensions_.end()); } std::vector enabled; auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) { auto name = GetExtensionName(ext); - if (exts->find(name) == exts->end()) { + if (exts.find(name) == exts.end()) { VALIDATION_LOG << "Device does not support required extension: " << name; return false; } @@ -260,7 +280,7 @@ CapabilitiesVK::GetEnabledDeviceExtensions( auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) { #ifdef FML_OS_ANDROID auto name = GetExtensionName(ext); - if (exts->find(name) == exts->end()) { + if (exts.find(name) == exts.end()) { VALIDATION_LOG << "Device does not support required Android extension: " << name; return false; @@ -272,7 +292,7 @@ CapabilitiesVK::GetEnabledDeviceExtensions( auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) { auto name = GetExtensionName(ext); - if (exts->find(name) != exts->end()) { + if (exts.find(name) != exts.end()) { enabled.push_back(name); } return true; @@ -524,27 +544,36 @@ bool CapabilitiesVK::SetPhysicalDevice( required_common_device_extensions_.clear(); required_android_device_extensions_.clear(); optional_device_extensions_.clear(); - auto exts = GetSupportedDeviceExtensions(device); - if (!exts.has_value()) { - return false; + + std::set exts; + if (!use_embedder_extensions_) { + auto maybe_exts = GetSupportedDeviceExtensions(device); + if (!maybe_exts.has_value()) { + return false; + } + exts = maybe_exts.value(); + } else { + exts = std::set(embedder_device_extensions_.begin(), + embedder_device_extensions_.end()); } + IterateExtensions([&](auto ext) -> bool { auto ext_name = GetExtensionName(ext); - if (exts->find(ext_name) != exts->end()) { + if (exts.find(ext_name) != exts.end()) { required_common_device_extensions_.insert(ext); } return true; }); IterateExtensions([&](auto ext) -> bool { auto ext_name = GetExtensionName(ext); - if (exts->find(ext_name) != exts->end()) { + if (exts.find(ext_name) != exts.end()) { required_android_device_extensions_.insert(ext); } return true; }); IterateExtensions([&](auto ext) -> bool { auto ext_name = GetExtensionName(ext); - if (exts->find(ext_name) != exts->end()) { + if (exts.find(ext_name) != exts.end()) { optional_device_extensions_.insert(ext); } return true; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h index a42907da33..671e8fc1b1 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.h @@ -170,7 +170,10 @@ class CapabilitiesVK final : public Capabilities, public BackendCast { public: explicit CapabilitiesVK(bool enable_validations, - bool fatal_missing_validations = false); + bool fatal_missing_validations = false, + bool use_embedder_extensions = false, + std::vector instance_extensions = {}, + std::vector device_extensions = {}); ~CapabilitiesVK(); @@ -293,6 +296,12 @@ class CapabilitiesVK final : public Capabilities, ISize max_render_pass_attachment_size_ = ISize{0, 0}; bool is_valid_ = false; + // The embedder.h API is responsible for providing the instance and device + // extensions. + bool use_embedder_extensions_ = false; + std::vector embedder_instance_extensions_; + std::vector embedder_device_extensions_; + bool HasExtension(const std::string& ext) const; bool HasLayer(const std::string& layer) const; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc index 82f3091e61..95fd1793e4 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc @@ -160,8 +160,19 @@ void ContextVK::Setup(Settings settings) { auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; dispatcher.init(settings.proc_address_callback); + std::vector embedder_instance_extensions; + std::vector embedder_device_extensions; + if (settings.embedder_data.has_value()) { + embedder_instance_extensions = settings.embedder_data->instance_extensions; + embedder_device_extensions = settings.embedder_data->device_extensions; + } auto caps = std::shared_ptr(new CapabilitiesVK( - settings.enable_validation, settings.fatal_missing_validations)); + settings.enable_validation, // + settings.fatal_missing_validations, // + /*use_embedder_extensions=*/settings.embedder_data.has_value(), // + embedder_instance_extensions, // + embedder_device_extensions // + )); if (!caps->IsValid()) { VALIDATION_LOG << "Could not determine device capabilities."; @@ -226,7 +237,7 @@ void ContextVK::Setup(Settings settings) { instance_info.setFlags(instance_flags); auto device_holder = std::make_shared(); - { + if (!settings.embedder_data.has_value()) { auto instance = vk::createInstanceUnique(instance_info); if (instance.result != vk::Result::eSuccess) { VALIDATION_LOG << "Could not create Vulkan instance: " @@ -234,6 +245,9 @@ void ContextVK::Setup(Settings settings) { return; } device_holder->instance = std::move(instance.value); + } else { + device_holder->instance.reset(settings.embedder_data->instance); + device_holder->owned = false; } dispatcher.init(device_holder->instance.get()); @@ -254,7 +268,7 @@ void ContextVK::Setup(Settings settings) { //---------------------------------------------------------------------------- /// Pick the physical device. /// - { + if (!settings.embedder_data.has_value()) { auto physical_device = PickPhysicalDevice(*caps, device_holder->instance.get()); if (!physical_device.has_value()) { @@ -262,6 +276,8 @@ void ContextVK::Setup(Settings settings) { return; } device_holder->physical_device = physical_device.value(); + } else { + device_holder->physical_device = settings.embedder_data->physical_device; } //---------------------------------------------------------------------------- @@ -320,7 +336,7 @@ void ContextVK::Setup(Settings settings) { device_info.setPEnabledExtensionNames(enabled_device_extensions_c); // Device layers are deprecated and ignored. - { + if (!settings.embedder_data.has_value()) { auto device_result = device_holder->physical_device.createDeviceUnique(device_info); if (device_result.result != vk::Result::eSuccess) { @@ -328,6 +344,8 @@ void ContextVK::Setup(Settings settings) { return; } device_holder->device = std::move(device_result.value); + } else { + device_holder->device.reset(settings.embedder_data->device); } if (!caps->SetPhysicalDevice(device_holder->physical_device, @@ -413,11 +431,18 @@ void ContextVK::Setup(Settings settings) { //---------------------------------------------------------------------------- /// Fetch the queues. /// - QueuesVK queues(device_holder->device.get(), // - graphics_queue.value(), // - compute_queue.value(), // - transfer_queue.value() // - ); + QueuesVK queues; + if (!settings.embedder_data.has_value()) { + queues = QueuesVK::FromQueueIndices(device_holder->device.get(), // + graphics_queue.value(), // + compute_queue.value(), // + transfer_queue.value() // + ); + } else { + queues = + QueuesVK::FromEmbedderQueue(settings.embedder_data->queue, + settings.embedder_data->queue_family_index); + } if (!queues.IsValid()) { VALIDATION_LOG << "Could not fetch device queues."; return; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h index 013e627dad..aa587bb003 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.h @@ -45,6 +45,17 @@ class ContextVK final : public Context, public BackendCast, public std::enable_shared_from_this { public: + /// Embedder Stuff + struct EmbedderData { + VkInstance instance; + VkPhysicalDevice physical_device; + VkDevice device; + uint32_t queue_family_index; + VkQueue queue; + std::vector instance_extensions; + std::vector device_extensions; + }; + struct Settings { PFN_vkGetInstanceProcAddr proc_address_callback = nullptr; std::vector> shader_libraries_data; @@ -55,6 +66,8 @@ class ContextVK final : public Context, /// If validations are requested but cannot be enabled, log a fatal error. bool fatal_missing_validations = false; + std::optional embedder_data; + Settings() = default; Settings(Settings&&) = default; @@ -207,9 +220,17 @@ class ContextVK final : public Context, return physical_device; } + ~DeviceHolderImpl() { + if (!owned) { + instance.release(); + device.release(); + } + } + vk::UniqueInstance instance; vk::PhysicalDevice physical_device; vk::UniqueDevice device; + bool owned = true; }; std::shared_ptr device_holder_; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc index 38cc53867d..84b242c648 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc @@ -9,6 +9,7 @@ #include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" +#include "vulkan/vulkan_core.h" namespace impeller { namespace testing { @@ -260,6 +261,48 @@ TEST(ContextVKTest, HasDefaultColorFormat) { ASSERT_NE(capabilites_vk->GetDefaultColorFormat(), PixelFormat::kUnknown); } +TEST(ContextVKTest, EmbedderOverridesUsesInstanceExtensions) { + ContextVK::EmbedderData data; + auto other_context = MockVulkanContextBuilder().Build(); + + data.instance = other_context->GetInstance(); + data.device = other_context->GetDevice(); + data.physical_device = other_context->GetPhysicalDevice(); + data.queue = VkQueue{}; + data.queue_family_index = 0; + // Missing surface extension. + data.instance_extensions = {}; + data.device_extensions = {"VK_KHR_swapchain"}; + + ScopedValidationDisable scoped; + auto context = MockVulkanContextBuilder().SetEmbedderData(data).Build(); + + EXPECT_EQ(context, nullptr); +} + +TEST(ContextVKTest, EmbedderOverrides) { + ContextVK::EmbedderData data; + auto other_context = MockVulkanContextBuilder().Build(); + + data.instance = other_context->GetInstance(); + data.device = other_context->GetDevice(); + data.physical_device = other_context->GetPhysicalDevice(); + data.queue = VkQueue{}; + data.queue_family_index = 0; + data.instance_extensions = {"VK_KHR_surface", + "VK_KHR_portability_enumeration"}; + data.device_extensions = {"VK_KHR_swapchain"}; + + auto context = MockVulkanContextBuilder().SetEmbedderData(data).Build(); + + EXPECT_TRUE(context->IsValid()); + EXPECT_EQ(context->GetInstance(), other_context->GetInstance()); + EXPECT_EQ(context->GetDevice(), other_context->GetDevice()); + EXPECT_EQ(context->GetPhysicalDevice(), other_context->GetPhysicalDevice()); + EXPECT_EQ(context->GetGraphicsQueue()->GetIndex().index, 0u); + EXPECT_EQ(context->GetGraphicsQueue()->GetIndex().family, 0u); +} + TEST(ContextVKTest, BatchSubmitCommandBuffersOnArm) { std::shared_ptr context = MockVulkanContextBuilder() diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h index 8ff6ac4a8f..4b1d57f390 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/formats_vk.h @@ -16,6 +16,18 @@ namespace impeller { +constexpr std::optional VkFormatToImpellerFormat( + vk::Format format) { + switch (format) { + case vk::Format::eR8G8B8A8Unorm: + return PixelFormat::kR8G8B8A8UNormInt; + case vk::Format::eB8G8R8A8Unorm: + return PixelFormat::kB8G8R8A8UNormInt; + default: + return std::nullopt; + } +} + constexpr vk::SampleCountFlagBits ToVKSampleCountFlagBits(SampleCount count) { switch (count) { case SampleCount::kCount1: diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.cc index c5cea22daf..a96e2b0882 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.cc @@ -4,6 +4,8 @@ #include "impeller/renderer/backend/vulkan/queue_vk.h" +#include + #include "impeller/renderer/backend/vulkan/context_vk.h" namespace impeller { @@ -45,19 +47,37 @@ void QueueVK::InsertDebugMarker(std::string_view label) const { QueuesVK::QueuesVK() = default; -QueuesVK::QueuesVK(const vk::Device& device, - QueueIndexVK graphics, - QueueIndexVK compute, - QueueIndexVK transfer) { +QueuesVK::QueuesVK(std::shared_ptr graphics_queue, + std::shared_ptr compute_queue, + std::shared_ptr transfer_queue) + : graphics_queue(std::move(graphics_queue)), + compute_queue(std::move(compute_queue)), + transfer_queue(std::move(transfer_queue)) {} + +// static +QueuesVK QueuesVK::FromEmbedderQueue(vk::Queue queue, + uint32_t queue_family_index) { + auto graphics_queue = std::make_shared( + QueueIndexVK{.family = queue_family_index, .index = 0}, queue); + + return QueuesVK(graphics_queue, graphics_queue, graphics_queue); +} + +// static +QueuesVK QueuesVK::FromQueueIndices(const vk::Device& device, + QueueIndexVK graphics, + QueueIndexVK compute, + QueueIndexVK transfer) { auto vk_graphics = device.getQueue(graphics.family, graphics.index); auto vk_compute = device.getQueue(compute.family, compute.index); auto vk_transfer = device.getQueue(transfer.family, transfer.index); // Always set up the graphics queue. - graphics_queue = std::make_shared(graphics, vk_graphics); + auto graphics_queue = std::make_shared(graphics, vk_graphics); ContextVK::SetDebugName(device, vk_graphics, "ImpellerGraphicsQ"); // Setup the compute queue if its different from the graphics queue. + std::shared_ptr compute_queue; if (compute == graphics) { compute_queue = graphics_queue; } else { @@ -67,6 +87,7 @@ QueuesVK::QueuesVK(const vk::Device& device, // Setup the transfer queue if its different from the graphics or compute // queues. + std::shared_ptr transfer_queue; if (transfer == graphics) { transfer_queue = graphics_queue; } else if (transfer == compute) { @@ -75,6 +96,9 @@ QueuesVK::QueuesVK(const vk::Device& device, transfer_queue = std::make_shared(transfer, vk_transfer); ContextVK::SetDebugName(device, vk_transfer, "ImpellerTransferQ"); } + + return QueuesVK(std::move(graphics_queue), std::move(compute_queue), + std::move(transfer_queue)); } bool QueuesVK::IsValid() const { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.h index eab025a34f..2fcf7fba09 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/queue_vk.h @@ -67,10 +67,17 @@ struct QueuesVK { QueuesVK(); - QueuesVK(const vk::Device& device, - QueueIndexVK graphics, - QueueIndexVK compute, - QueueIndexVK transfer); + QueuesVK(std::shared_ptr graphics_queue, + std::shared_ptr compute_queue, + std::shared_ptr transfer_queue); + + static QueuesVK FromEmbedderQueue(vk::Queue queue, + uint32_t queue_family_index); + + static QueuesVK FromQueueIndices(const vk::Device& device, + QueueIndexVK graphics, + QueueIndexVK compute, + QueueIndexVK transfer); bool IsValid() const; }; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc index ca896f66aa..3b6d77150d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.cc @@ -82,13 +82,17 @@ std::unique_ptr SurfaceContextVK::AcquireNextSurface() { if (!surface) { return nullptr; } + MarkFrameEnd(); + return surface; +} + +void SurfaceContextVK::MarkFrameEnd() { if (auto pipeline_library = parent_->GetPipelineLibrary()) { impeller::PipelineLibraryVK::Cast(*pipeline_library) .DidAcquireSurfaceFrame(); } parent_->DisposeThreadLocalCachedResources(); parent_->GetResourceAllocator()->DebugTraceMemoryStatistics(); - return surface; } void SurfaceContextVK::UpdateSurfaceSize(const ISize& size) const { diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h index 444eb91bf1..22663f0fb4 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/surface_context_vk.h @@ -76,6 +76,12 @@ class SurfaceContextVK : public Context, std::unique_ptr AcquireNextSurface(); + /// @brief Performs frame incrementing processes like AcquireNextSurface but + /// without the surface. + /// + /// Used by the embedder.h implementations. + void MarkFrameEnd(); + /// @brief Mark the current swapchain configuration as dirty, forcing it to be /// recreated on the next frame. void UpdateSurfaceSize(const ISize& size) const; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc index 93a6ba452f..447b0665b5 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.cc @@ -928,6 +928,7 @@ std::shared_ptr MockVulkanContextBuilder::Build() { g_instance_layers = instance_layers_; g_format_properties_callback = format_properties_callback_; g_physical_device_properties_callback = physical_properties_callback_; + settings.embedder_data = embedder_data_; std::shared_ptr result = ContextVK::Create(std::move(settings)); return result; } diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.h b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.h index adffe42202..25da5720c3 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/test/mock_vulkan.h @@ -108,10 +108,17 @@ class MockVulkanContextBuilder { return *this; } + MockVulkanContextBuilder SetEmbedderData( + const ContextVK::EmbedderData& embedder_data) { + embedder_data_ = embedder_data; + return *this; + } + private: std::function settings_callback_; std::vector instance_extensions_; std::vector instance_layers_; + std::optional embedder_data_; std::function diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc index 28668b6d3f..7d432ef32d 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/texture_vk.cc @@ -4,6 +4,7 @@ #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/core/texture_descriptor.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/sampler_vk.h" diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan.cc index c6f5c62ca4..9207bfa506 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan.cc @@ -68,18 +68,14 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( return nullptr; } - SurfaceFrame::EncodeCallback encode_callback = - [image = image, delegate = delegate_](const SurfaceFrame&, - DlCanvas* canvas) -> bool { + SurfaceFrame::EncodeCallback encode_callback = [](const SurfaceFrame&, + DlCanvas* canvas) -> bool { if (canvas == nullptr) { FML_DLOG(ERROR) << "Canvas not available."; return false; } - canvas->Flush(); - - return delegate->PresentImage(reinterpret_cast(image.image), - static_cast(image.format)); + return true; }; SurfaceFrame::SubmitCallback submit_callback = diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc index aea1c9994d..c0a3fb7344 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -4,17 +4,52 @@ #include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h" +#include + #include "flow/surface_frame.h" #include "flutter/fml/make_copyable.h" +#include "fml/trace_event.h" +#include "impeller/core/formats.h" +#include "impeller/core/texture_descriptor.h" #include "impeller/display_list/dl_dispatcher.h" +#include "impeller/renderer/backend/vulkan/command_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/surface_context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain/surface_vk.h" +#include "impeller/renderer/render_target.h" #include "impeller/renderer/surface.h" #include "impeller/typographer/backends/skia/typographer_context_skia.h" namespace flutter { +class WrappedTextureSourceVK : public impeller::TextureSourceVK { + public: + explicit WrappedTextureSourceVK(impeller::vk::Image image, + impeller::vk::ImageView image_view, + impeller::TextureDescriptor desc) + : TextureSourceVK(desc), image_(image), image_view_(image_view) {} + + ~WrappedTextureSourceVK() {} + + private: + impeller::vk::Image GetImage() const override { return image_; } + + impeller::vk::ImageView GetImageView() const override { return image_view_; } + + impeller::vk::ImageView GetRenderTargetView() const override { + return image_view_; + } + + bool IsSwapchainImage() const override { return true; } + + impeller::vk::Image image_; + impeller::vk::ImageView image_view_; +}; + GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller( - std::shared_ptr context) { + GPUSurfaceVulkanDelegate* delegate, + std::shared_ptr context) + : delegate_(delegate) { if (!context || !context->IsValid()) { return; } @@ -27,7 +62,7 @@ GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller( impeller_context_ = std::move(context); aiks_context_ = std::move(aiks_context); - is_valid_ = true; + is_valid_ = !!aiks_context_; } // |Surface| @@ -51,53 +86,193 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( return nullptr; } - auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_); - std::unique_ptr surface = context_vk.AcquireNextSurface(); + if (delegate_ == nullptr) { + auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_); + std::unique_ptr surface = + context_vk.AcquireNextSurface(); - if (!surface) { - FML_LOG(ERROR) << "No surface available."; - return nullptr; - } - - auto cull_rect = surface->GetRenderTarget().GetRenderTargetSize(); - - impeller::RenderTarget render_target = surface->GetRenderTarget(); - - SurfaceFrame::EncodeCallback encode_callback = [aiks_context = - aiks_context_, // - render_target, - cull_rect // - ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { - if (!aiks_context) { - return false; + if (!surface) { + FML_LOG(ERROR) << "No surface available."; + return nullptr; } - auto display_list = surface_frame.BuildDisplayList(); - if (!display_list) { - FML_LOG(ERROR) << "Could not build display list for surface frame."; - return false; - } + impeller::RenderTarget render_target = surface->GetRenderTarget(); + auto cull_rect = render_target.GetRenderTargetSize(); - SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // - render_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + SurfaceFrame::EncodeCallback encode_callback = [aiks_context = + aiks_context_, // + render_target, + cull_rect // + ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { + if (!aiks_context) { + return false; + } + + auto display_list = surface_frame.BuildDisplayList(); + if (!display_list) { + FML_LOG(ERROR) << "Could not build display list for surface frame."; + return false; + } + + SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); + return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // + ); + }; + + return std::make_unique( + nullptr, // surface + SurfaceFrame::FramebufferInfo{}, // framebuffer info + encode_callback, // encode callback + fml::MakeCopyable([surface = std::move(surface)](const SurfaceFrame&) { + return surface->Present(); + }), // submit callback + size, // frame size + nullptr, // context result + true // display list fallback ); - }; + } else { + FlutterVulkanImage flutter_image = delegate_->AcquireImage(size); + if (!flutter_image.image) { + FML_LOG(ERROR) << "Invalid VkImage given by the embedder."; + return nullptr; + } + impeller::vk::Format vk_format = + static_cast(flutter_image.format); + std::optional format = + impeller::VkFormatToImpellerFormat(vk_format); + if (!format.has_value()) { + FML_LOG(ERROR) << "Unsupported pixel format: " + << impeller::vk::to_string(vk_format); + return nullptr; + } - return std::make_unique( - nullptr, // surface - SurfaceFrame::FramebufferInfo{}, // framebuffer info - encode_callback, // encode callback - fml::MakeCopyable([surface = std::move(surface)](const SurfaceFrame&) { - return surface->Present(); - }), // submit callback - size, // frame size - nullptr, // context result - true // display list fallback - ); + impeller::vk::Image vk_image = + impeller::vk::Image(reinterpret_cast(flutter_image.image)); + + impeller::TextureDescriptor desc; + desc.format = format.value(); + desc.size = impeller::ISize{size.width(), size.height()}; + desc.storage_mode = impeller::StorageMode::kDevicePrivate; + desc.mip_count = 1; + desc.compression_type = impeller::CompressionType::kLossless; + desc.usage = impeller::TextureUsage::kRenderTarget; + + impeller::ContextVK& context_vk = + impeller::ContextVK::Cast(*impeller_context_); + + impeller::vk::ImageViewCreateInfo view_info = {}; + view_info.viewType = impeller::vk::ImageViewType::e2D; + view_info.format = ToVKImageFormat(desc.format); + view_info.subresourceRange.aspectMask = + impeller::vk::ImageAspectFlagBits::eColor; + view_info.subresourceRange.baseMipLevel = 0u; + view_info.subresourceRange.baseArrayLayer = 0u; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.layerCount = 1; + view_info.image = vk_image; + + auto [result, image_view] = + context_vk.GetDevice().createImageView(view_info); + if (result != impeller::vk::Result::eSuccess) { + FML_LOG(ERROR) << "Failed to create image view for provided image: " + << impeller::vk::to_string(result); + return nullptr; + } + + if (transients_ == nullptr) { + transients_ = std::make_shared( + impeller_context_, desc, + /*enable_msaa=*/true); + } + + auto wrapped_onscreen = + std::make_shared(vk_image, image_view, desc); + auto surface = impeller::SurfaceVK::WrapSwapchainImage( + transients_, wrapped_onscreen, [&]() -> bool { return true; }); + impeller::RenderTarget render_target = surface->GetRenderTarget(); + auto cull_rect = render_target.GetRenderTargetSize(); + + SurfaceFrame::EncodeCallback encode_callback = [aiks_context = + aiks_context_, // + render_target, + cull_rect // + ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { + if (!aiks_context) { + return false; + } + + auto display_list = surface_frame.BuildDisplayList(); + if (!display_list) { + FML_LOG(ERROR) << "Could not build display list for surface frame."; + return false; + } + + SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); + return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/true // + ); + }; + + SurfaceFrame::SubmitCallback submit_callback = + [image = flutter_image, delegate = delegate_, + impeller_context = impeller_context_, + wrapped_onscreen](const SurfaceFrame&) -> bool { + TRACE_EVENT0("flutter", "GPUSurfaceVulkan::PresentImage"); + + { + const auto& context = impeller::ContextVK::Cast(*impeller_context); + + //---------------------------------------------------------------------------- + /// Transition the image to color-attachment-optimal. + /// + auto cmd_buffer = context.CreateCommandBuffer(); + + auto vk_final_cmd_buffer = + impeller::CommandBufferVK::Cast(*cmd_buffer).GetCommandBuffer(); + { + impeller::BarrierVK barrier; + barrier.new_layout = + impeller::vk::ImageLayout::eColorAttachmentOptimal; + barrier.cmd_buffer = vk_final_cmd_buffer; + barrier.src_access = + impeller::vk::AccessFlagBits::eColorAttachmentWrite; + barrier.src_stage = + impeller::vk::PipelineStageFlagBits::eColorAttachmentOutput; + barrier.dst_access = {}; + barrier.dst_stage = + impeller::vk::PipelineStageFlagBits::eBottomOfPipe; + + if (!wrapped_onscreen->SetLayout(barrier).ok()) { + return false; + } + } + if (!context.GetCommandQueue()->Submit({cmd_buffer}).ok()) { + return false; + } + } + + return delegate->PresentImage(reinterpret_cast(image.image), + static_cast(image.format)); + }; + + SurfaceFrame::FramebufferInfo framebuffer_info{.supports_readback = true}; + + return std::make_unique(nullptr, // surface + framebuffer_info, // framebuffer info + encode_callback, // encode callback + submit_callback, + size, // frame size + nullptr, // context result + true // display list fallback + ); + } } // |Surface| diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.h b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.h index 41d296a58c..602761db0c 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.h +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.h @@ -12,12 +12,14 @@ #include "flutter/impeller/display_list/aiks_context.h" #include "flutter/impeller/renderer/context.h" #include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "impeller/renderer/backend/vulkan/swapchain/swapchain_transients_vk.h" namespace flutter { class GPUSurfaceVulkanImpeller final : public Surface { public: - explicit GPUSurfaceVulkanImpeller(std::shared_ptr context); + explicit GPUSurfaceVulkanImpeller(GPUSurfaceVulkanDelegate* delegate, + std::shared_ptr context); // |Surface| ~GPUSurfaceVulkanImpeller() override; @@ -26,8 +28,10 @@ class GPUSurfaceVulkanImpeller final : public Surface { bool IsValid() override; private: + GPUSurfaceVulkanDelegate* delegate_; std::shared_ptr impeller_context_; std::shared_ptr aiks_context_; + std::shared_ptr transients_; bool is_valid_ = false; // |Surface| diff --git a/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc b/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc index 8dc12a78ac..69d9575128 100644 --- a/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc +++ b/engine/src/flutter/shell/platform/android/android_surface_vk_impeller.cc @@ -25,7 +25,7 @@ AndroidSurfaceVKImpeller::AndroidSurfaceVKImpeller( impeller::ContextVK::Cast(*android_context->GetImpellerContext()); surface_context_vk_ = context_vk.CreateSurfaceContext(); eager_gpu_surface_ = - std::make_unique(surface_context_vk_); + std::make_unique(nullptr, surface_context_vk_); } AndroidSurfaceVKImpeller::~AndroidSurfaceVKImpeller() = default; @@ -57,7 +57,7 @@ std::unique_ptr AndroidSurfaceVKImpeller::CreateGPUSurface( } std::unique_ptr gpu_surface = - std::make_unique(surface_context_vk_); + std::make_unique(nullptr, surface_context_vk_); if (!gpu_surface->IsValid()) { return nullptr; diff --git a/engine/src/flutter/shell/platform/embedder/BUILD.gn b/engine/src/flutter/shell/platform/embedder/BUILD.gn index 38c7e2db98..17717457cf 100644 --- a/engine/src/flutter/shell/platform/embedder/BUILD.gn +++ b/engine/src/flutter/shell/platform/embedder/BUILD.gn @@ -171,6 +171,13 @@ template("embedder_source_set") { "embedder_surface_vulkan.h", ] + if (impeller_supports_rendering) { + sources += [ + "embedder_surface_vulkan_impeller.cc", + "embedder_surface_vulkan_impeller.h", + ] + } + deps += [ "//flutter/flutter_vma:flutter_skia_vma", "//flutter/vulkan/procs", diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index 2adf56c592..08adfc6c4a 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -615,7 +615,8 @@ InferVulkanPlatformViewCreationCallback( const flutter::PlatformViewEmbedder::PlatformDispatchTable& platform_dispatch_table, std::unique_ptr - external_view_embedder) { + external_view_embedder, + bool enable_impeller) { if (config->type != kVulkan) { return nullptr; } @@ -655,6 +656,82 @@ InferVulkanPlatformViewCreationCallback( auto proc_addr = vulkan_get_instance_proc_address(vk_instance, "vkGetInstanceProcAddr"); + std::shared_ptr view_embedder = + std::move(external_view_embedder); + +#if IMPELLER_SUPPORTS_RENDERING + if (enable_impeller) { + flutter::EmbedderSurfaceVulkanImpeller::VulkanDispatchTable + vulkan_dispatch_table = { + .get_instance_proc_address = + reinterpret_cast(proc_addr), + .get_next_image = vulkan_get_next_image, + .present_image = vulkan_present_image_callback, + }; + + std::unique_ptr embedder_surface = + std::make_unique( + config->vulkan.version, vk_instance, + config->vulkan.enabled_instance_extension_count, + config->vulkan.enabled_instance_extensions, + config->vulkan.enabled_device_extension_count, + config->vulkan.enabled_device_extensions, + static_cast(config->vulkan.physical_device), + static_cast(config->vulkan.device), + config->vulkan.queue_family_index, + static_cast(config->vulkan.queue), vulkan_dispatch_table, + view_embedder); + + return fml::MakeCopyable( + [embedder_surface = std::move(embedder_surface), + platform_dispatch_table, + external_view_embedder = + std::move(view_embedder)](flutter::Shell& shell) mutable { + return std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + std::move(embedder_surface), // embedder surface + platform_dispatch_table, // platform dispatch table + std::move(external_view_embedder) // external view embedder + ); + }); + } else { + flutter::EmbedderSurfaceVulkan::VulkanDispatchTable vulkan_dispatch_table = + { + .get_instance_proc_address = + reinterpret_cast(proc_addr), + .get_next_image = vulkan_get_next_image, + .present_image = vulkan_present_image_callback, + }; + + std::unique_ptr embedder_surface = + std::make_unique( + config->vulkan.version, vk_instance, + config->vulkan.enabled_instance_extension_count, + config->vulkan.enabled_instance_extensions, + config->vulkan.enabled_device_extension_count, + config->vulkan.enabled_device_extensions, + static_cast(config->vulkan.physical_device), + static_cast(config->vulkan.device), + config->vulkan.queue_family_index, + static_cast(config->vulkan.queue), vulkan_dispatch_table, + view_embedder); + + return fml::MakeCopyable( + [embedder_surface = std::move(embedder_surface), + platform_dispatch_table, + external_view_embedder = + std::move(view_embedder)](flutter::Shell& shell) mutable { + return std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + std::move(embedder_surface), // embedder surface + platform_dispatch_table, // platform dispatch table + std::move(external_view_embedder) // external view embedder + ); + }); + } +#else flutter::EmbedderSurfaceVulkan::VulkanDispatchTable vulkan_dispatch_table = { .get_instance_proc_address = reinterpret_cast(proc_addr), @@ -662,9 +739,6 @@ InferVulkanPlatformViewCreationCallback( .present_image = vulkan_present_image_callback, }; - std::shared_ptr view_embedder = - std::move(external_view_embedder); - std::unique_ptr embedder_surface = std::make_unique( config->vulkan.version, vk_instance, @@ -690,6 +764,7 @@ InferVulkanPlatformViewCreationCallback( std::move(external_view_embedder) // external view embedder ); }); +#endif // // IMPELLER_SUPPORTS_RENDERING #else // SHELL_ENABLE_VULKAN FML_LOG(ERROR) << "This Flutter Engine does not support Vulkan rendering."; return nullptr; @@ -762,7 +837,7 @@ InferPlatformViewCreationCallback( case kVulkan: return InferVulkanPlatformViewCreationCallback( config, user_data, platform_dispatch_table, - std::move(external_view_embedder)); + std::move(external_view_embedder), enable_impeller); default: return nullptr; } @@ -1434,11 +1509,16 @@ CreateEmbedderRenderTarget( break; } case kFlutterBackingStoreTypeVulkan: { - auto skia_surface = - MakeSkSurfaceFromBackingStore(context, config, &backing_store.vulkan); - render_target = MakeRenderTargetFromSkSurface( - backing_store, std::move(skia_surface), collect_callback.Release()); - break; + if (enable_impeller) { + FML_LOG(ERROR) << "Unimplemented"; + break; + } else { + auto skia_surface = MakeSkSurfaceFromBackingStore( + context, config, &backing_store.vulkan); + render_target = MakeRenderTargetFromSkSurface( + backing_store, std::move(skia_surface), collect_callback.Release()); + break; + } } }; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc new file mode 100644 index 0000000000..a590898843 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.cc @@ -0,0 +1,124 @@ +// Copyright 2013 The Flutter 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/shell/platform/embedder/embedder_surface_vulkan_impeller.h" + +#include + +#include "flutter/impeller/entity/vk/entity_shaders_vk.h" +#include "flutter/impeller/entity/vk/framebuffer_blend_shaders_vk.h" +#include "flutter/impeller/entity/vk/modern_shaders_vk.h" +#include "flutter/shell/gpu/gpu_surface_vulkan.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "include/gpu/ganesh/GrDirectContext.h" +#include "shell/gpu/gpu_surface_vulkan_impeller.h" + +namespace flutter { + +EmbedderSurfaceVulkanImpeller::EmbedderSurfaceVulkanImpeller( + uint32_t version, + VkInstance instance, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + VkPhysicalDevice physical_device, + VkDevice device, + uint32_t queue_family_index, + VkQueue queue, + const VulkanDispatchTable& vulkan_dispatch_table, + std::shared_ptr external_view_embedder) + : vk_(fml::MakeRefCounted( + vulkan_dispatch_table.get_instance_proc_address)), + vulkan_dispatch_table_(vulkan_dispatch_table), + external_view_embedder_(std::move(external_view_embedder)) { + // Make sure all required members of the dispatch table are checked. + if (!vulkan_dispatch_table_.get_instance_proc_address || + !vulkan_dispatch_table_.get_next_image || + !vulkan_dispatch_table_.present_image) { + return; + } + + std::vector> shader_mappings = { + std::make_shared(impeller_entity_shaders_vk_data, + impeller_entity_shaders_vk_length), + std::make_shared(impeller_modern_shaders_vk_data, + impeller_modern_shaders_vk_length), + std::make_shared( + impeller_framebuffer_blend_shaders_vk_data, + impeller_framebuffer_blend_shaders_vk_length), + }; + impeller::ContextVK::Settings settings; + settings.shader_libraries_data = shader_mappings; + settings.proc_address_callback = + vulkan_dispatch_table.get_instance_proc_address; + + impeller::ContextVK::EmbedderData data; + data.instance = instance; + data.physical_device = physical_device; + data.device = device; + data.queue = queue; + data.queue_family_index = queue_family_index; + data.instance_extensions.reserve(instance_extension_count); + for (auto i = 0u; i < instance_extension_count; i++) { + data.instance_extensions.push_back(std::string{instance_extensions[i]}); + } + data.device_extensions.reserve(device_extension_count); + for (auto i = 0u; i < device_extension_count; i++) { + data.device_extensions.push_back(std::string{device_extensions[i]}); + } + settings.embedder_data = data; + + context_ = impeller::ContextVK::Create(std::move(settings)); + if (!context_) { + FML_LOG(ERROR) << "Failed to initialize Vulkan Context."; + return; + } + + FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (Vulkan)."; + + valid_ = true; +} + +EmbedderSurfaceVulkanImpeller::~EmbedderSurfaceVulkanImpeller() {} + +std::shared_ptr +EmbedderSurfaceVulkanImpeller::CreateImpellerContext() const { + return context_; +} + +// |GPUSurfaceVulkanDelegate| +const vulkan::VulkanProcTable& EmbedderSurfaceVulkanImpeller::vk() { + return *vk_; +} + +// |GPUSurfaceVulkanDelegate| +FlutterVulkanImage EmbedderSurfaceVulkanImpeller::AcquireImage( + const SkISize& size) { + return vulkan_dispatch_table_.get_next_image(size); +} + +// |GPUSurfaceVulkanDelegate| +bool EmbedderSurfaceVulkanImpeller::PresentImage(VkImage image, + VkFormat format) { + return vulkan_dispatch_table_.present_image(image, format); +} + +// |EmbedderSurface| +bool EmbedderSurfaceVulkanImpeller::IsValid() const { + return valid_; +} + +// |EmbedderSurface| +std::unique_ptr EmbedderSurfaceVulkanImpeller::CreateGPUSurface() { + return std::make_unique(this, context_); +} + +// |EmbedderSurface| +sk_sp EmbedderSurfaceVulkanImpeller::CreateResourceContext() + const { + return nullptr; +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h new file mode 100644 index 0000000000..5d1463aa83 --- /dev/null +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter 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_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_VULKAN_IMPELLER_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_VULKAN_IMPELLER_H_ + +#include "flutter/shell/common/context_options.h" +#include "flutter/shell/gpu/gpu_surface_vulkan.h" +#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h" +#include "flutter/shell/platform/embedder/embedder_surface.h" +#include "flutter/vulkan/procs/vulkan_proc_table.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" + +namespace flutter { + +class EmbedderSurfaceVulkanImpeller final : public EmbedderSurface, + public GPUSurfaceVulkanDelegate { + public: + struct VulkanDispatchTable { + PFN_vkGetInstanceProcAddr get_instance_proc_address; // required + std::function + get_next_image; // required + std::function + present_image; // required + }; + + EmbedderSurfaceVulkanImpeller( + uint32_t version, + VkInstance instance, + size_t instance_extension_count, + const char** instance_extensions, + size_t device_extension_count, + const char** device_extensions, + VkPhysicalDevice physical_device, + VkDevice device, + uint32_t queue_family_index, + VkQueue queue, + const VulkanDispatchTable& vulkan_dispatch_table, + std::shared_ptr external_view_embedder); + + ~EmbedderSurfaceVulkanImpeller() override; + + // |GPUSurfaceVulkanDelegate| + const vulkan::VulkanProcTable& vk() override; + + // |GPUSurfaceVulkanDelegate| + FlutterVulkanImage AcquireImage(const SkISize& size) override; + + // |GPUSurfaceVulkanDelegate| + bool PresentImage(VkImage image, VkFormat format) override; + + // |GPUSurfaceVulkanDelegate| + std::shared_ptr CreateImpellerContext() const override; + + private: + bool valid_ = false; + fml::RefPtr vk_; + VulkanDispatchTable vulkan_dispatch_table_; + std::shared_ptr external_view_embedder_; + std::shared_ptr context_; + + // |EmbedderSurface| + bool IsValid() const override; + + // |EmbedderSurface| + std::unique_ptr CreateGPUSurface() override; + + // |EmbedderSurface| + sk_sp CreateResourceContext() const override; + + EmbedderSurfaceVulkanImpeller(const EmbedderSurfaceVulkanImpeller&) = delete; + EmbedderSurfaceVulkanImpeller& operator=( + const EmbedderSurfaceVulkanImpeller&) = delete; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_VULKAN_IMPELLER_H_ diff --git a/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h b/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h index f443058940..090e6920df 100644 --- a/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h +++ b/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h @@ -26,6 +26,9 @@ #ifdef SHELL_ENABLE_VULKAN #include "flutter/shell/platform/embedder/embedder_surface_vulkan.h" +#ifdef IMPELLER_SUPPORTS_RENDERING +#include "flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h" +#endif // IMPELLER_SUPPORTS_RENDERING #endif namespace flutter { diff --git a/engine/src/flutter/shell/testing/tester_main.cc b/engine/src/flutter/shell/testing/tester_main.cc index 1d7358f0d5..75516fbcb1 100644 --- a/engine/src/flutter/shell/testing/tester_main.cc +++ b/engine/src/flutter/shell/testing/tester_main.cc @@ -211,7 +211,7 @@ class TesterPlatformView : public PlatformView, if (delegate_.OnPlatformViewGetSettings().enable_impeller) { FML_DCHECK(impeller_context_holder_.context); auto surface = std::make_unique( - impeller_context_holder_.surface_context); + nullptr, impeller_context_holder_.surface_context); FML_DCHECK(surface->IsValid()); return surface; }