[WK2] Enable using a single ShareableBitmap for multiple updates
authornoam.rosenthal@nokia.com <noam.rosenthal@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Apr 2012 04:57:32 +0000 (04:57 +0000)
committernoam.rosenthal@nokia.com <noam.rosenthal@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Apr 2012 04:57:32 +0000 (04:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=83424

Source/WebCore:

Modify BitmapTexture::updateContents to include a source offset.
This allows us to update a texture from a sub-image.

Reviewed by Kenneth Rohde Christiansen.

Tested by existing API tests.

* platform/graphics/texmap/TextureMapper.h:
(BitmapTexture):
* platform/graphics/texmap/TextureMapperGL.cpp:
(WebCore::BitmapTextureGL::didReset):
(WebCore::driverSupportsBGRASwizzling):
(WebCore::BitmapTextureGL::updateContents):
* platform/graphics/texmap/TextureMapperGL.h:
(WebCore::BitmapTextureGL::textureTarget):
(BitmapTextureGL):
* platform/graphics/texmap/TextureMapperImageBuffer.cpp:
(WebCore::BitmapTextureImageBuffer::updateContents):
* platform/graphics/texmap/TextureMapperImageBuffer.h:
(BitmapTextureImageBuffer):

Source/WebKit2:

Reviewed by Kenneth Rohde Christiansen.

Enabled creating a GraphicsContext that references a rect inside ShareableBitmap.
Added bitmapOffset to UpdateInfo, to allow updates to reference an offset inside the bitmap.
Added UpdateAtlas, a class that manages available rects in a larger ShareableBitmap.

In this iteration, UpdateAtlas has a simple behavior where a rect inside the bitmap is
either available or used. When the buffers are swapped, all used buffers become available
again. A future enhancement might allow triple-buffering, where available rects can be
updated while other rects from the same atlas are in use.

Added the necessary plumbing to allow Qt's UI-side compositing to take advantage of
UpdateAtlas. LayerTreeHostQt creates an atlas per type of bitmap (i.e. one opaque and one
alpha-enabled atlas). When a tile wants to update and there's no available scratch-buffer,
the update would be postponed to the next frame, creating a tiling-artifact in low memory
situations.

* Shared/UpdateInfo.cpp:
(WebKit::UpdateInfo::encode):
(WebKit::UpdateInfo::decode):
* Shared/UpdateInfo.h:
(UpdateInfo):
* Target.pri:
* UIProcess/LayerTreeHostProxy.cpp:
(WebKit::LayerTreeHostProxy::updateTileForLayer):
* UIProcess/WebLayerTreeRenderer.cpp:
(WebKit::WebLayerTreeRenderer::syncLayerParameters):
(WebKit::WebLayerTreeRenderer::updateTile):
(WebKit::WebLayerTreeRenderer::createImage):
* UIProcess/WebLayerTreeRenderer.h:
(TileUpdate):
(WebKit::WebLayerTreeRenderer::TileUpdate::TileUpdate):
(WebLayerTreeRenderer):
* UIProcess/qt/LayerBackingStore.cpp:
(WebKit::LayerBackingStoreTile::swapBuffers):
(WebKit::LayerBackingStoreTile::setBackBuffer):
(WebKit::LayerBackingStore::createTile):
* UIProcess/qt/LayerBackingStore.h:
(LayerBackingStoreTile):
(LayerBackingStore):
* WebProcess/WebCoreSupport/WebGraphicsLayer.cpp:
(WebCore::WebGraphicsLayer::tiledBackingStoreBackgroundColor):
(WebCore::WebGraphicsLayer::beginContentUpdate):
(WebCore):
* WebProcess/WebCoreSupport/WebGraphicsLayer.h:
(WebGraphicsLayerClient):
(WebGraphicsLayer):
* WebProcess/WebPage/TiledBackingStoreRemoteTile.cpp:
(WebKit::TiledBackingStoreRemoteTile::updateBackBuffer):
* WebProcess/WebPage/TiledBackingStoreRemoteTile.h:
(TiledBackingStoreRemoteTileClient):
* WebProcess/WebPage/UpdateAtlas.cpp: Added.
(WebKit):
(WebKit::UpdateAtlas::UpdateAtlas):
(WebKit::nextPowerOfTwo):
(WebKit::UpdateAtlas::buildLayoutIfNeeded):
(WebKit::UpdateAtlas::findAvailableIndex):
(WebKit::UpdateAtlas::didSwapBuffers):
(WebKit::UpdateAtlas::acquireScratchBuffer):
(WebKit::UpdateAtlas::offsetForIndex):
* WebProcess/WebPage/UpdateAtlas.h: Added.
(WebCore):
(WebKit):
(UpdateAtlas):
(WebKit::UpdateAtlas::bitmap):
(WebKit::UpdateAtlas::size):
(WebKit::UpdateAtlas::flags):
* WebProcess/WebPage/qt/LayerTreeHostQt.cpp:
(WebKit::LayerTreeHostQt::adoptImageBackingStore):
(WebKit::LayerTreeHostQt::renderNextFrame):
(WebKit::LayerTreeHostQt::purgeBackingStores):
(WebKit):
(WebKit::LayerTreeHostQt::getAtlas):
(WebKit::LayerTreeHostQt::beginContentUpdate):
* WebProcess/WebPage/qt/LayerTreeHostQt.h:
(LayerTreeHostQt):

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

26 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/texmap/TextureMapper.h
Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp
Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h
Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp
Source/WebCore/platform/graphics/texmap/TextureMapperGL.h
Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp
Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h
Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/UpdateInfo.cpp
Source/WebKit2/Shared/UpdateInfo.h
Source/WebKit2/Target.pri
Source/WebKit2/UIProcess/LayerTreeHostProxy.cpp
Source/WebKit2/UIProcess/WebLayerTreeRenderer.cpp
Source/WebKit2/UIProcess/WebLayerTreeRenderer.h
Source/WebKit2/UIProcess/qt/LayerBackingStore.cpp
Source/WebKit2/UIProcess/qt/LayerBackingStore.h
Source/WebKit2/WebProcess/WebCoreSupport/WebGraphicsLayer.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebGraphicsLayer.h
Source/WebKit2/WebProcess/WebPage/TiledBackingStoreRemoteTile.cpp
Source/WebKit2/WebProcess/WebPage/TiledBackingStoreRemoteTile.h
Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp [new file with mode: 0644]
Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h [new file with mode: 0644]
Source/WebKit2/WebProcess/WebPage/qt/LayerTreeHostQt.cpp
Source/WebKit2/WebProcess/WebPage/qt/LayerTreeHostQt.h

index b530eb9..e26dd0b 100644 (file)
@@ -1,3 +1,29 @@
+2012-04-09  No'am Rosenthal  <noam.rosenthal@nokia.com>
+
+        [WK2] Enable using a single ShareableBitmap for multiple updates
+        https://bugs.webkit.org/show_bug.cgi?id=83424
+
+        Modify BitmapTexture::updateContents to include a source offset.
+        This allows us to update a texture from a sub-image.
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        Tested by existing API tests.
+
+        * platform/graphics/texmap/TextureMapper.h:
+        (BitmapTexture):
+        * platform/graphics/texmap/TextureMapperGL.cpp:
+        (WebCore::BitmapTextureGL::didReset):
+        (WebCore::driverSupportsBGRASwizzling):
+        (WebCore::BitmapTextureGL::updateContents):
+        * platform/graphics/texmap/TextureMapperGL.h:
+        (WebCore::BitmapTextureGL::textureTarget):
+        (BitmapTextureGL):
+        * platform/graphics/texmap/TextureMapperImageBuffer.cpp:
+        (WebCore::BitmapTextureImageBuffer::updateContents):
+        * platform/graphics/texmap/TextureMapperImageBuffer.h:
+        (BitmapTextureImageBuffer):
+
 2012-04-09  Dana Jansens  <danakj@chromium.org>
 
         [chromium] Viewport is not filled when out of texture memory on mac
index 6cb5b77..a287dbd 100644 (file)
@@ -52,7 +52,6 @@ class TextureMapper;
 // A 2D texture that can be the target of software or GL rendering.
 class BitmapTexture  : public RefCounted<BitmapTexture> {
 public:
-    enum PixelFormat { BGRAFormat, RGBAFormat, BGRFormat, RGBFormat };
     enum Flag {
         SupportsAlpha = 0x01
     };
@@ -67,8 +66,8 @@ public:
     virtual ~BitmapTexture() { }
 
     virtual IntSize size() const = 0;
-    virtual void updateContents(Image*, const IntRect&, const IntRect&, BitmapTexture::PixelFormat) = 0;
-    virtual void updateContents(const void*, const IntRect&) = 0;
+    virtual void updateContents(Image*, const IntRect&, const IntPoint& offset) = 0;
+    virtual void updateContents(const void*, const IntRect& target, const IntPoint& offset, int bytesPerLine) = 0;
     virtual bool isValid() const = 0;
     inline Flags flags() const { return m_flags; }
 
index 6c3e2d8..43ac781 100644 (file)
 
 namespace WebCore {
 
-void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect, BitmapTexture::PixelFormat format)
+void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect)
 {
     IntRect targetRect = enclosingIntRect(m_rect);
     targetRect.intersect(dirtyRect);
     if (targetRect.isEmpty())
         return;
-    IntRect sourceRect = targetRect;
+    IntPoint sourceOffset = targetRect.location();
 
     // Normalize sourceRect to the buffer's coordinates.
-    sourceRect.move(-dirtyRect.x(), -dirtyRect.y());
+    sourceOffset.move(-dirtyRect.x(), -dirtyRect.y());
 
     // Normalize targetRect to the texture's coordinates.
     targetRect.move(-m_rect.x(), -m_rect.y());
@@ -44,7 +44,7 @@ void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* imag
         m_texture->reset(targetRect.size(), image->currentFrameHasAlpha() ? BitmapTexture::SupportsAlpha : 0);
     }
 
-    m_texture->updateContents(image, targetRect, sourceRect, format);
+    m_texture->updateContents(image, targetRect, sourceOffset);
 }
 
 void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, BitmapTexture* mask)
@@ -57,7 +57,7 @@ void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapp
     if (!m_image)
         return;
 
-    updateContents(textureMapper, m_image.get(), m_image->currentFrameHasAlpha() ? BitmapTexture::BGRAFormat : BitmapTexture::BGRFormat);
+    updateContents(textureMapper, m_image.get());
     m_image.clear();
 }
 
@@ -134,11 +134,11 @@ void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSiz
         m_tiles.remove(tileIndicesToRemove[i]);
 }
 
-void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::PixelFormat format)
+void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect)
 {
     createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), image->currentFrameHasAlpha());
     for (size_t i = 0; i < m_tiles.size(); ++i)
-        m_tiles[i].updateContents(textureMapper, image, dirtyRect, format);
+        m_tiles[i].updateContents(textureMapper, image, dirtyRect);
 }
 
 PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const
index 02e84f2..df61b86 100644 (file)
@@ -45,7 +45,7 @@ public:
     inline void setTexture(BitmapTexture* texture) { m_texture = texture; }
     inline void setRect(const FloatRect& rect) { m_rect = rect; }
 
-    void updateContents(TextureMapper*, Image*, const IntRect&, BitmapTexture::PixelFormat);
+    void updateContents(TextureMapper*, Image*, const IntRect&);
     virtual void paint(TextureMapper*, const TransformationMatrix&, float, BitmapTexture*);
     virtual ~TextureMapperTile() { }
 
@@ -65,8 +65,8 @@ public:
     virtual ~TextureMapperTiledBackingStore() { }
     virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float, BitmapTexture*);
     virtual PassRefPtr<BitmapTexture> texture() const;
-    void updateContents(TextureMapper*, Image*, const FloatSize&, const IntRect&, BitmapTexture::PixelFormat);
-    void updateContents(TextureMapper* textureMapper, Image* image, BitmapTexture::PixelFormat format) { updateContents(textureMapper, image, image->size(), image->rect(), format); }
+    void updateContents(TextureMapper*, Image*, const FloatSize&, const IntRect&);
+    void updateContents(TextureMapper* textureMapper, Image* image) { updateContents(textureMapper, image, image->size(), image->rect()); }
     inline FloatRect rect() const { return FloatRect(FloatPoint::zero(), m_size); }
     static PassRefPtr<TextureMapperTiledBackingStore> create() { return adoptRef(new TextureMapperTiledBackingStore); }
     void setContentsToImage(Image* image) { m_image = image; }
index ba49fb2..8a25973 100644 (file)
@@ -409,12 +409,13 @@ void BitmapTextureGL::didReset()
     m_surfaceNeedsReset = true;
 }
 
-static void swizzleBGRAToRGBA(uint32_t* data, const IntSize& size)
+static void swizzleBGRAToRGBA(uint32_t* data, const IntSize& size, int stride = 0)
 {
     int width = size.width();
     int height = size.height();
+    stride = stride | width;
     for (int y = 0; y < height; ++y) {
-        uint32_t* p = data + y * width;
+        uint32_t* p = data + y * stride;
         for (int x = 0; x < width; ++x)
             p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
     }
@@ -430,33 +431,64 @@ static bool driverSupportsBGRASwizzling()
 #endif
 }
 
-void BitmapTextureGL::updateContents(const void* data, const IntRect& targetRect)
+static bool driverSupportsSubImage()
+{
+#if defined(TEXMAP_OPENGL_ES_2)
+    // FIXME: Implement reliable detection.
+    return false;
+#else
+    return true;
+#endif
+}
+
+void BitmapTextureGL::updateContents(const void* data, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine)
 {
     GLuint glFormat = GL_RGBA;
     GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
+
     if (driverSupportsBGRASwizzling())
         glFormat = GL_BGRA;
-    else {
-        swizzleBGRAToRGBA(static_cast<uint32_t*>(const_cast<void*>(data)), targetRect.size());
-        glFormat = GL_RGBA;
+    else
+        swizzleBGRAToRGBA(static_cast<uint32_t*>(const_cast<void*>(data)), targetRect.size(), bytesPerLine / 4);
+
+    if (bytesPerLine == targetRect.width() / 4 && sourceOffset == IntPoint::zero()) {
+        GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, GL_UNSIGNED_BYTE, (const char*)data))
+        return;
+    }
+
+    // For ES drivers that don't support sub-images, transfer the pixels row-by-row.
+    if (!driverSupportsSubImage()) {
+        const char* bits = static_cast<const char*>(data);
+        for (int y = 0; y < targetRect.height(); ++y) {
+            const char *row = bits + ((sourceOffset.y() + y) * bytesPerLine + sourceOffset.x() * 4);
+            GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, targetRect.x(), targetRect.y() + y, targetRect.width(), 1, glFormat, GL_UNSIGNED_BYTE, row))
+        }
+        return;
     }
 
-    GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, GL_UNSIGNED_BYTE, data))
+    // Use the OpenGL sub-image extension, now that we know it's available.
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, bytesPerLine / 4);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, sourceOffset.y());
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, sourceOffset.x());
+    GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, GL_UNSIGNED_BYTE, (const char*)data))
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 }
 
-void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntRect& sourceRect, BitmapTexture::PixelFormat format)
+void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset)
 {
     if (!image)
         return;
-    GL_CMD(glBindTexture(GL_TEXTURE_2D, m_id))
-    GLuint glFormat = isOpaque() ? GL_RGB : GL_RGBA;
     NativeImagePtr frameImage = image->nativeImageForCurrentFrame();
     if (!frameImage)
         return;
 
+    int bytesPerLine;
+    const char* imageData;
+
 #if PLATFORM(QT)
     QImage qtImage;
-
 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     // With QPA, we can avoid a deep copy.
     qtImage = *frameImage->handle()->buffer();
@@ -464,40 +496,15 @@ void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, co
     // This might be a deep copy, depending on other references to the pixmap.
     qtImage = frameImage->toImage();
 #endif
-
-    if (IntSize(qtImage.size()) != sourceRect.size())
-        qtImage = qtImage.copy(sourceRect);
-    if (format == BGRAFormat || format == BGRFormat) {
-        if (driverSupportsBGRASwizzling())
-            glFormat = isOpaque() ? GL_BGR : GL_BGRA;
-        else
-            swizzleBGRAToRGBA(reinterpret_cast<uint32_t*>(qtImage.bits()), qtImage.size());
-    }
-    GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, GL_UNSIGNED_BYTE, qtImage.constBits()))
-
+    imageData = reinterpret_cast<const char*>(qtImage.constBits());
+    bytesPerLine = qtImage.bytesPerLine();
 #elif USE(CAIRO)
-
-#if !CPU(BIG_ENDIAN)
-#if defined(TEXMAP_OPENGL_ES_2)
-    swizzleBGRAToRGBA(reinterpret_cast<uint32_t*>(cairo_image_surface_get_data(frameImage)),
-                      cairo_image_surface_get_stride(frameImage) * cairo_image_surface_get_height(frameImage));
-#else
-    glFormat = isOpaque() ? GL_BGR : GL_BGRA;
-#endif
+    imageData = cairo_image_surface_get_data(frameImage);
+    bytesPerLine = cairo_image_surface_get_stride(frameImage);
 #endif
 
-    glPixelStorei(GL_UNPACK_ROW_LENGTH, cairo_image_surface_get_stride(frameImage) / 4);
-    glPixelStorei(GL_UNPACK_SKIP_ROWS, sourceRect.y());
-    glPixelStorei(GL_UNPACK_SKIP_PIXELS, sourceRect.x());
-    GL_CMD(glTexSubImage2D(GL_TEXTURE_2D, 0,
-                           targetRect.x(), targetRect.y(),
-                           targetRect.width(), targetRect.height(),
-                           glFormat, GL_UNSIGNED_BYTE,
-                           cairo_image_surface_get_data(frameImage)));
-    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
-    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
-#endif
+    updateContents(imageData, targetRect, offset, bytesPerLine);
+
 }
 
 static inline TransformationMatrix createProjectionMatrix(const IntSize& size, bool flip)
index 547fe2f..b6c6e42 100644 (file)
@@ -62,7 +62,7 @@ public:
     void setGraphicsContext(GraphicsContext* context) { m_context = context; }
     GraphicsContext* graphicsContext() { return m_context; }
     virtual bool isOpenGLBacked() const { return true; }
-    void platformUpdateContents(NativeImagePtr, const IntRect&, const IntRect&, BitmapTexture::PixelFormat);
+    void platformUpdateContents(NativeImagePtr, const IntRect&, const IntRect&);
     virtual AccelerationMode accelerationMode() const { return OpenGLMode; }
 
 private:
@@ -83,10 +83,11 @@ public:
     void initializeStencil();
     ~BitmapTextureGL();
     virtual uint32_t id() const { return m_id; }
+    uint32_t textureTarget() const { return GL_TEXTURE_2D; }
     IntSize textureSize() const { return m_textureSize; }
     void setTextureMapper(TextureMapperGL* texmap) { m_textureMapper = texmap; }
-    void updateContents(Image*, const IntRect&, const IntRect&, PixelFormat);
-    void updateContents(const void*, const IntRect&);
+    void updateContents(Image*, const IntRect&, const IntPoint&);
+    virtual void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine);
 
 private:
     GLuint m_id;
index e53b9f8..4c28177 100644 (file)
 #if USE(TEXTURE_MAPPER)
 namespace WebCore {
 
-void BitmapTextureImageBuffer::updateContents(const void* data, const IntRect& targetRect)
+void BitmapTextureImageBuffer::updateContents(const void* data, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine)
 {
 #if PLATFORM(QT)
-    QImage image(reinterpret_cast<const uchar*>(data), targetRect.width(), targetRect.height(), targetRect.width() * 4, QImage::Format_ARGB32_Premultiplied);
+    QImage image(reinterpret_cast<const uchar*>(data), targetRect.width(), targetRect.height(), bytesPerLine, QImage::Format_ARGB32_Premultiplied);
+
     QPainter* painter = m_image->context()->platformContext();
     painter->save();
     painter->setCompositionMode(QPainter::CompositionMode_Source);
-    painter->drawImage(targetRect, image);
+    painter->drawImage(targetRect, image, IntRect(sourceOffset, targetRect.size()));
     painter->restore();
 #endif
 }
@@ -42,9 +43,9 @@ void BitmapTextureImageBuffer::didReset()
     m_image = ImageBuffer::create(contentSize());
 }
 
-void BitmapTextureImageBuffer::updateContents(Image* image, const IntRect& targetRect, const IntRect& sourceRect, PixelFormat)
+void BitmapTextureImageBuffer::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset)
 {
-    m_image->context()->drawImage(image, ColorSpaceDeviceRGB, targetRect, sourceRect, CompositeCopy);
+    m_image->context()->drawImage(image, ColorSpaceDeviceRGB, targetRect, IntRect(offset, targetRect.size()), CompositeCopy);
 }
 
 void TextureMapperImageBuffer::beginClip(const TransformationMatrix& matrix, const FloatRect& rect)
index 2826c4b..37c98ab 100644 (file)
@@ -34,8 +34,8 @@ public:
     virtual void didReset();
     virtual bool isValid() const { return m_image; }
     inline GraphicsContext* graphicsContext() { return m_image ? m_image->context() : 0; }
-    virtual void updateContents(Image*, const IntRect&, const IntRect&, PixelFormat);
-    void updateContents(const void* data, const IntRect& targetRect);
+    virtual void updateContents(Image*, const IntRect&, const IntPoint&);
+    virtual void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine);
 #if ENABLE(CSS_FILTERS)
     void applyFilters(const BitmapTexture&, const FilterOperations&);
 #endif
index 23797e6..db59807 100644 (file)
@@ -131,7 +131,7 @@ void TextureMapperLayer::updateBackingStore(TextureMapper* textureMapper, Graphi
     image = imageBuffer->copyImage(CopyBackingStore);
 #endif
 
-    static_cast<TextureMapperTiledBackingStore*>(m_backingStore.get())->updateContents(textureMapper, image.get(), m_size, dirtyRect, BitmapTexture::BGRAFormat);
+    static_cast<TextureMapperTiledBackingStore*>(m_backingStore.get())->updateContents(textureMapper, image.get(), m_size, dirtyRect);
 }
 
 void TextureMapperLayer::paint()
index b3a51e1..c26e5eb 100644 (file)
@@ -1,5 +1,87 @@
 2012-04-09  No'am Rosenthal  <noam.rosenthal@nokia.com>
 
+        [WK2] Enable using a single ShareableBitmap for multiple updates
+        https://bugs.webkit.org/show_bug.cgi?id=83424
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        Enabled creating a GraphicsContext that references a rect inside ShareableBitmap.
+        Added bitmapOffset to UpdateInfo, to allow updates to reference an offset inside the bitmap.
+        Added UpdateAtlas, a class that manages available rects in a larger ShareableBitmap.
+
+        In this iteration, UpdateAtlas has a simple behavior where a rect inside the bitmap is
+        either available or used. When the buffers are swapped, all used buffers become available
+        again. A future enhancement might allow triple-buffering, where available rects can be
+        updated while other rects from the same atlas are in use.
+
+        Added the necessary plumbing to allow Qt's UI-side compositing to take advantage of
+        UpdateAtlas. LayerTreeHostQt creates an atlas per type of bitmap (i.e. one opaque and one
+        alpha-enabled atlas). When a tile wants to update and there's no available scratch-buffer,
+        the update would be postponed to the next frame, creating a tiling-artifact in low memory
+        situations.
+
+        * Shared/UpdateInfo.cpp:
+        (WebKit::UpdateInfo::encode):
+        (WebKit::UpdateInfo::decode):
+        * Shared/UpdateInfo.h:
+        (UpdateInfo):
+        * Target.pri:
+        * UIProcess/LayerTreeHostProxy.cpp:
+        (WebKit::LayerTreeHostProxy::updateTileForLayer):
+        * UIProcess/WebLayerTreeRenderer.cpp:
+        (WebKit::WebLayerTreeRenderer::syncLayerParameters):
+        (WebKit::WebLayerTreeRenderer::updateTile):
+        (WebKit::WebLayerTreeRenderer::createImage):
+        * UIProcess/WebLayerTreeRenderer.h:
+        (TileUpdate):
+        (WebKit::WebLayerTreeRenderer::TileUpdate::TileUpdate):
+        (WebLayerTreeRenderer):
+        * UIProcess/qt/LayerBackingStore.cpp:
+        (WebKit::LayerBackingStoreTile::swapBuffers):
+        (WebKit::LayerBackingStoreTile::setBackBuffer):
+        (WebKit::LayerBackingStore::createTile):
+        * UIProcess/qt/LayerBackingStore.h:
+        (LayerBackingStoreTile):
+        (LayerBackingStore):
+        * WebProcess/WebCoreSupport/WebGraphicsLayer.cpp:
+        (WebCore::WebGraphicsLayer::tiledBackingStoreBackgroundColor):
+        (WebCore::WebGraphicsLayer::beginContentUpdate):
+        (WebCore):
+        * WebProcess/WebCoreSupport/WebGraphicsLayer.h:
+        (WebGraphicsLayerClient):
+        (WebGraphicsLayer):
+        * WebProcess/WebPage/TiledBackingStoreRemoteTile.cpp:
+        (WebKit::TiledBackingStoreRemoteTile::updateBackBuffer):
+        * WebProcess/WebPage/TiledBackingStoreRemoteTile.h:
+        (TiledBackingStoreRemoteTileClient):
+        * WebProcess/WebPage/UpdateAtlas.cpp: Added.
+        (WebKit):
+        (WebKit::UpdateAtlas::UpdateAtlas):
+        (WebKit::nextPowerOfTwo):
+        (WebKit::UpdateAtlas::buildLayoutIfNeeded):
+        (WebKit::UpdateAtlas::findAvailableIndex):
+        (WebKit::UpdateAtlas::didSwapBuffers):
+        (WebKit::UpdateAtlas::acquireScratchBuffer):
+        (WebKit::UpdateAtlas::offsetForIndex):
+        * WebProcess/WebPage/UpdateAtlas.h: Added.
+        (WebCore):
+        (WebKit):
+        (UpdateAtlas):
+        (WebKit::UpdateAtlas::bitmap):
+        (WebKit::UpdateAtlas::size):
+        (WebKit::UpdateAtlas::flags):
+        * WebProcess/WebPage/qt/LayerTreeHostQt.cpp:
+        (WebKit::LayerTreeHostQt::adoptImageBackingStore):
+        (WebKit::LayerTreeHostQt::renderNextFrame):
+        (WebKit::LayerTreeHostQt::purgeBackingStores):
+        (WebKit):
+        (WebKit::LayerTreeHostQt::getAtlas):
+        (WebKit::LayerTreeHostQt::beginContentUpdate):
+        * WebProcess/WebPage/qt/LayerTreeHostQt.h:
+        (LayerTreeHostQt):
+
+2012-04-09  No'am Rosenthal  <noam.rosenthal@nokia.com>
+
         [Qt][WK2] Sync the layer's state and the layer's children separately
         https://bugs.webkit.org/show_bug.cgi?id=82534
 
index a15d716..5bb1895 100644 (file)
@@ -40,6 +40,7 @@ void UpdateInfo::encode(CoreIPC::ArgumentEncoder* encoder) const
     encoder->encode(updateRects);
     encoder->encode(updateScaleFactor);
     encoder->encode(bitmapHandle);
+    encoder->encode(bitmapOffset);
 }
 
 bool UpdateInfo::decode(CoreIPC::ArgumentDecoder* decoder, UpdateInfo& result)
@@ -60,6 +61,8 @@ bool UpdateInfo::decode(CoreIPC::ArgumentDecoder* decoder, UpdateInfo& result)
         return false;
     if (!decoder->decode(result.bitmapHandle))
         return false;
+    if (!decoder->decode(result.bitmapOffset))
+        return false;
 
     return true;
 }
index 40c86dc..e3a8de2 100644 (file)
@@ -65,6 +65,9 @@ public:
 
     // The handle of the shareable bitmap containing the updates. Will be null if there are no updates.
     ShareableBitmap::Handle bitmapHandle;
+
+    // The offset in the bitmap where the rendered contents are.
+    WebCore::IntPoint bitmapOffset;
 };
 
 } // namespace WebKit
index 0db9859..50bc150 100644 (file)
@@ -363,6 +363,7 @@ HEADERS += \
     WebProcess/WebPage/FindController.h \
     WebProcess/WebPage/TapHighlightController.h \
     WebProcess/WebPage/PageOverlay.h \
+    WebProcess/WebPage/UpdateAtlas.h \
     WebProcess/WebPage/WebContextMenu.h \
     WebProcess/WebPage/WebFrame.h \
     WebProcess/WebPage/WebInspector.h \
@@ -370,6 +371,7 @@ HEADERS += \
     WebProcess/WebPage/WebPage.h \
     WebProcess/WebPage/WebPageGroupProxy.h \
     WebProcess/WebPage/WebUndoStep.h \
+    WebProcess/WebPage/qt/LayerTreeHostQt.h \
     WebProcess/WebConnectionToUIProcess.h \
     WebProcess/WebProcess.h \
     WebProcess/qt/QtBuiltinBundle.h \
@@ -729,6 +731,7 @@ SOURCES += \
     WebProcess/WebPage/LayerTreeHost.cpp \
     WebProcess/WebPage/PageOverlay.cpp \
     WebProcess/WebPage/TiledBackingStoreRemoteTile.cpp \
+    WebProcess/WebPage/UpdateAtlas.cpp \
     WebProcess/WebPage/WebBackForwardListProxy.cpp \
     WebProcess/WebPage/WebContextMenu.cpp \
     WebProcess/WebPage/WebFrame.cpp \
index 2449c31..f790627 100644 (file)
@@ -78,7 +78,7 @@ void LayerTreeHostProxy::updateTileForLayer(int layerID, int tileID, const WebKi
     IntRect sourceRect = updateInfo.updateRects.first();
     IntRect targetRect = updateInfo.updateRectBounds;
     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(updateInfo.bitmapHandle);
-    dispatchUpdate(bind(&WebLayerTreeRenderer::updateTile, m_renderer.get(), layerID, tileID, sourceRect, targetRect, bitmap));
+    dispatchUpdate(bind(&WebLayerTreeRenderer::updateTile, m_renderer.get(), layerID, tileID, WebLayerTreeRenderer::TileUpdate(sourceRect, targetRect, bitmap, updateInfo.bitmapOffset)));
 }
 
 void LayerTreeHostProxy::removeTileForLayer(int layerID, int tileID)
index f28d079..d6e72e6 100644 (file)
@@ -267,11 +267,10 @@ void WebLayerTreeRenderer::removeTile(WebLayerID layerID, int tileID)
     getBackingStore(layerID)->removeTile(tileID);
 }
 
-void WebLayerTreeRenderer::updateTile(WebLayerID layerID, int tileID, const IntRect& sourceRect, const IntRect& targetRect, PassRefPtr<ShareableBitmap> weakBitmap)
+void WebLayerTreeRenderer::updateTile(WebLayerID layerID, int tileID, const TileUpdate& update)
 {
-    RefPtr<ShareableBitmap> bitmap = weakBitmap;
     RefPtr<LayerBackingStore> backingStore = getBackingStore(layerID);
-    backingStore->updateTile(tileID, sourceRect, targetRect, bitmap.get());
+    backingStore->updateTile(tileID, update.sourceRect, update.targetRect, update.bitmap, update.offset);
     m_backingStoresWithPendingBuffers.add(backingStore);
 }
 
@@ -279,8 +278,8 @@ void WebLayerTreeRenderer::createImage(int64_t imageID, PassRefPtr<ShareableBitm
 {
     RefPtr<ShareableBitmap> bitmap = weakBitmap;
     RefPtr<TextureMapperTiledBackingStore> backingStore = TextureMapperTiledBackingStore::create();
-    backingStore->updateContents(m_textureMapper.get(), bitmap->createImage().get(), BitmapTexture::BGRAFormat);
     m_directlyCompositedImages.set(imageID, backingStore);
+    backingStore->updateContents(m_textureMapper.get(), bitmap->createImage().get());
 }
 
 void WebLayerTreeRenderer::destroyImage(int64_t imageID)
index 44cdba7..181be0c 100644 (file)
@@ -45,6 +45,19 @@ class WebLayerUpdateInfo;
 
 class WebLayerTreeRenderer : public ThreadSafeRefCounted<WebLayerTreeRenderer>, public WebCore::GraphicsLayerClient {
 public:
+    struct TileUpdate {
+        WebCore::IntRect sourceRect;
+        WebCore::IntRect targetRect;
+        RefPtr<ShareableBitmap> bitmap;
+        WebCore::IntPoint offset;
+        TileUpdate(const WebCore::IntRect& source, const WebCore::IntRect& target, PassRefPtr<ShareableBitmap> newBitmap, const WebCore::IntPoint& newOffset)
+            : sourceRect(source)
+            , targetRect(target)
+            , bitmap(newBitmap)
+            , offset(newOffset)
+        {
+        }
+    };
     WebLayerTreeRenderer(LayerTreeHostProxy*);
     virtual ~WebLayerTreeRenderer();
     void purgeGLResources();
@@ -63,7 +76,7 @@ public:
     void setLayerState(WebLayerID, const WebLayerInfo&);
     void createTile(WebLayerID, int, float scale);
     void removeTile(WebLayerID, int);
-    void updateTile(WebLayerID, int, const WebCore::IntRect&, const WebCore::IntRect&, PassRefPtr<ShareableBitmap>);
+    void updateTile(WebLayerID, int, const TileUpdate&);
     void flushLayerChanges();
     void createImage(int64_t, PassRefPtr<ShareableBitmap>);
     void destroyImage(int64_t);
index 3f8a8c8..fee0c90 100644 (file)
@@ -23,8 +23,7 @@
 #if USE(UI_SIDE_COMPOSITING)
 #include "GraphicsLayer.h"
 #include "TextureMapper.h"
-
-#include "stdio.h"
+#include "TextureMapperGL.h"
 
 using namespace WebCore;
 
@@ -50,18 +49,17 @@ void LayerBackingStoreTile::swapBuffers(WebCore::TextureMapper* textureMapper)
     }
 
     QImage qImage = m_backBuffer->createQImage();
-
     if (shouldReset)
         texture->reset(m_sourceRect.size(), qImage.hasAlphaChannel() ? BitmapTexture::SupportsAlpha : 0);
-
-    texture->updateContents(qImage.constBits(), m_sourceRect);
+    texture->updateContents(qImage.constBits(), m_sourceRect, m_bitmapOffset, qImage.bytesPerLine());
     m_backBuffer.clear();
 }
 
-void LayerBackingStoreTile::setBackBuffer(const WebCore::IntRect& targetRect, const WebCore::IntRect& sourceRect, ShareableBitmap* buffer)
+void LayerBackingStoreTile::setBackBuffer(const IntRect& targetRect, const IntRect& sourceRect, PassRefPtr<ShareableBitmap> buffer, const IntPoint& offset)
 {
     m_sourceRect = sourceRect;
     m_targetRect = targetRect;
+    m_bitmapOffset = offset;
     m_backBuffer = buffer;
 }
 
@@ -76,11 +74,12 @@ void LayerBackingStore::removeTile(int id)
     m_tilesToRemove.append(id);
 }
 
-void LayerBackingStore::updateTile(int id, const IntRect& sourceRect, const IntRect& targetRect, ShareableBitmap* backBuffer)
+
+void LayerBackingStore::updateTile(int id, const IntRect& sourceRect, const IntRect& targetRect, PassRefPtr<ShareableBitmap> backBuffer, const IntPoint& offset)
 {
     HashMap<int, LayerBackingStoreTile>::iterator it = m_tiles.find(id);
     ASSERT(it != m_tiles.end());
-    it->second.setBackBuffer(targetRect, sourceRect, backBuffer);
+    it->second.setBackBuffer(targetRect, sourceRect, backBuffer, offset);
 }
 
 PassRefPtr<BitmapTexture> LayerBackingStore::texture() const
index f08b144..a241e4c 100644 (file)
@@ -39,12 +39,13 @@ public:
 
     inline float scale() const { return m_scale; }
     void swapBuffers(WebCore::TextureMapper*);
-    void setBackBuffer(const WebCore::IntRect&, const WebCore::IntRect&, ShareableBitmap* buffer);
+    void setBackBuffer(const WebCore::IntRect&, const WebCore::IntRect&, PassRefPtr<ShareableBitmap> buffer, const WebCore::IntPoint&);
 
 private:
     RefPtr<ShareableBitmap> m_backBuffer;
     WebCore::IntRect m_sourceRect;
     WebCore::IntRect m_targetRect;
+    WebCore::IntPoint m_bitmapOffset;
     float m_scale;
 };
 
@@ -52,7 +53,7 @@ class LayerBackingStore : public WebCore::TextureMapperBackingStore {
 public:
     void createTile(int, float);
     void removeTile(int);
-    void updateTile(int, const WebCore::IntRect&, const WebCore::IntRect&, ShareableBitmap*);
+    void updateTile(int, const WebCore::IntRect&, const WebCore::IntRect&, PassRefPtr<ShareableBitmap>, const WebCore::IntPoint&);
     static PassRefPtr<LayerBackingStore> create() { return adoptRef(new LayerBackingStore); }
     void commitTileOperations(WebCore::TextureMapper*);
     PassRefPtr<WebCore::BitmapTexture> texture() const;
index 523b419..3af6257 100644 (file)
@@ -553,6 +553,11 @@ Color WebGraphicsLayer::tiledBackingStoreBackgroundColor() const
     return contentsOpaque() ? Color::white : Color::transparent;
 }
 
+PassOwnPtr<WebCore::GraphicsContext> WebGraphicsLayer::beginContentUpdate(const WebCore::IntSize& size, ShareableBitmap::Handle& handle, WebCore::IntPoint& offset)
+{
+    return m_webGraphicsLayerClient->beginContentUpdate(size, contentsOpaque() ? 0 : ShareableBitmap::SupportsAlpha, handle, offset);
+}
+
 void WebGraphicsLayer::createTile(int tileID, const UpdateInfo& updateInfo)
 {
     m_webGraphicsLayerClient->createTile(id(), tileID, updateInfo);
index f9d6ea6..27fec55 100644 (file)
@@ -59,6 +59,7 @@ public:
     virtual void syncLayerChildren(WebLayerID, const Vector<WebLayerID>&) = 0;
     virtual void attachLayer(WebCore::WebGraphicsLayer*) = 0;
     virtual void detachLayer(WebCore::WebGraphicsLayer*) = 0;
+    virtual PassOwnPtr<WebCore::GraphicsContext> beginContentUpdate(const WebCore::IntSize&, ShareableBitmap::Flags, ShareableBitmap::Handle&, WebCore::IntPoint&) = 0;
 };
 }
 
@@ -128,6 +129,7 @@ public:
     virtual void createTile(int tileID, const WebKit::UpdateInfo&);
     virtual void updateTile(int tileID, const WebKit::UpdateInfo&);
     virtual void removeTile(int tileID);
+    virtual PassOwnPtr<WebCore::GraphicsContext> beginContentUpdate(const WebCore::IntSize&, WebKit::ShareableBitmap::Handle&, WebCore::IntPoint&);
 
     void setWebGraphicsLayerClient(WebKit::WebGraphicsLayerClient*);
     void syncChildren();
index ee116c2..aeb6ebc 100644 (file)
@@ -72,19 +72,20 @@ Vector<IntRect> TiledBackingStoreRemoteTile::updateBackBuffer()
     if (!isDirty())
         return Vector<IntRect>();
 
-    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(m_dirtyRect.size(), m_tiledBackingStore->supportsAlpha() ? ShareableBitmap::SupportsAlpha : 0);
-    OwnPtr<GraphicsContext> graphicsContext(bitmap->createGraphicsContext());
+    UpdateInfo updateInfo;
+    OwnPtr<GraphicsContext> graphicsContext = m_client->beginContentUpdate(m_dirtyRect.size(), updateInfo.bitmapHandle, updateInfo.bitmapOffset);
+    if (!graphicsContext)
+        return Vector<IntRect>();
     graphicsContext->translate(-m_dirtyRect.x(), -m_dirtyRect.y());
     graphicsContext->scale(FloatSize(m_tiledBackingStore->contentsScale(), m_tiledBackingStore->contentsScale()));
     m_tiledBackingStore->client()->tiledBackingStorePaint(graphicsContext.get(), m_tiledBackingStore->mapToContents(m_dirtyRect));
 
-    UpdateInfo updateInfo;
     updateInfo.updateRectBounds = m_rect;
     IntRect updateRect = m_dirtyRect;
     updateRect.move(-m_rect.x(), -m_rect.y());
     updateInfo.updateRects.append(updateRect);
     updateInfo.updateScaleFactor = m_tiledBackingStore->contentsScale();
-    bitmap->createHandle(updateInfo.bitmapHandle);
+    graphicsContext.release();
 
     static int id = 0;
     if (!m_ID) {
index 12b2e06..dfc252e 100644 (file)
@@ -28,6 +28,7 @@
 
 #if USE(TILED_BACKING_STORE)
 
+#include "ShareableBitmap.h"
 #include "Tile.h"
 #include "TiledBackingStore.h"
 #include "WebCore/IntRect.h"
@@ -78,6 +79,7 @@ public:
     virtual void createTile(int tileID, const UpdateInfo&) = 0;
     virtual void updateTile(int tileID, const UpdateInfo&) = 0;
     virtual void removeTile(int tileID) = 0;
+    virtual PassOwnPtr<WebCore::GraphicsContext> beginContentUpdate(const WebCore::IntSize&, ShareableBitmap::Handle&, WebCore::IntPoint&) = 0;
 };
 
 class TiledBackingStoreRemoteTileBackend : public WebCore::TiledBackingStoreBackend {
diff --git a/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp b/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.cpp
new file mode 100644 (file)
index 0000000..9e46413
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ 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 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 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; 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"
+#include "UpdateAtlas.h"
+
+#if USE(UI_SIDE_COMPOSITING)
+
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "MathExtras.h"
+using namespace WebCore;
+
+namespace WebKit {
+
+UpdateAtlas::UpdateAtlas(int dimension, ShareableBitmap::Flags flags)
+    : m_flags(flags)
+{
+    m_bitmap = ShareableBitmap::createShareable(IntSize(dimension, dimension), flags);
+}
+
+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);
+    }
+
+    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()
+{
+    buildLayoutIfNeeded();
+    for (int i = 0; i < m_bufferStates.size(); ++i)
+        m_bufferStates[i] = Available;
+}
+
+PassOwnPtr<GraphicsContext> UpdateAtlas::beginPaintingOnAvailableBuffer(const WebCore::IntSize& size, IntPoint& offset)
+{
+    buildLayoutIfNeeded();
+    int index = findAvailableIndex(size);
+
+    // No available buffer was found, returning null.
+    if (index < 0)
+        return PassOwnPtr<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_bitmap->createGraphicsContext();
+    graphicsContext->translate(offset.x(), offset.y());
+    graphicsContext->clip(rect);
+    graphicsContext->setCompositeOperation(CompositeCopy);
+    graphicsContext->fillRect(rect, (flags() & ShareableBitmap::SupportsAlpha) ? Color::transparent : Color::white, 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
diff --git a/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h b/Source/WebKit2/WebProcess/WebPage/UpdateAtlas.h
new file mode 100644 (file)
index 0000000..cef3e9c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ 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 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 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; 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 UpdateAtlas_h
+#define UpdateAtlas_h
+
+#include "ShareableBitmap.h"
+
+#if USE(UI_SIDE_COMPOSITING)
+namespace WebCore {
+class GraphicsContext;
+class IntRect;
+}
+
+namespace WebKit {
+
+class UpdateAtlas {
+public:
+    UpdateAtlas(int dimension, ShareableBitmap::Flags);
+
+    PassRefPtr<ShareableBitmap> bitmap() { return m_bitmap; }
+    inline WebCore::IntSize size() const { return m_bitmap->size(); }
+
+    // Returns a null pointer of there is no available buffer.
+    PassOwnPtr<WebCore::GraphicsContext> beginPaintingOnAvailableBuffer(const WebCore::IntSize&, WebCore::IntPoint& offset);
+    void didSwapBuffers();
+    ShareableBitmap::Flags flags() const { return m_flags; }
+
+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;
+    ShareableBitmap::Flags m_flags;
+    RefPtr<ShareableBitmap> m_bitmap;
+};
+
+}
+#endif
+#endif // UpdateAtlas_h
index 13e9fc1..13ea96a 100644 (file)
@@ -32,6 +32,7 @@
 #include "GraphicsContext.h"
 #include "LayerTreeHostProxyMessages.h"
 #include "MessageID.h"
+#include "WebCoreArgumentCoders.h"
 #include "WebGraphicsLayer.h"
 #include "WebPage.h"
 #include <WebCore/Frame.h>
@@ -329,7 +330,7 @@ int64_t LayerTreeHostQt::adoptImageBackingStore(Image* image)
         return key;
     }
 
-    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(image->size(), image->currentFrameHasAlpha() ? ShareableBitmap::SupportsAlpha : 0);
+    RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(image->size(), (image->currentFrameHasAlpha() ? ShareableBitmap::SupportsAlpha : 0));
     {
         OwnPtr<WebCore::GraphicsContext> graphicsContext = bitmap->createGraphicsContext();
         graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntPoint::zero());
@@ -451,6 +452,8 @@ void LayerTreeHostQt::renderNextFrame()
 {
     m_waitingForUIProcess = false;
     scheduleLayerFlush();
+    for (int i = 0; i < m_updateAtlases.size(); ++i)
+        m_updateAtlases[i].didSwapBuffers();
 }
 
 bool LayerTreeHostQt::layerTreeTileUpdatesAllowed() const
@@ -465,6 +468,32 @@ void LayerTreeHostQt::purgeBackingStores()
         (*it)->purgeBackingStores();
 
     ASSERT(!m_directlyCompositedImageRefCounts.size());
+    m_updateAtlases.clear();
+}
+
+UpdateAtlas& LayerTreeHostQt::getAtlas(ShareableBitmap::Flags flags)
+{
+    for (int i = 0; i < m_updateAtlases.size(); ++i) {
+        if (m_updateAtlases[i].flags() == flags)
+            return m_updateAtlases[i];
+    }
+    static const int ScratchBufferDimension = 2000;
+    m_updateAtlases.append(UpdateAtlas(ScratchBufferDimension, flags));
+    return m_updateAtlases.last();
+}
+
+PassOwnPtr<WebCore::GraphicsContext> LayerTreeHostQt::beginContentUpdate(const WebCore::IntSize& size, ShareableBitmap::Flags flags, ShareableBitmap::Handle& handle, WebCore::IntPoint& offset)
+{
+    UpdateAtlas& atlas = getAtlas(flags);
+    if (!atlas.bitmap()->createHandle(handle))
+        return PassOwnPtr<WebCore::GraphicsContext>();
+
+    // This will return null if there is no available buffer.
+    OwnPtr<WebCore::GraphicsContext> graphicsContext = atlas.beginPaintingOnAvailableBuffer(size, offset);
+    if (!graphicsContext)
+        return PassOwnPtr<WebCore::GraphicsContext>();
+
+    return graphicsContext.release();
 }
 
 } // namespace WebKit
index 8d3236e..7912842 100644 (file)
@@ -23,6 +23,7 @@
 #include "LayerTreeContext.h"
 #include "LayerTreeHost.h"
 #include "Timer.h"
+#include "UpdateAtlas.h"
 #include "WebGraphicsLayer.h"
 #include <WebCore/GraphicsLayerClient.h>
 #include <wtf/OwnPtr.h>
@@ -76,6 +77,8 @@ public:
     virtual void attachLayer(WebCore::WebGraphicsLayer*);
     virtual void detachLayer(WebCore::WebGraphicsLayer*);
 
+    virtual PassOwnPtr<WebCore::GraphicsContext> beginContentUpdate(const WebCore::IntSize&, ShareableBitmap::Flags, ShareableBitmap::Handle&, WebCore::IntPoint&);
+
 protected:
     explicit LayerTreeHostQt(WebPage*);
 
@@ -95,6 +98,8 @@ private:
     void performScheduledLayerFlush();
     void sendLayersToUI();
 
+    UpdateAtlas& getAtlas(ShareableBitmap::Flags);
+
     OwnPtr<WebCore::GraphicsLayer> m_rootLayer;
 
     // The layer which contains all non-composited content.
@@ -105,6 +110,7 @@ private:
 
     HashSet<WebCore::WebGraphicsLayer*> m_registeredLayers;
     HashMap<int64_t, int> m_directlyCompositedImageRefCounts;
+    Vector<UpdateAtlas> m_updateAtlases;
 
     bool m_notifyAfterScheduledLayerFlush;
     bool m_isValid;