diff options
Diffstat (limited to 'WebCore/platform/graphics/android/BaseTile.cpp')
-rw-r--r-- | WebCore/platform/graphics/android/BaseTile.cpp | 270 |
1 files changed, 199 insertions, 71 deletions
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 |