Changeset 220672 in webkit
- Timestamp:
- Aug 14, 2017 3:23:35 AM (7 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r220639 r220672 1 2017-08-14 Zan Dobersek <zdobersek@igalia.com> 2 3 [ThreadedCompositor] Improve composition and update state handling 4 https://bugs.webkit.org/show_bug.cgi?id=172448 5 6 Reviewed by Carlos Garcia Campos. 7 8 In the ThreadedCompositor and related classes, we now track composition 9 and scene update states separately. This enables properly piping in the 10 DisplayRefreshMonitor object, leveraging it for both display refresh 11 notifications and signalling to the client that the scene update is 12 completed. 13 14 In CompositingRunLoop, two separate states are now used, one for 15 compositing and the other for scene update. Access to both should be done 16 while the related Lock object is held. The pending update state is also 17 tracked in order to schedule any required updates as soon as the current 18 state update is completed. 19 20 In ThreadedCompositor, the information about client notification and 21 update completion coordination is now also kept under a Lock object, 22 moving away from atomics. DisplayRefreshMonitor can now utilize just 23 two methods in order to either schedule an update or report that update 24 as finished. 25 26 * Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp: 27 (WebKit::CompositingRunLoop::CompositingRunLoop): 28 (WebKit::CompositingRunLoop::scheduleUpdate): 29 (WebKit::CompositingRunLoop::stopUpdates): 30 (WebKit::CompositingRunLoop::compositionCompleted): 31 (WebKit::CompositingRunLoop::updateCompleted): 32 (WebKit::CompositingRunLoop::updateTimerFired): 33 (WebKit::CompositingRunLoop::isActive): Deleted. 34 * Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h: 35 (WebKit::CompositingRunLoop::stateLock): 36 * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp: 37 (WebKit::m_displayRefreshMonitor): 38 (WebKit::ThreadedCompositor::sceneUpdateFinished): 39 (WebKit::ThreadedCompositor::updateSceneState): 40 (WebKit::ThreadedCompositor::requestDisplayRefreshMonitorUpdate): 41 (WebKit::ThreadedCompositor::handleDisplayRefreshMonitorUpdate): 42 (WebKit::ThreadedCompositor::renderNextFrameIfNeeded): Deleted. 43 (WebKit::ThreadedCompositor::completeCoordinatedUpdateIfNeeded): Deleted. 44 (WebKit::ThreadedCompositor::coordinateUpdateCompletionWithClient): Deleted. 45 * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h: 46 * Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp: 47 (WebKit::ThreadedDisplayRefreshMonitor::requestRefreshCallback): 48 (WebKit::ThreadedDisplayRefreshMonitor::displayRefreshCallback): 49 1 50 2017-08-13 Manuel Rego Casasnovas <rego@igalia.com> 2 51 -
trunk/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp
r218763 r220672 110 110 , m_updateFunction(WTFMove(updateFunction)) 111 111 { 112 m_updateState.store(UpdateState::Completed);113 114 112 #if USE(GLIB_EVENT_LOOP) 115 113 m_updateTimer.setPriority(RunLoopSourcePriority::CompositingThreadUpdateTimer); … … 145 143 } 146 144 147 bool CompositingRunLoop::isActive()148 {149 return m_updateState.load() != UpdateState::Completed;150 }151 152 145 void CompositingRunLoop::scheduleUpdate() 153 146 { 154 if (m_updateState.compareExchangeStrong(UpdateState::Completed, UpdateState::InProgress) == UpdateState::Completed) { 147 LockHolder stateLocker(m_state.lock); 148 scheduleUpdate(stateLocker); 149 } 150 151 void CompositingRunLoop::scheduleUpdate(LockHolder& stateLocker) 152 { 153 // An update was requested. Depending on the state: 154 // - if Idle, enter the Scheduled state and start the update timer, 155 // - if Scheduled, do nothing, 156 // - if InProgress or PendingCompletion, mark an update as pending, meaning another 157 // update will be scheduled as soon as the current one is completed. 158 159 UNUSED_PARAM(stateLocker); 160 161 switch (m_state.update) { 162 case UpdateState::Idle: 163 m_state.update = UpdateState::Scheduled; 155 164 m_updateTimer.startOneShot(0); 156 165 return; 157 } 158 159 if (m_updateState.compareExchangeStrong(UpdateState::InProgress, UpdateState::PendingAfterCompletion) == UpdateState::InProgress) 160 return; 166 case UpdateState::Scheduled: 167 return; 168 case UpdateState::InProgress: 169 case UpdateState::PendingCompletion: 170 m_state.pendingUpdate = true; 171 return; 172 } 161 173 } 162 174 163 175 void CompositingRunLoop::stopUpdates() 164 176 { 177 // Stop everything. 178 179 LockHolder locker(m_state.lock); 165 180 m_updateTimer.stop(); 166 m_updateState.store(UpdateState::Completed); 167 } 168 169 void CompositingRunLoop::updateCompleted() 170 { 171 if (m_updateState.compareExchangeStrong(UpdateState::InProgress, UpdateState::Completed) == UpdateState::InProgress) 172 return; 173 174 if (m_updateState.compareExchangeStrong(UpdateState::PendingAfterCompletion, UpdateState::InProgress) == UpdateState::PendingAfterCompletion) { 175 m_updateTimer.startOneShot(0); 176 return; 177 } 178 179 ASSERT_NOT_REACHED(); 181 m_state.composition = CompositionState::Idle; 182 m_state.update = UpdateState::Idle; 183 m_state.pendingUpdate = false; 184 } 185 186 void CompositingRunLoop::compositionCompleted(LockHolder& stateLocker) 187 { 188 // Composition has been signaled as completed, pushing the state into Idle. 189 // Depending on the state of the scene update: 190 // - if Idle, Scheduled or InProgress, do nothing, 191 // - if PendingCompletion, schedule a new update in case a pending update was marked, 192 // or push the scene update state into Idle otherwise. 193 194 UNUSED_PARAM(stateLocker); 195 196 m_state.composition = CompositionState::Idle; 197 198 switch (m_state.update) { 199 case UpdateState::Idle: 200 case UpdateState::Scheduled: 201 case UpdateState::InProgress: 202 return; 203 case UpdateState::PendingCompletion: 204 if (m_state.pendingUpdate) { 205 m_state.pendingUpdate = false; 206 m_state.update = UpdateState::Scheduled; 207 m_updateTimer.startOneShot(0); 208 return; 209 } 210 211 m_state.update = UpdateState::Idle; 212 return; 213 } 214 } 215 216 void CompositingRunLoop::updateCompleted(LockHolder& stateLocker) 217 { 218 // Scene update has been signaled as completed. Depending on the state: 219 // - if Idle, Scheduled or InProgress, do nothing, 220 // - if InProgress, push the state into PendingCompletion if the composition state is 221 // InProgress, otherwise schedule a new update in case a pending update was marked, 222 // otherwise push the scene update state into Idle. 223 224 UNUSED_PARAM(stateLocker); 225 226 switch (m_state.update) { 227 case UpdateState::Idle: 228 case UpdateState::Scheduled: 229 return; 230 case UpdateState::InProgress: 231 if (m_state.composition == CompositionState::InProgress) { 232 m_state.update = UpdateState::PendingCompletion; 233 return; 234 } 235 236 if (m_state.pendingUpdate) { 237 m_state.pendingUpdate = false; 238 m_state.update = UpdateState::Scheduled; 239 m_updateTimer.startOneShot(0); 240 return; 241 } 242 243 m_state.update = UpdateState::Idle; 244 return; 245 case UpdateState::PendingCompletion: 246 return; 247 } 180 248 } 181 249 182 250 void CompositingRunLoop::updateTimerFired() 183 251 { 252 { 253 // Both composition and scene update are now in progress. 254 LockHolder locker(m_state.lock); 255 m_state.composition = CompositionState::InProgress; 256 m_state.update = UpdateState::InProgress; 257 } 184 258 m_updateFunction(); 185 259 } -
trunk/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h
r218457 r220672 49 49 void performTaskSync(Function<void ()>&&); 50 50 51 bool isActive(); 51 Lock& stateLock() { return m_state.lock; } 52 52 53 void scheduleUpdate(); 54 void scheduleUpdate(LockHolder&); 53 55 void stopUpdates(); 54 56 55 void updateCompleted(); 57 void compositionCompleted(LockHolder&); 58 void updateCompleted(LockHolder&); 56 59 57 60 private: 61 enum class CompositionState { 62 Idle, 63 InProgress, 64 }; 58 65 enum class UpdateState { 59 Completed, 66 Idle, 67 Scheduled, 60 68 InProgress, 61 Pending AfterCompletion,69 PendingCompletion, 62 70 }; 63 71 … … 66 74 RunLoop::Timer<CompositingRunLoop> m_updateTimer; 67 75 Function<void ()> m_updateFunction; 68 Atomic<UpdateState> m_updateState;69 76 Lock m_dispatchSyncConditionMutex; 70 77 Condition m_dispatchSyncCondition; 78 79 80 struct { 81 Lock lock; 82 CompositionState composition { CompositionState::Idle }; 83 UpdateState update { UpdateState::Idle }; 84 bool pendingUpdate { false }; 85 } m_state; 71 86 }; 72 87 -
trunk/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp
r219391 r220672 69 69 } 70 70 71 m_clientRendersNextFrame.store(false);72 m_coordinateUpdateCompletionWithClient.store(false);73 74 71 m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] { 75 72 m_scene = adoptRef(new CoordinatedGraphicsScene(this)); … … 247 244 void ThreadedCompositor::sceneUpdateFinished() 248 245 { 249 bool shouldDispatchDisplayRefreshCallback = m_clientRendersNextFrame.load() 250 || m_displayRefreshMonitor->requiresDisplayRefreshCallback(); 251 bool shouldCoordinateUpdateCompletionWithClient = m_coordinateUpdateCompletionWithClient.load(); 252 246 // The composition has finished. Now we have to determine how to manage 247 // the scene update completion. 248 249 // The DisplayRefreshMonitor will be used to dispatch a callback on the client thread if: 250 // - clientRendersNextFrame is true (i.e. client has to be notified about the finished update), or 251 // - a DisplayRefreshMonitor callback was requested from the Web engine 252 bool shouldDispatchDisplayRefreshCallback { false }; 253 254 // If coordinateUpdateCompletionWithClient is true, the scene update completion has to be 255 // delayed until the DisplayRefreshMonitor callback. 256 bool shouldCoordinateUpdateCompletionWithClient { false }; 257 258 { 259 LockHolder locker(m_attributes.lock); 260 shouldDispatchDisplayRefreshCallback = m_attributes.clientRendersNextFrame 261 || m_displayRefreshMonitor->requiresDisplayRefreshCallback(); 262 shouldCoordinateUpdateCompletionWithClient = m_attributes.coordinateUpdateCompletionWithClient; 263 } 264 265 LockHolder stateLocker(m_compositingRunLoop->stateLock()); 266 267 // Schedule the DisplayRefreshMonitor callback, if necessary. 253 268 if (shouldDispatchDisplayRefreshCallback) 254 269 m_displayRefreshMonitor->dispatchDisplayRefreshCallback(); 270 271 // Mark the scene update as completed if no coordination is required and if not in a forced repaint. 255 272 if (!shouldCoordinateUpdateCompletionWithClient && !m_inForceRepaint) 256 m_compositingRunLoop->updateCompleted(); 273 m_compositingRunLoop->updateCompleted(stateLocker); 274 275 // Independent of the scene update, the composition itself is now completed. 276 m_compositingRunLoop->compositionCompleted(stateLocker); 257 277 } 258 278 … … 263 283 scene->commitSceneState(state); 264 284 265 m_clientRendersNextFrame.store(true); 285 LockHolder locker(m_attributes.lock); 286 287 // Client has to be notified upon finishing this scene update. 288 m_attributes.clientRendersNextFrame = true; 289 290 // Coordinate scene update completion with the client in case of changed or updated platform layers. 266 291 // Do not change m_coordinateUpdateCompletionWithClient while in force repaint. 267 if (m_inForceRepaint) 268 return; 269 bool coordinateUpdate = std::any_of(state.layersToUpdate.begin(), state.layersToUpdate.end(), 292 bool coordinateUpdate = !m_inForceRepaint && std::any_of(state.layersToUpdate.begin(), state.layersToUpdate.end(), 270 293 [](const std::pair<CoordinatedLayerID, CoordinatedGraphicsLayerState>& it) { 271 294 return it.second.platformLayerChanged || it.second.platformLayerUpdated; 272 295 }); 273 m_coordinateUpdateCompletionWithClient.store(coordinateUpdate); 296 297 m_attributes.coordinateUpdateCompletionWithClient |= coordinateUpdate; 274 298 }); 275 299 … … 292 316 } 293 317 294 void ThreadedCompositor::renderNextFrameIfNeeded() 295 { 296 if (m_clientRendersNextFrame.compareExchangeStrong(true, false)) 297 m_scene->renderNextFrame(); 298 } 299 300 void ThreadedCompositor::completeCoordinatedUpdateIfNeeded() 301 { 302 if (m_coordinateUpdateCompletionWithClient.compareExchangeStrong(true, false)) 303 m_compositingRunLoop->updateCompleted(); 304 } 305 306 void ThreadedCompositor::coordinateUpdateCompletionWithClient() 307 { 308 m_coordinateUpdateCompletionWithClient.store(true); 309 if (!m_compositingRunLoop->isActive()) 310 m_compositingRunLoop->scheduleUpdate(); 318 void ThreadedCompositor::requestDisplayRefreshMonitorUpdate() 319 { 320 // This is invoked by ThreadedDisplayRefreshMonitor when a fresh update is required. 321 322 LockHolder stateLocker(m_compositingRunLoop->stateLock()); 323 { 324 // coordinateUpdateCompletionWithClient is set to true in order to delay the scene update 325 // completion until the DisplayRefreshMonitor is fired on the main thread after the composition 326 // is completed. 327 LockHolder locker(m_attributes.lock); 328 m_attributes.coordinateUpdateCompletionWithClient = true; 329 } 330 m_compositingRunLoop->scheduleUpdate(stateLocker); 331 } 332 333 void ThreadedCompositor::handleDisplayRefreshMonitorUpdate(bool hasBeenRescheduled) 334 { 335 // Retrieve the clientRendersNextFrame and coordinateUpdateCompletionWithClient. 336 bool clientRendersNextFrame { false }; 337 bool coordinateUpdateCompletionWithClient { false }; 338 { 339 LockHolder locker(m_attributes.lock); 340 clientRendersNextFrame = std::exchange(m_attributes.clientRendersNextFrame, false); 341 coordinateUpdateCompletionWithClient = std::exchange(m_attributes.coordinateUpdateCompletionWithClient, false); 342 } 343 344 // If clientRendersNextFrame is true, the client is finally notified about the scene update nearing 345 // completion. The client will use this opportunity to clean up resources as appropriate. It can also 346 // perform any layer flush that was requested during the composition, or by any DisplayRefreshMonitor 347 // notifications that have been handled at this point. 348 if (clientRendersNextFrame) 349 m_client.renderNextFrame(); 350 351 LockHolder stateLocker(m_compositingRunLoop->stateLock()); 352 353 // If required, mark the current scene update as completed. CompositingRunLoop will take care of 354 // scheduling a new update in case an update was marked as pending due to previous layer flushes 355 // or DisplayRefreshMonitor notifications. 356 if (coordinateUpdateCompletionWithClient) 357 m_compositingRunLoop->updateCompleted(stateLocker); 358 359 // If the DisplayRefreshMonitor was scheduled again, we immediately demand the update completion 360 // coordination (like we do in requestDisplayRefreshMonitorUpdate()) and request an update. 361 if (hasBeenRescheduled) { 362 { 363 LockHolder locker(m_attributes.lock); 364 m_attributes.coordinateUpdateCompletionWithClient = true; 365 } 366 m_compositingRunLoop->scheduleUpdate(stateLocker); 367 } 311 368 } 312 369 #endif -
trunk/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h
r219067 r220672 89 89 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR) 90 90 RefPtr<WebCore::DisplayRefreshMonitor> displayRefreshMonitor(WebCore::PlatformDisplayID); 91 void renderNextFrameIfNeeded(); 92 void completeCoordinatedUpdateIfNeeded(); 93 void coordinateUpdateCompletionWithClient(); 91 void requestDisplayRefreshMonitorUpdate(); 92 void handleDisplayRefreshMonitorUpdate(bool hasBeenRescheduled); 94 93 #endif 95 94 … … 127 126 bool drawsBackground { true }; 128 127 bool needsResize { false }; 128 129 bool clientRendersNextFrame { false }; 130 bool coordinateUpdateCompletionWithClient { false }; 129 131 } m_attributes; 130 132 … … 132 134 Ref<ThreadedDisplayRefreshMonitor> m_displayRefreshMonitor; 133 135 #endif 134 135 Atomic<bool> m_clientRendersNextFrame;136 Atomic<bool> m_coordinateUpdateCompletionWithClient;137 136 }; 138 137 -
trunk/Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp
r216970 r220672 54 54 setIsScheduled(true); 55 55 56 // Only request an update in case we're not currently handling the display 57 // refresh notifications under ThreadedDisplayRefreshMonitor::displayRefreshCallback(). 58 // Any such schedule request is handled in that method after the notifications. 56 59 if (isPreviousFrameDone()) 57 m_compositor-> coordinateUpdateCompletionWithClient();60 m_compositor->requestDisplayRefreshMonitorUpdate(); 58 61 59 62 return true; … … 81 84 void ThreadedDisplayRefreshMonitor::displayRefreshCallback() 82 85 { 83 bool shouldHandleDisplayRefreshNotification = false;86 bool shouldHandleDisplayRefreshNotification { false }; 84 87 { 85 88 LockHolder locker(mutex()); … … 92 95 DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(this); 93 96 94 if (m_compositor) {95 m_compositor->renderNextFrameIfNeeded();96 m_compositor->completeCoordinatedUpdateIfNeeded();97 if (isScheduled())98 m_compositor->coordinateUpdateCompletionWithClient();97 // Retrieve the scheduled status for this DisplayRefreshMonitor. 98 bool hasBeenRescheduled { false }; 99 { 100 LockHolder locker(mutex()); 101 hasBeenRescheduled = isScheduled(); 99 102 } 103 104 // Notify the compositor about the completed DisplayRefreshMonitor update, passing 105 // along information about any schedule request that might have occurred during 106 // the notification handling. 107 if (m_compositor) 108 m_compositor->handleDisplayRefreshMonitorUpdate(hasBeenRescheduled); 100 109 } 101 110
Note: See TracChangeset
for help on using the changeset viewer.