summaryrefslogtreecommitdiff
path: root/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp372
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