summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/android
diff options
context:
space:
mode:
authorTeng-Hui Zhu <ztenghui@google.com>2011-08-01 11:32:58 -0700
committerTeng-Hui Zhu <ztenghui@google.com>2011-08-02 17:48:21 -0700
commit7c554a61cb935660cdc86905d040c781b490150f (patch)
tree033ba7f31eb01931dd94eb37cff5e014faf79bc3 /Source/WebCore/platform/graphics/android
parentd4f990572c3485cdc15cff48c3bedc6e7cad809b (diff)
downloadexternal_webkit-7c554a61cb935660cdc86905d040c781b490150f.zip
external_webkit-7c554a61cb935660cdc86905d040c781b490150f.tar.gz
external_webkit-7c554a61cb935660cdc86905d040c781b490150f.tar.bz2
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
Diffstat (limited to 'Source/WebCore/platform/graphics/android')
-rw-r--r--Source/WebCore/platform/graphics/android/BaseRenderer.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTile.cpp26
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTileTexture.cpp50
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTileTexture.h66
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.cpp154
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.h12
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.cpp10
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.cpp6
-rw-r--r--Source/WebCore/platform/graphics/android/RasterRenderer.cpp3
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.cpp13
-rw-r--r--Source/WebCore/platform/graphics/android/SharedTexture.cpp6
-rw-r--r--Source/WebCore/platform/graphics/android/TextureInfo.cpp3
-rw-r--r--Source/WebCore/platform/graphics/android/TextureInfo.h9
-rw-r--r--Source/WebCore/platform/graphics/android/TiledTexture.cpp8
-rw-r--r--Source/WebCore/platform/graphics/android/TilesManager.cpp14
-rw-r--r--Source/WebCore/platform/graphics/android/TilesManager.h5
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.cpp403
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.h126
18 files changed, 847 insertions, 69 deletions
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 <utils/Log.h>
+#ifdef DEBUG
+
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+
+#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<SharedTexture*, TextureTileInfo*> 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 <cutils/log.h>
#include <gui/SurfaceTexture.h>
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
+
+#ifdef DEBUG
+
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+
#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<android::SurfaceTexture> surfaceTexture = texture->m_surfaceTexture;
- sp<ANativeWindow> ANW = texture->m_ANW;
+
+ TextureInfo* texture = renderInfo->textureInfo;
texture->m_width = bitmap.width();
texture->m_height = bitmap.height();
texture->m_internalFormat = GL_RGBA;
+ sp<android::SurfaceTexture> surfaceTexture = texture->m_surfaceTexture;
+ sp<ANativeWindow> 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<android::SurfaceTexture> surfaceTexture = texture->m_surfaceTexture;
sp<ANativeWindow> 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<ANativeWindow> 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<android::GraphicBuffer> 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<uint8_t*>(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<LayerAndroid*>(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 <jni.h>
#include <ui/GraphicBuffer.h>
#include <utils/RefBase.h>
-
+#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<android::SurfaceTexture> m_surfaceTexture;
+#endif
+ // TODO: Delete this after the Ganesh code path get fixed.
sp<ANativeWindow> 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 <android/native_window.h>
#include <cutils/atomic.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
#include <cutils/log.h>
@@ -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<PaintedSurface*> collect;
+ WTF::Vector<PaintedSurface*> 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 <utils/threads.h>
#include <wtf/HashMap.h>
@@ -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<GLWebViewState*, unsigned int> 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 <android/native_window.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+#ifdef DEBUG
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+
+#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<ANativeWindow> 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<android::SurfaceTexture> m_sharedSurfaceTexture;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // TransferQueue_h