未验证 提交 e65b4901 编写于 作者: K Kaushik Iska 提交者: GitHub

[animator] Pass target frametime for Window.onBeginFrame (#14318)

This gives us a time closer to when the frame will be rendered on
screen.

Fixes: https://github.com/flutter/flutter/issues/10850
上级 8d62a7c8
......@@ -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_) {
......
// 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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册