| Index: mojo/ui/choreographer.cc
|
| diff --git a/mojo/ui/choreographer.cc b/mojo/ui/choreographer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7ea295b682aecc1d9c44c15d884aaa9f38c3d973
|
| --- /dev/null
|
| +++ b/mojo/ui/choreographer.cc
|
| @@ -0,0 +1,119 @@
|
| +// 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.
|
| +
|
| +#include "mojo/ui/choreographer.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| +#include "mojo/public/cpp/system/functions.h"
|
| +
|
| +namespace mojo {
|
| +namespace ui {
|
| +
|
| +Choreographer::Choreographer(mojo::gfx::composition::Scene* scene,
|
| + ChoreographerDelegate* delegate)
|
| + : delegate_(delegate) {
|
| + DCHECK(delegate_);
|
| + scene->GetScheduler(mojo::GetProxy(&scene_scheduler_));
|
| +}
|
| +
|
| +Choreographer::Choreographer(
|
| + mojo::gfx::composition::SceneSchedulerPtr scene_scheduler,
|
| + ChoreographerDelegate* delegate)
|
| + : scene_scheduler_(scene_scheduler.Pass()), delegate_(delegate) {
|
| + DCHECK(scene_scheduler_);
|
| + DCHECK(delegate_);
|
| +}
|
| +
|
| +Choreographer::~Choreographer() {}
|
| +
|
| +void Choreographer::ScheduleDraw() {
|
| + if (!draw_scheduled_) {
|
| + draw_scheduled_ = true;
|
| + ScheduleFrame();
|
| + }
|
| +}
|
| +
|
| +void Choreographer::ScheduleFrame() {
|
| + if (!frame_scheduled_) {
|
| + frame_scheduled_ = true;
|
| + scene_scheduler_->ScheduleFrame(
|
| + base::Bind(&Choreographer::DoFrame, base::Unretained(this)));
|
| + }
|
| +}
|
| +
|
| +void Choreographer::DoFrame(mojo::gfx::composition::FrameInfoPtr frame_info) {
|
| + DCHECK(frame_info);
|
| + DCHECK(frame_scheduled_);
|
| + frame_scheduled_ = false;
|
| +
|
| + if (draw_scheduled_) {
|
| + draw_scheduled_ = false;
|
| +
|
| + // To reduce latency and jank, anticipate the next frame to be drawn by
|
| + // scheduling it early.
|
| + //
|
| + // TODO(jeffbrown): Reenable this once issue #604 is fixed. Unfortunately
|
| + // this exacerbates starvation issues in the Mojo message pump.
|
| + // ScheduleFrame();
|
| +
|
| + // Ensure frame info is sane since it comes from another service.
|
| + // TODO(jeffbrown): Would be better to report an error to the client
|
| + // who can shut things down if needed.
|
| + MojoTimeTicks now = MojoGetTimeTicksNow();
|
| + if (frame_info->frame_time > now) {
|
| + LOG(WARNING) << "Frame time is in the future: frame_time="
|
| + << frame_info->frame_time << ", now=" << now;
|
| + frame_info->frame_time = now;
|
| + }
|
| + if (frame_info->frame_deadline < frame_info->frame_time) {
|
| + LOG(WARNING)
|
| + << "Frame deadline is earlier than frame time: frame_deadline="
|
| + << frame_info->frame_deadline
|
| + << ", frame_time=" << frame_info->frame_time << ", now=" << now;
|
| + frame_info->frame_deadline = frame_info->frame_time;
|
| + }
|
| + if (frame_info->presentation_time < frame_info->frame_deadline) {
|
| + LOG(WARNING) << "Presentation time is earlier than frame deadline: "
|
| + "presentation_time="
|
| + << frame_info->presentation_time
|
| + << ", frame_deadline=" << frame_info->frame_deadline
|
| + << ", now=" << now;
|
| + frame_info->presentation_time = frame_info->frame_deadline;
|
| + }
|
| +
|
| + // Compensate for significant lag by adjusting the frame time if needed
|
| + // to step past skipped frames.
|
| + uint64_t lag = now - frame_info->frame_time;
|
| + if (frame_info->frame_interval > 0u && lag > frame_info->frame_interval) {
|
| + uint64_t offset = lag % frame_info->frame_interval;
|
| + uint64_t adjustment = now - offset - frame_info->frame_time;
|
| + frame_info->frame_time = now - offset;
|
| + frame_info->frame_deadline += adjustment;
|
| + frame_info->presentation_time += adjustment;
|
| +
|
| + // Jank warning.
|
| + // TODO(jeffbrown): Suppress this once we're happy with things.
|
| + LOG(WARNING) << "Missed " << frame_info->frame_interval
|
| + << " us frame deadline by " << lag << " us, skipping "
|
| + << (lag / frame_info->frame_interval) << " frames";
|
| + }
|
| +
|
| + // Ensure frame time isn't going backwards, just in case the compositor's
|
| + // timing is seriously broken.
|
| + base::TimeDelta time_delta;
|
| + if (last_frame_info_) {
|
| + DCHECK(frame_info->frame_time >= last_frame_info_->frame_time);
|
| + time_delta = base::TimeDelta::FromMicroseconds(
|
| + frame_info->frame_time - last_frame_info_->frame_time);
|
| + }
|
| +
|
| + // Invoke the callback.
|
| + last_frame_info_ = frame_info.Pass();
|
| + delegate_->OnDraw(*last_frame_info_, time_delta);
|
| + }
|
| +}
|
| +
|
| +} // namespace ui
|
| +} // namespace mojo
|
|
|