From f81d96e1ddb45d2f06db078de7b6511f8ee2088c Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Tue, 28 Jul 2015 22:32:36 -0700 Subject: [PATCH] Drive frames from the vsync provider on Android Instead of using back pressure from swap buffers to drive the engine, this patch using the vsync signal from the Android framework. We still respect back pressure from swap buffers if we get too far ahead. --- sky/packages/sky_services/BUILD.gn | 1 + sky/services/vsync/BUILD.gn | 39 +++++++++++++++++++ .../org/domokit/vsync/VsyncProviderImpl.java | 36 +++++++++++++++++ sky/services/vsync/vsync.mojom | 9 +++++ sky/shell/BUILD.gn | 3 ++ .../org/domokit/sky/shell/SkyApplication.java | 9 +++++ sky/shell/ui/animator.cc | 20 +++++++--- sky/shell/ui/animator.h | 8 +++- sky/shell/ui/engine.cc | 7 ++++ 9 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 sky/services/vsync/BUILD.gn create mode 100644 sky/services/vsync/src/org/domokit/vsync/VsyncProviderImpl.java create mode 100644 sky/services/vsync/vsync.mojom diff --git a/sky/packages/sky_services/BUILD.gn b/sky/packages/sky_services/BUILD.gn index 3fcd4fd0860..049dc468c41 100644 --- a/sky/packages/sky_services/BUILD.gn +++ b/sky/packages/sky_services/BUILD.gn @@ -28,5 +28,6 @@ dart_pkg("sky_services") { "//sky/services/activity:interfaces", "//sky/services/media:interfaces", "//sky/services/testing:interfaces", + "//sky/services/vsync:interfaces", ] } diff --git a/sky/services/vsync/BUILD.gn b/sky/services/vsync/BUILD.gn new file mode 100644 index 00000000000..8b9e4200181 --- /dev/null +++ b/sky/services/vsync/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +group("vsync") { + testonly = true + + deps = [ + ":interfaces", + ] + + if (is_android) { + deps += [ ":vsync_lib" ] + } +} + +mojom("interfaces") { + sources = [ + "vsync.mojom", + ] +} + +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") + + android_library("vsync_lib") { + java_files = [ "src/org/domokit/vsync/VsyncProviderImpl.java" ] + + deps = [ + "//base:base_java", + "//mojo/public/java:bindings", + "//mojo/public/java:system", + ":interfaces_java", + ] + } +} diff --git a/sky/services/vsync/src/org/domokit/vsync/VsyncProviderImpl.java b/sky/services/vsync/src/org/domokit/vsync/VsyncProviderImpl.java new file mode 100644 index 00000000000..fa0d6d28bfd --- /dev/null +++ b/sky/services/vsync/src/org/domokit/vsync/VsyncProviderImpl.java @@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.domokit.vsync; + +import android.view.Choreographer; + +import org.chromium.mojo.system.MojoException; +import org.chromium.mojom.vsync.VsyncProvider; + +/** + * Android implementation of VsyncProvider. + */ +public class VsyncProviderImpl implements VsyncProvider { + private static final String TAG = "VsyncProviderImpl"; + + public VsyncProviderImpl() { + } + + @Override + public void close() {} + + @Override + public void onConnectionError(MojoException e) {} + + @Override + public void awaitVsync(final AwaitVsyncResponse callback) { + Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + callback.call(frameTimeNanos); + } + }); + } +} diff --git a/sky/services/vsync/vsync.mojom b/sky/services/vsync/vsync.mojom new file mode 100644 index 00000000000..d4445bac749 --- /dev/null +++ b/sky/services/vsync/vsync.mojom @@ -0,0 +1,9 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module vsync; + +interface VsyncProvider { + AwaitVsync() => (int64 time_stamp); +}; diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index 3c17d7e8c60..bc152d1eeda 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -20,6 +20,7 @@ common_deps = [ "//sky/engine/tonic", "//sky/engine/wtf", "//sky/services/engine:interfaces", + "//sky/services/vsync:interfaces", "//sky/shell/dart", "//ui/gfx/geometry", "//ui/gl", @@ -134,6 +135,8 @@ if (is_android) { "//sky/services/media:interfaces_java", "//sky/services/media:media_lib", "//sky/services/oknet", + "//sky/services/vsync:interfaces_java", + "//sky/services/vsync:vsync_lib", ] } diff --git a/sky/shell/android/org/domokit/sky/shell/SkyApplication.java b/sky/shell/android/org/domokit/sky/shell/SkyApplication.java index a871d47ad55..f89fae83102 100644 --- a/sky/shell/android/org/domokit/sky/shell/SkyApplication.java +++ b/sky/shell/android/org/domokit/sky/shell/SkyApplication.java @@ -21,9 +21,11 @@ import org.chromium.mojom.keyboard.KeyboardService; import org.chromium.mojom.media.MediaService; import org.chromium.mojom.mojo.NetworkService; import org.chromium.mojom.sensors.SensorService; +import org.chromium.mojom.vsync.VsyncProvider; import org.domokit.activity.ActivityImpl; import org.domokit.media.MediaServiceImpl; import org.domokit.oknet.NetworkServiceImpl; +import org.domokit.vsync.VsyncProviderImpl; /** * Sky implementation of {@link android.app.Application}, managing application-level global @@ -97,6 +99,13 @@ public class SkyApplication extends BaseChromiumApplication { SensorService.MANAGER.bind(new SensorServiceImpl(context), pipe); } }); + + registry.register(VsyncProvider.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + VsyncProvider.MANAGER.bind(new VsyncProviderImpl(), pipe); + } + }); } private void initJavaUtils() { diff --git a/sky/shell/ui/animator.cc b/sky/shell/ui/animator.cc index 83c02bb1fe1..39eb5cf3124 100644 --- a/sky/shell/ui/animator.cc +++ b/sky/shell/ui/animator.cc @@ -39,9 +39,14 @@ void Animator::RequestFrame() { return; } - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&Animator::BeginFrame, weak_factory_.GetWeakPtr())); + if (vsync_provider_) { + vsync_provider_->AwaitVsync( + base::Bind(&Animator::BeginFrame, weak_factory_.GetWeakPtr())); + } else { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&Animator::BeginFrame, weak_factory_.GetWeakPtr(), 0)); + } } void Animator::Stop() { @@ -54,7 +59,7 @@ void Animator::Start() { RequestFrame(); } -void Animator::BeginFrame() { +void Animator::BeginFrame(int64_t time_stamp) { TRACE_EVENT_ASYNC_END0("sky", "Frame request pending", this); DCHECK(engine_requested_frame_); engine_requested_frame_ = false; @@ -62,7 +67,10 @@ void Animator::BeginFrame() { DCHECK(outstanding_requests_ > 0); DCHECK(outstanding_requests_ <= kPipelineDepth) << outstanding_requests_; - engine_->BeginFrame(base::TimeTicks::Now()); + base::TimeTicks frame_time = time_stamp ? + base::TimeTicks::FromInternalValue(time_stamp) : base::TimeTicks::Now(); + + engine_->BeginFrame(frame_time); skia::RefPtr picture = engine_->Paint(); config_.gpu_task_runner->PostTaskAndReply( @@ -79,7 +87,7 @@ void Animator::OnFrameComplete() { if (did_defer_frame_request_) { did_defer_frame_request_ = false; - BeginFrame(); + BeginFrame(0); } } diff --git a/sky/shell/ui/animator.h b/sky/shell/ui/animator.h index 1d8b17d8da4..764b3b01079 100644 --- a/sky/shell/ui/animator.h +++ b/sky/shell/ui/animator.h @@ -6,6 +6,7 @@ #define SKY_SHELL_UI_ANIMATOR_H_ #include "base/memory/weak_ptr.h" +#include "sky/services/vsync/vsync.mojom.h" #include "sky/shell/ui/engine.h" namespace sky { @@ -21,12 +22,17 @@ class Animator { void Start(); void Stop(); + void set_vsync_provider(vsync::VsyncProviderPtr vsync_provider) { + vsync_provider_ = vsync_provider.Pass(); + } + private: - void BeginFrame(); + void BeginFrame(int64_t time_stamp); void OnFrameComplete(); Engine::Config config_; Engine* engine_; + vsync::VsyncProviderPtr vsync_provider_; int outstanding_requests_; bool did_defer_frame_request_; bool engine_requested_frame_; diff --git a/sky/shell/ui/engine.cc b/sky/shell/ui/engine.cc index 800f456aa51..840dd9fa020 100644 --- a/sky/shell/ui/engine.cc +++ b/sky/shell/ui/engine.cc @@ -65,6 +65,13 @@ Engine::Engine(const Config& config) mojo::ServiceProviderPtr service_provider = CreateServiceProvider(config.service_provider_context); mojo::ConnectToService(service_provider.get(), &network_service_); + +#if defined(OS_ANDROID) + // TODO(abarth): Implement VsyncProvider on other platforms. + vsync::VsyncProviderPtr vsync_provider; + mojo::ConnectToService(service_provider.get(), &vsync_provider); + animator_->set_vsync_provider(vsync_provider.Pass()); +#endif } Engine::~Engine() {