OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "mojo/ui/choreographer.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/logging.h" |
| 9 #include "mojo/public/cpp/system/functions.h" |
| 10 |
| 11 namespace mojo { |
| 12 namespace ui { |
| 13 |
| 14 Choreographer::Choreographer(mojo::gfx::composition::Scene* scene, |
| 15 ChoreographerDelegate* delegate) |
| 16 : delegate_(delegate) { |
| 17 DCHECK(delegate_); |
| 18 scene->GetScheduler(mojo::GetProxy(&scene_scheduler_)); |
| 19 } |
| 20 |
| 21 Choreographer::Choreographer( |
| 22 mojo::gfx::composition::SceneSchedulerPtr scene_scheduler, |
| 23 ChoreographerDelegate* delegate) |
| 24 : scene_scheduler_(scene_scheduler.Pass()), delegate_(delegate) { |
| 25 DCHECK(scene_scheduler_); |
| 26 DCHECK(delegate_); |
| 27 } |
| 28 |
| 29 Choreographer::~Choreographer() {} |
| 30 |
| 31 void Choreographer::ScheduleDraw() { |
| 32 if (!draw_scheduled_) { |
| 33 draw_scheduled_ = true; |
| 34 ScheduleFrame(); |
| 35 } |
| 36 } |
| 37 |
| 38 void Choreographer::ScheduleFrame() { |
| 39 if (!frame_scheduled_) { |
| 40 frame_scheduled_ = true; |
| 41 scene_scheduler_->ScheduleFrame( |
| 42 base::Bind(&Choreographer::DoFrame, base::Unretained(this))); |
| 43 } |
| 44 } |
| 45 |
| 46 void Choreographer::DoFrame(mojo::gfx::composition::FrameInfoPtr frame_info) { |
| 47 DCHECK(frame_info); |
| 48 DCHECK(frame_scheduled_); |
| 49 frame_scheduled_ = false; |
| 50 |
| 51 if (draw_scheduled_) { |
| 52 draw_scheduled_ = false; |
| 53 |
| 54 // To reduce latency and jank, anticipate the next frame to be drawn by |
| 55 // scheduling it early. |
| 56 // |
| 57 // TODO(jeffbrown): Reenable this once issue #604 is fixed. Unfortunately |
| 58 // this exacerbates starvation issues in the Mojo message pump. |
| 59 // ScheduleFrame(); |
| 60 |
| 61 // Ensure frame info is sane since it comes from another service. |
| 62 // TODO(jeffbrown): Would be better to report an error to the client |
| 63 // who can shut things down if needed. |
| 64 MojoTimeTicks now = MojoGetTimeTicksNow(); |
| 65 if (frame_info->frame_time > now) { |
| 66 LOG(WARNING) << "Frame time is in the future: frame_time=" |
| 67 << frame_info->frame_time << ", now=" << now; |
| 68 frame_info->frame_time = now; |
| 69 } |
| 70 if (frame_info->frame_deadline < frame_info->frame_time) { |
| 71 LOG(WARNING) |
| 72 << "Frame deadline is earlier than frame time: frame_deadline=" |
| 73 << frame_info->frame_deadline |
| 74 << ", frame_time=" << frame_info->frame_time << ", now=" << now; |
| 75 frame_info->frame_deadline = frame_info->frame_time; |
| 76 } |
| 77 if (frame_info->presentation_time < frame_info->frame_deadline) { |
| 78 LOG(WARNING) << "Presentation time is earlier than frame deadline: " |
| 79 "presentation_time=" |
| 80 << frame_info->presentation_time |
| 81 << ", frame_deadline=" << frame_info->frame_deadline |
| 82 << ", now=" << now; |
| 83 frame_info->presentation_time = frame_info->frame_deadline; |
| 84 } |
| 85 |
| 86 // Compensate for significant lag by adjusting the frame time if needed |
| 87 // to step past skipped frames. |
| 88 uint64_t lag = now - frame_info->frame_time; |
| 89 if (frame_info->frame_interval > 0u && lag > frame_info->frame_interval) { |
| 90 uint64_t offset = lag % frame_info->frame_interval; |
| 91 uint64_t adjustment = now - offset - frame_info->frame_time; |
| 92 frame_info->frame_time = now - offset; |
| 93 frame_info->frame_deadline += adjustment; |
| 94 frame_info->presentation_time += adjustment; |
| 95 |
| 96 // Jank warning. |
| 97 // TODO(jeffbrown): Suppress this once we're happy with things. |
| 98 LOG(WARNING) << "Missed " << frame_info->frame_interval |
| 99 << " us frame deadline by " << lag << " us, skipping " |
| 100 << (lag / frame_info->frame_interval) << " frames"; |
| 101 } |
| 102 |
| 103 // Ensure frame time isn't going backwards, just in case the compositor's |
| 104 // timing is seriously broken. |
| 105 base::TimeDelta time_delta; |
| 106 if (last_frame_info_) { |
| 107 DCHECK(frame_info->frame_time >= last_frame_info_->frame_time); |
| 108 time_delta = base::TimeDelta::FromMicroseconds( |
| 109 frame_info->frame_time - last_frame_info_->frame_time); |
| 110 } |
| 111 |
| 112 // Invoke the callback. |
| 113 last_frame_info_ = frame_info.Pass(); |
| 114 delegate_->OnDraw(*last_frame_info_, time_delta); |
| 115 } |
| 116 } |
| 117 |
| 118 } // namespace ui |
| 119 } // namespace mojo |
OLD | NEW |