From 7c554a61cb935660cdc86905d040c781b490150f Mon Sep 17 00:00:00 2001 From: Teng-Hui Zhu Date: Mon, 1 Aug 2011 11:32:58 -0700 Subject: Shared surface texture Instead of assigning each tile a Surface Texture, now just a normal GL texture. The content from skia bitmap will first drawn into a queue of Surface Textures, at draw time, blit them into each tile's GL texture. Added extra lock to protect the queue operation and Surface Texture operation. bug:5044597 Change-Id: I25f46228b93a3e99526daf52d8bd0d8d8fcc2879 --- Source/WebCore/Android.mk | 1 + .../platform/graphics/android/BaseRenderer.cpp | 2 +- .../WebCore/platform/graphics/android/BaseTile.cpp | 26 +- .../platform/graphics/android/BaseTileTexture.cpp | 50 ++- .../platform/graphics/android/BaseTileTexture.h | 66 +++- .../WebCore/platform/graphics/android/GLUtils.cpp | 154 +++++++- Source/WebCore/platform/graphics/android/GLUtils.h | 12 +- .../platform/graphics/android/GLWebViewState.cpp | 10 +- .../platform/graphics/android/LayerAndroid.cpp | 6 +- .../platform/graphics/android/RasterRenderer.cpp | 3 +- .../platform/graphics/android/ShaderProgram.cpp | 13 +- .../platform/graphics/android/SharedTexture.cpp | 6 + .../platform/graphics/android/TextureInfo.cpp | 3 + .../platform/graphics/android/TextureInfo.h | 9 +- .../platform/graphics/android/TiledTexture.cpp | 8 +- .../platform/graphics/android/TilesManager.cpp | 14 +- .../platform/graphics/android/TilesManager.h | 5 +- .../platform/graphics/android/TransferQueue.cpp | 403 +++++++++++++++++++++ .../platform/graphics/android/TransferQueue.h | 126 +++++++ 19 files changed, 848 insertions(+), 69 deletions(-) create mode 100644 Source/WebCore/platform/graphics/android/TransferQueue.cpp create mode 100644 Source/WebCore/platform/graphics/android/TransferQueue.h (limited to 'Source') diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index c803c5f..d814c1a 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -676,6 +676,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/TilesProfiler.cpp \ platform/graphics/android/TiledPage.cpp \ platform/graphics/android/TiledTexture.cpp \ + platform/graphics/android/TransferQueue.cpp \ platform/graphics/android/VideoLayerAndroid.cpp \ platform/graphics/android/VideoLayerManager.cpp \ platform/graphics/android/android_graphics.cpp \ diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp index ea6c8ec..cafab4a 100644 --- a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp @@ -154,7 +154,7 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo) if (renderInfo.measurePerf) drawTileInfo(&canvas, renderInfo, pictureCount); } - + renderInfo.textureInfo->m_pictureCount = pictureCount; renderingComplete(renderInfo, &canvas); return pictureCount; } diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 6ab2cd2..8bc560e 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -92,6 +92,17 @@ BaseTile::BaseTile(bool isLayerTile) BaseTile::~BaseTile() { + TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); + if (tileQueue->getHasGLContext()) { + tileQueue->m_transferQueueLock.lock(); + for (int i = 0 ; i < tileQueue->size(); i ++) { + TileTransferData* data = &(tileQueue->m_transferQueue[i]); + if (data->savedBaseTilePtr == this) + data->status = pendingDiscard; + } + tileQueue->m_transferQueueLock.unlock(); + } + setUsedLevel(-1); if (m_texture) m_texture->release(this); @@ -239,16 +250,14 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) } if (m_texture->readyFor(this)) { - XLOG("draw tile %x : %d, %d, %.2f with texture %x", this, x(), y(), scale(), m_texture); + XLOG("draw tile %x : %d, %d, %.2f with texture %x", this, x(), y(), m_scale, m_texture); if (isLayerTile()) TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), - rect, textureInfo->m_textureId, - transparency, true, - textureInfo->getTextureTarget()); + rect, m_texture->m_ownTextureId, + transparency, true); else - TilesManager::instance()->shader()->drawQuad(rect, textureInfo->m_textureId, - transparency, - textureInfo->getTextureTarget()); + TilesManager::instance()->shader()->drawQuad(rect, m_texture->m_ownTextureId, + transparency); } m_texture->consumerRelease(); } @@ -400,7 +409,10 @@ void BaseTile::paintBitmap() XLOG("%x update texture %x for tile %d, %d scale %.2f (m_scale: %.2f)", this, textureInfo, x, y, scale, m_scale); m_atomicSync.lock(); + +#if DEPRECATED_SURFACE_TEXTURE_MODE texture->setTile(textureInfo, x, y, scale, painter, pictureCount); +#endif texture->producerReleaseAndSwap(); if (texture == m_texture) { diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp index 8419e80..c964e04 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp @@ -32,9 +32,20 @@ #include "GLUtils.h" #include "TilesManager.h" -#define LOG_NDEBUG 1 -#define LOG_TAG "BaseTileTexture.cpp" -#include +#ifdef DEBUG + +#include +#include + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseTileTexture", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG namespace WebCore { @@ -48,6 +59,10 @@ BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) , m_busy(false) { m_size.set(w, h); + m_ownTextureId = GLUtils::createBaseTileGLTexture(w, h); + + // Make sure they are created on the UI thread. + TilesManager::instance()->transferQueue()->initSharedSurfaceTextures(w, h); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("BaseTileTexture"); @@ -130,7 +145,9 @@ void BaseTileTexture::producerUpdate(TextureInfo* textureInfo, const SkBitmap& b return; } - GLUtils::paintTextureWithBitmap(textureInfo, m_size, bitmap, 0, 0); + // After the tiled layer checked in, this is not called anyway. + // TODO: cleanup the old code path for layer painting + // GLUtils::paintTextureWithBitmap(info, m_size, bitmap, 0, 0); producerReleaseAndSwap(); } @@ -225,23 +242,36 @@ void BaseTileTexture::setTile(TextureInfo* info, int x, int y, float BaseTileTexture::scale() { - TextureTileInfo* textureInfo = m_texturesInfo.get(getWriteableTexture()); - if (!textureInfo) - return 1.0; + TextureTileInfo* textureInfo = &m_ownTextureTileInfo; return textureInfo->m_scale; } +// This function + TilesManager::addItemInTransferQueue() is replacing the +// setTile(). +void BaseTileTexture::setOwnTextureTileInfoFromQueue(const TextureTileInfo* info) +{ + m_ownTextureTileInfo.m_x = info->m_x; + m_ownTextureTileInfo.m_y = info->m_y; + m_ownTextureTileInfo.m_scale = info->m_scale; + m_ownTextureTileInfo.m_painter = info->m_painter; + m_ownTextureTileInfo.m_picture = info->m_picture; +} + bool BaseTileTexture::readyFor(BaseTile* baseTile) { - TextureTileInfo* info = m_texturesInfo.get(getReadableTexture()); + const TextureTileInfo* info = &m_ownTextureTileInfo; if (info && (info->m_x == baseTile->x()) && (info->m_y == baseTile->y()) && (info->m_scale == baseTile->scale()) && (info->m_painter == baseTile->painter()) && - (info->m_picture == baseTile->lastPaintedPicture())) { + (info->m_picture == baseTile->lastPaintedPicture())) return true; - } + + XLOG("readyFor return false for tile x, y (%d %d) texId %d ," + " BaseTileTexture %p, BaseTile is %p", + baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile); + return false; } diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h index 0cdd137..b21659f 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h @@ -40,23 +40,50 @@ class BaseTile; class TextureTileInfo { public: - TextureTileInfo() - : m_x(-1) - , m_y(-1) - , m_layerId(-1) - , m_scale(0) - , m_texture(0) - , m_painter(0) - , m_picture(0) - { - } - int m_x; - int m_y; - int m_layerId; - float m_scale; - TextureInfo* m_texture; - TilePainter* m_painter; - unsigned int m_picture; + TextureTileInfo() + : m_x(-1) + , m_y(-1) + , m_layerId(-1) + , m_scale(0) + , m_texture(0) + , m_painter(0) + , m_picture(0) + { + } + int m_x; + int m_y; + int m_layerId; + float m_scale; + TextureInfo* m_texture; + TilePainter* m_painter; + unsigned int m_picture; +}; + +// While in the queue, the BaseTile can be re-used, the updated bitmap +// can be discarded. In order to track this obsolete base tiles, we save +// the Tile's Info to make the comparison. +// At the time of base tile's dtor or webview destroy, we want to discard +// all the data in the queue. However, we have to do the Surface Texture +// update in the same GL context as the UI thread. So we mark the status +// as pendingDiscard, and delay the Surface Texture operation to the next +// draw call. + +enum TransferItemStatus { + emptyItem = 0, // S.T. buffer ready for new content + pendingBlit = 1, // Ready for bliting into tile's GL Tex. + pendingDiscard = 2 // Waiting for the next draw call to discard +}; + +class TileTransferData { +public: + TileTransferData() + : status(emptyItem) + , savedBaseTilePtr(0) + { + } + TransferItemStatus status; + BaseTile* savedBaseTilePtr; + TextureTileInfo tileInfo; }; // DoubleBufferedTexture using a SkBitmap as backing mechanism @@ -108,11 +135,16 @@ public: bool readyFor(BaseTile* baseTile); float scale(); + GLuint m_ownTextureId; + + void setOwnTextureTileInfoFromQueue(const TextureTileInfo* info); + protected: HashMap m_texturesInfo; private: void destroyTextures(SharedTexture** textures); + TextureTileInfo m_ownTextureTileInfo; SkSize m_size; int m_usedLevel; diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index 1f04ff5..5a6a158 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -29,15 +29,29 @@ #if USE(ACCELERATED_COMPOSITING) #include "ShaderProgram.h" +#include "TilesManager.h" #include #include #include #include + +#ifdef DEBUG + +#include +#include + #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__) +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + struct ANativeWindowBuffer; namespace WebCore { @@ -112,8 +126,9 @@ static void crashIfOOM(GLint errorCode) { void GLUtils::checkEglError(const char* op, EGLBoolean returnVal) { - if (returnVal != EGL_TRUE) + if (returnVal != EGL_TRUE) { XLOG("EGL ERROR - %s() returned %d\n", op, returnVal); + } for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) { XLOG("after %s() eglError (0x%x)\n", op, error); @@ -145,8 +160,9 @@ bool GLUtils::checkGlErrorOn(void* p, const char* op) void GLUtils::checkSurfaceTextureError(const char* functionName, int status) { - if (status != NO_ERROR) + if (status != NO_ERROR) { XLOG("ERROR at calling %s status is (%d)", functionName, status); + } } ///////////////////////////////////////////////////////////////////////////////////////// // GL & EGL extension checks @@ -336,17 +352,46 @@ GLuint GLUtils::createSampleTexture() return texture; } -void GLUtils::paintTextureWithBitmap(TextureInfo* textureInfo, - const SkSize& requiredSize, - const SkBitmap& bitmap, - int x, int y) +GLuint GLUtils::createBaseTileGLTexture(int width, int height) +{ + GLuint texture; + glGenTextures(1, &texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + GLubyte* pixels = 0; +#ifdef DEBUG + int length = width * height * 4; + pixels = new GLubyte[length]; + for (int i = 0; i < length; i++) + pixels[i] = i % 256; +#endif + glBindTexture(GL_TEXTURE_2D, texture); + GLUtils::checkGlError("glBindTexture"); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + GLUtils::checkGlError("glTexImage2D"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + return texture; +} + +void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, + const SkBitmap& bitmap) { + if (!renderInfo) + return; + const int x = renderInfo->invalRect->fLeft; + const int y = renderInfo->invalRect->fTop; + const SkSize& requiredSize = renderInfo->tileSize; + TextureInfo* textureInfo = renderInfo->textureInfo; SharedTextureMode mode = textureInfo->getSharedTextureMode(); if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) { if (mode == EglImageMode) GLUtils::updateTextureWithBitmap(textureInfo->m_textureId, x, y, bitmap); else if (mode == SurfaceTextureMode) - GLUtils::updateSurfaceTextureWithBitmap(textureInfo, x, y, bitmap); +#if DEPRECATED_SURFACE_TEXTURE_MODE + GLUtils::updateSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); +#else + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); +#endif } else { if (!requiredSize.equals(bitmap.width(), bitmap.height())) { @@ -358,22 +403,30 @@ void GLUtils::paintTextureWithBitmap(TextureInfo* textureInfo, if (mode == EglImageMode) GLUtils::createTextureWithBitmap(textureInfo->m_textureId, bitmap); else if (mode == SurfaceTextureMode) - GLUtils::createSurfaceTextureWithBitmap(textureInfo, bitmap); - +#if DEPRECATED_SURFACE_TEXTURE_MODE + GLUtils::createSurfaceTextureWithBitmap(renderInfo, bitmap); +#else + GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap); +#endif textureInfo->m_width = bitmap.width(); textureInfo->m_height = bitmap.height(); + textureInfo->m_internalFormat = GL_RGBA; } } -void GLUtils::createSurfaceTextureWithBitmap(TextureInfo* texture, const SkBitmap& bitmap, GLint filter) +#if DEPRECATED_SURFACE_TEXTURE_MODE +void GLUtils::createSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap, GLint filter) { - sp surfaceTexture = texture->m_surfaceTexture; - sp ANW = texture->m_ANW; + + TextureInfo* texture = renderInfo->textureInfo; texture->m_width = bitmap.width(); texture->m_height = bitmap.height(); texture->m_internalFormat = GL_RGBA; + sp surfaceTexture = texture->m_surfaceTexture; + sp ANW = texture->m_ANW; + int result; result = native_window_set_buffers_geometry(ANW.get(), texture->m_width, texture->m_height, HAL_PIXEL_FORMAT_RGBA_8888); @@ -382,11 +435,12 @@ void GLUtils::createSurfaceTextureWithBitmap(TextureInfo* texture, const SkBitma GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); checkSurfaceTextureError("native_window_set_usage", result); - updateSurfaceTextureWithBitmap(texture, 0, 0, bitmap, filter); + updateSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap, filter); } -void GLUtils::updateSurfaceTextureWithBitmap(TextureInfo* texture, int x, int y, const SkBitmap& bitmap, GLint filter) +void GLUtils::updateSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap, GLint filter) { + TextureInfo* texture = renderInfo->textureInfo; sp surfaceTexture = texture->m_surfaceTexture; sp ANW = texture->m_ANW; @@ -426,6 +480,78 @@ void GLUtils::updateSurfaceTextureWithBitmap(TextureInfo* texture, int x, int y, status = ANW->queueBuffer(ANW.get(), buf->getNativeBuffer()); checkSurfaceTextureError("queueBuffer", status); } +#endif + +void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap) +{ + if (!renderInfo + || !renderInfo->textureInfo + || !renderInfo->baseTile) + return; + TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); + // Only changed in the Tex Gen thread. + const int index = tileQueue->getNextTransferQueueIndex(); + + bool ready = tileQueue->lockForUpdate(index, renderInfo); + if (!ready) + return; + + // Dequeue the Surface Texture. + sp ANW = tileQueue->m_ANW; + if (!ANW.get()) { + XLOG("ERROR: ANW is null"); + return; + } + ANativeWindowBuffer* anb; + + // We bound the Surface Texture update and transfer queue update together. + tileQueue->m_transferQueueLock.lock(); + + int status = ANW->dequeueBuffer(ANW.get(), &anb); + checkSurfaceTextureError("dequeueBuffer", status); + // a) Update surface texture + sp buf(new android::GraphicBuffer(anb, false)); + status |= ANW->lockBuffer(ANW.get(), buf->getNativeBuffer()); // Mutex Lock + checkSurfaceTextureError("lockBuffer", status); + + // Fill the buffer with the content of the bitmap + uint8_t* img = 0; + status |= buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + checkSurfaceTextureError("lock", status); + + if (status == NO_ERROR) { + int row, col; + int bpp = 4; // Now we only deal with RGBA8888 format. + int width = TilesManager::instance()->tileWidth(); + int height = TilesManager::instance()->tileHeight(); + if (x == 0 && y == 0 && bitmap.width() == width && bitmap.height() == height) { + bitmap.lockPixels(); + uint8_t* bitmapOrigin = static_cast(bitmap.getPixels()); + // Copied line by line since we need to handle the offsets and stride. + for (row = 0 ; row < bitmap.height(); row ++) { + uint8_t* dst = &(img[(buf->getStride() * (row + x) + y) * bpp]); + uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]); + memcpy(dst, src, bpp * bitmap.width()); + } + bitmap.unlockPixels(); + } + else{ + // TODO: implement the partial invalidate here! + XLOG("ERROR: don't expect to get here yet before we support partial inval"); + } + } + buf->unlock(); + + status = ANW->queueBuffer(ANW.get(), buf->getNativeBuffer()); + checkSurfaceTextureError("queueBuffer", status); + + // b) After update the Surface Texture, now udpate the transfer queue info. + tileQueue->addItemInTransferQueue(renderInfo, index); + XLOG("Bitmap updated x, y %d %d, baseTile %p", + renderInfo->x, renderInfo->y, renderInfo->baseTile); + + tileQueue->m_transferQueueLock.unlock(); +} void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter) { diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index a015136..57557b2 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -64,15 +64,19 @@ public: static void deleteTexture(GLuint* texture); static GLuint createSampleColorTexture(int r, int g, int b); static GLuint createSampleTexture(); + 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 createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); - static void paintTextureWithBitmap(TextureInfo* textureInfo, const SkSize& requiredSize, const SkBitmap& bitmap, int x, int y); - - static void createSurfaceTextureWithBitmap(TextureInfo* texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR); - static void updateSurfaceTextureWithBitmap(TextureInfo* texture, int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); + static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); +#if DEPRECATED_SURFACE_TEXTURE_MODE + static void createSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap, GLint filter = GL_LINEAR); + static void updateSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR); +#endif + static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 07dda03..df8ecbe 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -104,6 +104,9 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex) GLWebViewState::~GLWebViewState() { + // Take care of the transfer queue such that Tex Gen thread will not stuck + TilesManager::instance()->unregisterGLWebViewState(this); + // We have to destroy the two tiled pages first as their destructor // may depend on the existence of this GLWebViewState and some of its // instance variables in order to complete. @@ -121,7 +124,7 @@ GLWebViewState::~GLWebViewState() #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("GLWebViewState"); #endif - TilesManager::instance()->unregisterGLWebViewState(this); + } void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, @@ -544,6 +547,11 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, if (baseForComposited && baseForComposited->countChildren() >= 1) compositedRoot = static_cast(baseForComposited->getChild(0)); + // Here before we draw, update the BaseTile which has updated content. + // Inside this function, just do GPU blits from the transfer queue into + // the BaseTiles' texture. + TilesManager::instance()->transferQueue()->updateDirtyBaseTiles(); + if (compositedRoot != m_previouslyUsedRoot) { TilesManager::instance()->swapLayersTextures(m_previouslyUsedRoot, compositedRoot); TilesManager::instance()->cleanupTilesTextures(); diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 05cb85e..00db27c 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -683,7 +683,7 @@ void LayerAndroid::showLayer(int indent) { char spaces[256]; memset(spaces, 0, 256); - for (unsigned int i = 0; i < indent; i++) + for (int i = 0; i < indent; i++) spaces[i] = ' '; if (!indent) @@ -745,10 +745,10 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) } // When the layer is dirty, the UI thread should be notified to redraw. - askPaint = drawChildrenGL(glWebViewState, matrix); + askPaint |= drawChildrenGL(glWebViewState, matrix); m_atomicSync.lock(); askPaint |= m_dirty; - if ((m_dirty && needsTexture()) || m_hasRunningAnimations || m_drawTransform.hasPerspective()) + if (askPaint || m_hasRunningAnimations || m_drawTransform.hasPerspective()) addDirtyArea(glWebViewState); m_atomicSync.unlock(); diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp index 4a18861..f66c7c1 100644 --- a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp @@ -121,8 +121,7 @@ void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); - GLUtils::paintTextureWithBitmap(renderInfo.textureInfo, renderInfo.tileSize, - bitmap, renderInfo.invalRect->fLeft, renderInfo.invalRect->fTop); + GLUtils::paintTextureWithBitmap(&renderInfo, bitmap); if (renderInfo.measurePerf) m_perfMon.stop(TAG_UPDATE_TEXTURE); diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index ed1ce11..be979ab 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -341,7 +341,18 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, GLint alpha) { glUseProgram(program); - setProjectionMatrix(geometry, projectionMatrixHandle); + + if (!geometry.isEmpty()) + setProjectionMatrix(geometry, projectionMatrixHandle); + else { + TransformationMatrix matrix; + // Map x,y from (0,1) to (-1, 1) + matrix.scale3d(2, 2, 1); + matrix.translate3d(-0.5, -0.5, 0); + GLfloat projectionMatrix[16]; + GLUtils::toGLMatrix(projectionMatrix, matrix); + glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix); + } glActiveTexture(GL_TEXTURE0); glUniform1i(texSampler, 0); diff --git a/Source/WebCore/platform/graphics/android/SharedTexture.cpp b/Source/WebCore/platform/graphics/android/SharedTexture.cpp index a7d43b5..74cd2c6 100644 --- a/Source/WebCore/platform/graphics/android/SharedTexture.cpp +++ b/Source/WebCore/platform/graphics/android/SharedTexture.cpp @@ -57,12 +57,14 @@ SharedTexture::SharedTexture(SharedTextureMode mode) m_supportsEGLImage = false; m_supportsEGLFenceSyncKHR = false; } else if (m_sharedTextureMode == SurfaceTextureMode) { +#if DEPRECATED_SURFACE_TEXTURE_MODE glGenTextures(1, &m_sourceTexture->m_textureId); m_sourceTexture->m_surfaceTexture = new android::SurfaceTexture(m_sourceTexture->m_textureId, false); m_sourceTexture->m_ANW = new android::SurfaceTextureClient(m_sourceTexture->m_surfaceTexture); +#endif } } @@ -74,9 +76,11 @@ SharedTexture::~SharedTexture() if (m_sharedTextureMode == EglImageMode) deleteTargetTexture(); else if (m_sharedTextureMode == SurfaceTextureMode) { +#if DEPRECATED_SURFACE_TEXTURE_MODE m_sourceTexture->m_surfaceTexture.clear(); m_sourceTexture->m_ANW.clear(); GLUtils::deleteTexture(&m_sourceTexture->m_textureId); +#endif } delete m_sourceTexture; delete m_targetTexture; @@ -196,7 +200,9 @@ TextureInfo* SharedTexture::lockTarget() { // Note that the source and targe are the same when using Surface Texture. if (m_sharedTextureMode == SurfaceTextureMode) { +#if DEPRECATED_SURFACE_TEXTURE_MODE m_sourceTexture->m_surfaceTexture->updateTexImage(); +#endif return m_sourceTexture; } diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.cpp b/Source/WebCore/platform/graphics/android/TextureInfo.cpp index 5db1711..8b3da8e 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.cpp +++ b/Source/WebCore/platform/graphics/android/TextureInfo.cpp @@ -43,6 +43,7 @@ TextureInfo::TextureInfo(SharedTextureMode mode) m_internalFormat = 0; m_sharedTextureMode = mode; m_eglSurface = EGL_NO_SURFACE; + m_pictureCount = 0; } bool TextureInfo::equalsAttributes(const TextureInfo* otherTexture) @@ -66,6 +67,7 @@ bool TextureInfo::operator==(const TextureInfo& otherTexture) GLenum TextureInfo::getTextureTarget() { +#if DEPRECATED_SURFACE_TEXTURE_MODE if (m_surfaceTexture.get()) { GLenum target = m_surfaceTexture->getCurrentTextureTarget(); // TODO: remove this translation when TEXTURE_2D+RGBA surface texture @@ -74,6 +76,7 @@ GLenum TextureInfo::getTextureTarget() return 0; return target; } +#endif return GL_TEXTURE_2D; } diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.h b/Source/WebCore/platform/graphics/android/TextureInfo.h index c1cb1cd..fda85da 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.h +++ b/Source/WebCore/platform/graphics/android/TextureInfo.h @@ -31,9 +31,11 @@ #include #include #include - +#include "BaseTile.h" using android::sp; +#define DEPRECATED_SURFACE_TEXTURE_MODE 0 + namespace android { class SurfaceTexture; } @@ -68,12 +70,15 @@ public: GLenum m_internalFormat; // Surface Texture specific data +#if DEPRECATED_SURFACE_TEXTURE_MODE sp m_surfaceTexture; +#endif + // TODO: Delete this after the Ganesh code path get fixed. sp m_ANW; - // The EGLSurface wraps the m_ANW to enable direct OpenGL rendering (e.g. Ganesh) EGLSurface m_eglSurface; + int m_pictureCount; private: SharedTextureMode m_sharedTextureMode; }; diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index 3dc0956..66846fe 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -82,15 +82,15 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) m_area.setWidth(area.width() / tileWidth); m_area.setHeight(area.height() / tileHeight); - XLOG("for TiledTexture %x, we have a visible area of %d x %d, corresponding to %d x %d tiles", - this, visibleArea.width(), visibleArea.height(), - m_area.width(), m_area.height()); - if (m_area.width() * tileWidth < area.width()) m_area.setWidth(m_area.width() + 1); if (m_area.height() * tileHeight < area.height()) m_area.setHeight(m_area.height() + 1); + XLOG("for TiledTexture %x, we have a visible area of %d x %d, corresponding to %d x %d tiles", + this, visibleArea.width(), visibleArea.height(), + m_area.width(), m_area.height()); + bool goingDown = m_prevTileY < m_area.y(); m_prevTileY = m_area.y(); diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 6a294b0..402f4ec 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -33,7 +33,10 @@ #include "SkCanvas.h" #include "SkDevice.h" #include "SkPaint.h" +#include #include +#include +#include #include @@ -101,8 +104,8 @@ TilesManager::TilesManager() , m_expandedTileBounds(false) , m_generatorReady(false) , m_showVisualIndicator(false) - , m_drawRegistrationCount(0) , m_invertedScreen(false) + , m_drawRegistrationCount(0) { XLOG("TilesManager ctor"); m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); @@ -190,7 +193,7 @@ void TilesManager::addPaintedSurface(PaintedSurface* surface) void TilesManager::cleanupTilesTextures() { // release existing surfaces without layers - Vector collect; + WTF::Vector collect; for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) { PaintedSurface* surface = m_paintedSurfaces[i]; if (!surface->layer()) @@ -200,7 +203,10 @@ void TilesManager::cleanupTilesTextures() for (unsigned int i = 0; i < collect.size(); i++) { m_paintedSurfaces.remove(m_paintedSurfaces.find(collect[i])); TilePainter* painter = collect[i]->texture(); + // Mark the current painter to destroy!! + transferQueue()->m_currentRemovingPaint = painter; m_pixmapsGenerationThread->removeOperationsForPainter(painter, true); + transferQueue()->m_currentRemovingPaint = 0; XLOG("destroy %x (%x)", collect[i], painter); delete collect[i]; } @@ -365,6 +371,10 @@ void TilesManager::registerGLWebViewState(GLWebViewState* state) void TilesManager::unregisterGLWebViewState(GLWebViewState* state) { + // Discard the whole queue b/c we lost GL context already. + // Note the real updateTexImage will still wait for the next draw. + transferQueue()->discardQueue(); + m_glWebViewStateMap.remove(state); XLOG("state %p now removed, total of %d states", state, m_glWebViewStateMap.size()); } diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 5ea4ccb..f5db599 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -36,6 +36,7 @@ #include "TiledPage.h" #include "TilesProfiler.h" #include "TilesTracker.h" +#include "TransferQueue.h" #include "VideoLayerManager.h" #include #include @@ -84,6 +85,7 @@ public: void addPaintedSurface(PaintedSurface* surface); ShaderProgram* shader() { return &m_shader; } + TransferQueue* transferQueue() { return &m_queue; } VideoLayerManager* videoLayerManager() { return &m_videoLayerManager; } BaseTileTexture* getAvailableTexture(BaseTile* owner); @@ -151,7 +153,6 @@ public: } private: - TilesManager(); void waitForGenerator() @@ -184,6 +185,8 @@ private: static TilesManager* gInstance; ShaderProgram m_shader; + TransferQueue m_queue; + VideoLayerManager m_videoLayerManager; HashMap m_glWebViewStateMap; diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp new file mode 100644 index 0000000..878affb --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -0,0 +1,403 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TransferQueue.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "BaseTile.h" +#include "PaintedSurface.h" +#include +#include +#include + +#ifdef DEBUG +#include +#include + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TransferQueue", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + +#define ST_BUFFER_NUMBER 4 + +namespace WebCore { + +TransferQueue::TransferQueue() + : m_currentRemovingPaint(0) + , m_transferQueueIndex(0) + , m_fboID(0) + , m_sharedSurfaceTextureId(0) + , m_hasGLContext(true) +{ + memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit)); + + m_transferQueueItemLocks = new android::Mutex[ST_BUFFER_NUMBER]; + + m_transferQueue = new TileTransferData[ST_BUFFER_NUMBER]; + for (int i = 0; i < ST_BUFFER_NUMBER; i++) { + m_transferQueue[i].savedBaseTilePtr = 0; + m_transferQueue[i].status = emptyItem; + } +} + +TransferQueue::~TransferQueue() +{ + glDeleteFramebuffers(1, &m_fboID); + m_fboID = 0; + glDeleteTextures(1, &m_sharedSurfaceTextureId); + m_sharedSurfaceTextureId = 0; + + delete[] m_transferQueueItemLocks; + delete[] m_transferQueue; +} + +int TransferQueue::size() +{ + return ST_BUFFER_NUMBER; +} + +void TransferQueue::initSharedSurfaceTextures(int width, int height) +{ + if (!m_sharedSurfaceTextureId) { + glGenTextures(1, &m_sharedSurfaceTextureId); + m_sharedSurfaceTexture = + new android::SurfaceTexture(m_sharedSurfaceTextureId); + m_ANW = new android::SurfaceTextureClient(m_sharedSurfaceTexture); + m_sharedSurfaceTexture->setSynchronousMode(true); + m_sharedSurfaceTexture->setBufferCount(ST_BUFFER_NUMBER+1); + + int result = native_window_set_buffers_geometry(m_ANW.get(), + width, height, HAL_PIXEL_FORMAT_RGBA_8888); + GLUtils::checkSurfaceTextureError("native_window_set_buffers_geometry", result); + result = native_window_set_usage(m_ANW.get(), + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + GLUtils::checkSurfaceTextureError("native_window_set_usage", result); + } + + if (!m_fboID) + glGenFramebuffers(1, &m_fboID); +} + +// When bliting, if the item from the transfer queue is mismatching b/t the +// BaseTile and the content, then the item is considered as obsolete, and +// the content is discarded. +bool TransferQueue::checkObsolete(int index) +{ + BaseTile* baseTilePtr = m_transferQueue[index].savedBaseTilePtr; + if (!baseTilePtr) { + XLOG("Invalid savedBaseTilePtr , such that the tile is obsolete"); + return true; + } + + BaseTileTexture* baseTileTexture = baseTilePtr->texture(); + if (!baseTileTexture) { + XLOG("Invalid baseTileTexture , such that the tile is obsolete"); + return true; + } + + const TextureTileInfo* tileInfo = &m_transferQueue[index].tileInfo; + + if (tileInfo->m_x != baseTilePtr->x() + || tileInfo->m_y != baseTilePtr->y() + || tileInfo->m_scale != baseTilePtr->scale() + || tileInfo->m_painter != baseTilePtr->painter()) { + XLOG("Mismatching x, y, scale or painter , such that the tile is obsolete"); + return true; + } + + return false; +} + +void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, GLuint srcTexId, GLenum srcTexTarget) +{ + // Then set up the FBO and copy the SurfTex content in. + glBindFramebuffer(GL_FRAMEBUFFER, fboID); + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + destTex->m_ownTextureId, + 0); + setGLStateForCopy(destTex->getSize().width(), + destTex->getSize().height()); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + XLOG("Error: glCheckFramebufferStatus failed"); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return; + } + + // Use empty rect to set up the special matrix to draw. + SkRect rect = SkRect::MakeEmpty(); + TilesManager::instance()->shader()->drawQuad(rect, srcTexId, 1.0, + srcTexTarget); + + // Need to WAR a driver bug to add a sync point here + GLubyte readBackPixels[4]; + glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, readBackPixels); + + // Clean up FBO setup. + glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO + GLUtils::checkGlError("copy the surface texture into the normal one"); +} + +bool TransferQueue::currentOpWaitingRemoval(const TileRenderInfo* renderInfo) +{ + if (m_currentRemovingPaint + && m_currentRemovingPaint == renderInfo->tilePainter) + return true; + return false; +} + +bool TransferQueue::lockForUpdate(int index, const TileRenderInfo* renderInfo) +{ + // Before dequeuing the buffer from Surface Texture, make sure this item + // has been consumed. We can't simply rely on dequeueBuffer, due to the + // UI thread may want to remove the current operation, so we have to add + // our own locking mechanism. + // For blocking case, the item's status should not be emptyItem. + while (m_transferQueueItemLocks[index].tryLock()) { + // If the current operation is on an resource which is going to be + // removed from UI thread, then early return. + if (currentOpWaitingRemoval(renderInfo)) { + XLOG("Quit bitmap update: operation is removed from UI thread!" + " x y %d %d", + renderInfo->x, renderInfo->y); + return false; + } + } + + // And if we have lost GL Context, then we can just early return here. + if (!getHasGLContext()) { + m_transferQueue[index].status = pendingDiscard; + m_transferQueueItemLocks[index].unlock(); + XLOG("Quit bitmap update: No GL Context! x y %d %d", + renderInfo->x, renderInfo->y); + return false; + } + + return true; +} + +bool TransferQueue::getHasGLContext() +{ + android::Mutex::Autolock lock(m_hasGLContextLock); + bool hasContext = m_hasGLContext; + return hasContext; +} + +void TransferQueue::setHasGLContext(bool hasContext) +{ + android::Mutex::Autolock lock(m_hasGLContextLock); + m_hasGLContext = hasContext; +} + +void TransferQueue::discardQueue() +{ + // Unblock the Tex Gen thread first before Tile Page deletion. + // Otherwise, there will be a deadlock while removing operations. + setHasGLContext(false); + + for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { + m_transferQueue[i].status = pendingDiscard; + m_transferQueueItemLocks[i].unlock(); + } +} + +// Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture. +void TransferQueue::updateDirtyBaseTiles() +{ + bool unlockFlag[ST_BUFFER_NUMBER]; + memset(unlockFlag, 0, sizeof(unlockFlag)); + + saveGLState(); + m_transferQueueLock.lock(); + + cleanupTransportQueue(); + if (!getHasGLContext()) + setHasGLContext(true); + + // Start from the oldest item, we call the updateTexImage to retrive + // the texture and blit that into each BaseTile's texture. + const int nextItemIndex = getNextTransferQueueIndex(); + int index = nextItemIndex; + for (int k = 0; k < ST_BUFFER_NUMBER ; k++) { + if (m_transferQueue[index].status == pendingBlit) { + bool obsoleteBaseTile = checkObsolete(index); + // 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) + destTexture = m_transferQueue[index].savedBaseTilePtr->texture(); + + m_sharedSurfaceTexture->updateTexImage(); + + unlockFlag[index] = true; + m_transferQueue[index].savedBaseTilePtr = 0; + m_transferQueue[index].status = emptyItem; + if (obsoleteBaseTile) { + XLOG("Warning: the texture is obsolete for this baseTile"); + continue; + } + + blitTileFromQueue(m_fboID, destTexture, + m_sharedSurfaceTextureId, + m_sharedSurfaceTexture->getCurrentTextureTarget()); + + // After the base tile copied into the GL texture, we need to + // update the texture's info such that at draw time, readyFor + // will find the latest texture's info + // We don't need a map any more, each texture contains its own + // texturesTileInfo. + destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo); + + XLOG("Blit tile x, y %d %d to destTexture->m_ownTextureId %d", + m_transferQueue[index].tileInfo.m_x, + m_transferQueue[index].tileInfo.m_y, + destTexture->m_ownTextureId); + } + index = (index + 1) % ST_BUFFER_NUMBER; + } + + restoreGLState(); + + int unlockIndex = nextItemIndex; + for (int k = 0; k < ST_BUFFER_NUMBER; k++) { + // Check the same order as the updateTexImage. + if (unlockFlag[unlockIndex]) + m_transferQueueItemLocks[unlockIndex].unlock(); + unlockIndex = (unlockIndex + 1) % ST_BUFFER_NUMBER; + } + + m_transferQueueLock.unlock(); +} + +// Note that there should be lock/unlock around this function call. +// Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap. +void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, + int index) +{ + m_transferQueueIndex = index; + + if (m_transferQueue[index].savedBaseTilePtr + || m_transferQueue[index].status != emptyItem) { + XLOG("ERROR update a tile which is dirty already @ index %d", index); + } + + m_transferQueue[index].savedBaseTilePtr = renderInfo->baseTile; + m_transferQueue[index].status = pendingBlit; + + // Now fill the tileInfo. + TextureTileInfo* textureInfo = &m_transferQueue[index].tileInfo; + + textureInfo->m_x = renderInfo->x; + textureInfo->m_y = renderInfo->y; + textureInfo->m_scale = renderInfo->scale; + textureInfo->m_painter = renderInfo->tilePainter; + + textureInfo->m_picture = renderInfo->textureInfo->m_pictureCount; +} + +// Note: this need to be called within th m_transferQueueLock. +void TransferQueue::cleanupTransportQueue() +{ + // We should call updateTexImage to the items first, + // then unlock. And we should start from the next item. + const int nextItemIndex = getNextTransferQueueIndex(); + bool needUnlock[ST_BUFFER_NUMBER]; + int index = nextItemIndex; + + for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { + needUnlock[index] = false; + if (m_transferQueue[index].status == pendingDiscard) { + m_sharedSurfaceTexture->updateTexImage(); + + m_transferQueue[index].savedBaseTilePtr = 0; + m_transferQueue[index].status == emptyItem; + needUnlock[index] = true; + } + index = (index + 1) % ST_BUFFER_NUMBER; + } + index = nextItemIndex; + for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { + if (needUnlock[index]) + m_transferQueueItemLocks[index].unlock(); + index = (index + 1) % ST_BUFFER_NUMBER; + } +} + +void TransferQueue::saveGLState() +{ + glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport); + glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor); + glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth); + glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor); +} + +void TransferQueue::setGLStateForCopy(int width, int height) +{ + // Need to match the texture size. + glViewport(0, 0, width, height); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void TransferQueue::restoreGLState() +{ + glViewport(m_GLStateBeforeBlit.viewport[0], + m_GLStateBeforeBlit.viewport[1], + m_GLStateBeforeBlit.viewport[2], + m_GLStateBeforeBlit.viewport[3]); + + if (m_GLStateBeforeBlit.scissor[0]) + glEnable(GL_SCISSOR_TEST); + + if (m_GLStateBeforeBlit.depth) + glEnable(GL_DEPTH_TEST); + + glClearColor(m_GLStateBeforeBlit.clearColor[0], + m_GLStateBeforeBlit.clearColor[1], + m_GLStateBeforeBlit.clearColor[2], + m_GLStateBeforeBlit.clearColor[3]); +} + +int TransferQueue::getNextTransferQueueIndex() +{ + return (m_transferQueueIndex + 1) % ST_BUFFER_NUMBER; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.h b/Source/WebCore/platform/graphics/android/TransferQueue.h new file mode 100644 index 0000000..e0046c3 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TransferQueue.h @@ -0,0 +1,126 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TransferQueue_h +#define TransferQueue_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "BaseTile.h" +#include "BaseTileTexture.h" +#include "ShaderProgram.h" +#include "TiledPage.h" + +namespace WebCore { + +struct GLState { + GLint viewport[4]; + GLboolean scissor[1]; + GLboolean depth[1]; + GLfloat clearColor[4]; +}; + +class TransferQueue { +public: + TransferQueue(); + ~TransferQueue(); + + void updateDirtyBaseTiles(); + + // This queue can be accessed from UI and TexGen thread, therefore, we need + // a lock to protect its access + TileTransferData* m_transferQueue; + android::Mutex m_transferQueueLock; + + void initSharedSurfaceTextures(int width, int height); + sp m_ANW; + + bool getHasGLContext(); + void setHasGLContext(bool hasContext); + + int getNextTransferQueueIndex(); + + void addItemInTransferQueue(const TileRenderInfo* info, int index); + + // Check if the item @ index is ready for update. + // The lock will be done when returning true. + bool lockForUpdate(int index, const TileRenderInfo* renderInfo); + + void discardQueue(); + + // Store info for currentOpWaitingRemoval() to tell which operation + // will be removed. + TilePainter* m_currentRemovingPaint; + + // Return the buffer number. + int size(); + +private: + // Note that the m_transferQueueIndex only changed in the TexGen thread + // where we are going to move on to update the next item in the queue. + int m_transferQueueIndex; + + GLuint m_fboID; // The FBO used for copy the SurfTex to each tile + + GLuint m_sharedSurfaceTextureId; + + // GLContext can be lost when WebView destroyed. + bool m_hasGLContext; + android::Mutex m_hasGLContextLock; + + // Save and restore the GL State while switching from/to FBO. + void saveGLState(); + void setGLStateForCopy(int width, int height); + void restoreGLState(); + GLState m_GLStateBeforeBlit; + + // Check the current transfer queue item is obsolete or not. + bool checkObsolete(int index); + + // Before each draw call and the blit operation, clean up all the + // pendingDiscard items. + void cleanupTransportQueue(); + + // This function can tell Tex Gen thread whether or not the current + // operation need to be removed now. + bool currentOpWaitingRemoval(const TileRenderInfo* renderInfo); + + void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, GLuint srcTexId, GLenum srcTexTarget); + + // Each element in the queue has its own lock, basically lock before update + // and unlock at drawGL time. + // This is similar to the internal lock from SurfaceTexture, but we can't + // naively rely on them since when tearing down, UI thread need to clean up + // the pending jobs in that Tex Gen thread, if the Tex Gen is waiting for + // Surface Texture, then we are stuck. + android::Mutex* m_transferQueueItemLocks; + + sp m_sharedSurfaceTexture; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) +#endif // TransferQueue_h -- cgit v1.1