Platform View implemenation for Metal (#11070)

This commit is contained in:
Dan Field 2019-08-23 16:15:41 -07:00 committed by GitHub
parent 6b8a4ae654
commit 66636eaded
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 317 additions and 103 deletions

View File

@ -513,6 +513,7 @@ FILE: ../../../flutter/shell/common/vsync_waiter.cc
FILE: ../../../flutter/shell/common/vsync_waiter.h
FILE: ../../../flutter/shell/common/vsync_waiter_fallback.cc
FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h
FILE: ../../../flutter/shell/gpu/gpu_surface_delegate.h
FILE: ../../../flutter/shell/gpu/gpu_surface_gl.cc
FILE: ../../../flutter/shell/gpu/gpu_surface_gl.h
FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc

View File

@ -27,14 +27,18 @@ Animator::Animator(Delegate& delegate,
waiter_(std::move(waiter)),
last_begin_frame_time_(),
dart_frame_deadline_(0),
#if FLUTTER_SHELL_ENABLE_METAL
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(2)),
#else // FLUTTER_SHELL_ENABLE_METAL
// TODO(dnfield): We should remove this logic and set the pipeline depth
// back to 2 in this case. See https://github.com/flutter/engine/pull/9132
// for discussion.
// back to 2 in this case. See
// https://github.com/flutter/engine/pull/9132 for discussion.
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(
task_runners.GetPlatformTaskRunner() ==
task_runners.GetGPUTaskRunner()
? 1
: 2)),
#endif // FLUTTER_SHELL_ENABLE_METAL
pending_frame_semaphore_(1),
frame_number_(1),
paused_(false),
@ -42,7 +46,8 @@ Animator::Animator(Delegate& delegate,
frame_scheduled_(false),
notify_idle_task_id_(0),
dimension_change_pending_(false),
weak_factory_(this) {}
weak_factory_(this) {
}
Animator::~Animator() = default;

View File

@ -27,6 +27,7 @@ source_set("gpu_surface_software") {
source_set("gpu_surface_gl") {
sources = [
"$gpu_dir/gpu_surface_delegate.h",
"$gpu_dir/gpu_surface_gl.cc",
"$gpu_dir/gpu_surface_gl.h",
"$gpu_dir/gpu_surface_gl_delegate.cc",
@ -50,6 +51,7 @@ source_set("gpu_surface_vulkan") {
source_set("gpu_surface_metal") {
sources = [
"$gpu_dir/gpu_surface_delegate.h",
"$gpu_dir/gpu_surface_metal.h",
"$gpu_dir/gpu_surface_metal.mm",
]

View File

@ -0,0 +1,18 @@
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
namespace flutter {
class GPUSurfaceDelegate {
public:
// Get a reference to the external views embedder. This happens on the same
// thread that the renderer is operating on.
virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0;
};
} // namespace flutter
#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_

View File

@ -7,12 +7,13 @@
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/shell/gpu/gpu_surface_delegate.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
namespace flutter {
class GPUSurfaceGLDelegate {
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
public:
// Called to make the main GL context current on the current thread.
virtual bool GLContextMakeCurrent() = 0;
@ -42,10 +43,6 @@ class GPUSurfaceGLDelegate {
// flushed.
virtual SkMatrix GLContextSurfaceTransformation() const;
// Get a reference to the external views embedder. This happens on the same
// thread that the renderer is operating on.
virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0;
sk_sp<const GrGLInterface> GetGLInterface() const;
// TODO(chinmaygarde): The presence of this method is to work around the fact

View File

@ -10,6 +10,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/surface.h"
#include "flutter/shell/gpu/gpu_surface_delegate.h"
#include "third_party/skia/include/gpu/GrContext.h"
@class CAMetalLayer;
@ -18,11 +19,15 @@ namespace flutter {
class GPUSurfaceMetal : public Surface {
public:
GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer);
GPUSurfaceMetal(GPUSurfaceDelegate* delegate, fml::scoped_nsobject<CAMetalLayer> layer);
GPUSurfaceMetal(GPUSurfaceDelegate* delegate,
sk_sp<GrContext> gr_context,
fml::scoped_nsobject<CAMetalLayer> layer);
~GPUSurfaceMetal() override;
private:
GPUSurfaceDelegate* delegate_;
fml::scoped_nsobject<CAMetalLayer> layer_;
sk_sp<GrContext> context_;
fml::scoped_nsprotocol<id<MTLCommandQueue>> command_queue_;
@ -39,6 +44,9 @@ class GPUSurfaceMetal : public Surface {
// |Surface|
GrContext* GetContext() override;
// |Surface|
flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |Surface|
bool MakeRenderContextCurrent() override;

View File

@ -12,8 +12,9 @@
namespace flutter {
GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer)
: layer_(std::move(layer)) {
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceDelegate* delegate,
fml::scoped_nsobject<CAMetalLayer> layer)
: delegate_(delegate), layer_(std::move(layer)) {
if (!layer_) {
FML_LOG(ERROR) << "Could not create metal surface because of invalid layer.";
return;
@ -41,6 +42,32 @@ GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer)
context_ = context;
}
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceDelegate* delegate,
sk_sp<GrContext> gr_context,
fml::scoped_nsobject<CAMetalLayer> layer)
: delegate_(delegate), layer_(std::move(layer)), context_(gr_context) {
if (!layer_) {
FML_LOG(ERROR) << "Could not create metal surface because of invalid layer.";
return;
}
if (!context_) {
FML_LOG(ERROR) << "Could not create metal surface because of invalid Skia metal context.";
return;
}
layer.get().pixelFormat = MTLPixelFormatBGRA8Unorm;
auto metal_device = fml::scoped_nsprotocol<id<MTLDevice>>([layer_.get().device retain]);
auto metal_queue = fml::scoped_nsprotocol<id<MTLCommandQueue>>([metal_device newCommandQueue]);
if (!metal_device || !metal_queue) {
FML_LOG(ERROR) << "Could not create metal device or queue.";
return;
}
command_queue_ = metal_queue;
}
GPUSurfaceMetal::~GPUSurfaceMetal() = default;
// |Surface|
@ -112,11 +139,26 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& size)
return nullptr;
}
auto submit_callback = [drawable = next_drawable, command_buffer](
bool hasExternalViewEmbedder = delegate_->GetExternalViewEmbedder() != nullptr;
// External views need to present with transaction. When presenting with
// transaction, we have to block, otherwise we risk presenting the drawable
// after the CATransaction has completed.
// See:
// https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction
// TODO(dnfield): only do this if transactions are actually being used.
// https://github.com/flutter/flutter/issues/24133
auto submit_callback = [drawable = next_drawable, command_buffer, hasExternalViewEmbedder](
const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool {
canvas->flush();
[command_buffer.get() presentDrawable:drawable.get()];
[command_buffer.get() commit];
if (!hasExternalViewEmbedder) {
[command_buffer.get() presentDrawable:drawable.get()];
[command_buffer.get() commit];
} else {
[command_buffer.get() commit];
[command_buffer.get() waitUntilScheduled];
[drawable.get() present];
}
return true;
};
@ -137,6 +179,11 @@ GrContext* GPUSurfaceMetal::GetContext() {
return context_.get();
}
// |Surface|
flutter::ExternalViewEmbedder* GPUSurfaceMetal::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
// |Surface|
bool GPUSurfaceMetal::MakeRenderContextCurrent() {
// This backend has no such concept.

View File

@ -24,8 +24,7 @@
- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithContentsScale:(CGFloat)contentsScale;
- (std::unique_ptr<flutter::IOSSurface>)createSoftwareSurface;
- (std::unique_ptr<flutter::IOSSurfaceGL>)createGLSurfaceWithContext:
- (std::unique_ptr<flutter::IOSSurface>)createSurface:
(std::shared_ptr<flutter::IOSGLContext>)gl_context;
@end

View File

@ -13,6 +13,7 @@
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h"
#include "flutter/shell/platform/darwin/ios/ios_surface_software.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
@ -51,6 +52,13 @@
layer.allowsGroupOpacity = NO;
layer.contentsScale = contentsScale;
layer.rasterizationScale = contentsScale;
#if FLUTTER_SHELL_ENABLE_METAL
} else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
CAMetalLayer* layer = reinterpret_cast<CAMetalLayer*>(self.layer);
layer.allowsGroupOpacity = NO;
layer.contentsScale = contentsScale;
layer.rasterizationScale = contentsScale;
#endif // FLUTTER_SHELL_ENABLE_METAL
}
return self;
@ -59,27 +67,39 @@
+ (Class)layerClass {
#if TARGET_IPHONE_SIMULATOR
return [CALayer class];
#else // TARGET_IPHONE_SIMULATOR
#else // TARGET_IPHONE_SIMULATOR
#if FLUTTER_SHELL_ENABLE_METAL
return [CAMetalLayer class];
#else // FLUTTER_SHELL_ENABLE_METAL
return [CAEAGLLayer class];
#endif // FLUTTER_SHELL_ENABLE_METAL
#endif // TARGET_IPHONE_SIMULATOR
}
- (std::unique_ptr<flutter::IOSSurface>)createSoftwareSurface {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<flutter::IOSSurfaceSoftware>(std::move(layer), nullptr);
}
- (std::unique_ptr<flutter::IOSSurfaceGL>)createGLSurfaceWithContext:
- (std::unique_ptr<flutter::IOSSurface>)createSurface:
(std::shared_ptr<flutter::IOSGLContext>)gl_context {
fml::scoped_nsobject<CAEAGLLayer> eagl_layer(reinterpret_cast<CAEAGLLayer*>([self.layer retain]));
// TODO(amirh): We can lower this to iOS 8.0 once we have a Metal rendering backend.
// https://github.com/flutter/flutter/issues/24132
if (@available(iOS 9.0, *)) {
eagl_layer.get().presentsWithTransaction = YES;
if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
fml::scoped_nsobject<CAEAGLLayer> eagl_layer(
reinterpret_cast<CAEAGLLayer*>([self.layer retain]));
if (@available(iOS 9.0, *)) {
eagl_layer.get().presentsWithTransaction = YES;
}
return std::make_unique<flutter::IOSSurfaceGL>(std::move(eagl_layer), gl_context);
#if FLUTTER_SHELL_ENABLE_METAL
} else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
fml::scoped_nsobject<CAMetalLayer> metalLayer(
reinterpret_cast<CAMetalLayer*>([self.layer retain]));
if (@available(iOS 8.0, *)) {
metalLayer.get().presentsWithTransaction = YES;
}
return std::make_unique<flutter::IOSSurfaceMetal>(std::move(metalLayer));
#endif // FLUTTER_SHELL_ENABLE_METAL
} else {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<flutter::IOSSurfaceSoftware>(std::move(layer), nullptr);
}
return std::make_unique<flutter::IOSSurfaceGL>(eagl_layer, std::move(gl_context));
}
// TODO(amirh): implement drawLayer to suppoer snapshotting.
// TODO(amirh): implement drawLayer to support snapshotting.
@end

View File

@ -361,19 +361,13 @@ void FlutterPlatformViewsController::Reset() {
views_to_recomposite_.clear();
}
bool FlutterPlatformViewsController::SubmitFrame(bool gl_rendering,
GrContext* gr_context,
bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context,
std::shared_ptr<IOSGLContext> gl_context) {
DisposeViews();
bool did_submit = true;
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t view_id = composition_order_[i];
if (gl_rendering) {
EnsureGLOverlayInitialized(view_id, gl_context, gr_context);
} else {
EnsureOverlayInitialized(view_id);
}
for (int64_t view_id : composition_order_) {
EnsureOverlayInitialized(view_id, std::move(gl_context), gr_context);
auto frame = overlays_[view_id]->surface->AcquireFrame(frame_size_);
SkCanvas* canvas = frame->SkiaCanvas();
canvas->drawPicture(picture_recorders_[view_id]->finishRecordingAsPicture());
@ -455,46 +449,53 @@ void FlutterPlatformViewsController::DisposeViews() {
views_to_dispose_.clear();
}
void FlutterPlatformViewsController::EnsureOverlayInitialized(int64_t overlay_id) {
if (overlays_.count(overlay_id) != 0) {
return;
}
FlutterOverlayView* overlay_view = [[FlutterOverlayView alloc] init];
overlay_view.frame = flutter_view_.get().bounds;
overlay_view.autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface = overlay_view.createSoftwareSurface;
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
fml::scoped_nsobject<UIView>(overlay_view), std::move(ios_surface), std::move(surface));
}
void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
void FlutterPlatformViewsController::EnsureOverlayInitialized(
int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context) {
if (overlays_.count(overlay_id) != 0) {
FML_DCHECK(flutter_view_);
auto overlay_it = overlays_.find(overlay_id);
if (!gr_context) {
FML_DLOG(ERROR) << "No GrContext";
if (overlays_.count(overlay_id) != 0) {
return;
}
fml::scoped_nsobject<FlutterOverlayView> overlay_view(
[[[FlutterOverlayView alloc] init] retain]);
overlay_view.get().frame = flutter_view_.get().bounds;
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurface> ios_surface = [overlay_view.get() createSurface:nil];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface();
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
std::move(overlay_view), std::move(ios_surface), std::move(surface));
return;
}
if (overlay_it != overlays_.end()) {
if (gr_context != overlays_gr_context_) {
overlays_gr_context_ = gr_context;
// The overlay already exists, but the GrContext was changed so we need to recreate
// the rendering surface with the new GrContext.
IOSSurfaceGL* ios_surface_gl = (IOSSurfaceGL*)overlays_[overlay_id]->ios_surface.get();
std::unique_ptr<Surface> surface = ios_surface_gl->CreateSecondaryGPUSurface(gr_context);
overlays_[overlay_id]->surface = std::move(surface);
IOSSurface* ios_surface = overlay_it->second->ios_surface.get();
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
overlay_it->second->surface = std::move(surface);
}
return;
}
auto contentsScale = flutter_view_.get().layer.contentsScale;
FlutterOverlayView* overlay_view =
[[FlutterOverlayView alloc] initWithContentsScale:contentsScale];
overlay_view.frame = flutter_view_.get().bounds;
overlay_view.autoresizingMask =
fml::scoped_nsobject<FlutterOverlayView> overlay_view(
[[[FlutterOverlayView alloc] initWithContentsScale:contentsScale] retain]);
overlay_view.get().frame = flutter_view_.get().bounds;
overlay_view.get().autoresizingMask =
(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
std::unique_ptr<IOSSurfaceGL> ios_surface =
[overlay_view createGLSurfaceWithContext:std::move(gl_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateSecondaryGPUSurface(gr_context);
std::unique_ptr<IOSSurface> ios_surface =
[overlay_view.get() createSurface:std::move(gl_context)];
std::unique_ptr<Surface> surface = ios_surface->CreateGPUSurface(gr_context);
overlays_[overlay_id] = std::make_unique<FlutterPlatformViewLayer>(
fml::scoped_nsobject<UIView>(overlay_view), std::move(ios_surface), std::move(surface));
std::move(overlay_view), std::move(ios_surface), std::move(surface));
overlays_gr_context_ = gr_context;
}

View File

@ -100,9 +100,7 @@ class FlutterPlatformViewsController {
// Discards all platform views instances and auxiliary resources.
void Reset();
bool SubmitFrame(bool gl_rendering,
GrContext* gr_context,
std::shared_ptr<IOSGLContext> gl_context);
bool SubmitFrame(GrContext* gr_context, std::shared_ptr<IOSGLContext> gl_context);
void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
@ -163,10 +161,9 @@ class FlutterPlatformViewsController {
void DetachUnusedLayers();
// Dispose the views in `views_to_dispose_`.
void DisposeViews();
void EnsureOverlayInitialized(int64_t overlay_id);
void EnsureGLOverlayInitialized(int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context);
void EnsureOverlayInitialized(int64_t overlay_id,
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context);
// This will return true after pre-roll if any of the embedded views
// have mutated for last layer tree.

View File

@ -99,8 +99,6 @@ id<FlutterViewEngineDelegate> _delegate;
fml::scoped_nsobject<CAEAGLLayer> eagl_layer(
reinterpret_cast<CAEAGLLayer*>([self.layer retain]));
if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
// TODO(amirh): We can lower this to iOS 8.0 once we have a Metal rendering backend.
// https://github.com/flutter/flutter/issues/24132
if (@available(iOS 9.0, *)) {
// TODO(amirh): only do this if there's an embedded view.
// https://github.com/flutter/flutter/issues/24133
@ -109,16 +107,21 @@ id<FlutterViewEngineDelegate> _delegate;
}
return std::make_unique<flutter::IOSSurfaceGL>(context, std::move(eagl_layer),
[_delegate platformViewsController]);
}
#if FLUTTER_SHELL_ENABLE_METAL
else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
return std::make_unique<flutter::IOSSurfaceMetal>(
fml::scoped_nsobject<CAMetalLayer>(reinterpret_cast<CAMetalLayer*>([self.layer retain])),
[_delegate platformViewsController]);
}
} else if ([self.layer isKindOfClass:[CAMetalLayer class]]) {
fml::scoped_nsobject<CAMetalLayer> metalLayer(
reinterpret_cast<CAMetalLayer*>([self.layer retain]));
if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
if (@available(iOS 8.0, *)) {
// TODO(amirh): only do this if there's an embedded view.
// https://github.com/flutter/flutter/issues/24133
metalLayer.get().presentsWithTransaction = YES;
}
}
return std::make_unique<flutter::IOSSurfaceMetal>(std::move(metalLayer),
[_delegate platformViewsController]);
#endif // FLUTTER_SHELL_ENABLE_METAL
else {
} else {
fml::scoped_nsobject<CALayer> layer(reinterpret_cast<CALayer*>([self.layer retain]));
return std::make_unique<flutter::IOSSurfaceSoftware>(std::move(layer),
[_delegate platformViewsController]);

View File

@ -31,7 +31,13 @@ class IOSSurface {
virtual void UpdateStorageSizeIfNecessary() = 0;
virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;
// Creates a GPU surface. If no GrContext is supplied and the rendering mode
// supports one, a new one will be created; otherwise, the software backend
// will be used.
//
// If a GrContext is supplied, creates a secondary surface.
virtual std::unique_ptr<Surface> CreateGPUSurface(
GrContext* gr_context = nullptr) = 0;
protected:
FlutterPlatformViewsController* GetPlatformViewsController();

View File

@ -28,15 +28,17 @@ class IOSSurfaceGL final : public IOSSurface,
~IOSSurfaceGL() override;
// |IOSSurface|
bool IsValid() const override;
// |IOSSurface|
bool ResourceContextMakeCurrent() override;
// |IOSSurface|
void UpdateStorageSizeIfNecessary() override;
std::unique_ptr<Surface> CreateGPUSurface() override;
std::unique_ptr<Surface> CreateSecondaryGPUSurface(GrContext* gr_context);
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface(GrContext* gr_context = nullptr) override;
bool GLContextMakeCurrent() override;

View File

@ -38,14 +38,13 @@ void IOSSurfaceGL::UpdateStorageSizeIfNecessary() {
}
}
std::unique_ptr<Surface> IOSSurfaceGL::CreateGPUSurface() {
std::unique_ptr<Surface> IOSSurfaceGL::CreateGPUSurface(GrContext* gr_context) {
if (gr_context) {
return std::make_unique<GPUSurfaceGL>(sk_ref_sp(gr_context), this, true);
}
return std::make_unique<GPUSurfaceGL>(this, true);
}
std::unique_ptr<Surface> IOSSurfaceGL::CreateSecondaryGPUSurface(GrContext* gr_context) {
return std::make_unique<GPUSurfaceGL>(sk_ref_sp(gr_context), this, true);
}
intptr_t IOSSurfaceGL::GLContextFBO() const {
return IsValid() ? render_target_->framebuffer() : GL_NONE;
}
@ -146,7 +145,7 @@ bool IOSSurfaceGL::SubmitFrame(GrContext* context) {
return true;
}
bool submitted = platform_views_controller->SubmitFrame(true, std::move(context), context_);
bool submitted = platform_views_controller->SubmitFrame(std::move(context), context_);
[CATransaction commit];
return submitted;
}

View File

@ -7,6 +7,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_delegate.h"
#include "flutter/shell/gpu/gpu_surface_metal.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
@ -14,15 +15,16 @@
namespace flutter {
class IOSSurfaceMetal final : public IOSSurface {
class IOSSurfaceMetal final : public IOSSurface,
public GPUSurfaceDelegate,
public ExternalViewEmbedder {
public:
IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
FlutterPlatformViewsController* platform_views_controller);
~IOSSurfaceMetal() override;
IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer);
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
~IOSSurfaceMetal() override;
// |IOSSurface|
bool IsValid() const override;
@ -34,7 +36,38 @@ class IOSSurfaceMetal final : public IOSSurface {
void UpdateStorageSizeIfNecessary() override;
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
std::unique_ptr<Surface> CreateGPUSurface(GrContext* gr_context = nullptr) override;
// |GPUSurfaceDelegate|
flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |ExternalViewEmbedder|
sk_sp<SkSurface> GetRootSurface() override;
// |ExternalViewEmbedder|
void CancelFrame() override;
// |ExternalViewEmbedder|
void BeginFrame(SkISize frame_size, GrContext* context) override;
// |ExternalViewEmbedder|
void PrerollCompositeEmbeddedView(int view_id,
std::unique_ptr<flutter::EmbeddedViewParams> params) override;
// |ExternalViewEmbedder|
PostPrerollResult PostPrerollAction(fml::RefPtr<fml::GpuThreadMerger> gpu_thread_merger) override;
// |ExternalViewEmbedder|
std::vector<SkCanvas*> GetCurrentCanvases() override;
// |ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id) override;
// |ExternalViewEmbedder|
bool SubmitFrame(GrContext* context) override;
private:
fml::scoped_nsobject<CAMetalLayer> layer_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceMetal);
};

View File

@ -11,6 +11,9 @@ IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer,
FlutterPlatformViewsController* platform_views_controller)
: IOSSurface(platform_views_controller), layer_(std::move(layer)) {}
IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject<CAMetalLayer> layer)
: IOSSurface(nullptr), layer_(std::move(layer)) {}
IOSSurfaceMetal::~IOSSurfaceMetal() = default;
// |IOSSurface|
@ -27,8 +30,81 @@ bool IOSSurfaceMetal::ResourceContextMakeCurrent() {
void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {}
// |IOSSurface|
std::unique_ptr<Surface> IOSSurfaceMetal::CreateGPUSurface() {
return std::make_unique<GPUSurfaceMetal>(layer_);
std::unique_ptr<Surface> IOSSurfaceMetal::CreateGPUSurface(GrContext* gr_context) {
if (gr_context) {
return std::make_unique<GPUSurfaceMetal>(this, sk_ref_sp(gr_context), layer_);
}
return std::make_unique<GPUSurfaceMetal>(this, layer_);
}
// |ExternalViewEmbedder|
sk_sp<SkSurface> IOSSurfaceMetal::GetRootSurface() {
// On iOS, the root surface is created from the on-screen render target. Only the surfaces for the
// various overlays are controlled by this class.
return nullptr;
}
flutter::ExternalViewEmbedder* IOSSurfaceMetal::GetExternalViewEmbedder() {
if (IsIosEmbeddedViewsPreviewEnabled()) {
return this;
} else {
return nullptr;
}
}
void IOSSurfaceMetal::CancelFrame() {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->CancelFrame();
// Committing the current transaction as |BeginFrame| will create a nested
// CATransaction otherwise.
[CATransaction commit];
}
void IOSSurfaceMetal::BeginFrame(SkISize frame_size, GrContext* context) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->SetFrameSize(frame_size);
[CATransaction begin];
}
void IOSSurfaceMetal::PrerollCompositeEmbeddedView(
int view_id,
std::unique_ptr<flutter::EmbeddedViewParams> params) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->PrerollCompositeEmbeddedView(view_id, std::move(params));
}
// |ExternalViewEmbedder|
PostPrerollResult IOSSurfaceMetal::PostPrerollAction(
fml::RefPtr<fml::GpuThreadMerger> gpu_thread_merger) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->PostPrerollAction(gpu_thread_merger);
}
std::vector<SkCanvas*> IOSSurfaceMetal::GetCurrentCanvases() {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->GetCurrentCanvases();
}
SkCanvas* IOSSurfaceMetal::CompositeEmbeddedView(int view_id) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->CompositeEmbeddedView(view_id);
}
bool IOSSurfaceMetal::SubmitFrame(GrContext* context) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
if (platform_views_controller == nullptr) {
return true;
}
bool submitted = platform_views_controller->SubmitFrame(std::move(context), nullptr);
[CATransaction commit];
return submitted;
}
} // namespace flutter

View File

@ -34,7 +34,7 @@ class IOSSurfaceSoftware final : public IOSSurface,
void UpdateStorageSizeIfNecessary() override;
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
std::unique_ptr<Surface> CreateGPUSurface(GrContext* gr_context = nullptr) override;
// |GPUSurfaceSoftwareDelegate|
sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) override;

View File

@ -38,7 +38,7 @@ void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() {
// Android oddities.
}
std::unique_ptr<Surface> IOSSurfaceSoftware::CreateGPUSurface() {
std::unique_ptr<Surface> IOSSurfaceSoftware::CreateGPUSurface(GrContext* gr_context) {
if (!IsValid()) {
return nullptr;
}
@ -184,7 +184,7 @@ bool IOSSurfaceSoftware::SubmitFrame(GrContext* context) {
if (platform_views_controller == nullptr) {
return true;
}
return platform_views_controller->SubmitFrame(false, nullptr, nullptr);
return platform_views_controller->SubmitFrame(nullptr, nullptr);
}
} // namespace flutter