diff options
author | John Reck <jreck@google.com> | 2012-04-27 08:13:38 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2012-05-02 16:13:16 -0700 |
commit | e859a34171f2a36877d95197d118d962078f8aa0 (patch) | |
tree | 3c8b592536fa193bcb468c03e5f318c7d0edcf8e /Source/WebCore/platform/graphics/android/rendering/Surface.cpp | |
parent | 8a3e157baecb453158df1f7bc81bfb4704448b2e (diff) | |
download | external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.zip external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.gz external_webkit-e859a34171f2a36877d95197d118d962078f8aa0.tar.bz2 |
Rewrite PictureSet with TURBO!
This changes how partial invals are done by adding a hybrid mode.
What we used to do is generate a SkPicture for the new area. This
SkPicture would possibly be larger than the actual inval, depending
on various merge rules (more SkPictures == slower to draw a tile)
The new code rewrites PictureSet entirely, preserving many of the old rules
but cleans up the code and adds the concept of a "PrerenderedInval". This is
a partial inval that WebKit has rasterized. By having WebKit produce both
a SkPicture and a SkBitmap, we avoid needing to play back the picture and
avoid overdrawing. We take this SkBitmap, and simply update the front
textures with it. This gives us full partial invals through the entire
system without hitting any driver bugs, and with minimal copies. And while
the SkPicture may be larger than the inval, the SkBitmap that is rasterized
is not - it matches the area webkit has said is dirty.
Change-Id: Ieb7ecc9db0d4f679102fda004a43399f9b319ebc
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering/Surface.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/android/rendering/Surface.cpp | 98 |
1 files changed, 92 insertions, 6 deletions
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 |