From 800dc43095ad39827221dad41c37188b51aa6115 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Fri, 20 Nov 2020 11:32:08 -0600 Subject: [PATCH 1/4] [embedder] Allow for the backing stores to not be cached --- shell/platform/embedder/embedder.h | 2 ++ .../embedder_external_view_embedder.cc | 9 ++++-- .../embedder/tests/embedder_assertions.h | 3 +- .../embedder_test_backingstore_producer.cc | 3 ++ .../embedder/tests/embedder_unittests.cc | 5 ++++ .../embedder/tests/embedder_unittests_gl.cc | 30 +++++++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index f98f848e967b3..d7bbce362f8e2 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -858,6 +858,8 @@ typedef struct { /// Indicates if this backing store was updated since the last time it was /// associated with a presented layer. bool did_update; + /// Indicates whether this backing store can be cached and re-used. + bool is_cacheable; union { /// The description of the OpenGL backing store. FlutterOpenGLBackingStore open_gl; diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index fc6c2905331c9..e5a8536a98791 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -8,6 +8,7 @@ #include "flutter/shell/platform/embedder/embedder_layers.h" #include "flutter/shell/platform/embedder/embedder_render_target.h" +#include "flutter/shell/platform/embedder/embedder_struct_macros.h" #include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -263,8 +264,12 @@ void EmbedderExternalViewEmbedder::SubmitFrame( // Hold all rendered layers in the render target cache for one frame to // see if they may be reused next frame. for (auto& render_target : matched_render_targets) { - render_target_cache_.CacheRenderTarget(render_target.first, - std::move(render_target.second)); + const FlutterBackingStore* backing_store = + render_target.second->GetBackingStore(); + if (SAFE_ACCESS(backing_store, is_cacheable, true)) { + render_target_cache_.CacheRenderTarget(render_target.first, + std::move(render_target.second)); + } } frame->Submit(); diff --git a/shell/platform/embedder/tests/embedder_assertions.h b/shell/platform/embedder/tests/embedder_assertions.h index 89faa037b2083..212d8133a1d9e 100644 --- a/shell/platform/embedder/tests/embedder_assertions.h +++ b/shell/platform/embedder/tests/embedder_assertions.h @@ -91,7 +91,8 @@ inline bool operator==(const FlutterSoftwareBackingStore& a, inline bool operator==(const FlutterBackingStore& a, const FlutterBackingStore& b) { if (!(a.struct_size == b.struct_size && a.user_data == b.user_data && - a.type == b.type && a.did_update == b.did_update)) { + a.type == b.type && a.did_update == b.did_update && + a.is_cacheable == b.is_cacheable)) { return false; } diff --git a/shell/platform/embedder/tests/embedder_test_backingstore_producer.cc b/shell/platform/embedder/tests/embedder_test_backingstore_producer.cc index baa8e29c32064..f641d1ebe5b77 100644 --- a/shell/platform/embedder/tests/embedder_test_backingstore_producer.cc +++ b/shell/platform/embedder/tests/embedder_test_backingstore_producer.cc @@ -72,6 +72,7 @@ bool EmbedderTestBackingStoreProducer::CreateFramebuffer( backing_store_out->type = kFlutterBackingStoreTypeOpenGL; backing_store_out->user_data = surface.get(); + backing_store_out->is_cacheable = true; backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; backing_store_out->open_gl.framebuffer.target = framebuffer_info.fFormat; backing_store_out->open_gl.framebuffer.name = framebuffer_info.fFBOID; @@ -124,6 +125,7 @@ bool EmbedderTestBackingStoreProducer::CreateTexture( } backing_store_out->type = kFlutterBackingStoreTypeOpenGL; + backing_store_out->is_cacheable = true; backing_store_out->user_data = surface.get(); backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeTexture; backing_store_out->open_gl.texture.target = texture_info.fTarget; @@ -160,6 +162,7 @@ bool EmbedderTestBackingStoreProducer::CreateSoftware( } backing_store_out->type = kFlutterBackingStoreTypeSoftware; + backing_store_out->is_cacheable = true; backing_store_out->user_data = surface.get(); backing_store_out->software.allocation = pixmap.addr(); backing_store_out->software.row_bytes = pixmap.rowBytes(); diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 538ab9ae15dad..92de687d4eb64 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -552,6 +552,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.software.height = 600; FlutterLayer layer = {}; @@ -585,6 +586,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.software.height = 600; FlutterLayer layer = {}; @@ -618,6 +620,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[4]->backing_store; backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.software.height = 600; FlutterLayer layer = {}; @@ -862,6 +865,7 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; FlutterLayer layer = {}; layer.struct_size = sizeof(layer); @@ -894,6 +898,7 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; FlutterLayer layer = {}; layer.struct_size = sizeof(layer); diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index d9b0ba79bb65a..549f2e9cc99ce 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -85,6 +85,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -117,6 +118,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -178,6 +180,7 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -210,6 +213,7 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -282,6 +286,7 @@ TEST_F(EmbedderTest, RasterCacheEnabled) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -351,6 +356,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -383,6 +389,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -443,6 +450,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; ASSERT_FLOAT_EQ( backing_store.software.row_bytes * backing_store.software.height, 800 * 4 * 600.0); @@ -477,6 +485,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + backing_store.is_cacheable = true; FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; @@ -537,6 +546,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -570,6 +580,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -603,6 +614,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { FlutterBackingStore backing_store = *layers[4]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -720,6 +732,7 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -752,6 +765,7 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -834,6 +848,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -901,6 +916,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1021,6 +1037,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1054,6 +1071,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1087,6 +1105,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[4]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1365,6 +1384,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -1398,6 +1418,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) { FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -1478,6 +1499,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -1511,6 +1533,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; FlutterLayer layer = {}; @@ -1822,6 +1845,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1855,6 +1879,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1917,6 +1942,7 @@ TEST_F( FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -1950,6 +1976,7 @@ TEST_F( FlutterBackingStore backing_store = *layers[2]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -2083,6 +2110,7 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValid) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -2179,6 +2207,7 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) { FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; @@ -2281,6 +2310,7 @@ TEST_F(EmbedderTest, FlutterBackingStore backing_store = *layers[0]->backing_store; backing_store.type = kFlutterBackingStoreTypeOpenGL; backing_store.did_update = true; + backing_store.is_cacheable = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; FlutterLayer layer = {}; From 2cc55ad011ddacbc970d8bbde7f7d1981b35cb1f Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Fri, 20 Nov 2020 10:52:03 -0600 Subject: [PATCH 2/4] [embedder] FlutterBackingStoreConfig allows special treatment of root-views --- shell/platform/embedder/embedder.h | 2 ++ .../platform/embedder/embedder_external_view_embedder.cc | 8 +++++--- shell/platform/embedder/tests/embedder_config_builder.cc | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index d7bbce362f8e2..0d70c9bae4454 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -873,6 +873,8 @@ typedef struct { size_t struct_size; /// The size of the render target the engine expects to render into. FlutterSize size; + /// This is true if a backing store is requested for the root view. + bool is_root_view; } FlutterBackingStoreConfig; typedef enum { diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index e5a8536a98791..bfdf711fe3f22 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -120,13 +120,15 @@ SkCanvas* EmbedderExternalViewEmbedder::CompositeEmbeddedView(int view_id) { } static FlutterBackingStoreConfig MakeBackingStoreConfig( - const SkISize& backing_store_size) { + const SkISize& backing_store_size, + bool is_root_view) { FlutterBackingStoreConfig config = {}; config.struct_size = sizeof(config); config.size.width = backing_store_size.width(); config.size.height = backing_store_size.height(); + config.is_root_view = is_root_view; return config; } @@ -173,8 +175,8 @@ void EmbedderExternalViewEmbedder::SubmitFrame( // directly. const auto render_surface_size = external_view->GetRenderSurfaceSize(); - const auto backing_store_config = - MakeBackingStoreConfig(render_surface_size); + const auto backing_store_config = MakeBackingStoreConfig( + render_surface_size, external_view->IsRootView()); // This is where the embedder will create render targets for us. Control // flow to the embedder makes the engine susceptible to having the embedder diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index 93d4c6af916f2..bc96fb776d0f7 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -276,7 +276,6 @@ void EmbedderConfigBuilder::SetCompositor() { return reinterpret_cast(user_data)->Present( layers, // layers_count // - ); }; project_args_.compositor = &compositor_; From aa7b40371f9250c48a93fad2584a77be0d98ad62 Mon Sep 17 00:00:00 2001 From: richardjcai Date: Fri, 20 Nov 2020 19:19:11 -0500 Subject: [PATCH 3/4] Create a wrapper for IOSurface to handle creation and binding IOSurfaces to textures / framebuffers. --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/darwin/macos/BUILD.gn | 2 + .../framework/Source/FlutterIOSurfaceHolder.h | 29 ++++++++ .../Source/FlutterIOSurfaceHolder.mm | 66 +++++++++++++++++++ .../framework/Source/FlutterSurfaceManager.mm | 58 ++++------------ 5 files changed, 113 insertions(+), 44 deletions(-) create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b70e0f86c285c..616a6acfc721d 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1056,6 +1056,8 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExter FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 6731939cf7975..8a7f69477aed5 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -54,6 +54,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterExternalTextureGL.mm", "framework/Source/FlutterFrameBufferProvider.h", "framework/Source/FlutterFrameBufferProvider.mm", + "framework/Source/FlutterIOSurfaceHolder.h", + "framework/Source/FlutterIOSurfaceHolder.mm", "framework/Source/FlutterMouseCursorPlugin.h", "framework/Source/FlutterMouseCursorPlugin.mm", "framework/Source/FlutterResizeSynchronizer.h", diff --git a/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h new file mode 100644 index 0000000000000..39b4e4b515dd6 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h @@ -0,0 +1,29 @@ +// 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. + +#import + +/** + * FlutterIOSurfaceHolder maintains an IOSurface + * and provides an interface to bind the IOSurface to a texture. + */ +@interface FlutterIOSurfaceHolder : NSObject + +/** + * Bind the IOSurface to the provided texture and fbo. + */ +- (void)bindSurfaceToTexture:(GLuint)texture fbo:(GLuint)fbo size:(CGSize)size; + +/** + * Releases the current IOSurface if one exists + * and creates a new IOSurface with the specified size. + */ +- (void)recreateIOSurfaceWithSize:(CGSize)size; + +/** + * Returns a reference to the underlying IOSurface. + */ +- (const IOSurfaceRef&)ioSurface; + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm new file mode 100644 index 0000000000000..c7127393e9aea --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm @@ -0,0 +1,66 @@ +// 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. + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h" + +#include + +@interface FlutterIOSurfaceHolder () { + IOSurfaceRef _ioSurface; +} +@end + +@implementation FlutterIOSurfaceHolder + +- (void)bindSurfaceToTexture:(GLuint)texture fbo:(GLuint)fbo size:(CGSize)size { + [self recreateIOSurfaceWithSize:size]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + + CGLTexImageIOSurface2D(CGLGetCurrentContext(), GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, int(size.width), + int(size.height), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _ioSurface, + 0 /* plane */); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, texture, + 0); + + NSAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, + @"Framebuffer status check failed"); +} + +- (void)recreateIOSurfaceWithSize:(CGSize)size { + if (_ioSurface) { + CFRelease(_ioSurface); + } + + unsigned pixelFormat = 'BGRA'; + unsigned bytesPerElement = 4; + + size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width * bytesPerElement); + size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height * bytesPerRow); + NSDictionary* options = @{ + (id)kIOSurfaceWidth : @(size.width), + (id)kIOSurfaceHeight : @(size.height), + (id)kIOSurfacePixelFormat : @(pixelFormat), + (id)kIOSurfaceBytesPerElement : @(bytesPerElement), + (id)kIOSurfaceBytesPerRow : @(bytesPerRow), + (id)kIOSurfaceAllocSize : @(totalBytes), + }; + + _ioSurface = IOSurfaceCreate((CFDictionaryRef)options); +} + +- (const IOSurfaceRef&)ioSurface { + return _ioSurface; +} + +- (void)dealloc { + if (_ioSurface) { + CFRelease(_ioSurface); + } +} + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm index a1076bb395eb4..20a1b1a341dc4 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm @@ -4,6 +4,7 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h" #include @@ -22,7 +23,7 @@ @interface FlutterSurfaceManager () { NSOpenGLContext* _openGLContext; - IOSurfaceRef _ioSurface[kFlutterSurfaceManagerBufferCount]; + FlutterIOSurfaceHolder* _ioSurfaces[kFlutterSurfaceManagerBufferCount]; FlutterFrameBufferProvider* _frameBuffers[kFlutterSurfaceManagerBufferCount]; } @end @@ -42,6 +43,9 @@ - (instancetype)initWithLayer:(CALayer*)containingLayer _frameBuffers[0] = [[FlutterFrameBufferProvider alloc] initWithOpenGLContext:_openGLContext]; _frameBuffers[1] = [[FlutterFrameBufferProvider alloc] initWithOpenGLContext:_openGLContext]; + + _ioSurfaces[0] = [FlutterIOSurfaceHolder alloc]; + _ioSurfaces[1] = [FlutterIOSurfaceHolder alloc]; } return self; } @@ -55,38 +59,11 @@ - (void)ensureSurfaceSize:(CGSize)size { MacOSGLContextSwitch context_switch(_openGLContext); for (int i = 0; i < kFlutterSurfaceManagerBufferCount; ++i) { - if (_ioSurface[i]) { - CFRelease(_ioSurface[i]); - } - unsigned pixelFormat = 'BGRA'; - unsigned bytesPerElement = 4; - - size_t bytesPerRow = - IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width * bytesPerElement); - size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height * bytesPerRow); - NSDictionary* options = @{ - (id)kIOSurfaceWidth : @(size.width), - (id)kIOSurfaceHeight : @(size.height), - (id)kIOSurfacePixelFormat : @(pixelFormat), - (id)kIOSurfaceBytesPerElement : @(bytesPerElement), - (id)kIOSurfaceBytesPerRow : @(bytesPerRow), - (id)kIOSurfaceAllocSize : @(totalBytes), - }; - _ioSurface[i] = IOSurfaceCreate((CFDictionaryRef)options); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, [_frameBuffers[i] glTextureId]); - - CGLTexImageIOSurface2D(CGLGetCurrentContext(), GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, - int(size.width), int(size.height), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - _ioSurface[i], 0 /* plane */); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - glBindFramebuffer(GL_FRAMEBUFFER, [_frameBuffers[i] glFrameBufferId]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, - [_frameBuffers[i] glTextureId], 0); - - NSAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, - @"Framebuffer status check failed"); + [_ioSurfaces[i] recreateIOSurfaceWithSize:size]; + + GLuint fbo = [_frameBuffers[i] glFrameBufferId]; + GLuint texture = [_frameBuffers[i] glTextureId]; + [_ioSurfaces[i] bindSurfaceToTexture:texture fbo:fbo size:size]; } } @@ -96,10 +73,11 @@ - (void)swapBuffers { // The surface is an OpenGL texture, which means it has origin in bottom left corner // and needs to be flipped vertically _contentLayer.transform = CATransform3DMakeScale(1, -1, 1); - [_contentLayer setContents:(__bridge id)_ioSurface[kFlutterSurfaceManagerBackBuffer]]; + IOSurfaceRef contentIOSurface = [_ioSurfaces[kFlutterSurfaceManagerBackBuffer] ioSurface]; + [_contentLayer setContents:(__bridge id)contentIOSurface]; - std::swap(_ioSurface[kFlutterSurfaceManagerBackBuffer], - _ioSurface[kFlutterSurfaceManagerFrontBuffer]); + std::swap(_ioSurfaces[kFlutterSurfaceManagerBackBuffer], + _ioSurfaces[kFlutterSurfaceManagerFrontBuffer]); std::swap(_frameBuffers[kFlutterSurfaceManagerBackBuffer], _frameBuffers[kFlutterSurfaceManagerFrontBuffer]); } @@ -108,12 +86,4 @@ - (uint32_t)glFrameBufferId { return [_frameBuffers[kFlutterSurfaceManagerBackBuffer] glFrameBufferId]; } -- (void)dealloc { - for (int i = 0; i < kFlutterSurfaceManagerBufferCount; ++i) { - if (_ioSurface[i]) { - CFRelease(_ioSurface[i]); - } - } -} - @end From 8f1c21b984300403aa227e19174bfd447c151af0 Mon Sep 17 00:00:00 2001 From: RichardJCai Date: Tue, 27 Oct 2020 13:59:23 -0400 Subject: [PATCH 4/4] Create FlutterGLCompositor. Refactor rendering one layer to use the FlutterGLCompositor. In this commit, FlutterGLCompositor only supports rendering one view and does not support rendering platform views. --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/darwin/macos/BUILD.gn | 10 +++ .../Source/FlutterBackingStoreData.h | 17 ++++ .../Source/FlutterBackingStoreData.mm | 27 ++++++ .../macos/framework/Source/FlutterEngine.mm | 50 ++++++++++- .../framework/Source/FlutterGLCompositor.h | 56 ++++++++++++ .../framework/Source/FlutterGLCompositor.mm | 88 +++++++++++++++++++ .../Source/FlutterGLCompositorUnittests.mm | 29 ++++++ .../Source/FlutterViewControllerTest.mm | 26 +----- .../Source/FlutterViewControllerTestUtils.h | 18 ++++ .../Source/FlutterViewControllerTestUtils.mm | 30 +++++++ 11 files changed, 329 insertions(+), 24 deletions(-) create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterGLCompositorUnittests.mm create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 616a6acfc721d..a378e02aaf9f5 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1047,6 +1047,8 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterPlug FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h +FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 8a7f69477aed5..79996675a9965 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -46,6 +46,8 @@ source_set("flutter_framework_source") { sources = [ "framework/Source/FlutterAppDelegate.mm", + "framework/Source/FlutterBackingStoreData.h", + "framework/Source/FlutterBackingStoreData.mm", "framework/Source/FlutterDartProject.mm", "framework/Source/FlutterDartProject_Internal.h", "framework/Source/FlutterEngine.mm", @@ -54,6 +56,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterExternalTextureGL.mm", "framework/Source/FlutterFrameBufferProvider.h", "framework/Source/FlutterFrameBufferProvider.mm", + "framework/Source/FlutterGLCompositor.h", + "framework/Source/FlutterGLCompositor.mm", "framework/Source/FlutterIOSurfaceHolder.h", "framework/Source/FlutterIOSurfaceHolder.mm", "framework/Source/FlutterMouseCursorPlugin.h", @@ -77,9 +81,12 @@ source_set("flutter_framework_source") { sources += _flutter_framework_headers deps = [ + "//flutter/flow:flow", + "//flutter/fml", "//flutter/shell/platform/common/cpp:common_cpp_switches", "//flutter/shell/platform/darwin/common:framework_shared", "//flutter/shell/platform/embedder:embedder_as_internal_library", + "//third_party/skia", ] public_configs = [ "//flutter:config" ] @@ -119,7 +126,10 @@ executable("flutter_desktop_darwin_unittests") { sources = [ "framework/Source/FlutterEngineTest.mm", + "framework/Source/FlutterGLCompositorUnittests.mm", "framework/Source/FlutterViewControllerTest.mm", + "framework/Source/FlutterViewControllerTestUtils.h", + "framework/Source/FlutterViewControllerTestUtils.mm", ] cflags_objcc = [ "-fobjc-arc" ] diff --git a/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h b/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h new file mode 100644 index 0000000000000..753895e1be395 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h @@ -0,0 +1,17 @@ +// 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. + +#import + +/** + * FlutterBackingStoreData holds data to be stored in the + * BackingStore's user_data. + */ +@interface FlutterBackingStoreData : NSObject + +- (nullable instancetype)initWithIsRootView:(bool)isRootView; + +- (bool)isRootView; + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm b/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm new file mode 100644 index 0000000000000..342b9fc079e66 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm @@ -0,0 +1,27 @@ +// 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. + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h" + +#include + +@interface FlutterBackingStoreData () { + bool _isRootView; +} +@end + +@implementation FlutterBackingStoreData + +- (nullable instancetype)initWithIsRootView:(bool)isRootView { + if (self = [super init]) { + _isRootView = isRootView; + } + return self; +} + +- (bool)isRootView { + return _isRootView; +} + +@end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index d9ebd55f0d7ec..6e50f5d6b4504 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -10,7 +10,7 @@ #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h" -#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h" #import "flutter/shell/platform/embedder/embedder.h" /** @@ -197,6 +197,13 @@ @implementation FlutterEngine { // Pointer to the Dart AOT snapshot and instruction data. _FlutterEngineAOTData* _aotData; + + // _macOSGLCompositor is created when the engine is created and + // it's destruction is handled by ARC when the engine is destroyed. + std::unique_ptr _macOSGLCompositor; + + // FlutterCompositor is copied and used in embedder.cc. + FlutterCompositor _compositor; } - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project { @@ -306,6 +313,8 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { flutterArguments.aot_data = _aotData; } + flutterArguments.compositor = [self createFlutterCompositor]; + FlutterEngineResult result = _embedderAPI.Initialize( FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine); if (result != kSuccess) { @@ -360,6 +369,45 @@ - (void)setViewController:(FlutterViewController*)controller { } } +- (FlutterCompositor*)createFlutterCompositor { + [_mainOpenGLContext makeCurrentContext]; + + _macOSGLCompositor = std::make_unique(_viewController); + + _compositor = {}; + _compositor.struct_size = sizeof(FlutterCompositor); + _compositor.user_data = _macOSGLCompositor.get(); + + _compositor.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, // + FlutterBackingStore* backing_store_out, // + void* user_data // + ) { + return reinterpret_cast(user_data)->CreateBackingStore( + config, backing_store_out); + }; + + _compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, // + void* user_data // + ) { + return reinterpret_cast(user_data)->CollectBackingStore( + backing_store); + }; + + _compositor.present_layers_callback = [](const FlutterLayer** layers, // + size_t layers_count, // + void* user_data // + ) { + return reinterpret_cast(user_data)->Present(layers, + layers_count); + }; + + __weak FlutterEngine* weak_self = self; + _macOSGLCompositor->SetPresentCallback( + [weak_self]() { return [weak_self engineCallbackOnPresent]; }); + + return &_compositor; +} + - (id)binaryMessenger { // TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins // keeping the engine alive. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h new file mode 100644 index 0000000000000..19293facd40fd --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h @@ -0,0 +1,56 @@ +// 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 + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h" +#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" + +namespace flutter { + +// FlutterGLCompositor creates and manages the backing stores used for +// rendering Flutter content and presents Flutter content and Platform views. +// Platform views are not yet supported. +// FlutterGLCompositor is created and destroyed by FlutterEngine. +class FlutterGLCompositor { + public: + FlutterGLCompositor(FlutterViewController* view_controller); + + // Creates a BackingStore and saves updates the backing_store_out + // data with the new BackingStore data. + // If the view requesting the backing store is the root view, + // we do not create a new backing store but rather return the + // backing store associated with the root view's FlutterSurfaceManager. + // + // Any additional state allocated for the backing store and + // saved as user_data in the backing store must be collected + // in the backing_store's desctruction_callback field which will + // be called when the embedder collects the backing store. + bool CreateBackingStore(const FlutterBackingStoreConfig* config, + FlutterBackingStore* backing_store_out); + + // Releases the memory for any state used by the backing store. + bool CollectBackingStore(const FlutterBackingStore* backing_store); + + // Presents the FlutterLayers by updating FlutterView(s) using the + // layer content. + bool Present(const FlutterLayer** layers, size_t layers_count); + + using PresentCallback = std::function; + + // PresentCallback is called at the end of the Present function. + void SetPresentCallback(const PresentCallback& present_callback); + + private: + FlutterViewController* view_controller_; + PresentCallback present_callback_; + NSOpenGLContext* open_gl_context_; + + FML_DISALLOW_COPY_AND_ASSIGN(FlutterGLCompositor); +}; + +} // namespace flutter diff --git a/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm new file mode 100644 index 0000000000000..a2fb9faa65607 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm @@ -0,0 +1,88 @@ +// 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. + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterFrameBufferProvider.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.h" + +#import +#import "flutter/fml/logging.h" +#import "flutter/fml/platform/darwin/cf_utils.h" +#import "third_party/skia/include/core/SkCanvas.h" +#import "third_party/skia/include/core/SkSurface.h" +#import "third_party/skia/include/gpu/gl/GrGLAssembleInterface.h" +#import "third_party/skia/include/utils/mac/SkCGUtils.h" + +#include + +namespace flutter { + +FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller) + : view_controller_(view_controller), + open_gl_context_(view_controller.flutterView.openGLContext) {} + +bool FlutterGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config, + FlutterBackingStore* backing_store_out) { + CGSize size = CGSizeMake(config->size.width, config->size.height); + FlutterBackingStoreData* data = + [[FlutterBackingStoreData alloc] initWithIsRootView:config->is_root_view]; + + backing_store_out->type = kFlutterBackingStoreTypeOpenGL; + backing_store_out->is_cacheable = true; + backing_store_out->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + backing_store_out->open_gl.framebuffer.target = GL_RGBA8; + + if (config->is_root_view) { + // The root view uses FlutterSurfaceManager and is not cacheable since + // the fbo id changes on every present. + backing_store_out->is_cacheable = false; + auto fbo = [view_controller_.flutterView frameBufferIDForSize:size]; + backing_store_out->open_gl.framebuffer.name = fbo; + } else { + FML_CHECK(false) << "Compositor only supports creating a backing store for the root view"; + } + + backing_store_out->open_gl.framebuffer.user_data = (__bridge_retained void*)data; + backing_store_out->open_gl.framebuffer.destruction_callback = [](void* user_data) { + if (user_data != nullptr) { + CFRelease(user_data); + } + }; + + return true; +} + +bool FlutterGLCompositor::CollectBackingStore(const FlutterBackingStore* backing_store) { + return true; +} + +bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) { + for (size_t i = 0; i < layers_count; ++i) { + const auto* layer = layers[i]; + FlutterBackingStore* backing_store = const_cast(layer->backing_store); + switch (layer->type) { + case kFlutterLayerContentTypeBackingStore: { + FlutterBackingStoreData* data = + (__bridge FlutterBackingStoreData*)(backing_store->open_gl.framebuffer.user_data); + if (![data isRootView]) { + FML_CHECK(false) << "Compositor only supports presenting the root view."; + } + break; + } + case kFlutterLayerContentTypePlatformView: + // Add functionality in follow up PR. + FML_CHECK(false) << "Presenting PlatformViews not yet supported"; + break; + }; + } + return present_callback_(); +} + +void FlutterGLCompositor::SetPresentCallback( + const FlutterGLCompositor::PresentCallback& present_callback) { + present_callback_ = present_callback; +} + +} // namespace flutter diff --git a/shell/platform/darwin/macos/framework/Source/FlutterGLCompositorUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositorUnittests.mm new file mode 100644 index 0000000000000..7db8d870e05a9 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterGLCompositorUnittests.mm @@ -0,0 +1,29 @@ +// 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. + +#import + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h" +#import "flutter/testing/testing.h" + +namespace flutter::testing { + +TEST(FlutterGLCompositorTest, TestPresent) { + id mockViewController = CreateMockViewController(nil); + + std::unique_ptr macos_compositor = + std::make_unique(mockViewController); + + bool flag = false; + macos_compositor->SetPresentCallback([f = &flag]() { + *f = true; + return true; + }); + + ASSERT_TRUE(macos_compositor->Present(nil, 0)); + ASSERT_TRUE(flag); +} + +} // flutter::testing diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index ab73278d9c5bf..671520f494923 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -9,34 +9,14 @@ #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h" #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h" #include "flutter/testing/testing.h" namespace flutter::testing { -// Returns a mock FlutterViewController that is able to work in environments -// without a real pasteboard. -id mockViewController(NSString* pasteboardString) { - NSString* fixtures = @(testing::GetFixturesPath()); - FlutterDartProject* project = [[FlutterDartProject alloc] - initWithAssetsPath:fixtures - ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; - FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; - - // Mock pasteboard so that this test will work in environments without a - // real pasteboard. - id pasteboardMock = OCMClassMock([NSPasteboard class]); - OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(^(NSInvocation* invocation) { - NSString* returnValue = pasteboardString.length > 0 ? pasteboardString : nil; - [invocation setReturnValue:&returnValue]; - }); - id viewControllerMock = OCMPartialMock(viewController); - OCMStub([viewControllerMock pasteboard]).andReturn(pasteboardMock); - return viewControllerMock; -} - TEST(FlutterViewController, HasStringsWhenPasteboardEmpty) { // Mock FlutterViewController so that it behaves like the pasteboard is empty. - id viewControllerMock = mockViewController(nil); + id viewControllerMock = CreateMockViewController(nil); // Call hasStrings and expect it to be false. __block bool calledAfterClear = false; @@ -56,7 +36,7 @@ id mockViewController(NSString* pasteboardString) { TEST(FlutterViewController, HasStringsWhenPasteboardFull) { // Mock FlutterViewController so that it behaves like the pasteboard has a // valid string. - id viewControllerMock = mockViewController(@"some string"); + id viewControllerMock = CreateMockViewController(@"some string"); // Call hasStrings and expect it to be true. __block bool called = false; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h new file mode 100644 index 0000000000000..cc3c7f2bcff17 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h @@ -0,0 +1,18 @@ +// 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. + +#import +#import + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h" +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h" +#import "flutter/testing/testing.h" + +namespace flutter::testing { + +// Returns a mock FlutterViewController that is able to work in environments +// without a real pasteboard. +id CreateMockViewController(NSString* pasteboardString); + +} diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.mm new file mode 100644 index 0000000000000..972e3515283ed --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.mm @@ -0,0 +1,30 @@ +// 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. + +#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h" + +namespace flutter::testing { + +id CreateMockViewController(NSString* pasteboardString) { + { + NSString* fixtures = @(testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + + // Mock pasteboard so that this test will work in environments without a + // real pasteboard. + id pasteboardMock = OCMClassMock([NSPasteboard class]); + OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(^(NSInvocation* invocation) { + NSString* returnValue = pasteboardString.length > 0 ? pasteboardString : nil; + [invocation setReturnValue:&returnValue]; + }); + id viewControllerMock = OCMPartialMock(viewController); + OCMStub([viewControllerMock pasteboard]).andReturn(pasteboardMock); + return viewControllerMock; + } +} + +}