Re-jigger layers
Bug: 15185239
Bug: 15238382
Make DeferredLayerUpdater ref counted so that
HardwareLayer:finalizer() works non-crashily on
leaked layers
Give DeferredLayerUpdater the ability to have a layer destroyer
set so that leaked layers can still be recycled on the
RenderThread
Order layer updates based off of pushLayerUpdate() calls to fix
issue with nested layers
Change-Id: I4449cee607f7e5126e02fed7464cf48038e3dfdf
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 285c8c3..97e9bf6 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -22,14 +22,19 @@
namespace android {
namespace uirenderer {
-DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
+static void defaultLayerDestroyer(Layer* layer) {
+ Caches::getInstance().resourceCache.decrementRefcount(layer);
+}
+
+DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
: mDisplayList(0)
, mSurfaceTexture(0)
, mTransform(0)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
, mLayer(layer)
- , mCaches(Caches::getInstance()) {
+ , mCaches(Caches::getInstance())
+ , mDestroyer(destroyer) {
mWidth = mLayer->layer.getWidth();
mHeight = mLayer->layer.getHeight();
mBlend = mLayer->isBlend();
@@ -37,14 +42,16 @@
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
mDirtyRect.setEmpty();
+
+ if (!mDestroyer) {
+ mDestroyer = defaultLayerDestroyer;
+ }
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
SkSafeUnref(mColorFilter);
setTransform(0);
- if (mLayer) {
- mCaches.resourceCache.decrementRefcount(mLayer);
- }
+ mDestroyer(mLayer);
}
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index cc62caa..b7cfe80 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -30,13 +30,15 @@
namespace android {
namespace uirenderer {
+typedef void (*LayerDestroyer)(Layer* layer);
+
// Container to hold the properties a layer should be set to at the start
// of a render pass
-class DeferredLayerUpdater {
+class DeferredLayerUpdater : public VirtualLightRefBase {
public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
- ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
+ ANDROID_API DeferredLayerUpdater(Layer* layer, LayerDestroyer = 0);
ANDROID_API ~DeferredLayerUpdater();
ANDROID_API bool setSize(uint32_t width, uint32_t height) {
@@ -83,12 +85,6 @@
return mLayer;
}
- ANDROID_API Layer* detachBackingLayer() {
- Layer* layer = mLayer;
- mLayer = 0;
- return layer;
- }
-
private:
// Generic properties
uint32_t mWidth;
@@ -111,6 +107,8 @@
Layer* mLayer;
Caches& mCaches;
+ LayerDestroyer mDestroyer;
+
void doUpdateTexImage();
};
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f91e90e..9ebee1d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -427,27 +427,11 @@
mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
}
-void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
- TreeInfo& info) {
- LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
- makeCurrent();
-
- processLayerUpdates(layerUpdaters, info);
- if (info.out.hasAnimations) {
- // TODO: Uh... crap?
- }
- prepareTree(info);
-}
-
-void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
- TreeInfo& info) {
- for (size_t i = 0; i < layerUpdaters->size(); i++) {
- DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
- bool success = update->apply(info);
- LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
- if (update->backingLayer()->deferredUpdateScheduled) {
- mCanvas->pushLayerUpdate(update->backingLayer());
- }
+void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
+ bool success = layerUpdater->apply(info);
+ LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
+ if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
+ mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
}
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a04269b..00c5bf0 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -55,7 +55,8 @@
void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
void makeCurrent();
- void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+ void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
+ void prepareTree(TreeInfo& info);
void draw(Rect* dirty);
void destroyCanvasAndSurface();
@@ -83,9 +84,6 @@
private:
friend class RegisterFrameCallbackTask;
- void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
- void prepareTree(TreeInfo& info);
-
void setSurface(ANativeWindow* window);
void swapBuffers();
void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 7ea358f..61d67ca 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -21,6 +21,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include "../DeferredLayerUpdater.h"
#include "../DisplayList.h"
#include "../RenderNode.h"
#include "CanvasContext.h"
@@ -47,17 +48,22 @@
mContext = context;
}
-void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
- LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
+void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
+ LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
- mLayers.push(layer);
+ for (size_t i = 0; i < mLayers.size(); i++) {
+ if (mLayers[i].get() == layer) {
+ return;
+ }
+ }
+ mLayers.push_back(layer);
}
-void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) {
+void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
for (size_t i = 0; i < mLayers.size(); i++) {
- if (mLayers[i] == layer) {
- mLayers.removeAt(i);
- break;
+ if (mLayers[i].get() == layer) {
+ mLayers.erase(mLayers.begin() + i);
+ return;
}
}
}
@@ -132,7 +138,16 @@
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse();
initTreeInfo(info);
- mContext->prepareDraw(&mLayers, info);
+
+ for (size_t i = 0; i < mLayers.size(); i++) {
+ mContext->processLayerUpdate(mLayers[i].get(), info);
+ }
+ mLayers.clear();
+ if (info.out.hasAnimations) {
+ // TODO: Uh... crap?
+ }
+ mContext->prepareTree(info);
+
if (info.out.hasAnimations) {
// TODO: dirty calculations, for now just do a full-screen inval
mDirty.setEmpty();
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 30c8880..d4129b6 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,10 +16,11 @@
#ifndef DRAWFRAMETASK_H
#define DRAWFRAMETASK_H
+#include <vector>
+
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
-#include <utils/Vector.h>
#include "RenderTask.h"
@@ -56,8 +57,8 @@
void setContext(RenderThread* thread, CanvasContext* context);
- void addLayer(DeferredLayerUpdater* layer);
- void removeLayer(DeferredLayerUpdater* layer);
+ void pushLayerUpdate(DeferredLayerUpdater* layer);
+ void removeLayerUpdate(DeferredLayerUpdater* layer);
void setDirty(int left, int top, int right, int bottom);
void setDensity(float density) { mDensity = density; }
@@ -83,13 +84,9 @@
nsecs_t mFrameTimeNanos;
nsecs_t mRecordDurationNanos;
float mDensity;
+ std::vector< sp<DeferredLayerUpdater> > mLayers;
int mSyncResult;
-
- /*********************************************
- * Multi frame data
- *********************************************/
- Vector<DeferredLayerUpdater*> mLayers;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 77c0aa7..0901963 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -229,10 +229,21 @@
postAndWait(task);
}
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+ LayerRenderer::destroyLayer(args->layer);
+ return NULL;
+}
+
+static void enqueueDestroyLayer(Layer* layer) {
+ SETUP_TASK(destroyLayer);
+ args->layer = layer;
+ RenderThread::getInstance().queue(task);
+}
+
CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
Layer* layer = args->context->createRenderLayer(args->width, args->height);
if (!layer) return 0;
- return new DeferredLayerUpdater(layer);
+ return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
}
DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
@@ -242,14 +253,13 @@
args->context = mContext;
void* retval = postAndWait(task);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
- mDrawFrameTask.addLayer(layer);
return layer;
}
CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
Layer* layer = args->context->createTextureLayer();
if (!layer) return 0;
- return new DeferredLayerUpdater(layer);
+ return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
}
DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -257,15 +267,9 @@
args->context = mContext;
void* retval = postAndWait(task);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
- mDrawFrameTask.addLayer(layer);
return layer;
}
-CREATE_BRIDGE1(destroyLayer, Layer* layer) {
- LayerRenderer::destroyLayer(args->layer);
- return NULL;
-}
-
CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
SkBitmap* bitmap) {
bool success = args->context->copyLayerInto(args->layer, args->bitmap);
@@ -280,11 +284,12 @@
return (bool) postAndWait(task);
}
-void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
- mDrawFrameTask.removeLayer(layer);
- SETUP_TASK(destroyLayer);
- args->layer = layer->detachBackingLayer();
- post(task);
+void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
+ mDrawFrameTask.pushLayerUpdate(layer);
+}
+
+void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
+ mDrawFrameTask.removeLayerUpdate(layer);
}
CREATE_BRIDGE2(flushCaches, CanvasContext* context, Caches::FlushMode flushMode) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c8d42ec..944ff9c 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -80,7 +80,8 @@
ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
ANDROID_API DeferredLayerUpdater* createTextureLayer();
ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
- ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+ ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
+ ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void flushCaches(Caches::FlushMode flushMode);