Add initial implementation of ThreadSafeCoordinatedSurface, ThreadedCompositor, and...
authoryoon@igalia.com <yoon@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Dec 2014 10:39:49 +0000 (10:39 +0000)
committeryoon@igalia.com <yoon@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Dec 2014 10:39:49 +0000 (10:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=118383

Reviewed by Martin Robinson.

Implements an initial version of the Threaded Compositor.

Threaded Compositor is a variant of Coordinated Graphics implementation.
Basic structure of the implementaion is simliar, thus, Threaded
Compositor reuses lots of classes from Coordinated Graphics. However,
instead of compositing on UI Process, Threaded Compositor performs
compositing on a dedicate thread of Web Process.

No new test, because it is in experimental stage.

* Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
(WebKit::CoordinatedGraphicsScene::CoordinatedGraphicsScene):
Removed a assertion not to force its creation in the main thread. In
the Threaded Compositor, it can be created in the dedicated thread.

* Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp: Added.
* Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h: Added.
Implements a surface using ImageBuffer as a backend to use in the Web
Process.

* Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h: Added.
* Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp: Added.
Implements a compositor which runs on the created thread. It owns
SimpleViewportController and CoordinatedGraphicsScene to render scene on the
actual surface.

* Shared/CoordinatedGraphics/SimpleViewportController.cpp: Added.
* Shared/CoordinatedGraphics/SimpleViewportController.h: Added.
This class is responsible to handle scale factor and scrolling position
with a simplifed logic in the compositing thread.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@177276 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp
Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h [new file with mode: 0644]

index 05a7a08..add3a32 100644 (file)
@@ -1,3 +1,41 @@
+2014-12-15  Gwang Yoon Hwang  <yoon@igalia.com>
+
+        Add initial implementation of ThreadSafeCoordinatedSurface, ThreadedCompositor, and SimpleViewportController
+        https://bugs.webkit.org/show_bug.cgi?id=118383
+
+        Reviewed by Martin Robinson.
+
+        Implements an initial version of the Threaded Compositor.
+
+        Threaded Compositor is a variant of Coordinated Graphics implementation.
+        Basic structure of the implementaion is simliar, thus, Threaded
+        Compositor reuses lots of classes from Coordinated Graphics. However,
+        instead of compositing on UI Process, Threaded Compositor performs
+        compositing on a dedicate thread of Web Process.
+
+        No new test, because it is in experimental stage.
+
+        * Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
+        (WebKit::CoordinatedGraphicsScene::CoordinatedGraphicsScene):
+        Removed a assertion not to force its creation in the main thread. In
+        the Threaded Compositor, it can be created in the dedicated thread.
+
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp: Added.
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h: Added.
+        Implements a surface using ImageBuffer as a backend to use in the Web
+        Process.
+
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h: Added.
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp: Added.
+        Implements a compositor which runs on the created thread. It owns
+        SimpleViewportController and CoordinatedGraphicsScene to render scene on the
+        actual surface.
+
+        * Shared/CoordinatedGraphics/SimpleViewportController.cpp: Added.
+        * Shared/CoordinatedGraphics/SimpleViewportController.h: Added.
+        This class is responsible to handle scale factor and scrolling position
+        with a simplifed logic in the compositing thread.
+
 2014-12-14  Andreas Kling  <akling@apple.com>
 
         Replace PassRef with Ref/Ref&& across the board.
index 399ef68..9473d46 100644 (file)
@@ -54,7 +54,6 @@ CoordinatedGraphicsScene::CoordinatedGraphicsScene(CoordinatedGraphicsSceneClien
     , m_rootLayerID(InvalidCoordinatedLayerID)
     , m_viewBackgroundColor(Color::white)
 {
-    ASSERT(isMainThread());
 }
 
 CoordinatedGraphicsScene::~CoordinatedGraphicsScene()
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.cpp
new file mode 100644 (file)
index 0000000..11b55be
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org>
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if USE(COORDINATED_GRAPHICS_THREADED)
+#include "SimpleViewportController.h"
+
+using namespace WebCore;
+
+namespace WebKit {
+
+SimpleViewportController::SimpleViewportController(Client* client)
+    : m_client(client)
+    , m_contentsPosition(FloatPoint())
+    , m_contentsSize(FloatSize())
+    , m_viewportSize(FloatSize())
+    , m_allowsUserScaling(false)
+    , m_initiallyFitToViewport(true)
+    , m_hasViewportAttribute(false)
+{
+    resetViewportToDefaultState();
+}
+
+void SimpleViewportController::didChangeViewportSize(const FloatSize& newSize)
+{
+    if (newSize.isEmpty())
+        return;
+
+    m_viewportSize = newSize;
+    updateMinimumScaleToFit();
+    syncVisibleContents();
+}
+
+void SimpleViewportController::didChangeContentsSize(const IntSize& newSize)
+{
+    m_contentsSize = newSize;
+
+    updateMinimumScaleToFit();
+
+    if (m_initiallyFitToViewport) {
+        // Restrict scale factors to m_minimumScaleToFit.
+        ASSERT(m_minimumScaleToFit > 0);
+        m_rawAttributes.initialScale = m_minimumScaleToFit;
+        restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes);
+    }
+
+    syncVisibleContents();
+}
+
+void SimpleViewportController::didChangeViewportAttribute(const ViewportAttributes& newAttributes)
+{
+    if (newAttributes.layoutSize.isEmpty()) {
+        resetViewportToDefaultState();
+        return;
+    }
+
+    m_hasViewportAttribute = true;
+
+    m_rawAttributes = newAttributes;
+    m_allowsUserScaling = m_rawAttributes.userScalable;
+    m_initiallyFitToViewport = m_rawAttributes.initialScale < 0;
+
+    if (!m_initiallyFitToViewport)
+        restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes);
+
+    updateMinimumScaleToFit();
+
+    syncVisibleContents();
+}
+
+void SimpleViewportController::scrollBy(const IntSize& scrollOffset)
+{
+    m_contentsPosition.move(scrollOffset);
+    m_contentsPosition = boundContentsPosition(m_contentsPosition);
+
+    syncVisibleContents();
+}
+
+void SimpleViewportController::scrollTo(const IntPoint& position)
+{
+    if (m_contentsPosition == boundContentsPosition(position))
+        return;
+
+    m_contentsPosition = boundContentsPosition(position);
+    syncVisibleContents();
+}
+
+void SimpleViewportController::syncVisibleContents()
+{
+    if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty())
+        return;
+
+    m_client->didChangeVisibleRect();
+}
+
+FloatRect SimpleViewportController::visibleContentsRect() const
+{
+    FloatRect visibleContentsRect(boundContentsPosition(m_contentsPosition), visibleContentsSize());
+    visibleContentsRect.intersect(FloatRect(FloatPoint::zero(), m_contentsSize));
+
+    return visibleContentsRect;
+}
+
+FloatSize SimpleViewportController::visibleContentsSize() const
+{
+    return FloatSize(m_viewportSize.width() / m_pageScaleFactor, m_viewportSize.height() / m_pageScaleFactor);
+}
+
+FloatPoint SimpleViewportController::boundContentsPositionAtScale(const FloatPoint& framePosition, float scale) const
+{
+    // We need to floor the viewport here as to allow aligning the content in device units. If not,
+    // it might not be possible to scroll the last pixel and that affects fixed position elements.
+    return FloatPoint(
+        clampTo(framePosition.x(), .0f, std::max(.0f, m_contentsSize.width() - floorf(m_viewportSize.width() / scale))),
+        clampTo(framePosition.y(), .0f, std::max(.0f, m_contentsSize.height() - floorf(m_viewportSize.height() / scale))));
+}
+
+FloatPoint SimpleViewportController::boundContentsPosition(const FloatPoint& framePosition) const
+{
+    return boundContentsPositionAtScale(framePosition, m_pageScaleFactor);
+}
+
+bool fuzzyCompare(float a, float b, float epsilon)
+{
+    return std::abs(a - b) < epsilon;
+}
+
+bool SimpleViewportController::updateMinimumScaleToFit()
+{
+    if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty() || !m_hasViewportAttribute)
+        return false;
+
+    bool currentlyScaledToFit = fuzzyCompare(m_pageScaleFactor, m_minimumScaleToFit, 0.0001);
+
+    float minimumScale = computeMinimumScaleFactorForContentContained(m_rawAttributes, roundedIntSize(m_viewportSize), roundedIntSize(m_contentsSize));
+
+    if (minimumScale <= 0)
+        return false;
+
+    if (!fuzzyCompare(minimumScale, m_minimumScaleToFit, 0.0001)) {
+        m_minimumScaleToFit = minimumScale;
+
+        if (currentlyScaledToFit)
+            m_pageScaleFactor = m_minimumScaleToFit;
+        else {
+            // Ensure the effective scale stays within bounds.
+            float boundedScale = innerBoundedViewportScale(m_pageScaleFactor);
+            if (!fuzzyCompare(boundedScale, m_pageScaleFactor, 0.0001))
+                m_pageScaleFactor = boundedScale;
+        }
+
+        return true;
+    }
+    return false;
+}
+
+float SimpleViewportController::innerBoundedViewportScale(float viewportScale) const
+{
+    return clampTo(viewportScale, m_minimumScaleToFit, m_rawAttributes.maximumScale);
+}
+
+void SimpleViewportController::resetViewportToDefaultState()
+{
+    m_hasViewportAttribute = false;
+    m_pageScaleFactor = 1;
+    m_minimumScaleToFit = 1;
+
+    // Initializing Viewport Raw Attributes to avoid random negative or infinity scale factors
+    // if there is a race condition between the first layout and setting the viewport attributes for the first time.
+    m_rawAttributes.minimumScale = 1;
+    m_rawAttributes.maximumScale = 1;
+    m_rawAttributes.userScalable = m_allowsUserScaling;
+
+    // The initial scale might be implicit and set to -1, in this case we have to infer it
+    // using the viewport size and the final layout size.
+    // To be able to assert for valid scale we initialize it to -1.
+    m_rawAttributes.initialScale = -1;
+}
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS_THREADED)
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h b/Source/WebKit2/Shared/CoordinatedGraphics/SimpleViewportController.h
new file mode 100644 (file)
index 0000000..c2ed49f
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org>
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SimpleViewportController_h
+#define SimpleViewportController_h
+
+#if USE(COORDINATED_GRAPHICS_THREADED)
+
+#include <WebCore/FloatPoint.h>
+#include <WebCore/FloatRect.h>
+#include <WebCore/FloatSize.h>
+#include <WebCore/IntRect.h>
+#include <WebCore/IntSize.h>
+#include <WebCore/ViewportArguments.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class SimpleViewportController {
+    WTF_MAKE_NONCOPYABLE(SimpleViewportController);
+public:
+    class Client {
+    public:
+        virtual void didChangeVisibleRect() = 0;
+    };
+
+    explicit SimpleViewportController(Client*);
+
+    void didChangeViewportSize(const WebCore::FloatSize&);
+    void didChangeContentsSize(const WebCore::IntSize&);
+    void didChangeViewportAttribute(const WebCore::ViewportAttributes&);
+
+    void scrollBy(const WebCore::IntSize&);
+    void scrollTo(const WebCore::IntPoint&);
+
+    WebCore::FloatRect visibleContentsRect() const;
+    float pageScaleFactor() const { return m_pageScaleFactor; }
+
+private:
+
+    WebCore::FloatSize visibleContentsSize() const;
+
+    void syncVisibleContents();
+
+    void applyScaleAfterRenderingContents(float scale);
+    void applyPositionAfterRenderingContents(const WebCore::FloatPoint& pos);
+
+    WebCore::FloatPoint boundContentsPosition(const WebCore::FloatPoint&) const;
+    WebCore::FloatPoint boundContentsPositionAtScale(const WebCore::FloatPoint&, float scale) const;
+
+    bool updateMinimumScaleToFit();
+    float innerBoundedViewportScale(float) const;
+
+    void resetViewportToDefaultState();
+
+    Client* m_client;
+
+    WebCore::FloatPoint m_contentsPosition;
+    WebCore::FloatSize m_contentsSize;
+    WebCore::FloatSize m_viewportSize;
+    float m_pageScaleFactor;
+
+    bool m_allowsUserScaling;
+    float m_minimumScaleToFit;
+    bool m_initiallyFitToViewport;
+
+    bool m_hasViewportAttribute;
+    WebCore::ViewportAttributes m_rawAttributes;
+};
+
+} // namespace WebKit
+
+#endif // USE(COORDINATED_GRAPHICS_THREADED)
+
+#endif // SimpleViewportController_h
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp
new file mode 100644 (file)
index 0000000..c703467
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(COORDINATED_GRAPHICS)
+#include "ThreadSafeCoordinatedSurface.h"
+
+#include <WebCore/TextureMapperGL.h>
+#include <wtf/StdLibExtras.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+PassRefPtr<ThreadSafeCoordinatedSurface> ThreadSafeCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags)
+{
+    return adoptRef(new ThreadSafeCoordinatedSurface(size, flags, ImageBuffer::create(size)));
+}
+
+PassRefPtr<ThreadSafeCoordinatedSurface> ThreadSafeCoordinatedSurface::create(const IntSize& size, CoordinatedSurface::Flags flags, std::unique_ptr<ImageBuffer> buffer)
+{
+    return adoptRef(new ThreadSafeCoordinatedSurface(size, flags, WTF::move(buffer)));
+}
+
+ThreadSafeCoordinatedSurface::ThreadSafeCoordinatedSurface(const IntSize& size, CoordinatedSurface::Flags flags, std::unique_ptr<ImageBuffer> buffer)
+    : CoordinatedSurface(size, flags)
+    , m_imageBuffer(WTF::move(buffer))
+{
+}
+
+ThreadSafeCoordinatedSurface::~ThreadSafeCoordinatedSurface()
+{
+}
+
+void ThreadSafeCoordinatedSurface::paintToSurface(const IntRect& rect, CoordinatedSurface::Client* client)
+{
+    ASSERT(client);
+
+    GraphicsContext* context = beginPaint(rect);
+    client->paintToSurfaceContext(context);
+    endPaint();
+}
+
+GraphicsContext* ThreadSafeCoordinatedSurface::beginPaint(const IntRect& rect)
+{
+    ASSERT(m_imageBuffer);
+    GraphicsContext* graphicsContext = m_imageBuffer->context();
+    graphicsContext->save();
+    graphicsContext->clip(rect);
+    graphicsContext->translate(rect.x(), rect.y());
+    return graphicsContext;
+}
+
+void ThreadSafeCoordinatedSurface::endPaint()
+{
+    ASSERT(m_imageBuffer);
+    m_imageBuffer->context()->restore();
+}
+
+void ThreadSafeCoordinatedSurface::copyToTexture(PassRefPtr<BitmapTexture> passTexture, const IntRect& target, const IntPoint& sourceOffset)
+{
+    RefPtr<BitmapTexture> texture(passTexture);
+
+    ASSERT(m_imageBuffer);
+    RefPtr<Image> image = m_imageBuffer->copyImage(DontCopyBackingStore);
+    texture->updateContents(image.get(), target, sourceOffset, BitmapTexture::UpdateCanModifyOriginalImageData);
+}
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS)
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.h
new file mode 100644 (file)
index 0000000..7e3277f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThreadSafeCoordinatedSurface_h
+#define ThreadSafeCoordinatedSurface_h
+
+#if USE(COORDINATED_GRAPHICS)
+#include <WebCore/CoordinatedSurface.h>
+#include <WebCore/ImageBuffer.h>
+
+namespace WebKit {
+
+class ThreadSafeCoordinatedSurface : public WebCore::CoordinatedSurface {
+public:
+    virtual ~ThreadSafeCoordinatedSurface();
+
+    // Create a new ThreadSafeCoordinatedSurface and allocate either a GraphicsSurface or a ImageBuffer as backing.
+    static PassRefPtr<ThreadSafeCoordinatedSurface> create(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags);
+
+    virtual void paintToSurface(const WebCore::IntRect&, WebCore::CoordinatedSurface::Client*) override;
+    virtual void copyToTexture(PassRefPtr<WebCore::BitmapTexture>, const WebCore::IntRect& target, const WebCore::IntPoint& sourceOffset) override;
+
+private:
+    ThreadSafeCoordinatedSurface(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags, std::unique_ptr<WebCore::ImageBuffer>);
+
+    WebCore::GraphicsContext* beginPaint(const WebCore::IntRect&);
+    void endPaint();
+
+    // Create a ThreadSafeCoordinatedSurface referencing an exisiting ImageBuffer
+    static PassRefPtr<ThreadSafeCoordinatedSurface> create(const WebCore::IntSize&, WebCore::CoordinatedSurface::Flags, std::unique_ptr<WebCore::ImageBuffer>);
+
+    std::unique_ptr<WebCore::ImageBuffer> m_imageBuffer;
+};
+
+} // namespace WebKit
+
+#endif // USE(COORDINATED_GRAPHICS)
+
+#endif // ThreadSafeCoordinatedSurface_h
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp
new file mode 100644 (file)
index 0000000..2802f0d
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(COORDINATED_GRAPHICS_THREADED)
+#include "ThreadedCompositor.h"
+
+#include <WebCore/TransformationMatrix.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/RunLoop.h>
+#include <wtf/StdLibExtras.h>
+
+#if USE(OPENGL_ES_2)
+#include <GLES2/gl2.h>
+#else
+#include <GL/gl.h>
+#endif
+
+using namespace WebCore;
+
+namespace WebKit {
+
+class CompositingRunLoop {
+    WTF_MAKE_NONCOPYABLE(CompositingRunLoop);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    CompositingRunLoop(std::function<void()> updateFunction)
+        : m_runLoop(RunLoop::current())
+        , m_updateTimer(m_runLoop, this, &CompositingRunLoop::updateTimerFired)
+        , m_updateFunction(WTF::move(updateFunction))
+    {
+    }
+
+    void callOnCompositingRunLoop(std::function<void()> function)
+    {
+        if (&m_runLoop == &RunLoop::current()) {
+            function();
+            return;
+        }
+
+        m_runLoop.dispatch(WTF::move(function));
+    }
+
+    void setUpdateTimer(double interval = 0)
+    {
+        if (m_updateTimer.isActive())
+            return;
+
+        m_updateTimer.startOneShot(interval);
+    }
+
+    void stopUpdateTimer()
+    {
+        if (m_updateTimer.isActive())
+            m_updateTimer.stop();
+    }
+
+    RunLoop& runLoop()
+    {
+        return m_runLoop;
+    }
+
+private:
+
+    void updateTimerFired()
+    {
+        m_updateFunction();
+    }
+
+    RunLoop& m_runLoop;
+    RunLoop::Timer<CompositingRunLoop> m_updateTimer;
+    std::function<void()> m_updateFunction;
+};
+
+PassRefPtr<ThreadedCompositor> ThreadedCompositor::create(Client* client)
+{
+    return adoptRef(new ThreadedCompositor(client));
+}
+
+ThreadedCompositor::ThreadedCompositor(Client* client)
+    : m_client(client)
+    , m_scene(adoptRef(new CoordinatedGraphicsScene(this)))
+    , m_viewportController(std::make_unique<SimpleViewportController>(this))
+    , m_threadIdentifier(0)
+{
+    createCompositingThread();
+}
+
+ThreadedCompositor::~ThreadedCompositor()
+{
+    terminateCompositingThread();
+}
+
+void ThreadedCompositor::setNeedsDisplay()
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->scheduleDisplayIfNeeded();
+    });
+}
+
+void ThreadedCompositor::setNativeSurfaceHandleForCompositing(uint64_t handle)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->m_nativeSurfaceHandle = handle;
+        protector->m_scene->setActive(true);
+    });
+}
+
+
+void ThreadedCompositor::didChangeViewportSize(const IntSize& newSize)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->viewportController()->didChangeViewportSize(newSize);
+    });
+}
+
+void ThreadedCompositor::didChangeViewportAttribute(const ViewportAttributes& attr)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->viewportController()->didChangeViewportAttribute(attr);
+    });
+}
+
+void ThreadedCompositor::didChangeContentsSize(const IntSize& size)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->viewportController()->didChangeContentsSize(size);
+    });
+}
+
+void ThreadedCompositor::scrollTo(const IntPoint& position)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->viewportController()->scrollTo(position);
+    });
+}
+
+void ThreadedCompositor::scrollBy(const IntSize& delta)
+{
+    RefPtr<ThreadedCompositor> protector(this);
+    callOnCompositingThread([=] {
+        protector->viewportController()->scrollBy(delta);
+    });
+}
+
+void ThreadedCompositor::purgeBackingStores()
+{
+    m_client->purgeBackingStores();
+}
+
+void ThreadedCompositor::renderNextFrame()
+{
+    m_client->renderNextFrame();
+}
+
+void ThreadedCompositor::updateViewport()
+{
+    setNeedsDisplay();
+}
+
+void ThreadedCompositor::commitScrollOffset(uint32_t layerID, const IntSize& offset)
+{
+    m_client->commitScrollOffset(layerID, offset);
+}
+
+bool ThreadedCompositor::ensureGLContext()
+{
+    if (!glContext())
+        return false;
+
+    glContext()->makeContextCurrent();
+    // The window size may be out of sync with the page size at this point, and getting
+    // the viewport parameters incorrect, means that the content will be misplaced. Thus
+    // we set the viewport parameters directly from the window size.
+    IntSize contextSize = glContext()->defaultFrameBufferSize();
+    if (m_viewportSize != contextSize) {
+        glViewport(0, 0, contextSize.width(), contextSize.height());
+        m_viewportSize = contextSize;
+    }
+
+    return true;
+}
+
+GLContext* ThreadedCompositor::glContext()
+{
+    if (m_context)
+        return m_context.get();
+
+    if (!m_nativeSurfaceHandle)
+        return 0;
+
+    m_context = GLContext::createContextForWindow(m_nativeSurfaceHandle, GLContext::sharingContext());
+    return m_context.get();
+}
+
+void ThreadedCompositor::scheduleDisplayIfNeeded(double interval)
+{
+    m_compositingRunLoop->setUpdateTimer(interval);
+}
+
+void ThreadedCompositor::didChangeVisibleRect()
+{
+    FloatRect visibleRect = viewportController()->visibleContentsRect();
+    float scale = viewportController()->pageScaleFactor();
+    callOnMainThread([=] {
+        m_client->setVisibleContentsRect(visibleRect, FloatPoint::zero(), scale);
+    });
+
+    setNeedsDisplay();
+}
+
+void ThreadedCompositor::renderLayerTree()
+{
+    if (!m_scene)
+        return;
+
+    if (!ensureGLContext())
+        return;
+
+    FloatRect clipRect(0, 0, m_viewportSize.width(), m_viewportSize.height());
+
+    TransformationMatrix viewportTransform;
+    FloatPoint scrollPostion = viewportController()->visibleContentsRect().location();
+    viewportTransform.scale(viewportController()->pageScaleFactor());
+    viewportTransform.translate(-scrollPostion.x(), -scrollPostion.y());
+
+    m_scene->paintToCurrentGLContext(viewportTransform, 1, clipRect, Color::white, false, scrollPostion);
+
+    glContext()->swapBuffers();
+}
+
+void ThreadedCompositor::updateSceneState(const CoordinatedGraphicsState& state)
+{
+    m_scene->appendUpdate(bind(&CoordinatedGraphicsScene::commitSceneState, m_scene.get(), state));
+    setNeedsDisplay();
+}
+
+void ThreadedCompositor::callOnCompositingThread(std::function<void()> function)
+{
+    m_compositingRunLoop->callOnCompositingRunLoop(WTF::move(function));
+}
+
+void ThreadedCompositor::compositingThreadEntry(void* coordinatedCompositor)
+{
+    static_cast<ThreadedCompositor*>(coordinatedCompositor)->runCompositingThread();
+}
+
+void ThreadedCompositor::createCompositingThread()
+{
+    if (m_threadIdentifier)
+        return;
+
+    MutexLocker locker(m_initializeRunLoopConditionMutex);
+    m_threadIdentifier = createThread(compositingThreadEntry, this, "WebCore: ThreadedCompositor");
+
+    m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex);
+}
+
+void ThreadedCompositor::runCompositingThread()
+{
+    {
+        MutexLocker locker(m_initializeRunLoopConditionMutex);
+
+        m_compositingRunLoop = std::make_unique<CompositingRunLoop>([&] {
+            renderLayerTree();
+        });
+
+        m_initializeRunLoopCondition.signal();
+    }
+
+    m_compositingRunLoop->runLoop().run();
+
+    m_compositingRunLoop->stopUpdateTimer();
+    m_scene->purgeGLResources();
+
+    {
+        MutexLocker locker(m_terminateRunLoopConditionMutex);
+        m_compositingRunLoop = nullptr;
+        m_context.clear();
+        m_terminateRunLoopCondition.signal();
+    }
+
+    detachThread(m_threadIdentifier);
+}
+
+void ThreadedCompositor::terminateCompositingThread()
+{
+    MutexLocker locker(m_terminateRunLoopConditionMutex);
+
+    m_scene->detach();
+    m_compositingRunLoop->runLoop().stop();
+
+    m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex);
+}
+
+}
+#endif // USE(COORDINATED_GRAPHICS_THREADED)
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h
new file mode 100644 (file)
index 0000000..ad0ccfd
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThreadedCompositor_h
+#define ThreadedCompositor_h
+
+#if USE(COORDINATED_GRAPHICS_THREADED)
+
+#include "CoordinatedGraphicsScene.h"
+#include "SimpleViewportController.h"
+#include <WebCore/GLContext.h>
+#include <WebCore/IntSize.h>
+#include <WebCore/TransformationMatrix.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+class CoordinatedGraphicsState;
+}
+
+namespace WebKit {
+class CoordinatedGraphicsScene;
+class CoordinatedGraphicsSceneClient;
+
+class CompositingRunLoop;
+
+class ThreadedCompositor : public SimpleViewportController::Client, public CoordinatedGraphicsSceneClient, public ThreadSafeRefCounted<ThreadedCompositor> {
+    WTF_MAKE_NONCOPYABLE(ThreadedCompositor);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    class Client {
+    public:
+        virtual void setVisibleContentsRect(const WebCore::FloatRect&, const WebCore::FloatPoint&, float) = 0;
+        virtual void purgeBackingStores() = 0;
+        virtual void renderNextFrame() = 0;
+        virtual void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) = 0;
+    };
+
+    static PassRefPtr<ThreadedCompositor> create(Client*);
+    virtual ~ThreadedCompositor();
+
+    void setNeedsDisplay();
+
+    void setNativeSurfaceHandleForCompositing(uint64_t);
+
+    void updateSceneState(const WebCore::CoordinatedGraphicsState&);
+
+    void didChangeViewportSize(const WebCore::IntSize&);
+    void didChangeViewportAttribute(const WebCore::ViewportAttributes&);
+    void didChangeContentsSize(const WebCore::IntSize&);
+    void scrollTo(const WebCore::IntPoint&);
+    void scrollBy(const WebCore::IntSize&);
+
+private:
+    ThreadedCompositor(Client*);
+
+    // CoordinatedGraphicsSceneClient
+    virtual void purgeBackingStores() override;
+    virtual void renderNextFrame() override;
+    virtual void updateViewport() override;
+    virtual void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) override;
+
+    void renderLayerTree();
+    void scheduleDisplayIfNeeded(double interval = 0);
+    virtual void didChangeVisibleRect() override;
+
+    bool ensureGLContext();
+    WebCore::GLContext* glContext();
+    SimpleViewportController* viewportController() { return m_viewportController.get(); }
+
+    void callOnCompositingThread(std::function<void()>);
+    void createCompositingThread();
+    void runCompositingThread();
+    void terminateCompositingThread();
+    static void compositingThreadEntry(void*);
+
+    Client* m_client;
+    RefPtr<CoordinatedGraphicsScene> m_scene;
+    std::unique_ptr<SimpleViewportController> m_viewportController;
+
+    OwnPtr<WebCore::GLContext> m_context;
+
+    WebCore::IntSize m_viewportSize;
+    uint64_t m_nativeSurfaceHandle;
+
+    std::unique_ptr<CompositingRunLoop> m_compositingRunLoop;
+
+    ThreadIdentifier m_threadIdentifier;
+    ThreadCondition m_initializeRunLoopCondition;
+    Mutex m_initializeRunLoopConditionMutex;
+    ThreadCondition m_terminateRunLoopCondition;
+    Mutex m_terminateRunLoopConditionMutex;
+};
+
+} // namespace WebKit
+
+#endif
+
+#endif // ThreadedCompositor_h