Reverts "Reland 3: Multiview pipeline (#49950)" (flutter/engine#50929)

Reverts flutter/engine#49950

Initiated by: dkwingsmt

Reason for reverting: Head redness 
```
java.lang.RuntimeException: Timeout waiting for firstFrameLatch to signal
	at dev.flutter.scenarios.ExternalTextureFlutterActivity.waitUntilFlutterRendered(ExternalTextureFlutterActivity.java:98)
	at dev.flutter.scenariosui.ScreenshotUtil.capture(ScreenshotUtil.java:122)
```

Original PR Author: dkwingsmt

Reviewed By: {loic-sharma}

This change reverts the following previous change:
Original Description:
This is the 3rd attempt to land multiview pipeline, following
https://github.com/flutter/engine/pull/47239.

The pipeline now properly implements the required logic for
`scheduleWarmUpFrame` to work in a multi-view setup, following the
preparation in https://github.com/flutter/flutter/pull/143290 and
https://github.com/flutter/engine/pull/50570.

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I signed the [CLA].
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat

Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
This commit is contained in:
auto-submit[bot] 2024-02-23 15:15:00 -08:00 committed by GitHub
parent 7fd214252c
commit c388fc8bf0
21 changed files with 153 additions and 488 deletions

View File

@ -13,31 +13,6 @@
namespace flutter {
namespace {
const char* StateToString(FrameTimingsRecorder::State state) {
#ifndef NDEBUG
switch (state) {
case FrameTimingsRecorder::State::kUninitialized:
return "kUninitialized";
case FrameTimingsRecorder::State::kVsync:
return "kVsync";
case FrameTimingsRecorder::State::kBuildStart:
return "kBuildStart";
case FrameTimingsRecorder::State::kBuildEnd:
return "kBuildEnd";
case FrameTimingsRecorder::State::kRasterStart:
return "kRasterStart";
case FrameTimingsRecorder::State::kRasterEnd:
return "kRasterEnd";
};
FML_UNREACHABLE();
#endif
return "";
}
} // namespace
std::atomic<uint64_t> FrameTimingsRecorder::frame_number_gen_ = {1};
FrameTimingsRecorder::FrameTimingsRecorder()
@ -280,8 +255,7 @@ const char* FrameTimingsRecorder::GetFrameNumberTraceArg() const {
}
void FrameTimingsRecorder::AssertInState(State state) const {
FML_DCHECK(state_ == state) << "Expected state " << StateToString(state)
<< ", actual state " << StateToString(state_);
FML_DCHECK(state_ == state);
}
} // namespace flutter

View File

@ -31,7 +31,6 @@ class FrameTimingsRecorder {
public:
/// Various states that the recorder can be in. When created the recorder is
/// in an unitialized state and transtions in sequential order of the states.
// After adding an item to this enum, modify StateToString accordingly.
enum class State : uint32_t {
kUninitialized,
kVsync,
@ -122,8 +121,6 @@ class FrameTimingsRecorder {
///
/// Instead of adding a `GetState` method and asserting on the result, this
/// method prevents other logic from relying on the state.
///
/// In release builds, this call is a no-op.
void AssertInState(State state) const;
private:

View File

@ -5,7 +5,6 @@
#define FML_USED_ON_EMBEDDER
#include "flutter/common/task_runners.h"
#include "flutter/fml/synchronization/count_down_latch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/lib/ui/painting/canvas.h"
#include "flutter/lib/ui/painting/image.h"
@ -58,10 +57,6 @@ TEST_F(ImageDisposeTest, ImageReleasedAfterFrameAndDisposePictureAndLayer) {
};
Settings settings = CreateSettingsForFixture();
fml::CountDownLatch frame_latch{2};
settings.frame_rasterized_callback = [&frame_latch](const FrameTiming& t) {
frame_latch.CountDown();
};
auto task_runner = CreateNewThread();
TaskRunners task_runners("test", // label
GetCurrentTaskRunner(), // platform
@ -88,15 +83,12 @@ TEST_F(ImageDisposeTest, ImageReleasedAfterFrameAndDisposePictureAndLayer) {
shell->RunEngine(std::move(configuration), [&](auto result) {
ASSERT_EQ(result, Engine::RunStatus::Success);
});
message_latch_.Wait();
ASSERT_TRUE(current_display_list_);
ASSERT_TRUE(current_image_);
// Wait for 2 frames to be rasterized. The 2nd frame releases resources of the
// 1st frame.
frame_latch.Wait();
// Force a drain the SkiaUnrefQueue. The engine does this normally as frames
// pump, but we force it here to make the test more deterministic.
message_latch_.Reset();

View File

@ -453,9 +453,12 @@ void PlatformConfigurationNativeApi::Render(int64_t view_id,
Scene* scene,
double width,
double height) {
// TODO(dkwingsmt): Currently only supports a single window.
// See https://github.com/flutter/flutter/issues/135530, item 2.
FML_DCHECK(view_id == kFlutterImplicitViewId);
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()->platform_configuration()->client()->Render(
view_id, scene, width, height);
scene, width, height);
}
void PlatformConfigurationNativeApi::SetNeedsReportTimings(bool value) {

View File

@ -76,10 +76,7 @@ class PlatformConfigurationClient {
/// @brief Updates the client's rendering on the GPU with the newly
/// provided Scene.
///
virtual void Render(int64_t view_id,
Scene* scene,
double width,
double height) = 0;
virtual void Render(Scene* scene, double width, double height) = 0;
//--------------------------------------------------------------------------
/// @brief Receives an updated semantics tree from the Framework.

View File

@ -340,21 +340,21 @@ void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
// |PlatformConfigurationClient|
void RuntimeController::EndWarmUpFrame() {
client_.EndWarmUpFrame();
}
// |PlatformConfigurationClient|
void RuntimeController::Render(int64_t view_id,
Scene* scene,
double width,
double height) {
void RuntimeController::Render(Scene* scene, double width, double height) {
// TODO(dkwingsmt): Currently only supports a single window.
int64_t view_id = kFlutterImplicitViewId;
const ViewportMetrics* view_metrics =
UIDartState::Current()->platform_configuration()->GetMetrics(view_id);
if (view_metrics == nullptr) {
return;
}
client_.Render(view_id, scene->takeLayerTree(width, height),
client_.Render(scene->takeLayerTree(width, height),
view_metrics->device_pixel_ratio);
}

View File

@ -661,10 +661,7 @@ class RuntimeController : public PlatformConfigurationClient {
void EndWarmUpFrame() override;
// |PlatformConfigurationClient|
void Render(int64_t view_id,
Scene* scene,
double width,
double height) override;
void Render(Scene* scene, double width, double height) override;
// |PlatformConfigurationClient|
void UpdateSemantics(SemanticsUpdate* update) override;

View File

@ -27,8 +27,7 @@ class RuntimeDelegate {
virtual void EndWarmUpFrame() = 0;
virtual void Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
virtual void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) = 0;
virtual void UpdateSemantics(SemanticsNodeUpdates update,

View File

@ -62,10 +62,6 @@ void Animator::BeginFrame(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending",
frame_request_number_);
// Clear layer trees rendered out of a frame. Only Animator::Render called
// within a frame is used.
layer_trees_tasks_.clear();
frame_request_number_++;
frame_timings_recorder_ = std::move(frame_timings_recorder);
@ -116,33 +112,6 @@ void Animator::BeginFrame(
dart_frame_deadline_ = frame_target_time.ToEpochDelta();
uint64_t frame_number = frame_timings_recorder_->GetFrameNumber();
delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
}
void Animator::EndFrame() {
FML_DCHECK(frame_timings_recorder_ != nullptr);
if (!layer_trees_tasks_.empty()) {
// The build is completed in OnAnimatorBeginFrame.
frame_timings_recorder_->RecordBuildEnd(fml::TimePoint::Now());
delegate_.OnAnimatorUpdateLatestFrameTargetTime(
frame_timings_recorder_->GetVsyncTargetTime());
// Commit the pending continuation.
PipelineProduceResult result =
producer_continuation_.Complete(std::make_unique<FrameItem>(
std::move(layer_trees_tasks_), std::move(frame_timings_recorder_)));
if (!result.success) {
FML_DLOG(INFO) << "Failed to commit to the pipeline";
} else if (!result.is_first_item) {
// Do nothing. It has been successfully pushed to the pipeline but not as
// the first item. Eventually the 'Rasterizer' will consume it, so we
// don't need to notify the delegate.
} else {
delegate_.OnAnimatorDraw(layer_tree_pipeline_);
}
}
frame_timings_recorder_ = nullptr;
if (!frame_scheduled_ && has_rendered_) {
// Wait a tad more than 3 60hz frames before reporting a big idle period.
@ -170,18 +139,14 @@ void Animator::EndFrame() {
},
kNotifyIdleTaskWaitTime);
}
FML_DCHECK(layer_trees_tasks_.empty());
FML_DCHECK(frame_timings_recorder_ == nullptr);
}
void Animator::Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
void Animator::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) {
has_rendered_ = true;
if (!frame_timings_recorder_) {
// Framework can directly call render with a built scene. A major reason is
// to render warm up frames.
// Framework can directly call render with a built scene.
frame_timings_recorder_ = std::make_unique<FrameTimingsRecorder>();
const fml::TimePoint placeholder_time = fml::TimePoint::Now();
frame_timings_recorder_->RecordVsync(placeholder_time, placeholder_time);
@ -191,9 +156,35 @@ void Animator::Render(int64_t view_id,
TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder_, "flutter",
"Animator::Render", /*flow_id_count=*/0,
/*flow_ids=*/nullptr);
frame_timings_recorder_->RecordBuildEnd(fml::TimePoint::Now());
layer_trees_tasks_.push_back(std::make_unique<LayerTreeTask>(
delegate_.OnAnimatorUpdateLatestFrameTargetTime(
frame_timings_recorder_->GetVsyncTargetTime());
// TODO(dkwingsmt): Currently only supports a single window.
// See https://github.com/flutter/flutter/issues/135530, item 2.
int64_t view_id = kFlutterImplicitViewId;
std::vector<std::unique_ptr<LayerTreeTask>> layer_trees_tasks;
layer_trees_tasks.push_back(std::make_unique<LayerTreeTask>(
view_id, std::move(layer_tree), device_pixel_ratio));
// Commit the pending continuation.
PipelineProduceResult result =
producer_continuation_.Complete(std::make_unique<FrameItem>(
std::move(layer_trees_tasks), std::move(frame_timings_recorder_)));
if (!result.success) {
FML_DLOG(INFO) << "No pending continuation to commit";
return;
}
if (!result.is_first_item) {
// It has been successfully pushed to the pipeline but not as the first
// item. Eventually the 'Rasterizer' will consume it, so we don't need to
// notify the delegate.
return;
}
delegate_.OnAnimatorDraw(layer_tree_pipeline_);
}
const std::weak_ptr<VsyncWaiter> Animator::GetVsyncWaiter() const {
@ -265,7 +256,6 @@ void Animator::AwaitVSync() {
self->DrawLastLayerTrees(std::move(frame_timings_recorder));
} else {
self->BeginFrame(std::move(frame_timings_recorder));
self->EndFrame();
}
}
});
@ -275,9 +265,9 @@ void Animator::AwaitVSync() {
}
void Animator::EndWarmUpFrame() {
if (!layer_trees_tasks_.empty()) {
EndFrame();
}
// Do nothing. The warm up frame does not need any additional work to end the
// frame for now. This will change once the pipeline supports multi-view.
// https://github.com/flutter/flutter/issues/142851
}
void Animator::ScheduleSecondaryVsyncCallback(uintptr_t id,

View File

@ -76,8 +76,7 @@ class Animator final {
/// technically, between Animator::BeginFrame and Animator::EndFrame
/// (both private methods). Otherwise, this call will be ignored.
///
void Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio);
const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const;
@ -106,13 +105,7 @@ class Animator final {
void EnqueueTraceFlowId(uint64_t trace_flow_id);
private:
// Animator's work during a vsync is split into two methods, BeginFrame and
// EndFrame. The two methods should be called synchronously back-to-back to
// avoid being interrupted by a regular vsync. The reason to split them is to
// allow ShellTest::PumpOneFrame to insert a Render in between.
void BeginFrame(std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder);
void EndFrame();
bool CanReuseLastLayerTrees();
@ -129,7 +122,6 @@ class Animator final {
std::shared_ptr<VsyncWaiter> waiter_;
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder_;
std::vector<std::unique_ptr<LayerTreeTask>> layer_trees_tasks_;
uint64_t frame_request_number_ = 1;
fml::TimeDelta dart_frame_deadline_;
std::shared_ptr<FramePipeline> layer_tree_pipeline_;

View File

@ -23,8 +23,6 @@
namespace flutter {
namespace testing {
constexpr int64_t kImplicitViewId = 0;
class FakeAnimatorDelegate : public Animator::Delegate {
public:
MOCK_METHOD(void,
@ -160,30 +158,20 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) {
latch.Wait();
ASSERT_FALSE(delegate.notify_idle_called_);
fml::AutoResetWaitableEvent render_latch;
// Validate it has not notified idle and try to render.
task_runners.GetUITaskRunner()->PostDelayedTask(
[&] {
ASSERT_FALSE(delegate.notify_idle_called_);
EXPECT_CALL(delegate, OnAnimatorBeginFrame).WillOnce([&] {
auto layer_tree = std::make_unique<LayerTree>(
LayerTree::Config(), SkISize::Make(600, 800));
animator->Render(kImplicitViewId, std::move(layer_tree), 1.0);
render_latch.Signal();
});
// Request a frame that builds a layer tree and renders a frame.
// When the frame is rendered, render_latch will be signaled.
animator->RequestFrame(true);
auto layer_tree = std::make_unique<LayerTree>(LayerTree::Config(),
SkISize::Make(600, 800));
animator->Render(std::move(layer_tree), 1.0);
task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task);
},
// See kNotifyIdleTaskWaitTime in animator.cc.
fml::TimeDelta::FromMilliseconds(60));
latch.Wait();
render_latch.Wait();
// A frame has been rendered, and the next frame request will notify idle.
// But at the moment there isn't another frame request, therefore it still
// hasn't notified idle.
// Still hasn't notified idle because there has been no frame request.
task_runners.GetUITaskRunner()->PostTask([&] {
ASSERT_FALSE(delegate.notify_idle_called_);
// False to avoid getting cals to BeginFrame that will request more frames
@ -236,6 +224,11 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) {
});
fml::AutoResetWaitableEvent begin_frame_latch;
EXPECT_CALL(delegate, OnAnimatorBeginFrame)
.WillRepeatedly(
[&](fml::TimePoint frame_target_time, uint64_t frame_number) {
begin_frame_latch.Signal();
});
// It must always be called when the method 'Animator::Render' is called,
// regardless of whether the pipeline is empty or not.
EXPECT_CALL(delegate, OnAnimatorUpdateLatestFrameTargetTime).Times(2);
@ -246,16 +239,16 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) {
for (int i = 0; i < 2; i++) {
task_runners.GetUITaskRunner()->PostTask([&] {
EXPECT_CALL(delegate, OnAnimatorBeginFrame).WillOnce([&] {
auto layer_tree = std::make_unique<LayerTree>(LayerTree::Config(),
SkISize::Make(600, 800));
animator->Render(kImplicitViewId, std::move(layer_tree), 1.0);
begin_frame_latch.Signal();
});
animator->RequestFrame();
task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task);
});
begin_frame_latch.Wait();
PostTaskSync(task_runners.GetUITaskRunner(), [&] {
auto layer_tree = std::make_unique<LayerTree>(LayerTree::Config(),
SkISize::Make(600, 800));
animator->Render(std::move(layer_tree), 1.0);
});
}
PostTaskSync(task_runners.GetUITaskRunner(), [&] { animator.reset(); });

View File

@ -466,8 +466,7 @@ void Engine::EndWarmUpFrame() {
animator_->EndWarmUpFrame();
}
void Engine::Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) {
if (!layer_tree) {
return;
@ -478,7 +477,7 @@ void Engine::Render(int64_t view_id,
return;
}
animator_->Render(view_id, std::move(layer_tree), device_pixel_ratio);
animator_->Render(std::move(layer_tree), device_pixel_ratio);
}
void Engine::UpdateSemantics(SemanticsNodeUpdates update,

View File

@ -966,8 +966,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
std::string DefaultRouteName() override;
// |RuntimeDelegate|
void Render(int64_t view_id,
std::unique_ptr<flutter::LayerTree> layer_tree,
void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) override;
// |RuntimeDelegate|

View File

@ -25,10 +25,8 @@ namespace {
using ::testing::Invoke;
using ::testing::ReturnRef;
fml::AutoResetWaitableEvent native_latch;
void PostSync(const fml::RefPtr<fml::TaskRunner>& task_runner,
const fml::closure& task) {
static void PostSync(const fml::RefPtr<fml::TaskRunner>& task_runner,
const fml::closure& task) {
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(task_runner, [&latch, &task] {
task();
@ -84,7 +82,7 @@ class MockRuntimeDelegate : public RuntimeDelegate {
MOCK_METHOD(void, EndWarmUpFrame, (), (override));
MOCK_METHOD(void,
Render,
(int64_t, std::unique_ptr<flutter::LayerTree>, float),
(std::unique_ptr<flutter::LayerTree>, float),
(override));
MOCK_METHOD(void,
UpdateSemantics,
@ -572,66 +570,6 @@ TEST_F(EngineTest, PassesLoadDartDeferredLibraryErrorToRuntime) {
});
}
TEST_F(EngineTest, AnimatorAcceptsMultipleRenders) {
MockAnimatorDelegate animator_delegate;
std::unique_ptr<EngineContext> engine_context;
std::shared_ptr<PlatformMessageHandler> platform_message_handler =
std::make_shared<MockPlatformMessageHandler>();
EXPECT_CALL(delegate_, GetPlatformMessageHandler)
.WillOnce(ReturnRef(platform_message_handler));
fml::AutoResetWaitableEvent draw_latch;
EXPECT_CALL(animator_delegate, OnAnimatorDraw)
.WillOnce(
Invoke([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
auto status =
pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
EXPECT_EQ(item->layer_tree_tasks.size(), 2u);
EXPECT_EQ(item->layer_tree_tasks[0]->view_id, 1);
EXPECT_EQ(item->layer_tree_tasks[1]->view_id, 2);
});
EXPECT_EQ(status, PipelineConsumeResult::Done);
draw_latch.Signal();
}));
EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
.WillOnce(Invoke([&engine_context](fml::TimePoint frame_target_time,
uint64_t frame_number) {
engine_context->EngineTaskSync([&](Engine& engine) {
engine.BeginFrame(frame_target_time, frame_number);
});
}));
native_latch.Reset();
AddNativeCallback("NotifyNative", [](auto args) { native_latch.Signal(); });
std::unique_ptr<Animator> animator;
PostSync(task_runners_.GetUITaskRunner(),
[&animator, &animator_delegate, &task_runners = task_runners_] {
animator = std::make_unique<Animator>(
animator_delegate, task_runners,
static_cast<std::unique_ptr<VsyncWaiter>>(
std::make_unique<testing::ConstantFiringVsyncWaiter>(
task_runners)));
});
engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
std::move(animator));
auto configuration = RunConfiguration::InferFromSettings(settings_);
configuration.SetEntrypoint("onDrawFrameRenderAllViews");
engine_context->Run(std::move(configuration));
engine_context->EngineTaskSync([](Engine& engine) {
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0});
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0});
});
native_latch.Wait();
engine_context->EngineTaskSync(
[](Engine& engine) { engine.ScheduleFrame(); });
draw_latch.Wait();
}
// The animator should submit to the pipeline the implicit view rendered in a
// warm up frame if there's already a continuation (i.e. Animator::BeginFrame
// has been called)
@ -697,72 +635,4 @@ TEST_F(EngineTest, AnimatorSubmitWarmUpImplicitView) {
draw_latch.Wait();
}
// The warm up frame should work if only some of the registered views are
// included.
//
// This test also verifies that the warm up frame can render multiple views.
TEST_F(EngineTest, AnimatorSubmitPartialViewsForWarmUp) {
MockAnimatorDelegate animator_delegate;
std::unique_ptr<EngineContext> engine_context;
std::shared_ptr<PlatformMessageHandler> platform_message_handler =
std::make_shared<MockPlatformMessageHandler>();
EXPECT_CALL(delegate_, GetPlatformMessageHandler)
.WillOnce(ReturnRef(platform_message_handler));
fml::AutoResetWaitableEvent continuation_ready_latch;
fml::AutoResetWaitableEvent draw_latch;
EXPECT_CALL(animator_delegate, OnAnimatorDraw)
.WillOnce(
Invoke([&draw_latch](const std::shared_ptr<FramePipeline>& pipeline) {
auto status =
pipeline->Consume([&](std::unique_ptr<FrameItem> item) {
EXPECT_EQ(item->layer_tree_tasks.size(), 2u);
EXPECT_EQ(item->layer_tree_tasks[0]->view_id, 1);
EXPECT_EQ(item->layer_tree_tasks[1]->view_id, 2);
});
EXPECT_EQ(status, PipelineConsumeResult::Done);
draw_latch.Signal();
}));
EXPECT_CALL(animator_delegate, OnAnimatorBeginFrame)
.WillRepeatedly(
Invoke([&engine_context, &continuation_ready_latch](
fml::TimePoint frame_target_time, uint64_t frame_number) {
continuation_ready_latch.Signal();
engine_context->EngineTaskSync([&](Engine& engine) {
engine.BeginFrame(frame_target_time, frame_number);
});
}));
std::unique_ptr<Animator> animator;
PostSync(task_runners_.GetUITaskRunner(),
[&animator, &animator_delegate, &task_runners = task_runners_] {
animator = std::make_unique<Animator>(
animator_delegate, task_runners,
static_cast<std::unique_ptr<VsyncWaiter>>(
std::make_unique<testing::ConstantFiringVsyncWaiter>(
task_runners)));
});
engine_context = EngineContext::Create(delegate_, settings_, task_runners_,
std::move(animator));
engine_context->EngineTaskSync([](Engine& engine) {
// Schedule a frame to make the animator create a continuation.
engine.ScheduleFrame(true);
// Add multiple views.
engine.AddView(0, ViewportMetrics{1, 10, 10, 22, 0});
engine.AddView(1, ViewportMetrics{1, 10, 10, 22, 0});
engine.AddView(2, ViewportMetrics{1, 10, 10, 22, 0});
});
continuation_ready_latch.Wait();
auto configuration = RunConfiguration::InferFromSettings(settings_);
configuration.SetEntrypoint("renderWarmUpView1and2");
engine_context->Run(std::move(configuration));
draw_latch.Wait();
}
} // namespace flutter

View File

@ -532,27 +532,6 @@ void testReportViewWidths() {
};
}
@pragma('vm:entry-point')
void onDrawFrameRenderAllViews() {
PlatformDispatcher.instance.onDrawFrame = () {
for (final FlutterView view in PlatformDispatcher.instance.views) {
final SceneBuilder builder = SceneBuilder();
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawPaint(Paint()..color = const Color(0xFFABCDEF));
final Picture picture = recorder.endRecording();
builder.addPicture(Offset.zero, picture);
final Scene scene = builder.build();
view.render(scene);
scene.dispose();
picture.dispose();
}
};
notifyNative();
}
@pragma('vm:entry-point')
void renderWarmUpImplicitView() {
bool beginFrameCalled = false;
@ -580,35 +559,3 @@ void renderWarmUpImplicitView() {
},
);
}
@pragma('vm:entry-point')
void renderWarmUpView1and2() {
bool beginFrameCalled = false;
PlatformDispatcher.instance.scheduleWarmUpFrame(
beginFrame: () {
expect(beginFrameCalled, false);
beginFrameCalled = true;
},
drawFrame: () {
expect(beginFrameCalled, true);
for (final int viewId in <int>[1, 2]) {
final FlutterView view = PlatformDispatcher.instance.view(id: viewId)!;
final SceneBuilder builder = SceneBuilder();
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawPaint(Paint()..color = const Color(0xFFABCDEF));
final Picture picture = recorder.endRecording();
builder.addPicture(Offset.zero, picture);
final Scene scene = builder.build();
view.render(scene);
scene.dispose();
picture.dispose();
}
}
);
}

View File

@ -127,11 +127,11 @@ static void TestSimulatedInputEvents(
ShellTest::DispatchFakePointerData(shell.get());
i += 1;
}
ShellTest::VSyncFlush(shell.get(), &will_draw_new_frame);
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
}
// Finally, issue a vsync for the pending event that may be generated duing
// the last vsync.
ShellTest::VSyncFlush(shell.get(), &will_draw_new_frame);
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
});
simulation.wait();
@ -345,7 +345,8 @@ TEST_F(ShellTest, CanCorrectlyPipePointerPacket) {
CreateSimulatedPointerData(data, PointerData::Change::kRemove, 3.0, 4.0);
packet->SetPointerData(5, data);
ShellTest::DispatchPointerData(shell.get(), std::move(packet));
ShellTest::VSyncFlush(shell.get());
bool will_draw_new_frame;
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
reportLatch.Wait();
size_t expect_length = 6;
@ -406,7 +407,8 @@ TEST_F(ShellTest, CanCorrectlySynthesizePointerPacket) {
CreateSimulatedPointerData(data, PointerData::Change::kRemove, 3.0, 4.0);
packet->SetPointerData(3, data);
ShellTest::DispatchPointerData(shell.get(), std::move(packet));
ShellTest::VSyncFlush(shell.get());
bool will_draw_new_frame;
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
reportLatch.Wait();
size_t expect_length = 6;

View File

@ -261,7 +261,6 @@ DrawStatus Rasterizer::Draw(const std::shared_ptr<FramePipeline>& pipeline) {
bool should_resubmit_frame = ShouldResubmitFrame(draw_result);
if (should_resubmit_frame) {
FML_CHECK(draw_result.resubmitted_item);
auto front_continuation = pipeline->ProduceIfEmpty();
PipelineProduceResult pipeline_result =
front_continuation.Complete(std::move(draw_result.resubmitted_item));

View File

@ -22,39 +22,6 @@ namespace testing {
constexpr int64_t kImplicitViewId = 0;
FrameContent ViewContent::NoViews() {
return std::map<int64_t, ViewContent>();
}
FrameContent ViewContent::DummyView(double width, double height) {
FrameContent result;
result[kImplicitViewId] = ViewContent{
.viewport_metrics = {1.0, width, height, 22, 0},
.builder = {},
};
return result;
}
FrameContent ViewContent::DummyView(flutter::ViewportMetrics viewport_metrics) {
FrameContent result;
result[kImplicitViewId] = ViewContent{
.viewport_metrics = std::move(viewport_metrics),
.builder = {},
};
return result;
}
FrameContent ViewContent::ImplicitView(double width,
double height,
LayerTreeBuilder builder) {
FrameContent result;
result[kImplicitViewId] = ViewContent{
.viewport_metrics = {1.0, width, height, 22, 0},
.builder = std::move(builder),
};
return result;
}
ShellTest::ShellTest()
: thread_host_("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::kPlatform | ThreadHost::Type::kIo |
@ -125,18 +92,16 @@ void ShellTest::RestartEngine(Shell* shell, RunConfiguration configuration) {
ASSERT_TRUE(restarted.get_future().get());
}
void ShellTest::VSyncFlush(Shell* shell, bool* will_draw_new_frame) {
void ShellTest::VSyncFlush(Shell* shell, bool& will_draw_new_frame) {
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetPlatformTaskRunner(),
[shell, will_draw_new_frame, &latch] {
[shell, &will_draw_new_frame, &latch] {
// The following UI task ensures that all previous UI tasks are flushed.
fml::AutoResetWaitableEvent ui_latch;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&ui_latch, will_draw_new_frame]() {
if (will_draw_new_frame != nullptr) {
*will_draw_new_frame = true;
}
[&ui_latch, &will_draw_new_frame]() {
will_draw_new_frame = true;
ui_latch.Signal();
});
@ -189,7 +154,6 @@ void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) {
std::make_unique<FrameTimingsRecorder>();
recorder->RecordVsync(frame_begin_time, frame_end_time);
engine->animator_->BeginFrame(std::move(recorder));
engine->animator_->EndFrame();
}
latch.Signal();
});
@ -208,22 +172,23 @@ void ShellTest::NotifyIdle(Shell* shell, fml::TimeDelta deadline) {
latch.Wait();
}
void ShellTest::PumpOneFrame(Shell* shell) {
PumpOneFrame(shell, ViewContent::DummyView());
void ShellTest::PumpOneFrame(Shell* shell,
double width,
double height,
LayerTreeBuilder builder) {
PumpOneFrame(shell, {1.0, width, height, 22, 0}, std::move(builder));
}
void ShellTest::PumpOneFrame(Shell* shell, FrameContent frame_content) {
void ShellTest::PumpOneFrame(Shell* shell,
const flutter::ViewportMetrics& viewport_metrics,
LayerTreeBuilder builder) {
// Set viewport to nonempty, and call Animator::BeginFrame to make the layer
// tree pipeline nonempty. Without either of this, the layer tree below
// won't be rasterized.
fml::AutoResetWaitableEvent latch;
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&latch, engine = shell->weak_engine_, &frame_content,
runtime_delegate]() {
for (auto& [view_id, view_content] : frame_content) {
engine->SetViewportMetrics(view_id, view_content.viewport_metrics);
}
[&latch, engine = shell->weak_engine_, viewport_metrics]() {
engine->SetViewportMetrics(kImplicitViewId, viewport_metrics);
const auto frame_begin_time = fml::TimePoint::Now();
const auto frame_end_time =
frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
@ -231,28 +196,28 @@ void ShellTest::PumpOneFrame(Shell* shell, FrameContent frame_content) {
std::make_unique<FrameTimingsRecorder>();
recorder->RecordVsync(frame_begin_time, frame_end_time);
engine->animator_->BeginFrame(std::move(recorder));
latch.Signal();
});
latch.Wait();
// The BeginFrame phase and the EndFrame phase must be performed in a
// single task, otherwise a normal vsync might be inserted in between,
// causing flaky assertion errors.
for (auto& [view_id, view_content] : frame_content) {
SkMatrix identity;
identity.setIdentity();
auto root_layer = std::make_shared<TransformLayer>(identity);
auto layer_tree = std::make_unique<LayerTree>(
LayerTree::Config{.root_layer = root_layer},
SkISize::Make(view_content.viewport_metrics.physical_width,
view_content.viewport_metrics.physical_height));
float device_pixel_ratio = static_cast<float>(
view_content.viewport_metrics.device_pixel_ratio);
if (view_content.builder) {
view_content.builder(root_layer);
}
runtime_delegate->Render(view_id, std::move(layer_tree),
device_pixel_ratio);
latch.Reset();
// Call |Render| to rasterize a layer tree and trigger |OnFrameRasterized|
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&latch, runtime_delegate, &builder, viewport_metrics]() {
SkMatrix identity;
identity.setIdentity();
auto root_layer = std::make_shared<TransformLayer>(identity);
auto layer_tree = std::make_unique<LayerTree>(
LayerTree::Config{.root_layer = root_layer},
SkISize::Make(viewport_metrics.physical_width,
viewport_metrics.physical_height));
float device_pixel_ratio =
static_cast<float>(viewport_metrics.device_pixel_ratio);
if (builder) {
builder(root_layer);
}
engine->animator_->EndFrame();
runtime_delegate->Render(std::move(layer_tree), device_pixel_ratio);
latch.Signal();
});
latch.Wait();

View File

@ -29,38 +29,6 @@
namespace flutter {
namespace testing {
// The signature of ViewContent::builder.
using LayerTreeBuilder =
std::function<void(std::shared_ptr<ContainerLayer> root)>;
struct ViewContent;
// Defines the content to be rendered to all views of a frame in PumpOneFrame.
using FrameContent = std::map<int64_t, ViewContent>;
// Defines the content to be rendered to a view in PumpOneFrame.
struct ViewContent {
flutter::ViewportMetrics viewport_metrics;
// Given the root layer, this callback builds the layer tree to be rasterized
// in PumpOneFrame.
LayerTreeBuilder builder;
// Build a frame with no views. This is useful when PumpOneFrame is used just
// to schedule the frame while the frame content is defined by other means.
static FrameContent NoViews();
// Build a frame with a single implicit view with the specific size and no
// content.
static FrameContent DummyView(double width = 1, double height = 1);
// Build a frame with a single implicit view with the specific viewport
// metrics and no content.
static FrameContent DummyView(flutter::ViewportMetrics viewport_metrics);
// Build a frame with a single implicit view with the specific size and
// content.
static FrameContent ImplicitView(double width,
double height,
LayerTreeBuilder builder);
};
class ShellTest : public FixtureTest {
public:
struct Config {
@ -102,14 +70,24 @@ class ShellTest : public FixtureTest {
static void RestartEngine(Shell* shell, RunConfiguration configuration);
/// Issue as many VSYNC as needed to flush the UI tasks so far, and reset
/// the content of `will_draw_new_frame` to true if it's not nullptr.
static void VSyncFlush(Shell* shell, bool* will_draw_new_frame = nullptr);
/// the `will_draw_new_frame` to true.
static void VSyncFlush(Shell* shell, bool& will_draw_new_frame);
/// Given the root layer, this callback builds the layer tree to be rasterized
/// in PumpOneFrame.
using LayerTreeBuilder =
std::function<void(std::shared_ptr<ContainerLayer> root)>;
static void SetViewportMetrics(Shell* shell, double width, double height);
static void NotifyIdle(Shell* shell, fml::TimeDelta deadline);
static void PumpOneFrame(Shell* shell);
static void PumpOneFrame(Shell* shell, FrameContent frame_content);
static void PumpOneFrame(Shell* shell,
double width = 1,
double height = 1,
LayerTreeBuilder = {});
static void PumpOneFrame(Shell* shell,
const flutter::ViewportMetrics& viewport_metrics,
LayerTreeBuilder = {});
static void DispatchFakePointerData(Shell* shell);
static void DispatchPointerData(Shell* shell,
std::unique_ptr<PointerDataPacket> packet);

View File

@ -42,7 +42,6 @@
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/common/vsync_waiter_fallback.h"
#include "flutter/shell/common/vsync_waiters_test.h"
#include "flutter/shell/version/version.h"
#include "flutter/testing/mock_canvas.h"
#include "flutter/testing/testing.h"
@ -876,7 +875,7 @@ TEST_F(ShellTest, ExternalEmbedderNoThreadMerger) {
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
ASSERT_TRUE(end_frame_called);
@ -950,7 +949,7 @@ TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) {
backdrop_filter_layer->Add(platform_view_layer2);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
ASSERT_EQ(visited_platform_views, (std::vector<int64_t>{50, 75}));
ASSERT_TRUE(stack_75.is_empty());
@ -1011,7 +1010,7 @@ TEST_F(ShellTest,
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
ASSERT_TRUE(end_frame_called);
@ -1057,12 +1056,9 @@ TEST_F(ShellTest, OnPlatformViewDestroyDisablesThreadMerger) {
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
auto result = shell->WaitForFirstFrame(fml::TimeDelta::Max());
// Wait for the rasterizer to process the frame. WaitForFirstFrame only waits
// for the Animator, but end_frame_callback is called by the Rasterizer.
PostSync(shell->GetTaskRunners().GetRasterTaskRunner(), [] {});
ASSERT_TRUE(result.ok()) << "Result: " << static_cast<int>(result.code())
<< ": " << result.message();
@ -1127,12 +1123,12 @@ TEST_F(ShellTest, OnPlatformViewDestroyAfterMergingThreads) {
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
// Pump one frame to trigger thread merging.
end_frame_latch.Wait();
// Pump another frame to ensure threads are merged and a regular layer tree is
// submitted.
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
// Threads are merged here. PlatformViewNotifyDestroy should be executed
// successfully.
ASSERT_TRUE(fml::TaskRunnerChecker::RunsOnTheSameThread(
@ -1196,7 +1192,7 @@ TEST_F(ShellTest, OnPlatformViewDestroyWhenThreadsAreMerging) {
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
// Pump one frame and threads aren't merged
end_frame_latch.Wait();
ASSERT_FALSE(fml::TaskRunnerChecker::RunsOnTheSameThread(
@ -1207,7 +1203,7 @@ TEST_F(ShellTest, OnPlatformViewDestroyWhenThreadsAreMerging) {
// threads
external_view_embedder->UpdatePostPrerollResult(
PostPrerollResult::kResubmitFrame);
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
// Now destroy the platform view immediately.
// Two things can happen here:
@ -1263,7 +1259,7 @@ TEST_F(ShellTest,
SkPoint::Make(10, 10), MakeSizedDisplayList(80, 80), false, false);
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
// Threads should not be merged.
@ -1302,7 +1298,7 @@ TEST_F(ShellTest, OnPlatformViewDestroyWithoutRasterThreadMerger) {
SkPoint::Make(10, 10), MakeSizedDisplayList(80, 80), false, false);
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
// Threads should not be merged.
ASSERT_FALSE(fml::TaskRunnerChecker::RunsOnTheSameThread(
@ -1368,7 +1364,7 @@ TEST_F(ShellTest, OnPlatformViewDestroyWithStaticThreadMerging) {
SkPoint::Make(10, 10), MakeSizedDisplayList(80, 80), false, false);
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
ValidateDestroyPlatformView(shell.get());
@ -1414,7 +1410,7 @@ TEST_F(ShellTest, GetUsedThisFrameShouldBeSetBeforeEndFrame) {
SkPoint::Make(10, 10), MakeSizedDisplayList(80, 80), false, false);
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
end_frame_latch.Wait();
ASSERT_FALSE(used_this_frame);
@ -1564,11 +1560,10 @@ TEST_F(ShellTest, WaitForFirstFrameZeroSizeFrame) {
configuration.SetEntrypoint("emptyMain");
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get(), ViewContent::DummyView({1.0, 0.0, 0.0, 22, 0}));
PumpOneFrame(shell.get(), {1.0, 0.0, 0.0, 22, 0});
fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::Zero());
EXPECT_FALSE(result.ok());
EXPECT_EQ(result.message(), "timeout");
EXPECT_EQ(result.code(), fml::StatusCode::kDeadlineExceeded);
ASSERT_FALSE(result.ok());
ASSERT_EQ(result.code(), fml::StatusCode::kDeadlineExceeded);
DestroyShell(std::move(shell));
}
@ -2084,7 +2079,6 @@ TEST_F(ShellTest, CanScheduleFrameFromPlatform) {
TEST_F(ShellTest, SecondaryVsyncCallbackShouldBeCalledAfterVsyncCallback) {
bool is_on_begin_frame_called = false;
bool is_secondary_callback_called = false;
bool test_started = false;
Settings settings = CreateSettingsForFixture();
TaskRunners task_runners = GetTaskRunnersForFixture();
fml::AutoResetWaitableEvent latch;
@ -2094,18 +2088,12 @@ TEST_F(ShellTest, SecondaryVsyncCallbackShouldBeCalledAfterVsyncCallback) {
fml::CountDownLatch count_down_latch(2);
AddNativeCallback("NativeOnBeginFrame",
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
if (!test_started) {
return;
}
EXPECT_FALSE(is_on_begin_frame_called);
EXPECT_FALSE(is_secondary_callback_called);
is_on_begin_frame_called = true;
count_down_latch.CountDown();
}));
std::unique_ptr<Shell> shell = CreateShell({
.settings = settings,
.task_runners = task_runners,
});
std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
ASSERT_TRUE(shell->IsSetup());
auto configuration = RunConfiguration::InferFromSettings(settings);
@ -2118,16 +2106,12 @@ TEST_F(ShellTest, SecondaryVsyncCallbackShouldBeCalledAfterVsyncCallback) {
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(), [&]() {
shell->GetEngine()->ScheduleSecondaryVsyncCallback(0, [&]() {
if (!test_started) {
return;
}
EXPECT_TRUE(is_on_begin_frame_called);
EXPECT_FALSE(is_secondary_callback_called);
is_secondary_callback_called = true;
count_down_latch.CountDown();
});
shell->GetEngine()->ScheduleFrame();
test_started = true;
});
count_down_latch.Wait();
EXPECT_TRUE(is_on_begin_frame_called);
@ -2172,7 +2156,7 @@ TEST_F(ShellTest, Screenshot) {
root->Add(display_list_layer);
};
PumpOneFrame(shell.get(), ViewContent::ImplicitView(100, 100, builder));
PumpOneFrame(shell.get(), 100, 100, builder);
firstFrameLatch.Wait();
std::promise<Rasterizer::Screenshot> screenshot_promise;
@ -2557,13 +2541,7 @@ TEST_F(ShellTest, OnServiceProtocolRenderFrameWithRasterStatsWorks) {
configuration.SetEntrypoint("scene_with_red_box");
RunEngine(shell.get(), std::move(configuration));
// Set a non-zero viewport metrics, otherwise the scene would be discarded.
PostSync(shell->GetTaskRunners().GetUITaskRunner(),
[engine = shell->GetEngine()]() {
engine->SetViewportMetrics(kImplicitViewId,
ViewportMetrics{1, 1, 1, 22, 0});
});
PumpOneFrame(shell.get(), ViewContent::NoViews());
PumpOneFrame(shell.get());
ServiceProtocol::Handler::ServiceProtocolMap empty_params;
rapidjson::Document document;
@ -2675,7 +2653,7 @@ TEST_F(ShellTest, OnServiceProtocolRenderFrameWithRasterStatsDisableImpeller) {
configuration.SetEntrypoint("scene_with_red_box");
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get(), ViewContent::NoViews());
PumpOneFrame(shell.get());
ServiceProtocol::Handler::ServiceProtocolMap empty_params;
rapidjson::Document document;
@ -2739,16 +2717,14 @@ TEST_F(ShellTest, DISABLED_DiscardLayerTreeOnResize) {
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get(), ViewContent::DummyView(
static_cast<double>(wrong_size.width()),
static_cast<double>(wrong_size.height())));
PumpOneFrame(shell.get(), static_cast<double>(wrong_size.width()),
static_cast<double>(wrong_size.height()));
end_frame_latch.Wait();
// Wrong size, no frames are submitted.
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());
PumpOneFrame(shell.get(), ViewContent::DummyView(
static_cast<double>(expected_size.width()),
static_cast<double>(expected_size.height())));
PumpOneFrame(shell.get(), static_cast<double>(expected_size.width()),
static_cast<double>(expected_size.height()));
end_frame_latch.Wait();
// Expected size, 1 frame submitted.
ASSERT_EQ(1, external_view_embedder->GetSubmittedFrameCount());
@ -2819,9 +2795,8 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) {
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get(), ViewContent::DummyView(
static_cast<double>(origin_size.width()),
static_cast<double>(origin_size.height())));
PumpOneFrame(shell.get(), static_cast<double>(origin_size.width()),
static_cast<double>(origin_size.height()));
end_frame_latch.Wait();
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());
@ -2842,9 +2817,8 @@ TEST_F(ShellTest, DISABLED_DiscardResubmittedLayerTreeOnResize) {
ASSERT_EQ(0, external_view_embedder->GetSubmittedFrameCount());
// Threads will be merged at the end of this frame.
PumpOneFrame(shell.get(),
ViewContent::DummyView(static_cast<double>(new_size.width()),
static_cast<double>(new_size.height())));
PumpOneFrame(shell.get(), static_cast<double>(new_size.width()),
static_cast<double>(new_size.height()));
end_frame_latch.Wait();
ASSERT_TRUE(raster_thread_merger_ref->IsMerged());

View File

@ -10,12 +10,10 @@ void main() {
test('PlatformView layers do not emit errors from tester', () async {
final SceneBuilder builder = SceneBuilder();
builder.addPlatformView(1);
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
final Scene scene = builder.build();
PlatformDispatcher.instance.implicitView!.render(scene);
scene.dispose();
};
PlatformDispatcher.instance.scheduleFrame();
final Scene scene = builder.build();
PlatformDispatcher.instance.implicitView!.render(scene);
scene.dispose();
// Test harness asserts that this does not emit an error from the shell logs.
});
}