[Impeller] add basic Impeller+Vulkan support to embedder API. (flutter/engine#55490)

Works on GLFW example app with no validation errors.
This commit is contained in:
Jonah Williams 2024-10-28 13:20:17 -07:00 committed by GitHub
parent 2c6a76e3d1
commit 23641d582a
24 changed files with 777 additions and 114 deletions

View File

@ -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_software.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc + ../../../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.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.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_task_runner.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/embedder/embedder_task_runner.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc + ../../../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_software.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc 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.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.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.h FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.h
FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc

View File

@ -16,27 +16,39 @@ namespace impeller {
static constexpr const char* kInstanceLayer = "ImpellerInstance"; static constexpr const char* kInstanceLayer = "ImpellerInstance";
CapabilitiesVK::CapabilitiesVK(bool enable_validations, CapabilitiesVK::CapabilitiesVK(bool enable_validations,
bool fatal_missing_validations) { bool fatal_missing_validations,
auto extensions = vk::enumerateInstanceExtensionProperties(); bool use_embedder_extensions,
auto layers = vk::enumerateInstanceLayerProperties(); std::vector<std::string> instance_extensions,
std::vector<std::string> 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 || if (extensions.result != vk::Result::eSuccess ||
layers.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) {
return; 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<std::set<std::string>> GetSupportedDeviceExtensions(
std::optional<std::vector<std::string>> std::optional<std::vector<std::string>>
CapabilitiesVK::GetEnabledDeviceExtensions( CapabilitiesVK::GetEnabledDeviceExtensions(
const vk::PhysicalDevice& physical_device) const { const vk::PhysicalDevice& physical_device) const {
auto exts = GetSupportedDeviceExtensions(physical_device); std::set<std::string> exts;
if (!exts.has_value()) { if (!use_embedder_extensions_) {
return std::nullopt; 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<std::string> enabled; std::vector<std::string> enabled;
auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) { auto for_each_common_extension = [&](RequiredCommonDeviceExtensionVK ext) {
auto name = GetExtensionName(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; VALIDATION_LOG << "Device does not support required extension: " << name;
return false; return false;
} }
@ -260,7 +280,7 @@ CapabilitiesVK::GetEnabledDeviceExtensions(
auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) { auto for_each_android_extension = [&](RequiredAndroidDeviceExtensionVK ext) {
#ifdef FML_OS_ANDROID #ifdef FML_OS_ANDROID
auto name = GetExtensionName(ext); 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: " VALIDATION_LOG << "Device does not support required Android extension: "
<< name; << name;
return false; return false;
@ -272,7 +292,7 @@ CapabilitiesVK::GetEnabledDeviceExtensions(
auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) { auto for_each_optional_extension = [&](OptionalDeviceExtensionVK ext) {
auto name = GetExtensionName(ext); auto name = GetExtensionName(ext);
if (exts->find(name) != exts->end()) { if (exts.find(name) != exts.end()) {
enabled.push_back(name); enabled.push_back(name);
} }
return true; return true;
@ -524,27 +544,36 @@ bool CapabilitiesVK::SetPhysicalDevice(
required_common_device_extensions_.clear(); required_common_device_extensions_.clear();
required_android_device_extensions_.clear(); required_android_device_extensions_.clear();
optional_device_extensions_.clear(); optional_device_extensions_.clear();
auto exts = GetSupportedDeviceExtensions(device);
if (!exts.has_value()) { std::set<std::string> exts;
return false; 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<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool { IterateExtensions<RequiredCommonDeviceExtensionVK>([&](auto ext) -> bool {
auto ext_name = GetExtensionName(ext); 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); required_common_device_extensions_.insert(ext);
} }
return true; return true;
}); });
IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool { IterateExtensions<RequiredAndroidDeviceExtensionVK>([&](auto ext) -> bool {
auto ext_name = GetExtensionName(ext); 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); required_android_device_extensions_.insert(ext);
} }
return true; return true;
}); });
IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool { IterateExtensions<OptionalDeviceExtensionVK>([&](auto ext) -> bool {
auto ext_name = GetExtensionName(ext); auto ext_name = GetExtensionName(ext);
if (exts->find(ext_name) != exts->end()) { if (exts.find(ext_name) != exts.end()) {
optional_device_extensions_.insert(ext); optional_device_extensions_.insert(ext);
} }
return true; return true;

View File

@ -170,7 +170,10 @@ class CapabilitiesVK final : public Capabilities,
public BackendCast<CapabilitiesVK, Capabilities> { public BackendCast<CapabilitiesVK, Capabilities> {
public: public:
explicit CapabilitiesVK(bool enable_validations, explicit CapabilitiesVK(bool enable_validations,
bool fatal_missing_validations = false); bool fatal_missing_validations = false,
bool use_embedder_extensions = false,
std::vector<std::string> instance_extensions = {},
std::vector<std::string> device_extensions = {});
~CapabilitiesVK(); ~CapabilitiesVK();
@ -293,6 +296,12 @@ class CapabilitiesVK final : public Capabilities,
ISize max_render_pass_attachment_size_ = ISize{0, 0}; ISize max_render_pass_attachment_size_ = ISize{0, 0};
bool is_valid_ = false; bool is_valid_ = false;
// The embedder.h API is responsible for providing the instance and device
// extensions.
bool use_embedder_extensions_ = false;
std::vector<std::string> embedder_instance_extensions_;
std::vector<std::string> embedder_device_extensions_;
bool HasExtension(const std::string& ext) const; bool HasExtension(const std::string& ext) const;
bool HasLayer(const std::string& layer) const; bool HasLayer(const std::string& layer) const;

View File

@ -160,8 +160,19 @@ void ContextVK::Setup(Settings settings) {
auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER;
dispatcher.init(settings.proc_address_callback); dispatcher.init(settings.proc_address_callback);
std::vector<std::string> embedder_instance_extensions;
std::vector<std::string> 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<CapabilitiesVK>(new CapabilitiesVK( auto caps = std::shared_ptr<CapabilitiesVK>(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()) { if (!caps->IsValid()) {
VALIDATION_LOG << "Could not determine device capabilities."; VALIDATION_LOG << "Could not determine device capabilities.";
@ -226,7 +237,7 @@ void ContextVK::Setup(Settings settings) {
instance_info.setFlags(instance_flags); instance_info.setFlags(instance_flags);
auto device_holder = std::make_shared<DeviceHolderImpl>(); auto device_holder = std::make_shared<DeviceHolderImpl>();
{ if (!settings.embedder_data.has_value()) {
auto instance = vk::createInstanceUnique(instance_info); auto instance = vk::createInstanceUnique(instance_info);
if (instance.result != vk::Result::eSuccess) { if (instance.result != vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create Vulkan instance: " VALIDATION_LOG << "Could not create Vulkan instance: "
@ -234,6 +245,9 @@ void ContextVK::Setup(Settings settings) {
return; return;
} }
device_holder->instance = std::move(instance.value); 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()); dispatcher.init(device_holder->instance.get());
@ -254,7 +268,7 @@ void ContextVK::Setup(Settings settings) {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
/// Pick the physical device. /// Pick the physical device.
/// ///
{ if (!settings.embedder_data.has_value()) {
auto physical_device = auto physical_device =
PickPhysicalDevice(*caps, device_holder->instance.get()); PickPhysicalDevice(*caps, device_holder->instance.get());
if (!physical_device.has_value()) { if (!physical_device.has_value()) {
@ -262,6 +276,8 @@ void ContextVK::Setup(Settings settings) {
return; return;
} }
device_holder->physical_device = physical_device.value(); 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_info.setPEnabledExtensionNames(enabled_device_extensions_c);
// Device layers are deprecated and ignored. // Device layers are deprecated and ignored.
{ if (!settings.embedder_data.has_value()) {
auto device_result = auto device_result =
device_holder->physical_device.createDeviceUnique(device_info); device_holder->physical_device.createDeviceUnique(device_info);
if (device_result.result != vk::Result::eSuccess) { if (device_result.result != vk::Result::eSuccess) {
@ -328,6 +344,8 @@ void ContextVK::Setup(Settings settings) {
return; return;
} }
device_holder->device = std::move(device_result.value); device_holder->device = std::move(device_result.value);
} else {
device_holder->device.reset(settings.embedder_data->device);
} }
if (!caps->SetPhysicalDevice(device_holder->physical_device, if (!caps->SetPhysicalDevice(device_holder->physical_device,
@ -413,11 +431,18 @@ void ContextVK::Setup(Settings settings) {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
/// Fetch the queues. /// Fetch the queues.
/// ///
QueuesVK queues(device_holder->device.get(), // QueuesVK queues;
graphics_queue.value(), // if (!settings.embedder_data.has_value()) {
compute_queue.value(), // queues = QueuesVK::FromQueueIndices(device_holder->device.get(), //
transfer_queue.value() // 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()) { if (!queues.IsValid()) {
VALIDATION_LOG << "Could not fetch device queues."; VALIDATION_LOG << "Could not fetch device queues.";
return; return;

View File

@ -45,6 +45,17 @@ class ContextVK final : public Context,
public BackendCast<ContextVK, Context>, public BackendCast<ContextVK, Context>,
public std::enable_shared_from_this<ContextVK> { public std::enable_shared_from_this<ContextVK> {
public: public:
/// Embedder Stuff
struct EmbedderData {
VkInstance instance;
VkPhysicalDevice physical_device;
VkDevice device;
uint32_t queue_family_index;
VkQueue queue;
std::vector<std::string> instance_extensions;
std::vector<std::string> device_extensions;
};
struct Settings { struct Settings {
PFN_vkGetInstanceProcAddr proc_address_callback = nullptr; PFN_vkGetInstanceProcAddr proc_address_callback = nullptr;
std::vector<std::shared_ptr<fml::Mapping>> shader_libraries_data; std::vector<std::shared_ptr<fml::Mapping>> shader_libraries_data;
@ -55,6 +66,8 @@ class ContextVK final : public Context,
/// If validations are requested but cannot be enabled, log a fatal error. /// If validations are requested but cannot be enabled, log a fatal error.
bool fatal_missing_validations = false; bool fatal_missing_validations = false;
std::optional<EmbedderData> embedder_data;
Settings() = default; Settings() = default;
Settings(Settings&&) = default; Settings(Settings&&) = default;
@ -207,9 +220,17 @@ class ContextVK final : public Context,
return physical_device; return physical_device;
} }
~DeviceHolderImpl() {
if (!owned) {
instance.release();
device.release();
}
}
vk::UniqueInstance instance; vk::UniqueInstance instance;
vk::PhysicalDevice physical_device; vk::PhysicalDevice physical_device;
vk::UniqueDevice device; vk::UniqueDevice device;
bool owned = true;
}; };
std::shared_ptr<DeviceHolderImpl> device_holder_; std::shared_ptr<DeviceHolderImpl> device_holder_;

View File

@ -9,6 +9,7 @@
#include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/command_pool_vk.h"
#include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h"
#include "impeller/renderer/backend/vulkan/test/mock_vulkan.h" #include "impeller/renderer/backend/vulkan/test/mock_vulkan.h"
#include "vulkan/vulkan_core.h"
namespace impeller { namespace impeller {
namespace testing { namespace testing {
@ -260,6 +261,48 @@ TEST(ContextVKTest, HasDefaultColorFormat) {
ASSERT_NE(capabilites_vk->GetDefaultColorFormat(), PixelFormat::kUnknown); 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) { TEST(ContextVKTest, BatchSubmitCommandBuffersOnArm) {
std::shared_ptr<ContextVK> context = std::shared_ptr<ContextVK> context =
MockVulkanContextBuilder() MockVulkanContextBuilder()

View File

@ -16,6 +16,18 @@
namespace impeller { namespace impeller {
constexpr std::optional<PixelFormat> 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) { constexpr vk::SampleCountFlagBits ToVKSampleCountFlagBits(SampleCount count) {
switch (count) { switch (count) {
case SampleCount::kCount1: case SampleCount::kCount1:

View File

@ -4,6 +4,8 @@
#include "impeller/renderer/backend/vulkan/queue_vk.h" #include "impeller/renderer/backend/vulkan/queue_vk.h"
#include <utility>
#include "impeller/renderer/backend/vulkan/context_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h"
namespace impeller { namespace impeller {
@ -45,19 +47,37 @@ void QueueVK::InsertDebugMarker(std::string_view label) const {
QueuesVK::QueuesVK() = default; QueuesVK::QueuesVK() = default;
QueuesVK::QueuesVK(const vk::Device& device, QueuesVK::QueuesVK(std::shared_ptr<QueueVK> graphics_queue,
QueueIndexVK graphics, std::shared_ptr<QueueVK> compute_queue,
QueueIndexVK compute, std::shared_ptr<QueueVK> transfer_queue)
QueueIndexVK transfer) { : 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<QueueVK>(
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_graphics = device.getQueue(graphics.family, graphics.index);
auto vk_compute = device.getQueue(compute.family, compute.index); auto vk_compute = device.getQueue(compute.family, compute.index);
auto vk_transfer = device.getQueue(transfer.family, transfer.index); auto vk_transfer = device.getQueue(transfer.family, transfer.index);
// Always set up the graphics queue. // Always set up the graphics queue.
graphics_queue = std::make_shared<QueueVK>(graphics, vk_graphics); auto graphics_queue = std::make_shared<QueueVK>(graphics, vk_graphics);
ContextVK::SetDebugName(device, vk_graphics, "ImpellerGraphicsQ"); ContextVK::SetDebugName(device, vk_graphics, "ImpellerGraphicsQ");
// Setup the compute queue if its different from the graphics queue. // Setup the compute queue if its different from the graphics queue.
std::shared_ptr<QueueVK> compute_queue;
if (compute == graphics) { if (compute == graphics) {
compute_queue = graphics_queue; compute_queue = graphics_queue;
} else { } else {
@ -67,6 +87,7 @@ QueuesVK::QueuesVK(const vk::Device& device,
// Setup the transfer queue if its different from the graphics or compute // Setup the transfer queue if its different from the graphics or compute
// queues. // queues.
std::shared_ptr<QueueVK> transfer_queue;
if (transfer == graphics) { if (transfer == graphics) {
transfer_queue = graphics_queue; transfer_queue = graphics_queue;
} else if (transfer == compute) { } else if (transfer == compute) {
@ -75,6 +96,9 @@ QueuesVK::QueuesVK(const vk::Device& device,
transfer_queue = std::make_shared<QueueVK>(transfer, vk_transfer); transfer_queue = std::make_shared<QueueVK>(transfer, vk_transfer);
ContextVK::SetDebugName(device, vk_transfer, "ImpellerTransferQ"); ContextVK::SetDebugName(device, vk_transfer, "ImpellerTransferQ");
} }
return QueuesVK(std::move(graphics_queue), std::move(compute_queue),
std::move(transfer_queue));
} }
bool QueuesVK::IsValid() const { bool QueuesVK::IsValid() const {

View File

@ -67,10 +67,17 @@ struct QueuesVK {
QueuesVK(); QueuesVK();
QueuesVK(const vk::Device& device, QueuesVK(std::shared_ptr<QueueVK> graphics_queue,
QueueIndexVK graphics, std::shared_ptr<QueueVK> compute_queue,
QueueIndexVK compute, std::shared_ptr<QueueVK> transfer_queue);
QueueIndexVK transfer);
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; bool IsValid() const;
}; };

View File

@ -82,13 +82,17 @@ std::unique_ptr<Surface> SurfaceContextVK::AcquireNextSurface() {
if (!surface) { if (!surface) {
return nullptr; return nullptr;
} }
MarkFrameEnd();
return surface;
}
void SurfaceContextVK::MarkFrameEnd() {
if (auto pipeline_library = parent_->GetPipelineLibrary()) { if (auto pipeline_library = parent_->GetPipelineLibrary()) {
impeller::PipelineLibraryVK::Cast(*pipeline_library) impeller::PipelineLibraryVK::Cast(*pipeline_library)
.DidAcquireSurfaceFrame(); .DidAcquireSurfaceFrame();
} }
parent_->DisposeThreadLocalCachedResources(); parent_->DisposeThreadLocalCachedResources();
parent_->GetResourceAllocator()->DebugTraceMemoryStatistics(); parent_->GetResourceAllocator()->DebugTraceMemoryStatistics();
return surface;
} }
void SurfaceContextVK::UpdateSurfaceSize(const ISize& size) const { void SurfaceContextVK::UpdateSurfaceSize(const ISize& size) const {

View File

@ -76,6 +76,12 @@ class SurfaceContextVK : public Context,
std::unique_ptr<Surface> AcquireNextSurface(); std::unique_ptr<Surface> 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 /// @brief Mark the current swapchain configuration as dirty, forcing it to be
/// recreated on the next frame. /// recreated on the next frame.
void UpdateSurfaceSize(const ISize& size) const; void UpdateSurfaceSize(const ISize& size) const;

View File

@ -928,6 +928,7 @@ std::shared_ptr<ContextVK> MockVulkanContextBuilder::Build() {
g_instance_layers = instance_layers_; g_instance_layers = instance_layers_;
g_format_properties_callback = format_properties_callback_; g_format_properties_callback = format_properties_callback_;
g_physical_device_properties_callback = physical_properties_callback_; g_physical_device_properties_callback = physical_properties_callback_;
settings.embedder_data = embedder_data_;
std::shared_ptr<ContextVK> result = ContextVK::Create(std::move(settings)); std::shared_ptr<ContextVK> result = ContextVK::Create(std::move(settings));
return result; return result;
} }

View File

@ -108,10 +108,17 @@ class MockVulkanContextBuilder {
return *this; return *this;
} }
MockVulkanContextBuilder SetEmbedderData(
const ContextVK::EmbedderData& embedder_data) {
embedder_data_ = embedder_data;
return *this;
}
private: private:
std::function<void(ContextVK::Settings&)> settings_callback_; std::function<void(ContextVK::Settings&)> settings_callback_;
std::vector<std::string> instance_extensions_; std::vector<std::string> instance_extensions_;
std::vector<std::string> instance_layers_; std::vector<std::string> instance_layers_;
std::optional<ContextVK::EmbedderData> embedder_data_;
std::function<void(VkPhysicalDevice physicalDevice, std::function<void(VkPhysicalDevice physicalDevice,
VkFormat format, VkFormat format,
VkFormatProperties* pFormatProperties)> VkFormatProperties* pFormatProperties)>

View File

@ -4,6 +4,7 @@
#include "impeller/renderer/backend/vulkan/texture_vk.h" #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/command_buffer_vk.h"
#include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h"
#include "impeller/renderer/backend/vulkan/sampler_vk.h" #include "impeller/renderer/backend/vulkan/sampler_vk.h"

View File

@ -68,18 +68,14 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkan::AcquireFrame(
return nullptr; return nullptr;
} }
SurfaceFrame::EncodeCallback encode_callback = SurfaceFrame::EncodeCallback encode_callback = [](const SurfaceFrame&,
[image = image, delegate = delegate_](const SurfaceFrame&, DlCanvas* canvas) -> bool {
DlCanvas* canvas) -> bool {
if (canvas == nullptr) { if (canvas == nullptr) {
FML_DLOG(ERROR) << "Canvas not available."; FML_DLOG(ERROR) << "Canvas not available.";
return false; return false;
} }
canvas->Flush(); canvas->Flush();
return true;
return delegate->PresentImage(reinterpret_cast<VkImage>(image.image),
static_cast<VkFormat>(image.format));
}; };
SurfaceFrame::SubmitCallback submit_callback = SurfaceFrame::SubmitCallback submit_callback =

View File

@ -4,17 +4,52 @@
#include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h" #include "flutter/shell/gpu/gpu_surface_vulkan_impeller.h"
#include <memory>
#include "flow/surface_frame.h" #include "flow/surface_frame.h"
#include "flutter/fml/make_copyable.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/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/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/renderer/surface.h"
#include "impeller/typographer/backends/skia/typographer_context_skia.h" #include "impeller/typographer/backends/skia/typographer_context_skia.h"
namespace flutter { 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( GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller(
std::shared_ptr<impeller::Context> context) { GPUSurfaceVulkanDelegate* delegate,
std::shared_ptr<impeller::Context> context)
: delegate_(delegate) {
if (!context || !context->IsValid()) { if (!context || !context->IsValid()) {
return; return;
} }
@ -27,7 +62,7 @@ GPUSurfaceVulkanImpeller::GPUSurfaceVulkanImpeller(
impeller_context_ = std::move(context); impeller_context_ = std::move(context);
aiks_context_ = std::move(aiks_context); aiks_context_ = std::move(aiks_context);
is_valid_ = true; is_valid_ = !!aiks_context_;
} }
// |Surface| // |Surface|
@ -51,53 +86,193 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
return nullptr; return nullptr;
} }
auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_); if (delegate_ == nullptr) {
std::unique_ptr<impeller::Surface> surface = context_vk.AcquireNextSurface(); auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_);
std::unique_ptr<impeller::Surface> surface =
context_vk.AcquireNextSurface();
if (!surface) { if (!surface) {
FML_LOG(ERROR) << "No surface available."; FML_LOG(ERROR) << "No surface available.";
return nullptr; 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;
} }
auto display_list = surface_frame.BuildDisplayList(); impeller::RenderTarget render_target = surface->GetRenderTarget();
if (!display_list) { auto cull_rect = render_target.GetRenderTargetSize();
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); SurfaceFrame::EncodeCallback encode_callback = [aiks_context =
return impeller::RenderToOnscreen(aiks_context->GetContentContext(), // aiks_context_, //
render_target, // render_target,
display_list, // cull_rect //
sk_cull_rect, // ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
/*reset_host_buffer=*/true // 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<SurfaceFrame>(
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<impeller::vk::Format>(flutter_image.format);
std::optional<impeller::PixelFormat> 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<SurfaceFrame>( impeller::vk::Image vk_image =
nullptr, // surface impeller::vk::Image(reinterpret_cast<VkImage>(flutter_image.image));
SurfaceFrame::FramebufferInfo{}, // framebuffer info
encode_callback, // encode callback impeller::TextureDescriptor desc;
fml::MakeCopyable([surface = std::move(surface)](const SurfaceFrame&) { desc.format = format.value();
return surface->Present(); desc.size = impeller::ISize{size.width(), size.height()};
}), // submit callback desc.storage_mode = impeller::StorageMode::kDevicePrivate;
size, // frame size desc.mip_count = 1;
nullptr, // context result desc.compression_type = impeller::CompressionType::kLossless;
true // display list fallback 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::SwapchainTransientsVK>(
impeller_context_, desc,
/*enable_msaa=*/true);
}
auto wrapped_onscreen =
std::make_shared<WrappedTextureSourceVK>(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<VkImage>(image.image),
static_cast<VkFormat>(image.format));
};
SurfaceFrame::FramebufferInfo framebuffer_info{.supports_readback = true};
return std::make_unique<SurfaceFrame>(nullptr, // surface
framebuffer_info, // framebuffer info
encode_callback, // encode callback
submit_callback,
size, // frame size
nullptr, // context result
true // display list fallback
);
}
} }
// |Surface| // |Surface|

View File

@ -12,12 +12,14 @@
#include "flutter/impeller/display_list/aiks_context.h" #include "flutter/impeller/display_list/aiks_context.h"
#include "flutter/impeller/renderer/context.h" #include "flutter/impeller/renderer/context.h"
#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" #include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h"
#include "impeller/renderer/backend/vulkan/swapchain/swapchain_transients_vk.h"
namespace flutter { namespace flutter {
class GPUSurfaceVulkanImpeller final : public Surface { class GPUSurfaceVulkanImpeller final : public Surface {
public: public:
explicit GPUSurfaceVulkanImpeller(std::shared_ptr<impeller::Context> context); explicit GPUSurfaceVulkanImpeller(GPUSurfaceVulkanDelegate* delegate,
std::shared_ptr<impeller::Context> context);
// |Surface| // |Surface|
~GPUSurfaceVulkanImpeller() override; ~GPUSurfaceVulkanImpeller() override;
@ -26,8 +28,10 @@ class GPUSurfaceVulkanImpeller final : public Surface {
bool IsValid() override; bool IsValid() override;
private: private:
GPUSurfaceVulkanDelegate* delegate_;
std::shared_ptr<impeller::Context> impeller_context_; std::shared_ptr<impeller::Context> impeller_context_;
std::shared_ptr<impeller::AiksContext> aiks_context_; std::shared_ptr<impeller::AiksContext> aiks_context_;
std::shared_ptr<impeller::SwapchainTransientsVK> transients_;
bool is_valid_ = false; bool is_valid_ = false;
// |Surface| // |Surface|

View File

@ -25,7 +25,7 @@ AndroidSurfaceVKImpeller::AndroidSurfaceVKImpeller(
impeller::ContextVK::Cast(*android_context->GetImpellerContext()); impeller::ContextVK::Cast(*android_context->GetImpellerContext());
surface_context_vk_ = context_vk.CreateSurfaceContext(); surface_context_vk_ = context_vk.CreateSurfaceContext();
eager_gpu_surface_ = eager_gpu_surface_ =
std::make_unique<GPUSurfaceVulkanImpeller>(surface_context_vk_); std::make_unique<GPUSurfaceVulkanImpeller>(nullptr, surface_context_vk_);
} }
AndroidSurfaceVKImpeller::~AndroidSurfaceVKImpeller() = default; AndroidSurfaceVKImpeller::~AndroidSurfaceVKImpeller() = default;
@ -57,7 +57,7 @@ std::unique_ptr<Surface> AndroidSurfaceVKImpeller::CreateGPUSurface(
} }
std::unique_ptr<GPUSurfaceVulkanImpeller> gpu_surface = std::unique_ptr<GPUSurfaceVulkanImpeller> gpu_surface =
std::make_unique<GPUSurfaceVulkanImpeller>(surface_context_vk_); std::make_unique<GPUSurfaceVulkanImpeller>(nullptr, surface_context_vk_);
if (!gpu_surface->IsValid()) { if (!gpu_surface->IsValid()) {
return nullptr; return nullptr;

View File

@ -171,6 +171,13 @@ template("embedder_source_set") {
"embedder_surface_vulkan.h", "embedder_surface_vulkan.h",
] ]
if (impeller_supports_rendering) {
sources += [
"embedder_surface_vulkan_impeller.cc",
"embedder_surface_vulkan_impeller.h",
]
}
deps += [ deps += [
"//flutter/flutter_vma:flutter_skia_vma", "//flutter/flutter_vma:flutter_skia_vma",
"//flutter/vulkan/procs", "//flutter/vulkan/procs",

View File

@ -615,7 +615,8 @@ InferVulkanPlatformViewCreationCallback(
const flutter::PlatformViewEmbedder::PlatformDispatchTable& const flutter::PlatformViewEmbedder::PlatformDispatchTable&
platform_dispatch_table, platform_dispatch_table,
std::unique_ptr<flutter::EmbedderExternalViewEmbedder> std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
external_view_embedder) { external_view_embedder,
bool enable_impeller) {
if (config->type != kVulkan) { if (config->type != kVulkan) {
return nullptr; return nullptr;
} }
@ -655,6 +656,82 @@ InferVulkanPlatformViewCreationCallback(
auto proc_addr = auto proc_addr =
vulkan_get_instance_proc_address(vk_instance, "vkGetInstanceProcAddr"); vulkan_get_instance_proc_address(vk_instance, "vkGetInstanceProcAddr");
std::shared_ptr<flutter::EmbedderExternalViewEmbedder> 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<PFN_vkGetInstanceProcAddr>(proc_addr),
.get_next_image = vulkan_get_next_image,
.present_image = vulkan_present_image_callback,
};
std::unique_ptr<flutter::EmbedderSurfaceVulkanImpeller> embedder_surface =
std::make_unique<flutter::EmbedderSurfaceVulkanImpeller>(
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<VkPhysicalDevice>(config->vulkan.physical_device),
static_cast<VkDevice>(config->vulkan.device),
config->vulkan.queue_family_index,
static_cast<VkQueue>(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<flutter::PlatformViewEmbedder>(
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<PFN_vkGetInstanceProcAddr>(proc_addr),
.get_next_image = vulkan_get_next_image,
.present_image = vulkan_present_image_callback,
};
std::unique_ptr<flutter::EmbedderSurfaceVulkan> embedder_surface =
std::make_unique<flutter::EmbedderSurfaceVulkan>(
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<VkPhysicalDevice>(config->vulkan.physical_device),
static_cast<VkDevice>(config->vulkan.device),
config->vulkan.queue_family_index,
static_cast<VkQueue>(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<flutter::PlatformViewEmbedder>(
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 = { flutter::EmbedderSurfaceVulkan::VulkanDispatchTable vulkan_dispatch_table = {
.get_instance_proc_address = .get_instance_proc_address =
reinterpret_cast<PFN_vkGetInstanceProcAddr>(proc_addr), reinterpret_cast<PFN_vkGetInstanceProcAddr>(proc_addr),
@ -662,9 +739,6 @@ InferVulkanPlatformViewCreationCallback(
.present_image = vulkan_present_image_callback, .present_image = vulkan_present_image_callback,
}; };
std::shared_ptr<flutter::EmbedderExternalViewEmbedder> view_embedder =
std::move(external_view_embedder);
std::unique_ptr<flutter::EmbedderSurfaceVulkan> embedder_surface = std::unique_ptr<flutter::EmbedderSurfaceVulkan> embedder_surface =
std::make_unique<flutter::EmbedderSurfaceVulkan>( std::make_unique<flutter::EmbedderSurfaceVulkan>(
config->vulkan.version, vk_instance, config->vulkan.version, vk_instance,
@ -690,6 +764,7 @@ InferVulkanPlatformViewCreationCallback(
std::move(external_view_embedder) // external view embedder std::move(external_view_embedder) // external view embedder
); );
}); });
#endif // // IMPELLER_SUPPORTS_RENDERING
#else // SHELL_ENABLE_VULKAN #else // SHELL_ENABLE_VULKAN
FML_LOG(ERROR) << "This Flutter Engine does not support Vulkan rendering."; FML_LOG(ERROR) << "This Flutter Engine does not support Vulkan rendering.";
return nullptr; return nullptr;
@ -762,7 +837,7 @@ InferPlatformViewCreationCallback(
case kVulkan: case kVulkan:
return InferVulkanPlatformViewCreationCallback( return InferVulkanPlatformViewCreationCallback(
config, user_data, platform_dispatch_table, config, user_data, platform_dispatch_table,
std::move(external_view_embedder)); std::move(external_view_embedder), enable_impeller);
default: default:
return nullptr; return nullptr;
} }
@ -1434,11 +1509,16 @@ CreateEmbedderRenderTarget(
break; break;
} }
case kFlutterBackingStoreTypeVulkan: { case kFlutterBackingStoreTypeVulkan: {
auto skia_surface = if (enable_impeller) {
MakeSkSurfaceFromBackingStore(context, config, &backing_store.vulkan); FML_LOG(ERROR) << "Unimplemented";
render_target = MakeRenderTargetFromSkSurface( break;
backing_store, std::move(skia_surface), collect_callback.Release()); } else {
break; auto skia_surface = MakeSkSurfaceFromBackingStore(
context, config, &backing_store.vulkan);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface), collect_callback.Release());
break;
}
} }
}; };

View File

@ -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 <utility>
#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<EmbedderExternalViewEmbedder> external_view_embedder)
: vk_(fml::MakeRefCounted<vulkan::VulkanProcTable>(
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<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
impeller_modern_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
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<impeller::Context>
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<Surface> EmbedderSurfaceVulkanImpeller::CreateGPUSurface() {
return std::make_unique<GPUSurfaceVulkanImpeller>(this, context_);
}
// |EmbedderSurface|
sk_sp<GrDirectContext> EmbedderSurfaceVulkanImpeller::CreateResourceContext()
const {
return nullptr;
}
} // namespace flutter

View File

@ -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<FlutterVulkanImage(const SkISize& frame_size)>
get_next_image; // required
std::function<bool(VkImage image, VkFormat format)>
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<EmbedderExternalViewEmbedder> 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<impeller::Context> CreateImpellerContext() const override;
private:
bool valid_ = false;
fml::RefPtr<vulkan::VulkanProcTable> vk_;
VulkanDispatchTable vulkan_dispatch_table_;
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder_;
std::shared_ptr<impeller::ContextVK> context_;
// |EmbedderSurface|
bool IsValid() const override;
// |EmbedderSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
// |EmbedderSurface|
sk_sp<GrDirectContext> CreateResourceContext() const override;
EmbedderSurfaceVulkanImpeller(const EmbedderSurfaceVulkanImpeller&) = delete;
EmbedderSurfaceVulkanImpeller& operator=(
const EmbedderSurfaceVulkanImpeller&) = delete;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_VULKAN_IMPELLER_H_

View File

@ -26,6 +26,9 @@
#ifdef SHELL_ENABLE_VULKAN #ifdef SHELL_ENABLE_VULKAN
#include "flutter/shell/platform/embedder/embedder_surface_vulkan.h" #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 #endif
namespace flutter { namespace flutter {

View File

@ -211,7 +211,7 @@ class TesterPlatformView : public PlatformView,
if (delegate_.OnPlatformViewGetSettings().enable_impeller) { if (delegate_.OnPlatformViewGetSettings().enable_impeller) {
FML_DCHECK(impeller_context_holder_.context); FML_DCHECK(impeller_context_holder_.context);
auto surface = std::make_unique<GPUSurfaceVulkanImpeller>( auto surface = std::make_unique<GPUSurfaceVulkanImpeller>(
impeller_context_holder_.surface_context); nullptr, impeller_context_holder_.surface_context);
FML_DCHECK(surface->IsValid()); FML_DCHECK(surface->IsValid());
return surface; return surface;
} }