mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[animator] Pass target frametime for Window.onBeginFrame (flutter/engine#14318)
This gives us a time closer to when the frame will be rendered on screen. Fixes: https://github.com/flutter/flutter/issues/10850
This commit is contained in:
parent
0ff946c2b1
commit
4107c00949
@ -533,6 +533,7 @@ FILE: ../../../flutter/runtime/test_font_data.cc
|
||||
FILE: ../../../flutter/runtime/test_font_data.h
|
||||
FILE: ../../../flutter/shell/common/animator.cc
|
||||
FILE: ../../../flutter/shell/common/animator.h
|
||||
FILE: ../../../flutter/shell/common/animator_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/canvas_spy.cc
|
||||
FILE: ../../../flutter/shell/common/canvas_spy.h
|
||||
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
|
||||
|
||||
@ -34,7 +34,13 @@ namespace fml {
|
||||
#endif
|
||||
|
||||
bool TimerRearm(int fd, fml::TimePoint time_point) {
|
||||
const uint64_t nano_secs = time_point.ToEpochDelta().ToNanoseconds();
|
||||
uint64_t nano_secs = time_point.ToEpochDelta().ToNanoseconds();
|
||||
|
||||
// "0" will disarm the timer, desired behavior is to immediately
|
||||
// trigger the timer.
|
||||
if (nano_secs < 1) {
|
||||
nano_secs = 1;
|
||||
}
|
||||
|
||||
struct itimerspec spec = {};
|
||||
spec.it_value.tv_sec = (time_t)(nano_secs / NSEC_PER_SEC);
|
||||
|
||||
@ -159,6 +159,7 @@ if (current_toolchain == host_toolchain) {
|
||||
|
||||
shell_host_executable("shell_unittests") {
|
||||
sources = [
|
||||
"animator_unittests.cc",
|
||||
"canvas_spy_unittests.cc",
|
||||
"input_events_unittests.cc",
|
||||
"persistent_cache_unittests.cc",
|
||||
|
||||
@ -137,7 +137,7 @@ void Animator::BeginFrame(fml::TimePoint frame_start_time,
|
||||
{
|
||||
TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame",
|
||||
FrameParity());
|
||||
delegate_.OnAnimatorBeginFrame(last_begin_frame_time_);
|
||||
delegate_.OnAnimatorBeginFrame(frame_target_time);
|
||||
}
|
||||
|
||||
if (!frame_scheduled_) {
|
||||
|
||||
95
engine/src/flutter/shell/common/animator_unittests.cc
Normal file
95
engine/src/flutter/shell/common/animator_unittests.cc
Normal file
@ -0,0 +1,95 @@
|
||||
// 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.
|
||||
|
||||
#define FML_USED_ON_EMBEDDER
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/shell/common/animator.h"
|
||||
#include "flutter/shell/common/shell_test.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
TEST_F(ShellTest, VSyncTargetTime) {
|
||||
// Add native callbacks to listen for window.onBeginFrame
|
||||
int64_t target_time;
|
||||
fml::AutoResetWaitableEvent on_target_time_latch;
|
||||
auto nativeOnBeginFrame = [&on_target_time_latch,
|
||||
&target_time](Dart_NativeArguments args) {
|
||||
Dart_Handle exception = nullptr;
|
||||
target_time =
|
||||
tonic::DartConverter<int64_t>::FromArguments(args, 0, exception);
|
||||
on_target_time_latch.Signal();
|
||||
};
|
||||
AddNativeCallback("NativeOnBeginFrame",
|
||||
CREATE_NATIVE_ENTRY(nativeOnBeginFrame));
|
||||
|
||||
// Create all te prerequisites for a shell.
|
||||
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
|
||||
auto settings = CreateSettingsForFixture();
|
||||
|
||||
std::unique_ptr<Shell> shell;
|
||||
|
||||
TaskRunners task_runners = GetTaskRunnersForFixture();
|
||||
// this is not used as we are not using simulated events.
|
||||
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
|
||||
CreateVsyncWaiter create_vsync_waiter = [&]() {
|
||||
return static_cast<std::unique_ptr<VsyncWaiter>>(
|
||||
std::make_unique<ConstantFiringVsyncWaiter>(task_runners));
|
||||
};
|
||||
|
||||
// create a shell with a constant firing vsync waiter.
|
||||
fml::AutoResetWaitableEvent shell_creation;
|
||||
|
||||
auto platform_task = std::async(std::launch::async, [&]() {
|
||||
shell = Shell::Create(
|
||||
task_runners, settings,
|
||||
[vsync_clock, &create_vsync_waiter](Shell& shell) {
|
||||
return std::make_unique<ShellTestPlatformView>(
|
||||
shell, shell.GetTaskRunners(), vsync_clock,
|
||||
std::move(create_vsync_waiter));
|
||||
},
|
||||
[](Shell& shell) {
|
||||
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
|
||||
});
|
||||
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
|
||||
|
||||
auto configuration = RunConfiguration::InferFromSettings(settings);
|
||||
ASSERT_TRUE(configuration.IsValid());
|
||||
configuration.SetEntrypoint("onBeginFrameMain");
|
||||
|
||||
RunEngine(shell.get(), std::move(configuration));
|
||||
shell_creation.Signal();
|
||||
});
|
||||
|
||||
shell_creation.Wait();
|
||||
|
||||
// schedule a frame to trigger window.onBeginFrame
|
||||
fml::TaskRunner::RunNowOrPostTask(shell->GetTaskRunners().GetUITaskRunner(),
|
||||
[engine = shell->GetEngine()]() {
|
||||
if (engine) {
|
||||
// this implies we can re-use the last
|
||||
// frame to trigger begin frame rather
|
||||
// than re-generating the layer tree.
|
||||
engine->ScheduleFrame(true);
|
||||
}
|
||||
});
|
||||
|
||||
on_target_time_latch.Wait();
|
||||
ASSERT_EQ(ConstantFiringVsyncWaiter::frame_target_time.ToEpochDelta()
|
||||
.ToMicroseconds(),
|
||||
target_time);
|
||||
|
||||
// teardown.
|
||||
DestroyShell(std::move(shell), std::move(task_runners));
|
||||
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@ -435,10 +435,10 @@ TEST_F(ShellTest, FrameRasterizedCallbackIsCalled) {
|
||||
auto configuration = RunConfiguration::InferFromSettings(settings);
|
||||
configuration.SetEntrypoint("onBeginFrameMain");
|
||||
|
||||
int64_t begin_frame;
|
||||
auto nativeOnBeginFrame = [&begin_frame](Dart_NativeArguments args) {
|
||||
int64_t frame_target_time;
|
||||
auto nativeOnBeginFrame = [&frame_target_time](Dart_NativeArguments args) {
|
||||
Dart_Handle exception = nullptr;
|
||||
begin_frame =
|
||||
frame_target_time =
|
||||
tonic::DartConverter<int64_t>::FromArguments(args, 0, exception);
|
||||
};
|
||||
AddNativeCallback("NativeOnBeginFrame",
|
||||
@ -455,10 +455,11 @@ TEST_F(ShellTest, FrameRasterizedCallbackIsCalled) {
|
||||
std::vector<FrameTiming> timings = {timing};
|
||||
CheckFrameTimings(timings, start, finish);
|
||||
|
||||
// Check that onBeginFrame has the same timestamp as FrameTiming's build start
|
||||
// Check that onBeginFrame, which is the frame_target_time, is after
|
||||
// FrameTiming's build start
|
||||
int64_t build_start =
|
||||
timing.Get(FrameTiming::kBuildStart).ToEpochDelta().ToMicroseconds();
|
||||
ASSERT_EQ(build_start, begin_frame);
|
||||
ASSERT_GT(frame_target_time, build_start);
|
||||
DestroyShell(std::move(shell));
|
||||
}
|
||||
|
||||
|
||||
@ -57,5 +57,13 @@ void ShellTestVsyncWaiter::AwaitVSync() {
|
||||
});
|
||||
}
|
||||
|
||||
void ConstantFiringVsyncWaiter::AwaitVSync() {
|
||||
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
|
||||
auto async_wait = std::async([this]() {
|
||||
task_runners_.GetPlatformTaskRunner()->PostTask(
|
||||
[this]() { FireCallback(frame_begin_time, frame_target_time); });
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -41,6 +41,21 @@ class ShellTestVsyncWaiter : public VsyncWaiter {
|
||||
std::shared_ptr<ShellTestVsyncClock> clock_;
|
||||
};
|
||||
|
||||
class ConstantFiringVsyncWaiter : public VsyncWaiter {
|
||||
public:
|
||||
// both of these are set in the past so as to fire immediately.
|
||||
static constexpr fml::TimePoint frame_begin_time =
|
||||
fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromSeconds(0));
|
||||
static constexpr fml::TimePoint frame_target_time =
|
||||
fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromSeconds(100));
|
||||
|
||||
ConstantFiringVsyncWaiter(TaskRunners task_runners)
|
||||
: VsyncWaiter(std::move(task_runners)) {}
|
||||
|
||||
protected:
|
||||
void AwaitVSync() override;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user