d31f042e76180bc872aa2aa336614306b13ef39a
[platform/framework/web/crosswalk.git] / src / cc / scheduler / scheduler.cc
1 // Copyright 2011 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 "cc/scheduler/scheduler.h"
6
7 #include <algorithm>
8 #include "base/auto_reset.h"
9 #include "base/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "cc/debug/devtools_instrumentation.h"
12 #include "cc/debug/traced_value.h"
13 #include "ui/gfx/frame_time.h"
14
15 namespace cc {
16
17 Scheduler::Scheduler(SchedulerClient* client,
18                      const SchedulerSettings& scheduler_settings,
19                      int layer_tree_host_id)
20     : settings_(scheduler_settings),
21       client_(client),
22       layer_tree_host_id_(layer_tree_host_id),
23       last_set_needs_begin_impl_frame_(false),
24       state_machine_(scheduler_settings),
25       inside_process_scheduled_actions_(false),
26       inside_action_(SchedulerStateMachine::ACTION_NONE),
27       weak_factory_(this) {
28   DCHECK(client_);
29   DCHECK(!state_machine_.BeginImplFrameNeeded());
30 }
31
32 Scheduler::~Scheduler() {}
33
34 void Scheduler::SetCanStart() {
35   state_machine_.SetCanStart();
36   ProcessScheduledActions();
37 }
38
39 void Scheduler::SetVisible(bool visible) {
40   state_machine_.SetVisible(visible);
41   ProcessScheduledActions();
42 }
43
44 void Scheduler::SetCanDraw(bool can_draw) {
45   state_machine_.SetCanDraw(can_draw);
46   ProcessScheduledActions();
47 }
48
49 void Scheduler::NotifyReadyToActivate() {
50   state_machine_.NotifyReadyToActivate();
51   ProcessScheduledActions();
52 }
53
54 void Scheduler::ActivatePendingTree() {
55   client_->ScheduledActionActivatePendingTree();
56 }
57
58 void Scheduler::SetNeedsCommit() {
59   state_machine_.SetNeedsCommit();
60   ProcessScheduledActions();
61 }
62
63 void Scheduler::SetNeedsForcedCommitForReadback() {
64   state_machine_.SetNeedsCommit();
65   state_machine_.SetNeedsForcedCommitForReadback();
66   ProcessScheduledActions();
67 }
68
69 void Scheduler::SetNeedsRedraw() {
70   state_machine_.SetNeedsRedraw();
71   ProcessScheduledActions();
72 }
73
74 void Scheduler::SetNeedsManageTiles() {
75   DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
76   state_machine_.SetNeedsManageTiles();
77   ProcessScheduledActions();
78 }
79
80 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
81   state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
82   ProcessScheduledActions();
83 }
84
85 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
86   state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
87   ProcessScheduledActions();
88 }
89
90 void Scheduler::SetMainThreadNeedsLayerTextures() {
91   state_machine_.SetMainThreadNeedsLayerTextures();
92   ProcessScheduledActions();
93 }
94
95 void Scheduler::FinishCommit() {
96   TRACE_EVENT0("cc", "Scheduler::FinishCommit");
97   state_machine_.FinishCommit();
98   ProcessScheduledActions();
99 }
100
101 void Scheduler::BeginMainFrameAborted(bool did_handle) {
102   TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
103   state_machine_.BeginMainFrameAborted(did_handle);
104   ProcessScheduledActions();
105 }
106
107 void Scheduler::DidManageTiles() {
108   state_machine_.DidManageTiles();
109 }
110
111 void Scheduler::DidLoseOutputSurface() {
112   TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
113   last_set_needs_begin_impl_frame_ = false;
114   begin_impl_frame_deadline_closure_.Cancel();
115   state_machine_.DidLoseOutputSurface();
116   ProcessScheduledActions();
117 }
118
119 void Scheduler::DidCreateAndInitializeOutputSurface() {
120   TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
121   DCHECK(!last_set_needs_begin_impl_frame_);
122   DCHECK(begin_impl_frame_deadline_closure_.IsCancelled());
123   state_machine_.DidCreateAndInitializeOutputSurface();
124   ProcessScheduledActions();
125 }
126
127 base::TimeTicks Scheduler::AnticipatedDrawTime() {
128   TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
129
130   if (!last_set_needs_begin_impl_frame_ ||
131       last_begin_impl_frame_args_.interval <= base::TimeDelta())
132     return base::TimeTicks();
133
134   base::TimeTicks now = gfx::FrameTime::Now();
135   base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time,
136                                       last_begin_impl_frame_args_.deadline);
137   int64 intervals =
138       1 + ((now - timebase) / last_begin_impl_frame_args_.interval);
139   return timebase + (last_begin_impl_frame_args_.interval * intervals);
140 }
141
142 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
143   return last_begin_impl_frame_args_.frame_time;
144 }
145
146 void Scheduler::SetupNextBeginImplFrameIfNeeded() {
147   bool needs_begin_impl_frame =
148       state_machine_.BeginImplFrameNeeded();
149
150   bool at_end_of_deadline =
151       state_machine_.begin_impl_frame_state() ==
152           SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
153
154   bool should_call_set_needs_begin_impl_frame =
155       // Always request the BeginImplFrame immediately if it wasn't needed
156       // before.
157       (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) ||
158       // We always need to explicitly request our next BeginImplFrame.
159       at_end_of_deadline;
160
161   if (should_call_set_needs_begin_impl_frame) {
162     client_->SetNeedsBeginImplFrame(needs_begin_impl_frame);
163     last_set_needs_begin_impl_frame_ = needs_begin_impl_frame;
164   }
165
166   bool needs_advance_commit_state_timer = false;
167   // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
168   // aren't expecting any more BeginImplFrames. This should only be needed by
169   // the synchronous compositor when BeginImplFrameNeeded is false.
170   if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
171     DCHECK(!state_machine_.SupportsProactiveBeginImplFrame());
172     DCHECK(!needs_begin_impl_frame);
173     if (poll_for_draw_triggers_closure_.IsCancelled()) {
174       poll_for_draw_triggers_closure_.Reset(
175           base::Bind(&Scheduler::PollForAnticipatedDrawTriggers,
176                      weak_factory_.GetWeakPtr()));
177       base::MessageLoop::current()->PostDelayedTask(
178           FROM_HERE,
179           poll_for_draw_triggers_closure_.callback(),
180           last_begin_impl_frame_args_.interval);
181     }
182   } else {
183     poll_for_draw_triggers_closure_.Cancel();
184
185     // At this point we'd prefer to advance through the commit flow by
186     // drawing a frame, however it's possible that the frame rate controller
187     // will not give us a BeginImplFrame until the commit completes.  See
188     // crbug.com/317430 for an example of a swap ack being held on commit. Thus
189     // we set a repeating timer to poll on ProcessScheduledActions until we
190     // successfully reach BeginImplFrame.
191     if (state_machine_.IsCommitStateWaiting())
192       needs_advance_commit_state_timer = true;
193   }
194   if (needs_advance_commit_state_timer !=
195       advance_commit_state_timer_.IsRunning()) {
196     if (needs_advance_commit_state_timer &&
197         last_begin_impl_frame_args_.IsValid()) {
198     // Since we'd rather get a BeginImplFrame by the normally mechanism, we set
199     // the interval to twice the interval from the previous frame.
200       advance_commit_state_timer_.Start(
201           FROM_HERE,
202           last_begin_impl_frame_args_.interval * 2,
203           base::Bind(&Scheduler::ProcessScheduledActions,
204                      base::Unretained(this)));
205     } else {
206       advance_commit_state_timer_.Stop();
207     }
208   }
209 }
210
211 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
212   TRACE_EVENT0("cc", "Scheduler::BeginImplFrame");
213   DCHECK(state_machine_.begin_impl_frame_state() ==
214          SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
215   DCHECK(state_machine_.HasInitializedOutputSurface());
216   last_begin_impl_frame_args_ = args;
217   last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
218   state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_);
219
220   if (settings_.switch_to_low_latency_if_possible) {
221     state_machine_.SetSkipBeginMainFrameToReduceLatency(
222         state_machine_.MainThreadIsInHighLatencyMode() &&
223             CanCommitAndActivateBeforeDeadline());
224   }
225
226   ProcessScheduledActions();
227
228   if (!state_machine_.HasInitializedOutputSurface())
229     return;
230
231   state_machine_.OnBeginImplFrameDeadlinePending();
232   devtools_instrumentation::didBeginFrame(layer_tree_host_id_);
233   if (settings_.using_synchronous_renderer_compositor) {
234     // The synchronous renderer compositor has to make its GL calls
235     // within this call to BeginImplFrame.
236     // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
237     // so the sychronous renderer compositor can take advantage of splitting
238     // up the BeginImplFrame and deadline as well.
239     OnBeginImplFrameDeadline();
240   } else if (!settings_.deadline_scheduling_enabled) {
241     // We emulate the old non-deadline scheduler here by posting the
242     // deadline task without any delay.
243     PostBeginImplFrameDeadline(base::TimeTicks());
244   } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
245     // We are ready to draw a new active tree immediately.
246     PostBeginImplFrameDeadline(base::TimeTicks());
247   } else if (state_machine_.needs_redraw()) {
248     // We have an animation or fast input path on the impl thread that wants
249     // to draw, so don't wait too long for a new active tree.
250     PostBeginImplFrameDeadline(last_begin_impl_frame_args_.deadline);
251   } else {
252     // The impl thread doesn't have anything it wants to draw and we are just
253     // waiting for a new active tree, so post the deadline for the next
254     // expected BeginImplFrame start. This allows us to draw immediately when
255     // there is a new active tree, instead of waiting for the next
256     // BeginImplFrame.
257     // TODO(brianderson): Handle long deadlines (that are past the next frame's
258     // frame time) properly instead of using this hack.
259     PostBeginImplFrameDeadline(last_begin_impl_frame_args_.frame_time +
260                                last_begin_impl_frame_args_.interval);
261   }
262 }
263
264 void Scheduler::PostBeginImplFrameDeadline(base::TimeTicks deadline) {
265   begin_impl_frame_deadline_closure_.Cancel();
266   begin_impl_frame_deadline_closure_.Reset(
267       base::Bind(&Scheduler::OnBeginImplFrameDeadline,
268                  weak_factory_.GetWeakPtr()));
269   client_->PostBeginImplFrameDeadline(
270       begin_impl_frame_deadline_closure_.callback(), deadline);
271 }
272
273 void Scheduler::OnBeginImplFrameDeadline() {
274   TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
275   DCHECK(state_machine_.HasInitializedOutputSurface());
276   begin_impl_frame_deadline_closure_.Cancel();
277   state_machine_.OnBeginImplFrameDeadline();
278   ProcessScheduledActions();
279
280   if (state_machine_.HasInitializedOutputSurface()) {
281     // We only transition out of BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE when all
282     // actions that occur back-to-back in response to entering
283     // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE have completed. This is important
284     // because sending the BeginMainFrame will not occur if we transition to
285     // BEGIN_IMPL_FRAME_STATE_IDLE too early.
286     state_machine_.OnBeginImplFrameIdle();
287   }
288
289   client_->DidBeginImplFrameDeadline();
290 }
291
292 void Scheduler::PollForAnticipatedDrawTriggers() {
293   TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
294   poll_for_draw_triggers_closure_.Cancel();
295   state_machine_.DidEnterPollForAnticipatedDrawTriggers();
296   ProcessScheduledActions();
297   state_machine_.DidLeavePollForAnticipatedDrawTriggers();
298 }
299
300 void Scheduler::DrawAndSwapIfPossible() {
301   DrawSwapReadbackResult result =
302       client_->ScheduledActionDrawAndSwapIfPossible();
303   state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
304 }
305
306 void Scheduler::DrawAndSwapForced() {
307   client_->ScheduledActionDrawAndSwapForced();
308 }
309
310 void Scheduler::DrawAndReadback() {
311   DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
312   DCHECK(!result.did_swap);
313 }
314
315 void Scheduler::ProcessScheduledActions() {
316   // We do not allow ProcessScheduledActions to be recursive.
317   // The top-level call will iteratively execute the next action for us anyway.
318   if (inside_process_scheduled_actions_)
319     return;
320
321   base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
322
323   SchedulerStateMachine::Action action;
324   do {
325     state_machine_.CheckInvariants();
326     action = state_machine_.NextAction();
327     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
328                  "SchedulerStateMachine",
329                  "state",
330                  TracedValue::FromValue(state_machine_.AsValue().release()));
331     state_machine_.UpdateState(action);
332     base::AutoReset<SchedulerStateMachine::Action>
333         mark_inside_action(&inside_action_, action);
334     switch (action) {
335       case SchedulerStateMachine::ACTION_NONE:
336         break;
337       case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
338         client_->ScheduledActionSendBeginMainFrame();
339         break;
340       case SchedulerStateMachine::ACTION_COMMIT:
341         client_->ScheduledActionCommit();
342         break;
343       case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
344         client_->ScheduledActionUpdateVisibleTiles();
345         break;
346       case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
347         ActivatePendingTree();
348         break;
349       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
350         DrawAndSwapIfPossible();
351         break;
352       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
353         DrawAndSwapForced();
354         break;
355       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
356         // No action is actually performed, but this allows the state machine to
357         // advance out of its waiting to draw state without actually drawing.
358         break;
359       case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
360         DrawAndReadback();
361         break;
362       case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
363         client_->ScheduledActionBeginOutputSurfaceCreation();
364         break;
365       case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
366         client_->ScheduledActionAcquireLayerTexturesForMainThread();
367         break;
368       case SchedulerStateMachine::ACTION_MANAGE_TILES:
369         client_->ScheduledActionManageTiles();
370         break;
371     }
372   } while (action != SchedulerStateMachine::ACTION_NONE);
373
374   SetupNextBeginImplFrameIfNeeded();
375   client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
376
377   if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly())
378     PostBeginImplFrameDeadline(base::TimeTicks());
379 }
380
381 bool Scheduler::WillDrawIfNeeded() const {
382   return !state_machine_.PendingDrawsShouldBeAborted();
383 }
384
385 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
386   // Check if the main thread computation and commit can be finished before the
387   // impl thread's deadline.
388   base::TimeTicks estimated_draw_time =
389       last_begin_impl_frame_args_.frame_time +
390       client_->BeginMainFrameToCommitDurationEstimate() +
391       client_->CommitToActivateDurationEstimate();
392
393   return estimated_draw_time < last_begin_impl_frame_args_.deadline;
394 }
395
396 }  // namespace cc