Allow embedders to specify a vsync waiter. (flutter/engine#7914)

Fixes https://github.com/flutter/flutter/issues/28240
This commit is contained in:
Chinmay Garde
2019-02-21 23:02:32 -08:00
committed by GitHub
parent 8d12a45c6a
commit d0f9af0324
14 changed files with 236 additions and 51 deletions

View File

@@ -653,6 +653,8 @@ FILE: ../../../flutter/shell/platform/embedder/fixtures/a11y_main.dart
FILE: ../../../flutter/shell/platform/embedder/fixtures/simple_main.dart
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.cc
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.h
FILE: ../../../flutter/shell/platform/embedder/vsync_waiter_embedder.cc
FILE: ../../../flutter/shell/platform/embedder/vsync_waiter_embedder.h
FILE: ../../../flutter/sky/packages/flutter_services/lib/empty.dart
FILE: ../../../flutter/sky/tools/roll/patches/chromium/android_build.patch
FILE: ../../../flutter/synchronization/pipeline.cc

View File

@@ -52,4 +52,8 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
});
}
float VsyncWaiter::GetDisplayRefreshRate() const {
return kUnknownRefreshRateFPS;
}
} // namespace shell

View File

@@ -14,8 +14,6 @@
namespace shell {
constexpr float kUnknownRefreshRateFPS = 0.0;
class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
public:
using Callback = std::function<void(fml::TimePoint frame_start_time,
@@ -25,22 +23,35 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
void AsyncWaitForVsync(Callback callback);
void FireCallback(fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
static constexpr float kUnknownRefreshRateFPS = 0.0;
// Get the display's maximum refresh rate in the unit of frame per second.
// Return 0.0 if the refresh rate is unkonwn.
virtual float GetDisplayRefreshRate() const { return 0.0; }
// Return kUnknownRefreshRateFPS if the refresh rate is unkonwn.
virtual float GetDisplayRefreshRate() const;
protected:
// On some backends, the |FireCallback| needs to be made from a static C
// method.
friend class VsyncWaiterAndroid;
friend class VsyncWaiterEmbedder;
const blink::TaskRunners task_runners_;
std::mutex callback_mutex_;
Callback callback_;
VsyncWaiter(blink::TaskRunners task_runners);
// Implementations are meant to override this method and arm their vsync
// latches when in response to this invocation. On vsync, they are meant to
// invoke the |FireCallback| method once (and only once) with the appropriate
// arguments.
virtual void AwaitVSync() = 0;
void FireCallback(fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
private:
std::mutex callback_mutex_;
Callback callback_;
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter);
};

View File

@@ -16,10 +16,6 @@
namespace shell {
static void ConsumePendingCallback(jlong java_baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
static fml::jni::ScopedJavaGlobalRef<jclass>* g_vsync_waiter_class = nullptr;
static jmethodID g_async_wait_for_vsync_method_ = nullptr;
@@ -30,8 +26,7 @@ VsyncWaiterAndroid::~VsyncWaiterAndroid() = default;
// |shell::VsyncWaiter|
void VsyncWaiterAndroid::AwaitVSync() {
std::weak_ptr<VsyncWaiter>* weak_this =
new std::weak_ptr<VsyncWaiter>(shared_from_this());
auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
jlong java_baton = reinterpret_cast<jlong>(weak_this);
task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
@@ -43,11 +38,25 @@ void VsyncWaiterAndroid::AwaitVSync() {
});
}
static void OnNativeVsync(JNIEnv* env,
jclass jcaller,
jlong frameTimeNanos,
jlong frameTargetTimeNanos,
jlong java_baton) {
float VsyncWaiterAndroid::GetDisplayRefreshRate() const {
JNIEnv* env = fml::jni::AttachCurrentThread();
if (g_vsync_waiter_class == nullptr) {
return kUnknownRefreshRateFPS;
}
jclass clazz = g_vsync_waiter_class->obj();
if (clazz == nullptr) {
return kUnknownRefreshRateFPS;
}
jfieldID fid = env->GetStaticFieldID(clazz, "refreshRateFPS", "F");
return env->GetStaticFloatField(clazz, fid);
}
// static
void VsyncWaiterAndroid::OnNativeVsync(JNIEnv* env,
jclass jcaller,
jlong frameTimeNanos,
jlong frameTargetTimeNanos,
jlong java_baton) {
auto frame_time = fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(frameTimeNanos));
auto target_time = fml::TimePoint::FromEpochDelta(
@@ -56,6 +65,21 @@ static void OnNativeVsync(JNIEnv* env,
ConsumePendingCallback(java_baton, frame_time, target_time);
}
// static
void VsyncWaiterAndroid::ConsumePendingCallback(
jlong java_baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
auto* weak_this = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(java_baton);
auto shared_this = weak_this->lock();
delete weak_this;
if (shared_this) {
shared_this->FireCallback(frame_start_time, frame_target_time);
}
}
// static
bool VsyncWaiterAndroid::Register(JNIEnv* env) {
static const JNINativeMethod methods[] = {{
.name = "nativeOnVsync",
@@ -81,32 +105,4 @@ bool VsyncWaiterAndroid::Register(JNIEnv* env) {
return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
float VsyncWaiterAndroid::GetDisplayRefreshRate() const {
JNIEnv* env = fml::jni::AttachCurrentThread();
if (g_vsync_waiter_class == nullptr) {
return kUnknownRefreshRateFPS;
}
jclass clazz = g_vsync_waiter_class->obj();
if (clazz == nullptr) {
return kUnknownRefreshRateFPS;
}
jfieldID fid = env->GetStaticFieldID(clazz, "refreshRateFPS", "F");
// We can safely read this 32-bit float from Java in any thread because
// 32-bits read and write are guaranteed to be atomic:
// https://stackoverflow.com/questions/11459543/should-getters-and-setters-be-synchronized/11459616#11459616
return env->GetStaticFloatField(clazz, fid);
}
static void ConsumePendingCallback(jlong java_baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
auto* weak_this = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(java_baton);
auto shared_this = weak_this->lock();
delete weak_this;
if (shared_this) {
shared_this->FireCallback(frame_start_time, frame_target_time);
}
}
} // namespace shell

View File

@@ -6,9 +6,10 @@
#define SHELL_PLATFORM_ANDROID_VSYNC_WAITER_ANDROID_H_
#include <jni.h>
#include <memory>
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/shell/common/vsync_waiter.h"
namespace shell {
@@ -27,6 +28,16 @@ class VsyncWaiterAndroid final : public VsyncWaiter {
// |shell::VsyncWaiter|
void AwaitVSync() override;
static void OnNativeVsync(JNIEnv* env,
jclass jcaller,
jlong frameTimeNanos,
jlong frameTargetTimeNanos,
jlong java_baton);
static void ConsumePendingCallback(jlong java_baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid);
};

View File

@@ -30,6 +30,8 @@ source_set("embedder") {
"embedder_surface_software.h",
"platform_view_embedder.cc",
"platform_view_embedder.h",
"vsync_waiter_embedder.cc",
"vsync_waiter_embedder.h",
]
deps = [

View File

@@ -478,9 +478,18 @@ FlutterEngineResult FlutterEngineRun(size_t version,
};
}
shell::VsyncWaiterEmbedder::VsyncCallback vsync_callback = nullptr;
if (SAFE_ACCESS(args, vsync_callback, nullptr) != nullptr) {
vsync_callback = [ptr = args->vsync_callback, user_data](intptr_t baton) {
return ptr(user_data, baton);
};
}
shell::PlatformViewEmbedder::PlatformDispatchTable platform_dispatch_table = {
update_semantics_nodes_callback, update_semantics_custom_actions_callback,
platform_message_response_callback, // platform_message_response_callback
update_semantics_nodes_callback, //
update_semantics_custom_actions_callback, //
platform_message_response_callback, //
vsync_callback, //
};
auto on_create_platform_view = InferPlatformViewCreationCallback(
@@ -810,6 +819,28 @@ FlutterEngineResult FlutterEngineDispatchSemanticsAction(
return kSuccess;
}
FlutterEngineResult FlutterEngineOnVsync(FlutterEngine engine,
intptr_t baton,
uint64_t frame_start_time_nanos,
uint64_t frame_target_time_nanos) {
if (engine == nullptr) {
return kInvalidArguments;
}
auto start_time = fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(frame_start_time_nanos));
auto target_time = fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(frame_target_time_nanos));
if (!reinterpret_cast<shell::EmbedderEngine*>(engine)->OnVsyncEvent(
baton, start_time, target_time)) {
return kInternalInconsistency;
}
return kSuccess;
}
void FlutterEngineTraceEventDurationBegin(const char* name) {
fml::tracing::TraceEvent0("flutter", name);
}

View File

@@ -204,6 +204,7 @@ typedef bool (*TextureFrameCallback)(void* /* user data */,
size_t /* width */,
size_t /* height */,
FlutterOpenGLTexture* /* texture out */);
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */);
typedef struct {
// The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig).
@@ -509,6 +510,14 @@ typedef struct {
// Flutter application (such as compiled shader programs used by Skia).
// This is optional. The string must be NULL terminated.
const char* persistent_cache_path;
// A callback that gets invoked by the engine when it attempts to wait for
// a platform vsync event. The engine will give the platform a baton that
// needs to be returned back to the engine via |FlutterEngineOnVsync|. All
// vsync operations must occur on the thread that made the call to
// |FlutterEngineRun|. All batons must be retured to the engine before
// initializing a |FlutterEngineShutdown|. Not doing the same will result in a
// memory leak.
VsyncCallback vsync_callback;
} FlutterProjectArgs;
FLUTTER_EXPORT
@@ -596,6 +605,14 @@ FlutterEngineResult FlutterEngineDispatchSemanticsAction(
const uint8_t* data,
size_t data_length);
// Notify the engine that a vsync event occured. A baton passed to the platform
// via the vsync callback must be returned.
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineOnVsync(FlutterEngine engine,
intptr_t baton,
uint64_t frame_start_time_nanos,
uint64_t frame_target_time_nanos);
// A profiling utility. Logs a trace duration begin event to the timeline. If
// the timeline is unavailable or disabled, this has no effect. Must be
// balanced with an duration end event (via

View File

@@ -5,6 +5,7 @@
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/shell/platform/embedder/vsync_waiter_embedder.h"
namespace shell {
@@ -191,4 +192,15 @@ bool EmbedderEngine::DispatchSemanticsAction(int id,
return true;
}
bool EmbedderEngine::OnVsyncEvent(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (!IsValid()) {
return false;
}
return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time,
frame_target_time);
}
} // namespace shell

View File

@@ -59,6 +59,10 @@ class EmbedderEngine {
blink::SemanticsAction action,
std::vector<uint8_t> args);
bool OnVsyncEvent(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
private:
const ThreadHost thread_host_;
std::unique_ptr<Shell> shell_;

View File

@@ -80,4 +80,15 @@ sk_sp<GrContext> PlatformViewEmbedder::CreateResourceContext() const {
return embedder_surface_->CreateResourceContext();
}
// |shell::PlatformView|
std::unique_ptr<VsyncWaiter> PlatformViewEmbedder::CreateVSyncWaiter() {
if (!platform_dispatch_table_.vsync_callback) {
// Superclass implementation creates a timer based fallback.
return PlatformView::CreateVSyncWaiter();
}
return std::make_unique<VsyncWaiterEmbedder>(
platform_dispatch_table_.vsync_callback, task_runners_);
}
} // namespace shell

View File

@@ -13,6 +13,7 @@
#include "flutter/shell/platform/embedder/embedder_surface.h"
#include "flutter/shell/platform/embedder/embedder_surface_gl.h"
#include "flutter/shell/platform/embedder/embedder_surface_software.h"
#include "flutter/shell/platform/embedder/vsync_waiter_embedder.h"
namespace shell {
@@ -30,7 +31,8 @@ class PlatformViewEmbedder final : public PlatformView {
UpdateSemanticsCustomActionsCallback
update_semantics_custom_actions_callback; // optional
PlatformMessageResponseCallback
platform_message_response_callback; // optional
platform_message_response_callback; // optional
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional
};
// Creates a platform view that sets up an OpenGL rasterizer.
@@ -68,6 +70,9 @@ class PlatformViewEmbedder final : public PlatformView {
// |shell::PlatformView|
sk_sp<GrContext> CreateResourceContext() const override;
// |shell::PlatformView|
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override;
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder);
};

View File

@@ -0,0 +1,43 @@
// 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 "flutter/shell/platform/embedder/vsync_waiter_embedder.h"
namespace shell {
VsyncWaiterEmbedder::VsyncWaiterEmbedder(VsyncCallback vsync_callback,
blink::TaskRunners task_runners)
: VsyncWaiter(std::move(task_runners)), vsync_callback_(vsync_callback) {
FML_DCHECK(vsync_callback_);
}
VsyncWaiterEmbedder::~VsyncWaiterEmbedder() = default;
// |shell::VsyncWaiter|
void VsyncWaiterEmbedder::AwaitVSync() {
auto* weak_waiter = new std::weak_ptr<VsyncWaiter>(shared_from_this());
vsync_callback_(reinterpret_cast<intptr_t>(weak_waiter));
}
// static
bool VsyncWaiterEmbedder::OnEmbedderVsync(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (baton == 0) {
return false;
}
auto* weak_waiter = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(baton);
auto strong_waiter = weak_waiter->lock();
delete weak_waiter;
if (!strong_waiter) {
return false;
}
strong_waiter->FireCallback(frame_start_time, frame_target_time);
return true;
}
} // namespace shell

View File

@@ -0,0 +1,36 @@
// 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 SHELL_PLATFORM_EMBEDDER_VSYNC_WAITER_EMBEDDER_H_
#define SHELL_PLATFORM_EMBEDDER_VSYNC_WAITER_EMBEDDER_H_
#include "flutter/fml/macros.h"
#include "flutter/shell/common/vsync_waiter.h"
namespace shell {
class VsyncWaiterEmbedder final : public VsyncWaiter {
public:
using VsyncCallback = std::function<void(intptr_t)>;
VsyncWaiterEmbedder(VsyncCallback callback, blink::TaskRunners task_runners);
~VsyncWaiterEmbedder() override;
static bool OnEmbedderVsync(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
private:
const VsyncCallback vsync_callback_;
// |shell::VsyncWaiter|
void AwaitVSync() override;
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterEmbedder);
};
} // namespace shell
#endif // SHELL_PLATFORM_EMBEDDER_VSYNC_WAITER_EMBEDDER_H_