summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
diff options
context:
space:
mode:
authorNicolas Roard <nicolasroard@google.com>2012-04-06 11:35:50 -0700
committerNicolas Roard <nicolasroard@google.com>2012-04-06 14:03:59 -0700
commit2e510fd5b5a30f1315c272d44ae3aa4cba355498 (patch)
treedb3af5f32855d329856f190c3509ae11ae519851 /Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
parentc88c88907b618e468ec3928b06a3a31d4f99b9c6 (diff)
downloadexternal_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.zip
external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.gz
external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.bz2
Reorganize platform/graphics/android
Change-Id: Idc67155cfa99784dcd931e705336bfa063ecae46
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp')
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp644
1 files changed, 644 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
new file mode 100644
index 0000000..ec0d9e7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "TransferQueue"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TransferQueue.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "DrawQuadData.h"
+#include "GLUtils.h"
+#include "Tile.h"
+#include "TileTexture.h"
+#include "TilesManager.h"
+#include <android/native_window.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+// For simple webView usage, MINIMAL_SIZE is recommended for memory saving.
+// In browser case, EFFICIENT_SIZE is preferred.
+#define MINIMAL_SIZE 1
+#define EFFICIENT_SIZE 6
+
+// Set this to 1 if we would like to take the new GpuUpload approach which
+// relied on the glCopyTexSubImage2D instead of a glDraw call
+#define GPU_UPLOAD_WITHOUT_DRAW 1
+
+namespace WebCore {
+
+TransferQueue::TransferQueue(bool useMinimalMem)
+ : m_eglSurface(EGL_NO_SURFACE)
+ , m_transferQueueIndex(0)
+ , m_fboID(0)
+ , m_sharedSurfaceTextureId(0)
+ , m_hasGLContext(true)
+ , m_interruptedByRemovingOp(false)
+ , m_currentDisplay(EGL_NO_DISPLAY)
+ , m_currentUploadType(DEFAULT_UPLOAD_TYPE)
+{
+ memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit));
+ m_transferQueueSize = useMinimalMem ? MINIMAL_SIZE : EFFICIENT_SIZE;
+ m_emptyItemCount = m_transferQueueSize;
+ m_transferQueue = new TileTransferData[m_transferQueueSize];
+}
+
+TransferQueue::~TransferQueue()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ cleanupGLResources();
+ delete[] m_transferQueue;
+}
+
+// This should be called within the m_transferQueueItemLocks.
+// Now only called by emptyQueue() and destructor.
+void TransferQueue::cleanupGLResources()
+{
+ if (m_sharedSurfaceTexture.get()) {
+ m_sharedSurfaceTexture->abandon();
+ m_sharedSurfaceTexture.clear();
+ }
+ if (m_fboID) {
+ glDeleteFramebuffers(1, &m_fboID);
+ m_fboID = 0;
+ }
+ if (m_sharedSurfaceTextureId) {
+ glDeleteTextures(1, &m_sharedSurfaceTextureId);
+ m_sharedSurfaceTextureId = 0;
+ }
+}
+
+void TransferQueue::initGLResources(int width, int height)
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ if (!m_sharedSurfaceTextureId) {
+ glGenTextures(1, &m_sharedSurfaceTextureId);
+ sp<BufferQueue> bufferQueue(new BufferQueue(true));
+ m_sharedSurfaceTexture =
+#if GPU_UPLOAD_WITHOUT_DRAW
+ new android::SurfaceTexture(m_sharedSurfaceTextureId, true,
+ GL_TEXTURE_2D, false, bufferQueue);
+#else
+ new android::SurfaceTexture(m_sharedSurfaceTextureId, true,
+ GL_TEXTURE_EXTERNAL_OES, true,
+ bufferQueue);
+#endif
+ m_ANW = new android::SurfaceTextureClient(m_sharedSurfaceTexture);
+ m_sharedSurfaceTexture->setSynchronousMode(true);
+
+ int extraBuffersNeeded = 0;
+ m_ANW->query(m_ANW.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &extraBuffersNeeded);
+ bufferQueue->setBufferCount(m_transferQueueSize + extraBuffersNeeded);
+
+ 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
+// Tile and the content, then the item is considered as obsolete, and
+// the content is discarded.
+bool TransferQueue::checkObsolete(const TileTransferData* data)
+{
+ Tile* baseTilePtr = data->savedTilePtr;
+ if (!baseTilePtr) {
+ ALOGV("Invalid savedTilePtr , such that the tile is obsolete");
+ return true;
+ }
+
+ TileTexture* baseTileTexture = baseTilePtr->backTexture();
+ if (!baseTileTexture || baseTileTexture != data->savedTileTexturePtr) {
+ ALOGV("Invalid baseTileTexture %p (vs expected %p), such that the tile is obsolete",
+ baseTileTexture, data->savedTileTexturePtr);
+ return true;
+ }
+
+ return false;
+}
+
+void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex,
+ TileTexture* frontTex,
+ GLuint srcTexId, GLenum srcTexTarget,
+ int index)
+{
+#if GPU_UPLOAD_WITHOUT_DRAW
+ glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
+
+ int textureWidth = destTex->getSize().width();
+ int textureHeight = destTex->getSize().height();
+
+ IntRect inval = m_transferQueue[index].invalRect;
+ bool partialInval = !inval.isEmpty();
+
+ if (partialInval && frontTex) {
+ // recopy the previous texture to the new one, as
+ // the partial update will not cover the entire texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ frontTex->m_ownTextureId,
+ 0);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ }
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ srcTexId,
+ 0);
+
+ if (!partialInval) {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0,
+ inval.width(), inval.height());
+ }
+
+#else
+ // Then set up the FBO and copy the SurfTex content in.
+ glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ 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) {
+ ALOGV("Error: glCheckFramebufferStatus failed");
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return;
+ }
+
+ // Use empty rect to set up the special matrix to draw.
+ SkRect rect = SkRect::MakeEmpty();
+
+ TextureQuadData data(srcTexId, GL_NEAREST, srcTexTarget, Blit, 0, 0, 1.0, false);
+ TilesManager::instance()->shader()->drawQuad(&data);
+
+ // To workaround a sync issue on some platforms, we should insert the sync
+ // here while in the current FBO.
+ // This will essentially kick off the GPU command buffer, and the Tex Gen
+ // thread will then have to wait for this buffer to finish before writing
+ // into the same memory.
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ if (m_currentDisplay != dpy)
+ m_currentDisplay = dpy;
+ if (m_currentDisplay != EGL_NO_DISPLAY) {
+ if (m_transferQueue[index].m_syncKHR != EGL_NO_SYNC_KHR)
+ eglDestroySyncKHR(m_currentDisplay, m_transferQueue[index].m_syncKHR);
+ m_transferQueue[index].m_syncKHR = eglCreateSyncKHR(m_currentDisplay,
+ EGL_SYNC_FENCE_KHR,
+ 0);
+ }
+ GLUtils::checkEglError("CreateSyncKHR");
+#endif
+}
+
+void TransferQueue::interruptTransferQueue(bool interrupt)
+{
+ m_transferQueueItemLocks.lock();
+ m_interruptedByRemovingOp = interrupt;
+ if (m_interruptedByRemovingOp)
+ m_transferQueueItemCond.signal();
+ m_transferQueueItemLocks.unlock();
+}
+
+// This function must be called inside the m_transferQueueItemLocks, for the
+// wait, m_interruptedByRemovingOp and getHasGLContext().
+// Only called by updateQueueWithBitmap() for now.
+bool TransferQueue::readyForUpdate()
+{
+ if (!getHasGLContext())
+ return false;
+ // Don't use a while loop since when the WebView tear down, the emptyCount
+ // will still be 0, and we bailed out b/c of GL context lost.
+ if (!m_emptyItemCount) {
+ if (m_interruptedByRemovingOp)
+ return false;
+ m_transferQueueItemCond.wait(m_transferQueueItemLocks);
+ if (m_interruptedByRemovingOp)
+ return false;
+ }
+
+ if (!getHasGLContext())
+ return false;
+
+ // Disable this wait until we figure out why this didn't work on some
+ // drivers b/5332112.
+#if 0
+ if (m_currentUploadType == GpuUpload
+ && m_currentDisplay != EGL_NO_DISPLAY) {
+ // Check the GPU fence
+ EGLSyncKHR syncKHR = m_transferQueue[getNextTransferQueueIndex()].m_syncKHR;
+ if (syncKHR != EGL_NO_SYNC_KHR)
+ eglClientWaitSyncKHR(m_currentDisplay,
+ syncKHR,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ EGL_FOREVER_KHR);
+ }
+ GLUtils::checkEglError("WaitSyncKHR");
+#endif
+
+ return true;
+}
+
+// Both getHasGLContext and setHasGLContext should be called within the lock.
+bool TransferQueue::getHasGLContext()
+{
+ return m_hasGLContext;
+}
+
+void TransferQueue::setHasGLContext(bool hasContext)
+{
+ m_hasGLContext = hasContext;
+}
+
+void TransferQueue::setPendingDiscardWithLock()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ setPendingDiscard();
+}
+
+void TransferQueue::emptyQueue()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ setPendingDiscard();
+ cleanupPendingDiscard();
+ cleanupGLResources();
+}
+
+// Set all the content in the queue to pendingDiscard, after this, there will
+// be nothing added to the queue, and this can be called in any thread.
+// However, in order to discard the content in the Surface Texture using
+// updateTexImage, cleanupPendingDiscard need to be called on the UI thread.
+// Must be called within a m_transferQueueItemLocks.
+void TransferQueue::setPendingDiscard()
+{
+ for (int i = 0 ; i < m_transferQueueSize; i++)
+ if (m_transferQueue[i].status == pendingBlit)
+ m_transferQueue[i].status = pendingDiscard;
+
+ m_pureColorTileQueue.clear();
+
+ bool GLContextExisted = getHasGLContext();
+ // Unblock the Tex Gen thread first before Tile Page deletion.
+ // Otherwise, there will be a deadlock while removing operations.
+ setHasGLContext(false);
+
+ // Only signal once when GL context lost.
+ if (GLContextExisted)
+ m_transferQueueItemCond.signal();
+}
+
+void TransferQueue::updatePureColorTiles()
+{
+ for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) {
+ TileTransferData* data = &m_pureColorTileQueue[i];
+ if (data->status == pendingBlit) {
+ TileTexture* destTexture = 0;
+ bool obsoleteTile = checkObsolete(data);
+ if (!obsoleteTile) {
+ destTexture = data->savedTilePtr->backTexture();
+ destTexture->setPureColor(data->pureColor);
+ destTexture->transferComplete();
+ }
+ } else if (data->status == emptyItem || data->status == pendingDiscard) {
+ // The queue should be clear instead of setting to different status.
+ ALOGV("Warning: Don't expect an emptyItem here.");
+ }
+ }
+ m_pureColorTileQueue.clear();
+}
+
+// Call on UI thread to copy from the shared Surface Texture to the Tile's texture.
+void TransferQueue::updateDirtyTiles()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+
+ cleanupPendingDiscard();
+ if (!getHasGLContext())
+ setHasGLContext(true);
+
+ // Check the pure color tile first, since it is simpler.
+ updatePureColorTiles();
+
+ // Start from the oldest item, we call the updateTexImage to retrive
+ // the texture and blit that into each Tile's texture.
+ const int nextItemIndex = getNextTransferQueueIndex();
+ int index = nextItemIndex;
+ bool usedFboForUpload = false;
+ for (int k = 0; k < m_transferQueueSize ; k++) {
+ if (m_transferQueue[index].status == pendingBlit) {
+ bool obsoleteTile = checkObsolete(&m_transferQueue[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.
+ TileTexture* destTexture = 0;
+ TileTexture* frontTexture = 0;
+ if (!obsoleteTile) {
+ destTexture = m_transferQueue[index].savedTilePtr->backTexture();
+ // while destTexture is guaranteed to not be null, frontTexture
+ // might be (first transfer)
+ frontTexture = m_transferQueue[index].savedTilePtr->frontTexture();
+ }
+
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ ALOGE("unexpected error: updateTexImage return %d", result);
+ }
+ m_transferQueue[index].savedTilePtr = 0;
+ m_transferQueue[index].status = emptyItem;
+ if (obsoleteTile) {
+ ALOGV("Warning: the texture is obsolete for this baseTile");
+ index = (index + 1) % m_transferQueueSize;
+ continue;
+ }
+
+ // guarantee that we have a texture to blit into
+ destTexture->requireGLTexture();
+
+ if (m_transferQueue[index].uploadType == CpuUpload) {
+ // Here we just need to upload the bitmap content to the GL Texture
+ GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
+ *m_transferQueue[index].bitmap,
+ m_transferQueue[index].invalRect);
+ } else {
+ if (!usedFboForUpload) {
+ saveGLState();
+ usedFboForUpload = true;
+ }
+ blitTileFromQueue(m_fboID, destTexture, frontTexture,
+ m_sharedSurfaceTextureId,
+ m_sharedSurfaceTexture->getCurrentTextureTarget(),
+ index);
+ }
+
+ destTexture->setPure(false);
+ destTexture->transferComplete();
+
+ ALOGV("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
+ m_transferQueue[index].savedTilePtr,
+ destTexture,
+ destTexture->m_ownTextureId);
+ }
+ index = (index + 1) % m_transferQueueSize;
+ }
+
+ // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
+ // dynamic switch possible. Moving this out from the loop can save some
+ // milli-seconds.
+ if (usedFboForUpload) {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
+ restoreGLState();
+ GLUtils::checkGlError("updateDirtyTiles");
+ }
+
+ m_emptyItemCount = m_transferQueueSize;
+ m_transferQueueItemCond.signal();
+}
+
+void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) {
+ // failed placing bitmap in queue, discard tile's texture so it will be
+ // re-enqueued (and repainted)
+ Tile* tile = renderInfo->baseTile;
+ if (tile)
+ tile->backTextureTransferFail();
+ }
+}
+
+bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ // This lock need to cover the full update since it is possible that queue
+ // will be cleaned up in the middle of this update without the lock.
+ // The Surface Texture will not block us since the readyForUpdate will check
+ // availability of the slots in the queue first.
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ bool ready = readyForUpdate();
+ TextureUploadType currentUploadType = m_currentUploadType;
+ if (!ready) {
+ ALOGV("Quit bitmap update: not ready! for tile x y %d %d",
+ renderInfo->x, renderInfo->y);
+ return false;
+ }
+ if (currentUploadType == GpuUpload) {
+ // a) Dequeue the Surface Texture and write into the buffer
+ if (!m_ANW.get()) {
+ ALOGV("ERROR: ANW is null");
+ return false;
+ }
+
+ if (!GLUtils::updateSharedSurfaceTextureWithBitmap(m_ANW.get(), bitmap))
+ return false;
+ }
+
+ // b) After update the Surface Texture, now udpate the transfer queue info.
+ addItemInTransferQueue(renderInfo, currentUploadType, &bitmap);
+
+ ALOGV("Bitmap updated x, y %d %d, baseTile %p",
+ renderInfo->x, renderInfo->y, renderInfo->baseTile);
+ return true;
+}
+
+void TransferQueue::addItemInPureColorQueue(const TileRenderInfo* renderInfo)
+{
+ // The pure color tiles' queue will be read from UI thread and written in
+ // Tex Gen thread, thus we need to have a lock here.
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ TileTransferData data;
+ addItemCommon(renderInfo, GpuUpload, &data);
+ data.pureColor = renderInfo->pureColor;
+ m_pureColorTileQueue.append(data);
+}
+
+// Translates the info from TileRenderInfo and others to TileTransferData.
+// This is used by pure color tiles and normal tiles.
+void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
+ TextureUploadType type,
+ TileTransferData* data)
+{
+ data->savedTileTexturePtr = renderInfo->baseTile->backTexture();
+ data->savedTilePtr = renderInfo->baseTile;
+ data->status = pendingBlit;
+ data->uploadType = type;
+
+ IntRect inval(0, 0, 0, 0);
+ if (renderInfo->invalRect) {
+ inval.setX(renderInfo->invalRect->fLeft);
+ inval.setY(renderInfo->invalRect->fTop);
+ inval.setWidth(renderInfo->invalRect->width());
+ inval.setHeight(renderInfo->invalRect->height());
+ }
+ data->invalRect = inval;
+}
+
+// Note that there should be lock/unlock around this function call.
+// Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
+void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
+ TextureUploadType type,
+ const SkBitmap* bitmap)
+{
+ m_transferQueueIndex = (m_transferQueueIndex + 1) % m_transferQueueSize;
+
+ int index = m_transferQueueIndex;
+ if (m_transferQueue[index].savedTilePtr
+ || m_transferQueue[index].status != emptyItem) {
+ ALOGV("ERROR update a tile which is dirty already @ index %d", index);
+ }
+
+ TileTransferData* data = &m_transferQueue[index];
+ addItemCommon(renderInfo, type, data);
+ if (type == CpuUpload && bitmap) {
+ // Lazily create the bitmap
+ if (!m_transferQueue[index].bitmap) {
+ m_transferQueue[index].bitmap = new SkBitmap();
+ int w = bitmap->width();
+ int h = bitmap->height();
+ m_transferQueue[index].bitmap->setConfig(bitmap->config(), w, h);
+ }
+ bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config());
+ }
+
+ m_emptyItemCount--;
+}
+
+void TransferQueue::setTextureUploadType(TextureUploadType type)
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ if (m_currentUploadType == type)
+ return;
+
+ setPendingDiscard();
+
+ m_currentUploadType = type;
+ ALOGD("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload");
+}
+
+// Note: this need to be called within the lock and on the UI thread.
+// Only called by updateDirtyTiles() and emptyQueue() for now
+void TransferQueue::cleanupPendingDiscard()
+{
+ int index = getNextTransferQueueIndex();
+
+ for (int i = 0 ; i < m_transferQueueSize; i++) {
+ if (m_transferQueue[index].status == pendingDiscard) {
+ // No matter what the current upload type is, as long as there has
+ // been a Surf Tex enqueue operation, this updateTexImage need to
+ // be called to keep things in sync.
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ ALOGE("unexpected error: updateTexImage return %d", result);
+ }
+
+ // since tiles in the queue may be from another webview, remove
+ // their textures so that they will be repainted / retransferred
+ Tile* tile = m_transferQueue[index].savedTilePtr;
+ TileTexture* texture = m_transferQueue[index].savedTileTexturePtr;
+ if (tile && texture && texture->owner() == tile) {
+ // since tile destruction removes textures on the UI thread, the
+ // texture->owner ptr guarantees the tile is valid
+ tile->discardBackTexture();
+ ALOGV("transfer queue discarded tile %p, removed texture", tile);
+ }
+
+ m_transferQueue[index].savedTilePtr = 0;
+ m_transferQueue[index].savedTileTexturePtr = 0;
+ m_transferQueue[index].status = emptyItem;
+ }
+ index = (index + 1) % m_transferQueueSize;
+ }
+}
+
+void TransferQueue::saveGLState()
+{
+ glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport);
+ glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor);
+ glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth);
+#ifdef DEBUG
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor);
+#endif
+}
+
+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);
+ // Clear the content is only for debug purpose.
+#ifdef DEBUG
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+#endif
+}
+
+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[0])
+ glEnable(GL_DEPTH_TEST);
+#ifdef DEBUG
+ glClearColor(m_GLStateBeforeBlit.clearColor[0],
+ m_GLStateBeforeBlit.clearColor[1],
+ m_GLStateBeforeBlit.clearColor[2],
+ m_GLStateBeforeBlit.clearColor[3]);
+#endif
+}
+
+int TransferQueue::getNextTransferQueueIndex()
+{
+ return (m_transferQueueIndex + 1) % m_transferQueueSize;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING