Title: [125540] trunk/Source/WebKit2
Revision
125540
Author
[email protected]
Date
2012-08-14 04:22:06 -0700 (Tue, 14 Aug 2012)

Log Message

[Qt] UpdateAtlas is wasting memory
https://bugs.webkit.org/show_bug.cgi?id=93606

Reviewed by Jocelyn Turcotte.

Imported and QAreaAllocator from Qt3D and ported it to WebCore style,
and use this new area allocator to replace old one from UpdateAtlas.

* CMakeLists.txt:
* Target.pri:
* WebProcess/WebPage/AreaAllocator.cpp: Added.
(WebKit::AreaAllocator::AreaAllocator):
(WebKit::AreaAllocator::~AreaAllocator):
(WebKit::AreaAllocator::expand):
(WebKit::AreaAllocator::expandBy):
(WebKit::AreaAllocator::release):
(WebKit::AreaAllocator::overhead):
(WebKit::AreaAllocator::roundAllocation):
(WebKit::GeneralAreaAllocator::GeneralAreaAllocator):
(WebKit::GeneralAreaAllocator::~GeneralAreaAllocator):
(WebKit::GeneralAreaAllocator::freeNode):
(WebKit::GeneralAreaAllocator::expand):
(WebKit::fitsWithin):
(WebKit::GeneralAreaAllocator::allocate):
(WebKit::GeneralAreaAllocator::allocateFromNode):
(WebKit::GeneralAreaAllocator::splitNode):
(WebKit::GeneralAreaAllocator::updateLargestFree):
(WebKit::GeneralAreaAllocator::release):
(WebKit::GeneralAreaAllocator::overhead):
* WebProcess/WebPage/AreaAllocator.h: Added.
(WebCore::nextPowerOfTwo):
(AreaAllocator):
(WebKit::AreaAllocator::size):
(WebKit::AreaAllocator::minimumAllocation):
(WebKit::AreaAllocator::setMinimumAllocation):
(WebKit::AreaAllocator::margin):
(WebKit::AreaAllocator::setMargin):
(GeneralAreaAllocator):
(Node):
* WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.cpp:
(WebKit::LayerTreeCoordinator::renderNextFrame):
(WebKit::LayerTreeCoordinator::beginContentUpdate):
* WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.h:
(LayerTreeCoordinator):
* WebProcess/WebPage/UpdateAtlas.cpp:
(WebKit::UpdateAtlas::UpdateAtlas):
(WebKit::UpdateAtlas::buildLayoutIfNeeded):
(WebKit::UpdateAtlas::didSwapBuffers):
(WebKit::UpdateAtlas::beginPaintingOnAvailableBuffer):
* WebProcess/WebPage/UpdateAtlas.h:
(UpdateAtlas):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit2/CMakeLists.txt (125539 => 125540)


--- trunk/Source/WebKit2/CMakeLists.txt	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/CMakeLists.txt	2012-08-14 11:22:06 UTC (rev 125540)
@@ -464,6 +464,7 @@
     WebProcess/WebPage/EventDispatcher.cpp
     WebProcess/WebPage/FindController.cpp
 
+    WebProcess/WebPage/AreaAllocator.cpp
     WebProcess/WebPage/LayerTreeHost.cpp
     WebProcess/WebPage/PageOverlay.cpp
     WebProcess/WebPage/TapHighlightController.cpp

Modified: trunk/Source/WebKit2/ChangeLog (125539 => 125540)


--- trunk/Source/WebKit2/ChangeLog	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/ChangeLog	2012-08-14 11:22:06 UTC (rev 125540)
@@ -1,3 +1,57 @@
+2012-08-14  Allan Sandfeld Jensen  <[email protected]>
+
+        [Qt] UpdateAtlas is wasting memory
+        https://bugs.webkit.org/show_bug.cgi?id=93606
+
+        Reviewed by Jocelyn Turcotte.
+
+        Imported and QAreaAllocator from Qt3D and ported it to WebCore style,
+        and use this new area allocator to replace old one from UpdateAtlas.
+
+        * CMakeLists.txt:
+        * Target.pri:
+        * WebProcess/WebPage/AreaAllocator.cpp: Added.
+        (WebKit::AreaAllocator::AreaAllocator):
+        (WebKit::AreaAllocator::~AreaAllocator):
+        (WebKit::AreaAllocator::expand):
+        (WebKit::AreaAllocator::expandBy):
+        (WebKit::AreaAllocator::release):
+        (WebKit::AreaAllocator::overhead):
+        (WebKit::AreaAllocator::roundAllocation):
+        (WebKit::GeneralAreaAllocator::GeneralAreaAllocator):
+        (WebKit::GeneralAreaAllocator::~GeneralAreaAllocator):
+        (WebKit::GeneralAreaAllocator::freeNode):
+        (WebKit::GeneralAreaAllocator::expand):
+        (WebKit::fitsWithin):
+        (WebKit::GeneralAreaAllocator::allocate):
+        (WebKit::GeneralAreaAllocator::allocateFromNode):
+        (WebKit::GeneralAreaAllocator::splitNode):
+        (WebKit::GeneralAreaAllocator::updateLargestFree):
+        (WebKit::GeneralAreaAllocator::release):
+        (WebKit::GeneralAreaAllocator::overhead):
+        * WebProcess/WebPage/AreaAllocator.h: Added.
+        (WebCore::nextPowerOfTwo):
+        (AreaAllocator):
+        (WebKit::AreaAllocator::size):
+        (WebKit::AreaAllocator::minimumAllocation):
+        (WebKit::AreaAllocator::setMinimumAllocation):
+        (WebKit::AreaAllocator::margin):
+        (WebKit::AreaAllocator::setMargin):
+        (GeneralAreaAllocator):
+        (Node):
+        * WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.cpp:
+        (WebKit::LayerTreeCoordinator::renderNextFrame):
+        (WebKit::LayerTreeCoordinator::beginContentUpdate):
+        * WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.h:
+        (LayerTreeCoordinator):
+        * WebProcess/WebPage/UpdateAtlas.cpp:
+        (WebKit::UpdateAtlas::UpdateAtlas):
+        (WebKit::UpdateAtlas::buildLayoutIfNeeded):
+        (WebKit::UpdateAtlas::didSwapBuffers):
+        (WebKit::UpdateAtlas::beginPaintingOnAvailableBuffer):
+        * WebProcess/WebPage/UpdateAtlas.h:
+        (UpdateAtlas):
+
 2012-08-14  Sergio Villar Senin  <[email protected]>
 
         [GTK] REGRESSION (r122428) WebKit2APITests/TestWebKitFindController fails "next" test

Modified: trunk/Source/WebKit2/Target.pri (125539 => 125540)


--- trunk/Source/WebKit2/Target.pri	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/Target.pri	2012-08-14 11:22:06 UTC (rev 125540)
@@ -341,6 +341,7 @@
     WebProcess/WebCoreSupport/WebSearchPopupMenu.h \
     WebProcess/WebCoreSupport/WebVibrationClient.h \
     WebProcess/WebCoreSupport/qt/WebFrameNetworkingContext.h \
+    WebProcess/WebPage/AreaAllocator.h \
     WebProcess/WebPage/DrawingArea.h \
     WebProcess/WebPage/DrawingAreaImpl.h \
     WebProcess/WebPage/EventDispatcher.h \
@@ -702,6 +703,7 @@
     WebProcess/WebCoreSupport/qt/WebDragClientQt.cpp \
     WebProcess/WebCoreSupport/qt/WebFrameNetworkingContext.cpp \
     WebProcess/WebCoreSupport/qt/WebPopupMenuQt.cpp \
+    WebProcess/WebPage/AreaAllocator.cpp \
     WebProcess/WebPage/DecoderAdapter.cpp \
     WebProcess/WebPage/DrawingArea.cpp \
     WebProcess/WebPage/DrawingAreaImpl.cpp \

Added: trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.cpp (0 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.cpp	2012-08-14 11:22:06 UTC (rev 125540)
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "config.h"
+
+#include "AreaAllocator.h"
+
+namespace WebKit {
+
+AreaAllocator::AreaAllocator(const WebCore::IntSize& size)
+    : m_size(size)
+    , m_minAlloc(1, 1)
+    , m_margin(0, 0)
+{
+}
+
+AreaAllocator::~AreaAllocator()
+{
+}
+
+void AreaAllocator::expand(const WebCore::IntSize& size)
+{
+    m_size = m_size.expandedTo(size);
+}
+
+void AreaAllocator::expandBy(const WebCore::IntSize& size)
+{
+    m_size += size;
+}
+
+void AreaAllocator::release(const WebCore::IntRect&)
+{
+}
+
+int AreaAllocator::overhead() const
+{
+    return 0;
+}
+
+WebCore::IntSize AreaAllocator::roundAllocation(const WebCore::IntSize& size) const
+{
+    int width = size.width() + m_margin.width();
+    int height = size.height() + m_margin.height();
+    int extra = width % m_minAlloc.width();
+    if (extra)
+        width += m_minAlloc.width() - extra;
+    extra = height % m_minAlloc.height();
+    if (extra)
+        height += m_minAlloc.height() - extra;
+
+    return WebCore::IntSize(width, height);
+}
+
+GeneralAreaAllocator::GeneralAreaAllocator(const WebCore::IntSize& size)
+    : AreaAllocator(WebCore::nextPowerOfTwo(size))
+{
+    m_root = new Node();
+    m_root->rect = WebCore::IntRect(0, 0, m_size.width(), m_size.height());
+    m_root->largestFree = m_size;
+    m_root->parent = 0;
+    m_root->left = 0;
+    m_root->right = 0;
+    m_nodeCount = 1;
+    setMinimumAllocation(WebCore::IntSize(8, 8));
+}
+
+GeneralAreaAllocator::~GeneralAreaAllocator()
+{
+    freeNode(m_root);
+}
+
+void GeneralAreaAllocator::freeNode(Node* node)
+{
+    if (node) {
+        freeNode(node->left);
+        freeNode(node->right);
+    }
+    delete node;
+}
+
+void GeneralAreaAllocator::expand(const WebCore::IntSize& size)
+{
+    AreaAllocator::expand(WebCore::nextPowerOfTwo(size));
+
+    if (m_root->rect.size() == m_size)
+        return; // No change.
+
+    if (!m_root->left && m_root->largestFree.width() > 0) {
+        // No allocations have occurred, so just adjust the root size.
+        m_root->rect = WebCore::IntRect(0, 0, m_size.width(), m_size.height());
+        m_root->largestFree = m_size;
+        return;
+    }
+
+    // Add extra nodes above the current root to expand the tree.
+    Node* oldRoot = m_root;
+    Split split;
+    if (m_size.width() >= m_size.height())
+        split = SplitOnX;
+    else
+        split = SplitOnY;
+
+    while (m_root->rect.size() != m_size) {
+        if (m_root->rect.width() == m_size.width())
+            split = SplitOnY;
+        else if (m_root->rect.height() == m_size.height())
+            split = SplitOnX;
+        Node* parent = new Node();
+        Node* right = new Node();
+        m_nodeCount += 2;
+        m_root->parent = parent;
+        parent->parent = 0;
+        parent->left = m_root;
+        parent->right = right;
+        parent->largestFree = m_root->rect.size();
+        right->parent = parent;
+        right->left = 0;
+        right->right = 0;
+        right->largestFree = m_root->rect.size();
+        if (split == SplitOnX) {
+            parent->rect = WebCore::IntRect(m_root->rect.x(), m_root->rect.y(),
+                                            m_root->rect.width() * 2, m_root->rect.height());
+            right->rect = WebCore::IntRect(m_root->rect.x() + m_root->rect.width(), m_root->rect.y(),
+                                           m_root->rect.width(), m_root->rect.height());
+        } else {
+            parent->rect = WebCore::IntRect(m_root->rect.x(), m_root->rect.y(),
+                                            m_root->rect.width(), m_root->rect.height() * 2);
+            right->rect = WebCore::IntRect(m_root->rect.x(), m_root->rect.y() + m_root->rect.width(),
+                                           m_root->rect.width(), m_root->rect.height());
+        }
+        split = (split == SplitOnX ? SplitOnY : SplitOnX);
+        m_root = parent;
+    }
+    updateLargestFree(oldRoot);
+}
+
+static inline bool fitsWithin(const WebCore::IntSize& size1, const WebCore::IntSize& size2)
+{
+    return size1.width() <= size2.width() && size1.height() <= size2.height();
+}
+
+WebCore::IntRect GeneralAreaAllocator::allocate(const WebCore::IntSize& size)
+{
+    WebCore::IntSize rounded = roundAllocation(size);
+    rounded = WebCore::nextPowerOfTwo(rounded);
+    if (rounded.width() <= 0 || rounded.width() > m_size.width()
+        || rounded.height() <= 0 || rounded.height() > m_size.height())
+        return WebCore::IntRect();
+
+    WebCore::IntPoint point = allocateFromNode(rounded, m_root);
+    if (point.x() >= 0)
+        return WebCore::IntRect(point, size);
+    return WebCore::IntRect();
+}
+
+WebCore::IntPoint GeneralAreaAllocator::allocateFromNode(const WebCore::IntSize& size, Node* node)
+{
+    // Find the best node to insert into, which should be
+    // a node with the least amount of unused space that is
+    // big enough to contain the requested size.
+    while (node) {
+        // Go down a level and determine if the left or right
+        // sub-tree contains the best chance of allocation.
+        Node* left = node->left;
+        Node* right = node->right;
+        if (left && fitsWithin(size, left->largestFree)) {
+            if (right && fitsWithin(size, right->largestFree)) {
+                if (left->largestFree.width() < right->largestFree.width()
+                    || left->largestFree.height() < right->largestFree.height()) {
+                    // The largestFree values may be a little oversized,
+                    // so try the left sub-tree and then the right sub-tree.
+                    WebCore::IntPoint point = allocateFromNode(size, left);
+                    if (point.x() >= 0)
+                        return point;
+                    return allocateFromNode(size, right);
+                }
+                node = right;
+            } else
+                node = left;
+        } else if (right && fitsWithin(size, right->largestFree))
+            node = right;
+        else if (left || right) {
+            // Neither sub-node has enough space to allocate from.
+            return WebCore::IntPoint(-1, -1);
+        } else if (fitsWithin(size, node->largestFree)) {
+            // Do we need to split this node into smaller pieces?
+            Split split;
+            if (fitsWithin(WebCore::IntSize(size.width() * 2, size.height() * 2), node->largestFree)) {
+                // Split in either direction: choose the inverse of
+                // the parent node's split direction to try to balance
+                // out the wasted space as further subdivisions happen.
+                if (node->parent
+                    && node->parent->left->rect.x() == node->parent->right->rect.x())
+                    split = SplitOnX;
+                else if (node->parent)
+                    split = SplitOnY;
+                else if (node->rect.width() >= node->rect.height())
+                    split = SplitOnX;
+                else
+                    split = SplitOnY;
+            } else if (fitsWithin(WebCore::IntSize(size.width() * 2, size.height()), node->largestFree)) {
+                // Split along the X direction.
+                split = SplitOnX;
+            } else if (fitsWithin(WebCore::IntSize(size.width(), size.height() * 2), node->largestFree)) {
+                // Split along the Y direction.
+                split = SplitOnY;
+            } else {
+                // Cannot split further - allocate this node.
+                node->largestFree = WebCore::IntSize(0, 0);
+                updateLargestFree(node);
+                return node->rect.location();
+            }
+
+            // Split the node, then go around again using the left sub-tree.
+            node = splitNode(node, split);
+        } else {
+            // Cannot possibly fit into this node.
+            break;
+        }
+    }
+    return WebCore::IntPoint(-1, -1);
+}
+
+GeneralAreaAllocator::Node* GeneralAreaAllocator::splitNode
+    (Node* node, Split split)
+{
+    Node* left = new Node();
+    Node* right = new Node();
+    m_nodeCount += 2;
+    left->parent = node;
+    left->left = 0;
+    left->right = 0;
+    right->parent = node;
+    right->left = 0;
+    right->right = 0;
+    node->left = left;
+    node->right = right;
+
+    if (split == SplitOnX) {
+        left->rect = WebCore::IntRect(node->rect.x(), node->rect.y(),
+                                      node->rect.width() / 2, node->rect.height());
+        right->rect = WebCore::IntRect(left->rect.maxX(), node->rect.y(),
+                                       node->rect.width() / 2, node->rect.height());
+    } else {
+        left->rect = WebCore::IntRect(node->rect.x(), node->rect.y(),
+                                      node->rect.width(), node->rect.height() / 2);
+        right->rect = WebCore::IntRect(node->rect.x(), left->rect.maxY(),
+                                       node->rect.width(), node->rect.height() / 2);
+    }
+
+    left->largestFree = left->rect.size();
+    right->largestFree = right->rect.size();
+    node->largestFree = right->largestFree;
+    return left;
+}
+
+void GeneralAreaAllocator::updateLargestFree(Node* node)
+{
+    while ((node = node->parent)) {
+        node->largestFree = WebCore::IntSize(
+                                std::max(node->left->largestFree.width(), node->right->largestFree.width()),
+                                std::max(node->left->largestFree.height(), node->right->largestFree.height())
+                            );
+    }
+}
+
+void GeneralAreaAllocator::release(const WebCore::IntRect& rect)
+{
+    // Locate the node that contains the allocated region.
+    Node* node = m_root;
+    WebCore::IntPoint point = rect.location();
+    while (node) {
+        if (node->left && node->left->rect.contains(point))
+            node = node->left;
+        else if (node->right && node->right->rect.contains(point))
+            node = node->right;
+        else if (node->rect.contains(point))
+            break;
+        else
+            return; // Point is completely outside the tree.
+    }
+    if (!node)
+        return;
+
+    // Mark the node as free and then work upwards through the tree
+    // recombining and deleting nodes until we reach a sibling
+    // that is still allocated.
+    node->largestFree = node->rect.size();
+    while (node->parent) {
+        if (node->parent->left == node) {
+            if (node->parent->right->largestFree != node->parent->right->rect.size())
+                break;
+        } else {
+            if (node->parent->left->largestFree != node->parent->left->rect.size())
+                break;
+        }
+        node = node->parent;
+        freeNode(node->left);
+        freeNode(node->right);
+        m_nodeCount -= 2;
+        node->left = 0;
+        node->right = 0;
+        node->largestFree = node->rect.size();
+    }
+
+    // Make the rest of our ancestors have the correct "largest free size".
+    updateLargestFree(node);
+}
+
+int GeneralAreaAllocator::overhead() const
+{
+    return m_nodeCount * sizeof(Node);
+}
+
+} // namespace

Added: trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.h (0 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.h	                        (rev 0)
+++ trunk/Source/WebKit2/WebProcess/WebPage/AreaAllocator.h	2012-08-14 11:22:06 UTC (rev 125540)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef AreaAllocator_h
+#define AreaAllocator_h
+
+#include <IntPoint.h>
+#include <IntRect.h>
+#include <IntSize.h>
+
+namespace WebCore {
+inline int nextPowerOfTwo(int number)
+{
+    // This is a fast trick to get nextPowerOfTwo for an integer.
+    --number;
+    number |= number >> 1;
+    number |= number >> 2;
+    number |= number >> 4;
+    number |= number >> 8;
+    number |= number >> 16;
+    number++;
+    return number;
+}
+
+inline IntSize nextPowerOfTwo(const IntSize& size)
+{
+    return IntSize(nextPowerOfTwo(size.width()), nextPowerOfTwo(size.height()));
+}
+} // namespace WebCore
+
+namespace WebKit {
+
+class AreaAllocator {
+public:
+    AreaAllocator(const WebCore::IntSize&);
+    virtual ~AreaAllocator();
+
+    WebCore::IntSize size() const { return m_size; }
+
+    WebCore::IntSize minimumAllocation() const { return m_minAlloc; }
+    void setMinimumAllocation(const WebCore::IntSize& size) { m_minAlloc = size; }
+
+    WebCore::IntSize margin() const { return m_margin; }
+    void setMargin(const WebCore::IntSize &margin) { m_margin = margin; }
+
+    virtual void expand(const WebCore::IntSize&);
+    void expandBy(const WebCore::IntSize&);
+
+    virtual WebCore::IntRect allocate(const WebCore::IntSize&) = 0;
+    virtual void release(const WebCore::IntRect&);
+
+    virtual int overhead() const;
+
+protected:
+    WebCore::IntSize m_size;
+    WebCore::IntSize m_minAlloc;
+    WebCore::IntSize m_margin;
+
+    WebCore::IntSize roundAllocation(const WebCore::IntSize&) const;
+};
+
+class GeneralAreaAllocator : public AreaAllocator {
+public:
+    GeneralAreaAllocator(const WebCore::IntSize&);
+    virtual ~GeneralAreaAllocator();
+
+    void expand(const WebCore::IntSize&);
+    WebCore::IntRect allocate(const WebCore::IntSize&);
+    void release(const WebCore::IntRect&);
+    int overhead() const;
+
+private:
+    enum Split { SplitOnX, SplitOnY };
+
+    struct Node {
+        WebCore::IntRect rect;
+        WebCore::IntSize largestFree;
+        Node* parent;
+        Node* left;
+        Node* right;
+    };
+
+    Node* m_root;
+    int m_nodeCount;
+
+    static void freeNode(Node*);
+    WebCore::IntPoint allocateFromNode(const WebCore::IntSize&, Node*);
+    Node* splitNode(Node*, Split);
+    static void updateLargestFree(Node*);
+};
+
+} // namespace WebKit
+
+#endif

Modified: trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.cpp (125539 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.cpp	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.cpp	2012-08-14 11:22:06 UTC (rev 125540)
@@ -601,7 +601,7 @@
     m_waitingForUIProcess = false;
     scheduleLayerFlush();
     for (int i = 0; i < m_updateAtlases.size(); ++i)
-        m_updateAtlases[i].didSwapBuffers();
+        m_updateAtlases[i]->didSwapBuffers();
 }
 
 bool LayerTreeCoordinator::layerTreeTileUpdatesAllowed() const
@@ -623,18 +623,18 @@
 {
     OwnPtr<WebCore::GraphicsContext> graphicsContext;
     for (int i = 0; i < m_updateAtlases.size(); ++i) {
-        UpdateAtlas& atlas = m_updateAtlases[i];
-        if (atlas.flags() == flags) {
+        UpdateAtlas* atlas = m_updateAtlases[i].get();
+        if (atlas->flags() == flags) {
             // This will return null if there is no available buffer space.
-            graphicsContext = atlas.beginPaintingOnAvailableBuffer(handle, size, offset);
+            graphicsContext = atlas->beginPaintingOnAvailableBuffer(handle, size, offset);
             if (graphicsContext)
                 return graphicsContext.release();
         }
     }
 
-    static const int ScratchBufferDimension = 2000;
-    m_updateAtlases.append(UpdateAtlas(ScratchBufferDimension, flags));
-    return m_updateAtlases.last().beginPaintingOnAvailableBuffer(handle, size, offset);
+    static const int ScratchBufferDimension = 1024; // Should be a power of two.
+    m_updateAtlases.append(adoptPtr(new UpdateAtlas(ScratchBufferDimension, flags)));
+    return m_updateAtlases.last()->beginPaintingOnAvailableBuffer(handle, size, offset);
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.h (125539 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.h	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/LayerTreeCoordinator.h	2012-08-14 11:22:06 UTC (rev 125540)
@@ -123,7 +123,7 @@
 
     HashSet<WebCore::CoordinatedGraphicsLayer*> m_registeredLayers;
     HashMap<int64_t, int> m_directlyCompositedImageRefCounts;
-    Vector<UpdateAtlas> m_updateAtlases;
+    Vector<OwnPtr<UpdateAtlas> > m_updateAtlases;
 
     bool m_notifyAfterScheduledLayerFlush;
     bool m_isValid;

Modified: trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp (125539 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp	2012-08-14 11:22:06 UTC (rev 125540)
@@ -25,6 +25,7 @@
 #include "GraphicsContext.h"
 #include "IntRect.h"
 #include <wtf/MathExtras.h>
+
 using namespace WebCore;
 
 namespace WebKit {
@@ -32,112 +33,48 @@
 UpdateAtlas::UpdateAtlas(int dimension, ShareableBitmap::Flags flags)
     : m_flags(flags)
 {
-    m_surface = ShareableSurface::create(IntSize(dimension, dimension), flags, ShareableSurface::SupportsGraphicsSurface);
+    IntSize size = nextPowerOfTwo(IntSize(dimension, dimension));
+    m_surface = ShareableSurface::create(size, flags, ShareableSurface::SupportsGraphicsSurface);
 }
 
-static int nextPowerOfTwo(int number)
-{
-    // This is a fast trick to get nextPowerOfTwo for an integer.
-    --number;
-    number |= number >> 1;
-    number |= number >> 2;
-    number |= number >> 4;
-    number |= number >> 8;
-    number |= number >> 16;
-    number++;
-    return number;
-}
-
 void UpdateAtlas::buildLayoutIfNeeded()
 {
-    if (!m_layout.isEmpty())
-        return;
-
-    static const int MinTileSize = 32;
-    static const int MaxTileSize = 512;
-
-    // Divide our square to square power-of-two boxes.
-    for (int cursor = 0; cursor < size().width(); ) {
-        int remainder = size().width() - cursor;
-        int dimension = std::min(remainder, std::min(MaxTileSize, std::max(MinTileSize, nextPowerOfTwo(remainder / 2))));
-        cursor += dimension;
-        m_layout.append(dimension);
+    if (!m_areaAllocator) {
+        m_areaAllocator = adoptPtr(new GeneralAreaAllocator(size()));
+        m_areaAllocator->setMinimumAllocation(IntSize(32, 32));
     }
-
-    m_bufferStates.resize(m_layout.size() * m_layout.size());
-    for (int i = 0; i < m_bufferStates.size(); ++i)
-        m_bufferStates[i] = Available;
 }
 
-int UpdateAtlas::findAvailableIndex(const WebCore::IntSize& size)
-{
-    int dimension = m_layout.size();
-    int stride = dimension;
-    int requiredDimension = std::max(size.width(), size.height());
-
-    // Begin from the smallest buffer, until we reach the smallest available buffer that's big enough to contain our rect.
-    for (int i = m_bufferStates.size() - 1; i >= 0; i -= (dimension + 1), --stride) {
-        // Need a bigger buffer.
-        if (m_layout[i / dimension] < requiredDimension)
-            continue;
-
-        // Check all buffers of current size, to find an available one.
-        for (int offset = 0; offset < stride; ++offset) {
-            int index = i - offset;
-            if (m_bufferStates[index] == Available)
-                return index;
-        }
-    }
-
-    return -1;
-}
-
 void UpdateAtlas::didSwapBuffers()
 {
+    m_areaAllocator.clear();
     buildLayoutIfNeeded();
-    for (int i = 0; i < m_bufferStates.size(); ++i)
-        m_bufferStates[i] = Available;
 }
 
 PassOwnPtr<GraphicsContext> UpdateAtlas::beginPaintingOnAvailableBuffer(ShareableSurface::Handle& handle, const WebCore::IntSize& size, IntPoint& offset)
 {
     buildLayoutIfNeeded();
-    int index = findAvailableIndex(size);
+    IntRect rect = m_areaAllocator->allocate(size);
 
     // No available buffer was found, returning null.
-    if (index < 0)
+    if (rect.isEmpty())
         return PassOwnPtr<GraphicsContext>();
 
     if (!m_surface->createHandle(handle))
         return PassOwnPtr<WebCore::GraphicsContext>();
 
     // FIXME: Use tri-state buffers, to allow faster updates.
-    m_bufferStates[index] = Taken;
-    offset = offsetForIndex(index);
-    IntRect rect(IntPoint::zero(), size);
-    OwnPtr<GraphicsContext> graphicsContext = m_surface->createGraphicsContext(IntRect(offset, size));
+    offset = rect.location();
+    OwnPtr<GraphicsContext> graphicsContext = m_surface->createGraphicsContext(rect);
 
     if (flags() & ShareableBitmap::SupportsAlpha) {
         graphicsContext->setCompositeOperation(CompositeCopy);
-        graphicsContext->fillRect(rect, Color::transparent, ColorSpaceDeviceRGB);
+        graphicsContext->fillRect(IntRect(IntPoint::zero(), size), Color::transparent, ColorSpaceDeviceRGB);
         graphicsContext->setCompositeOperation(CompositeSourceOver);
     }
 
     return graphicsContext.release();
 }
 
-IntPoint UpdateAtlas::offsetForIndex(int index) const
-{
-    IntPoint coord(index % m_layout.size(), index / m_layout.size());
-    int x = 0;
-    int y = 0;
-    for (int i = 0; i < coord.x(); ++i)
-        x += m_layout[i];
-    for (int i = 0; i < coord.y(); ++i)
-        y += m_layout[i];
-
-    return IntPoint(x, y);
 }
-
-}
 #endif

Modified: trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h (125539 => 125540)


--- trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h	2012-08-14 11:14:55 UTC (rev 125539)
+++ trunk/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h	2012-08-14 11:22:06 UTC (rev 125540)
@@ -20,17 +20,20 @@
 #ifndef UpdateAtlas_h
 #define UpdateAtlas_h
 
+#include "AreaAllocator.h"
+#include "IntSize.h"
 #include "ShareableSurface.h"
 
 #if USE(COORDINATED_GRAPHICS)
 namespace WebCore {
 class GraphicsContext;
-class IntRect;
+class IntPoint;
 }
 
 namespace WebKit {
 
 class UpdateAtlas {
+    WTF_MAKE_NONCOPYABLE(UpdateAtlas);
 public:
     UpdateAtlas(int dimension, ShareableBitmap::Flags);
 
@@ -43,17 +46,9 @@
 
 private:
     void buildLayoutIfNeeded();
-    WebCore::IntPoint offsetForIndex(int) const;
-    int findAvailableIndex(const WebCore::IntSize&);
 
 private:
-    enum State {
-        Available,
-        Taken
-    };
-
-    Vector<State> m_bufferStates;
-    Vector<int> m_layout;
+    OwnPtr<GeneralAreaAllocator> m_areaAllocator;
     ShareableBitmap::Flags m_flags;
     RefPtr<ShareableSurface> m_surface;
 };
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to