[CoordinatedGraphics] The compositing loop is still running even after exiting AC...
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / CoordinatedGraphics / LayerTreeHost.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4  * Copyright (C) 2012 Company 100, Inc.
5  * Copyright (C) 2014-2019 Igalia S.L.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "LayerTreeHost.h"
31
32 #if USE(COORDINATED_GRAPHICS)
33
34 #include "DrawingArea.h"
35 #include "WebPage.h"
36 #include "WebPageProxyMessages.h"
37 #include <WebCore/Frame.h>
38 #include <WebCore/FrameView.h>
39 #include <WebCore/PageOverlayController.h>
40
41 #if USE(GLIB_EVENT_LOOP)
42 #include <wtf/glib/RunLoopSourcePriority.h>
43 #endif
44
45 namespace WebKit {
46 using namespace WebCore;
47
48 static const PlatformDisplayID primaryDisplayID = 0;
49 #if PLATFORM(GTK)
50 static const PlatformDisplayID compositingDisplayID = 1;
51 #else
52 static const PlatformDisplayID compositingDisplayID = primaryDisplayID;
53 #endif
54
55 LayerTreeHost::LayerTreeHost(WebPage& webPage)
56     : m_webPage(webPage)
57     , m_coordinator(webPage.corePage(), *this)
58     , m_compositorClient(*this)
59     , m_surface(AcceleratedSurface::create(webPage, *this))
60     , m_viewportController(webPage.size())
61     , m_layerFlushTimer(RunLoop::main(), this, &LayerTreeHost::layerFlushTimerFired)
62 {
63 #if USE(GLIB_EVENT_LOOP)
64     m_layerFlushTimer.setPriority(RunLoopSourcePriority::LayerFlushTimer);
65     m_layerFlushTimer.setName("[WebKit] LayerTreeHost");
66 #endif
67     m_coordinator.createRootLayer(m_webPage.size());
68     scheduleLayerFlush();
69
70     if (FrameView* frameView = m_webPage.mainFrameView()) {
71         auto contentsSize = frameView->contentsSize();
72         if (!contentsSize.isEmpty())
73             m_viewportController.didChangeContentsSize(contentsSize);
74     }
75
76     IntSize scaledSize(m_webPage.size());
77     scaledSize.scale(m_webPage.deviceScaleFactor());
78     float scaleFactor = m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor();
79
80     if (m_surface) {
81         TextureMapper::PaintFlags paintFlags = 0;
82
83         if (m_surface->shouldPaintMirrored())
84             paintFlags |= TextureMapper::PaintingMirrored;
85
86         m_compositor = ThreadedCompositor::create(m_compositorClient, m_compositorClient, compositingDisplayID, scaledSize, scaleFactor, ThreadedCompositor::ShouldDoFrameSync::Yes, paintFlags);
87         m_layerTreeContext.contextID = m_surface->surfaceID();
88     } else
89         m_compositor = ThreadedCompositor::create(m_compositorClient, m_compositorClient, compositingDisplayID, scaledSize, scaleFactor);
90
91     m_webPage.windowScreenDidChange(compositingDisplayID);
92
93     didChangeViewport();
94 }
95
96 LayerTreeHost::~LayerTreeHost()
97 {
98     ASSERT(!m_isValid);
99 }
100
101 void LayerTreeHost::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled)
102 {
103     if (m_layerFlushSchedulingEnabled == layerFlushingEnabled)
104         return;
105
106     m_layerFlushSchedulingEnabled = layerFlushingEnabled;
107
108     if (m_layerFlushSchedulingEnabled) {
109         m_compositor->resume();
110         scheduleLayerFlush();
111         return;
112     }
113
114     cancelPendingLayerFlush();
115     m_compositor->suspend();
116 }
117
118 void LayerTreeHost::setShouldNotifyAfterNextScheduledLayerFlush(bool notifyAfterScheduledLayerFlush)
119 {
120     m_notifyAfterScheduledLayerFlush = notifyAfterScheduledLayerFlush;
121 }
122
123 void LayerTreeHost::scheduleLayerFlush()
124 {
125     if (!m_layerFlushSchedulingEnabled)
126         return;
127
128     if (m_isWaitingForRenderer) {
129         m_scheduledWhileWaitingForRenderer = true;
130         return;
131     }
132
133     if (!m_layerFlushTimer.isActive())
134         m_layerFlushTimer.startOneShot(0_s);
135 }
136
137 void LayerTreeHost::cancelPendingLayerFlush()
138 {
139     m_layerFlushTimer.stop();
140 }
141
142 void LayerTreeHost::layerFlushTimerFired()
143 {
144     if (m_isSuspended || m_isWaitingForRenderer)
145         return;
146
147     m_coordinator.syncDisplayState();
148     m_webPage.flushPendingEditorStateUpdate();
149     m_webPage.willDisplayPage();
150
151     if (!m_isValid || !m_coordinator.rootCompositingLayer())
152         return;
153
154     // If a force-repaint callback was registered, we should force a 'frame sync' that
155     // will guarantee us a call to renderNextFrame() once the update is complete.
156     if (m_forceRepaintAsync.callbackID)
157         m_coordinator.forceFrameSync();
158
159     bool didSync = m_coordinator.flushPendingLayerChanges();
160
161     if (m_notifyAfterScheduledLayerFlush && didSync) {
162         m_webPage.drawingArea()->layerHostDidFlushLayers();
163         m_notifyAfterScheduledLayerFlush = false;
164     }
165 }
166
167 void LayerTreeHost::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
168 {
169     m_coordinator.setRootCompositingLayer(graphicsLayer);
170 }
171
172 void LayerTreeHost::setViewOverlayRootLayer(GraphicsLayer* viewOverlayRootLayer)
173 {
174     m_viewOverlayRootLayer = viewOverlayRootLayer;
175     m_coordinator.setViewOverlayRootLayer(viewOverlayRootLayer);
176 }
177
178 void LayerTreeHost::invalidate()
179 {
180     ASSERT(m_isValid);
181     m_isValid = false;
182
183     cancelPendingLayerFlush();
184
185     m_coordinator.invalidate();
186     m_compositor->invalidate();
187     m_surface = nullptr;
188 }
189
190 void LayerTreeHost::scrollNonCompositedContents(const IntRect& rect)
191 {
192     auto* frameView = m_webPage.mainFrameView();
193     if (!frameView || !frameView->delegatesScrolling())
194         return;
195
196     m_viewportController.didScroll(rect.location());
197     if (m_isDiscardable)
198         m_discardableSyncActions.add(DiscardableSyncActions::UpdateViewport);
199     else
200         didChangeViewport();
201 }
202
203 void LayerTreeHost::forceRepaint()
204 {
205     // This is necessary for running layout tests. Since in this case we are not waiting for a UIProcess to reply nicely.
206     // Instead we are just triggering forceRepaint. But we still want to have the scripted animation callbacks being executed.
207     m_coordinator.syncDisplayState();
208
209     // We need to schedule another flush, otherwise the forced paint might cancel a later expected flush.
210     scheduleLayerFlush();
211
212     if (!m_isWaitingForRenderer)
213         m_coordinator.flushPendingLayerChanges();
214     m_compositor->forceRepaint();
215 }
216
217 bool LayerTreeHost::forceRepaintAsync(CallbackID callbackID)
218 {
219     scheduleLayerFlush();
220
221     // We want a clean repaint, meaning that if we're currently waiting for the renderer
222     // to finish an update, we'll have to schedule another flush when it's done.
223     ASSERT(!m_forceRepaintAsync.callbackID);
224     m_forceRepaintAsync.callbackID = OptionalCallbackID(callbackID);
225     m_forceRepaintAsync.needsFreshFlush = m_scheduledWhileWaitingForRenderer;
226     return true;
227 }
228
229 void LayerTreeHost::sizeDidChange(const IntSize& size)
230 {
231     if (m_isDiscardable) {
232         m_discardableSyncActions.add(DiscardableSyncActions::UpdateSize);
233         m_viewportController.didChangeViewportSize(size);
234         return;
235     }
236
237     if (m_surface && m_surface->hostResize(size))
238         m_layerTreeContext.contextID = m_surface->surfaceID();
239
240     m_coordinator.sizeDidChange(size);
241     scheduleLayerFlush();
242
243     m_viewportController.didChangeViewportSize(size);
244     IntSize scaledSize(size);
245     scaledSize.scale(m_webPage.deviceScaleFactor());
246     m_compositor->setViewportSize(scaledSize, m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor());
247     didChangeViewport();
248 }
249
250 void LayerTreeHost::pauseRendering()
251 {
252     m_isSuspended = true;
253     m_compositor->suspend();
254 }
255
256 void LayerTreeHost::resumeRendering()
257 {
258     m_isSuspended = false;
259     m_compositor->resume();
260     scheduleLayerFlush();
261 }
262
263 GraphicsLayerFactory* LayerTreeHost::graphicsLayerFactory()
264 {
265     return &m_coordinator;
266 }
267
268 void LayerTreeHost::contentsSizeChanged(const IntSize& newSize)
269 {
270     m_viewportController.didChangeContentsSize(newSize);
271     if (m_isDiscardable)
272         m_discardableSyncActions.add(DiscardableSyncActions::UpdateViewport);
273     else
274         didChangeViewport();
275 }
276
277 void LayerTreeHost::didChangeViewportAttributes(ViewportAttributes&& attr)
278 {
279     m_viewportController.didChangeViewportAttributes(WTFMove(attr));
280     if (m_isDiscardable)
281         m_discardableSyncActions.add(DiscardableSyncActions::UpdateViewport);
282     else
283         didChangeViewport();
284 }
285
286 void LayerTreeHost::didChangeViewport()
287 {
288     FloatRect visibleRect(m_viewportController.visibleContentsRect());
289     if (visibleRect.isEmpty())
290         return;
291
292     // When using non overlay scrollbars, the contents size doesn't include the scrollbars, but we need to include them
293     // in the visible area used by the compositor to ensure that the scrollbar layers are also updated.
294     // See https://bugs.webkit.org/show_bug.cgi?id=160450.
295     FrameView* view = m_webPage.corePage()->mainFrame().view();
296     Scrollbar* scrollbar = view->verticalScrollbar();
297     if (scrollbar && !scrollbar->isOverlayScrollbar())
298         visibleRect.expand(scrollbar->width(), 0);
299     scrollbar = view->horizontalScrollbar();
300     if (scrollbar && !scrollbar->isOverlayScrollbar())
301         visibleRect.expand(0, scrollbar->height());
302
303     m_coordinator.setVisibleContentsRect(visibleRect);
304     scheduleLayerFlush();
305
306     float pageScale = m_viewportController.pageScaleFactor();
307     IntPoint scrollPosition = roundedIntPoint(visibleRect.location());
308     if (m_lastScrollPosition != scrollPosition) {
309         m_lastScrollPosition = scrollPosition;
310         m_compositor->setScrollPosition(m_lastScrollPosition, m_webPage.deviceScaleFactor() * pageScale);
311
312         if (!view->useFixedLayout())
313             view->notifyScrollPositionChanged(m_lastScrollPosition);
314     }
315
316     if (m_lastPageScaleFactor != pageScale) {
317         m_lastPageScaleFactor = pageScale;
318         m_webPage.scalePage(pageScale, m_lastScrollPosition);
319     }
320 }
321
322 void LayerTreeHost::setIsDiscardable(bool discardable)
323 {
324     m_isDiscardable = discardable;
325     if (m_isDiscardable) {
326         m_discardableSyncActions = OptionSet<DiscardableSyncActions>();
327         m_webPage.windowScreenDidChange(primaryDisplayID);
328         return;
329     }
330     m_webPage.windowScreenDidChange(compositingDisplayID);
331
332     if (m_discardableSyncActions.isEmpty())
333         return;
334
335     if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateSize)) {
336         // Size changes already sets the scale factor and updates the viewport.
337         sizeDidChange(m_webPage.size());
338         return;
339     }
340
341     if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateScale))
342         deviceOrPageScaleFactorChanged();
343
344     if (m_discardableSyncActions.contains(DiscardableSyncActions::UpdateViewport))
345         didChangeViewport();
346 }
347
348 #if PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
349 void LayerTreeHost::setNativeSurfaceHandleForCompositing(uint64_t handle)
350 {
351     m_layerTreeContext.contextID = handle;
352     m_compositor->setNativeSurfaceHandleForCompositing(handle);
353     scheduleLayerFlush();
354 }
355 #endif
356
357 void LayerTreeHost::deviceOrPageScaleFactorChanged()
358 {
359     if (m_isDiscardable) {
360         m_discardableSyncActions.add(DiscardableSyncActions::UpdateScale);
361         return;
362     }
363
364     if (m_surface && m_surface->hostResize(m_webPage.size()))
365         m_layerTreeContext.contextID = m_surface->surfaceID();
366
367     m_coordinator.deviceOrPageScaleFactorChanged();
368     m_webPage.corePage()->pageOverlayController().didChangeDeviceScaleFactor();
369     m_compositor->setScaleFactor(m_webPage.deviceScaleFactor() * m_viewportController.pageScaleFactor());
370 }
371
372 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
373 RefPtr<DisplayRefreshMonitor> LayerTreeHost::createDisplayRefreshMonitor(PlatformDisplayID displayID)
374 {
375     return m_compositor->displayRefreshMonitor(displayID);
376 }
377 #endif
378
379 void LayerTreeHost::didFlushRootLayer(const FloatRect& visibleContentRect)
380 {
381     // Because our view-relative overlay root layer is not attached to the FrameView's GraphicsLayer tree, we need to flush it manually.
382     if (m_viewOverlayRootLayer)
383         m_viewOverlayRootLayer->flushCompositingState(visibleContentRect);
384 }
385
386 void LayerTreeHost::commitSceneState(const CoordinatedGraphicsState& state)
387 {
388     m_isWaitingForRenderer = true;
389     m_compositor->updateSceneState(state);
390 }
391
392 void LayerTreeHost::frameComplete()
393 {
394     m_compositor->frameComplete();
395 }
396
397 uint64_t LayerTreeHost::nativeSurfaceHandleForCompositing()
398 {
399     if (!m_surface)
400         return m_layerTreeContext.contextID;
401
402     m_surface->initialize();
403     return m_surface->window();
404 }
405
406 void LayerTreeHost::didDestroyGLContext()
407 {
408     if (m_surface)
409         m_surface->finalize();
410 }
411
412 void LayerTreeHost::willRenderFrame()
413 {
414     if (m_surface)
415         m_surface->willRenderFrame();
416 }
417
418 void LayerTreeHost::didRenderFrame()
419 {
420     if (m_surface)
421         m_surface->didRenderFrame();
422 }
423
424 void LayerTreeHost::requestDisplayRefreshMonitorUpdate()
425 {
426     // Flush layers to cause a repaint. If m_isWaitingForRenderer was true at this point, the layer
427     // flush won't do anything, but that means there's a painting ongoing that will send the
428     // display refresh notification when it's done.
429     m_coordinator.forceFrameSync();
430     scheduleLayerFlush();
431 }
432
433 void LayerTreeHost::handleDisplayRefreshMonitorUpdate(bool hasBeenRescheduled)
434 {
435     // Call renderNextFrame. If hasBeenRescheduled is true, the layer flush will force a repaint
436     // that will cause the display refresh notification to come.
437     renderNextFrame(hasBeenRescheduled);
438     m_compositor->handleDisplayRefreshMonitorUpdate();
439 }
440
441 void LayerTreeHost::renderNextFrame(bool forceRepaint)
442 {
443     m_isWaitingForRenderer = false;
444     bool scheduledWhileWaitingForRenderer = std::exchange(m_scheduledWhileWaitingForRenderer, false);
445     m_coordinator.renderNextFrame();
446
447     if (m_forceRepaintAsync.callbackID) {
448         // If the asynchronous force-repaint needs a separate fresh flush, it was due to
449         // the force-repaint request being registered while CoordinatedLayerTreeHost was
450         // waiting for the renderer to finish an update.
451         ASSERT(!m_forceRepaintAsync.needsFreshFlush || scheduledWhileWaitingForRenderer);
452
453         // Execute the callback if another layer flush and the subsequent state update
454         // aren't needed. If they are, the callback will be executed when this function
455         // is called after the next update.
456         if (!m_forceRepaintAsync.needsFreshFlush) {
457             m_webPage.send(Messages::WebPageProxy::VoidCallback(m_forceRepaintAsync.callbackID.callbackID()));
458             m_forceRepaintAsync.callbackID = OptionalCallbackID();
459         }
460         m_forceRepaintAsync.needsFreshFlush = false;
461     }
462
463     if (scheduledWhileWaitingForRenderer || m_layerFlushTimer.isActive() || forceRepaint) {
464         m_layerFlushTimer.stop();
465         if (forceRepaint)
466             m_coordinator.forceFrameSync();
467         layerFlushTimerFired();
468     }
469 }
470
471 } // namespace WebKit
472
473 #endif // USE(COORDINATED_GRAPHICS)