OLD | NEW |
(Empty) | |
| 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 AN
Y |
| 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 AN
Y |
| 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 O
N |
| 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 #include <stdio.h> |
| 30 |
| 31 namespace WebCore { |
| 32 |
| 33 CCSchedulerStateMachine::CCSchedulerStateMachine() |
| 34 : m_commitState(COMMIT_STATE_IDLE) |
| 35 , m_currentFrameNumber(0) |
| 36 , m_lastFrameNumberWhereDrawWasCalled(-1) |
| 37 , m_consecutiveFailedDraws(0) |
| 38 , m_maximumNumberOfFailedDrawsBeforeDrawIsForced(3) |
| 39 , m_needsRedraw(false) |
| 40 , m_needsForcedRedraw(false) |
| 41 , m_needsForcedRedrawAfterNextCommit(false) |
| 42 , m_needsCommit(false) |
| 43 , m_needsForcedCommit(false) |
| 44 , m_mainThreadNeedsLayerTextures(false) |
| 45 , m_updateMoreResourcesPending(false) |
| 46 , m_insideVSync(false) |
| 47 , m_visible(false) |
| 48 , m_canBeginFrame(false) |
| 49 , m_canDraw(true) |
| 50 , m_drawIfPossibleFailed(false) |
| 51 , m_textureState(LAYER_TEXTURE_STATE_UNLOCKED) |
| 52 , m_contextState(CONTEXT_ACTIVE) |
| 53 { |
| 54 } |
| 55 |
| 56 bool CCSchedulerStateMachine::hasDrawnThisFrame() const |
| 57 { |
| 58 return m_currentFrameNumber == m_lastFrameNumberWhereDrawWasCalled; |
| 59 } |
| 60 |
| 61 bool CCSchedulerStateMachine::drawSuspendedUntilCommit() const |
| 62 { |
| 63 if (!m_canDraw) |
| 64 return true; |
| 65 if (!m_visible) |
| 66 return true; |
| 67 if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD) |
| 68 return true; |
| 69 return false; |
| 70 } |
| 71 |
| 72 bool CCSchedulerStateMachine::scheduledToDraw() const |
| 73 { |
| 74 if (!m_needsRedraw) |
| 75 return false; |
| 76 if (drawSuspendedUntilCommit()) |
| 77 return false; |
| 78 return true; |
| 79 } |
| 80 |
| 81 bool CCSchedulerStateMachine::shouldDraw() const |
| 82 { |
| 83 if (m_needsForcedRedraw) |
| 84 return true; |
| 85 |
| 86 if (!scheduledToDraw()) |
| 87 return false; |
| 88 if (!m_insideVSync) |
| 89 return false; |
| 90 if (hasDrawnThisFrame()) |
| 91 return false; |
| 92 if (m_contextState != CONTEXT_ACTIVE) |
| 93 return false; |
| 94 return true; |
| 95 } |
| 96 |
| 97 bool CCSchedulerStateMachine::shouldAcquireLayerTexturesForMainThread() const |
| 98 { |
| 99 if (!m_mainThreadNeedsLayerTextures) |
| 100 return false; |
| 101 if (m_textureState == LAYER_TEXTURE_STATE_UNLOCKED) |
| 102 return true; |
| 103 ASSERT(m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD); |
| 104 // Transfer the lock from impl thread to main thread immediately if the |
| 105 // impl thread is not even scheduled to draw. Guards against deadlocking. |
| 106 if (!scheduledToDraw()) |
| 107 return true; |
| 108 if (!vsyncCallbackNeeded()) |
| 109 return true; |
| 110 return false; |
| 111 } |
| 112 |
| 113 CCSchedulerStateMachine::Action CCSchedulerStateMachine::nextAction() const |
| 114 { |
| 115 if (shouldAcquireLayerTexturesForMainThread()) |
| 116 return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD; |
| 117 switch (m_commitState) { |
| 118 case COMMIT_STATE_IDLE: |
| 119 if (m_contextState != CONTEXT_ACTIVE && m_needsForcedRedraw) |
| 120 return ACTION_DRAW_FORCED; |
| 121 if (m_contextState != CONTEXT_ACTIVE && m_needsForcedCommit) |
| 122 return ACTION_BEGIN_FRAME; |
| 123 if (m_contextState == CONTEXT_LOST) |
| 124 return ACTION_BEGIN_CONTEXT_RECREATION; |
| 125 if (m_contextState == CONTEXT_RECREATING) |
| 126 return ACTION_NONE; |
| 127 if (shouldDraw()) |
| 128 return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POS
SIBLE; |
| 129 if (m_needsCommit && ((m_visible && m_canBeginFrame) || m_needsForcedCom
mit)) |
| 130 return ACTION_BEGIN_FRAME; |
| 131 return ACTION_NONE; |
| 132 |
| 133 case COMMIT_STATE_FRAME_IN_PROGRESS: |
| 134 if (shouldDraw()) |
| 135 return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POS
SIBLE; |
| 136 return ACTION_NONE; |
| 137 |
| 138 case COMMIT_STATE_UPDATING_RESOURCES: |
| 139 if (shouldDraw()) |
| 140 return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POS
SIBLE; |
| 141 if (!m_updateMoreResourcesPending) |
| 142 return ACTION_BEGIN_UPDATE_MORE_RESOURCES; |
| 143 return ACTION_NONE; |
| 144 |
| 145 case COMMIT_STATE_READY_TO_COMMIT: |
| 146 return ACTION_COMMIT; |
| 147 |
| 148 case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: |
| 149 if (shouldDraw() || m_contextState == CONTEXT_LOST) |
| 150 return m_needsForcedRedraw ? ACTION_DRAW_FORCED : ACTION_DRAW_IF_POS
SIBLE; |
| 151 // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If m_can
Draw is false |
| 152 // or textures are not available, proceed to the next step (similar as i
n COMMIT_STATE_IDLE). |
| 153 bool canCommit = m_visible || m_needsForcedCommit; |
| 154 if (m_needsCommit && canCommit && drawSuspendedUntilCommit()) |
| 155 return ACTION_BEGIN_FRAME; |
| 156 return ACTION_NONE; |
| 157 } |
| 158 ASSERT_NOT_REACHED(); |
| 159 return ACTION_NONE; |
| 160 } |
| 161 |
| 162 void CCSchedulerStateMachine::updateState(Action action) |
| 163 { |
| 164 switch (action) { |
| 165 case ACTION_NONE: |
| 166 return; |
| 167 |
| 168 case ACTION_BEGIN_FRAME: |
| 169 ASSERT(m_visible || m_needsForcedCommit); |
| 170 m_commitState = COMMIT_STATE_FRAME_IN_PROGRESS; |
| 171 m_needsCommit = false; |
| 172 m_needsForcedCommit = false; |
| 173 return; |
| 174 |
| 175 case ACTION_BEGIN_UPDATE_MORE_RESOURCES: |
| 176 ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES); |
| 177 m_updateMoreResourcesPending = true; |
| 178 return; |
| 179 |
| 180 case ACTION_COMMIT: |
| 181 if ((m_needsCommit || !m_visible) && !m_needsForcedCommit) |
| 182 m_commitState = COMMIT_STATE_WAITING_FOR_FIRST_DRAW; |
| 183 else |
| 184 m_commitState = COMMIT_STATE_IDLE; |
| 185 |
| 186 m_needsRedraw = true; |
| 187 if (m_drawIfPossibleFailed) |
| 188 m_lastFrameNumberWhereDrawWasCalled = -1; |
| 189 |
| 190 if (m_needsForcedRedrawAfterNextCommit) { |
| 191 m_needsForcedRedrawAfterNextCommit = false; |
| 192 m_needsForcedRedraw = true; |
| 193 } |
| 194 |
| 195 m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD; |
| 196 return; |
| 197 |
| 198 case ACTION_DRAW_FORCED: |
| 199 case ACTION_DRAW_IF_POSSIBLE: |
| 200 m_needsRedraw = false; |
| 201 m_needsForcedRedraw = false; |
| 202 m_drawIfPossibleFailed = false; |
| 203 if (m_insideVSync) |
| 204 m_lastFrameNumberWhereDrawWasCalled = m_currentFrameNumber; |
| 205 if (m_commitState == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) |
| 206 m_commitState = COMMIT_STATE_IDLE; |
| 207 if (m_textureState == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD) |
| 208 m_textureState = LAYER_TEXTURE_STATE_UNLOCKED; |
| 209 return; |
| 210 |
| 211 case ACTION_BEGIN_CONTEXT_RECREATION: |
| 212 ASSERT(m_commitState == COMMIT_STATE_IDLE); |
| 213 ASSERT(m_contextState == CONTEXT_LOST); |
| 214 m_contextState = CONTEXT_RECREATING; |
| 215 return; |
| 216 |
| 217 case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD: |
| 218 m_textureState = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD; |
| 219 m_mainThreadNeedsLayerTextures = false; |
| 220 if (m_commitState != COMMIT_STATE_FRAME_IN_PROGRESS) |
| 221 m_needsCommit = true; |
| 222 return; |
| 223 } |
| 224 } |
| 225 |
| 226 void CCSchedulerStateMachine::setMainThreadNeedsLayerTextures() |
| 227 { |
| 228 ASSERT(!m_mainThreadNeedsLayerTextures); |
| 229 ASSERT(m_textureState != LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD); |
| 230 m_mainThreadNeedsLayerTextures = true; |
| 231 } |
| 232 |
| 233 bool CCSchedulerStateMachine::vsyncCallbackNeeded() const |
| 234 { |
| 235 if (!m_visible || m_contextState != CONTEXT_ACTIVE) { |
| 236 if (m_needsForcedRedraw || m_commitState == COMMIT_STATE_UPDATING_RESOUR
CES) |
| 237 return true; |
| 238 |
| 239 return false; |
| 240 } |
| 241 |
| 242 return m_needsRedraw || m_needsForcedRedraw || m_commitState == COMMIT_STATE
_UPDATING_RESOURCES; |
| 243 } |
| 244 |
| 245 void CCSchedulerStateMachine::didEnterVSync() |
| 246 { |
| 247 m_insideVSync = true; |
| 248 } |
| 249 |
| 250 void CCSchedulerStateMachine::didLeaveVSync() |
| 251 { |
| 252 m_currentFrameNumber++; |
| 253 m_insideVSync = false; |
| 254 } |
| 255 |
| 256 void CCSchedulerStateMachine::setVisible(bool visible) |
| 257 { |
| 258 m_visible = visible; |
| 259 } |
| 260 |
| 261 void CCSchedulerStateMachine::setNeedsRedraw() |
| 262 { |
| 263 m_needsRedraw = true; |
| 264 } |
| 265 |
| 266 void CCSchedulerStateMachine::setNeedsForcedRedraw() |
| 267 { |
| 268 m_needsForcedRedraw = true; |
| 269 } |
| 270 |
| 271 void CCSchedulerStateMachine::didDrawIfPossibleCompleted(bool success) |
| 272 { |
| 273 m_drawIfPossibleFailed = !success; |
| 274 if (m_drawIfPossibleFailed) { |
| 275 m_needsRedraw = true; |
| 276 m_needsCommit = true; |
| 277 m_consecutiveFailedDraws++; |
| 278 if (m_consecutiveFailedDraws >= m_maximumNumberOfFailedDrawsBeforeDrawIs
Forced) { |
| 279 m_consecutiveFailedDraws = 0; |
| 280 // We need to force a draw, but it doesn't make sense to do this unt
il |
| 281 // we've committed and have new textures. |
| 282 m_needsForcedRedrawAfterNextCommit = true; |
| 283 } |
| 284 } else |
| 285 m_consecutiveFailedDraws = 0; |
| 286 } |
| 287 |
| 288 void CCSchedulerStateMachine::setNeedsCommit() |
| 289 { |
| 290 m_needsCommit = true; |
| 291 } |
| 292 |
| 293 void CCSchedulerStateMachine::setNeedsForcedCommit() |
| 294 { |
| 295 m_needsForcedCommit = true; |
| 296 } |
| 297 |
| 298 void CCSchedulerStateMachine::beginFrameComplete() |
| 299 { |
| 300 ASSERT(m_commitState == COMMIT_STATE_FRAME_IN_PROGRESS); |
| 301 m_commitState = COMMIT_STATE_UPDATING_RESOURCES; |
| 302 } |
| 303 |
| 304 void CCSchedulerStateMachine::beginFrameAborted() |
| 305 { |
| 306 ASSERT(m_commitState == COMMIT_STATE_FRAME_IN_PROGRESS); |
| 307 m_commitState = COMMIT_STATE_IDLE; |
| 308 } |
| 309 |
| 310 void CCSchedulerStateMachine::beginUpdateMoreResourcesComplete(bool morePending) |
| 311 { |
| 312 ASSERT(m_commitState == COMMIT_STATE_UPDATING_RESOURCES); |
| 313 ASSERT(m_updateMoreResourcesPending); |
| 314 m_updateMoreResourcesPending = false; |
| 315 if (!morePending) |
| 316 m_commitState = COMMIT_STATE_READY_TO_COMMIT; |
| 317 } |
| 318 |
| 319 void CCSchedulerStateMachine::didLoseContext() |
| 320 { |
| 321 if (m_contextState == CONTEXT_LOST || m_contextState == CONTEXT_RECREATING) |
| 322 return; |
| 323 m_contextState = CONTEXT_LOST; |
| 324 } |
| 325 |
| 326 void CCSchedulerStateMachine::didRecreateContext() |
| 327 { |
| 328 ASSERT(m_contextState == CONTEXT_RECREATING); |
| 329 m_contextState = CONTEXT_ACTIVE; |
| 330 setNeedsCommit(); |
| 331 } |
| 332 |
| 333 void CCSchedulerStateMachine::setMaximumNumberOfFailedDrawsBeforeDrawIsForced(in
t numDraws) |
| 334 { |
| 335 m_maximumNumberOfFailedDrawsBeforeDrawIsForced = numDraws; |
| 336 } |
| 337 |
| 338 } |
OLD | NEW |