diff options
12 files changed, 189 insertions, 177 deletions
diff --git a/content/browser/android/content_view_render_view.cc b/content/browser/android/content_view_render_view.cc index 9f5ed31..4a39885 100644 --- a/content/browser/android/content_view_render_view.cc +++ b/content/browser/android/content_view_render_view.cc @@ -53,8 +53,7 @@ bool ContentViewRenderView::RegisterContentViewRenderView(JNIEnv* env) { ContentViewRenderView::ContentViewRenderView(JNIEnv* env, jobject obj, gfx::NativeWindow root_window) - : buffers_swapped_during_composite_(false), - layer_tree_build_helper_(new LayerTreeBuildHelperImpl()), + : layer_tree_build_helper_(new LayerTreeBuildHelperImpl()), root_window_(root_window), current_surface_format_(0) { java_obj_.Reset(env, obj); @@ -118,15 +117,6 @@ void ContentViewRenderView::SurfaceChanged(JNIEnv* env, jobject obj, compositor_->SetWindowBounds(gfx::Size(width, height)); } -jboolean ContentViewRenderView::Composite(JNIEnv* env, jobject obj) { - if (!compositor_) - return false; - - buffers_swapped_during_composite_ = false; - compositor_->Composite(); - return buffers_swapped_during_composite_; -} - jboolean ContentViewRenderView::CompositeToBitmap(JNIEnv* env, jobject obj, jobject java_bitmap) { gfx::JavaBitmap bitmap(java_bitmap); @@ -139,19 +129,14 @@ jboolean ContentViewRenderView::CompositeToBitmap(JNIEnv* env, jobject obj, void ContentViewRenderView::SetOverlayVideoMode( JNIEnv* env, jobject obj, bool enabled) { compositor_->SetHasTransparentBackground(enabled); - Java_ContentViewRenderView_requestRender(env, obj); } -void ContentViewRenderView::ScheduleComposite() { +void ContentViewRenderView::Layout() { JNIEnv* env = base::android::AttachCurrentThread(); - Java_ContentViewRenderView_requestRender(env, java_obj_.obj()); -} - -void ContentViewRenderView::OnSwapBuffersPosted() { - buffers_swapped_during_composite_ = true; + Java_ContentViewRenderView_onCompositorLayout(env, java_obj_.obj()); } -void ContentViewRenderView::OnSwapBuffersCompleted() { +void ContentViewRenderView::OnSwapBuffersCompleted(int pending_swap_buffers) { JNIEnv* env = base::android::AttachCurrentThread(); Java_ContentViewRenderView_onSwapBuffersCompleted(env, java_obj_.obj()); } diff --git a/content/browser/android/content_view_render_view.h b/content/browser/android/content_view_render_view.h index 8f14456..cbdb1f1 100644 --- a/content/browser/android/content_view_render_view.h +++ b/content/browser/android/content_view_render_view.h @@ -43,18 +43,15 @@ class ContentViewRenderView : public CompositorClient { jboolean CompositeToBitmap(JNIEnv* env, jobject obj, jobject java_bitmap); void SetOverlayVideoMode(JNIEnv* env, jobject obj, bool enabled); - // CompositorClient --------------------------------------------------------- - virtual void ScheduleComposite() OVERRIDE; - virtual void OnSwapBuffersPosted() OVERRIDE; - virtual void OnSwapBuffersCompleted() OVERRIDE; + // CompositorClient implementation + virtual void Layout() OVERRIDE; + virtual void OnSwapBuffersCompleted(int pending_swap_buffers) OVERRIDE; private: virtual ~ContentViewRenderView(); void InitCompositor(); - bool buffers_swapped_during_composite_; - base::android::ScopedJavaGlobalRef<jobject> java_obj_; scoped_ptr<LayerTreeBuildHelper> layer_tree_build_helper_; diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 2e8e882..fcd0a7b3 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -238,7 +238,14 @@ CompositorImpl::CompositorImpl(CompositorClient* client, window_(NULL), surface_id_(0), client_(client), - root_window_(root_window) { + root_window_(root_window), + did_post_swapbuffers_(false), + ignore_schedule_composite_(false), + needs_composite_(false), + should_composite_on_vsync_(false), + did_composite_this_frame_(false), + pending_swapbuffers_(0U), + weak_factory_(this) { DCHECK(client); DCHECK(root_window); ImageTransportFactoryAndroid::AddObserver(this); @@ -252,9 +259,69 @@ CompositorImpl::~CompositorImpl() { SetSurface(NULL); } -void CompositorImpl::Composite() { - if (host_) - host_->Composite(gfx::FrameTime::Now()); +void CompositorImpl::PostComposite(base::TimeDelta delay) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&CompositorImpl::Composite, + weak_factory_.GetWeakPtr(), + COMPOSITE_IMMEDIATELY), + delay); +} + +void CompositorImpl::Composite(CompositingTrigger trigger) { + if (!host_) + return; + + if (!needs_composite_) + return; + + if (trigger != COMPOSITE_ON_VSYNC && should_composite_on_vsync_) { + TRACE_EVENT0("compositor", "CompositorImpl_DeferCompositeToVSync"); + root_window_->RequestVSyncUpdate(); + return; + } + + // Don't Composite more than once in between vsync ticks. + if (did_composite_this_frame_) { + TRACE_EVENT0("compositor", "CompositorImpl_ThrottleComposite"); + if (should_composite_on_vsync_) + root_window_->RequestVSyncUpdate(); + else + PostComposite(vsync_period_); + return; + } + + const unsigned int kMaxSwapBuffers = 2U; + DCHECK_LE(pending_swapbuffers_, kMaxSwapBuffers); + if (pending_swapbuffers_ == kMaxSwapBuffers) { + TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit"); + if (should_composite_on_vsync_) + root_window_->RequestVSyncUpdate(); + else + PostComposite(vsync_period_); + return; + } + + // Reset state before Layout+Composite since that might create more + // requests to Composite that we need to respect. + needs_composite_ = false; + should_composite_on_vsync_ = false; + + // Ignore ScheduleComposite() from layer tree changes during Layout. + ignore_schedule_composite_ = true; + client_->Layout(); + ignore_schedule_composite_ = false; + + did_post_swapbuffers_ = false; + host_->Composite(gfx::FrameTime::Now()); + if (did_post_swapbuffers_) + pending_swapbuffers_++; + + if (trigger != COMPOSITE_ON_VSYNC) { + // Need to track vsync to avoid compositing more than once per frame. + root_window_->RequestVSyncUpdate(); + } + did_composite_this_frame_ = true; } void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { @@ -316,6 +383,10 @@ void CompositorImpl::SetVisible(bool visible) { host_.reset(); client_->UIResourcesAreInvalid(); } else if (!host_) { + needs_composite_ = false; + did_composite_this_frame_ = false; + should_composite_on_vsync_ = false; + pending_swapbuffers_ = 0; cc::LayerTreeSettings settings; settings.refresh_rate = 60.0; settings.impl_side_painting = false; @@ -374,6 +445,17 @@ bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { return false; } +void CompositorImpl::SetNeedsComposite() { + if (!host_.get() || needs_composite_) + return; + + needs_composite_ = true; + + // For explicit requests we try to composite regularly on vsync. + should_composite_on_vsync_ = true; + root_window_->RequestVSyncUpdate(); +} + cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap( const cc::UIResourceBitmap& bitmap, bool is_transient) { @@ -468,6 +550,13 @@ CreateGpuProcessViewContext( NULL)); } +void CompositorImpl::Layout() { + // TODO: If we get this callback from the SingleThreadProxy, we need + // to stop calling it ourselves in CompositorImpl::Composite(). + NOTREACHED(); + client_->Layout(); +} + scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( bool fallback) { blink::WebGraphicsContext3D::Attributes attrs; @@ -493,12 +582,16 @@ void CompositorImpl::OnLostResources() { client_->DidLoseResources(); } -void CompositorImpl::DidCompleteSwapBuffers() { - client_->OnSwapBuffersCompleted(); -} - void CompositorImpl::ScheduleComposite() { - client_->ScheduleComposite(); + if (needs_composite_ || ignore_schedule_composite_) + return; + + needs_composite_ = true; + + // We currently expect layer tree invalidations at most once per frame + // during normal operation and therefore try to composite immediately + // to minimize latency. + PostComposite(base::TimeDelta()); } void CompositorImpl::ScheduleAnimation() { @@ -507,12 +600,19 @@ void CompositorImpl::ScheduleAnimation() { void CompositorImpl::DidPostSwapBuffers() { TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); - client_->OnSwapBuffersPosted(); + did_post_swapbuffers_ = true; +} + +void CompositorImpl::DidCompleteSwapBuffers() { + TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers"); + DCHECK_GT(pending_swapbuffers_, 0U); + client_->OnSwapBuffersCompleted(pending_swapbuffers_--); } void CompositorImpl::DidAbortSwapBuffers() { TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); - client_->OnSwapBuffersCompleted(); + DCHECK_GT(pending_swapbuffers_, 0U); + client_->OnSwapBuffersCompleted(pending_swapbuffers_--); } void CompositorImpl::DidCommit() { @@ -523,4 +623,13 @@ void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) { root_layer_->AddChild(layer); } +void CompositorImpl::OnVSync(base::TimeTicks frame_time, + base::TimeDelta vsync_period) { + vsync_period_ = vsync_period; + did_composite_this_frame_ = false; + + if (should_composite_on_vsync_) + Composite(COMPOSITE_ON_VSYNC); +} + } // namespace content diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 969b114..8fd65ad 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "cc/resources/ui_resource_client.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" @@ -53,6 +54,7 @@ class CONTENT_EXPORT CompositorImpl // Destroy all surface textures associated with |child_process_id|. static void DestroyAllSurfaceTextures(int child_process_id); + private: // Compositor implementation. virtual void SetRootLayer(scoped_refptr<cc::Layer> root) OVERRIDE; virtual void SetWindowSurface(ANativeWindow* window) OVERRIDE; @@ -63,7 +65,7 @@ class CONTENT_EXPORT CompositorImpl virtual void SetHasTransparentBackground(bool flag) OVERRIDE; virtual bool CompositeAndReadback( void *pixels, const gfx::Rect& rect) OVERRIDE; - virtual void Composite() OVERRIDE; + virtual void SetNeedsComposite() OVERRIDE; virtual cc::UIResourceId GenerateUIResource(const SkBitmap& bitmap, bool is_transient) OVERRIDE; virtual cc::UIResourceId GenerateCompressedUIResource(const gfx::Size& size, @@ -76,7 +78,7 @@ class CONTENT_EXPORT CompositorImpl virtual void WillBeginMainFrame(int frame_id) OVERRIDE {} virtual void DidBeginMainFrame() OVERRIDE {} virtual void Animate(base::TimeTicks frame_begin_time) OVERRIDE {} - virtual void Layout() OVERRIDE {} + virtual void Layout() OVERRIDE; virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta, float page_scale) OVERRIDE {} virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(bool fallback) @@ -98,8 +100,15 @@ class CONTENT_EXPORT CompositorImpl // WindowAndroidCompositor implementation. virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) OVERRIDE; - - private: + virtual void OnVSync(base::TimeTicks frame_time, + base::TimeDelta vsync_period) OVERRIDE; + + void PostComposite(base::TimeDelta delay); + enum CompositingTrigger { + COMPOSITE_IMMEDIATELY, + COMPOSITE_ON_VSYNC + }; + void Composite(CompositingTrigger trigger); cc::UIResourceId GenerateUIResourceFromUIResourceBitmap( const cc::UIResourceBitmap& bitmap, bool is_transient); @@ -122,6 +131,32 @@ class CONTENT_EXPORT CompositorImpl gfx::NativeWindow root_window_; + // Used locally to track whether a call to LTH::Composite() did result in + // a posted SwapBuffers(). + bool did_post_swapbuffers_; + + // Used locally to inhibit ScheduleComposite() during Layout(). + bool ignore_schedule_composite_; + + // Whether we need to composite in general because of any invalidation or + // explicit request. + bool needs_composite_; + + // When SetNeedsComposite() is getting called, we will try to schedule + // regularly during vsync. + bool should_composite_on_vsync_; + + // Whether we composited already in the current vsync interval. + bool did_composite_this_frame_; + + // The number of SwapBuffer calls that have not returned and ACK'd from + // the GPU thread. + unsigned int pending_swapbuffers_; + + base::TimeDelta vsync_period_; + + base::WeakPtrFactory<CompositorImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(CompositorImpl); }; 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 0dbb0d8..a33443c 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -255,6 +255,7 @@ void RenderWidgetHostViewAndroid::WasShown() { if (content_view_core_ && !using_synchronous_compositor_) { content_view_core_->GetWindowAndroid()->AddObserver(this); + content_view_core_->GetWindowAndroid()->RequestVSyncUpdate(); observing_root_window_ = true; } } 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 149b7862..ce58221 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 @@ -301,9 +301,6 @@ public class ContentViewCore // because the OSK was just brought up. private final Rect mFocusPreOSKViewportRect = new Rect(); - // Whether we received a new frame since consumePendingRendererFrame() was last called. - private boolean mPendingRendererFrame = false; - // On single tap this will store the x, y coordinates of the touch. private int mSingleTapX; private int mSingleTapY; @@ -880,17 +877,6 @@ public class ContentViewCore } /** - * Mark any new frames that have arrived since this function was last called as non-pending. - * - * @return Whether there was a pending frame from the renderer. - */ - public boolean consumePendingRendererFrame() { - boolean hadPendingFrame = mPendingRendererFrame; - mPendingRendererFrame = false; - return hadPendingFrame; - } - - /** * @return Viewport width in physical pixels as set from onSizeChanged. */ @CalledByNative @@ -2286,7 +2272,6 @@ public class ContentViewCore getContentViewClient().onOffsetsForFullscreenChanged( controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix); - mPendingRendererFrame = true; if (mBrowserAccessibilityManager != null) { mBrowserAccessibilityManager.notifyFrameInfoInitialized(); } 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 6c11209..709d574 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.Handler; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -17,7 +16,6 @@ import android.widget.FrameLayout; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; -import org.chromium.base.TraceEvent; import org.chromium.ui.base.WindowAndroid; /*** @@ -27,31 +25,16 @@ import org.chromium.ui.base.WindowAndroid; * Note that only one ContentViewCore can be shown at a time. */ @JNINamespace("content") -public class ContentViewRenderView extends FrameLayout implements WindowAndroid.VSyncClient { - private static final int MAX_SWAP_BUFFER_COUNT = 2; - +public class ContentViewRenderView extends FrameLayout { // The native side of this object. private long mNativeContentViewRenderView; private final SurfaceHolder.Callback mSurfaceCallback; private final SurfaceView mSurfaceView; - private final WindowAndroid mRootWindow; - - private int mPendingRenders; - private int mPendingSwapBuffers; - private boolean mNeedToRender; - protected ContentViewCore mContentViewCore; private ContentReadbackHandler mContentReadbackHandler; - private final Runnable mRenderRunnable = new Runnable() { - @Override - public void run() { - render(); - } - }; - /** * Constructs a new ContentViewRenderView that should be can to a view hierarchy. * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer. @@ -63,8 +46,6 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. mNativeContentViewRenderView = nativeInit(rootWindow.getNativePointer()); assert mNativeContentViewRenderView != 0; - mRootWindow = rootWindow; - rootWindow.setVSyncClient(this); mSurfaceView = createSurfaceView(getContext()); mSurfaceView.setZOrderMediaOverlay(true); mSurfaceCallback = new SurfaceHolder.Callback() { @@ -86,9 +67,6 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. assert mNativeContentViewRenderView != 0; nativeSurfaceCreated(mNativeContentViewRenderView); - mPendingSwapBuffers = 0; - mPendingRenders = 0; - onReadyToRender(); } @@ -114,19 +92,6 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. mContentReadbackHandler.initNativeContentReadbackHandler(); } - @Override - public void onVSync(long vsyncTimeMicros) { - if (mNeedToRender) { - if (mPendingSwapBuffers + mPendingRenders <= MAX_SWAP_BUFFER_COUNT) { - mNeedToRender = false; - mPendingRenders++; - render(); - } else { - TraceEvent.instant("ContentViewRenderView:bail"); - } - } - } - /** * @return The content readback handler. */ @@ -153,7 +118,6 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. public void destroy() { mContentReadbackHandler.destroy(); mContentReadbackHandler = null; - mRootWindow.setVSyncClient(null); mSurfaceView.getHolder().removeCallback(mSurfaceCallback); nativeDestroy(mNativeContentViewRenderView); mNativeContentViewRenderView = 0; @@ -226,54 +190,17 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. } @CalledByNative - private void requestRender() { - boolean rendererHasFrame = - mContentViewCore != null && mContentViewCore.consumePendingRendererFrame(); - - if (rendererHasFrame && mPendingSwapBuffers + mPendingRenders < MAX_SWAP_BUFFER_COUNT) { - TraceEvent.instant("requestRender:now"); - mNeedToRender = false; - mPendingRenders++; - - // The handler can be null if we are detached from the window. Calling - // {@link View#post(Runnable)} properly handles this case, but we lose the front of - // queue behavior. That is okay for this edge case. - Handler handler = getHandler(); - if (handler != null) { - handler.postAtFrontOfQueue(mRenderRunnable); - } else { - post(mRenderRunnable); - } - } else if (mPendingRenders <= 0) { - assert mPendingRenders == 0; - TraceEvent.instant("requestRender:later"); - mNeedToRender = true; - mRootWindow.requestVSyncUpdate(); - } + protected void onCompositorLayout() { } @CalledByNative private void onSwapBuffersCompleted() { - TraceEvent.instant("onSwapBuffersCompleted"); - - if (mPendingSwapBuffers == MAX_SWAP_BUFFER_COUNT && mNeedToRender) requestRender(); - if (mPendingSwapBuffers > 0) mPendingSwapBuffers--; - } - - protected void render() { - if (mPendingRenders > 0) mPendingRenders--; - - boolean didDraw = nativeComposite(mNativeContentViewRenderView); - if (didDraw) { - mPendingSwapBuffers++; - if (mSurfaceView.getBackground() != null) { - post(new Runnable() { - @Override - public void run() { - mSurfaceView.setBackgroundResource(0); - } - }); - } + if (mSurfaceView.getBackground() != null) { + post(new Runnable() { + @Override public void run() { + mSurfaceView.setBackgroundResource(0); + } + }); } } @@ -287,7 +214,6 @@ public class ContentViewRenderView extends FrameLayout implements WindowAndroid. private native void nativeSurfaceDestroyed(long nativeContentViewRenderView); private native void nativeSurfaceChanged(long nativeContentViewRenderView, int format, int width, int height, Surface surface); - private native boolean nativeComposite(long nativeContentViewRenderView); private native boolean nativeCompositeToBitmap(long nativeContentViewRenderView, Bitmap bitmap); private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView, boolean enabled); diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h index 7cb73e2..236a90d 100644 --- a/content/public/browser/android/compositor.h +++ b/content/public/browser/android/compositor.h @@ -69,8 +69,9 @@ class CONTENT_EXPORT Compositor { // The buffer is not modified if false is returned. virtual bool CompositeAndReadback(void *pixels, const gfx::Rect& rect) = 0; - // Composite immediately. Used in single-threaded mode. - virtual void Composite() = 0; + // Request layout and draw. You only need to call this if you need to trigger + // Composite *without* having modified the layer tree. + virtual void SetNeedsComposite() = 0; // Generates a UIResource and returns a UIResourceId. |is_transient| // indicates whether or not to release the resource once the bitmap diff --git a/content/public/browser/android/compositor_client.h b/content/public/browser/android/compositor_client.h index d835de1..09a12e5 100644 --- a/content/public/browser/android/compositor_client.h +++ b/content/public/browser/android/compositor_client.h @@ -11,14 +11,11 @@ namespace content { class CONTENT_EXPORT CompositorClient { public: - // Tells the client that it should schedule a composite. - virtual void ScheduleComposite() = 0; + // Gives the client a chance for layout changes before compositing. + virtual void Layout() {} // The compositor has completed swapping a frame. - virtual void OnSwapBuffersCompleted() {} - - // The compositor will eventually swap a frame. - virtual void OnSwapBuffersPosted() {} + virtual void OnSwapBuffersCompleted(int pending_swap_buffers) {} // Tells the client that GL resources were lost and need to be reinitialized. virtual void DidLoseResources() {} 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 8be2dd0..4a68dea 100644 --- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java +++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java @@ -32,7 +32,6 @@ 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"; @@ -51,9 +50,6 @@ public class WindowAndroid { 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); } @@ -231,34 +227,9 @@ public class WindowAndroid { return false; } - /** - * 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(); + private void requestVSyncUpdate() { + mVSyncMonitor.requestUpdate(); } /** diff --git a/ui/base/android/window_android.cc b/ui/base/android/window_android.cc index bbacf9c..3dd3e6e 100644 --- a/ui/base/android/window_android.cc +++ b/ui/base/android/window_android.cc @@ -96,10 +96,13 @@ void WindowAndroid::RequestVSyncUpdate() { } void WindowAndroid::OnVSync(JNIEnv* env, jobject obj, jlong time_micros) { + base::TimeTicks frame_time(base::TimeTicks::FromInternalValue(time_micros)); FOR_EACH_OBSERVER( WindowAndroidObserver, observer_list_, - OnVSync(base::TimeTicks::FromInternalValue(time_micros), vsync_period_)); + OnVSync(frame_time, vsync_period_)); + if (compositor_) + compositor_->OnVSync(frame_time, vsync_period_); } // ---------------------------------------------------------------------------- diff --git a/ui/base/android/window_android_compositor.h b/ui/base/android/window_android_compositor.h index 8f219fa..1c2fefc 100644 --- a/ui/base/android/window_android_compositor.h +++ b/ui/base/android/window_android_compositor.h @@ -19,6 +19,8 @@ class UI_BASE_EXPORT WindowAndroidCompositor { virtual ~WindowAndroidCompositor() {} virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) = 0; + virtual void OnVSync(base::TimeTicks frame_time, + base::TimeDelta vsync_period) = 0; }; } // namespace ui |