diff options
author | Nicolas Roard <nicolasroard@google.com> | 2012-01-31 18:06:15 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-01-31 18:06:15 -0800 |
commit | 862a02dd939461195b9994e829ef1207801f0ea3 (patch) | |
tree | 819d1b549d4c08bf3e1263351d360ed84d3fc399 /Source/WebCore/platform/graphics/android | |
parent | 82921a8052f869822cbd9fb6d54750c480ac9054 (diff) | |
parent | c048426c23be795d3bf870e47429167b4157a2d6 (diff) | |
download | external_webkit-862a02dd939461195b9994e829ef1207801f0ea3.zip external_webkit-862a02dd939461195b9994e829ef1207801f0ea3.tar.gz external_webkit-862a02dd939461195b9994e829ef1207801f0ea3.tar.bz2 |
Merge "Partial repaint implementation"
Diffstat (limited to 'Source/WebCore/platform/graphics/android')
8 files changed, 165 insertions, 72 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp index 57baee8..b708ad1 100644 --- a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp @@ -141,7 +141,13 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo) // only color the invalidated area SkPaint invalPaint; invalPaint.setARGB(color, 0, 255, 0); - canvas.drawIRect(*renderInfo.invalRect, invalPaint); + if (renderInfo.invalRect) + canvas.drawIRect(*renderInfo.invalRect, invalPaint); + else { + SkIRect rect; + rect.set(0, 0, tileSize.width(), tileSize.height()); + canvas.drawIRect(rect, invalPaint); + } // paint the tile boundaries SkPaint paint; @@ -154,6 +160,18 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo) canvas.drawLine(0, 0, tileSize.width(), 0, paint); canvas.drawLine(tileSize.width(), 0, tileSize.width(), tileSize.height(), 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); + } + if (renderInfo.measurePerf) drawTileInfo(&canvas, renderInfo, pictureCount); } diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 76ee1e7..42d02a5 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -54,6 +54,13 @@ #endif // DEBUG +// If the dirty portion of a tile exceeds this ratio, fully repaint. +// Lower values give fewer partial repaints, thus fewer front-to-back +// texture copies (cost will vary by device). It's a tradeoff between +// the rasterization cost and the FBO texture recopy cost when using +// GPU for the transfer queue. +#define MAX_INVAL_AREA 0.6 + namespace WebCore { BaseTile::BaseTile(bool isLayerTile) @@ -369,55 +376,65 @@ void BaseTile::paintBitmap() fullRepaint = true; } - // With SurfaceTexture, just repaint the entire tile if we intersect. - // TODO: Implement the partial invalidate in Surface Texture Mode. - // Such that the code of partial invalidation below is preserved. + // For now, only do full repaint fullRepaint = true; - 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; + 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; + } } - // 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; + cliperator.next(); + } - renderInfo.invalRect = &finalRealRect; + if (!fullRepaint) { + renderInfo.invalRect = &totalRect; renderInfo.measurePerf = false; - pictureCount = m_renderer->renderTiledContent(renderInfo); } - - cliperator.next(); } // Do a full repaint if needed if (fullRepaint) { - SkIRect rect; - rect.set(0, 0, tileWidth, tileHeight); - - renderInfo.invalRect = ▭ + renderInfo.invalRect = 0; renderInfo.measurePerf = TilesManager::instance()->getShowVisualIndicator(); - pictureCount = m_renderer->renderTiledContent(renderInfo); } diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h index 55314c7..67eeeb9 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h @@ -60,6 +60,7 @@ public: TilePainter* m_painter; unsigned int m_picture; bool m_inverted; + IntRect m_inval; }; class BaseTileTexture { diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index efd611b..39d8755 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -36,12 +36,14 @@ #include <wtf/CurrentTime.h> #include <wtf/text/CString.h> - -#ifdef DEBUG - #include <cutils/log.h> #include <wtf/text/CString.h> +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__) + +#ifdef DEBUG + #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__) @@ -425,6 +427,10 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, bool skipTransfer = false; BaseTile* tilePtr = renderInfo->baseTile; + // TODO: use pure color for partial invals as well + if (renderInfo->invalRect) + return false; + if (tilePtr) { BaseTileTexture* tileTexture = tilePtr->backTexture(); // Check the bitmap, and make everything ready here. @@ -450,8 +456,6 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, { if (!renderInfo) return; - const int x = renderInfo->invalRect->fLeft; - const int y = renderInfo->invalRect->fTop; const SkSize& requiredSize = renderInfo->tileSize; TextureInfo* textureInfo = renderInfo->textureInfo; @@ -459,14 +463,14 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, return; if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); else { if (!requiredSize.equals(bitmap.width(), bitmap.height())) { XLOG("The bitmap size (%d,%d) does not equal the texture size (%d,%d)", bitmap.width(), bitmap.height(), requiredSize.width(), requiredSize.height()); } - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap); + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); textureInfo->m_width = bitmap.width(); textureInfo->m_height = bitmap.height(); @@ -474,14 +478,14 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, } } -void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap) +void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) { if (!renderInfo || !renderInfo->textureInfo || !renderInfo->baseTile) return; - TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, x, y, bitmap); + TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, bitmap); } void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter) @@ -515,7 +519,8 @@ void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GL glDeleteFramebuffers(1, &fboID); } -void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter) +void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, + const IntRect& inval, GLint filter) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, texture); @@ -524,13 +529,18 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitm 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()); + if (inval.isEmpty()) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), + internalformat, type, bitmap.getPixels()); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), inval.width(), inval.height(), + internalformat, type, bitmap.getPixels()); + } bitmap.unlockPixels(); if (GLUtils::checkGlError("glTexSubImage2D")) { XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d," - " x %d, y %d, internalformat 0x%x, type 0x%x, bitmap.getPixels() %p", - bitmap.width(), bitmap.height(), x, y, internalformat, type, bitmap.getPixels()); + " 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); diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index 3475760..b198d35 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -74,12 +74,12 @@ public: static GLuint createBaseTileGLTexture(int width, int height); static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); + static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR); static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); - static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); + static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor); diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp index 0c92de4..4b6d2de 100644 --- a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp @@ -112,8 +112,14 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can device->unref(); - // ensure the canvas origin is translated to the coordinates of our inval rect - canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop); + // 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) diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index 56d79a1..e97e1a1 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -162,20 +162,46 @@ bool TransferQueue::checkObsolete(const TileTransferData* data) } void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, + BaseTileTexture* frontTex, GLuint srcTexId, GLenum srcTexTarget, int index) { #if GPU_UPLOAD_WITHOUT_DRAW glBindFramebuffer(GL_FRAMEBUFFER, fboID); + glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId); + + int textureWidth = destTex->getSize().width(); + int textureHeight = destTex->getSize().height(); + + IntRect inval = m_transferQueue[index].tileInfo.m_inval; + 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); - glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, - destTex->getSize().width(), - destTex->getSize().height()); + + 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()); + } + #else // Then set up the FBO and copy the SurfTex content in. glBindFramebuffer(GL_FRAMEBUFFER, fboID); @@ -356,8 +382,14 @@ void TransferQueue::updateDirtyBaseTiles() // Save the needed info, update the Surf Tex, clean up the item in // the queue. Then either move on to next item or copy the content. BaseTileTexture* destTexture = 0; - if (!obsoleteBaseTile) + BaseTileTexture* frontTexture = 0; + if (!obsoleteBaseTile) { destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); + // while destTexture is guaranteed to not be null, frontTexture + // might be (first transfer) + frontTexture = m_transferQueue[index].savedBaseTilePtr->frontTexture(); + } + if (m_transferQueue[index].uploadType == GpuUpload) { status_t result = m_sharedSurfaceTexture->updateTexImage(); if (result != OK) @@ -376,14 +408,15 @@ void TransferQueue::updateDirtyBaseTiles() if (m_transferQueue[index].uploadType == CpuUpload) { // Here we just need to upload the bitmap content to the GL Texture - GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0, - *m_transferQueue[index].bitmap); + GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, + *m_transferQueue[index].bitmap, + m_transferQueue[index].tileInfo.m_inval); } else { if (!usedFboForUpload) { saveGLState(); usedFboForUpload = true; } - blitTileFromQueue(m_fboID, destTexture, + blitTileFromQueue(m_fboID, destTexture, frontTexture, m_sharedSurfaceTextureId, m_sharedSurfaceTexture->getCurrentTextureTarget(), index); @@ -420,9 +453,9 @@ void TransferQueue::updateDirtyBaseTiles() } void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, - int x, int y, const SkBitmap& bitmap) + const SkBitmap& bitmap) { - if (!tryUpdateQueueWithBitmap(renderInfo, x, y, bitmap)) { + if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) { // failed placing bitmap in queue, discard tile's texture so it will be // re-enqueued (and repainted) BaseTile* tile = renderInfo->baseTile; @@ -432,7 +465,7 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, } bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, - int x, int y, const SkBitmap& bitmap) + const SkBitmap& bitmap) { // This lock need to cover the full update since it is possible that queue // will be cleaned up in the middle of this update without the lock. @@ -462,9 +495,10 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, int bpp = 4; // Now we only deal with RGBA8888 format. int width = TilesManager::instance()->tileWidth(); int height = TilesManager::instance()->tileHeight(); - if (!x && !y && bitmap.width() == width && bitmap.height() == height) { + if (bitmap.width() == width && bitmap.height() == height) { bitmap.lockPixels(); uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels()); + if (buffer.stride != bitmap.width()) // Copied line by line since we need to handle the offsets and stride. for (row = 0 ; row < bitmap.height(); row ++) { @@ -476,9 +510,6 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height()); bitmap.unlockPixels(); - } else { - // TODO: implement the partial invalidate here! - XLOG("ERROR: don't expect to get here yet before we support partial inval"); } ANativeWindow_unlockAndPost(m_ANW.get()); @@ -517,6 +548,15 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo, // Now fill the tileInfo. TextureTileInfo* textureInfo = &(data->tileInfo); + 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()); + } + textureInfo->m_inval = inval; + textureInfo->m_x = renderInfo->x; textureInfo->m_y = renderInfo->y; textureInfo->m_scale = renderInfo->scale; diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.h b/Source/WebCore/platform/graphics/android/TransferQueue.h index a18d448..ec3e5e2 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.h +++ b/Source/WebCore/platform/graphics/android/TransferQueue.h @@ -119,7 +119,7 @@ public: void initGLResources(int width, int height); // insert the bitmap into the queue, mark the tile dirty if failing - void updateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y, + void updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); void addItemInTransferQueue(const TileRenderInfo* info, @@ -151,7 +151,7 @@ public: private: // return true if successfully inserted into queue - bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y, + bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); bool getHasGLContext(); void setHasGLContext(bool hasContext); @@ -172,6 +172,7 @@ private: void cleanupPendingDiscard(); void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, + BaseTileTexture* frontTex, GLuint srcTexId, GLenum srcTexTarget, int index); |