summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2014-04-11 19:15:05 -0700
committerJohn Reck <jreck@google.com>2014-04-14 13:17:25 -0700
commit860d155f866cc15a725e7ce03763280987f24901 (patch)
tree1ade6b4f5c2c0910c088469b95255eb66ce0cb53
parentdb8b130a19484cb6018667905e64d42ab793654f (diff)
downloadframeworks_base-860d155f866cc15a725e7ce03763280987f24901.zip
frameworks_base-860d155f866cc15a725e7ce03763280987f24901.tar.gz
frameworks_base-860d155f866cc15a725e7ce03763280987f24901.tar.bz2
Fix issue with bitmap uploading
Bug: 13912749 Change-Id: Ic23fa1d280118dc93dc2716a4a24cc0bbbdca595
-rw-r--r--core/jni/android_view_GLRenderer.cpp4
-rw-r--r--core/jni/android_view_HardwareLayer.cpp4
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp6
-rw-r--r--libs/hwui/DeferredLayerUpdater.h2
-rw-r--r--libs/hwui/DisplayListOp.h20
-rw-r--r--libs/hwui/RenderNode.cpp13
-rw-r--r--libs/hwui/RenderNode.h6
-rw-r--r--libs/hwui/Texture.cpp4
-rw-r--r--libs/hwui/Texture.h6
-rw-r--r--libs/hwui/TextureCache.cpp72
-rw-r--r--libs/hwui/TextureCache.h17
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp15
-rw-r--r--libs/hwui/renderthread/CanvasContext.h6
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp20
14 files changed, 130 insertions, 65 deletions
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 6ae6c8f..d0269a3 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -146,8 +146,8 @@ static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz,
jlong renderNodePtr) {
using namespace android::uirenderer;
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- TreeInfo info = {0};
- renderNode->prepareTree(info);
+ TreeInfo ignoredInfo;
+ renderNode->prepareTree(ignoredInfo);
}
static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 2eb0d78..b2f17de 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -127,8 +127,8 @@ static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject cl
static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- bool ignoredHasFunctors;
- return layer->apply(&ignoredHasFunctors);
+ TreeInfo ignoredInfo;
+ return layer->apply(ignoredInfo);
}
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 8b23955..285c8c3 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -63,7 +63,7 @@ void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
}
}
-bool DeferredLayerUpdater::apply(bool* hasFunctors) {
+bool DeferredLayerUpdater::apply(TreeInfo& info) {
bool success = true;
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
@@ -74,11 +74,7 @@ bool DeferredLayerUpdater::apply(bool* hasFunctors) {
success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
}
mLayer->setBlend(mBlend);
- TreeInfo info = {0};
mDisplayList->prepareTree(info);
- if (info.hasFunctors) {
- *hasFunctors = true;
- }
mLayer->updateDeferred(mDisplayList.get(),
mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
mDirtyRect.setEmpty();
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 2cc9229..cc62caa 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,7 +77,7 @@ public:
ANDROID_API void setPaint(const SkPaint* paint);
- ANDROID_API bool apply(bool* hasFunctors);
+ ANDROID_API bool apply(TreeInfo& info);
ANDROID_API Layer* backingLayer() {
return mLayer;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 06f675e..f19da9d 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -286,12 +286,6 @@ public:
int getFlags() const { return mFlags; }
private:
- SaveOp() {}
- DisplayListOp* reinit(int flags) {
- mFlags = flags;
- return this;
- }
-
int mFlags;
};
@@ -318,12 +312,6 @@ public:
virtual const char* name() { return "RestoreToCount"; }
private:
- RestoreToCountOp() {}
- DisplayListOp* reinit(int count) {
- mCount = count;
- return this;
- }
-
int mCount;
};
@@ -514,7 +502,6 @@ public:
}
protected:
- ClipOp() {}
virtual bool isRect() { return false; }
SkRegion::Op mOp;
@@ -539,13 +526,6 @@ protected:
virtual bool isRect() { return true; }
private:
- ClipRectOp() {}
- DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
- mOp = op;
- mArea.set(left, top, right, bottom);
- return this;
- }
-
Rect mArea;
};
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c55ebd6..cf21834 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -109,7 +109,7 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
// that are no longer used
- TreeInfo oldTreeInfo = {0};
+ TreeInfo oldTreeInfo;
prepareSubTree(oldTreeInfo, mDisplayListData);
// TODO: The damage for the old tree should be accounted for
delete mDisplayListData;
@@ -120,8 +120,15 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
if (subtree) {
- if (!info.hasFunctors) {
- info.hasFunctors = subtree->functorCount;
+ TextureCache& cache = Caches::getInstance().textureCache;
+ info.hasFunctors |= subtree->functorCount;
+ // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
+ // and thus falling out of async drawing path.
+ if (subtree->ownedBitmapResources.size()) {
+ info.prepareTextures = false;
+ }
+ for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
+ info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}
for (size_t i = 0; i < subtree->children().size(); i++) {
RenderNode* childNode = subtree->children()[i]->mDisplayList;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 9e6ee3f..6688952 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -66,7 +66,13 @@ class RestoreToCountOp;
class DrawDisplayListOp;
struct TreeInfo {
+ TreeInfo()
+ : hasFunctors(false)
+ , prepareTextures(false)
+ {}
+
bool hasFunctors;
+ bool prepareTextures;
// TODO: Damage calculations? Flag to skip staging pushes for RT animations?
};
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 7923ce7..e783905 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -25,14 +25,14 @@ namespace android {
namespace uirenderer {
Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+ cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
}
Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+ cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index d48ec59..d5601f8 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -94,6 +94,12 @@ public:
*/
const UvMapper* uvMapper;
+ /**
+ * Whether or not the Texture is marked in use and thus not evictable for
+ * the current frame. This is reset at the start of a new frame.
+ */
+ bool isInUse;
+
private:
/**
* Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 01d72d1..34e2265 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -121,29 +121,49 @@ void TextureCache::operator()(const SkBitmap*&, Texture*& texture) {
// Caching
///////////////////////////////////////////////////////////////////////////////
-Texture* TextureCache::get(const SkBitmap* bitmap) {
+void TextureCache::resetMarkInUse() {
+ LruCache<const SkBitmap*, Texture*>::Iterator iter(mCache);
+ while (iter.next()) {
+ iter.value()->isInUse = false;
+ }
+}
+
+bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
+ if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
+ ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
+ bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+ return false;
+ }
+ return true;
+}
+
+// Returns a prepared Texture* that either is already in the cache or can fit
+// in the cache (and is thus added to the cache)
+Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
Texture* texture = mCache.get(bitmap);
if (!texture) {
- if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
- ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
- bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+ if (!canMakeTextureFromBitmap(bitmap)) {
return NULL;
}
const uint32_t size = bitmap->rowBytes() * bitmap->height();
+ bool canCache = size < mMaxSize;
// Don't even try to cache a bitmap that's bigger than the cache
- if (size < mMaxSize) {
- while (mSize + size > mMaxSize) {
+ while (canCache && mSize + size > mMaxSize) {
+ Texture* oldest = mCache.peekOldestValue();
+ if (oldest && !oldest->isInUse) {
mCache.removeOldest();
+ } else {
+ canCache = false;
}
}
- texture = new Texture();
- texture->bitmapSize = size;
- generateTexture(bitmap, texture, false);
+ if (canCache) {
+ texture = new Texture();
+ texture->bitmapSize = size;
+ generateTexture(bitmap, texture, false);
- if (size < mMaxSize) {
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
bitmap, texture->id, size, mSize);
@@ -151,16 +171,42 @@ Texture* TextureCache::get(const SkBitmap* bitmap) {
ALOGD("Texture created, size = %d", size);
}
mCache.put(bitmap, texture);
- } else {
- texture->cleanup = true;
}
- } else if (bitmap->getGenerationID() != texture->generation) {
+ } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
+ // Texture was in the cache but is dirty, re-upload
+ // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
generateTexture(bitmap, texture, true);
}
return texture;
}
+bool TextureCache::prefetchAndMarkInUse(const SkBitmap* bitmap) {
+ Texture* texture = getCachedTexture(bitmap);
+ if (texture) {
+ texture->isInUse = true;
+ }
+ return texture;
+}
+
+Texture* TextureCache::get(const SkBitmap* bitmap) {
+ Texture* texture = getCachedTexture(bitmap);
+
+ if (!texture) {
+ if (!canMakeTextureFromBitmap(bitmap)) {
+ return NULL;
+ }
+
+ const uint32_t size = bitmap->rowBytes() * bitmap->height();
+ texture = new Texture();
+ texture->bitmapSize = size;
+ generateTexture(bitmap, texture, false);
+ texture->cleanup = true;
+ }
+
+ return texture;
+}
+
Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
Texture* texture = new Texture();
texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index e33c60d..48a10c2 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -62,6 +62,18 @@ public:
void operator()(const SkBitmap*& bitmap, Texture*& texture);
/**
+ * Resets all Textures to not be marked as in use
+ */
+ void resetMarkInUse();
+
+ /**
+ * Attempts to precache the SkBitmap. Returns true if a Texture was successfully
+ * acquired for the bitmap, false otherwise. If a Texture was acquired it is
+ * marked as in use.
+ */
+ bool prefetchAndMarkInUse(const SkBitmap* bitmap);
+
+ /**
* Returns the texture associated with the specified bitmap. If the texture
* cannot be found in the cache, a new texture is generated.
*/
@@ -116,6 +128,11 @@ public:
void setFlushRate(float flushRate);
private:
+
+ bool canMakeTextureFromBitmap(const SkBitmap* bitmap);
+
+ Texture* getCachedTexture(const SkBitmap* bitmap);
+
/**
* Generates the texture from a bitmap into the specified texture structure.
*
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 3638184..a8980af 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -382,13 +382,18 @@ void CanvasContext::setup(int width, int height) {
mCanvas->setViewport(width, height);
}
+void CanvasContext::makeCurrent() {
+ mGlobalContext->makeCurrent(mEglSurface);
+}
+
void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
- bool* hasFunctors) {
+ TreeInfo& info) {
LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
- mGlobalContext->makeCurrent(mEglSurface);
+ makeCurrent();
for (size_t i = 0; i < layerUpdaters->size(); i++) {
DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
- LOG_ALWAYS_FATAL_IF(!update->apply(hasFunctors), "Failed to update layer!");
+ bool success = update->apply(info);
+ LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
if (update->backingLayer()->deferredUpdateScheduled) {
mCanvas->pushLayerUpdate(update->backingLayer());
}
@@ -444,8 +449,8 @@ void CanvasContext::invokeFunctor(Functor* functor) {
bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
requireGlContext();
- bool hasFunctors;
- layer->apply(&hasFunctors);
+ TreeInfo info;
+ layer->apply(info);
return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index dcb5957..bbf1b9a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -23,6 +23,7 @@
#include <utils/Functor.h>
#include <utils/Vector.h>
+#include "../RenderNode.h"
#include "RenderTask.h"
#define FUNCTOR_PROCESS_DELAY 4
@@ -31,8 +32,6 @@ namespace android {
namespace uirenderer {
class DeferredLayerUpdater;
-class RenderNode;
-class DisplayListData;
class OpenGLRenderer;
class Rect;
class Layer;
@@ -54,7 +53,8 @@ public:
void updateSurface(EGLNativeWindowType window);
void pauseSurface(EGLNativeWindowType window);
void setup(int width, int height);
- void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, bool* hasFunctors);
+ void makeCurrent();
+ void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
void drawDisplayList(RenderNode* displayList, Rect* dirty);
void destroyCanvas();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index cf6c8db..f542d43 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -85,7 +85,6 @@ void DrawFrameTask::postAndWait(RenderThread* renderThread) {
void DrawFrameTask::run() {
ATRACE_NAME("DrawFrame");
- // canUnblockUiThread is temporary until WebView has a solution for syncing frame state
bool canUnblockUiThread = syncFrameState();
// Grab a copy of everything we need
@@ -105,17 +104,20 @@ void DrawFrameTask::run() {
}
}
+static void prepareTreeInfo(TreeInfo& info) {
+ info.prepareTextures = true;
+}
+
bool DrawFrameTask::syncFrameState() {
ATRACE_CALL();
-
- bool hasFunctors = false;
- mContext->processLayerUpdates(&mLayers, &hasFunctors);
-
- TreeInfo info = {0};
+ mContext->makeCurrent();
+ Caches::getInstance().textureCache.resetMarkInUse();
+ TreeInfo info;
+ prepareTreeInfo(info);
+ mContext->processLayerUpdates(&mLayers, info);
mRenderNode->prepareTree(info);
- hasFunctors |= info.hasFunctors;
-
- return !hasFunctors;
+ // If prepareTextures is false, we ran out of texture cache space
+ return !info.hasFunctors && info.prepareTextures;
}
void DrawFrameTask::unblockUiThread() {