mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Improve iOS PlatformViews to better handle thread merging. (flutter/engine#16935)
This commit is contained in:
parent
0fafb9d02e
commit
930696bbb7
@ -592,6 +592,8 @@ FILE: ../../../flutter/shell/common/shell_io_manager.cc
|
||||
FILE: ../../../flutter/shell/common/shell_io_manager.h
|
||||
FILE: ../../../flutter/shell/common/shell_test.cc
|
||||
FILE: ../../../flutter/shell/common/shell_test.h
|
||||
FILE: ../../../flutter/shell/common/shell_test_external_view_embedder.cc
|
||||
FILE: ../../../flutter/shell/common/shell_test_external_view_embedder.h
|
||||
FILE: ../../../flutter/shell/common/shell_test_platform_view.cc
|
||||
FILE: ../../../flutter/shell/common/shell_test_platform_view.h
|
||||
FILE: ../../../flutter/shell/common/shell_test_platform_view_gl.cc
|
||||
|
||||
@ -253,6 +253,18 @@ class ExternalViewEmbedder {
|
||||
// This is called after submitting the embedder frame and the surface frame.
|
||||
virtual void FinishFrame();
|
||||
|
||||
// This should only be called after |SubmitFrame|.
|
||||
// This method provides the embedder a way to do additional tasks after
|
||||
// |SubmitFrame|. After invoking this method, the current task on the
|
||||
// TaskRunner should end immediately.
|
||||
//
|
||||
// For example on the iOS embedder, threads are merged in this call.
|
||||
// A new frame on the platform thread starts immediately. If the GPU thread
|
||||
// still has some task running, there could be two frames being rendered
|
||||
// concurrently, which causes undefined behaviors.
|
||||
virtual void EndFrame(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {}
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ExternalViewEmbedder);
|
||||
|
||||
}; // ExternalViewEmbedder
|
||||
|
||||
@ -191,6 +191,8 @@ if (enable_unittests) {
|
||||
"pipeline_unittests.cc",
|
||||
"shell_test.cc",
|
||||
"shell_test.h",
|
||||
"shell_test_external_view_embedder.cc",
|
||||
"shell_test_external_view_embedder.h",
|
||||
"shell_test_platform_view.cc",
|
||||
"shell_test_platform_view.h",
|
||||
"shell_unittests.cc",
|
||||
|
||||
@ -55,7 +55,7 @@ TEST_F(ShellTest, VSyncTargetTime) {
|
||||
return ShellTestPlatformView::Create(
|
||||
shell, shell.GetTaskRunners(), vsync_clock,
|
||||
std::move(create_vsync_waiter),
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend);
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend, nullptr);
|
||||
},
|
||||
[](Shell& shell) {
|
||||
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
|
||||
|
||||
@ -136,6 +136,16 @@ void Rasterizer::Draw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
|
||||
consume_result = PipelineConsumeResult::MoreAvailable;
|
||||
}
|
||||
|
||||
// Merging the thread as we know the next `Draw` should be run on the platform
|
||||
// thread.
|
||||
if (raster_status == RasterStatus::kResubmit) {
|
||||
auto* external_view_embedder = surface_->GetExternalViewEmbedder();
|
||||
// We know only the `external_view_embedder` can
|
||||
// causes|RasterStatus::kResubmit|. Check to make sure.
|
||||
FML_DCHECK(external_view_embedder != nullptr);
|
||||
external_view_embedder->EndFrame(raster_thread_merger_);
|
||||
}
|
||||
|
||||
// Consume as many pipeline items as possible. But yield the event loop
|
||||
// between successive tries.
|
||||
switch (consume_result) {
|
||||
|
||||
@ -260,9 +260,12 @@ std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
|
||||
simulate_vsync);
|
||||
}
|
||||
|
||||
std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
|
||||
TaskRunners task_runners,
|
||||
bool simulate_vsync) {
|
||||
std::unique_ptr<Shell> ShellTest::CreateShell(
|
||||
Settings settings,
|
||||
TaskRunners task_runners,
|
||||
bool simulate_vsync,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder) {
|
||||
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
|
||||
CreateVsyncWaiter create_vsync_waiter = [&]() {
|
||||
if (simulate_vsync) {
|
||||
@ -275,17 +278,18 @@ std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
|
||||
};
|
||||
return Shell::Create(
|
||||
task_runners, settings,
|
||||
[vsync_clock, &create_vsync_waiter](Shell& shell) {
|
||||
[vsync_clock, &create_vsync_waiter,
|
||||
shell_test_external_view_embedder](Shell& shell) {
|
||||
return ShellTestPlatformView::Create(
|
||||
shell, shell.GetTaskRunners(), vsync_clock,
|
||||
std::move(create_vsync_waiter),
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend);
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend,
|
||||
shell_test_external_view_embedder);
|
||||
},
|
||||
[](Shell& shell) {
|
||||
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
|
||||
});
|
||||
}
|
||||
|
||||
void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
|
||||
DestroyShell(std::move(shell), GetTaskRunnersForFixture());
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "flutter/lib/ui/window/platform_message.h"
|
||||
#include "flutter/shell/common/run_configuration.h"
|
||||
#include "flutter/shell/common/shell.h"
|
||||
#include "flutter/shell/common/shell_test_external_view_embedder.h"
|
||||
#include "flutter/shell/common/thread_host.h"
|
||||
#include "flutter/shell/common/vsync_waiters_test.h"
|
||||
#include "flutter/testing/elf_loader.h"
|
||||
@ -31,9 +32,12 @@ class ShellTest : public ThreadTest {
|
||||
Settings CreateSettingsForFixture();
|
||||
std::unique_ptr<Shell> CreateShell(Settings settings,
|
||||
bool simulate_vsync = false);
|
||||
std::unique_ptr<Shell> CreateShell(Settings settings,
|
||||
TaskRunners task_runners,
|
||||
bool simulate_vsync = false);
|
||||
std::unique_ptr<Shell> CreateShell(
|
||||
Settings settings,
|
||||
TaskRunners task_runners,
|
||||
bool simulate_vsync = false,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder = nullptr);
|
||||
void DestroyShell(std::unique_ptr<Shell> shell);
|
||||
void DestroyShell(std::unique_ptr<Shell> shell, TaskRunners task_runners);
|
||||
TaskRunners GetTaskRunnersForFixture();
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
#include "shell_test_external_view_embedder.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::CancelFrame() {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::PrerollCompositeEmbeddedView(
|
||||
int view_id,
|
||||
std::unique_ptr<EmbeddedViewParams> params) {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
PostPrerollResult ShellTestExternalViewEmbedder::PostPrerollAction(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
FML_DCHECK(raster_thread_merger);
|
||||
return post_preroll_result_;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
std::vector<SkCanvas*> ShellTestExternalViewEmbedder::GetCurrentCanvases() {
|
||||
return {};
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
SkCanvas* ShellTestExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
bool ShellTestExternalViewEmbedder::SubmitFrame(GrContext* context,
|
||||
SkCanvas* background_canvas) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::FinishFrame() {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void ShellTestExternalViewEmbedder::EndFrame(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
end_frame_call_back_();
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
SkCanvas* ShellTestExternalViewEmbedder::GetRootCanvas() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@ -0,0 +1,72 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_SHELL_TEST_EXTERNAL_VIEW_EMBEDDER_H_
|
||||
#define FLUTTER_SHELL_TEST_EXTERNAL_VIEW_EMBEDDER_H_
|
||||
|
||||
#include "flutter/flow/embedded_views.h"
|
||||
#include "flutter/fml/raster_thread_merger.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief The external view embedder used by |ShellTestPlatformViewGL|
|
||||
///
|
||||
class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
public:
|
||||
using EndFrameCallBack = std::function<void(void)>;
|
||||
|
||||
ShellTestExternalViewEmbedder(const EndFrameCallBack& end_frame_call_back,
|
||||
PostPrerollResult post_preroll_result)
|
||||
: end_frame_call_back_(end_frame_call_back),
|
||||
post_preroll_result_(post_preroll_result) {}
|
||||
|
||||
~ShellTestExternalViewEmbedder() = default;
|
||||
|
||||
private:
|
||||
// |ExternalViewEmbedder|
|
||||
void CancelFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void BeginFrame(SkISize frame_size,
|
||||
GrContext* context,
|
||||
double device_pixel_ratio) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void PrerollCompositeEmbeddedView(
|
||||
int view_id,
|
||||
std::unique_ptr<EmbeddedViewParams> params) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
PostPrerollResult PostPrerollAction(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
std::vector<SkCanvas*> GetCurrentCanvases() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
SkCanvas* CompositeEmbeddedView(int view_id) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void FinishFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void EndFrame(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
SkCanvas* GetRootCanvas() override;
|
||||
|
||||
const EndFrameCallBack end_frame_call_back_;
|
||||
const PostPrerollResult post_preroll_result_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ShellTestExternalViewEmbedder);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_TEST_EXTERNAL_VIEW_EMBEDDER_H_
|
||||
@ -19,7 +19,9 @@ std::unique_ptr<ShellTestPlatformView> ShellTestPlatformView::Create(
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
BackendType backend) {
|
||||
BackendType backend,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder) {
|
||||
// TODO(gw280): https://github.com/flutter/flutter/issues/50298
|
||||
// Make this fully runtime configurable
|
||||
switch (backend) {
|
||||
@ -27,12 +29,14 @@ std::unique_ptr<ShellTestPlatformView> ShellTestPlatformView::Create(
|
||||
#ifdef SHELL_ENABLE_GL
|
||||
case BackendType::kGLBackend:
|
||||
return std::make_unique<ShellTestPlatformViewGL>(
|
||||
delegate, task_runners, vsync_clock, create_vsync_waiter);
|
||||
delegate, task_runners, vsync_clock, create_vsync_waiter,
|
||||
shell_test_external_view_embedder);
|
||||
#endif // SHELL_ENABLE_GL
|
||||
#ifdef SHELL_ENABLE_VULKAN
|
||||
case BackendType::kVulkanBackend:
|
||||
return std::make_unique<ShellTestPlatformViewVulkan>(
|
||||
delegate, task_runners, vsync_clock, create_vsync_waiter);
|
||||
delegate, task_runners, vsync_clock, create_vsync_waiter,
|
||||
shell_test_external_view_embedder);
|
||||
#endif // SHELL_ENABLE_VULKAN
|
||||
default:
|
||||
FML_LOG(FATAL) << "No backends supported for ShellTestPlatformView";
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_H_
|
||||
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/common/shell_test_external_view_embedder.h"
|
||||
#include "flutter/shell/common/vsync_waiters_test.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -24,7 +25,9 @@ class ShellTestPlatformView : public PlatformView {
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
BackendType backend);
|
||||
BackendType backend,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder);
|
||||
|
||||
virtual void SimulateVSync() = 0;
|
||||
|
||||
|
||||
@ -12,11 +12,14 @@ ShellTestPlatformViewGL::ShellTestPlatformViewGL(
|
||||
PlatformView::Delegate& delegate,
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter)
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder)
|
||||
: ShellTestPlatformView(delegate, std::move(task_runners)),
|
||||
gl_surface_(SkISize::Make(800, 600)),
|
||||
create_vsync_waiter_(std::move(create_vsync_waiter)),
|
||||
vsync_clock_(vsync_clock) {}
|
||||
vsync_clock_(vsync_clock),
|
||||
shell_test_external_view_embedder_(shell_test_external_view_embedder) {}
|
||||
|
||||
ShellTestPlatformViewGL::~ShellTestPlatformViewGL() = default;
|
||||
|
||||
@ -70,7 +73,7 @@ ShellTestPlatformViewGL::GetGLProcResolver() const {
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
ExternalViewEmbedder* ShellTestPlatformViewGL::GetExternalViewEmbedder() {
|
||||
return nullptr;
|
||||
return shell_test_external_view_embedder_.get();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#ifndef FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_GL_H_
|
||||
#define FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_GL_H_
|
||||
|
||||
#include "flutter/shell/common/shell_test_external_view_embedder.h"
|
||||
#include "flutter/shell/common/shell_test_platform_view.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_gl_delegate.h"
|
||||
#include "flutter/testing/test_gl_surface.h"
|
||||
@ -18,7 +19,9 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView,
|
||||
ShellTestPlatformViewGL(PlatformView::Delegate& delegate,
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter);
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder);
|
||||
|
||||
virtual ~ShellTestPlatformViewGL() override;
|
||||
|
||||
@ -31,6 +34,9 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView,
|
||||
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock_;
|
||||
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder_;
|
||||
|
||||
// |PlatformView|
|
||||
std::unique_ptr<Surface> CreateRenderingSurface() override;
|
||||
|
||||
|
||||
@ -11,11 +11,14 @@ ShellTestPlatformViewVulkan::ShellTestPlatformViewVulkan(
|
||||
PlatformView::Delegate& delegate,
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter)
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder)
|
||||
: ShellTestPlatformView(delegate, std::move(task_runners)),
|
||||
create_vsync_waiter_(std::move(create_vsync_waiter)),
|
||||
vsync_clock_(vsync_clock),
|
||||
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>()) {}
|
||||
proc_table_(fml::MakeRefCounted<vulkan::VulkanProcTable>()),
|
||||
shell_test_external_view_embedder_(shell_test_external_view_embedder) {}
|
||||
|
||||
ShellTestPlatformViewVulkan::~ShellTestPlatformViewVulkan() = default;
|
||||
|
||||
@ -29,7 +32,8 @@ void ShellTestPlatformViewVulkan::SimulateVSync() {
|
||||
|
||||
// |PlatformView|
|
||||
std::unique_ptr<Surface> ShellTestPlatformViewVulkan::CreateRenderingSurface() {
|
||||
return std::make_unique<OffScreenSurface>(proc_table_);
|
||||
return std::make_unique<OffScreenSurface>(proc_table_,
|
||||
shell_test_external_view_embedder_);
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
@ -44,8 +48,12 @@ PointerDataDispatcherMaker ShellTestPlatformViewVulkan::GetDispatcherMaker() {
|
||||
// We need to merge this functionality back into //vulkan.
|
||||
// https://github.com/flutter/flutter/issues/51132
|
||||
ShellTestPlatformViewVulkan::OffScreenSurface::OffScreenSurface(
|
||||
fml::RefPtr<vulkan::VulkanProcTable> vk)
|
||||
: valid_(false), vk_(std::move(vk)) {
|
||||
fml::RefPtr<vulkan::VulkanProcTable> vk,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder)
|
||||
: valid_(false),
|
||||
vk_(std::move(vk)),
|
||||
shell_test_external_view_embedder_(shell_test_external_view_embedder) {
|
||||
if (!vk_ || !vk_->HasAcquiredMandatoryProcAddresses()) {
|
||||
FML_DLOG(ERROR) << "Proc table has not acquired mandatory proc addresses.";
|
||||
return;
|
||||
@ -170,5 +178,10 @@ SkMatrix ShellTestPlatformViewVulkan::OffScreenSurface::GetRootTransformation()
|
||||
return matrix;
|
||||
}
|
||||
|
||||
flutter::ExternalViewEmbedder*
|
||||
ShellTestPlatformViewVulkan::OffScreenSurface::GetExternalViewEmbedder() {
|
||||
return shell_test_external_view_embedder_.get();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#ifndef FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_VULKAN_H_
|
||||
#define FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_VULKAN_H_
|
||||
|
||||
#include "flutter/shell/common/shell_test_external_view_embedder.h"
|
||||
#include "flutter/shell/common/shell_test_platform_view.h"
|
||||
#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h"
|
||||
#include "flutter/vulkan/vulkan_application.h"
|
||||
@ -18,7 +19,9 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView {
|
||||
ShellTestPlatformViewVulkan(PlatformView::Delegate& delegate,
|
||||
TaskRunners task_runners,
|
||||
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
|
||||
CreateVsyncWaiter create_vsync_waiter);
|
||||
CreateVsyncWaiter create_vsync_waiter,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder);
|
||||
|
||||
~ShellTestPlatformViewVulkan() override;
|
||||
|
||||
@ -27,7 +30,9 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView {
|
||||
private:
|
||||
class OffScreenSurface : public flutter::Surface {
|
||||
public:
|
||||
OffScreenSurface(fml::RefPtr<vulkan::VulkanProcTable> vk);
|
||||
OffScreenSurface(fml::RefPtr<vulkan::VulkanProcTable> vk,
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder);
|
||||
|
||||
~OffScreenSurface() override;
|
||||
|
||||
@ -42,9 +47,13 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView {
|
||||
// |Surface|
|
||||
GrContext* GetContext() override;
|
||||
|
||||
flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override;
|
||||
|
||||
private:
|
||||
bool valid_;
|
||||
fml::RefPtr<vulkan::VulkanProcTable> vk_;
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder_;
|
||||
std::unique_ptr<vulkan::VulkanApplication> application_;
|
||||
std::unique_ptr<vulkan::VulkanDevice> logical_device_;
|
||||
sk_sp<GrContext> context_;
|
||||
@ -61,6 +70,9 @@ class ShellTestPlatformViewVulkan : public ShellTestPlatformView {
|
||||
|
||||
fml::RefPtr<vulkan::VulkanProcTable> proc_table_;
|
||||
|
||||
std::shared_ptr<ShellTestExternalViewEmbedder>
|
||||
shell_test_external_view_embedder_;
|
||||
|
||||
// |PlatformView|
|
||||
std::unique_ptr<Surface> CreateRenderingSurface() override;
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "flutter/shell/common/platform_view.h"
|
||||
#include "flutter/shell/common/rasterizer.h"
|
||||
#include "flutter/shell/common/shell_test.h"
|
||||
#include "flutter/shell/common/shell_test_external_view_embedder.h"
|
||||
#include "flutter/shell/common/shell_test_platform_view.h"
|
||||
#include "flutter/shell/common/switches.h"
|
||||
#include "flutter/shell/common/thread_host.h"
|
||||
@ -139,7 +140,7 @@ TEST_F(ShellTest,
|
||||
return static_cast<std::unique_ptr<VsyncWaiter>>(
|
||||
std::make_unique<VsyncWaiterFallback>(task_runners));
|
||||
},
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend);
|
||||
ShellTestPlatformView::BackendType::kDefaultBackend, nullptr);
|
||||
},
|
||||
[](Shell& shell) {
|
||||
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
|
||||
@ -466,6 +467,51 @@ TEST_F(ShellTest, FrameRasterizedCallbackIsCalled) {
|
||||
DestroyShell(std::move(shell));
|
||||
}
|
||||
|
||||
TEST_F(ShellTest,
|
||||
ExternalEmbedderEndFrameIsCalledWhenPostPrerollResultIsResubmit) {
|
||||
auto settings = CreateSettingsForFixture();
|
||||
fml::AutoResetWaitableEvent endFrameLatch;
|
||||
bool end_frame_called = false;
|
||||
auto end_frame_callback = [&] {
|
||||
end_frame_called = true;
|
||||
endFrameLatch.Signal();
|
||||
};
|
||||
auto external_view_embedder = std::make_shared<ShellTestExternalViewEmbedder>(
|
||||
end_frame_callback, PostPrerollResult::kResubmitFrame);
|
||||
auto shell = CreateShell(std::move(settings), GetTaskRunnersForFixture(),
|
||||
false, external_view_embedder);
|
||||
|
||||
// Create the surface needed by rasterizer
|
||||
PlatformViewNotifyCreated(shell.get());
|
||||
|
||||
auto configuration = RunConfiguration::InferFromSettings(settings);
|
||||
configuration.SetEntrypoint("emptyMain");
|
||||
|
||||
RunEngine(shell.get(), std::move(configuration));
|
||||
|
||||
LayerTreeBuilder builder = [&](std::shared_ptr<ContainerLayer> root) {
|
||||
SkPictureRecorder recorder;
|
||||
SkCanvas* recording_canvas =
|
||||
recorder.beginRecording(SkRect::MakeXYWH(0, 0, 80, 80));
|
||||
recording_canvas->drawRect(SkRect::MakeXYWH(0, 0, 80, 80),
|
||||
SkPaint(SkColor4f::FromColor(SK_ColorRED)));
|
||||
auto sk_picture = recorder.finishRecordingAsPicture();
|
||||
fml::RefPtr<SkiaUnrefQueue> queue = fml::MakeRefCounted<SkiaUnrefQueue>(
|
||||
this->GetCurrentTaskRunner(), fml::TimeDelta::FromSeconds(0));
|
||||
auto picture_layer = std::make_shared<PictureLayer>(
|
||||
SkPoint::Make(10, 10),
|
||||
flutter::SkiaGPUObject<SkPicture>({sk_picture, queue}), false, false);
|
||||
root->Add(picture_layer);
|
||||
};
|
||||
|
||||
PumpOneFrame(shell.get(), 100, 100, builder);
|
||||
endFrameLatch.Wait();
|
||||
|
||||
ASSERT_TRUE(end_frame_called);
|
||||
|
||||
DestroyShell(std::move(shell));
|
||||
}
|
||||
|
||||
TEST(SettingsTest, FrameTimingSetsAndGetsProperly) {
|
||||
// Ensure that all phases are in kPhases.
|
||||
ASSERT_EQ(sizeof(FrameTiming::kPhases),
|
||||
|
||||
@ -248,7 +248,7 @@ void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
|
||||
}
|
||||
|
||||
void FlutterPlatformViewsController::CancelFrame() {
|
||||
composition_order_.clear();
|
||||
composition_order_ = active_composition_order_;
|
||||
}
|
||||
|
||||
bool FlutterPlatformViewsController::HasPendingViewOperations() {
|
||||
@ -267,8 +267,9 @@ PostPrerollResult FlutterPlatformViewsController::PostPrerollAction(
|
||||
if (raster_thread_merger->IsMerged()) {
|
||||
raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration);
|
||||
} else {
|
||||
// Wait until |EndFrame| to merge the threads.
|
||||
merge_threads_ = true;
|
||||
CancelFrame();
|
||||
raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
|
||||
return PostPrerollResult::kResubmitFrame;
|
||||
}
|
||||
}
|
||||
@ -468,6 +469,21 @@ SkRect FlutterPlatformViewsController::GetPlatformViewRect(int view_id) {
|
||||
bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context,
|
||||
std::shared_ptr<IOSContext> ios_context,
|
||||
SkCanvas* background_canvas) {
|
||||
if (merge_threads_) {
|
||||
// Threads are about to be merged, we drop everything from this frame
|
||||
// and possibly resubmit the same layer tree in the next frame.
|
||||
// Before merging thread, we know the code is not running on the main thread. Assert that
|
||||
FML_DCHECK(![[NSThread currentThread] isMainThread]);
|
||||
picture_recorders_.clear();
|
||||
composition_order_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Any UIKit related code has to run on main thread.
|
||||
// When on a non-main thread, we only allow the rest of the method to run if there is no platform
|
||||
// view.
|
||||
FML_DCHECK([[NSThread currentThread] isMainThread] || views_to_dispose_.empty());
|
||||
|
||||
DisposeViews();
|
||||
|
||||
// Resolve all pending GPU operations before allocating a new surface.
|
||||
@ -578,6 +594,14 @@ void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
|
||||
}
|
||||
}
|
||||
|
||||
void FlutterPlatformViewsController::EndFrame(
|
||||
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
if (merge_threads_) {
|
||||
raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration);
|
||||
merge_threads_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<FlutterPlatformViewLayer> FlutterPlatformViewsController::GetLayer(
|
||||
GrContext* gr_context,
|
||||
std::shared_ptr<IOSContext> ios_context,
|
||||
@ -642,6 +666,8 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
return;
|
||||
}
|
||||
|
||||
FML_DCHECK([[NSThread currentThread] isMainThread]);
|
||||
|
||||
for (int64_t viewId : views_to_dispose_) {
|
||||
UIView* root_view = root_views_[viewId].get();
|
||||
[root_view removeFromSuperview];
|
||||
|
||||
@ -134,6 +134,8 @@ class FlutterPlatformViewsController {
|
||||
|
||||
void SetFrameSize(SkISize frame_size);
|
||||
|
||||
// Indicates that we don't compisite any platform views or overlays during this frame.
|
||||
// Also reverts the composition_order_ to its original state at the begining of the frame.
|
||||
void CancelFrame();
|
||||
|
||||
void PrerollCompositeEmbeddedView(int view_id,
|
||||
@ -163,6 +165,11 @@ class FlutterPlatformViewsController {
|
||||
std::shared_ptr<IOSContext> ios_context,
|
||||
SkCanvas* background_canvas);
|
||||
|
||||
// Invoked at the very end of a frame.
|
||||
// After invoking this method, nothing should happen on the current TaskRunner during the same
|
||||
// frame.
|
||||
void EndFrame(fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger);
|
||||
|
||||
void OnMethodCall(FlutterMethodCall* call, FlutterResult& result);
|
||||
|
||||
private:
|
||||
@ -273,6 +280,10 @@ class FlutterPlatformViewsController {
|
||||
void ApplyMutators(const MutatorsStack& mutators_stack, UIView* embedded_view);
|
||||
void CompositeWithParams(int view_id, const EmbeddedViewParams& params);
|
||||
|
||||
// Default to `false`.
|
||||
// If `true`, gpu thread and platform thread should be merged during |EndFrame|.
|
||||
// Always resets to `false` right after the threads are merged.
|
||||
bool merge_threads_;
|
||||
// Allocates a new FlutterPlatformViewLayer if needed, draws the pixels within the rect from
|
||||
// the picture on the layer's canvas.
|
||||
std::shared_ptr<FlutterPlatformViewLayer> GetLayer(GrContext* gr_context,
|
||||
@ -282,6 +293,7 @@ class FlutterPlatformViewsController {
|
||||
int64_t view_id,
|
||||
int64_t overlay_id);
|
||||
// Removes overlay views and platform views that aren't needed in the current frame.
|
||||
// Must run on the platform thread.
|
||||
void RemoveUnusedLayers();
|
||||
// Appends the overlay views and platform view and sets their z index based on the composition
|
||||
// order.
|
||||
|
||||
@ -83,6 +83,9 @@ class IOSSurface : public ExternalViewEmbedder {
|
||||
// |ExternalViewEmbedder|
|
||||
void FinishFrame() override;
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void EndFrame(fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override;
|
||||
|
||||
public:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(IOSSurface);
|
||||
};
|
||||
|
||||
@ -90,7 +90,12 @@ void IOSSurface::CancelFrame() {
|
||||
platform_views_controller_->CancelFrame();
|
||||
// Committing the current transaction as |BeginFrame| will create a nested
|
||||
// CATransaction otherwise.
|
||||
[CATransaction commit];
|
||||
if ([[NSThread currentThread] isMainThread]) {
|
||||
// The only time we need to commit the `CATranscation` is when
|
||||
// there are platform views in the scene, which has to be run on the
|
||||
// main thread.
|
||||
[CATransaction commit];
|
||||
}
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
@ -98,7 +103,12 @@ void IOSSurface::BeginFrame(SkISize frame_size, GrContext* context, double devic
|
||||
TRACE_EVENT0("flutter", "IOSSurface::BeginFrame");
|
||||
FML_CHECK(platform_views_controller_ != nullptr);
|
||||
platform_views_controller_->SetFrameSize(frame_size);
|
||||
[CATransaction begin];
|
||||
if ([[NSThread currentThread] isMainThread]) {
|
||||
// The only time we need to commit the `CATranscation` is when
|
||||
// there are platform views in the scene, which has to be run on the
|
||||
// main thread.
|
||||
[CATransaction begin];
|
||||
}
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
@ -141,9 +151,21 @@ bool IOSSurface::SubmitFrame(GrContext* context, SkCanvas* background_canvas) {
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void IOSSurface::FinishFrame() {
|
||||
TRACE_EVENT0("flutter", "IOSSurface::DidSubmitFrame");
|
||||
[CATransaction commit];
|
||||
void IOSSurface::EndFrame(fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
|
||||
TRACE_EVENT0("flutter", "IOSSurface::EndFrame");
|
||||
FML_CHECK(platform_views_controller_ != nullptr);
|
||||
return platform_views_controller_->EndFrame(raster_thread_merger);
|
||||
}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
void IOSSurface::FinishFrame() {
|
||||
TRACE_EVENT0("flutter", "IOSSurface::DidSubmitFrame");
|
||||
if (![[NSThread currentThread] isMainThread]) {
|
||||
return;
|
||||
}
|
||||
// The only time we need to commit the `CATranscation` is when
|
||||
// there are platform views in the scene, which has to be run on the
|
||||
// main thread.
|
||||
[CATransaction commit];
|
||||
}
|
||||
} // namespace flutter
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user