RendererContextSwitch guard flutter's gl context rework. (#13812)

This commit is contained in:
Chris Yang 2019-11-14 11:50:45 -08:00 committed by GitHub
parent b4899d911c
commit f456423cfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 864 additions and 129 deletions

View File

@ -514,6 +514,8 @@ FILE: ../../../flutter/shell/common/pointer_data_dispatcher.cc
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.h
FILE: ../../../flutter/shell/common/rasterizer.cc
FILE: ../../../flutter/shell/common/rasterizer.h
FILE: ../../../flutter/shell/common/renderer_context_switch_manager.cc
FILE: ../../../flutter/shell/common/renderer_context_switch_manager.h
FILE: ../../../flutter/shell/common/run_configuration.cc
FILE: ../../../flutter/shell/common/run_configuration.h
FILE: ../../../flutter/shell/common/shell.cc
@ -803,6 +805,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.h
FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.mm
FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.h

View File

@ -78,6 +78,8 @@ source_set("common") {
"pointer_data_dispatcher.h",
"rasterizer.cc",
"rasterizer.h",
"renderer_context_switch_manager.cc",
"renderer_context_switch_manager.h",
"run_configuration.cc",
"run_configuration.h",
"shell.cc",

View File

@ -163,7 +163,9 @@ sk_sp<SkImage> Rasterizer::MakeRasterSnapshot(sk_sp<SkPicture> picture,
// happen in case of software rendering.
surface = SkSurface::MakeRaster(image_info);
} else {
if (!surface_->MakeRenderContextCurrent()) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = surface_->MakeRenderContextCurrent();
if (!context_switch->GetSwitchResult()) {
return nullptr;
}
@ -377,7 +379,7 @@ static sk_sp<SkSurface> CreateSnapshotSurface(GrContext* surface_context,
return SkSurface::MakeRaster(image_info);
}
static sk_sp<SkData> ScreenshotLayerTreeAsImage(
sk_sp<SkData> Rasterizer::ScreenshotLayerTreeAsImage(
flutter::LayerTree* tree,
flutter::CompositorContext& compositor_context,
GrContext* surface_context,
@ -402,21 +404,20 @@ static sk_sp<SkData> ScreenshotLayerTreeAsImage(
auto frame = compositor_context.AcquireFrame(surface_context, canvas, nullptr,
root_surface_transformation,
false, nullptr);
canvas->clear(SK_ColorTRANSPARENT);
frame->Raster(*tree, true);
canvas->flush();
ScreenshotFlushCanvas(*canvas);
// Prepare an image from the surface, this image may potentially be on th GPU.
auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
auto potentially_gpu_snapshot = MakeImageSnapshot(snapshot_surface);
if (!potentially_gpu_snapshot) {
FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
return nullptr;
}
// Copy the GPU image snapshot into CPU memory.
auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
auto cpu_snapshot = MakeRasterImage(potentially_gpu_snapshot);
if (!cpu_snapshot) {
FML_LOG(ERROR) << "Screenshot: unable to make raster image";
return nullptr;
}
@ -436,6 +437,47 @@ static sk_sp<SkData> ScreenshotLayerTreeAsImage(
return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize());
}
sk_sp<SkImage> Rasterizer::MakeImageSnapshot(
sk_sp<SkSurface> snapshot_surface) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = surface_->MakeRenderContextCurrent();
if (!context_switch->GetSwitchResult()) {
return nullptr;
}
auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
if (!potentially_gpu_snapshot) {
FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
return nullptr;
}
return potentially_gpu_snapshot;
}
sk_sp<SkImage> Rasterizer::MakeRasterImage(
sk_sp<SkImage> potentially_gpu_snapshot) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = surface_->MakeRenderContextCurrent();
if (!context_switch->GetSwitchResult()) {
return nullptr;
}
auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
if (!cpu_snapshot) {
FML_LOG(ERROR) << "Screenshot: unable to make raster image";
return nullptr;
}
return cpu_snapshot;
}
void Rasterizer::ScreenshotFlushCanvas(SkCanvas& canvas) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = surface_->MakeRenderContextCurrent();
if (!context_switch->GetSwitchResult()) {
FML_LOG(ERROR)
<< "Screenshot: unable to switch gl context to flutter's context";
return;
}
canvas.flush();
}
Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
Rasterizer::ScreenshotType type,
bool base64_encode) {

View File

@ -432,6 +432,15 @@ class Rasterizer final : public SnapshotDelegate {
void FireNextFrameCallbackIfPresent();
sk_sp<SkData> ScreenshotLayerTreeAsImage(
flutter::LayerTree* tree,
flutter::CompositorContext& compositor_context,
GrContext* surface_context,
bool compressed);
sk_sp<SkImage> MakeImageSnapshot(sk_sp<SkSurface> snapshot_surface);
sk_sp<SkImage> MakeRasterImage(sk_sp<SkImage> potentially_gpu_snapshot);
void ScreenshotFlushCanvas(SkCanvas& canvas);
FML_DISALLOW_COPY_AND_ASSIGN(Rasterizer);
};

View File

@ -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.
#include "renderer_context_switch_manager.h"
namespace flutter {
RendererContextSwitchManager::RendererContextSwitchManager() = default;
RendererContextSwitchManager::~RendererContextSwitchManager() = default;
RendererContextSwitchManager::RendererContextSwitch::RendererContextSwitch() =
default;
RendererContextSwitchManager::RendererContextSwitch::~RendererContextSwitch(){};
RendererContextSwitchManager::RendererContextSwitchPureResult::
RendererContextSwitchPureResult(bool switch_result)
: switch_result_(switch_result){};
RendererContextSwitchManager::RendererContextSwitchPureResult::
~RendererContextSwitchPureResult() = default;
bool RendererContextSwitchManager::RendererContextSwitchPureResult::
GetSwitchResult() {
return switch_result_;
}
} // namespace flutter

View File

@ -0,0 +1,116 @@
// 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_COMMON_GL_CONTEXT_SWITCH_MANAGER_H_
#define FLUTTER_SHELL_COMMON_GL_CONTEXT_SWITCH_MANAGER_H_
#include <memory>
#include "flutter/fml/macros.h"
namespace flutter {
//------------------------------------------------------------------------------
/// Manages `RendererContextSwitch`.
///
/// Should be subclassed for platforms that uses GL and requires context
/// switching. Always use `MakeCurrent` and `ResourceMakeCurrent` in the
/// `RendererContextSwitchManager` to set gl contexts.
///
class RendererContextSwitchManager {
public:
//------------------------------------------------------------------------------
/// Switches the gl context to the flutter's contexts.
///
/// Should be subclassed for each platform embedder that uses GL.
/// In construction, it should set the current context to a flutter's context
/// In destruction, it should rest the current context.
///
class RendererContextSwitch {
public:
RendererContextSwitch();
virtual ~RendererContextSwitch();
virtual bool GetSwitchResult() = 0;
FML_DISALLOW_COPY_AND_ASSIGN(RendererContextSwitch);
};
RendererContextSwitchManager();
~RendererContextSwitchManager();
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// If this is the first instance of a shell in the process, this
/// call also bootstraps the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
//----------------------------------------------------------------------------
/// @brief Make the flutter's context as current context.
///
/// @return A `RendererContextSwitch` with `GetSwitchResult` returning
/// true if the setting process is succesful.
virtual std::unique_ptr<RendererContextSwitch> MakeCurrent() = 0;
//----------------------------------------------------------------------------
/// @brief Make the flutter's resources context as current context.
///
/// @return A `RendererContextSwitch` with `GetSwitchResult` returning
/// true if the setting process is succesful.
virtual std::unique_ptr<RendererContextSwitch> ResourceMakeCurrent() = 0;
//------------------------------------------------------------------------------
/// A representation of a `RendererContextSwitch` that doesn't require actual
/// context switching.
///
class RendererContextSwitchPureResult final : public RendererContextSwitch {
public:
// Constructor that creates an `RendererContextSwitchPureResult`.
// The `GetSwitchResult` will return the same value as `switch_result`.
//----------------------------------------------------------------------------
/// @brief Constructs a `RendererContextSwitchPureResult`.
///
/// @param[in] switch_result the switch result that will be returned
/// in `GetSwitchResult()`
///
RendererContextSwitchPureResult(bool switch_result);
~RendererContextSwitchPureResult();
bool GetSwitchResult() override;
private:
bool switch_result_;
FML_DISALLOW_COPY_AND_ASSIGN(RendererContextSwitchPureResult);
};
FML_DISALLOW_COPY_AND_ASSIGN(RendererContextSwitchManager);
};
} // namespace flutter
#endif

View File

@ -355,8 +355,11 @@ PointerDataDispatcherMaker ShellTestPlatformView::GetDispatcherMaker() {
}
// |GPUSurfaceGLDelegate|
bool ShellTestPlatformView::GLContextMakeCurrent() {
return gl_surface_.MakeCurrent();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
ShellTestPlatformView::GLContextMakeCurrent() {
return std::make_unique<
RendererContextSwitchManager::RendererContextSwitchPureResult>(
gl_surface_.MakeCurrent());
}
// |GPUSurfaceGLDelegate|
@ -387,5 +390,10 @@ ExternalViewEmbedder* ShellTestPlatformView::GetExternalViewEmbedder() {
return nullptr;
}
std::shared_ptr<RendererContextSwitchManager>
ShellTestPlatformView::GetRendererContextSwitchManager() {
return nullptr;
}
} // namespace testing
} // namespace flutter

View File

@ -144,7 +144,8 @@ class ShellTestPlatformView : public PlatformView, public GPUSurfaceGLDelegate {
PointerDataDispatcherMaker GetDispatcherMaker() override;
// |GPUSurfaceGLDelegate|
bool GLContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GLContextMakeCurrent() override;
// |GPUSurfaceGLDelegate|
bool GLContextClearCurrent() override;
@ -161,6 +162,9 @@ class ShellTestPlatformView : public PlatformView, public GPUSurfaceGLDelegate {
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
std::shared_ptr<RendererContextSwitchManager>
GetRendererContextSwitchManager() override;
FML_DISALLOW_COPY_AND_ASSIGN(ShellTestPlatformView);
};

View File

@ -952,5 +952,68 @@ TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) {
DestroyShell(std::move(shell), std::move(task_runners));
}
TEST_F(ShellTest, RasterizerScreenshot) {
Settings settings = CreateSettingsForFixture();
auto configuration = RunConfiguration::InferFromSettings(settings);
auto task_runner = CreateNewThread();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
std::unique_ptr<Shell> shell =
CreateShell(std::move(settings), std::move(task_runners));
ASSERT_TRUE(ValidateShell(shell.get()));
PlatformViewNotifyCreated(shell.get());
RunEngine(shell.get(), std::move(configuration));
auto latch = std::make_shared<fml::AutoResetWaitableEvent>();
PumpOneFrame(shell.get());
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetGPUTaskRunner(), [&shell, &latch]() {
Rasterizer::Screenshot screenshot =
shell->GetRasterizer()->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::CompressedImage, true);
EXPECT_NE(screenshot.data, nullptr);
latch->Signal();
});
latch->Wait();
DestroyShell(std::move(shell), std::move(task_runners));
}
TEST_F(ShellTest, RasterizerMakeRasterSnapshot) {
Settings settings = CreateSettingsForFixture();
auto configuration = RunConfiguration::InferFromSettings(settings);
auto task_runner = CreateNewThread();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
std::unique_ptr<Shell> shell =
CreateShell(std::move(settings), std::move(task_runners));
ASSERT_TRUE(ValidateShell(shell.get()));
PlatformViewNotifyCreated(shell.get());
RunEngine(shell.get(), std::move(configuration));
auto latch = std::make_shared<fml::AutoResetWaitableEvent>();
PumpOneFrame(shell.get());
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetGPUTaskRunner(), [&shell, &latch]() {
SnapshotDelegate* delegate =
reinterpret_cast<Rasterizer*>(shell->GetRasterizer().get());
sk_sp<SkImage> image = delegate->MakeRasterSnapshot(
SkPicture::MakePlaceholder({0, 0, 50, 50}), SkISize::Make(50, 50));
EXPECT_NE(image, nullptr);
latch->Signal();
});
latch->Wait();
DestroyShell(std::move(shell), std::move(task_runners));
}
} // namespace testing
} // namespace flutter

View File

@ -60,8 +60,10 @@ flutter::ExternalViewEmbedder* Surface::GetExternalViewEmbedder() {
return nullptr;
}
bool Surface::MakeRenderContextCurrent() {
return true;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
Surface::MakeRenderContextCurrent() {
return std::make_unique<
RendererContextSwitchManager::RendererContextSwitchPureResult>(true);
}
} // namespace flutter

View File

@ -10,6 +10,7 @@
#include "flutter/flow/compositor_context.h"
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/shell/common/renderer_context_switch_manager.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace flutter {
@ -58,7 +59,8 @@ class Surface {
virtual flutter::ExternalViewEmbedder* GetExternalViewEmbedder();
virtual bool MakeRenderContextCurrent();
virtual std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
MakeRenderContextCurrent();
private:
FML_DISALLOW_COPY_AND_ASSIGN(Surface);

View File

@ -9,6 +9,7 @@
#include "flutter/fml/size.h"
#include "flutter/fml/trace_event.h"
#include "flutter/shell/common/persistent_cache.h"
#include "flutter/shell/common/renderer_context_switch_manager.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
@ -39,7 +40,10 @@ GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate,
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetSwitchResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
@ -87,8 +91,6 @@ GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate,
}
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled "
<< compiled_count;
delegate_->GLContextClearCurrent();
}
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context,
@ -98,7 +100,9 @@ GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context,
context_(gr_context),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetSwitchResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
@ -114,8 +118,9 @@ GPUSurfaceGL::~GPUSurfaceGL() {
if (!valid_) {
return;
}
if (!delegate_->GLContextMakeCurrent()) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetSwitchResult()) {
FML_LOG(ERROR) << "Could not make the context current to destroy the "
"GrContext resources.";
return;
@ -126,8 +131,6 @@ GPUSurfaceGL::~GPUSurfaceGL() {
context_->releaseResourcesAndAbandonContext();
}
context_ = nullptr;
delegate_->GLContextClearCurrent();
}
// |Surface|
@ -253,7 +256,9 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
return nullptr;
}
if (!delegate_->GLContextMakeCurrent()) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = delegate_->GLContextMakeCurrent();
if (!context_switch->GetSwitchResult()) {
FML_LOG(ERROR)
<< "Could not make the context current to acquire the frame.";
return nullptr;
@ -285,7 +290,9 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
return weak ? weak->PresentSurface(canvas) : false;
};
return std::make_unique<SurfaceFrame>(surface, submit_callback);
std::unique_ptr<SurfaceFrame> result =
std::make_unique<SurfaceFrame>(surface, submit_callback);
return result;
}
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
@ -293,6 +300,8 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
return false;
}
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
context_switch = delegate_->GLContextMakeCurrent();
if (offscreen_surface_ != nullptr) {
TRACE_EVENT0("flutter", "CopyTextureOnscreen");
SkPaint paint;
@ -329,7 +338,6 @@ bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
onscreen_surface_ = std::move(new_onscreen_surface);
}
return true;
}
@ -360,7 +368,8 @@ flutter::ExternalViewEmbedder* GPUSurfaceGL::GetExternalViewEmbedder() {
}
// |Surface|
bool GPUSurfaceGL::MakeRenderContextCurrent() {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GPUSurfaceGL::MakeRenderContextCurrent() {
return delegate_->GLContextMakeCurrent();
}

View File

@ -44,7 +44,8 @@ class GPUSurfaceGL : public Surface {
flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |Surface|
bool MakeRenderContextCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
MakeRenderContextCurrent() override;
private:
GPUSurfaceGLDelegate* delegate_;

View File

@ -7,6 +7,7 @@
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/shell/common/renderer_context_switch_manager.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"
@ -16,7 +17,8 @@ namespace flutter {
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
public:
// Called to make the main GL context current on the current thread.
virtual bool GLContextMakeCurrent() = 0;
virtual std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GLContextMakeCurrent() = 0;
// Called to clear the current GL context on the thread. This may be called on
// either the GPU or IO threads.
@ -59,6 +61,9 @@ class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
// instrumentation to specific GL calls can specify custom GL functions
// here.
virtual GLProcResolver GetGLProcResolver() const;
virtual std::shared_ptr<RendererContextSwitchManager>
GetRendererContextSwitchManager() = 0;
};
} // namespace flutter

View File

@ -49,7 +49,8 @@ class GPUSurfaceMetal : public Surface {
flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |Surface|
bool MakeRenderContextCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> MakeRenderContextCurrent()
override;
void ReleaseUnusedDrawableIfNecessary();

View File

@ -175,9 +175,10 @@ flutter::ExternalViewEmbedder* GPUSurfaceMetal::GetExternalViewEmbedder() {
}
// |Surface|
bool GPUSurfaceMetal::MakeRenderContextCurrent() {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GPUSurfaceMetal::MakeRenderContextCurrent() {
// This backend has no such concept.
return true;
return std::make_unique<RendererContextSwitchManager::RendererContextSwitchPureResult>(true);
}
void GPUSurfaceMetal::ReleaseUnusedDrawableIfNecessary() {

View File

@ -104,9 +104,12 @@ bool AndroidSurfaceGL::SetNativeWindow(
return true;
}
bool AndroidSurfaceGL::GLContextMakeCurrent() {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
AndroidSurfaceGL::GLContextMakeCurrent() {
FML_DCHECK(onscreen_context_ && onscreen_context_->IsValid());
return onscreen_context_->MakeCurrent();
return std::make_unique<
RendererContextSwitchManager::RendererContextSwitchPureResult>(
onscreen_context_->MakeCurrent());
}
bool AndroidSurfaceGL::GLContextClearCurrent() {
@ -130,4 +133,10 @@ ExternalViewEmbedder* AndroidSurfaceGL::GetExternalViewEmbedder() {
return nullptr;
}
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager>
AndroidSurfaceGL::GetRendererContextSwitchManager() {
return nullptr;
}
} // namespace flutter

View File

@ -47,7 +47,8 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
bool SetNativeWindow(fml::RefPtr<AndroidNativeWindow> window) override;
// |GPUSurfaceGLDelegate|
bool GLContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GLContextMakeCurrent() override;
// |GPUSurfaceGLDelegate|
bool GLContextClearCurrent() override;
@ -61,6 +62,10 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager>
GetRendererContextSwitchManager() override;
private:
fml::RefPtr<AndroidContextGL> onscreen_context_;
fml::RefPtr<AndroidContextGL> offscreen_context_;

View File

@ -86,6 +86,8 @@ shared_library("create_flutter_framework_dylib") {
"ios_external_texture_gl.mm",
"ios_gl_context.h",
"ios_gl_context.mm",
"ios_gl_context_switch_manager.h",
"ios_gl_context_switch_manager.mm",
"ios_gl_render_target.h",
"ios_gl_render_target.mm",
"ios_surface.h",

View File

@ -553,6 +553,7 @@ NSString* const FlutterDefaultDartEntrypoint = nil;
- (flutter::Rasterizer::Screenshot)takeScreenshot:(flutter::Rasterizer::ScreenshotType)type
asBase64Encoded:(BOOL)base64Encode {
FML_DCHECK(_shell) << "Cannot takeScreenshot without a shell";
NSLog(@"NSLog take screenshoit");
return _shell->Screenshot(type, base64Encode);
}

View File

@ -160,6 +160,11 @@ void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
frame_size_ = frame_size;
}
void FlutterPlatformViewsController::SetRendererContextSwitchManager(
std::shared_ptr<IOSGLContextSwitchManager> gl_context_guard_manager) {
renderer_context_switch_manager_ = gl_context_guard_manager;
}
void FlutterPlatformViewsController::CancelFrame() {
composition_order_.clear();
}
@ -368,7 +373,12 @@ bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context,
bool did_submit = true;
for (int64_t view_id : composition_order_) {
EnsureOverlayInitialized(view_id, gl_context, gr_context);
if (renderer_context_switch_manager_ != nullptr) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> contextSwitch =
renderer_context_switch_manager_->MakeCurrent();
}
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,6 +465,10 @@ void FlutterPlatformViewsController::EnsureOverlayInitialized(
std::shared_ptr<IOSGLContext> gl_context,
GrContext* gr_context) {
FML_DCHECK(flutter_view_);
if (renderer_context_switch_manager_ != nullptr) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> contextSwitch =
renderer_context_switch_manager_->MakeCurrent();
}
auto overlay_it = overlays_.find(overlay_id);

View File

@ -11,6 +11,7 @@
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.h"
// A UIView that is used as the parent for embedded UIViews.
//
@ -80,6 +81,9 @@ class FlutterPlatformViewsController {
void SetFlutterViewController(UIViewController* flutter_view_controller);
void SetRendererContextSwitchManager(
std::shared_ptr<IOSGLContextSwitchManager> gl_context_guard_manager);
void RegisterViewFactory(NSObject<FlutterPlatformViewFactory>* factory, NSString* factoryId);
void SetFrameSize(SkISize frame_size);
@ -204,6 +208,8 @@ class FlutterPlatformViewsController {
void ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view);
void CompositeWithParams(int view_id, const EmbeddedViewParams& params);
std::shared_ptr<IOSGLContextSwitchManager> renderer_context_switch_manager_;
FML_DISALLOW_COPY_AND_ASSIGN(FlutterPlatformViewsController);
};

View File

@ -26,16 +26,25 @@ class IOSGLContext {
std::unique_ptr<IOSGLRenderTarget> CreateRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer);
bool MakeCurrent();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
MakeCurrent();
bool ResourceMakeCurrent();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
ResourceMakeCurrent();
std::shared_ptr<IOSGLContextSwitchManager> GetIOSGLContextSwitchManager() {
return renderer_context_switch_manager_;
}
sk_sp<SkColorSpace> ColorSpace() const { return color_space_; }
fml::scoped_nsobject<EAGLContext> GetContext() const {
return renderer_context_switch_manager_->GetContext();
}
private:
fml::scoped_nsobject<EAGLContext> context_;
fml::scoped_nsobject<EAGLContext> resource_context_;
sk_sp<SkColorSpace> color_space_;
std::shared_ptr<IOSGLContextSwitchManager> renderer_context_switch_manager_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContext);
};

View File

@ -13,15 +13,7 @@
namespace flutter {
IOSGLContext::IOSGLContext() {
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]);
if (resource_context_ != nullptr) {
context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
sharegroup:resource_context_.get().sharegroup]);
} else {
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]);
context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2
sharegroup:resource_context_.get().sharegroup]);
}
renderer_context_switch_manager_ = std::make_shared<IOSGLContextSwitchManager>();
// TODO:
// iOS displays are more variable than just P3 or sRGB. Reading the display
@ -48,16 +40,16 @@ IOSGLContext::~IOSGLContext() = default;
std::unique_ptr<IOSGLRenderTarget> IOSGLContext::CreateRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer) {
return std::make_unique<IOSGLRenderTarget>(std::move(layer), context_.get(),
resource_context_.get());
return std::make_unique<IOSGLRenderTarget>(std::move(layer), renderer_context_switch_manager_);
}
bool IOSGLContext::MakeCurrent() {
return [EAGLContext setCurrentContext:context_.get()];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> IOSGLContext::MakeCurrent() {
return renderer_context_switch_manager_->MakeCurrent();
}
bool IOSGLContext::ResourceMakeCurrent() {
return [EAGLContext setCurrentContext:resource_context_.get()];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSGLContext::ResourceMakeCurrent() {
return renderer_context_switch_manager_->ResourceMakeCurrent();
}
} // namespace flutter

View File

@ -0,0 +1,65 @@
// 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_DARWIN_IOS_IOS_GL_CONTEXT_SWITCH_MANAGER_H_
#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_SWITCH_MANAGER_H_
#define GLES_SILENCE_DEPRECATION
#import <OpenGLES/EAGL.h>
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/renderer_context_switch_manager.h"
namespace flutter {
//------------------------------------------------------------------------------
/// The iOS implementation of `RendererContextSwitchManager`.
///
/// On `IOSGLContextSwitch`'s construction, it pushes the current EAGLContext to a stack and
/// sets the flutter's gl context as current.
/// On `IOSGLContextSwitch`'s desstruction, it pops a EAGLContext from the stack and set it to
/// current.
///
class IOSGLContextSwitchManager final : public RendererContextSwitchManager {
public:
class IOSGLContextSwitch final : public RendererContextSwitch {
public:
IOSGLContextSwitch(IOSGLContextSwitchManager& manager,
fml::scoped_nsobject<EAGLContext> context);
~IOSGLContextSwitch();
bool GetSwitchResult() override;
private:
IOSGLContextSwitchManager& manager_;
bool switch_result_;
bool has_pushed_context_;
FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContextSwitch);
};
IOSGLContextSwitchManager();
~IOSGLContextSwitchManager();
std::unique_ptr<RendererContextSwitch> MakeCurrent() override;
std::unique_ptr<RendererContextSwitch> ResourceMakeCurrent() override;
fml::scoped_nsobject<EAGLContext> GetContext();
private:
fml::scoped_nsobject<EAGLContext> context_;
fml::scoped_nsobject<EAGLContext> resource_context_;
fml::scoped_nsobject<NSMutableArray> stored_;
bool PushContext(fml::scoped_nsobject<EAGLContext> context);
void PopContext();
FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContextSwitchManager);
};
}
#endif

View File

@ -0,0 +1,79 @@
// 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 "ios_gl_context_switch_manager.h"
namespace flutter {
IOSGLContextSwitchManager::IOSGLContextSwitchManager() {
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]);
stored_ = fml::scoped_nsobject<NSMutableArray>([[NSMutableArray new] retain]);
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]);
if (resource_context_ != nullptr) {
context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
sharegroup:resource_context_.get().sharegroup]);
} else {
resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]);
context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2
sharegroup:resource_context_.get().sharegroup]);
}
};
IOSGLContextSwitchManager::~IOSGLContextSwitchManager() = default;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSGLContextSwitchManager::MakeCurrent() {
return std::make_unique<IOSGLContextSwitchManager::IOSGLContextSwitch>(*this, context_);
}
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSGLContextSwitchManager::ResourceMakeCurrent() {
return std::make_unique<IOSGLContextSwitchManager::IOSGLContextSwitch>(*this, resource_context_);
}
fml::scoped_nsobject<EAGLContext> IOSGLContextSwitchManager::GetContext() {
return context_;
}
bool IOSGLContextSwitchManager::PushContext(fml::scoped_nsobject<EAGLContext> context) {
EAGLContext* current = [EAGLContext currentContext];
if (current == nil) {
[stored_.get() addObject:[NSNull null]];
} else {
[stored_.get() addObject:current];
}
bool result = [EAGLContext setCurrentContext:context.get()];
return result;
}
void IOSGLContextSwitchManager::PopContext() {
EAGLContext* last = [stored_.get() lastObject];
[stored_.get() removeLastObject];
if ([last isEqual:[NSNull null]]) {
[EAGLContext setCurrentContext:nil];
return;
}
[EAGLContext setCurrentContext:last];
}
IOSGLContextSwitchManager::IOSGLContextSwitch::IOSGLContextSwitch(
IOSGLContextSwitchManager& manager,
fml::scoped_nsobject<EAGLContext> context)
: manager_(manager) {
bool result = manager_.PushContext(context);
has_pushed_context_ = true;
switch_result_ = result;
}
IOSGLContextSwitchManager::IOSGLContextSwitch::~IOSGLContextSwitch() {
if (!has_pushed_context_) {
return;
}
manager_.PopContext();
}
bool IOSGLContextSwitchManager::IOSGLContextSwitch::GetSwitchResult() {
return switch_result_;
}
}

View File

@ -13,14 +13,15 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.h"
namespace flutter {
class IOSGLRenderTarget {
public:
IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer,
EAGLContext* context,
EAGLContext* resource_context);
IOSGLRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer,
std::shared_ptr<IOSGLContextSwitchManager> gl_context_guard_manager);
~IOSGLRenderTarget();
@ -32,16 +33,17 @@ class IOSGLRenderTarget {
bool UpdateStorageSizeIfNecessary();
bool MakeCurrent();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
MakeCurrent();
bool ResourceMakeCurrent();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
ResourceMakeCurrent();
sk_sp<SkColorSpace> ColorSpace() const { return color_space_; }
private:
fml::scoped_nsobject<CAEAGLLayer> layer_;
fml::scoped_nsobject<EAGLContext> context_;
fml::scoped_nsobject<EAGLContext> resource_context_;
std::shared_ptr<IOSGLContextSwitchManager> renderer_context_switch_manager_;
GLuint framebuffer_;
GLuint colorbuffer_;
GLint storage_size_width_;

View File

@ -12,22 +12,20 @@
namespace flutter {
IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer,
EAGLContext* context,
EAGLContext* resource_context)
IOSGLRenderTarget::IOSGLRenderTarget(
fml::scoped_nsobject<CAEAGLLayer> layer,
std::shared_ptr<IOSGLContextSwitchManager> gl_context_guard_manager)
: layer_(std::move(layer)),
context_([context retain]),
resource_context_([resource_context retain]),
renderer_context_switch_manager_(gl_context_guard_manager),
framebuffer_(GL_NONE),
colorbuffer_(GL_NONE),
storage_size_width_(0),
storage_size_height_(0),
valid_(false) {
FML_DCHECK(layer_ != nullptr);
FML_DCHECK(context_ != nullptr);
FML_DCHECK(resource_context_ != nullptr);
bool context_current = [EAGLContext setCurrentContext:context_];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> context_switch =
renderer_context_switch_manager_->MakeCurrent();
bool context_current = context_switch->GetSwitchResult();
FML_DCHECK(context_current);
FML_DCHECK(glGetError() == GL_NO_ERROR);
@ -62,8 +60,8 @@ IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject<CAEAGLLayer> layer,
}
IOSGLRenderTarget::~IOSGLRenderTarget() {
EAGLContext* context = EAGLContext.currentContext;
[EAGLContext setCurrentContext:context_];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> context_switch =
renderer_context_switch_manager_->MakeCurrent();
FML_DCHECK(glGetError() == GL_NO_ERROR);
// Deletes on GL_NONEs are ignored
@ -71,7 +69,6 @@ IOSGLRenderTarget::~IOSGLRenderTarget() {
glDeleteRenderbuffers(1, &colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
[EAGLContext setCurrentContext:context];
}
bool IOSGLRenderTarget::IsValid() const {
@ -104,8 +101,9 @@ bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() {
FML_DLOG(INFO) << "Updating render buffer storage size.";
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![EAGLContext setCurrentContext:context_]) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> context_switch =
renderer_context_switch_manager_->MakeCurrent();
if (!context_switch->GetSwitchResult()) {
return false;
}
@ -116,7 +114,8 @@ bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() {
glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_);
FML_DCHECK(glGetError() == GL_NO_ERROR);
if (![context_.get() renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer_.get()]) {
if (![renderer_context_switch_manager_->GetContext().get() renderbufferStorage:GL_RENDERBUFFER
fromDrawable:layer_.get()]) {
return false;
}
@ -132,12 +131,18 @@ bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() {
return true;
}
bool IOSGLRenderTarget::MakeCurrent() {
return UpdateStorageSizeIfNecessary() && [EAGLContext setCurrentContext:context_.get()];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSGLRenderTarget::MakeCurrent() {
bool isUpdateSuccessful = UpdateStorageSizeIfNecessary();
if (!isUpdateSuccessful) {
return std::make_unique<RendererContextSwitchManager::RendererContextSwitchPureResult>(false);
}
return renderer_context_switch_manager_->MakeCurrent();
}
bool IOSGLRenderTarget::ResourceMakeCurrent() {
return [EAGLContext setCurrentContext:resource_context_.get()];
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSGLRenderTarget::ResourceMakeCurrent() {
return renderer_context_switch_manager_->ResourceMakeCurrent();
}
} // namespace flutter

View File

@ -12,6 +12,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/surface.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.h"
namespace flutter {
@ -27,7 +28,8 @@ class IOSSurface {
virtual bool IsValid() const = 0;
virtual bool ResourceContextMakeCurrent() = 0;
virtual std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
ResourceContextMakeCurrent() = 0;
virtual void UpdateStorageSizeIfNecessary() = 0;

View File

@ -9,6 +9,7 @@
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_context_switch_manager.h"
#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
@ -32,7 +33,8 @@ class IOSSurfaceGL final : public IOSSurface,
bool IsValid() const override;
// |IOSSurface|
bool ResourceContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> ResourceContextMakeCurrent()
override;
// |IOSSurface|
void UpdateStorageSizeIfNecessary() override;
@ -40,7 +42,8 @@ class IOSSurfaceGL final : public IOSSurface,
// |IOSSurface|
std::unique_ptr<Surface> CreateGPUSurface(GrContext* gr_context = nullptr) override;
bool GLContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> GLContextMakeCurrent()
override;
bool GLContextClearCurrent() override;
@ -53,6 +56,9 @@ class IOSSurfaceGL final : public IOSSurface,
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager> GetRendererContextSwitchManager() override;
// |ExternalViewEmbedder|
SkCanvas* GetRootCanvas() override;

View File

@ -28,7 +28,8 @@ bool IOSSurfaceGL::IsValid() const {
return render_target_->IsValid();
}
bool IOSSurfaceGL::ResourceContextMakeCurrent() {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSSurfaceGL::ResourceContextMakeCurrent() {
return context_->ResourceMakeCurrent();
}
@ -56,11 +57,12 @@ bool IOSSurfaceGL::UseOffscreenSurface() const {
return true;
}
bool IOSSurfaceGL::GLContextMakeCurrent() {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSSurfaceGL::GLContextMakeCurrent() {
if (!IsValid()) {
return false;
return std::make_unique<RendererContextSwitchManager::RendererContextSwitchPureResult>(false);
}
return render_target_->UpdateStorageSizeIfNecessary() && context_->MakeCurrent();
return render_target_->MakeCurrent();
}
bool IOSSurfaceGL::GLContextClearCurrent() {
@ -73,6 +75,11 @@ bool IOSSurfaceGL::GLContextPresent() {
return IsValid() && render_target_->PresentRenderBuffer();
}
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager> IOSSurfaceGL::GetRendererContextSwitchManager() {
return context_->GetIOSGLContextSwitchManager();
}
// |ExternalViewEmbedder|
SkCanvas* IOSSurfaceGL::GetRootCanvas() {
// On iOS, the root surface is created from the on-screen render target. Only the surfaces for the
@ -144,7 +151,8 @@ bool IOSSurfaceGL::SubmitFrame(GrContext* context) {
if (platform_views_controller == nullptr) {
return true;
}
platform_views_controller->SetRendererContextSwitchManager(
context_->GetIOSGLContextSwitchManager());
bool submitted = platform_views_controller->SubmitFrame(std::move(context), context_);
[CATransaction commit];
return submitted;

View File

@ -30,7 +30,8 @@ class IOSSurfaceMetal final : public IOSSurface,
bool IsValid() const override;
// |IOSSurface|
bool ResourceContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> ResourceContextMakeCurrent()
override;
// |IOSSurface|
void UpdateStorageSizeIfNecessary() override;

View File

@ -22,8 +22,9 @@ bool IOSSurfaceMetal::IsValid() const {
}
// |IOSSurface|
bool IOSSurfaceMetal::ResourceContextMakeCurrent() {
return false;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSSurfaceMetal::ResourceContextMakeCurrent() {
return std::make_unique<RendererContextSwitchManager::RendererContextSwitchPureResult>(false);
}
// |IOSSurface|

View File

@ -8,9 +8,9 @@
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/renderer_context_switch_manager.h"
#include "flutter/shell/gpu/gpu_surface_software.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
@class CALayer;
namespace flutter {
@ -28,7 +28,8 @@ class IOSSurfaceSoftware final : public IOSSurface,
bool IsValid() const override;
// |IOSSurface|
bool ResourceContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> ResourceContextMakeCurrent()
override;
// |IOSSurface|
void UpdateStorageSizeIfNecessary() override;

View File

@ -27,8 +27,9 @@ bool IOSSurfaceSoftware::IsValid() const {
return layer_;
}
bool IOSSurfaceSoftware::ResourceContextMakeCurrent() {
return false;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
IOSSurfaceSoftware::ResourceContextMakeCurrent() {
return std::make_unique<RendererContextSwitchManager::RendererContextSwitchPureResult>(false);
}
void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() {

View File

@ -107,15 +107,18 @@ std::unique_ptr<Surface> PlatformViewIOS::CreateRenderingSurface() {
// |PlatformView|
sk_sp<GrContext> PlatformViewIOS::CreateResourceContext() const {
FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread());
if (!gl_context_ || !gl_context_->ResourceMakeCurrent()) {
FML_DLOG(INFO) << "Could not make resource context current on IO thread. "
"Async texture uploads will be disabled. On Simulators, "
"this is expected.";
return nullptr;
if (gl_context_ != nullptr) {
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch> context_switch =
gl_context_->ResourceMakeCurrent();
if (context_switch->GetSwitchResult()) {
return ShellIOManager::CreateCompatibleResourceLoadingContext(
GrBackend::kOpenGL_GrBackend, GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface());
}
}
return ShellIOManager::CreateCompatibleResourceLoadingContext(
GrBackend::kOpenGL_GrBackend, GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface());
FML_DLOG(INFO) << "Could not make resource context current on IO thread. "
"Async texture uploads will be disabled. On Simulators, "
"this is expected.";
return nullptr;
}
// |PlatformView|

View File

@ -34,8 +34,11 @@ bool EmbedderSurfaceGL::IsValid() const {
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGL::GLContextMakeCurrent() {
return gl_dispatch_table_.gl_make_current_callback();
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
EmbedderSurfaceGL::GLContextMakeCurrent() {
return std::make_unique<
RendererContextSwitchManager::RendererContextSwitchPureResult>(
gl_dispatch_table_.gl_make_current_callback());
}
// |GPUSurfaceGLDelegate|
@ -79,6 +82,12 @@ EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const {
return gl_dispatch_table_.gl_proc_resolver;
}
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager>
EmbedderSurfaceGL::GetRendererContextSwitchManager() {
return nullptr;
}
// |EmbedderSurface|
std::unique_ptr<Surface> EmbedderSurfaceGL::CreateGPUSurface() {
const bool render_to_surface = !external_view_embedder_;

View File

@ -50,7 +50,8 @@ class EmbedderSurfaceGL final : public EmbedderSurface,
sk_sp<GrContext> CreateResourceContext() const override;
// |GPUSurfaceGLDelegate|
bool GLContextMakeCurrent() override;
std::unique_ptr<RendererContextSwitchManager::RendererContextSwitch>
GLContextMakeCurrent() override;
// |GPUSurfaceGLDelegate|
bool GLContextClearCurrent() override;
@ -73,6 +74,10 @@ class EmbedderSurfaceGL final : public EmbedderSurface,
// |GPUSurfaceGLDelegate|
GLProcResolver GetGLProcResolver() const override;
// |GPUSurfaceGLDelegate|
std::shared_ptr<RendererContextSwitchManager>
GetRendererContextSwitchManager() override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceGL);
};

View File

@ -40,6 +40,8 @@
6816DBAC2318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA72318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png */; };
6816DBAD2318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */; };
6816DBAE2318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */; };
68396B28235FA0D700D5E655 /* GLTestPlatformView.m in Sources */ = {isa = PBXBuildFile; fileRef = 68396B27235FA0D700D5E655 /* GLTestPlatformView.m */; };
68396B2A235FBEA600D5E655 /* PlatformViewGLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68396B29235FBEA600D5E655 /* PlatformViewGLTests.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -136,6 +138,9 @@
6816DBA72318696600A51400 /* golden_platform_view_opacity_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_opacity_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA82318696600A51400 /* golden_platform_view_cliprect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
6816DBA92318696600A51400 /* golden_platform_view_cliprrect_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_cliprrect_iPhone SE_simulator.png"; sourceTree = "<group>"; };
68396B26235FA0D700D5E655 /* GLTestPlatformView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GLTestPlatformView.h; sourceTree = "<group>"; };
68396B27235FA0D700D5E655 /* GLTestPlatformView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GLTestPlatformView.m; sourceTree = "<group>"; };
68396B29235FBEA600D5E655 /* PlatformViewGLTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformViewGLTests.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -202,6 +207,8 @@
0A57B3BC2323C4BD00DD9521 /* ScreenBeforeFlutter.m */,
0A57B3BE2323C74200DD9521 /* FlutterEngine+ScenariosTest.m */,
0A57B3C02323C74D00DD9521 /* FlutterEngine+ScenariosTest.h */,
68396B26235FA0D700D5E655 /* GLTestPlatformView.h */,
68396B27235FA0D700D5E655 /* GLTestPlatformView.m */,
);
path = Scenarios;
sourceTree = "<group>";
@ -239,6 +246,7 @@
6816DBA02317573300A51400 /* GoldenImage.m */,
6816DBA22318358200A51400 /* PlatformViewGoldenTestManager.h */,
6816DBA32318358200A51400 /* PlatformViewGoldenTestManager.m */,
68396B29235FBEA600D5E655 /* PlatformViewGLTests.m */,
);
path = ScenariosUITests;
sourceTree = "<group>";
@ -398,6 +406,7 @@
files = (
248D76DA22E388380012F0C1 /* main.m in Sources */,
24F1FB89230B4579005ACE7C /* TextPlatformView.m in Sources */,
68396B28235FA0D700D5E655 /* GLTestPlatformView.m in Sources */,
248D76CC22E388370012F0C1 /* AppDelegate.m in Sources */,
0A57B3BF2323C74200DD9521 /* FlutterEngine+ScenariosTest.m in Sources */,
0A57B3BD2323C4BD00DD9521 /* ScreenBeforeFlutter.m in Sources */,
@ -418,6 +427,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
68396B2A235FBEA600D5E655 /* PlatformViewGLTests.m in Sources */,
6816DBA12317573300A51400 /* GoldenImage.m in Sources */,
6816DB9E231750ED00A51400 /* GoldenPlatformViewTests.m in Sources */,
6816DBA42318358200A51400 /* PlatformViewGoldenTestManager.m in Sources */,
@ -492,7 +502,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@ -545,7 +555,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -561,6 +571,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
@ -584,6 +595,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",

View File

@ -27,6 +27,15 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "248D76C622E388370012F0C1"
BuildableName = "Scenarios.app"
BlueprintName = "Scenarios"
ReferencedContainer = "container:Scenarios.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
@ -51,17 +60,6 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "248D76C622E388370012F0C1"
BuildableName = "Scenarios.app"
BlueprintName = "Scenarios"
ReferencedContainer = "container:Scenarios.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -93,8 +91,6 @@
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -4,6 +4,7 @@
#include "AppDelegate.h"
#import "FlutterEngine+ScenariosTest.h"
#import "GLTestPlatformView.h"
#import "ScreenBeforeFlutter.h"
#import "TextPlatformView.h"
@ -50,6 +51,8 @@
[self readyContextForPlatformViewTests:goldenTestName];
} else if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--screen-before-flutter"]) {
self.window.rootViewController = [[ScreenBeforeFlutter alloc] initWithEngineRunCompletion:nil];
} else if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--platform-view-gl"]) {
[self readyContextForGLPlatformViewTests:@"platform_view_eaglcontext"];
} else {
self.window.rootViewController = [[UIViewController alloc] init];
}
@ -79,4 +82,25 @@
self.window.rootViewController = flutterViewController;
}
- (void)readyContextForGLPlatformViewTests:(NSString*)scenarioIdentifier {
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"PlatformViewTest" project:nil];
[engine runWithEntrypoint:nil];
FlutterViewController* flutterViewController =
[[NoStatusBarFlutterViewController alloc] initWithEngine:engine nibName:nil bundle:nil];
[engine.binaryMessenger
setMessageHandlerOnChannel:@"scenario_status"
binaryMessageHandler:^(NSData* _Nullable message, FlutterBinaryReply _Nonnull reply) {
[engine.binaryMessenger
sendOnChannel:@"set_scenario"
message:[scenarioIdentifier dataUsingEncoding:NSUTF8StringEncoding]];
}];
GLTestPlatformViewFactory* platformViewFactory =
[[GLTestPlatformViewFactory alloc] initWithMessenger:flutterViewController.binaryMessenger];
NSObject<FlutterPluginRegistrar>* registrar =
[flutterViewController.engine registrarForPlugin:@"scenarios/glTestPlatformViewPlugin"];
[registrar registerViewFactory:platformViewFactory withId:@"scenarios/glTestPlatformView"];
self.window.rootViewController = flutterViewController;
}
@end

View File

@ -0,0 +1,30 @@
// Copyright 2019 The Chromium 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/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GLTestPlatformView : NSObject <FlutterPlatformView>
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
- (UIView*)view;
@end
@interface GLTestPlatformViewFactory : NSObject <FlutterPlatformViewFactory>
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
@end
@interface GLTestView : UIView
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,90 @@
// Copyright 2019 The Chromium 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 "GLTestPlatformView.h"
#define GLES_SILENCE_DEPRECATION
@implementation GLTestPlatformView {
int64_t _viewId;
GLTestView* _view;
}
- (instancetype)initWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id)args
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
if ([super init]) {
_viewId = viewId;
_view = [[GLTestView alloc] initWithFrame:CGRectMake(50.0, 50.0, 250.0, 100.0)];
}
return self;
}
- (UIView*)view {
return _view;
}
@end
@implementation GLTestPlatformViewFactory {
NSObject<FlutterBinaryMessenger>* _messenger;
}
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
self = [super init];
if (self) {
_messenger = messenger;
}
return self;
}
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
viewIdentifier:(int64_t)viewId
arguments:(id _Nullable)args {
GLTestPlatformView* platformView = [[GLTestPlatformView alloc] initWithFrame:frame
viewIdentifier:viewId
arguments:args
binaryMessenger:_messenger];
return platformView;
}
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
return [FlutterStringCodec sharedInstance];
}
@end
@interface GLTestView ()
@property(strong, nonatomic) EAGLContext* context;
@end
@implementation GLTestView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
_context.debugLabel = @"platform view context";
[EAGLContext setCurrentContext:_context];
self.backgroundColor = [UIColor redColor];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self checkEAGLContext];
});
}
return self;
}
- (void)checkEAGLContext {
if ([EAGLContext currentContext] != _context) {
self.accessibilityIdentifier = @"gl_platformview_wrong_context";
} else {
self.accessibilityIdentifier = @"gl_platformview_correct_context";
}
}
@end

View File

@ -0,0 +1,39 @@
// 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 <XCTest/XCTest.h>
@interface PlatformViewGLTests : XCTestCase
@property(nonatomic, strong) XCUIApplication* application;
@end
@implementation PlatformViewGLTests
- (void)setUp {
self.continueAfterFailure = NO;
self.application = [[XCUIApplication alloc] init];
self.application.launchArguments = @[ @"--platform-view-gl" ];
[self.application launch];
}
- (void)testExample {
NSPredicate* predicateToFindPlatformView =
[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject,
NSDictionary<NSString*, id>* _Nullable bindings) {
XCUIElement* element = evaluatedObject;
return [element.identifier isEqualToString:@"gl_platformview_wrong_context"] ||
[element.identifier isEqualToString:@"gl_platformview_correct_context"];
}];
XCUIElement* firstElement =
[self.application.otherElements elementMatchingPredicate:predicateToFindPlatformView];
if (![firstElement waitForExistenceWithTimeout:30]) {
XCTFail(@"Failed due to not able to find platform view with 30 seconds");
}
XCTAssertEqualObjects(firstElement.identifier, @"gl_platformview_correct_context");
}
@end

View File

@ -25,6 +25,7 @@ Map<String, Scenario> _scenarios = <String, Scenario>{
'platform_view_multiple': MultiPlatformViewScenario(window, firstId: 6, secondId: 7),
'platform_view_multiple_background_foreground': MultiPlatformViewBackgroundForegroundScenario(window, firstId: 8, secondId: 9),
'poppable_screen': PoppableScreenScenario(window),
'platform_view_eaglcontext': PlatformViewGLScenario(window, 'null', id:6),
};
Scenario _currentScenario = _scenarios['animated_color_square'];

View File

@ -34,7 +34,7 @@ class PlatformViewScenario extends Scenario with _BasePlatformViewScenarioMixin
PlatformViewScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
createPlatformView(window, text, id, 'scenarios/textPlatformView');
}
@override
@ -55,8 +55,8 @@ class MultiPlatformViewScenario extends Scenario with _BasePlatformViewScenarioM
MultiPlatformViewScenario(Window window, {this.firstId, this.secondId})
: assert(window != null),
super(window) {
createPlatformView(window, 'platform view 1', firstId);
createPlatformView(window, 'platform view 2', secondId);
createPlatformView(window, 'platform view 1', firstId, 'scenarios/textPlatformView');
createPlatformView(window, 'platform view 2', secondId, 'scenarios/textPlatformView');
}
/// The platform view identifier to use for the first platform view.
@ -91,8 +91,8 @@ class MultiPlatformViewBackgroundForegroundScenario extends Scenario with _BaseP
MultiPlatformViewBackgroundForegroundScenario(Window window, {this.firstId, this.secondId})
: assert(window != null),
super(window) {
createPlatformView(window, 'platform view 1', firstId);
createPlatformView(window, 'platform view 2', secondId);
createPlatformView(window, 'platform view 1', firstId, 'scenarios/textPlatformView');
createPlatformView(window, 'platform view 2', secondId, 'scenarios/textPlatformView');
_nextFrame = _firstFrame;
}
@ -177,7 +177,7 @@ class PlatformViewClipRectScenario extends Scenario with _BasePlatformViewScenar
PlatformViewClipRectScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id);
createPlatformView(window, text, id, 'scenarios/textPlatformView');
}
@override
@ -281,6 +281,24 @@ class PlatformViewOpacityScenario extends PlatformViewScenario {
}
}
/// Platform view scenario for testing EAGLContext on iOS.
class PlatformViewGLScenario extends Scenario with _BasePlatformViewScenarioMixin {
/// Constructs a platform view to test EAGLContext on iOS.
PlatformViewGLScenario(Window window, String text, {int id = 0})
: assert(window != null),
super(window) {
createPlatformView(window, text, id, 'scenarios/glTestPlatformView');
}
@override
void onBeginFrame(Duration duration) {
final SceneBuilder builder = SceneBuilder();
builder.pushOffset(0, 0);
finishBuilderByAddingPlatformViewAndPicture(builder, 6);
}
}
mixin _BasePlatformViewScenarioMixin on Scenario {
int _textureId;
@ -289,7 +307,7 @@ mixin _BasePlatformViewScenarioMixin on Scenario {
/// It prepare a TextPlatformView so it can be added to the SceneBuilder in `onBeginFrame`.
/// Call this method in the constructor of the platform view related scenarios
/// to perform necessary set up.
void createPlatformView(Window window, String text, int id) {
void createPlatformView(Window window, String text, int id, String viewType) {
const int _valueInt32 = 3;
const int _valueFloat64 = 6;
const int _valueString = 7;
@ -313,8 +331,8 @@ mixin _BasePlatformViewScenarioMixin on Scenario {
'viewType'.length,
...utf8.encode('viewType'),
_valueString,
'scenarios/textPlatformView'.length,
...utf8.encode('scenarios/textPlatformView'),
viewType.length,
...utf8.encode(viewType),
if (Platform.isAndroid) ...<int>[
_valueString,
'width'.length,