Index: services/gfx/compositor/backend/vsync_scheduler.h |
diff --git a/services/gfx/compositor/backend/vsync_scheduler.h b/services/gfx/compositor/backend/vsync_scheduler.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..46fced82c9057e35532311382e226cce1b143bd2 |
--- /dev/null |
+++ b/services/gfx/compositor/backend/vsync_scheduler.h |
@@ -0,0 +1,162 @@ |
+// 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. |
+ |
+#ifndef SERVICES_GFX_COMPOSITOR_BACKEND_VSYNC_SCHEDULER_H_ |
+#define SERVICES_GFX_COMPOSITOR_BACKEND_VSYNC_SCHEDULER_H_ |
+ |
+#include <limits> |
+#include <memory> |
+#include <mutex> |
+ |
+#include "base/callback.h" |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/task_runner.h" |
+#include "services/gfx/compositor/backend/scheduler.h" |
+ |
+namespace compositor { |
+ |
+// Schedules work to coincide with vsync intervals. |
+// |
+// This object is thread-safe and it intended to be used to allow one thread |
+// to be scheduling work for itself while another thread concurrently updates |
+// timing parameters. |
+class VsyncScheduler : public Scheduler { |
+ public: |
+ // Limits on allowable parameters. (Exposed for testing.) |
+ static constexpr int64_t kMinVsyncInterval = 1000; // 1000 Hz |
viettrungluu
2016/01/04 21:08:24
You need to declare storage for these (in the .cc)
jeffbrown
2016/01/16 03:28:31
Hah! You're right. I'd interpreted constexpr as
|
+ static constexpr int64_t kMaxVsyncInterval = 1000000; // 1 Hz |
+ |
+ // Time reference. Should be MojoTimeTicksNow() except during testing. |
+ using Clock = base::Callback<MojoTimeTicks()>; |
+ |
+ VsyncScheduler(const scoped_refptr<base::TaskRunner>& task_runner, |
+ const SchedulerCallbacks& callbacks); |
+ VsyncScheduler(const scoped_refptr<base::TaskRunner>& task_runner, |
+ const SchedulerCallbacks& callbacks, |
+ const Clock& clock); |
+ ~VsyncScheduler() override; |
+ |
+ // Starts scheduling work and sets the scheduling parameters. |
+ // |
+ // |vsync_timebase| is a value in the |MojoTimeTicks| timebase which |
+ // specifies when a recent vsync occurred and is used to determine the phase. |
+ // |
+ // |vsync_interval| is the number of microseconds between vsyncs which |
+ // also determines the |FrameInfo.frame_interval| value to deliver to |
+ // applications. |
+ // |
+ // |update_phase| specifies an offset relative to vsync for determining |
+ // when updates are scheduled and the |FrameInfo.frame_time| to deliver |
+ // to applications. |
+ // |
+ // |snapshot_phase| specifies an offset relative to vsync for |
+ // determining when snapshots are scheduled and the |FrameInfo.frame_deadline| |
+ // to deliver to applications. Must be greater than or equal to |
+ // |update_phase|. |
+ // |
+ // |presentation_phase| specifies an offset relative to vsync for |
+ // determining when frames are shown on the display output and the |
+ // |FrameInfo.presentation_time| to deliver to applications. Must be |
+ // greater than or equal to |snapshot_phase|. |
+ // |
+ // The notion of 'vsync' is somewhat abstract here. It's just a reference |
+ // pulse but we usually interpret it as a deadline for preparing the next |
+ // frame and submitting it to the display hardware. |
+ // |
+ // The phases can be positive or negative but negative offsets from vsync |
+ // may be easier to interpret when computing deadlines. To avoid |
+ // overflows, the values chosen for the phases should be close to 0. |
+ // |
+ // This function schedules an update and snapshot if not already scheduled. |
+ // |
+ // Returns true if the schedule was started successfully, false if the |
+ // parameters are invalid. |
+ bool Start(int64_t vsync_timebase, |
+ int64_t vsync_interval, |
+ int64_t update_phase, |
+ int64_t snapshot_phase, |
+ int64_t presentation_phase) { |
+ return state_->Start(vsync_timebase, vsync_interval, update_phase, |
+ snapshot_phase, presentation_phase); |
+ } |
+ |
+ // Stops scheduling work. |
+ // |
+ // Previously scheduled callbacks may still be delivered. |
+ void Stop() { state_->Stop(); } |
+ |
+ // |Scheduler|: |
+ void ScheduleFrame(SchedulingMode scheduling_mode) override; |
+ |
+ private: |
+ // Internal state. Held by a shared_ptr so that callbacks running on |
+ // other threads can reference it using a weak_ptr. |
+ class State : public std::enable_shared_from_this<State> { |
+ public: |
+ State(const scoped_refptr<base::TaskRunner>& task_runner, |
+ const SchedulerCallbacks& callbacks, |
+ const Clock& clock); |
+ ~State(); |
+ |
+ MojoTimeTicks GetTimeTicksNow() { return clock_.Run(); } |
+ |
+ bool Start(int64_t vsync_timebase, |
+ int64_t vsync_interval, |
+ int64_t update_phase, |
+ int64_t snapshot_phase, |
+ int64_t presentation_phase); |
+ void Stop(); |
+ void ScheduleFrame(SchedulingMode scheduling_mode); |
+ |
+ private: |
+ enum class Action { |
+ kUpdate, |
+ kEarlySnapshot, |
+ kLateSnapshot, |
+ }; |
+ |
+ static void DispatchThunk(const std::weak_ptr<State>& state_weak, |
+ int32_t generation, |
+ Action action, |
+ int64_t update_time); |
+ |
+ void ScheduleLocked(MojoTimeTicks now); |
+ void PostDispatchLocked(int64_t now, |
+ int64_t delivery_time, |
+ Action action, |
+ int64_t update_time); |
+ |
+ void Dispatch(int32_t generation, Action action, int64_t update_time); |
+ void SetFrameInfoLocked(mojo::gfx::composition::FrameInfo* frame_info, |
+ int64_t update_time); |
+ |
+ const scoped_refptr<base::TaskRunner> task_runner_; |
+ const SchedulerCallbacks callbacks_; |
+ const Clock clock_; |
+ |
+ // Parameters and state guarded by |mutex_|. |
+ std::mutex mutex_; |
+ bool running_ = false; |
+ int32_t generation_ = 0; |
+ int64_t vsync_timebase_ = 0; |
+ int64_t vsync_interval_ = 0; |
+ int64_t update_phase_ = 0; |
+ int64_t snapshot_phase_ = 0; |
+ int64_t presentation_phase_ = 0; |
+ bool need_update_ = false; |
+ bool pending_dispatch_ = false; |
+ int64_t last_delivered_update_time_ = std::numeric_limits<int64_t>::min(); |
+ |
+ DISALLOW_COPY_AND_ASSIGN(State); |
+ }; |
+ |
+ const std::shared_ptr<State> state_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(VsyncScheduler); |
+}; |
+ |
+} // namespace compositor |
+ |
+#endif // SERVICES_GFX_COMPOSITOR_BACKEND_VSYNC_SCHEDULER_H_ |