summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsievers@chromium.org <sievers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 23:40:32 +0000
committersievers@chromium.org <sievers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 23:40:32 +0000
commitf22e4584788e38f3b4b8b03981ac308f83cb3fc0 (patch)
treed970d3b1ea42a4feaec5e5e50eb7ba71c5763ef5
parent6daa739b3beaed1686d73da9d55ec8e8d54b9d49 (diff)
downloadchromium_src-f22e4584788e38f3b4b8b03981ac308f83cb3fc0.zip
chromium_src-f22e4584788e38f3b4b8b03981ac308f83cb3fc0.tar.gz
chromium_src-f22e4584788e38f3b4b8b03981ac308f83cb3fc0.tar.bz2
Android: Consolidate and simplify VSync logic
This moves handling of VSync over to WindowAndroid. It can have one client to receive vsync signals for the main browser-side scheduling logic. It also forwards the vsync to the WindowAndroidObservers, i.e. RenderWidgetHostView where it's used for sending BeginFrame signals to the renderer. This prepares for consolidating the scheduling logic in a single place upstream. Which will then further allow us to use the cc scheduler (with SingleThreadProxy) and unblock the landing of https://codereview.chromium.org/134623005/. BUG=234173,363479 NOTRY=True Review URL: https://codereview.chromium.org/236193013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266995 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java6
-rw-r--r--content/browser/android/content_view_core_impl.cc81
-rw-r--r--content/browser/android/content_view_core_impl.h13
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.cc79
-rw-r--r--content/browser/renderer_host/render_widget_host_view_android.h11
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java128
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java95
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/VSyncManager.java36
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java1
-rw-r--r--ui/android/java/src/org/chromium/ui/VSyncMonitor.java (renamed from content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java)28
-rw-r--r--ui/android/java/src/org/chromium/ui/base/WindowAndroid.java53
-rw-r--r--ui/base/android/window_android.cc21
-rw-r--r--ui/base/android/window_android.h7
-rw-r--r--ui/base/android/window_android_observer.h2
14 files changed, 169 insertions, 392 deletions
diff --git a/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java b/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
index a7be42a..c133ec7 100644
--- a/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
+++ b/chrome/android/shell/javatests/src/org/chromium/chrome/shell/ChromeShellUrlTest.java
@@ -10,6 +10,7 @@ import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.ContentViewRenderView;
+import org.chromium.ui.base.WindowAndroid;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -95,14 +96,17 @@ public class ChromeShellUrlTest extends ChromeShellTestBase {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
+ WindowAndroid windowAndroid = new WindowAndroid(
+ getInstrumentation().getTargetContext().getApplicationContext());
ContentViewRenderView contentViewRenderView =
new ContentViewRenderView(getInstrumentation().getTargetContext(),
- activity.getWindowAndroid());
+ windowAndroid);
contentViewRenderView.setCurrentContentViewCore(
activity.getActiveContentViewCore());
}
});
} catch (Throwable e) {
+ e.printStackTrace();
fail("Could not create a ContentViewRenderView: " + e);
}
}
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index a291f97..9d3dd4d 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -87,10 +87,6 @@ namespace content {
namespace {
-const unsigned int kDefaultVSyncIntervalMicros = 16666u;
-// TODO(brianderson): Use adaptive draw-time estimation.
-const float kDefaultBrowserCompositeVSyncFraction = 1.0f / 3;
-
const void* kContentViewUserDataKey = &kContentViewUserDataKey;
int GetRenderProcessIdFromRenderViewHost(RenderViewHost* host) {
@@ -223,10 +219,6 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env,
web_contents_(static_cast<WebContentsImpl*>(web_contents)),
root_layer_(cc::Layer::Create()),
dpi_scale_(GetPrimaryDisplayDeviceScaleFactor()),
- vsync_interval_(base::TimeDelta::FromMicroseconds(
- kDefaultVSyncIntervalMicros)),
- expected_browser_composite_time_(base::TimeDelta::FromMicroseconds(
- kDefaultVSyncIntervalMicros * kDefaultBrowserCompositeVSyncFraction)),
view_android_(view_android),
window_android_(window_android),
device_orientation_(0),
@@ -435,7 +427,6 @@ void ContentViewCoreImpl::OnTabCrashed() {
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
- Java_ContentViewCore_resetVSyncNotification(env, obj.obj());
}
// All positions and sizes are in CSS pixels.
@@ -855,30 +846,6 @@ void ContentViewCoreImpl::LoadUrl(
GetWebContents()->GetController().LoadURLWithParams(params);
}
-void ContentViewCoreImpl::AddBeginFrameSubscriber() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_addVSyncSubscriber(env, obj.obj());
-}
-
-void ContentViewCoreImpl::RemoveBeginFrameSubscriber() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_removeVSyncSubscriber(env, obj.obj());
-}
-
-void ContentViewCoreImpl::SetNeedsAnimate() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
- if (obj.is_null())
- return;
- Java_ContentViewCore_setNeedsAnimate(env, obj.obj());
-}
-
ui::ViewAndroid* ContentViewCoreImpl::GetViewAndroid() const {
// view_android_ should never be null for Chrome.
DCHECK(view_android_);
@@ -1326,54 +1293,6 @@ void ContentViewCoreImpl::RemoveJavascriptInterface(JNIEnv* env,
ConvertJavaStringToUTF16(env, name));
}
-void ContentViewCoreImpl::UpdateVSyncParameters(JNIEnv* env, jobject /* obj */,
- jlong timebase_micros,
- jlong interval_micros) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return;
-
- RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(
- view->GetRenderWidgetHost());
-
- host->UpdateVSyncParameters(
- base::TimeTicks::FromInternalValue(timebase_micros),
- base::TimeDelta::FromMicroseconds(interval_micros));
-
- vsync_interval_ =
- base::TimeDelta::FromMicroseconds(interval_micros);
- expected_browser_composite_time_ =
- vsync_interval_ * kDefaultBrowserCompositeVSyncFraction;
-}
-
-void ContentViewCoreImpl::OnVSync(JNIEnv* env, jobject /* obj */,
- jlong frame_time_micros) {
- base::TimeTicks frame_time =
- base::TimeTicks::FromInternalValue(frame_time_micros);
- SendBeginFrame(frame_time);
-}
-
-void ContentViewCoreImpl::SendBeginFrame(base::TimeTicks frame_time) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return;
-
- base::TimeTicks display_time = frame_time + vsync_interval_;
- base::TimeTicks deadline = display_time - expected_browser_composite_time_;
-
- view->SendBeginFrame(
- cc::BeginFrameArgs::Create(frame_time, deadline, vsync_interval_));
-}
-
-jboolean ContentViewCoreImpl::OnAnimate(JNIEnv* env, jobject /* obj */,
- jlong frame_time_micros) {
- RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
- if (!view)
- return false;
-
- return view->Animate(base::TimeTicks::FromInternalValue(frame_time_micros));
-}
-
void ContentViewCoreImpl::WasResized(JNIEnv* env, jobject obj) {
RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
if (view) {
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index f7d75e0..dd39522 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -195,10 +195,6 @@ class ContentViewCoreImpl : public ContentViewCore,
jint max_entries);
base::android::ScopedJavaLocalRef<jstring>
GetOriginalUrlForActiveNavigationEntry(JNIEnv* env, jobject obj);
- void UpdateVSyncParameters(JNIEnv* env, jobject obj, jlong timebase_micros,
- jlong interval_micros);
- void OnVSync(JNIEnv* env, jobject /* obj */, jlong frame_time_micros);
- jboolean OnAnimate(JNIEnv* env, jobject /* obj */, jlong frame_time_micros);
void WasResized(JNIEnv* env, jobject obj);
jboolean IsRenderWidgetHostViewReady(JNIEnv* env, jobject obj);
void ExitFullscreen(JNIEnv* env, jobject obj);
@@ -308,9 +304,6 @@ class ContentViewCoreImpl : public ContentViewCore,
void AttachLayer(scoped_refptr<cc::Layer> layer);
void RemoveLayer(scoped_refptr<cc::Layer> layer);
- void AddBeginFrameSubscriber();
- void RemoveBeginFrameSubscriber();
- void SetNeedsAnimate();
private:
class ContentViewUserData;
@@ -338,8 +331,6 @@ class ContentViewCoreImpl : public ContentViewCore,
blink::WebGestureEvent MakeGestureEvent(
blink::WebInputEvent::Type type, int64 time_ms, float x, float y) const;
- void SendBeginFrame(base::TimeTicks frame_time);
-
gfx::Size GetViewportSizePix() const;
gfx::Size GetViewportSizeOffsetPix() const;
@@ -371,10 +362,6 @@ class ContentViewCoreImpl : public ContentViewCore,
// Device scale factor.
float dpi_scale_;
- // Variables used to keep track of frame timestamps and deadlines.
- base::TimeDelta vsync_interval_;
- base::TimeDelta expected_browser_composite_time_;
-
// The Android view that can be used to add and remove decoration layers
// like AutofillPopup.
ui::ViewAndroid* view_android_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 48caee2..9953fae 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -531,39 +531,20 @@ void RenderWidgetHostViewAndroid::OnDidOverscroll(
device_scale_factor),
gfx::ScaleVector2d(params.current_fling_velocity,
device_scale_factor))) {
- content_view_core_->SetNeedsAnimate();
+ SetNeedsAnimate();
}
}
-void RenderWidgetHostViewAndroid::SendBeginFrame(
- const cc::BeginFrameArgs& args) {
- TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
- if (!host_)
+void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
+ if (enabled == needs_begin_frame_)
return;
- if (flush_input_requested_) {
- flush_input_requested_ = false;
- host_->FlushInput();
- content_view_core_->RemoveBeginFrameSubscriber();
- }
-
- host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
-}
-
-void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
"enabled", enabled);
- // ContentViewCoreImpl handles multiple subscribers to the BeginFrame, so
- // we have to make sure calls to ContentViewCoreImpl's
- // {Add,Remove}BeginFrameSubscriber are balanced, even if
- // RenderWidgetHostViewAndroid's may not be.
- if (content_view_core_ && needs_begin_frame_ != enabled) {
- if (enabled)
- content_view_core_->AddBeginFrameSubscriber();
- else
- content_view_core_->RemoveBeginFrameSubscriber();
- needs_begin_frame_ = enabled;
- }
+ if (content_view_core_ && enabled)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+
+ needs_begin_frame_ = enabled;
}
void RenderWidgetHostViewAndroid::OnStartContentIntent(
@@ -1083,6 +1064,10 @@ void RenderWidgetHostViewAndroid::RemoveLayers() {
overscroll_effect_->Disable();
}
+void RenderWidgetHostViewAndroid::SetNeedsAnimate() {
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
return overscroll_effect_->Animate(frame_time);
}
@@ -1194,7 +1179,6 @@ void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
return;
TRACE_EVENT0("input", "RenderWidgetHostViewAndroid::OnSetNeedsFlushInput");
flush_input_requested_ = true;
- content_view_core_->AddBeginFrameSubscriber();
}
void RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManagerIfNeeded() {
@@ -1285,6 +1269,14 @@ void RenderWidgetHostViewAndroid::SendTouchEvent(
const blink::WebTouchEvent& event) {
if (host_)
host_->ForwardTouchEventWithLatencyInfo(event, CreateLatencyInfo(event));
+
+ // Send a proactive BeginFrame on the next vsync to reduce latency.
+ // This is good enough as long as the first touch event has Begin semantics
+ // and the actual scroll happens on the next vsync.
+ // TODO: Is this actually still needed?
+ if (content_view_core_) {
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+ }
}
void RenderWidgetHostViewAndroid::SendMouseEvent(
@@ -1351,6 +1343,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
if (content_view_core_ && !using_synchronous_compositor_) {
content_view_core_->GetWindowAndroid()->AddObserver(this);
observing_root_window_ = true;
+ if (needs_begin_frame_)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
}
if (resize && content_view_core_)
@@ -1386,6 +1380,37 @@ void RenderWidgetHostViewAndroid::OnWillDestroyWindow() {
observing_root_window_ = false;
}
+void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) {
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::OnVSync");
+ if (!host_)
+ return;
+
+ if (flush_input_requested_) {
+ flush_input_requested_ = false;
+ host_->FlushInput();
+ }
+
+ TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
+ base::TimeTicks display_time = frame_time + vsync_period;
+
+ // TODO(brianderson): Use adaptive draw-time estimation.
+ base::TimeDelta estimated_browser_composite_time =
+ base::TimeDelta::FromMicroseconds(
+ (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
+
+ base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+
+ host_->Send(new ViewMsg_BeginFrame(
+ host_->GetRoutingID(),
+ cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
+
+ // TODO(sievers): This should use the LayerTreeHostClient callback
+ bool needs_animate = Animate(frame_time);
+ if (needs_begin_frame_ || needs_animate)
+ content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
void RenderWidgetHostViewAndroid::OnLostResources() {
ReleaseLocksOnSurface();
if (layer_.get())
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 978d1f3..dede4c0 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -197,6 +197,8 @@ class RenderWidgetHostViewAndroid
virtual void OnAttachCompositor() OVERRIDE {}
virtual void OnDetachCompositor() OVERRIDE;
virtual void OnWillDestroyWindow() OVERRIDE;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) OVERRIDE;
// ImageTransportFactoryAndroidObserver implementation.
virtual void OnLostResources() OVERRIDE;
@@ -214,7 +216,6 @@ class RenderWidgetHostViewAndroid
void SendMouseEvent(const blink::WebMouseEvent& event);
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendGestureEvent(const blink::WebGestureEvent& event);
- void SendBeginFrame(const cc::BeginFrameArgs& args);
void OnTextInputStateChanged(const ViewHostMsg_TextInputState_Params& params);
void OnDidChangeBodyBackgroundColor(SkColor color);
@@ -242,10 +243,6 @@ class RenderWidgetHostViewAndroid
void MoveCaret(const gfx::Point& point);
- // Returns true when animation ticks are still needed. This avoids a separate
- // round-trip for requesting follow-up animation.
- bool Animate(base::TimeTicks frame_time);
-
void SynchronousFrameMetadata(
const cc::CompositorFrameMetadata& frame_metadata);
@@ -307,6 +304,10 @@ class RenderWidgetHostViewAndroid
void InternalSwapCompositorFrame(uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame);
+ void SetNeedsAnimate();
+ bool Animate(base::TimeTicks frame_time);
+
+
// The model object.
RenderWidgetHostImpl* host_;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index e59d6f8..5532e06 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -209,98 +209,6 @@ public class ContentViewCore
public void onSmartClipDataExtracted(String result);
}
- private VSyncManager.Provider mVSyncProvider;
- private VSyncManager.Listener mVSyncListener;
- private int mVSyncSubscriberCount;
- private boolean mVSyncListenerRegistered;
-
- // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer.
- // When we do this, we also need to avoid sending the real vsync signal for the current
- // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification.
- private boolean mDidSignalVSyncUsingInputEvent;
-
- public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) {
- if (mVSyncProvider != null && mVSyncListenerRegistered) {
- mVSyncProvider.unregisterVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = false;
- }
-
- mVSyncProvider = vsyncProvider;
- mVSyncListener = new VSyncManager.Listener() {
- @Override
- public void updateVSync(long tickTimeMicros, long intervalMicros) {
- if (mNativeContentViewCore != 0) {
- nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros,
- intervalMicros);
- }
- }
-
- @Override
- public void onVSync(long frameTimeMicros) {
- animateIfNecessary(frameTimeMicros);
-
- if (mRequestedVSyncForInput) {
- mRequestedVSyncForInput = false;
- removeVSyncSubscriber();
- }
- if (mNativeContentViewCore != 0) {
- nativeOnVSync(mNativeContentViewCore, frameTimeMicros);
- }
- }
- };
-
- if (mVSyncSubscriberCount > 0) {
- // addVSyncSubscriber() is called before getVSyncListener.
- vsyncProvider.registerVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = true;
- }
-
- return mVSyncListener;
- }
-
- @CalledByNative
- void addVSyncSubscriber() {
- if (!isVSyncNotificationEnabled()) {
- mDidSignalVSyncUsingInputEvent = false;
- }
- if (mVSyncProvider != null && !mVSyncListenerRegistered) {
- mVSyncProvider.registerVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = true;
- }
- mVSyncSubscriberCount++;
- }
-
- @CalledByNative
- void removeVSyncSubscriber() {
- if (mVSyncProvider != null && mVSyncSubscriberCount == 1) {
- assert mVSyncListenerRegistered;
- mVSyncProvider.unregisterVSyncListener(mVSyncListener);
- mVSyncListenerRegistered = false;
- }
- mVSyncSubscriberCount--;
- assert mVSyncSubscriberCount >= 0;
- }
-
- @CalledByNative
- private void resetVSyncNotification() {
- while (isVSyncNotificationEnabled()) removeVSyncSubscriber();
- mVSyncSubscriberCount = 0;
- mVSyncListenerRegistered = false;
- mNeedAnimate = false;
- }
-
- private boolean isVSyncNotificationEnabled() {
- return mVSyncProvider != null && mVSyncListenerRegistered;
- }
-
- @CalledByNative
- private void setNeedsAnimate() {
- if (!mNeedAnimate) {
- mNeedAnimate = true;
- addVSyncSubscriber();
- }
- }
-
private final Context mContext;
private ViewGroup mContainerView;
private InternalAccessDelegate mContainerViewInternals;
@@ -399,16 +307,6 @@ public class ContentViewCore
// Whether we received a new frame since consumePendingRendererFrame() was last called.
private boolean mPendingRendererFrame = false;
- // Whether we should animate at the next vsync tick.
- private boolean mNeedAnimate = false;
-
- // Whether we requested a proactive vsync event in response to touch input.
- // This reduces the latency of responding to input by ensuring the renderer
- // is sent a BeginFrame for every touch event we receive. Otherwise the
- // renderer's SetNeedsBeginFrame message would get serviced at the next
- // vsync.
- private boolean mRequestedVSyncForInput = false;
-
// On single tap this will store the x, y coordinates of the touch.
private int mSingleTapX;
private int mSingleTapY;
@@ -850,8 +748,6 @@ public class ContentViewCore
nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
}
mWebContents = null;
- resetVSyncNotification();
- mVSyncProvider = null;
if (mViewAndroid != null) mViewAndroid.destroy();
mNativeContentViewCore = 0;
mContentSettings = null;
@@ -1194,11 +1090,6 @@ public class ContentViewCore
cancelRequestToScrollFocusedEditableNodeIntoView();
- if (!mRequestedVSyncForInput) {
- mRequestedVSyncForInput = true;
- addVSyncSubscriber();
- }
-
final int eventAction = offset.getActionMasked();
// Only these actions have any effect on gesture detection. Other
@@ -3119,18 +3010,6 @@ public class ContentViewCore
return new Rect(x, y, right, bottom);
}
- private boolean onAnimate(long frameTimeMicros) {
- if (mNativeContentViewCore == 0) return false;
- return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros);
- }
-
- private void animateIfNecessary(long frameTimeMicros) {
- if (mNeedAnimate) {
- mNeedAnimate = onAnimate(frameTimeMicros);
- if (!mNeedAnimate) removeVSyncSubscriber();
- }
- }
-
public void extractSmartClipData(int x, int y, int width, int height) {
if (mNativeContentViewCore != 0) {
nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height);
@@ -3340,13 +3219,6 @@ public class ContentViewCore
private native String nativeGetOriginalUrlForActiveNavigationEntry(
long nativeContentViewCoreImpl);
- private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl,
- long timebaseMicros, long intervalMicros);
-
- private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros);
-
- private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros);
-
private native void nativeWasResized(long nativeContentViewCoreImpl);
private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
index d18c7f2..9491258 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
@@ -9,7 +9,6 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
-import android.os.Build;
import android.os.Handler;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -18,8 +17,6 @@ import android.widget.FrameLayout;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
-import org.chromium.base.ObserverList;
-import org.chromium.base.ObserverList.RewindableIterator;
import org.chromium.base.TraceEvent;
import org.chromium.ui.base.WindowAndroid;
@@ -30,7 +27,7 @@ import org.chromium.ui.base.WindowAndroid;
* Note that only one ContentViewCore can be shown at a time.
*/
@JNINamespace("content")
-public class ContentViewRenderView extends FrameLayout {
+public class ContentViewRenderView extends FrameLayout implements WindowAndroid.VSyncClient {
private static final int MAX_SWAP_BUFFER_COUNT = 2;
// The native side of this object.
@@ -38,7 +35,7 @@ public class ContentViewRenderView extends FrameLayout {
private final SurfaceHolder.Callback mSurfaceCallback;
private final SurfaceView mSurfaceView;
- private final VSyncAdapter mVSyncAdapter;
+ private final WindowAndroid mRootWindow;
private int mPendingRenders;
private int mPendingSwapBuffers;
@@ -64,6 +61,8 @@ public class ContentViewRenderView extends FrameLayout {
mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer());
assert mNativeContentViewRenderView != 0;
+ mRootWindow = rootWindow;
+ rootWindow.setVSyncClient(this);
mSurfaceView = createSurfaceView(getContext());
mSurfaceView.setZOrderMediaOverlay(true);
mSurfaceCallback = new SurfaceHolder.Callback() {
@@ -99,86 +98,23 @@ public class ContentViewRenderView extends FrameLayout {
};
mSurfaceView.getHolder().addCallback(mSurfaceCallback);
- mVSyncAdapter = new VSyncAdapter(getContext());
addView(mSurfaceView,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
}
- private class VSyncAdapter implements VSyncManager.Provider, VSyncMonitor.Listener {
- private final VSyncMonitor mVSyncMonitor;
- private boolean mVSyncNotificationEnabled;
- private VSyncManager.Listener mVSyncListener;
- private final ObserverList<VSyncManager.Listener> mCurrentVSyncListeners;
- private final RewindableIterator<VSyncManager.Listener> mCurrentVSyncListenersIterator;
-
- // The VSyncMonitor gives the timebase for the actual vsync, but we don't want render until
- // we have had a chance for input events to propagate to the compositor thread. This takes
- // 3 ms typically, so we adjust the vsync timestamps forward by a bit to give input events a
- // chance to arrive.
- private static final long INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS = 3200;
-
- VSyncAdapter(Context context) {
- mVSyncMonitor = new VSyncMonitor(context, this);
- mCurrentVSyncListeners = new ObserverList<VSyncManager.Listener>();
- mCurrentVSyncListenersIterator = mCurrentVSyncListeners.rewindableIterator();
- }
-
- @Override
- public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
- if (mNeedToRender) {
- if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) {
- mNeedToRender = false;
- mPendingRenders++;
- render();
- } else {
- TraceEvent.instant("ContentViewRenderView:bail");
- }
- }
-
- if (mVSyncListener != null) {
- if (mVSyncNotificationEnabled) {
- for (mCurrentVSyncListenersIterator.rewind();
- mCurrentVSyncListenersIterator.hasNext();) {
- mCurrentVSyncListenersIterator.next().onVSync(vsyncTimeMicros);
- }
- mVSyncMonitor.requestUpdate();
- } else {
- // Compensate for input event lag. Input events are delivered immediately on
- // pre-JB releases, so this adjustment is only done for later versions.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS;
- }
- mVSyncListener.updateVSync(vsyncTimeMicros,
- mVSyncMonitor.getVSyncPeriodInMicroseconds());
- }
- }
- }
-
- @Override
- public void registerVSyncListener(VSyncManager.Listener listener) {
- if (!mVSyncNotificationEnabled) mVSyncMonitor.requestUpdate();
- mCurrentVSyncListeners.addObserver(listener);
- mVSyncNotificationEnabled = true;
- }
-
- @Override
- public void unregisterVSyncListener(VSyncManager.Listener listener) {
- mCurrentVSyncListeners.removeObserver(listener);
- if (mCurrentVSyncListeners.isEmpty()) {
- mVSyncNotificationEnabled = false;
+ @Override
+ public void onVSync(long vsyncTimeMicros) {
+ if (mNeedToRender) {
+ if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) {
+ mNeedToRender = false;
+ mPendingRenders++;
+ render();
+ } else {
+ TraceEvent.instant("ContentViewRenderView:bail");
}
}
-
- void setVSyncListener(VSyncManager.Listener listener) {
- mVSyncListener = listener;
- if (mVSyncListener != null) mVSyncMonitor.requestUpdate();
- }
-
- void requestUpdate() {
- mVSyncMonitor.requestUpdate();
- }
}
/**
@@ -198,6 +134,7 @@ public class ContentViewRenderView extends FrameLayout {
* native resource can be freed.
*/
public void destroy() {
+ mRootWindow.setVSyncClient(null);
mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
nativeDestroy(mNativeContentViewRenderView);
mNativeContentViewRenderView = 0;
@@ -209,7 +146,6 @@ public class ContentViewRenderView extends FrameLayout {
if (mContentViewCore != null) {
mContentViewCore.onPhysicalBackingSizeChanged(getWidth(), getHeight());
- mVSyncAdapter.setVSyncListener(mContentViewCore.getVSyncListener(mVSyncAdapter));
nativeSetCurrentContentViewCore(mNativeContentViewRenderView,
mContentViewCore.getNativeContentViewCore());
} else {
@@ -281,12 +217,11 @@ public class ContentViewRenderView extends FrameLayout {
} else {
post(mRenderRunnable);
}
- mVSyncAdapter.requestUpdate();
} else if (mPendingRenders <= 0) {
assert mPendingRenders == 0;
TraceEvent.instant("requestRender:later");
mNeedToRender = true;
- mVSyncAdapter.requestUpdate();
+ mRootWindow.requestVSyncUpdate();
}
}
diff --git a/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java b/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java
deleted file mode 100644
index a152b41..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/VSyncManager.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2013 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.chromium.content.browser;
-
-public abstract class VSyncManager {
- /**
- * Interface for requesting notification of the display vsync signal. The provider will call
- * Listener.onVSync() to notify about vsync. The number of registrations and unregistrations of
- * a given listener must be balanced.
- */
- public static interface Provider {
- void registerVSyncListener(Listener listener);
- void unregisterVSyncListener(Listener listener);
- }
-
- /**
- * Interface for receiving vsync notifications and information about the display refresh
- * interval.
- */
- public static interface Listener {
- /**
- * Notification of a vsync event.
- * @param frameTimeMicros The latest vsync frame time in microseconds.
- */
- void onVSync(long frameTimeMicros);
-
- /**
- * Update with the latest vsync parameters.
- * @param tickTimeMicros The latest vsync tick time in microseconds.
- * @param intervalMicros The vsync interval in microseconds.
- */
- void updateVSync(long tickTimeMicros, long intervalMicros);
- }
-}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
index 0b137c7..59e0c62 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
@@ -10,6 +10,7 @@ import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import org.chromium.base.ThreadUtils;
+import org.chromium.ui.VSyncMonitor;
import java.util.Arrays;
import java.util.concurrent.Callable;
diff --git a/content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
index ce9f36df..527b831 100644
--- a/content/public/android/java/src/org/chromium/content/browser/VSyncMonitor.java
+++ b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
@@ -1,8 +1,8 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 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.chromium.content.browser;
+package org.chromium.ui;
import android.content.Context;
import android.os.Build;
@@ -61,11 +61,22 @@ public class VSyncMonitor {
private final Runnable mSyntheticVSyncRunnable;
private long mLastVSyncCpuTimeNano;
+ /**
+ * Constructs a VSyncMonitor
+ * @param context The application context.
+ * @param listener The listener receiving VSync notifications.
+ */
public VSyncMonitor(Context context, VSyncMonitor.Listener listener) {
this(context, listener, true);
}
- VSyncMonitor(Context context, VSyncMonitor.Listener listener, boolean enableJBVSync) {
+ /**
+ * Constructs a VSyncMonitor
+ * @param context The application context.
+ * @param listener The listener receiving VSync notifications.
+ * @param enableJBVsync Whether to allow Choreographer-based notifications on JB and up.
+ */
+ public VSyncMonitor(Context context, VSyncMonitor.Listener listener, boolean enableJBVSync) {
mListener = listener;
float refreshRate = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getRefreshRate();
@@ -123,7 +134,7 @@ public class VSyncMonitor {
/**
* Determine whether a true vsync signal is available on this platform.
*/
- public boolean isVSyncSignalAvailable() {
+ private boolean isVSyncSignalAvailable() {
return mChoreographer != null;
}
@@ -136,15 +147,6 @@ public class VSyncMonitor {
}
/**
- * Unregister the listener.
- * No vsync events will be reported afterwards.
- */
- public void unregisterListener() {
- stop();
- mListener = null;
- }
-
- /**
* Request to be notified of the closest display vsync events.
* Listener.onVSync() will be called soon after the upcoming vsync pulses.
* It will be called at most MAX_AUTO_ONVSYNC_COUNT times unless requestUpdate() is called.
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 309b735..8be2dd0 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -17,6 +17,7 @@ import android.widget.Toast;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import org.chromium.ui.VSyncMonitor;
import java.lang.ref.WeakReference;
import java.util.HashMap;
@@ -30,6 +31,8 @@ public class WindowAndroid {
// Native pointer to the c++ WindowAndroid object.
private long mNativeWindowAndroid = 0;
+ private final VSyncMonitor mVSyncMonitor;
+ private VSyncClient mVSyncClient = null;
// A string used as a key to store intent errors in a bundle
static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors";
@@ -45,6 +48,18 @@ public class WindowAndroid {
// the Android lint warning "UseSparseArrays".
protected HashMap<Integer, String> mIntentErrors;
+ private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listener() {
+ @Override
+ public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
+ if (mVSyncClient != null) {
+ mVSyncClient.onVSync(vsyncTimeMicros);
+ }
+ if (mNativeWindowAndroid != 0) {
+ nativeOnVSync(mNativeWindowAndroid, vsyncTimeMicros);
+ }
+ }
+ };
+
/**
* @param context The application context.
*/
@@ -54,6 +69,7 @@ public class WindowAndroid {
mApplicationContext = context;
mOutstandingIntents = new SparseArray<IntentCallback>();
mIntentErrors = new HashMap<Integer, String>();
+ mVSyncMonitor = new VSyncMonitor(context, mVSyncListener);
}
/**
@@ -216,6 +232,36 @@ public class WindowAndroid {
}
/**
+ * An interface to receive VSync notifications from the window.
+ * The one and only client is set with setVSyncClient(client).
+ */
+ public interface VSyncClient {
+ /**
+ * Called very soon after the start of the display's vertical sync period.
+ * @param vsyncTimeMicros Absolute frame time in microseconds.
+ */
+ void onVSync(long vsyncTimeMicros);
+ }
+
+ /**
+ * Sets the VSyncClient.
+ * @param client The client receiving VSync notifications.
+ */
+ public void setVSyncClient(VSyncClient client) {
+ assert mVSyncClient == null || client == null;
+ mVSyncClient = client;
+ }
+
+ /**
+ * Request a VSync callback.
+ * VSyncClient.onVSync() will be called at least once.
+ */
+ @CalledByNative
+ public void requestVSyncUpdate() {
+ mVSyncMonitor.requestUpdate();
+ }
+
+ /**
* An interface that intent callback objects have to implement.
*/
public interface IntentCallback {
@@ -226,7 +272,7 @@ public class WindowAndroid {
* @param contentResolver An instance of ContentResolver class for accessing returned data.
* @param data The data returned by the intent.
*/
- public void onIntentCompleted(WindowAndroid window, int resultCode,
+ void onIntentCompleted(WindowAndroid window, int resultCode,
ContentResolver contentResolver, Intent data);
}
@@ -257,7 +303,7 @@ public class WindowAndroid {
*/
public long getNativePointer() {
if (mNativeWindowAndroid == 0) {
- mNativeWindowAndroid = nativeInit();
+ mNativeWindowAndroid = nativeInit(mVSyncMonitor.getVSyncPeriodInMicroseconds());
}
return mNativeWindowAndroid;
}
@@ -271,7 +317,8 @@ public class WindowAndroid {
return null;
}
- private native long nativeInit();
+ private native long nativeInit(long vsyncPeriod);
+ private native void nativeOnVSync(long nativeWindowAndroid, long vsyncTimeMicros);
private native void nativeDestroy(long nativeWindowAndroid);
}
diff --git a/ui/base/android/window_android.cc b/ui/base/android/window_android.cc
index b7a7e13..bbacf9c 100644
--- a/ui/base/android/window_android.cc
+++ b/ui/base/android/window_android.cc
@@ -17,9 +17,10 @@ namespace ui {
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
-WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj)
+WindowAndroid::WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period)
: weak_java_window_(env, obj),
- compositor_(NULL) {
+ compositor_(NULL),
+ vsync_period_(base::TimeDelta::FromInternalValue(vsync_period)) {
}
void WindowAndroid::Destroy(JNIEnv* env, jobject obj) {
@@ -89,12 +90,24 @@ void WindowAndroid::DetachCompositor() {
observer_list_.Clear();
}
+void WindowAndroid::RequestVSyncUpdate() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_WindowAndroid_requestVSyncUpdate(env, GetJavaObject().obj());
+}
+
+void WindowAndroid::OnVSync(JNIEnv* env, jobject obj, jlong time_micros) {
+ FOR_EACH_OBSERVER(
+ WindowAndroidObserver,
+ observer_list_,
+ OnVSync(base::TimeTicks::FromInternalValue(time_micros), vsync_period_));
+}
+
// ----------------------------------------------------------------------------
// Native JNI methods
// ----------------------------------------------------------------------------
-jlong Init(JNIEnv* env, jobject obj) {
- WindowAndroid* window = new WindowAndroid(env, obj);
+jlong Init(JNIEnv* env, jobject obj, jlong vsync_period) {
+ WindowAndroid* window = new WindowAndroid(env, obj, vsync_period);
return reinterpret_cast<intptr_t>(window);
}
diff --git a/ui/base/android/window_android.h b/ui/base/android/window_android.h
index 842bc4c..7e39184 100644
--- a/ui/base/android/window_android.h
+++ b/ui/base/android/window_android.h
@@ -10,6 +10,7 @@
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/observer_list.h"
+#include "base/time/time.h"
#include "ui/base/ui_base_export.h"
#include "ui/gfx/vector2d_f.h"
@@ -21,7 +22,7 @@ class WindowAndroidObserver;
// Android implementation of the activity window.
class UI_BASE_EXPORT WindowAndroid {
public:
- WindowAndroid(JNIEnv* env, jobject obj);
+ WindowAndroid(JNIEnv* env, jobject obj, jlong vsync_period);
void Destroy(JNIEnv* env, jobject obj);
@@ -49,12 +50,16 @@ class UI_BASE_EXPORT WindowAndroid {
WindowAndroidCompositor* GetCompositor() { return compositor_; }
+ void RequestVSyncUpdate();
+ void OnVSync(JNIEnv* env, jobject obj, jlong time_micros);
+
private:
~WindowAndroid();
JavaObjectWeakGlobalRef weak_java_window_;
gfx::Vector2dF content_offset_;
WindowAndroidCompositor* compositor_;
+ base::TimeDelta vsync_period_;
ObserverList<WindowAndroidObserver> observer_list_;
diff --git a/ui/base/android/window_android_observer.h b/ui/base/android/window_android_observer.h
index 69e4799..0d0062c 100644
--- a/ui/base/android/window_android_observer.h
+++ b/ui/base/android/window_android_observer.h
@@ -15,6 +15,8 @@ class UI_BASE_EXPORT WindowAndroidObserver {
virtual void OnAttachCompositor() = 0;
virtual void OnDetachCompositor() = 0;
virtual void OnWillDestroyWindow() = 0;
+ virtual void OnVSync(base::TimeTicks frame_time,
+ base::TimeDelta vsync_period) = 0;
protected:
virtual ~WindowAndroidObserver() {}