summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Roard <nicolas@android.com>2011-03-07 11:14:44 -0800
committerNicolas Roard <nicolasroard@google.com>2011-03-08 18:55:55 -0800
commit67e4aa15702646d5ff50e9524f4e63eb9ed20122 (patch)
tree054c51b8413613ea13248dad4fae47f1bd4f2426
parentdeb796f509e2ad13b4ef4c01b1a1e707b4e762ee (diff)
downloadexternal_webkit-67e4aa15702646d5ff50e9524f4e63eb9ed20122.zip
external_webkit-67e4aa15702646d5ff50e9524f4e63eb9ed20122.tar.gz
external_webkit-67e4aa15702646d5ff50e9524f4e63eb9ed20122.tar.bz2
Partial invalidation of the browser textures
bug:3461349 bug:3464483 Change-Id: I627f06d0fe48aaa0adca65cd13dc738af87eeefc
-rw-r--r--WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp46
-rw-r--r--WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h29
-rw-r--r--WebCore/platform/graphics/android/BaseLayerAndroid.cpp15
-rw-r--r--WebCore/platform/graphics/android/BaseTile.cpp270
-rw-r--r--WebCore/platform/graphics/android/BaseTile.h23
-rw-r--r--WebCore/platform/graphics/android/DoubleBufferedTexture.h5
-rw-r--r--WebCore/platform/graphics/android/GLUtils.cpp21
-rw-r--r--WebCore/platform/graphics/android/GLUtils.h1
-rw-r--r--WebCore/platform/graphics/android/GLWebViewState.cpp26
-rw-r--r--WebCore/platform/graphics/android/GLWebViewState.h6
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.cpp4
-rw-r--r--WebCore/platform/graphics/android/TileSet.h5
-rw-r--r--WebCore/platform/graphics/android/TiledPage.cpp15
-rw-r--r--WebCore/platform/graphics/android/TiledPage.h3
-rw-r--r--WebCore/platform/graphics/android/TilesManager.cpp12
-rw-r--r--WebKit/android/nav/WebView.cpp21
16 files changed, 385 insertions, 117 deletions
diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
index 7cfa480..470ecf1 100644
--- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
+++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp
@@ -42,8 +42,6 @@ BackedDoubleBufferedTexture::BackedDoubleBufferedTexture(uint32_t w, uint32_t h,
SkBitmap* bitmap,
SkBitmap::Config config)
: DoubleBufferedTexture(eglGetCurrentContext())
- , m_x(-1)
- , m_y(-1)
, m_usedLevel(-1)
, m_config(config)
, m_owner(0)
@@ -147,6 +145,21 @@ bool BackedDoubleBufferedTexture::busy()
return m_busy;
}
+bool BackedDoubleBufferedTexture::textureExist(TextureInfo* textureInfo)
+{
+ if (!m_bitmap)
+ return false;
+
+ if (!m_bitmap->width() || !m_bitmap->height())
+ return false;
+
+ if (textureInfo->m_width == m_bitmap->width() &&
+ textureInfo->m_height == m_bitmap->height())
+ return true;
+
+ return false;
+}
+
void BackedDoubleBufferedTexture::producerUpdate(TextureInfo* textureInfo)
{
if (!m_bitmap)
@@ -158,7 +171,7 @@ void BackedDoubleBufferedTexture::producerUpdate(TextureInfo* textureInfo)
return;
}
- if (textureInfo->m_width == m_bitmap->width() && textureInfo->m_height == m_bitmap->height())
+ if (textureExist(textureInfo))
GLUtils::updateTextureWithBitmap(textureInfo->m_textureId, *m_bitmap);
else {
GLUtils::createTextureWithBitmap(textureInfo->m_textureId, *m_bitmap);
@@ -227,4 +240,31 @@ bool BackedDoubleBufferedTexture::release(TextureOwner* owner)
return false;
}
+void BackedDoubleBufferedTexture::setTile(TextureInfo* info, int x, int y,
+ float scale, unsigned int pictureCount)
+{
+ TextureTileInfo* textureInfo = m_texturesInfo.get(getWriteableTexture());
+ if (!textureInfo) {
+ textureInfo = new TextureTileInfo();
+ }
+ textureInfo->m_x = x;
+ textureInfo->m_y = y;
+ textureInfo->m_scale = scale;
+ textureInfo->m_picture = pictureCount;
+ m_texturesInfo.set(getWriteableTexture(), textureInfo);
+}
+
+bool BackedDoubleBufferedTexture::readyFor(BaseTile* baseTile)
+{
+ TextureTileInfo* info = m_texturesInfo.get(getReadableTexture());
+ if (info &&
+ (info->m_x == baseTile->x()) &&
+ (info->m_y == baseTile->y()) &&
+ (info->m_scale == baseTile->scale()) &&
+ (info->m_picture == baseTile->lastPaintedPicture())) {
+ return true;
+ }
+ return false;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
index b1f170b..9c1d245 100644
--- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
+++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h
@@ -37,6 +37,23 @@ namespace WebCore {
class BaseTile;
+class TextureTileInfo {
+ public:
+ TextureTileInfo()
+ : m_x(-1)
+ , m_y(-1)
+ , m_scale(0)
+ , m_texture(0)
+ , m_picture(0)
+ {
+ }
+ int m_x;
+ int m_y;
+ float m_scale;
+ TextureInfo* m_texture;
+ unsigned int m_picture;
+};
+
// DoubleBufferedTexture using a SkBitmap as backing mechanism
class BackedDoubleBufferedTexture : public DoubleBufferedTexture {
public:
@@ -55,6 +72,8 @@ public:
// updates the texture with current bitmap and releases (and if needed also
// swaps) the texture.
virtual void producerUpdate(TextureInfo* textureInfo);
+ void producerUpdate(TextureInfo* textureInfo, SkBitmap* bitmap, SkIRect& rect);
+ bool textureExist(TextureInfo* textureInfo);
// The level can be one of the following values:
// * -1 for an unused texture.
@@ -76,21 +95,21 @@ public:
// private member accessor functions
TextureOwner* owner() { return m_owner; } // only used by the consumer thread
SkCanvas* canvas(); // only used by the producer thread
+ SkBitmap* bitmap() { return m_bitmap; }
bool busy();
void setNotBusy();
const SkSize& getSize() const { return m_size; }
- int x() { return m_x; }
- int y() { return m_y; }
- void setTile(int x, int y) { m_x = x; m_y = y; }
+ void setTile(TextureInfo* info, int x, int y, float scale, unsigned int pictureCount);
+ bool readyFor(BaseTile* baseTile);
private:
void destroyTextures(SharedTexture** textures);
- int m_x;
- int m_y;
+ HashMap<SharedTexture*, TextureTileInfo*> m_texturesInfo;
+
SkBitmap* m_bitmap;
bool m_sharedBitmap;
SkSize m_size;
diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
index 584add1..1f969be 100644
--- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
@@ -159,7 +159,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
bool zooming = false;
if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
- m_glWebViewState->unlockBaseLayerUpdate();
+ prepareNextTiledPage = true;
zooming = true;
}
@@ -168,7 +168,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
TiledPage* nextTiledPage = m_glWebViewState->backPage();
nextTiledPage->setScale(scale);
m_glWebViewState->setFutureViewport(viewportTileBounds);
- m_glWebViewState->unlockBaseLayerUpdate();
+ m_glWebViewState->lockBaseLayerUpdate();
nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
}
@@ -212,7 +212,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
TiledPage* nextTiledPage = m_glWebViewState->backPage();
- // We are now using an hybrid model -- during zooming or scrolling,
+ // We are now using an hybrid model -- during scrolling,
// we will display the current tiledPage even if some tiles are
// out of date. When standing still on the other hand, we wait until
// the back page is ready before swapping the pages, ensuring that the
@@ -232,7 +232,9 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
}
} else {
// Ask for the tiles and draw -- tiles may be out of date.
- m_glWebViewState->unlockBaseLayerUpdate();
+ if (!zooming)
+ m_glWebViewState->unlockBaseLayerUpdate();
+
tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
tiledPage->draw(transparency, preZoomBounds);
}
@@ -245,6 +247,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
if (doSwap) {
m_glWebViewState->setCurrentScale(scale);
m_glWebViewState->swapPages();
+ m_glWebViewState->unlockBaseLayerUpdate();
}
return ret;
@@ -260,8 +263,8 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
int top = viewRect.y();
int width = viewRect.width();
int height = viewRect.height();
- XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d",
- left, top, width, height);
+ XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
+ left, top, width, height, scale);
m_glWebViewState->setBackgroundColor(color);
glClearColor((float)m_color.red() / 255.0,
diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp
index 9499870..47be13b 100644
--- a/WebCore/platform/graphics/android/BaseTile.cpp
+++ b/WebCore/platform/graphics/android/BaseTile.cpp
@@ -67,11 +67,15 @@ BaseTile::BaseTile()
, m_dirty(true)
, m_usable(true)
, m_lastDirtyPicture(0)
+ , m_fullRepaintA(true)
+ , m_fullRepaintB(true)
+ , m_painting(false)
, m_lastPaintedPicture(0)
{
#ifdef DEBUG_COUNT
ClassTracker::instance()->increment("BaseTile");
#endif
+ m_currentDirtyArea = &m_dirtyAreaA;
}
BaseTile::~BaseTile()
@@ -100,11 +104,12 @@ void BaseTile::reserveTexture()
BackedDoubleBufferedTexture* texture = TilesManager::instance()->getAvailableTexture(this);
android::AutoMutex lock(m_atomicSync);
- if (m_texture != texture) {
+ if (texture && !m_painting &&
+ m_texture != texture) {
m_lastPaintedPicture = 0;
- m_dirty = true;
+ fullInval();
+ m_texture = texture;
}
- m_texture = texture;
}
bool BaseTile::removeTexture(BackedDoubleBufferedTexture* texture)
@@ -112,25 +117,39 @@ bool BaseTile::removeTexture(BackedDoubleBufferedTexture* texture)
XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page);
// We update atomically, so paintBitmap() can see the correct value
android::AutoMutex lock(m_atomicSync);
+ if (m_painting)
+ return false;
if (m_texture == texture)
m_texture = 0;
return true;
}
+void BaseTile::fullInval()
+{
+ m_dirtyAreaA.setEmpty();
+ m_dirtyAreaB.setEmpty();
+ m_fullRepaintA = true;
+ m_fullRepaintB = true;
+ m_dirty = true;
+}
+
void BaseTile::setScale(float scale)
{
android::AutoMutex lock(m_atomicSync);
- if (m_scale != scale)
- m_dirty = true;
- m_scale = scale;
+ if (m_scale != scale) {
+ m_scale = scale;
+ fullInval();
+ }
}
-void BaseTile::markAsDirty(int unsigned pictureCount)
+void BaseTile::markAsDirty(int unsigned pictureCount,
+ const SkRegion& dirtyArea)
{
android::AutoMutex lock(m_atomicSync);
m_lastDirtyPicture = pictureCount;
- if (m_lastPaintedPicture < m_lastDirtyPicture)
- m_dirty = true;
+ m_dirtyAreaA.op(dirtyArea, SkRegion::kUnion_Op);
+ m_dirtyAreaB.op(dirtyArea, SkRegion::kUnion_Op);
+ m_dirty = true;
}
void BaseTile::setUsable(bool usable)
@@ -154,6 +173,9 @@ void BaseTile::setUsedLevel(int usedLevel)
void BaseTile::draw(float transparency, SkRect& rect)
{
+ if (m_x < 0 || m_y < 0)
+ return;
+
// No need to mutex protect reads of m_texture as it is only written to by
// the consumer thread.
if (!m_texture) {
@@ -175,9 +197,6 @@ void BaseTile::draw(float transparency, SkRect& rect)
return;
}
- if (m_texture->x() != m_x || m_texture->y() != m_y)
- return;
-
TextureInfo* textureInfo = m_texture->consumerLock();
if (!textureInfo) {
XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y());
@@ -185,9 +204,11 @@ void BaseTile::draw(float transparency, SkRect& rect)
return;
}
- TilesManager::instance()->shader()->drawQuad(rect, textureInfo->m_textureId,
- transparency);
-
+ if (m_texture->readyFor(this)) {
+ XLOG("draw tile %d, %d, %.2f with texture %x", x(), y(), scale(), m_texture);
+ TilesManager::instance()->shader()->drawQuad(rect, textureInfo->m_textureId,
+ transparency);
+ }
m_texture->consumerRelease();
}
@@ -199,21 +220,33 @@ bool BaseTile::isTileReady()
return false;
android::AutoMutex lock(m_atomicSync);
- return !m_dirty;
+ if (m_dirty)
+ return false;
+
+ m_texture->consumerLock();
+ bool ready = m_texture->readyFor(this);
+ m_texture->consumerRelease();
+
+ if (ready)
+ return true;
+
+ m_dirty = true;
+ return false;
}
void BaseTile::drawTileInfo(SkCanvas* canvas,
BackedDoubleBufferedTexture* texture,
- int x, int y, float scale)
+ int x, int y, float scale,
+ int pictureCount)
{
SkPaint paint;
char str[256];
- snprintf(str, 256, "(%d,%d) %.2f, tile %x, texture: %x",
- x, y, scale, this, texture);
+ snprintf(str, 256, "(%d,%d) %.2f, tl%x tx%x p%x c%x",
+ x, y, scale, this, texture, m_page, pictureCount);
paint.setARGB(255, 0, 0, 0);
- canvas->drawText(str, strlen(str), 50, 100, paint);
+ canvas->drawText(str, strlen(str), 0, 10, paint);
paint.setARGB(255, 255, 0, 0);
- canvas->drawText(str, strlen(str), 51, 101, paint);
+ canvas->drawText(str, strlen(str), 0, 11, paint);
}
// This is called from the texture generation thread
@@ -226,11 +259,15 @@ void BaseTile::paintBitmap()
m_atomicSync.lock();
bool dirty = m_dirty;
BackedDoubleBufferedTexture* texture = m_texture;
+ SkRegion dirtyArea = *m_currentDirtyArea;
+ m_painting = true;
float scale = m_scale;
m_atomicSync.unlock();
- if (!dirty || !texture)
+ if (!dirty || !texture) {
+ m_painting = false;
return;
+ }
const int x = m_x;
const int y = m_y;
@@ -243,6 +280,7 @@ void BaseTile::paintBitmap()
// transferred to another BaseTile under us)
if (texture->owner() != this || texture->usedLevel() > 1) {
texture->producerRelease();
+ m_painting = false;
return;
}
@@ -255,70 +293,160 @@ void BaseTile::paintBitmap()
float h = tileHeight * invScale;
SkCanvas* canvas;
+ unsigned int pictureCount = 0;
+
+ SkRegion::Iterator cliperator(dirtyArea);
+
+ bool fullRepaint = false;
+ if (((m_currentDirtyArea == &m_dirtyAreaA) && m_fullRepaintA) ||
+ ((m_currentDirtyArea == &m_dirtyAreaB) && m_fullRepaintB))
+ fullRepaint = true;
+
+ if (fullRepaint) {
+ SkIRect rect;
+ pictureCount = paintPartialBitmap(rect, 0, 0, scale, texture,
+ textureInfo, tiledPage, true);
+ } else {
+ while (!cliperator.done()) {
+ SkRect dirtyRect;
+ dirtyRect.set(cliperator.rect());
+
+ SkRect tileRect;
+ tileRect.fLeft = x * tileWidth / scale;
+ tileRect.fTop = y * tileHeight / scale;
+ tileRect.fRight = tileRect.fLeft + (tileWidth / scale);
+ tileRect.fBottom = tileRect.fTop + (tileHeight / scale);
+
+ if (!tileRect.intersect(dirtyRect)) {
+ cliperator.next();
+ continue;
+ }
+
+ // recompute the rect to corresponds to pixels
+ SkRect realTileRect;
+ realTileRect.fLeft = floorf(tileRect.fLeft * scale);
+ realTileRect.fTop = floorf(tileRect.fTop * scale);
+ realTileRect.fRight = ceilf(tileRect.fRight * scale);
+ realTileRect.fBottom = ceilf(tileRect.fBottom * scale);
+
+ SkIRect finalRealRect;
+ finalRealRect.fLeft = static_cast<int>(realTileRect.fLeft) % static_cast<int>(tileWidth);
+ finalRealRect.fTop = static_cast<int>(realTileRect.fTop) % static_cast<int>(tileHeight);
+ finalRealRect.fRight = finalRealRect.fLeft + realTileRect.width();
+ finalRealRect.fBottom = finalRealRect.fTop + realTileRect.height();
+
+ // the canvas translate can be recomputed accounting for the scale
+ float tx = - realTileRect.fLeft / scale;
+ float ty = - realTileRect.fTop / scale;
+
+ pictureCount = paintPartialBitmap(finalRealRect, tx, ty, scale, texture,
+ textureInfo, tiledPage);
+
+ cliperator.next();
+ }
+ }
+ XLOG("%x update texture %x for tile %d, %d scale %.2f (m_scale: %.2f)", this, textureInfo, x, y, scale, m_scale);
-#ifdef USE_SKIA_GPU
- GLuint fboId;
- glGenFramebuffersEXT(1, &fboId);
- glBindFramebuffer(GL_FRAMEBUFFER, fboId);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureInfo->m_textureId, 0);
- glCheckFramebufferStatus(GL_FRAMEBUFFER)); // should return GL_FRAMEBUFFER_COMPLETE
-
- //Do I need to assign a width/height/format?
-
- GrContext* context = gr_get_global_ctx();
- context->resetContext();
- GrRenderTarget* target = context->createPlatformRenderTarget(fboId, tileWidth, tileHeight);
- SkCanvas tmpCanvas;
- SkDevice* device = new SkGpuDevice(context, bm, target);
- tmpCanvas.setDevice(device)->unref();
- canvas = &tmpCanvas;
-#else
- canvas = texture->canvas();
-#endif
+ m_atomicSync.lock();
+ texture->setTile(textureInfo, x, y, scale, pictureCount);
+ texture->producerReleaseAndSwap();
+
+ m_lastPaintedPicture = pictureCount;
- canvas->save();
- canvas->drawColor(tiledPage->glWebViewState()->getBackgroundColor());
- canvas->scale(scale, scale);
- canvas->translate(-x * w, -y * h);
+ // set the fullrepaint flags
- unsigned int pictureCount = tiledPage->paintBaseLayerContent(canvas);
+ if ((m_currentDirtyArea == &m_dirtyAreaA) && m_fullRepaintA)
+ m_fullRepaintA = false;
- canvas->restore();
+ if ((m_currentDirtyArea == &m_dirtyAreaB) && m_fullRepaintB)
+ m_fullRepaintB = false;
+
+ // The various checks to see if we are still dirty...
+
+ m_dirty = false;
+
+ if (m_scale != scale)
+ m_dirty = true;
+
+ if (!fullRepaint)
+ m_currentDirtyArea->op(dirtyArea, SkRegion::kDifference_Op);
+
+ if (!m_currentDirtyArea->isEmpty())
+ m_dirty = true;
+
+ // Now we can swap the dirty areas
+
+ m_currentDirtyArea = m_currentDirtyArea == &m_dirtyAreaA ? &m_dirtyAreaB : &m_dirtyAreaA;
+
+ if (!m_currentDirtyArea->isEmpty())
+ m_dirty = true;
+
+ m_painting = false;
+
+ m_atomicSync.unlock();
+}
+
+int BaseTile::paintPartialBitmap(SkIRect r, float ptx, float pty,
+ float scale, BackedDoubleBufferedTexture* texture,
+ TextureInfo* textureInfo,
+ TiledPage* tiledPage, bool fullRepaint)
+{
+ SkIRect rect = r;
+ float tx = ptx;
+ float ty = pty;
+ if (!texture->textureExist(textureInfo)) {
+ fullRepaint = true;
+ }
+
+ if (fullRepaint) {
+ rect.set(0, 0, TilesManager::instance()->tileWidth(),
+ TilesManager::instance()->tileHeight());
+ tx = - x() * TilesManager::instance()->tileWidth() / scale;
+ ty = - y() * TilesManager::instance()->tileHeight() / scale;
+ }
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+
+ SkCanvas canvas(bitmap);
+ canvas.drawARGB(255, 255, 255, 255);
+
+ canvas.save();
+ canvas.scale(scale, scale);
+ canvas.translate(tx, ty);
+ int pictureCount = tiledPage->paintBaseLayerContent(&canvas);
+ canvas.restore();
if (TilesManager::instance()->getShowVisualIndicator()) {
+ int color = 20 + pictureCount % 100;
+ canvas.drawARGB(color, 0, 255, 0);
+
SkPaint paint;
paint.setARGB(128, 255, 0, 0);
paint.setStrokeWidth(3);
- canvas->drawLine(0, 0, tileWidth, tileHeight, paint);
+ canvas.drawLine(0, 0, rect.width(), rect.height(), paint);
paint.setARGB(128, 0, 255, 0);
- canvas->drawLine(0, tileHeight, tileWidth, 0, paint);
+ canvas.drawLine(0, rect.height(), rect.width(), 0, paint);
paint.setARGB(128, 0, 0, 255);
- canvas->drawLine(0, 0, tileWidth, 0, paint);
- canvas->drawLine(tileWidth, 0, tileWidth, tileHeight, paint);
- drawTileInfo(canvas, texture, x, y, scale);
- }
+ canvas.drawLine(0, 0, rect.width(), 0, paint);
+ canvas.drawLine(rect.width(), 0, rect.width(), rect.height(), paint);
- texture->setTile(x, y);
+ drawTileInfo(&canvas, texture, x(), y(), scale, pictureCount);
+ }
-#ifdef USE_SKIA_GPU
- // set the texture info w/h/format
- textureInfo->m_width = tileWidth;
- textureInfo->m_height = tileHeight;
- texture->producerReleaseAndSwap();
+ if (!texture->textureExist(textureInfo)) {
+ GLUtils::createTextureWithBitmap(textureInfo->m_textureId, bitmap);
+ textureInfo->m_width = rect.width();
+ textureInfo->m_height = rect.height();
+ } else {
+ GLUtils::updateTextureWithBitmap(textureInfo->m_textureId, rect.fLeft, rect.fTop, bitmap);
+ }
- glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
- glDeleteFramebuffers(1, &fboId);
-#else
- texture->producerUpdate(textureInfo);
-#endif
+ bitmap.reset();
- m_atomicSync.lock();
- m_lastPaintedPicture = pictureCount;
- if (m_lastPaintedPicture >= m_lastDirtyPicture) {
- m_dirty = false;
- m_usable = true;
- }
- m_atomicSync.unlock();
+ return pictureCount;
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h
index af7df3a..c50f6f5 100644
--- a/WebCore/platform/graphics/android/BaseTile.h
+++ b/WebCore/platform/graphics/android/BaseTile.h
@@ -29,9 +29,11 @@
#if USE(ACCELERATED_COMPOSITING)
#include "HashMap.h"
+#include "SharedTexture.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkRect.h"
+#include "SkRegion.h"
#include "TextureOwner.h"
#include <EGL/egl.h>
@@ -75,18 +77,26 @@ public:
// the only thread-safe function called by the background thread
void paintBitmap();
+ int paintPartialBitmap(SkIRect rect, float tx, float ty,
+ float scale, BackedDoubleBufferedTexture* texture,
+ TextureInfo* textureInfo,
+ TiledPage* tiledPage,
+ bool fullRepaint = false);
void drawTileInfo(SkCanvas* canvas,
BackedDoubleBufferedTexture* texture,
- int x, int y, float scale);
+ int x, int y, float scale, int pictureCount);
- void markAsDirty(const unsigned int pictureCount);
+ void markAsDirty(const unsigned int pictureCount,
+ const SkRegion& dirtyArea);
bool isDirty();
void setUsable(bool usable);
float scale() const { return m_scale; }
void setScale(float scale);
+ void fullInval();
int x() const { return m_x; }
int y() const { return m_y; }
+ unsigned int lastPaintedPicture() const { return m_lastPaintedPicture; }
BackedDoubleBufferedTexture* texture() { return m_texture; }
// TextureOwner implementation
@@ -110,6 +120,15 @@ private:
// become dirty. A tile is no longer dirty when it has been painted with a
// picture that is newer than this value.
unsigned int m_lastDirtyPicture;
+
+ // store the dirty region
+ SkRegion m_dirtyAreaA;
+ SkRegion m_dirtyAreaB;
+ bool m_fullRepaintA;
+ bool m_fullRepaintB;
+ SkRegion* m_currentDirtyArea;
+ bool m_painting;
+
// stores the id of the latest picture painted to the tile. If the id is 0
// then we know that the picture has not yet been painted an there is nothing
// to display (dirty or otherwise).
diff --git a/WebCore/platform/graphics/android/DoubleBufferedTexture.h b/WebCore/platform/graphics/android/DoubleBufferedTexture.h
index b611c2e..5016332 100644
--- a/WebCore/platform/graphics/android/DoubleBufferedTexture.h
+++ b/WebCore/platform/graphics/android/DoubleBufferedTexture.h
@@ -48,12 +48,13 @@ public:
void consumerRelease();
protected:
+ SharedTexture* getReadableTexture();
+ SharedTexture* getWriteableTexture();
+
SharedTexture m_textureA;
SharedTexture m_textureB;
private:
- SharedTexture* getReadableTexture();
- SharedTexture* getWriteableTexture();
SharedTexture* m_writeableTexture;
SharedTexture* m_lockedConsumerTexture; // only used by the consumer
diff --git a/WebCore/platform/graphics/android/GLUtils.cpp b/WebCore/platform/graphics/android/GLUtils.cpp
index de794cb..23bf525 100644
--- a/WebCore/platform/graphics/android/GLUtils.cpp
+++ b/WebCore/platform/graphics/android/GLUtils.cpp
@@ -361,6 +361,27 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, SkBitmap& bitmap, GLint fi
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
}
+void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, SkBitmap& bitmap, GLint filter)
+{
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ SkBitmap::Config config = bitmap.getConfig();
+ int internalformat = getInternalFormat(config);
+ int type = getType(config);
+ bitmap.lockPixels();
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, bitmap.width(), bitmap.height(),
+ internalformat, type, bitmap.getPixels());
+ bitmap.unlockPixels();
+ if (GLUtils::checkGlError("glTexSubImage2D")) {
+ XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
+ " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
+ bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+}
+
void GLUtils::createEGLImageFromTexture(GLuint texture, EGLImageKHR* image)
{
EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture);
diff --git a/WebCore/platform/graphics/android/GLUtils.h b/WebCore/platform/graphics/android/GLUtils.h
index 3e7b800..64aedbb 100644
--- a/WebCore/platform/graphics/android/GLUtils.h
+++ b/WebCore/platform/graphics/android/GLUtils.h
@@ -62,6 +62,7 @@ public:
static GLuint createSampleTexture();
static void createTextureWithBitmap(GLuint texture, SkBitmap& bitmap, GLint filter = GL_LINEAR);
static void updateTextureWithBitmap(GLuint texture, SkBitmap& bitmap, GLint filter = GL_LINEAR);
+ static void updateTextureWithBitmap(GLuint texture, int x, int y, SkBitmap& bitmap, GLint filter = GL_LINEAR);
static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image);
static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR);
};
diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp
index 20a231c..444ff17 100644
--- a/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -110,7 +110,7 @@ GLWebViewState::~GLWebViewState()
#endif
}
-void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect,
+void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval,
bool showVisualIndicator)
{
android::Mutex::Autolock lock(m_baseLayerLock);
@@ -131,7 +131,7 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect,
SkSafeUnref(m_currentBaseLayer);
m_currentBaseLayer = layer;
}
- inval(rect);
+ invalRegion(inval);
#ifdef MEASURES_PERF
if (m_measurePerfs && !showVisualIndicator)
@@ -142,15 +142,29 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect,
TilesManager::instance()->setShowVisualIndicator(showVisualIndicator);
}
+void GLWebViewState::invalRegion(const SkRegion& region)
+{
+ SkRegion::Iterator iterator(region);
+ while (!iterator.done()) {
+ SkIRect r = iterator.rect();
+ IntRect ir(r.fLeft, r.fTop, r.width(), r.height());
+ inval(ir);
+ iterator.next();
+ }
+}
+
void GLWebViewState::unlockBaseLayerUpdate() {
+ if (m_baseLayerUpdate)
+ return;
+
m_baseLayerUpdate = true;
android::Mutex::Autolock lock(m_baseLayerLock);
SkSafeRef(m_baseLayer);
SkSafeUnref(m_currentBaseLayer);
m_currentBaseLayer = m_baseLayer;
- inval(m_invalidateRect);
- IntRect empty;
- m_invalidateRect = empty;
+
+ invalRegion(m_invalidateRegion);
+ m_invalidateRegion.setEmpty();
}
void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture,
@@ -182,7 +196,7 @@ void GLWebViewState::inval(const IntRect& rect)
m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
}
} else {
- m_invalidateRect.unite(rect);
+ m_invalidateRegion.op(rect.x(), rect.y(), rect.right(), rect.bottom(), SkRegion::kUnion_Op);
}
}
diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h
index b8194f4..3f68757 100644
--- a/WebCore/platform/graphics/android/GLWebViewState.h
+++ b/WebCore/platform/graphics/android/GLWebViewState.h
@@ -32,6 +32,7 @@
#include "IntRect.h"
#include "SkCanvas.h"
#include "SkRect.h"
+#include "SkRegion.h"
#include "TiledPage.h"
#include <utils/threads.h>
@@ -174,7 +175,7 @@ public:
void resetTransitionTime() { m_transitionTime = -1; }
unsigned int paintBaseLayerContent(SkCanvas* canvas);
- void setBaseLayer(BaseLayerAndroid* layer, const IntRect& rect, bool showVisualIndicator);
+ void setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator);
void setExtra(BaseLayerAndroid*, SkPicture&, const IntRect&, bool allowSame);
void scheduleUpdate(const double& currentTime, const SkIRect& viewport, float scale);
@@ -223,6 +224,7 @@ public:
private:
void inval(const IntRect& rect); // caller must hold m_baseLayerLock
+ void invalRegion(const SkRegion& region);
// Delay between scheduling a new page when the scale
// factor changes (i.e. zooming in or out)
@@ -259,7 +261,7 @@ private:
android::Mutex* m_globalButtonMutex;
bool m_baseLayerUpdate;
- IntRect m_invalidateRect;
+ SkRegion m_invalidateRegion;
SkColor m_backgroundColor;
double m_prevDrawTime;
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
index 842637a..714fa40 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -741,9 +741,9 @@ void LayerAndroid::showLayers(int indent)
bool outside = outsideViewport();
if (needsTexture() && !outside) {
- XLOGC("%s Layer %d (%d, %d), cropped to (%d, %d), using %d Mb",
+ XLOGC("%s Layer %d (%.2f, %.2f), cropped to (%d, %d, %d, %d), using %d Mb",
space, uniqueId(), getWidth(), getHeight(),
- cr.width(), cr.height(), size / 1024 / 1024);
+ cr.x(), cr.y(), cr.width(), cr.height(), size / 1024 / 1024);
} else if (needsTexture() && outside) {
XLOGC("%s Layer %d is outside the viewport", space, uniqueId());
} else {
diff --git a/WebCore/platform/graphics/android/TileSet.h b/WebCore/platform/graphics/android/TileSet.h
index 0cb16d0..aa0f2ed 100644
--- a/WebCore/platform/graphics/android/TileSet.h
+++ b/WebCore/platform/graphics/android/TileSet.h
@@ -58,6 +58,11 @@ public:
return m_tiledPage;
}
+ unsigned int size()
+ {
+ return m_tiles.size();
+ }
+
private:
Vector<BaseTile*> m_tiles;
diff --git a/WebCore/platform/graphics/android/TiledPage.cpp b/WebCore/platform/graphics/android/TiledPage.cpp
index 36988dd..a400a4a 100644
--- a/WebCore/platform/graphics/android/TiledPage.cpp
+++ b/WebCore/platform/graphics/android/TiledPage.cpp
@@ -129,6 +129,7 @@ void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureC
// We defer marking the tile as dirty until the next time we need to prepare
// to draw.
m_invalRegion.op(firstDirtyTileX, firstDirtyTileY, lastDirtyTileX, lastDirtyTileY, SkRegion::kUnion_Op);
+ m_invalTilesRegion.op(inval.x(), inval.y(), inval.right(), inval.bottom(), SkRegion::kUnion_Op);
m_latestPictureInval = pictureCount;
}
@@ -183,11 +184,12 @@ void TiledPage::updateTileState(const SkIRect& tileBounds)
{
if (!m_glWebViewState || tileBounds.isEmpty()) {
m_invalRegion.setEmpty();
+ m_invalTilesRegion.setEmpty();
return;
}
- const int nbTilesWidth = tileBounds.width();
- const int nbTilesHeight = tileBounds.height();
+ const int nbTilesWidth = tileBounds.width() - 1;
+ const int nbTilesHeight = tileBounds.height() - 1;
const int lastTileX = tileBounds.fRight - 1;
const int lastTileY = tileBounds.fBottom - 1;
@@ -196,14 +198,14 @@ void TiledPage::updateTileState(const SkIRect& tileBounds)
BaseTile& tile = m_baseTiles[x];
+ // if the tile is in the dirty region then we must invalidate it
+ if (m_invalRegion.contains(tile.x(), tile.y()))
+ tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion);
+
// if the tile no longer has a texture then proceed to the next tile
if (tile.isAvailable())
continue;
- // if the tile is in the dirty region then we must invalidate it
- if (m_invalRegion.contains(tile.x(), tile.y()))
- tile.markAsDirty(m_latestPictureInval);
-
// set the used level of the tile (e.g. distance from the viewport)
int dx = 0;
int dy = 0;
@@ -226,6 +228,7 @@ void TiledPage::updateTileState(const SkIRect& tileBounds)
// clear the invalidated region as all tiles within that region have now
// been marked as dirty.
m_invalRegion.setEmpty();
+ m_invalTilesRegion.setEmpty();
}
void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds)
diff --git a/WebCore/platform/graphics/android/TiledPage.h b/WebCore/platform/graphics/android/TiledPage.h
index e449107..9eb9f11 100644
--- a/WebCore/platform/graphics/android/TiledPage.h
+++ b/WebCore/platform/graphics/android/TiledPage.h
@@ -97,6 +97,9 @@ private:
// terms of the (x,y) coordinates used to determine the location of the tile
// within the page, not in content/view pixel coordinates.
SkRegion m_invalRegion;
+
+ // inval regions in content coordinates
+ SkRegion m_invalTilesRegion;
unsigned int m_latestPictureInval;
bool m_prepare;
};
diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp
index 16fb782..0cb30d2 100644
--- a/WebCore/platform/graphics/android/TilesManager.cpp
+++ b/WebCore/platform/graphics/android/TilesManager.cpp
@@ -56,10 +56,10 @@
// second page used when scaling.
// In our case, we use 300x300 textures. On the tablet, this equates to
// at least 5 * 3 = 15 textures. We also enable offscreen textures to a maximum
-// of 154 textures used (i.e. ~106Mb max, accounting for the double buffer textures)
+// of 101 textures used (i.e. ~70Mb max, accounting for the double buffer textures)
#define EXPANDED_TILE_BOUNDS_X 1
-#define EXPANDED_TILE_BOUNDS_Y 4
-#define MAX_TEXTURE_ALLOCATION (5+EXPANDED_TILE_BOUNDS_X*2)*(3+EXPANDED_TILE_BOUNDS_Y*2)*2
+#define EXPANDED_TILE_BOUNDS_Y 2
+#define MAX_TEXTURE_ALLOCATION 3+(5+EXPANDED_TILE_BOUNDS_X*2)*(3+EXPANDED_TILE_BOUNDS_Y*2)*2
#define TILE_WIDTH 300
#define TILE_HEIGHT 300
@@ -162,7 +162,8 @@ BackedDoubleBufferedTexture* TilesManager::getAvailableTexture(BaseTile* owner)
// Sanity check that the tile does not already own a texture
if (owner->texture() && owner->texture()->owner() == owner) {
owner->texture()->setUsedLevel(0);
- XLOG("same owner, getAvailableTexture(%x) => texture %x", owner, owner->texture());
+ XLOG("same owner (%d, %d), getAvailableTexture(%x) => texture %x",
+ owner->x(), owner->y(), owner, owner->texture());
return owner->texture();
}
@@ -314,8 +315,10 @@ void TilesManager::cleanupLayersTextures(LayerAndroid* layer, bool forceCleanup)
i++;
}
}
+#ifdef DEBUG
printLayersTextures("after cleanup");
XLOG("after cleanup, memory %d", m_layersMemoryUsage);
+#endif
}
LayerTexture* TilesManager::createTextureForLayer(LayerAndroid* layer, const IntRect& rect)
@@ -414,6 +417,7 @@ TilesManager* TilesManager::instance()
{
if (!gInstance) {
gInstance = new TilesManager();
+ XLOG("instance(), new gInstance is %x", gInstance);
XLOG("Waiting for the generator...");
gInstance->waitForGenerator();
XLOG("Generator ready!");
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 6c7b2d3..6bf5558 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -437,8 +437,11 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
if (!m_glWebViewState) {
m_glWebViewState = new GLWebViewState(&m_viewImpl->gButtonMutex);
if (m_baseLayer->content()) {
- IntRect rect(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
- m_glWebViewState->setBaseLayer(m_baseLayer, rect, false);
+ SkRegion region;
+ SkIRect rect;
+ rect.set(0, 0, m_baseLayer->content()->width(), m_baseLayer->content()->height());
+ region.setRect(rect);
+ m_glWebViewState->setBaseLayer(m_baseLayer, region, false);
}
}
@@ -1383,11 +1386,11 @@ static void copyScrollPositionRecursive(const LayerAndroid* from,
}
#endif
-void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect, bool showVisualIndicator)
+void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndicator)
{
#if USE(ACCELERATED_COMPOSITING)
if (m_glWebViewState)
- m_glWebViewState->setBaseLayer(layer, rect, showVisualIndicator);
+ m_glWebViewState->setBaseLayer(layer, inval, showVisualIndicator);
#endif
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
@@ -1797,12 +1800,14 @@ static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
return false;
}
-static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject jrect,
+static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inval,
jboolean showVisualIndicator)
{
BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
- WebCore::IntRect rect = jrect_to_webrect(env, jrect);
- GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, rect, showVisualIndicator);
+ SkRegion invalRegion;
+ if (inval)
+ invalRegion = *GraphicsJNI::getNativeRegion(env, inval);
+ GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, invalRegion, showVisualIndicator);
}
static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
@@ -2594,7 +2599,7 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetFindIsUp },
{ "nativeSetHeightCanMeasure", "(Z)V",
(void*) nativeSetHeightCanMeasure },
- { "nativeSetBaseLayer", "(ILandroid/graphics/Rect;Z)V",
+ { "nativeSetBaseLayer", "(ILandroid/graphics/Region;Z)V",
(void*) nativeSetBaseLayer },
{ "nativeReplaceBaseContent", "(I)V",
(void*) nativeReplaceBaseContent },