diff options
author | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-25 19:46:46 +0000 |
---|---|---|
committer | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-25 19:46:46 +0000 |
commit | de2cf8caf24f9dff41462b4ed164d18c553b30e3 (patch) | |
tree | 9b7833a432e15c49b8217d529e17cc474c0e47af /ui | |
parent | 406e93caa0d00078548cbbb830767f5cc976e32d (diff) | |
download | chromium_src-de2cf8caf24f9dff41462b4ed164d18c553b30e3.zip chromium_src-de2cf8caf24f9dff41462b4ed164d18c553b30e3.tar.gz chromium_src-de2cf8caf24f9dff41462b4ed164d18c553b30e3.tar.bz2 |
cc: Use HighResNow as timebase if it is fast and reliable
If base::TimeTicks::HighResNow is fast and reliable, we use it
for frame times, animations, and scheduling. Otherwise, we use
base::TimeTicks::Now and use a timebase of zero to avoid an
incorrect or jittery timebase.
This adds a gfx::FrameTime::Now() function, so the same timebase
is used across the ui and cc directories.
Additionally, the OutputSurface now uses a HighRes version of the
DelayBasedTimesource if gfx::FrameTime::Now() is HighRes.
BUG=303356
Review URL: https://codereview.chromium.org/27710005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231089 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/compositor/compositor.cc | 7 | ||||
-rw-r--r-- | ui/compositor/layer_animator.cc | 6 | ||||
-rw-r--r-- | ui/compositor/layer_animator_unittest.cc | 5 | ||||
-rw-r--r-- | ui/compositor/test/layer_animator_test_controller.cc | 4 | ||||
-rw-r--r-- | ui/gfx/animation/animation_container.cc | 7 | ||||
-rw-r--r-- | ui/gfx/frame_time.h | 37 | ||||
-rw-r--r-- | ui/gfx/gfx.gyp | 1 | ||||
-rw-r--r-- | ui/gl/gl_surface_win.cc | 13 | ||||
-rw-r--r-- | ui/surface/accelerated_surface_win.cc | 13 |
9 files changed, 76 insertions, 17 deletions
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 6f6b084..9c57dc7 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -31,6 +31,7 @@ #include "ui/compositor/dip_util.h" #include "ui/compositor/layer.h" #include "ui/compositor/reflector.h" +#include "ui/gfx/frame_time.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface.h" @@ -555,7 +556,7 @@ void Compositor::Terminate() { void Compositor::ScheduleDraw() { if (g_compositor_thread) { - host_->Composite(base::TimeTicks::Now()); + host_->Composite(gfx::FrameTime::Now()); } else if (!defer_draw_scheduling_) { defer_draw_scheduling_ = true; base::MessageLoop::current()->PostTask( @@ -603,7 +604,7 @@ void Compositor::Draw() { // TODO(nduca): Temporary while compositor calls // compositeImmediately() directly. Layout(); - host_->Composite(base::TimeTicks::Now()); + host_->Composite(gfx::FrameTime::Now()); #if defined(OS_WIN) // While we resize, we are usually a few frames behind. By blocking @@ -740,7 +741,7 @@ void Compositor::DidCommit() { } void Compositor::DidCommitAndDrawFrame() { - base::TimeTicks start_time = base::TimeTicks::Now(); + base::TimeTicks start_time = gfx::FrameTime::Now(); FOR_EACH_OBSERVER(CompositorObserver, observer_list_, OnCompositingStarted(this, start_time)); diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc index c287574..dd727a6 100644 --- a/ui/compositor/layer_animator.cc +++ b/ui/compositor/layer_animator.cc @@ -8,12 +8,14 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "cc/animation/animation_id_provider.h" +#include "cc/output/begin_frame_args.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_delegate.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/gfx/animation/animation_container.h" +#include "ui/gfx/frame_time.h" #define SAFE_INVOKE_VOID(function, running_anim, ...) \ if (running_anim.is_sequence_alive()) \ @@ -177,7 +179,7 @@ void LayerAnimator::StartTogether( if (GetAnimationContainer()->is_running()) last_step_time_ = GetAnimationContainer()->last_tick_time(); else - last_step_time_ = base::TimeTicks::Now(); + last_step_time_ = gfx::FrameTime::Now(); } // Collect all the affected properties. @@ -768,7 +770,7 @@ bool LayerAnimator::StartSequenceImmediately(LayerAnimationSequence* sequence) { else if (GetAnimationContainer()->is_running()) start_time = GetAnimationContainer()->last_tick_time(); else - start_time = base::TimeTicks::Now(); + start_time = gfx::FrameTime::Now(); if (!sequence->animation_group_id()) sequence->set_animation_group_id(cc::AnimationIdProvider::NextGroupId()); diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc index a1167bd..7c52200 100644 --- a/ui/compositor/layer_animator_unittest.cc +++ b/ui/compositor/layer_animator_unittest.cc @@ -20,6 +20,7 @@ #include "ui/compositor/test/test_layer_animation_delegate.h" #include "ui/compositor/test/test_layer_animation_observer.h" #include "ui/compositor/test/test_utils.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/rect.h" #include "ui/gfx/transform.h" @@ -168,7 +169,7 @@ TEST(LayerAnimatorTest, ImplicitAnimation) { animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); - base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks now = gfx::FrameTime::Now(); animator->SetBrightness(0.5); EXPECT_TRUE(animator->is_animating()); element->Step(now + base::TimeDelta::FromSeconds(1)); @@ -1035,7 +1036,7 @@ TEST(LayerAnimatorTest, StartTogetherSetsLastStepTime) { // miniscule (fractions of a millisecond). If set correctly, then the delta // should be enormous. Arbitrarily choosing 1 minute as the threshold, // though a much smaller value would probably have sufficed. - delta = base::TimeTicks::Now() - animator->last_step_time(); + delta = gfx::FrameTime::Now() - animator->last_step_time(); EXPECT_GT(60.0, delta.InSecondsF()); } diff --git a/ui/compositor/test/layer_animator_test_controller.cc b/ui/compositor/test/layer_animator_test_controller.cc index 2b686cc..b7b8c40 100644 --- a/ui/compositor/test/layer_animator_test_controller.cc +++ b/ui/compositor/test/layer_animator_test_controller.cc @@ -5,6 +5,8 @@ #include "cc/animation/animation.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/test/layer_animator_test_controller.h" +#include "ui/gfx/frame_time.h" +#include "ui/gfx/rect.h" namespace ui { @@ -52,7 +54,7 @@ void LayerAnimatorTestController::StartThreadedAnimationsIfNeeded() { 0, element->animation_group_id(), threaded_properties[i], - (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF())); + (gfx::FrameTime::Now() - base::TimeTicks()).InSecondsF())); } } diff --git a/ui/gfx/animation/animation_container.cc b/ui/gfx/animation/animation_container.cc index c76f1bb..d8290b2 100644 --- a/ui/gfx/animation/animation_container.cc +++ b/ui/gfx/animation/animation_container.cc @@ -6,6 +6,7 @@ #include "ui/gfx/animation/animation_container_element.h" #include "ui/gfx/animation/animation_container_observer.h" +#include "ui/gfx/frame_time.h" using base::TimeDelta; using base::TimeTicks; @@ -13,7 +14,7 @@ using base::TimeTicks; namespace gfx { AnimationContainer::AnimationContainer() - : last_tick_time_(TimeTicks::Now()), + : last_tick_time_(gfx::FrameTime::Now()), observer_(NULL) { } @@ -28,7 +29,7 @@ void AnimationContainer::Start(AnimationContainerElement* element) { // element isn't running. if (elements_.empty()) { - last_tick_time_ = TimeTicks::Now(); + last_tick_time_ = gfx::FrameTime::Now(); SetMinTimerInterval(element->GetTimerInterval()); } else if (element->GetTimerInterval() < min_timer_interval_) { SetMinTimerInterval(element->GetTimerInterval()); @@ -61,7 +62,7 @@ void AnimationContainer::Run() { // ourself here to make sure we're still valid after running all the elements. scoped_refptr<AnimationContainer> this_ref(this); - TimeTicks current_time = TimeTicks::Now(); + TimeTicks current_time = gfx::FrameTime::Now(); last_tick_time_ = current_time; diff --git a/ui/gfx/frame_time.h b/ui/gfx/frame_time.h new file mode 100644 index 0000000..8d143ee --- /dev/null +++ b/ui/gfx/frame_time.h @@ -0,0 +1,37 @@ +// 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. + +#ifndef UI_GFX_FRAME_TIME_H +#define UI_GFX_FRAME_TIME_H + +#include "base/time/time.h" +#include "base/logging.h" + +namespace gfx { + +// FrameTime::Now() should be used to get timestamps with a timebase that +// is consistent across the graphics stack. +class FrameTime { + public: + static base::TimeTicks Now() { + if (TimestampsAreHighRes()) + return base::TimeTicks::HighResNow(); + return base::TimeTicks::Now(); + } + +#if defined(OS_WIN) + static base::TimeTicks FromQPCValue(LONGLONG qpc_value) { + DCHECK(TimestampsAreHighRes()); + return base::TimeTicks::FromQPCValue(qpc_value); + } +#endif + + static bool TimestampsAreHighRes() { + return base::TimeTicks::IsHighResNowFastAndReliable(); + } +}; + +} + +#endif // UI_GFX_FRAME_TIME_H diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp index 66d4adb..56c4d64 100644 --- a/ui/gfx/gfx.gyp +++ b/ui/gfx/gfx.gyp @@ -86,6 +86,7 @@ 'display_observer.h', 'favicon_size.cc', 'favicon_size.h', + 'frame_time.h', 'font.cc', 'font.h', 'font_fallback_win.cc', diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc index d535c06..ff2ed84 100644 --- a/ui/gl/gl_surface_win.cc +++ b/ui/gl/gl_surface_win.cc @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "base/win/windows_version.h" #include "third_party/mesa/src/include/GL/osmesa.h" +#include "ui/gfx/frame_time.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface_egl.h" @@ -56,8 +57,16 @@ class DWMVSyncProvider : public VSyncProvider { if (result != S_OK) return; - base::TimeTicks timebase = base::TimeTicks::FromQPCValue( - static_cast<LONGLONG>(timing_info.qpcVBlank)); + base::TimeTicks timebase; + // If FrameTime is not high resolution, we do not want to translate the + // QPC value provided by DWM into the low-resolution timebase, which + // would be error prone and jittery. As a fallback, we assume the timebase + // is zero. + if (gfx::FrameTime::TimestampsAreHighRes()) { + timebase = gfx::FrameTime::FromQPCValue( + static_cast<LONGLONG>(timing_info.qpcVBlank)); + } + // Swap the numerator/denominator to convert frequency to period. if (timing_info.rateRefresh.uiDenominator > 0 && timing_info.rateRefresh.uiNumerator > 0) { diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc index f346dbe..a8b57c5 100644 --- a/ui/surface/accelerated_surface_win.cc +++ b/ui/surface/accelerated_surface_win.cc @@ -28,6 +28,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/win/shell.h" #include "ui/events/latency_info.h" +#include "ui/gfx/frame_time.h" #include "ui/gfx/rect.h" #include "ui/gfx/win/dpi.h" #include "ui/gfx/win/hwnd_util.h" @@ -877,18 +878,22 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( if (raster_status.InVBlank) clamped_scanline = display_mode.Height; - base::TimeTicks current_time = base::TimeTicks::HighResNow(); - // Figure out approximately how far back in time the last vsync was based on // the ratio of the raster scanline to the display height. base::TimeTicks last_vsync_time; base::TimeDelta refresh_period; + if (display_mode.Height) { + refresh_period = base::TimeDelta::FromMicroseconds( + 1000000 / display_mode.RefreshRate); + // If FrameTime is not high resolution, we use a timebase of zero to avoid + // introducing jitter into our frame start times. + if (gfx::FrameTime::TimestampsAreHighRes()) { + base::TimeTicks current_time = gfx::FrameTime::Now(); last_vsync_time = current_time - base::TimeDelta::FromMilliseconds((clamped_scanline * 1000) / (display_mode.RefreshRate * display_mode.Height)); - refresh_period = base::TimeDelta::FromMicroseconds( - 1000000 / display_mode.RefreshRate); + } } // Wait for the StretchRect to complete before notifying the GPU process |