diff --git a/shell/gpu/gpu_surface_metal_delegate.h b/shell/gpu/gpu_surface_metal_delegate.h index 56112042fbc1d..cb3900e392c1f 100644 --- a/shell/gpu/gpu_surface_metal_delegate.h +++ b/shell/gpu/gpu_surface_metal_delegate.h @@ -75,14 +75,14 @@ class GPUSurfaceMetalDelegate { //------------------------------------------------------------------------------ /// @brief Returns the handle to the MTLTexture to render to. This is only - /// called when the specefied render target type is `kMTLTexture`. + /// called when the specified render target type is `kMTLTexture`. /// virtual GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const = 0; //------------------------------------------------------------------------------ /// @brief Presents the texture with `texture_id` to the "screen". /// `texture_id` corresponds to a texture that has been obtained by an earlier - /// call to `GetMTLTexture`. This is only called when the specefied render + /// call to `GetMTLTexture`. This is only called when the specified render /// target type is `kMTLTexture`. /// /// @see |GPUSurfaceMetalDelegate::GetMTLTexture| diff --git a/shell/gpu/gpu_surface_vulkan.cc b/shell/gpu/gpu_surface_vulkan.cc index 570783bffa13d..b741ec806ea62 100644 --- a/shell/gpu/gpu_surface_vulkan.cc +++ b/shell/gpu/gpu_surface_vulkan.cc @@ -8,37 +8,19 @@ namespace flutter { -GPUSurfaceVulkan::GPUSurfaceVulkan( - GPUSurfaceVulkanDelegate* delegate, - std::unique_ptr native_surface, - bool render_to_surface) - : GPUSurfaceVulkan(/*context=*/nullptr, - delegate, - std::move(native_surface), - render_to_surface) {} - -GPUSurfaceVulkan::GPUSurfaceVulkan( - const sk_sp& context, - GPUSurfaceVulkanDelegate* delegate, - std::unique_ptr native_surface, - bool render_to_surface) - : window_(context, - delegate->vk(), - std::move(native_surface), - render_to_surface), - render_to_surface_(render_to_surface), - weak_factory_(this) {} +GPUSurfaceVulkan::GPUSurfaceVulkan(const sk_sp& skia_context, + GPUSurfaceVulkanDelegate* delegate) + : skia_context_(skia_context), delegate_(delegate), weak_factory_(this) {} GPUSurfaceVulkan::~GPUSurfaceVulkan() = default; bool GPUSurfaceVulkan::IsValid() { - return window_.IsValid(); + return image_ != nullptr; } std::unique_ptr GPUSurfaceVulkan::AcquireFrame( const SkISize& size) { - SurfaceFrame::FramebufferInfo framebuffer_info; - framebuffer_info.supports_readback = true; + VkImage image = delegate_->AcquireImage(size); // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. @@ -50,7 +32,7 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( }); } - auto surface = window_.AcquireSurface(); + sk_sp surface = window_.AcquireSurface(); if (surface == nullptr) { return nullptr; @@ -65,12 +47,14 @@ std::unique_ptr GPUSurfaceVulkan::AcquireFrame( if (canvas == nullptr || !weak_this) { return false; } - return weak_this->window_.SwapBuffers(); + return weak_this->Present(); }; return std::make_unique( std::move(surface), std::move(framebuffer_info), std::move(callback)); } +bool GPUSurfaceVulkan::Present() {} + SkMatrix GPUSurfaceVulkan::GetRootTransformation() const { // This backend does not support delegating to the underlying platform to // query for root surface transformations. Just return identity. @@ -80,7 +64,7 @@ SkMatrix GPUSurfaceVulkan::GetRootTransformation() const { } GrDirectContext* GPUSurfaceVulkan::GetContext() { - return window_.GetSkiaGrContext(); + return skia_context_; } } // namespace flutter diff --git a/shell/gpu/gpu_surface_vulkan.h b/shell/gpu/gpu_surface_vulkan.h index 50c420e38790b..67997877f96b7 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -11,30 +11,26 @@ #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "flutter/vulkan/vulkan_backbuffer.h" #include "flutter/vulkan/vulkan_native_surface.h" #include "flutter/vulkan/vulkan_window.h" #include "include/core/SkRefCnt.h" namespace flutter { + +//------------------------------------------------------------------------------ +/// @brief A GPU surface backed by VkImages provided by a +/// GPUSurfaceVulkanDelegate. +/// class GPUSurfaceVulkan : public Surface { public: - //------------------------------------------------------------------------------ - /// @brief Create a GPUSurfaceVulkan which implicitly creates its own - /// GrDirectContext for Skia. - /// - GPUSurfaceVulkan(GPUSurfaceVulkanDelegate* delegate, - std::unique_ptr native_surface, - bool render_to_surface); - //------------------------------------------------------------------------------ /// @brief Create a GPUSurfaceVulkan while letting it reuse an existing /// GrDirectContext. /// GPUSurfaceVulkan(const sk_sp& context, - GPUSurfaceVulkanDelegate* delegate, - std::unique_ptr native_surface, - bool render_to_surface); + GPUSurfaceVulkanDelegate* delegate); ~GPUSurfaceVulkan() override; @@ -44,6 +40,11 @@ class GPUSurfaceVulkan : public Surface { // |Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; + /// @brief Called when a frame is done rendering. It blocks on the render + /// fence and then calls `GPUSurfaceVulkanDelegate::PresentImage` with + /// the populated image. + bool Present(); + // |Surface| SkMatrix GetRootTransformation() const override; @@ -51,8 +52,12 @@ class GPUSurfaceVulkan : public Surface { GrDirectContext* GetContext() override; private: - vulkan::VulkanWindow window_; - const bool render_to_surface_; + sk_sp skia_context_; + GPUSurfaceVulkanDelegate* delegate_; + + std::vector> backbuffers_; + std::vector> surfaces_; + size_t current_backbuffer_index_; fml::WeakPtrFactory weak_factory_; FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkan); diff --git a/shell/gpu/gpu_surface_vulkan_delegate.h b/shell/gpu/gpu_surface_vulkan_delegate.h index 9b1a495959562..e138804835255 100644 --- a/shell/gpu/gpu_surface_vulkan_delegate.h +++ b/shell/gpu/gpu_surface_vulkan_delegate.h @@ -6,16 +6,42 @@ #define FLUTTER_SHELL_GPU_GPU_SURFACE_VULKAN_DELEGATE_H_ #include "flutter/fml/memory/ref_ptr.h" +#include "flutter/vulkan/vulkan_device.h" +#include "flutter/vulkan/vulkan_image.h" #include "flutter/vulkan/vulkan_proc_table.h" +#include "third_party/skia/include/core/SkSize.h" namespace flutter { +//------------------------------------------------------------------------------ +/// @brief Interface implemented by all platform surfaces that can present +/// a Vulkan backing store to the "screen". The GPU surface +/// abstraction (which abstracts the client rendering API) uses this +/// delegation pattern to tell the platform surface (which abstracts +/// how backing stores fulfilled by the selected client rendering +/// API end up on the "screen" on a particular platform) when the +/// rasterizer needs to allocate and present the Vulkan backing +/// store. +/// +/// @see |EmbedderSurfaceVulkan|. +/// class GPUSurfaceVulkanDelegate { public: - ~GPUSurfaceVulkanDelegate(); + virtual ~GPUSurfaceVulkanDelegate(); - // Obtain a reference to the Vulkan implementation's proc table. + /// @brief Obtain a reference to the Vulkan implementation's proc table. + /// virtual fml::RefPtr vk() = 0; + + /// @brief Called by the engine to fetch a VkImage for writing the next + /// frame. + /// + virtual VkImage AcquireImage(const SkISize& size); + + /// @brief Called by the engine once a frame has been rendered to the image + /// and it's ready to be bound for further reading/writing. + /// + virtual bool PresentImage(VkImage image); }; } // namespace flutter diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 529f48a7ebd41..0754d71140eba 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -104,6 +104,13 @@ template("embedder_source_set") { deps += [ "//flutter/shell/platform/darwin/graphics" ] } + if (embedder_enable_gl) { + sources += [ + "embedder_surface_vulkan.cc", + "embedder_surface_vulkan.h", + ] + } + public_deps = [ ":embedder_headers" ] public_configs += [ @@ -228,7 +235,9 @@ if (enable_unittests) { "tests/embedder_unittests_gl.cc", ] - deps += [ "//flutter/testing:opengl" ] + deps += [ + "//flutter/testing:opengl", + ] } if (test_enable_metal) { @@ -244,6 +253,11 @@ if (enable_unittests) { } if (test_enable_vulkan) { + sources += [ + "tests/embedder_test_context_vulkan.cc", + "tests/embedder_test_context_vulkan.h", + ] + deps += [ "//flutter/testing:vulkan", "//flutter/vulkan", diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 761db7a2de66c..4a9db40935464 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -388,6 +388,41 @@ InferMetalPlatformViewCreationCallback( #endif } +static flutter::Shell::CreateCallback +InferVulkanPlatformViewCreationCallback( + const FlutterRendererConfig* config, + void* user_data, + flutter::PlatformViewEmbedder::PlatformDispatchTable + platform_dispatch_table, + std::unique_ptr + external_view_embedder) { + if (config->type != kVulkan) { + return nullptr; + } + +#ifdef SHELL_ENABLE_VULKAN + std::shared_ptr view_embedder = + std::move(external_view_embedder); + + std::unique_ptr embedder_surface = + std::make_unique(view_embedder); + + return fml::MakeCopyable( + [embedder_surface = std::move(embedder_surface), platform_dispatch_table, + external_view_embedder = 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 + return nullptr; +#endif +} + static flutter::Shell::CreateCallback InferSoftwarePlatformViewCreationCallback( const FlutterRendererConfig* config, @@ -450,6 +485,10 @@ InferPlatformViewCreationCallback( return InferMetalPlatformViewCreationCallback( config, user_data, platform_dispatch_table, std::move(external_view_embedder)); + case kVulkan: + return InferVulkanPlatformViewCreationCallback( + config, user_data, platform_dispatch_table, + std::move(external_view_embedder)); default: return nullptr; } @@ -624,6 +663,14 @@ static sk_sp MakeSkSurfaceFromBackingStore( #endif } +static sk_sp MakeSkSurfaceFromBackingStore( + GrDirectContext* context, + const FlutterBackingStoreConfig& config, + const FlutterVulkanBackingStore* vulkan) { + assert(false); // TODO(bdero) + return nullptr; +} + static std::unique_ptr CreateEmbedderRenderTarget(const FlutterCompositor* compositor, const FlutterBackingStoreConfig& config, @@ -685,6 +732,11 @@ CreateEmbedderRenderTarget(const FlutterCompositor* compositor, render_surface = MakeSkSurfaceFromBackingStore(context, config, &backing_store.metal); break; + + case kFlutterBackingStoreTypeVulkan: + render_surface = + MakeSkSurfaceFromBackingStore(context, config, &backing_store.vulkan); + break; }; if (!render_surface) { diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index e8b769ef4cbef..8370c99257455 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -76,6 +76,7 @@ typedef enum { /// iOS version >= 10.0 (device), 13.0 (simulator) /// macOS version >= 10.14 kMetal, + kVulkan, } FlutterRendererType; /// Additional accessibility features that may be enabled by the platform. @@ -494,7 +495,7 @@ typedef struct { size_t struct_size; /// Embedder provided unique identifier to the texture buffer. Given that the /// `texture` handle is passed to the engine to render to, the texture buffer - /// is itseld owned by the embedder. This `texture_id` is then also given to + /// is itself owned by the embedder. This `texture_id` is then also given to /// the embedder in the present callback. int64_t texture_id; /// Handle to the MTLTexture that is owned by the embedder. Engine will render @@ -541,6 +542,79 @@ typedef struct { FlutterMetalTextureFrameCallback external_texture_frame_callback; } FlutterMetalRendererConfig; +/// Alias for VkInstance. +typedef const uint64_t* FlutterVulkanInstanceHandle; + +/// Alias for VkPhysicalDevice. +typedef const uint64_t* FlutterVulkanPhysicalDeviceHandle; + +/// Alias for VkDevice. +typedef const uint64_t* FlutterVulkanDeviceHandle; + +/// Alias for VkQueue. +typedef const uint64_t* FlutterVulkanQueueHandle; + +/// Alias for VkImage. +typedef const uint64_t* FlutterVulkanImageHandle; + +typedef struct { + /// The size of this struct. Must be sizeof(FlutterVulkanImage). + size_t struct_size; + /// Handle to the VkImage that is owned by the embedder. The engine will + /// bind this image for writing the frame. + FlutterVulkanImageHandle image; + /// A baton that is not interpreted by the engine in any way. It will be given + /// back to the embedder in the destruction callback below. Embedder resources + /// may be associated with this baton. + void* user_data; + /// The callback invoked by the engine when it no longer needs this backing + /// store. + VoidCallback destruction_callback; +} FlutterVulkanImage; + +/// Callback to fetch a Vulkan function pointer for a given instance. Normally, +/// this should return the results of vkGetInstanceProcAddr. +typedef void* (*FlutterVulkanInstanceProcAddressCallback)( + void* /* user data */, + FlutterVulkanInstanceHandle /* instance */, + const char* /* name */); + +/// Callback for when a VkImage is requested. +typedef FlutterVulkanImage (*FlutterVulkanImageCallback)( + void* /* user data */, + const FlutterFrameInfo* /* frame info */); + +/// Callback for when a VkImage has been written to and is ready for use by the +/// embedder. +typedef bool (*FlutterVulkanPresentCallback)( + void* /* user data */, + const FlutterVulkanImage* /* image */); +typedef uint64_t* (*Uint64Callback)(void* /* user data */); + +typedef struct { + /// The size of this struct. Must be sizeof(FlutterVulkanRendererConfig). + size_t struct_size; + // VkInstance handle. + FlutterVulkanInstanceHandle instance; + // VkPhysicalDevice handle. + FlutterVulkanPhysicalDeviceHandle physical_device; + // VkDevice handle. + FlutterVulkanDeviceHandle device; + uint32_t queue_family_index; + // VkQueue handle. + FlutterVulkanQueueHandle queue; + FlutterVulkanInstanceProcAddressCallback get_instance_proc_address_callback; + /// The callback invoked when the engine requests a VkImage from the embedder + /// for rendering the next frame. + FlutterVulkanImageCallback get_next_image_callback; + /// The callback invoked when a VkImage has been written to and is ready for + /// use by the embedder. Prior to calling this callback, the engine performs + /// a host sync, and so the VkImage can be used in a pipeline by the embedder + /// without any additional synchronization. + FlutterVulkanPresentCallback present_image_callback; + +} FlutterVulkanRendererConfig; + typedef struct { /// The size of this struct. Must be sizeof(FlutterSoftwareRendererConfig). size_t struct_size; @@ -557,6 +631,7 @@ typedef struct { FlutterOpenGLRendererConfig open_gl; FlutterSoftwareRendererConfig software; FlutterMetalRendererConfig metal; + FlutterVulkanRendererConfig vulkan; }; } FlutterRendererConfig; @@ -989,6 +1064,19 @@ typedef struct { }; } FlutterMetalBackingStore; +typedef struct { + /// The size of this struct. Must be sizeof(FlutterVulkanBackingStore). + size_t struct_size; + + /// The Vulkan image that the layer will be rendered to. This image must + /// already be available for the engine to bind for writing when it's given to + /// the engine via the backing store creation callback. The engine will + /// perform a host sync for all layers prior to calling the compositor present + /// callback, and so the written layer images can be freely bound by the + /// embedder without any additional synchronization. + FlutterVulkanImage image; +} FlutterVulkanBackingStore; + typedef enum { /// Indicates that the Flutter application requested that an opacity be /// applied to the platform view. @@ -1048,6 +1136,8 @@ typedef enum { kFlutterBackingStoreTypeSoftware, /// Specifies a Metal backing store. This is backed by a Metal texture. kFlutterBackingStoreTypeMetal, + /// Specifies a Vulkan backing store. This is backed by a Vulkan VkImage. + kFlutterBackingStoreTypeVulkan, } FlutterBackingStoreType; typedef struct { @@ -1069,6 +1159,8 @@ typedef struct { FlutterSoftwareBackingStore software; // The description of the Metal backing store. FlutterMetalBackingStore metal; + // The description of the Vulkan backing store. + FlutterVulkanBackingStore vulkan; }; } FlutterBackingStore; diff --git a/shell/platform/embedder/platform_view_embedder.cc b/shell/platform/embedder/platform_view_embedder.cc index 2a2752446f5e2..a24e13e2636d0 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -49,6 +49,19 @@ PlatformViewEmbedder::PlatformViewEmbedder( platform_dispatch_table_(platform_dispatch_table) {} #endif +#ifdef SHELL_ENABLE_VULKAN +PlatformViewEmbedder::PlatformViewEmbedder( + PlatformView::Delegate& delegate, + flutter::TaskRunners task_runners, + std::unique_ptr embedder_surface, + PlatformDispatchTable platform_dispatch_table, + std::shared_ptr external_view_embedder) + : PlatformView(delegate, std::move(task_runners)), + external_view_embedder_(external_view_embedder), + embedder_surface_(std::move(embedder_surface)), + platform_dispatch_table_(platform_dispatch_table) {} +#endif + PlatformViewEmbedder::~PlatformViewEmbedder() = default; void PlatformViewEmbedder::UpdateSemantics( diff --git a/shell/platform/embedder/platform_view_embedder.h b/shell/platform/embedder/platform_view_embedder.h index 22f4d2dee6ea0..61b4d6444c7bd 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -23,6 +23,10 @@ #include "flutter/shell/platform/embedder/embedder_surface_metal.h" #endif +#ifdef SHELL_ENABLE_METAL +#include "flutter/shell/platform/embedder/embedder_surface_vulkan.h" +#endif + namespace flutter { class PlatformViewEmbedder final : public PlatformView { @@ -79,6 +83,16 @@ class PlatformViewEmbedder final : public PlatformView { std::shared_ptr external_view_embedder); #endif +#ifdef SHELL_ENABLE_VULKAN + // Creates a platform view that sets up an Vulkan rasterizer. + PlatformViewEmbedder( + PlatformView::Delegate& delegate, + flutter::TaskRunners task_runners, + std::unique_ptr embedder_surface, + PlatformDispatchTable platform_dispatch_table, + std::shared_ptr external_view_embedder); +#endif + ~PlatformViewEmbedder() override; // |PlatformView| diff --git a/shell/platform/embedder/tests/embedder_assertions.h b/shell/platform/embedder/tests/embedder_assertions.h index 423c1239f34c7..7a4e519bf0d55 100644 --- a/shell/platform/embedder/tests/embedder_assertions.h +++ b/shell/platform/embedder/tests/embedder_assertions.h @@ -70,6 +70,11 @@ inline bool operator==(const FlutterMetalTexture& a, return a.texture_id == b.texture_id && a.texture == b.texture; } +inline bool operator==(const FlutterVulkanBackingStore& a, + const FlutterVulkanBackingStore& b) { + return a.handle == b.handle && a.image_ready == b.image_ready; +} + inline bool operator==(const FlutterMetalBackingStore& a, const FlutterMetalBackingStore& b) { return a.texture == b.texture; @@ -112,6 +117,8 @@ inline bool operator==(const FlutterBackingStore& a, return a.software == b.software; case kFlutterBackingStoreTypeMetal: return a.metal == b.metal; + case kFlutterBackingStoreTypeVulkan: + return a.vulkan == b.vulkan; } return false; @@ -230,6 +237,8 @@ inline std::string FlutterBackingStoreTypeToString( return "kFlutterBackingStoreTypeSoftware"; case kFlutterBackingStoreTypeMetal: return "kFlutterBackingStoreTypeMetal"; + case kFlutterBackingStoreTypeVulkan: + return "kFlutterBackingStoreTypeVulkan"; } return "Unknown"; } @@ -347,6 +356,12 @@ inline std::ostream& operator<<(std::ostream& out, return out << "(FlutterMetalBackingStore) Texture: " << item.texture; } +inline std::ostream& operator<<(std::ostream& out, + const FlutterVulkanBackingStore& item) { + return out << "(FlutterVulkanBackingStore) Handle: " << item.handle + << "Image Ready Semaphore: " << item.image_ready; +} + inline std::ostream& operator<<(std::ostream& out, const FlutterBackingStore& backing_store) { out << "(FlutterBackingStore) Struct size: " << backing_store.struct_size @@ -366,6 +381,10 @@ inline std::ostream& operator<<(std::ostream& out, case kFlutterBackingStoreTypeMetal: out << backing_store.metal; break; + + case kFlutterBackingStoreTypeVulkan: + out << backing_store.vulkan; + break; } return out; diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index d04188e0d3070..6d077e3e893a2 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -13,6 +13,10 @@ #include "flutter/shell/platform/embedder/tests/embedder_test_context_gl.h" #endif +//#ifdef SHELL_ENABLE_VULKAN +#include "flutter/shell/platform/embedder/tests/embedder_test_context_vulkan.h" +//#endif + #ifdef SHELL_ENABLE_METAL #include "flutter/shell/platform/embedder/tests/embedder_test_context_metal.h" #endif @@ -69,6 +73,41 @@ EmbedderConfigBuilder::EmbedderConfigBuilder( }; #endif + //#ifdef SHELL_ENABLE_VULKAN + vulkan_renderer_config_.struct_size = sizeof(FlutterVulkanRendererConfig); + vulkan_renderer_config_.get_proc_address_callback = + [](void* context, const char* name) -> void* { + return reinterpret_cast(context) + ->vk_->AcquireProc(name, nullptr); + }; + vulkan_renderer_config_.get_instance_proc_address_callback = + [](void* context, uintptr_t* instance, const char* name) -> void* { + return reinterpret_cast(context) + ->vk_->AcquireProc(name, instance); + }; + vulkan_renderer_config_.get_instance_handle_callback = + [](void* context) -> void* { + return reinterpret_cast(context) + ->application_->GetInstance(); + }; + vulkan_renderer_config_.get_physical_device_handle_callback = + [](void* context) -> void* { + return reinterpret_cast(context) + ->logical_device_->GetPhysicalDeviceHandle(); + }; + vulkan_renderer_config_.get_device_handle_callback = + [](void* context) -> void* { + return reinterpret_cast(context) + ->logical_device_->GetHandle(); + }; + vulkan_renderer_config_->acquire_next_image_callback = + [](void* context) -> void* { + // TODO(bdero): Return VkImage handles + return reinterpret_cast(context) + ->GetNextImage(); + }; + //#endif + #ifdef SHELL_ENABLE_METAL InitializeMetalRendererConfig(); #endif diff --git a/shell/platform/embedder/tests/embedder_config_builder.h b/shell/platform/embedder/tests/embedder_config_builder.h index ee1fb514bb611..be7f4282824ae 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.h +++ b/shell/platform/embedder/tests/embedder_config_builder.h @@ -49,6 +49,8 @@ class EmbedderConfigBuilder { void SetOpenGLRendererConfig(SkISize surface_size); + void SetVulkanRendererConfig(SkISize surface_size); + void SetMetalRendererConfig(SkISize surface_size); // Used to explicitly set an `open_gl.fbo_callback`. Using this method will @@ -117,6 +119,9 @@ class EmbedderConfigBuilder { #ifdef SHELL_ENABLE_GL FlutterOpenGLRendererConfig opengl_renderer_config_ = {}; #endif +//#ifdef SHELL_ENABLE_VULKAN + FlutterVulkanRendererConfig vulkan_renderer_config_ = {}; +//#endif #ifdef SHELL_ENABLE_METAL void InitializeMetalRendererConfig(); FlutterMetalRendererConfig metal_renderer_config_ = {}; diff --git a/shell/platform/embedder/tests/embedder_test.cc b/shell/platform/embedder/tests/embedder_test.cc index b816ab5d22307..0189a5c0457c9 100644 --- a/shell/platform/embedder/tests/embedder_test.cc +++ b/shell/platform/embedder/tests/embedder_test.cc @@ -4,6 +4,7 @@ #include "flutter/shell/platform/embedder/tests/embedder_test.h" #include "flutter/shell/platform/embedder/tests/embedder_test_context_software.h" +#include "flutter/shell/platform/embedder/tests/embedder_test_context_vulkan.h" #ifdef SHELL_ENABLE_GL #include "flutter/shell/platform/embedder/tests/embedder_test_context_gl.h" @@ -33,6 +34,11 @@ EmbedderTestContext& EmbedderTest::GetEmbedderContext( std::make_unique( GetFixturesDirectory()); break; + case EmbedderTestContextType::kVulkanContext: + embedder_contexts_[type] = + std::make_unique( + GetFixturesDirectory()); + break; #ifdef SHELL_ENABLE_GL case EmbedderTestContextType::kOpenGLContext: embedder_contexts_[type] = diff --git a/shell/platform/embedder/tests/embedder_test_context.h b/shell/platform/embedder/tests/embedder_test_context.h index 3f4f6d06b9c7d..74d2cd064b7b5 100644 --- a/shell/platform/embedder/tests/embedder_test_context.h +++ b/shell/platform/embedder/tests/embedder_test_context.h @@ -44,6 +44,7 @@ enum class EmbedderTestContextType { kSoftwareContext, kOpenGLContext, kMetalContext, + kVulkanContext, }; class EmbedderTestContext { diff --git a/shell/platform/embedder/tests/embedder_test_context_vulkan.cc b/shell/platform/embedder/tests/embedder_test_context_vulkan.cc new file mode 100644 index 0000000000000..d8e42b63eec5a --- /dev/null +++ b/shell/platform/embedder/tests/embedder_test_context_vulkan.cc @@ -0,0 +1,72 @@ +// 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/tests/embedder_test_context_vulkan.h" + +#include + +#include "embedder.h" +#include "flutter/fml/logging.h" +//#include +//"flutter/shell/platform/embedder/tests/embedder_test_compositor_vulkan.h" + +#include "flutter/vulkan/vulkan_proc_table.h" + +#ifdef OS_MACOSX +#define VULKAN_SO_PATH "libvk_swiftshader.dylib" +#elif OS_WIN +#define VULKAN_SO_PATH "vk_swiftshader.dll" +#else +#define VULKAN_SO_PATH "libvk_swiftshader.so" +#endif + +namespace flutter { +namespace testing { + +EmbedderTestContextVulkan::EmbedderTestContextVulkan(std::string assets_path) + : EmbedderTestContext(assets_path) { + vk_ = fml::MakeRefCounted(VULKAN_SO_PATH); + FML_DCHECK(vk_->HasAcquiredMandatoryProcAddresses()); + + application_ = std::unique_ptr( + new vulkan::VulkanApplication(*vk_, "Flutter Unittests", {})); + FML_DCHECK(application_->IsValid()); + FML_DCHECK(vk_->AreInstanceProcsSetup()); + + logical_device_ = application_->AcquireFirstCompatibleLogicalDevice(); + FML_DCHECK(logical_device_ != nullptr); + FML_DCHECK(logical_device_->IsValid()); +} + +EmbedderTestContextVulkan::~EmbedderTestContextVulkan() {} + +void EmbedderTestContextVulkan::SetupSurface(SkISize surface_size) { + FML_CHECK(surface_size_.isEmpty()); + surface_size_ = surface_size; + + assert(false); // TODO(bdero) + // vulkan_surface_ = TestVulkanSurface::Create(*vulkan_context_, + // surface_size_); +} + +size_t EmbedderTestContextVulkan::GetSurfacePresentCount() const { + return present_count_; +} + +EmbedderTestContextType EmbedderTestContextVulkan::GetContextType() const { + return EmbedderTestContextType::kVulkanContext; +} + +void EmbedderTestContextVulkan::SetupCompositor() { + FML_CHECK(!compositor_) << "Already set up a compositor in this context."; + + assert(false); // TODO(bdero) + // FML_CHECK(vulkan_surface_) + // << "Set up the Vulkan surface before setting up a compositor."; + // compositor_ = std::make_unique( + // surface_size_, vulkan_surface_->GetGrContext()); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/embedder/tests/embedder_test_context_vulkan.h b/shell/platform/embedder/tests/embedder_test_context_vulkan.h new file mode 100644 index 0000000000000..babdccdfcaa80 --- /dev/null +++ b/shell/platform/embedder/tests/embedder_test_context_vulkan.h @@ -0,0 +1,48 @@ +// 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_TESTS_EMBEDDER_CONTEXT_VULKAN_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_CONTEXT_VULKAN_H_ + +#include "vulkan/vulkan_application.h" + +namespace flutter { +namespace testing { + +class EmbedderTestContextVulkan : public EmbedderTestContext { + public: + explicit EmbedderTestContextVulkan(std::string assets_path = ""); + + ~EmbedderTestContextVulkan() override; + + // |EmbedderTestContext| + EmbedderTestContextType GetContextType() const override; + + // |EmbedderTestContext| + size_t GetSurfacePresentCount() const override; + + // |EmbedderTestContext| + void SetupCompositor() override; + + private: + // This allows the builder to access the hooks. + friend class EmbedderConfigBuilder; + + fml::RefPtr vk_; + std::unique_ptr application_; + std::unique_ptr logical_device_; + + SkISize surface_size_ = SkISize::MakeEmpty(); + //std::unique_ptr vulkan_context_; + size_t present_count_ = 0; + + void SetupSurface(SkISize surface_size) override; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTestContextVulkan); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_TESTS_EMBEDDER_CONTEXT_VULKAN_H_ diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index c8086191c8ba3..788c926ad78c0 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -7,6 +7,8 @@ #include #include +#include "vulkan/vulkan.h" + #include "embedder.h" #include "embedder_engine.h" #include "flutter/flow/raster_cache.h" @@ -15,6 +17,7 @@ #include "flutter/fml/mapping.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/message_loop_task_queues.h" +#include "flutter/fml/native_library.h" #include "flutter/fml/paths.h" #include "flutter/fml/synchronization/count_down_latch.h" #include "flutter/fml/synchronization/waitable_event.h" @@ -31,6 +34,7 @@ #include "flutter/testing/test_gl_surface.h" #include "flutter/testing/test_vulkan_context.h" #include "flutter/testing/testing.h" +#include "flutter/vulkan/vulkan_proc_table.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/src/gpu/gl/GrGLDefines.h" #include "third_party/tonic/converter/dart_converter.h" @@ -50,6 +54,11 @@ TEST_F(EmbedderTest, CanInitializeTestVulkanContext) { ASSERT_TRUE(ctx.IsValid()); } +TEST_F(EmbedderTest, CanGetVulkanEmbedderContext) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kVulkanContext); + EmbedderConfigBuilder builder(context); +} + TEST_F(EmbedderTest, CanCreateOpenGLRenderingEngine) { EmbedderConfigBuilder builder( GetEmbedderContext(EmbedderTestContextType::kOpenGLContext)); diff --git a/vulkan/vulkan_device.cc b/vulkan/vulkan_device.cc index 67191a2810c9a..d44f22390a4dc 100644 --- a/vulkan/vulkan_device.cc +++ b/vulkan/vulkan_device.cc @@ -35,8 +35,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, : vk(p_vk), physical_device_(std::move(physical_device)), graphics_queue_index_(std::numeric_limits::max()), - valid_(false), - enable_validation_layers_(enable_validation_layers) { + valid_(false) { if (!physical_device_ || !vk.AreInstanceProcsSetup()) { return; } @@ -74,7 +73,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, }; auto enabled_layers = - DeviceLayersToEnable(vk, physical_device_, enable_validation_layers_); + DeviceLayersToEnable(vk, physical_device_, enable_validation_layers); const char* layers[enabled_layers.size()]; @@ -122,6 +121,36 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, queue_ = VulkanHandle(queue); + if (!InitializeCommandPool()) { + return; + } + + valid_ = true; +} + +VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, + VulkanHandle physical_device, + VulkanHandle device, + uint32_t queue_family_index, + VulkanHandle queue) + : vk(p_vk), + physical_device_(std::move(physical_device)), + device_(std::move(device)), + graphics_queue_index_(queue_family_index), + queue_(std::move(queue)), + valid_(false) { + if (!physical_device_ || !vk.AreInstanceProcsSetup()) { + return; + } + + if (!InitializeCommandPool()) { + return; + } + + valid_ = true; +} + +bool VulkanDevice::InitializeCommandPool() { const VkCommandPoolCreateInfo command_pool_create_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = nullptr, @@ -134,7 +163,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, nullptr, &command_pool)) != VK_SUCCESS) { FML_DLOG(INFO) << "Could not create the command pool."; - return; + return false; } command_pool_ = VulkanHandle{ @@ -142,7 +171,7 @@ VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, vk.DestroyCommandPool(device_, pool, nullptr); }}; - valid_ = true; + return true; } VulkanDevice::~VulkanDevice() { diff --git a/vulkan/vulkan_device.h b/vulkan/vulkan_device.h index 73219ea098d94..22f848dd00e97 100644 --- a/vulkan/vulkan_device.h +++ b/vulkan/vulkan_device.h @@ -18,10 +18,20 @@ class VulkanSurface; class VulkanDevice { public: + /// @brief Create a new VkDevice with a resolved VkQueue suitable for + /// rendering with Skia. + /// VulkanDevice(VulkanProcTable& vk, VulkanHandle physical_device, bool enable_validation_layers); + /// @brief Wrap an existing VkDevice and VkQueue. + /// + VulkanDevice(VulkanProcTable& vk, + VulkanHandle physical_device, + VulkanHandle device, + uint32_t queue_family_index, + VulkanHandle queue); ~VulkanDevice(); bool IsValid() const; @@ -72,8 +82,8 @@ class VulkanDevice { VulkanHandle command_pool_; uint32_t graphics_queue_index_; bool valid_; - bool enable_validation_layers_; + bool InitializeCommandPool(); std::vector GetQueueFamilyProperties() const; FML_DISALLOW_COPY_AND_ASSIGN(VulkanDevice); diff --git a/vulkan/vulkan_swapchain.cc b/vulkan/vulkan_swapchain.cc index e33fd9742bcbc..7c3792d3fb571 100644 --- a/vulkan/vulkan_swapchain.cc +++ b/vulkan/vulkan_swapchain.cc @@ -350,7 +350,7 @@ VulkanSwapchain::AcquireResult VulkanSwapchain::AcquireSurface() { // --------------------------------------------------------------------------- // Step 2: - // Put semaphores in unsignaled state. + // Put fences in an unsignaled state. // --------------------------------------------------------------------------- if (!backbuffer->ResetFences()) { FML_DLOG(INFO) << "Could not reset fences."; diff --git a/vulkan/vulkan_window.cc b/vulkan/vulkan_window.cc index 1cee0820c615f..cf7730c7aa706 100644 --- a/vulkan/vulkan_window.cc +++ b/vulkan/vulkan_window.cc @@ -19,24 +19,21 @@ namespace vulkan { VulkanWindow::VulkanWindow(fml::RefPtr proc_table, - std::unique_ptr native_surface, - bool render_to_surface) + std::unique_ptr native_surface) : VulkanWindow(/*context/*/ nullptr, proc_table, - std::move(native_surface), - render_to_surface) {} + std::move(native_surface)) {} VulkanWindow::VulkanWindow(const sk_sp& context, fml::RefPtr proc_table, - std::unique_ptr native_surface, - bool render_to_surface) + std::unique_ptr native_surface) : valid_(false), vk(std::move(proc_table)), skia_gr_context_(context) { if (!vk || !vk->HasAcquiredMandatoryProcAddresses()) { FML_DLOG(INFO) << "Proc table has not acquired mandatory proc addresses."; return; } - if (native_surface == nullptr || !native_surface->IsValid()) { + if (native_surface && !native_surface->IsValid()) { FML_DLOG(INFO) << "Native surface is invalid."; return; } @@ -70,9 +67,7 @@ VulkanWindow::VulkanWindow(const sk_sp& context, return; } - // TODO(38466): Refactor GPU surface APIs take into account the fact that an - // external view embedder may want to render to the root surface. - if (!render_to_surface) { + if (!native_surface) { return; } diff --git a/vulkan/vulkan_window.h b/vulkan/vulkan_window.h index 685825024f7b8..bbaba38d47e1b 100644 --- a/vulkan/vulkan_window.h +++ b/vulkan/vulkan_window.h @@ -36,8 +36,7 @@ class VulkanWindow { /// GrDirectContext. /// VulkanWindow(fml::RefPtr proc_table, - std::unique_ptr native_surface, - bool render_to_surface); + std::unique_ptr native_surface); //------------------------------------------------------------------------------ /// @brief Construct a VulkanWindow. Let reuse an existing @@ -45,8 +44,7 @@ class VulkanWindow { /// VulkanWindow(const sk_sp& context, fml::RefPtr proc_table, - std::unique_ptr native_surface, - bool render_to_surface); + std::unique_ptr native_surface); ~VulkanWindow();