diff options
author | John Reck <jreck@google.com> | 2014-04-11 19:15:05 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-04-14 13:17:25 -0700 |
commit | 860d155f866cc15a725e7ce03763280987f24901 (patch) | |
tree | 1ade6b4f5c2c0910c088469b95255eb66ce0cb53 | |
parent | db8b130a19484cb6018667905e64d42ab793654f (diff) | |
download | frameworks_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.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_view_HardwareLayer.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 2 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 20 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 6 | ||||
-rw-r--r-- | libs/hwui/Texture.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Texture.h | 6 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 72 | ||||
-rw-r--r-- | libs/hwui/TextureCache.h | 17 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 6 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 20 |
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() { |