diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp')
-rw-r--r-- | Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp | 372 |
1 files changed, 179 insertions, 193 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp b/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp index 70f6c8365..40bb07d9f 100644 --- a/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp +++ b/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp @@ -29,6 +29,7 @@ #if USE(TEXTURE_MAPPER_GL) +#include "AcceleratedSurface.h" #include "DrawingAreaImpl.h" #include "TextureMapperGL.h" #include "WebPage.h" @@ -46,63 +47,103 @@ #include <WebCore/MainFrame.h> #include <WebCore/Page.h> #include <WebCore/Settings.h> -#include <wtf/CurrentTime.h> - #include <gdk/gdk.h> -#if defined(GDK_WINDOWING_X11) -#define Region XRegion -#define Font XFont -#define Cursor XCursor -#define Screen XScreen -#include <gdk/gdkx.h> -#endif +#include <wtf/CurrentTime.h> using namespace WebCore; namespace WebKit { -PassRefPtr<LayerTreeHostGtk> LayerTreeHostGtk::create(WebPage* webPage) +LayerTreeHostGtk::RenderFrameScheduler::RenderFrameScheduler(std::function<bool()> renderer) + : m_renderer(WTFMove(renderer)) + , m_timer(RunLoop::main(), this, &LayerTreeHostGtk::RenderFrameScheduler::renderFrame) { - RefPtr<LayerTreeHostGtk> host = adoptRef(new LayerTreeHostGtk(webPage)); - host->initialize(); - return host.release(); + // We use a RunLoop timer because otherwise GTK+ event handling during dragging can starve WebCore timers, which have a lower priority. + // Use a higher priority than WebCore timers. + m_timer.setPriority(GDK_PRIORITY_REDRAW - 1); } -LayerTreeHostGtk::LayerTreeHostGtk(WebPage* webPage) - : LayerTreeHost(webPage) - , m_isValid(true) - , m_notifyAfterScheduledLayerFlush(false) - , m_lastFlushTime(0) - , m_layerFlushSchedulingEnabled(true) - , m_layerFlushTimerCallbackId(0) +LayerTreeHostGtk::RenderFrameScheduler::~RenderFrameScheduler() { } -GLContext* LayerTreeHostGtk::glContext() +void LayerTreeHostGtk::RenderFrameScheduler::start() { - if (m_context) - return m_context.get(); + if (m_timer.isActive()) + return; + m_fireTime = 0; + nextFrame(); +} + +void LayerTreeHostGtk::RenderFrameScheduler::stop() +{ + m_timer.stop(); +} + +static inline bool shouldSkipNextFrameBecauseOfContinousImmediateFlushes(double current, double lastImmediateFlushTime) +{ + // 100ms is about a perceptable delay in UI, so when scheduling layer flushes immediately for more than 100ms, + // we skip the next frame to ensure pending timers have a change to be fired. + static const double maxDurationOfImmediateFlushes = 0.100; + if (!lastImmediateFlushTime) + return false; + return lastImmediateFlushTime + maxDurationOfImmediateFlushes < current; +} - uint64_t windowHandle = m_webPage->nativeWindowHandle(); - if (!windowHandle) - return 0; +void LayerTreeHostGtk::RenderFrameScheduler::nextFrame() +{ + static const double targetFramerate = 1 / 60.0; + // When rendering layers takes more time than the target delay (0.016), we end up scheduling layer flushes + // immediately. Since the layer flush timer has a higher priority than WebCore timers, these are never + // fired while we keep scheduling layer flushes immediately. + double current = monotonicallyIncreasingTime(); + double timeToNextFlush = std::max(targetFramerate - (current - m_fireTime), 0.0); + if (timeToNextFlush) + m_lastImmediateFlushTime = 0; + else if (!m_lastImmediateFlushTime) + m_lastImmediateFlushTime = current; + + if (shouldSkipNextFrameBecauseOfContinousImmediateFlushes(current, m_lastImmediateFlushTime)) { + timeToNextFlush = targetFramerate; + m_lastImmediateFlushTime = 0; + } + + m_timer.startOneShot(timeToNextFlush); +} + +void LayerTreeHostGtk::RenderFrameScheduler::renderFrame() +{ + m_fireTime = monotonicallyIncreasingTime(); + if (!m_renderer() || m_timer.isActive()) + return; + nextFrame(); +} - m_context = GLContext::createContextForWindow(windowHandle, GLContext::sharingContext()); - return m_context.get(); +Ref<LayerTreeHostGtk> LayerTreeHostGtk::create(WebPage& webPage) +{ + return adoptRef(*new LayerTreeHostGtk(webPage)); } -void LayerTreeHostGtk::initialize() +LayerTreeHostGtk::LayerTreeHostGtk(WebPage& webPage) + : LayerTreeHost(webPage) + , m_surface(AcceleratedSurface::create(webPage)) + , m_renderFrameScheduler(std::bind(&LayerTreeHostGtk::renderFrame, this)) { - m_rootLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + m_rootLayer = GraphicsLayer::create(graphicsLayerFactory(), *this); m_rootLayer->setDrawsContent(false); - m_rootLayer->setSize(m_webPage->size()); + m_rootLayer->setSize(m_webPage.size()); + + m_scaleMatrix.makeIdentity(); + m_scaleMatrix.scale(m_webPage.deviceScaleFactor() * m_webPage.pageScaleFactor()); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setAnchorPoint(FloatPoint3D()); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setTransform(m_scaleMatrix); // The non-composited contents are a child of the root layer. - m_nonCompositedContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this); + m_nonCompositedContentLayer = GraphicsLayer::create(graphicsLayerFactory(), *this); m_nonCompositedContentLayer->setDrawsContent(true); - m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground()); - m_nonCompositedContentLayer->setSize(m_webPage->size()); - if (m_webPage->corePage()->settings().acceleratedDrawingEnabled()) + m_nonCompositedContentLayer->setContentsOpaque(m_webPage.drawsBackground()); + m_nonCompositedContentLayer->setSize(m_webPage.size()); + if (m_webPage.corePage()->settings().acceleratedDrawingEnabled()) m_nonCompositedContentLayer->setAcceleratesDrawing(true); #ifndef NDEBUG @@ -113,46 +154,45 @@ void LayerTreeHostGtk::initialize() m_rootLayer->addChild(m_nonCompositedContentLayer.get()); m_nonCompositedContentLayer->setNeedsDisplay(); - m_layerTreeContext.windowHandle = m_webPage->nativeWindowHandle(); + if (m_surface) { + createTextureMapper(); + m_layerTreeContext.contextID = m_surface->surfaceID(); + } +} + +bool LayerTreeHostGtk::makeContextCurrent() +{ + uint64_t nativeHandle = m_surface ? m_surface->window() : m_layerTreeContext.contextID; + if (!nativeHandle) { + m_context = nullptr; + return false; + } - GLContext* context = glContext(); - if (!context) - return; + if (m_context) + return m_context->makeContextCurrent(); - // The creation of the TextureMapper needs an active OpenGL context. - context->makeContextCurrent(); + m_context = GLContext::createContextForWindow(reinterpret_cast<GLNativeWindowType>(nativeHandle), &PlatformDisplay::sharedDisplayForCompositing()); + if (!m_context) + return false; - m_textureMapper = TextureMapperGL::create(); - static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true); - toTextureMapperLayer(m_rootLayer.get())->setTextureMapper(m_textureMapper.get()); + if (!m_context->makeContextCurrent()) + return false; - if (m_webPage->hasPageOverlay()) { - PageOverlayList& pageOverlays = m_webPage->pageOverlays(); - PageOverlayList::iterator end = pageOverlays.end(); - for (PageOverlayList::iterator it = pageOverlays.begin(); it != end; ++it) - createPageOverlayLayer(it->get()); - } + // Do not do frame sync when rendering offscreen in the web process to ensure that SwapBuffers never blocks. + // Rendering to the actual screen will happen later anyway since the UI process schedules a redraw for every update, + // the compositor will take care of syncing to vblank. + if (m_surface) + m_context->swapInterval(0); - scheduleLayerFlush(); + return true; } LayerTreeHostGtk::~LayerTreeHostGtk() { - ASSERT(!m_isValid); ASSERT(!m_rootLayer); cancelPendingLayerFlush(); } -const LayerTreeContext& LayerTreeHostGtk::layerTreeContext() -{ - return m_layerTreeContext; -} - -void LayerTreeHostGtk::setShouldNotifyAfterNextScheduledLayerFlush(bool notifyAfterScheduledLayerFlush) -{ - m_notifyAfterScheduledLayerFlush = notifyAfterScheduledLayerFlush; -} - void LayerTreeHostGtk::setRootCompositingLayer(GraphicsLayer* graphicsLayer) { m_nonCompositedContentLayer->removeAllChildren(); @@ -166,7 +206,10 @@ void LayerTreeHostGtk::setRootCompositingLayer(GraphicsLayer* graphicsLayer) void LayerTreeHostGtk::invalidate() { - ASSERT(m_isValid); + // This can trigger destruction of GL objects so let's make sure that + // we have the right active context + if (m_context) + m_context->makeContextCurrent(); cancelPendingLayerFlush(); m_rootLayer = nullptr; @@ -174,28 +217,20 @@ void LayerTreeHostGtk::invalidate() m_textureMapper = nullptr; m_context = nullptr; - m_isValid = false; + LayerTreeHost::invalidate(); + + m_surface = nullptr; } void LayerTreeHostGtk::setNonCompositedContentsNeedDisplay() { m_nonCompositedContentLayer->setNeedsDisplay(); - - PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); - for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) - it->value->setNeedsDisplay(); - scheduleLayerFlush(); } void LayerTreeHostGtk::setNonCompositedContentsNeedDisplayInRect(const IntRect& rect) { m_nonCompositedContentLayer->setNeedsDisplayInRect(rect); - - PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); - for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) - it->value->setNeedsDisplayInRect(rect); - scheduleLayerFlush(); } @@ -224,88 +259,50 @@ void LayerTreeHostGtk::sizeDidChange(const IntSize& newSize) m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height())); m_nonCompositedContentLayer->setNeedsDisplay(); - PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); - for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) - it->value->setSize(newSize); + if (m_surface && m_surface->resize(newSize)) + m_layerTreeContext.contextID = m_surface->surfaceID(); compositeLayersToContext(ForResize); } void LayerTreeHostGtk::deviceOrPageScaleFactorChanged() { + if (m_surface && m_surface->resize(m_webPage.size())) + m_layerTreeContext.contextID = m_surface->surfaceID(); + // Other layers learn of the scale factor change via WebPage::setDeviceScaleFactor. m_nonCompositedContentLayer->deviceOrPageScaleFactorChanged(); -} -void LayerTreeHostGtk::forceRepaint() -{ - scheduleLayerFlush(); + m_scaleMatrix.makeIdentity(); + m_scaleMatrix.scale(m_webPage.deviceScaleFactor() * m_webPage.pageScaleFactor()); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setTransform(m_scaleMatrix); } -void LayerTreeHostGtk::didInstallPageOverlay(PageOverlay* pageOverlay) -{ - createPageOverlayLayer(pageOverlay); - scheduleLayerFlush(); -} - -void LayerTreeHostGtk::didUninstallPageOverlay(PageOverlay* pageOverlay) -{ - destroyPageOverlayLayer(pageOverlay); - scheduleLayerFlush(); -} - -void LayerTreeHostGtk::setPageOverlayNeedsDisplay(PageOverlay* pageOverlay, const IntRect& rect) +void LayerTreeHostGtk::forceRepaint() { - GraphicsLayer* layer = m_pageOverlayLayers.get(pageOverlay); - if (!layer) - return; - - layer->setNeedsDisplayInRect(rect); scheduleLayerFlush(); } -void LayerTreeHostGtk::notifyAnimationStarted(const WebCore::GraphicsLayer*, double time) +void LayerTreeHostGtk::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect) { + if (graphicsLayer == m_nonCompositedContentLayer.get()) + m_webPage.drawRect(graphicsContext, enclosingIntRect(clipRect)); } -void LayerTreeHostGtk::notifyFlushRequired(const WebCore::GraphicsLayer*) +float LayerTreeHostGtk::deviceScaleFactor() const { + return m_webPage.deviceScaleFactor(); } -void LayerTreeHostGtk::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const IntRect& clipRect) -{ - if (graphicsLayer == m_nonCompositedContentLayer.get()) { - m_webPage->drawRect(graphicsContext, clipRect); - return; - } - - for (auto& pageOverlayLayer : m_pageOverlayLayers) { - if (pageOverlayLayer.value.get() == graphicsLayer) { - m_webPage->drawPageOverlay(pageOverlayLayer.key, graphicsContext, clipRect); - break; - } - } -} - -gboolean LayerTreeHostGtk::layerFlushTimerFiredCallback(LayerTreeHostGtk* layerTreeHost) +float LayerTreeHostGtk::pageScaleFactor() const { - layerTreeHost->layerFlushTimerFired(); - return FALSE; + return m_webPage.pageScaleFactor(); } -void LayerTreeHostGtk::layerFlushTimerFired() +bool LayerTreeHostGtk::renderFrame() { - ASSERT(m_layerFlushTimerCallbackId); - m_layerFlushTimerCallbackId = 0; - flushAndRenderLayers(); - - if (toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations() && !m_layerFlushTimerCallbackId) { - const double targetFPS = 60; - double nextFlush = std::max((1 / targetFPS) - (currentTime() - m_lastFlushTime), 0.0); - m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, nextFlush * 1000.0, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0); - g_source_set_name_by_id(m_layerFlushTimerCallbackId, "[WebKit] layerFlushTimerFiredCallback"); - } + return downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().descendantsOrSelfHaveRunningAnimations(); } bool LayerTreeHostGtk::flushPendingLayerChanges() @@ -313,17 +310,19 @@ bool LayerTreeHostGtk::flushPendingLayerChanges() m_rootLayer->flushCompositingStateForThisLayerOnly(); m_nonCompositedContentLayer->flushCompositingStateForThisLayerOnly(); - PageOverlayLayerMap::iterator end = m_pageOverlayLayers.end(); - for (PageOverlayLayerMap::iterator it = m_pageOverlayLayers.begin(); it != end; ++it) - it->value->flushCompositingStateForThisLayerOnly(); + if (!m_webPage.corePage()->mainFrame().view()->flushCompositingStateIncludingSubframes()) + return false; + + if (m_viewOverlayRootLayer) + m_viewOverlayRootLayer->flushCompositingState(FloatRect(FloatPoint(), m_rootLayer->size())); - return m_webPage->corePage()->mainFrame().view()->flushCompositingStateIncludingSubframes(); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).updateBackingStoreIncludingSubLayers(); + return true; } void LayerTreeHostGtk::compositeLayersToContext(CompositePurpose purpose) { - GLContext* context = glContext(); - if (!context || !context->makeContextCurrent()) + if (!makeContextCurrent()) return; // The window size may be out of sync with the page size at this point, and getting @@ -331,34 +330,38 @@ void LayerTreeHostGtk::compositeLayersToContext(CompositePurpose purpose) // we set the viewport parameters directly from the window size. IntSize contextSize = m_context->defaultFrameBufferSize(); glViewport(0, 0, contextSize.width(), contextSize.height()); - - if (purpose == ForResize) { - glClearColor(1, 1, 1, 0); + if (purpose == ForResize || !m_webPage.drawsBackground()) { + glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } - m_textureMapper->beginPainting(); - toTextureMapperLayer(m_rootLayer.get())->paint(); + ASSERT(m_textureMapper); + + TextureMapper::PaintFlags paintFlags = 0; + + if (m_surface && m_surface->shouldPaintMirrored()) + paintFlags |= TextureMapper::PaintingMirrored; + + m_textureMapper->beginPainting(paintFlags); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().paint(); m_textureMapper->endPainting(); - context->swapBuffers(); + m_context->swapBuffers(); } void LayerTreeHostGtk::flushAndRenderLayers() { { RefPtr<LayerTreeHostGtk> protect(this); - m_webPage->layoutIfNeeded(); + m_webPage.layoutIfNeeded(); if (!m_isValid) return; } - GLContext* context = glContext(); - if (!context || !context->makeContextCurrent()) + if (!makeContextCurrent()) return; - m_lastFlushTime = currentTime(); if (!flushPendingLayerChanges()) return; @@ -367,76 +370,59 @@ void LayerTreeHostGtk::flushAndRenderLayers() if (m_notifyAfterScheduledLayerFlush) { // Let the drawing area know that we've done a flush of the layer changes. - static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->layerHostDidFlushLayers(); + m_webPage.drawingArea()->layerHostDidFlushLayers(); m_notifyAfterScheduledLayerFlush = false; } } -void LayerTreeHostGtk::createPageOverlayLayer(PageOverlay* pageOverlay) +void LayerTreeHostGtk::scheduleLayerFlush() { - std::unique_ptr<GraphicsLayer> layer = GraphicsLayer::create(graphicsLayerFactory(), this); -#ifndef NDEBUG - layer->setName("LayerTreeHost page overlay content"); -#endif - - layer->setAcceleratesDrawing(m_webPage->corePage()->settings().acceleratedDrawingEnabled()); - layer->setDrawsContent(true); - layer->setSize(m_webPage->size()); - layer->setShowDebugBorder(m_webPage->corePage()->settings().showDebugBorders()); - layer->setShowRepaintCounter(m_webPage->corePage()->settings().showRepaintCounter()); + if (!m_layerFlushSchedulingEnabled || !m_textureMapper) + return; - m_rootLayer->addChild(layer.get()); - m_pageOverlayLayers.add(pageOverlay, std::move(layer)); + m_renderFrameScheduler.start(); } -void LayerTreeHostGtk::destroyPageOverlayLayer(PageOverlay* pageOverlay) +void LayerTreeHostGtk::pageBackgroundTransparencyChanged() { - std::unique_ptr<GraphicsLayer> layer = m_pageOverlayLayers.take(pageOverlay); - ASSERT(layer); - - layer->removeFromParent(); + m_nonCompositedContentLayer->setContentsOpaque(m_webPage.drawsBackground()); } -void LayerTreeHostGtk::scheduleLayerFlush() +void LayerTreeHostGtk::cancelPendingLayerFlush() { - if (!m_layerFlushSchedulingEnabled) - return; - - // We use a GLib timer because otherwise GTK+ event handling during dragging can starve WebCore timers, which have a lower priority. - if (!m_layerFlushTimerCallbackId) { - m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 0, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0); - g_source_set_name_by_id(m_layerFlushTimerCallbackId, "[WebKit] layerFlushTimerFiredCallback"); - } + m_renderFrameScheduler.stop(); } -void LayerTreeHostGtk::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled) +void LayerTreeHostGtk::setViewOverlayRootLayer(GraphicsLayer* viewOverlayRootLayer) { - if (m_layerFlushSchedulingEnabled == layerFlushingEnabled) - return; - - m_layerFlushSchedulingEnabled = layerFlushingEnabled; - - if (m_layerFlushSchedulingEnabled) { - scheduleLayerFlush(); - return; - } - - cancelPendingLayerFlush(); + LayerTreeHost::setViewOverlayRootLayer(viewOverlayRootLayer); + if (m_viewOverlayRootLayer) + m_rootLayer->addChild(m_viewOverlayRootLayer); } -void LayerTreeHostGtk::pageBackgroundTransparencyChanged() +void LayerTreeHostGtk::createTextureMapper() { - m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground()); + // The creation of the TextureMapper needs an active OpenGL context. + if (!makeContextCurrent()) + return; + + ASSERT(m_isValid); + ASSERT(!m_textureMapper); + m_textureMapper = TextureMapper::create(); + static_cast<TextureMapperGL*>(m_textureMapper.get())->setEnableEdgeDistanceAntialiasing(true); + downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer().setTextureMapper(m_textureMapper.get()); } -void LayerTreeHostGtk::cancelPendingLayerFlush() +#if PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) +void LayerTreeHostGtk::setNativeSurfaceHandleForCompositing(uint64_t handle) { - if (!m_layerFlushTimerCallbackId) - return; + cancelPendingLayerFlush(); + m_layerTreeContext.contextID = handle; - g_source_remove(m_layerFlushTimerCallbackId); - m_layerFlushTimerCallbackId = 0; + createTextureMapper(); + scheduleLayerFlush(); } +#endif } // namespace WebKit |