diff options
Diffstat (limited to 'Source/WebCore/platform')
30 files changed, 339 insertions, 247 deletions
diff --git a/Source/WebCore/platform/android/ScrollViewAndroid.cpp b/Source/WebCore/platform/android/ScrollViewAndroid.cpp index ecaa2b5..cc1c09e 100644 --- a/Source/WebCore/platform/android/ScrollViewAndroid.cpp +++ b/Source/WebCore/platform/android/ScrollViewAndroid.cpp @@ -103,13 +103,7 @@ void ScrollView::platformOffscreenContentRectangle(const IntRect& vis, const Int android::WebViewCore* core = android::WebViewCore::getWebViewCore(this); if (!core) // SVG does not instantiate webviewcore return; // and doesn't need to record drawing offscreen - SkRegion rectRgn = SkRegion(rect); - rectRgn.op(vis, SkRegion::kDifference_Op); - SkRegion::Iterator iter(rectRgn); - for (; !iter.done(); iter.next()) { - const SkIRect& diff = iter.rect(); - core->offInvalidate(diff); - } + core->offInvalidate(rect); } #endif diff --git a/Source/WebCore/platform/android/WidgetAndroid.cpp b/Source/WebCore/platform/android/WidgetAndroid.cpp index 0f7758d..6858f29 100644 --- a/Source/WebCore/platform/android/WidgetAndroid.cpp +++ b/Source/WebCore/platform/android/WidgetAndroid.cpp @@ -59,10 +59,6 @@ void Widget::setFocus(bool focused) void Widget::paint(GraphicsContext* ctx, const IntRect& r) { - // FIXME: in what case, will this be called for the top frame? - if (!platformWidget()) - return; - platformWidget()->draw(ctx, r); } void Widget::releasePlatformWidget() diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp index 69c597f..535d211 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp @@ -20,6 +20,7 @@ #include "MediaLayer.h" #include "ParseCanvas.h" #include "PictureLayerContent.h" +#include "PrerenderedInval.h" #include "SkBitmapRef.h" #include "SkDrawFilter.h" #include "SkPaint.h" @@ -524,6 +525,20 @@ void LayerAndroid::setContent(LayerContent* content) m_content = content; } +bool LayerAndroid::canUpdateWithBlit() +{ + if (!m_content || !m_scale) + return false; + PrerenderedInval* prerendered = m_content->prerenderForRect(m_dirtyRegion.getBounds()); + if (!prerendered) + return false; + // Check that the scales are "close enough" to produce the same rects + FloatRect screenArea = prerendered->screenArea; + screenArea.scale(1 / m_scale); + IntRect enclosingDocArea = enclosingIntRect(screenArea); + return enclosingDocArea == prerendered->area; +} + bool LayerAndroid::needsTexture() { return m_content && !m_content->isEmpty(); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h index 4f94698..ca833f7 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h @@ -185,6 +185,9 @@ public: LayerContent* content() { return m_content; } void setContent(LayerContent* content); + // Check to see if the dirty area of this layer can be updated with a blit + // from the prerender instead of needing to generate tiles from the LayerContent + bool canUpdateWithBlit(); void addAnimation(PassRefPtr<AndroidAnimation> anim); void removeAnimationsForProperty(AnimatedPropertyID property); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerContent.h b/Source/WebCore/platform/graphics/android/layers/LayerContent.h index 97bc32a..2cd90a90 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerContent.h @@ -26,6 +26,7 @@ #ifndef LayerContent_h #define LayerContent_h +#include "IntRect.h" #include "SkRefCnt.h" #include <utils/threads.h> @@ -35,14 +36,18 @@ class SkWStream; namespace WebCore { +class PrerenderedInval; + class LayerContent : public SkRefCnt { public: virtual int width() = 0; virtual int height() = 0; - virtual bool isEmpty() = 0; + virtual bool isEmpty() { return !width() || !height(); } virtual void checkForOptimisations() = 0; virtual bool hasText() = 0; virtual void draw(SkCanvas* canvas) = 0; + virtual PrerenderedInval* prerenderForRect(const IntRect& dirty) { return 0; } + virtual void clearPrerenders() { }; virtual void serialize(SkWStream* stream) = 0; diff --git a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp new file mode 100644 index 0000000..b648e72 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp @@ -0,0 +1,41 @@ +#include "config.h" +#include "PicturePileLayerContent.h" + +#include "SkCanvas.h" +#include "SkPicture.h" + +namespace WebCore { + +PicturePileLayerContent::PicturePileLayerContent(const PicturePile& picturePile) + : m_picturePile(picturePile) +{ +} + +void PicturePileLayerContent::draw(SkCanvas* canvas) +{ + android::Mutex::Autolock lock(m_drawLock); + m_picturePile.draw(canvas); +} + +void PicturePileLayerContent::serialize(SkWStream* stream) +{ + if (!stream) + return; + SkPicture picture; + draw(picture.beginRecording(width(), height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag)); + picture.endRecording(); + picture.serialize(stream); +} + +PrerenderedInval* PicturePileLayerContent::prerenderForRect(const IntRect& dirty) +{ + return m_picturePile.prerenderedInvalForArea(dirty); +} + +void PicturePileLayerContent::clearPrerenders() +{ + m_picturePile.clearPrerenders(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h index 61fc3f4..4216617 100644 --- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h @@ -23,31 +23,31 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PictureSetLayerContent_h -#define PictureSetLayerContent_h +#ifndef PicturePileLayerContent_h +#define PicturePileLayerContent_h #include "LayerContent.h" -#include "PictureSet.h" +#include "PicturePile.h" namespace WebCore { -class PictureSetLayerContent : public LayerContent { +class PicturePileLayerContent : public LayerContent { public: - PictureSetLayerContent(const android::PictureSet& pictureSet); - ~PictureSetLayerContent(); + PicturePileLayerContent(const PicturePile& picturePile); - virtual int width() { return m_pictureSet.width(); } - virtual int height() { return m_pictureSet.height(); } - virtual bool isEmpty() { return m_pictureSet.isEmpty(); } + virtual int width() { return m_picturePile.size().width(); } + virtual int height() { return m_picturePile.size().height(); } virtual void checkForOptimisations() {} virtual bool hasText() { return true; } virtual void draw(SkCanvas* canvas); virtual void serialize(SkWStream* stream); + virtual PrerenderedInval* prerenderForRect(const IntRect& dirty); + virtual void clearPrerenders(); private: - android::PictureSet m_pictureSet; + PicturePile m_picturePile; }; } // WebCore -#endif // PictureLayerContent_h +#endif // PicturePileLayerContent_h diff --git a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp deleted file mode 100644 index 8b72b0a..0000000 --- a/Source/WebCore/platform/graphics/android/layers/PictureSetLayerContent.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "config.h" -#include "PictureSetLayerContent.h" - -#include "SkCanvas.h" -#include "SkPicture.h" - -namespace WebCore { - -PictureSetLayerContent::PictureSetLayerContent(const android::PictureSet& pictureSet) -{ - m_pictureSet.set(pictureSet); -} - -PictureSetLayerContent::~PictureSetLayerContent() -{ - m_pictureSet.clear(); -} - -void PictureSetLayerContent::draw(SkCanvas* canvas) -{ - if (m_pictureSet.isEmpty()) - return; - - android::Mutex::Autolock lock(m_drawLock); - SkRect r = SkRect::MakeWH(width(), height()); - canvas->clipRect(r); - m_pictureSet.draw(canvas); -} - -void PictureSetLayerContent::serialize(SkWStream* stream) -{ - if (!stream) - return; - SkPicture picture; - draw(picture.beginRecording(m_pictureSet.width(), m_pictureSet.height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag)); - picture.endRecording(); - picture.serialize(stream); -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h new file mode 100644 index 0000000..91f385d --- /dev/null +++ b/Source/WebCore/platform/graphics/android/layers/PrerenderedInval.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER OR + * 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 PrerenderedInval_h +#define PrerenderedInval_h + +#include "IntRect.h" +#include "SkBitmap.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { + +class PrerenderedInval : public ThreadSafeRefCounted<PrerenderedInval> { + WTF_MAKE_NONCOPYABLE(PrerenderedInval); +public: + SkBitmap bitmap; + IntRect area; + IntRect screenArea; + + static PassRefPtr<PrerenderedInval> create(const IntRect& ir) + { + return adoptRef(new PrerenderedInval(ir)); + } + +private: + PrerenderedInval(const IntRect& ir) + : area(ir) + {} +}; + +} // namespace WebCore + +#endif // PrerenderedInval_h diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp index 8bb1755..6f679da 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp @@ -109,7 +109,6 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) before = currentTimeMS(); } - setupPartialInval(renderInfo, &canvas); canvas.translate(-renderInfo.x * tileSize.width(), -renderInfo.y * tileSize.height()); canvas.scale(renderInfo.scale, renderInfo.scale); renderInfo.tilePainter->paint(&canvas); @@ -127,25 +126,10 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) // only color the invalidated area SkPaint paint; paint.setARGB(color, 0, 255, 0); - if (renderInfo.invalRect) - canvas.drawIRect(*renderInfo.invalRect, paint); - else { - SkIRect rect; - rect.set(0, 0, tileSize.width(), tileSize.height()); - canvas.drawIRect(rect, paint); - } - - if (renderInfo.invalRect) { - // if partial inval... - int x = renderInfo.invalRect->fLeft; - int y = renderInfo.invalRect->fTop; - int w = renderInfo.invalRect->width(); - int h = renderInfo.invalRect->height(); - - paint.setARGB(128, 255, 255, 0); - canvas.drawLine(x, y, x + w, y + h, paint); - canvas.drawLine(x, y + h, x + w, y, paint); - } + SkIRect rect; + rect.set(0, 0, tileSize.width(), tileSize.height()); + canvas.drawIRect(rect, paint); + drawTileInfo(&canvas, renderInfo, updateCount, after - before); // paint the tile boundaries diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h index f225871..b25a50e 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h @@ -49,9 +49,6 @@ struct TileRenderInfo { // current scale factor float scale; - // inval rectangle with coordinates in the tile's coordinate space - SkIRect* invalRect; - // the expected size of the tile SkSize tileSize; @@ -89,7 +86,6 @@ public: protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; - virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) {} virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp index 7206c98..32f353c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp @@ -418,10 +418,6 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, bool skipTransfer = false; Tile* tilePtr = renderInfo->baseTile; - // TODO: use pure color for partial invals as well - if (renderInfo->invalRect) - return false; - if (tilePtr) { TileTexture* tileTexture = tilePtr->backTexture(); // Check the bitmap, and make everything ready here. @@ -611,6 +607,33 @@ void GLUtils::clearBackgroundIfOpaque(const Color* backgroundColor) } } +bool GLUtils::deepCopyBitmapSubset(const SkBitmap& sourceBitmap, + SkBitmap& subset, int leftOffset, int topOffset) +{ + sourceBitmap.lockPixels(); + subset.lockPixels(); + char* srcPixels = (char*) sourceBitmap.getPixels(); + char* dstPixels = (char*) subset.getPixels(); + if (!dstPixels || !srcPixels || !subset.lockPixelsAreWritable()) { + ALOGD("no pixels :( %p, %p (writable=%d)", srcPixels, dstPixels, + subset.lockPixelsAreWritable()); + subset.unlockPixels(); + sourceBitmap.unlockPixels(); + return false; + } + int srcRowSize = sourceBitmap.rowBytes(); + int destRowSize = subset.rowBytes(); + for (int i = 0; i < subset.height(); i++) { + int srcOffset = (i + topOffset) * srcRowSize; + srcOffset += (leftOffset * sourceBitmap.bytesPerPixel()); + int dstOffset = i * destRowSize; + memcpy(dstPixels + dstOffset, srcPixels + srcOffset, destRowSize); + } + subset.unlockPixels(); + sourceBitmap.unlockPixels(); + return true; +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h index a235458..1b69d6c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h @@ -29,6 +29,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "Color.h" +#include "IntRect.h" #include "SkBitmap.h" #include "SkMatrix.h" #include "TransformationMatrix.h" @@ -73,7 +74,8 @@ public: static GLuint createTileGLTexture(int width, int height); static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR); + static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, + const IntRect& inval = IntRect(), GLint filter = GL_LINEAR); static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); @@ -82,6 +84,8 @@ public: static bool updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); + static bool deepCopyBitmapSubset(const SkBitmap& sourceBitmap, + SkBitmap& subset, int left, int top); static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor); static bool skipTransferForPureColor(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp index 208adb6..d779af4 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp @@ -84,16 +84,6 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can canvas->setDevice(device); } -void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) -{ - // set the clip to our invalRect - SkRect clipRect = SkRect::MakeLTRB(renderInfo.invalRect->fLeft, - renderInfo.invalRect->fTop, - renderInfo.invalRect->fRight, - renderInfo.invalRect->fBottom); - canvas->clipRect(clipRect); -} - void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) { ALOGV("rendered to tile (%d,%d)", renderInfo.x, renderInfo.y); diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h index d7eda24..cdd9f3e 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h @@ -47,7 +47,6 @@ public: protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas); - virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { renderInfo.isPureColor = false; diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp index b880eef..47e5c17 100644 --- a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp @@ -80,7 +80,7 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can ALOGV("setupCanvas use background on Base Layer %x", background->rgb()); g_bitmap->setIsOpaque(!background->hasAlpha()); g_bitmap->eraseARGB(background->alpha(), background->red(), - background->green(), background->blue()); + background->green(), background->blue()); } SkDevice* device = new SkDevice(*g_bitmap); @@ -88,15 +88,6 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can canvas->setDevice(device); device->unref(); - - // If we have a partially painted bitmap - if (renderInfo.invalRect) { - SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(), - renderInfo.invalRect->height()); - // ensure the canvas origin is translated to the coordinates of our inval rect - canvas->clipRect(clipRect); - canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop); - } } void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) @@ -107,7 +98,8 @@ void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva void RasterRenderer::checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { - renderInfo.isPureColor = GLUtils::isPureColorBitmap(*g_bitmap, renderInfo.pureColor); + const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); + renderInfo.isPureColor = GLUtils::isPureColorBitmap(bitmap, renderInfo.pureColor); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp index 13c7d27..652c165 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp @@ -33,9 +33,13 @@ #include "BaseLayerAndroid.h" #include "ClassTracker.h" #include "LayerAndroid.h" +#include "LayerContent.h" #include "GLWebViewState.h" +#include "PrerenderedInval.h" #include "SkCanvas.h" #include "SurfaceBacking.h" +#include "Tile.h" +#include "TileTexture.h" #include "TilesManager.h" #include <wtf/text/CString.h> @@ -181,7 +185,7 @@ bool Surface::useAggressiveRendering() || !m_background.hasAlpha()); } -void Surface::prepareGL(bool layerTilesDisabled) +void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) { bool tilesDisabled = layerTilesDisabled && !isBase(); if (!m_surfaceBacking) { @@ -210,8 +214,15 @@ void Surface::prepareGL(bool layerTilesDisabled) fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, - prepareArea, fullArea, - this, useAggressiveRendering()); + prepareArea, fullArea, + this, useAggressiveRendering(), updateWithBlit); + if (updateWithBlit) { + for (size_t i = 0; i < m_layers.size(); i++) { + LayerContent* content = m_layers[i]->content(); + if (content) + content->clearPrerenders(); + } + } } } @@ -273,7 +284,28 @@ bool Surface::isMissingContent() return m_surfaceBacking->isMissingContent(); } -IntRect Surface::computePrepareArea() { +bool Surface::canUpdateWithBlit() +{ + // If we don't have a texture, we have nothing to update and thus can take + // the fast path + if (!needsTexture()) + return true; + // If we have a surface backing that isn't ready, we can't update with a blit + // If it is ready, then check to see if it is dirty. We can only call isDirty() + // if isReady() returns true + if (!m_surfaceBacking) + return false; + if (!m_surfaceBacking->isReady()) + return false; + if (!m_surfaceBacking->isDirty()) + return true; + if (!singleLayer()) + return false; + return getFirstLayer()->canUpdateWithBlit(); +} + +IntRect Surface::computePrepareArea() +{ IntRect area; if (!getFirstLayer()->contentIsScrollable() @@ -285,9 +317,8 @@ IntRect Surface::computePrepareArea() { double total = ((double) area.width()) * ((double) area.height()); if (total > MAX_UNCLIPPED_AREA) area = visibleArea(); - } else { + } else area = visibleArea(); - } return area; } @@ -355,6 +386,61 @@ Color* Surface::background() return &m_background; } +bool Surface::blitFromContents(Tile* tile) +{ + if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) + return false; + + LayerContent* content = getFirstLayer()->content(); + // Extract the dirty rect from the region. Note that this is *NOT* constrained + // to this tile + IntRect dirtyRect = tile->dirtyArea().getBounds(); + PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); + if (!prerenderedInval || prerenderedInval->bitmap.isNull()) + return false; + SkBitmap sourceBitmap = prerenderedInval->bitmap; + // Calculate the screen rect that is dirty, then intersect it with the + // tile's screen rect so that we end up with the pixels we need to blit + FloatRect screenDirty = dirtyRect; + screenDirty.scale(tile->scale()); + IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); + IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), + tile->y() * TilesManager::tileHeight(), + TilesManager::tileWidth(), + TilesManager::tileHeight()); + enclosingScreenDirty.intersect(tileRect); + if (enclosingScreenDirty.isEmpty()) + return false; + // Make sure the screen area we want to blit is contained by the + // prerendered screen area + if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { + ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " + "enclosingScreenDirty " INT_RECT_FORMAT, + INT_RECT_ARGS(prerenderedInval->screenArea), + INT_RECT_ARGS(enclosingScreenDirty)); + return false; + } + IntPoint origin = prerenderedInval->screenArea.location(); + SkBitmap subset; + subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + subset.allocPixels(); + + int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); + int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); + if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) + return false; + // Now upload + SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), + enclosingScreenDirty.y() - tileRect.y(), + enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, + subset, textureInval); + tile->onBlitUpdate(); + return true; +} + const TransformationMatrix* Surface::drawTransform() { // single layer surfaces query the layer's draw transform, while multi-layer diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.h b/Source/WebCore/platform/graphics/android/rendering/Surface.h index 0fced47..dc46fcf 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.h +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.h @@ -49,11 +49,12 @@ public: bool tryUpdateSurface(Surface* oldSurface); void addLayer(LayerAndroid* layer, const TransformationMatrix& transform); - void prepareGL(bool layerTilesDisabled); + void prepareGL(bool layerTilesDisabled, bool updateWithBlit); bool drawGL(bool layerTilesDisabled); void swapTiles(); bool isReady(); bool isMissingContent(); + bool canUpdateWithBlit(); void computeTexturesAmount(TexturesResult* result); @@ -66,6 +67,7 @@ public: virtual bool paint(SkCanvas* canvas); virtual float opacity(); virtual Color* background(); + virtual bool blitFromContents(Tile* tile); private: IntRect computePrepareArea(); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp index f43472e..957aa63 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp @@ -57,7 +57,8 @@ SurfaceBacking::~SurfaceBacking() void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, bool aggressiveRendering) + TilePainter* painter, bool aggressiveRendering, + bool updateWithBlit) { float scale = state->scale(); if (scale > 1 && !allowZoom) @@ -113,7 +114,8 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, // if the front grid hasn't already prepared, or needs to prepare // expanded bounds do so now m_frontTileGrid->prepareGL(state, m_scale, - prepareArea, unclippedArea, painter, prepareRegionFlags, false); + prepareArea, unclippedArea, painter, + prepareRegionFlags, false, updateWithBlit); } if (aggressiveRendering) { // prepare low res content diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h index 61e3336..08cfc7c 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h @@ -42,7 +42,8 @@ public: ~SurfaceBacking(); void prepareGL(GLWebViewState* state, bool allowZoom, const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, bool aggressiveRendering); + TilePainter* painter, bool aggressiveRendering, + bool updateWithBlit); void swapTiles(); void drawGL(const IntRect& visibleArea, float opacity, const TransformationMatrix* transform, bool aggressiveRendering, @@ -59,6 +60,11 @@ public: return !m_zooming && m_frontTileGrid->isReady() && m_scale > 0; } + bool isDirty() + { + return m_frontTileGrid->isDirty(); + } + bool isMissingContent() { return m_zooming || m_frontTileGrid->isMissingContent(); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp index 24e196b..cf59044 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp @@ -88,8 +88,16 @@ void SurfaceCollection::prepareGL(const SkRect& visibleRect) updateLayerPositions(visibleRect); bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode() > GLWebViewState::kClippedTextures; + bool updateWithBlit = true; + if (!layerTilesDisabled) { + for (unsigned int i = 0; i < m_surfaces.size(); i++) { + updateWithBlit &= m_surfaces[i]->canUpdateWithBlit(); + if (!updateWithBlit) + break; + } + } for (unsigned int i = 0; i < m_surfaces.size(); i++) - m_surfaces[i]->prepareGL(layerTilesDisabled); + m_surfaces[i]->prepareGL(layerTilesDisabled, updateWithBlit); } static inline bool compareSurfaceZ(const Surface* a, const Surface* b) diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp index 2ee45b0..3af05f4 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp @@ -327,75 +327,7 @@ void Tile::paintBitmap(TilePainter* painter) const float tileWidth = renderInfo.tileSize.width(); const float tileHeight = renderInfo.tileSize.height(); - SkRegion::Iterator cliperator(dirtyArea); - - bool fullRepaint = false; - - if (m_fullRepaint - || textureInfo->m_width != tileWidth - || textureInfo->m_height != tileHeight) { - fullRepaint = true; - } - - // For now, only do full repaint - fullRepaint = true; - - if (!fullRepaint) { - // compute the partial inval area - SkIRect totalRect; - totalRect.set(0, 0, 0, 0); - float tileSurface = tileWidth * tileHeight; - float tileSurfaceCap = MAX_INVAL_AREA * tileSurface; - - // We join all the invals in the same tile for now - while (!fullRepaint && !cliperator.done()) { - SkRect realTileRect; - SkRect dirtyRect; - dirtyRect.set(cliperator.rect()); - bool intersect = intersectWithRect(x, y, tileWidth, tileHeight, - scale, dirtyRect, realTileRect); - if (intersect) { - // initialize finalRealRect to the rounded values of realTileRect - SkIRect finalRealRect; - realTileRect.roundOut(&finalRealRect); - - // stash the int values of the current width and height - const int iWidth = finalRealRect.width(); - const int iHeight = finalRealRect.height(); - - if (iWidth == tileWidth || iHeight == tileHeight) { - fullRepaint = true; - break; - } - - // translate the rect into tile space coordinates - finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth); - finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight); - finalRealRect.fRight = finalRealRect.fLeft + iWidth; - finalRealRect.fBottom = finalRealRect.fTop + iHeight; - totalRect.join(finalRealRect); - float repaintSurface = totalRect.width() * totalRect.height(); - - if (repaintSurface > tileSurfaceCap) { - fullRepaint = true; - break; - } - } - - cliperator.next(); - } - - if (!fullRepaint) { - renderInfo.invalRect = &totalRect; - m_renderer->renderTiledContent(renderInfo); - } - } - - // Do a full repaint if needed - if (fullRepaint) { - renderInfo.invalRect = 0; - m_renderer->renderTiledContent(renderInfo); - } + m_renderer->renderTiledContent(renderInfo); m_atomicSync.lock(); @@ -410,13 +342,7 @@ void Tile::paintBitmap(TilePainter* painter) if (m_scale != scale) m_dirty = true; - if (fullRepaint) - m_dirtyArea.setEmpty(); - else - m_dirtyArea.op(dirtyArea, SkRegion::kDifference_Op); - - if (!m_dirtyArea.isEmpty()) - m_dirty = true; + m_dirtyArea.setEmpty(); ALOGV("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty); @@ -498,6 +424,15 @@ void Tile::backTextureTransferFail() { // whether validatePaint is called before or after, it won't do anything } +void Tile::onBlitUpdate() +{ + // The front texture was directly updated with a blit, so mark this as clean + android::AutoMutex lock(m_atomicSync); + m_dirty = false; + m_dirtyArea.setEmpty(); + m_state = Tile::UpToDate; +} + void Tile::validatePaint() { // ONLY CALL while m_atomicSync is locked (at the end of paintBitmap()) diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.h b/Source/WebCore/platform/graphics/android/rendering/Tile.h index c115f1c..9697b61 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.h +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.h @@ -116,6 +116,7 @@ public: void markAsDirty(const SkRegion& dirtyArea); bool isDirty(); + const SkRegion& dirtyArea() { return m_dirtyArea; } virtual bool isRepaintPending(); void setRepaintPending(bool pending); float scale() const { return m_scale; } @@ -133,6 +134,7 @@ public: bool swapTexturesIfNeeded(); void backTextureTransfer(); void backTextureTransferFail(); + void onBlitUpdate(); // TextureOwner implementation virtual bool removeTexture(TileTexture* texture); diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp index 8bf033e..bee42ae 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp @@ -34,6 +34,7 @@ #include "GLWebViewState.h" #include "PaintTileOperation.h" #include "Tile.h" +#include "TileTexture.h" #include "TilesManager.h" #include <wtf/CurrentTime.h> @@ -113,7 +114,7 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale) ceilf(contentArea.width() * scale), ceilf(contentArea.height() * scale)); - ALOGV("TG %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height()); + ALOGV("TG prepare, scale %f, area %d x %d", scale, area.width(), area.height()); if (area.width() == 0 && area.height() == 0) { computedArea.setWidth(0); @@ -135,7 +136,8 @@ IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale) void TileGrid::prepareGL(GLWebViewState* state, float scale, const IntRect& prepareArea, const IntRect& unclippedArea, - TilePainter* painter, int regionFlags, bool isLowResPrefetch) + TilePainter* painter, int regionFlags, bool isLowResPrefetch, + bool updateWithBlit) { // first, how many tiles do we need m_area = computeTilesArea(prepareArea, scale); @@ -181,11 +183,11 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale, if (goingDown) { for (int j = 0; j < m_area.height(); j++) prepareTile(m_area.x() + i, m_area.y() + j, - painter, state, isLowResPrefetch, false); + painter, state, isLowResPrefetch, false, updateWithBlit); } else { for (int j = m_area.height() - 1; j >= 0; j--) prepareTile(m_area.x() + i, m_area.y() + j, - painter, state, isLowResPrefetch, false); + painter, state, isLowResPrefetch, false, updateWithBlit); } } } @@ -207,7 +209,7 @@ void TileGrid::prepareGL(GLWebViewState* state, float scale, for (int i = expandedArea.x(); i < expandedArea.maxX(); i++) for (int j = expandedArea.y(); j < expandedArea.maxY(); j++) if (!m_area.contains(i, j)) - prepareTile(i, j, painter, state, isLowResPrefetch, true); + prepareTile(i, j, painter, state, isLowResPrefetch, true, updateWithBlit); } } @@ -219,7 +221,8 @@ void TileGrid::markAsDirty(const SkRegion& invalRegion) } void TileGrid::prepareTile(int x, int y, TilePainter* painter, - GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch) + GLWebViewState* state, bool isLowResPrefetch, + bool isExpandPrefetch, bool shouldTryUpdateWithBlit) { Tile* tile = getTile(x, y); if (!tile) { @@ -232,6 +235,9 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter, tile->setContents(x, y, m_scale, isExpandPrefetch); + if (shouldTryUpdateWithBlit && tryBlitFromContents(tile, painter)) + return; + if (tile->isDirty() || !tile->frontTexture()) tile->reserveTexture(); @@ -243,6 +249,15 @@ void TileGrid::prepareTile(int x, int y, TilePainter* painter, } } +bool TileGrid::tryBlitFromContents(Tile* tile, TilePainter* painter) +{ + return tile->frontTexture() + && !tile->frontTexture()->isPureColor() + && tile->frontTexture()->m_ownTextureId + && !tile->isRepaintPending() + && painter->blitFromContents(tile); +} + Tile* TileGrid::getTile(int x, int y) { for (unsigned int i = 0; i <m_tiles.size(); i++) { diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h index 2483e0e..e412979 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h +++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h @@ -51,13 +51,11 @@ public: void prepareGL(GLWebViewState* state, float scale, const IntRect& prepareArea, const IntRect& unclippedArea, TilePainter* painter, int regionFlags = StandardRegion, - bool isLowResPrefetch = false); + bool isLowResPrefetch = false, bool updateWithBlit = false); void swapTiles(); void drawGL(const IntRect& visibleArea, float opacity, const TransformationMatrix* transform, const Color* background = 0); - void prepareTile(int x, int y, TilePainter* painter, - GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch); void markAsDirty(const SkRegion& dirtyArea); Tile* getTile(int x, int y); @@ -67,11 +65,17 @@ public: bool isReady(); bool isMissingContent(); + bool isDirty() { return !m_dirtyRegion.isEmpty(); } int nbTextures(IntRect& area, float scale); private: + void prepareTile(int x, int y, TilePainter* painter, + GLWebViewState* state, bool isLowResPrefetch, + bool isExpandPrefetch, bool shouldTryUpdateWithBlit); void drawMissingRegion(const SkRegion& region, float opacity, const Color* tileBackground); + bool tryBlitFromContents(Tile* tile, TilePainter* painter); + WTF::Vector<Tile*> m_tiles; IntRect m_area; diff --git a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h index 53dfadc..901db66 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h +++ b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h @@ -34,6 +34,7 @@ class SkCanvas; namespace WebCore { class Color; +class Tile; class TilePainter : public SkRefCnt { // TODO: investigate webkit threadsafe ref counting @@ -44,6 +45,7 @@ public: enum SurfaceType { Painted, Image }; virtual SurfaceType type() { return Painted; } virtual Color* background() { return 0; } + virtual bool blitFromContents(Tile* tile) { return false; } unsigned int getUpdateCount() { return m_updateCount; } void setUpdateCount(unsigned int updateCount) { m_updateCount = updateCount; } diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp index 5693d28..6e22d25 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp @@ -471,12 +471,12 @@ bool TilesManager::updateContextIfChanged() return changed; } -float TilesManager::tileWidth() +int TilesManager::tileWidth() { return TILE_WIDTH; } -float TilesManager::tileHeight() +int TilesManager::tileHeight() { return TILE_HEIGHT; } diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h index 834f36d..295acf6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h @@ -87,8 +87,8 @@ public: int currentLayerTextureCount(); void setCurrentTextureCount(int newTextureCount); void setCurrentLayerTextureCount(int newTextureCount); - static float tileWidth(); - static float tileHeight(); + static int tileWidth(); + static int tileHeight(); void allocateTextures(); diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp index df5ba6e..2316014 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp @@ -166,34 +166,14 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex, int textureWidth = destTex->getSize().width(); int textureHeight = destTex->getSize().height(); - IntRect inval = m_transferQueue[index].invalRect; - bool partialInval = !inval.isEmpty(); - - if (partialInval && frontTex) { - // recopy the previous texture to the new one, as - // the partial update will not cover the entire texture - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - frontTex->m_ownTextureId, - 0); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - textureWidth, textureHeight); - } - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcTexId, 0); - if (!partialInval) { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - textureWidth, textureHeight); - } else { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0, - inval.width(), inval.height()); - } + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, + textureWidth, textureHeight); #else // Then set up the FBO and copy the SurfTex content in. @@ -412,8 +392,7 @@ void TransferQueue::updateDirtyTiles() if (m_transferQueue[index].uploadType == CpuUpload) { // Here we just need to upload the bitmap content to the GL Texture GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, - *m_transferQueue[index].bitmap, - m_transferQueue[index].invalRect); + *m_transferQueue[index].bitmap); } else { if (!usedFboForUpload) { saveGLState(); @@ -517,13 +496,6 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo, data->uploadType = type; IntRect inval(0, 0, 0, 0); - if (renderInfo->invalRect) { - inval.setX(renderInfo->invalRect->fLeft); - inval.setY(renderInfo->invalRect->fTop); - inval.setWidth(renderInfo->invalRect->width()); - inval.setHeight(renderInfo->invalRect->height()); - } - data->invalRect = inval; } // Note that there should be lock/unlock around this function call. diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h index fe58336..b8563e3 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h @@ -91,7 +91,6 @@ public: TransferItemStatus status; Tile* savedTilePtr; TileTexture* savedTileTexturePtr; - IntRect invalRect; TextureUploadType uploadType; // This is only useful in Cpu upload code path, so it will be dynamically // lazily allocated. |