diff options
author | Nicolas Roard <nicolas@android.com> | 2011-03-07 11:14:44 -0800 |
---|---|---|
committer | Nicolas Roard <nicolasroard@google.com> | 2011-03-08 18:55:55 -0800 |
commit | 67e4aa15702646d5ff50e9524f4e63eb9ed20122 (patch) | |
tree | 054c51b8413613ea13248dad4fae47f1bd4f2426 | |
parent | deb796f509e2ad13b4ef4c01b1a1e707b4e762ee (diff) | |
download | external_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.cpp | 46 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h | 29 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/BaseLayerAndroid.cpp | 15 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/BaseTile.cpp | 270 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/BaseTile.h | 23 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/DoubleBufferedTexture.h | 5 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GLUtils.cpp | 21 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GLUtils.h | 1 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GLWebViewState.cpp | 26 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/GLWebViewState.h | 6 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/LayerAndroid.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/TileSet.h | 5 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/TiledPage.cpp | 15 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/TiledPage.h | 3 | ||||
-rw-r--r-- | WebCore/platform/graphics/android/TilesManager.cpp | 12 | ||||
-rw-r--r-- | WebKit/android/nav/WebView.cpp | 21 |
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 }, |