928a6d6d7bd88ab07af6473b3ec87e1bad28d818
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / cc / CCSchedulerStateMachine.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCSchedulerStateMachine.h"
28
29 namespace WebCore {
30
31 CCSchedulerStateMachine::CCSchedulerStateMachine()
32     : m_commitState(COMMIT_STATE_IDLE)
33     , m_currentFrameNumber(0)
34     , m_lastFrameNumberWhereDrawWasCalled(-1)
35     , m_consecutiveFailedDraws(0)
36     , m_maximumNumberOfFailedDrawsBeforeDrawIsForced(3)
37     , m_needsRedraw(false)
38     , m_needsForcedRedraw(false)
39     , m_needsForcedRedrawAfterNextCommit(false)
40     , m_needsCommit(false)
41     , m_needsForcedCommit(false)
42     , m_mainThreadNeedsLayerTextures(false)
43     , m_updateMoreResourcesPending(false)
44     , m_insideVSync(false)
45     , m_visible(false)
46     , m_canBeginFrame(false)
47     , m_canDraw(true)
48     , m_drawIfPossibleFailed(false)
49     , m_textureState(LAYER_TEXTURE_STATE_UNLOCKED)
50     , m_contextState(CONTEXT_ACTIVE)
51 {
52 }
53
54 bool CCSchedulerStateMachine::hasDrawnThisFrame() const
55 {
56     return m_currentFrameNumber == m_lastFrameNumberWhereDrawWasCalled;
57 }
58
59 bool CCSchedulerStateMachine::drawSuspendedUntilCommit() const
60 {
61     if (!m_canDraw)
62         return true;
63     if (!m_visible)
64         return true;
65     if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
66         return true;
67     return false;
68 }
69
70 bool CCSchedulerStateMachine::scheduledToDraw() const
71 {
72     if (!m_needsRedraw)
73         return false;
74     if (drawSuspendedUntilCommit())
75         return false;
76     return true;
77 }
78
79 bool CCSchedulerStateMachine::shouldDraw() const
80 {
81     if (m_needsForcedRedraw)
82         return true;
83
84     if (!scheduledToDraw())
85         return false;
86     if (!m_insideVSync)
87         return false;
88     if (hasDrawnThisFrame())
89         return false;
90     if (m_contextState != CONTEXT_ACTIVE)
91         return false;
92     return true;
93 }
94
95 bool CCSchedulerStateMachine::shouldAcquireLayerTexturesForMainThread() const
96 {
97     if (!m_mainThreadNeedsLayerTextures)
98         return false;
99     if (m_textureState == LAYER_TEXTURE_STATE_UNLOCKED)
100         return true;
101     ASSERT(m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
102     // Transfer the lock from impl thread to main thread immediately if the
103     // impl thread is not even scheduled to draw. Guards against deadlocking.
104     if (!scheduledToDraw())
105         return true;
106     if (!vsyncCallbackNeeded())
107         return true;
108     return false;
109 }
110
111 CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction() const
112 {
113     if (shouldAcquireLayerTexturesForMainThread())
114         return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
115     switch (m_commitState) {
116     case COMMIT_STATE_IDLE:
117         if (m_contextState != CONTEXT_ACTIVE && m_needsForcedRedraw)
118             return ACTION_DRAW_FORCED;
119         if (m_contextState != CONTEXT_ACTIVE && m_needsForcedCommit)
120             return ACTION_BEGIN_FRAME;
121         if (m_contextState == CONTEXT_LOST)
122             return ACTION_BEGIN_CONTEXT_RECREATION;
123         if (m_contextState == CONTEXT_RECREATING)
124             return ACTION_NONE;
125         if (shouldDraw())
126             return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE;
127         if (m_needsCommit && ((m_visible && m_canBeginFrame) || m_needsForcedCommit))
128             return ACTION_BEGIN_FRAME;
129         return ACTION_NONE;
130
131     case COMMIT_STATE_FRAME_IN_PROGRESS:
132         if (shouldDraw())
133             return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE;
134         return ACTION_NONE;
135
136     case COMMIT_STATE_UPDATING_RESOURCES:
137         if (shouldDraw())
138             return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE;
139         if (!m_updateMoreResourcesPending)
140             return ACTION_BEGIN_UPDATE_MORE_RESOURCES;
141         return ACTION_NONE;
142
143     case COMMIT_STATE_READY_TO_COMMIT:
144         return ACTION_COMMIT;
145
146     case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
147         if (shouldDraw() || m_contextState == CONTEXT_LOST)
148             return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POSSIBLE;
149         // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If m_canDraw is false
150         // or textures are not available, proceed to the next step (similar as in COMMIT_STATE_IDLE).
151         bool canCommit = m_visible || m_needsForcedCommit;
152         if (m_needsCommit && canCommit && drawSuspendedUntilCommit())
153             return ACTION_BEGIN_FRAME;
154         return ACTION_NONE;
155     }
156     ASSERT_NOT_REACHED();
157     return ACTION_NONE;
158 }
159
160 void CCSchedulerStateMachine::updateState(Action action)
161 {
162     switch (action) {
163     case ACTION_NONE:
164         return;
165
166     case ACTION_BEGIN_FRAME:
167         ASSERT(m_visible || m_needsForcedCommit);
168         m_commitState = COMMIT_STATE_FRAME_IN_PROGRESS;
169         m_needsCommit = false;
170         m_needsForcedCommit = false;
171         return;
172
173     case ACTION_BEGIN_UPDATE_MORE_RESOURCES:
174         ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES);
175         m_updateMoreResourcesPending = true;
176         return;
177
178     case ACTION_COMMIT:
179         if ((m_needsCommit || !m_visible) && !m_needsForcedCommit)
180             m_commitState = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
181         else
182             m_commitState = COMMIT_STATE_IDLE;
183
184         m_needsRedraw = true;
185         if (m_drawIfPossibleFailed)
186             m_lastFrameNumberWhereDrawWasCalled = -1;
187
188         if (m_needsForcedRedrawAfterNextCommit) {
189             m_needsForcedRedrawAfterNextCommit = false;
190             m_needsForcedRedraw = true;
191         }
192
193         m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
194         return;
195
196     case ACTION_DRAW_FORCED:
197     case ACTION_DRAW_IF_POSSIBLE:
198         m_needsRedraw = false;
199         m_needsForcedRedraw = false;
200         m_drawIfPossibleFailed = false;
201         if (m_insideVSync)
202             m_lastFrameNumberWhereDrawWasCalled = m_currentFrameNumber;
203         if (m_commitState == COMMIT_STATE_WAITING_FOR_FIRST_DRAW)
204             m_commitState = COMMIT_STATE_IDLE;
205         if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
206             m_textureState = LAYER_TEXTURE_STATE_UNLOCKED;
207         return;
208
209     case ACTION_BEGIN_CONTEXT_RECREATION:
210         ASSERT(m_commitState == COMMIT_STATE_IDLE);
211         ASSERT(m_contextState == CONTEXT_LOST);
212         m_contextState = CONTEXT_RECREATING;
213         return;
214
215     case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
216         m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
217         m_mainThreadNeedsLayerTextures = false;
218         if (m_commitState != COMMIT_STATE_FRAME_IN_PROGRESS)
219             m_needsCommit = true;
220         return;
221     }
222 }
223
224 void CCSchedulerStateMachine::setMainThreadNeedsLayerTextures()
225 {
226     ASSERT(!m_mainThreadNeedsLayerTextures);
227     ASSERT(m_textureState != LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
228     m_mainThreadNeedsLayerTextures = true;
229 }
230
231 bool CCSchedulerStateMachine::vsyncCallbackNeeded() const
232 {
233     if (!m_visible || m_contextState != CONTEXT_ACTIVE) {
234         if (m_needsForcedRedraw || m_commitState == COMMIT_STATE_UPDATING_RESOURCES)
235             return true;
236
237         return false;
238     }
239
240     return m_needsRedraw || m_needsForcedRedraw || m_commitState == COMMIT_STATE_UPDATING_RESOURCES;
241 }
242
243 void CCSchedulerStateMachine::didEnterVSync()
244 {
245     m_insideVSync = true;
246 }
247
248 void CCSchedulerStateMachine::didLeaveVSync()
249 {
250     m_currentFrameNumber++;
251     m_insideVSync = false;
252 }
253
254 void CCSchedulerStateMachine::setVisible(bool visible)
255 {
256     m_visible = visible;
257 }
258
259 void CCSchedulerStateMachine::setNeedsRedraw()
260 {
261     m_needsRedraw = true;
262 }
263
264 void CCSchedulerStateMachine::setNeedsForcedRedraw()
265 {
266     m_needsForcedRedraw = true;
267 }
268
269 void CCSchedulerStateMachine::didDrawIfPossibleCompleted(bool success)
270 {
271     m_drawIfPossibleFailed = !success;
272     if (m_drawIfPossibleFailed) {
273         m_needsRedraw = true;
274         m_needsCommit = true;
275         m_consecutiveFailedDraws++;
276         if (m_consecutiveFailedDraws >= m_maximumNumberOfFailedDrawsBeforeDrawIsForced) {
277             m_consecutiveFailedDraws = 0;
278             // We need to force a draw, but it doesn't make sense to do this until
279             // we've committed and have new textures.
280             m_needsForcedRedrawAfterNextCommit = true;
281         }
282     } else
283       m_consecutiveFailedDraws = 0;
284 }
285
286 void CCSchedulerStateMachine::setNeedsCommit()
287 {
288     m_needsCommit = true;
289 }
290
291 void CCSchedulerStateMachine::setNeedsForcedCommit()
292 {
293     m_needsForcedCommit = true;
294 }
295
296 void CCSchedulerStateMachine::beginFrameComplete()
297 {
298     ASSERT(m_commitState == COMMIT_STATE_FRAME_IN_PROGRESS);
299     m_commitState = COMMIT_STATE_UPDATING_RESOURCES;
300 }
301
302 void CCSchedulerStateMachine::beginUpdateMoreResourcesComplete(bool morePending)
303 {
304     ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES);
305     ASSERT(m_updateMoreResourcesPending);
306     m_updateMoreResourcesPending = false;
307     if (!morePending)
308         m_commitState = COMMIT_STATE_READY_TO_COMMIT;
309 }
310
311 void CCSchedulerStateMachine::didLoseContext()
312 {
313     if (m_contextState == CONTEXT_LOST || m_contextState == CONTEXT_RECREATING)
314         return;
315     m_contextState = CONTEXT_LOST;
316 }
317
318 void CCSchedulerStateMachine::didRecreateContext()
319 {
320     ASSERT(m_contextState == CONTEXT_RECREATING);
321     m_contextState = CONTEXT_ACTIVE;
322     setNeedsCommit();
323 }
324
325 void CCSchedulerStateMachine::setMaximumNumberOfFailedDrawsBeforeDrawIsForced(int numDraws)
326 {
327     m_maximumNumberOfFailedDrawsBeforeDrawIsForced = numDraws;
328 }
329
330 }