Support HardwareLayers in RenderThread
Also has a few HardwareLayer lifecycle fixes
Change-Id: I6308cb05f8f199eed72189ace768013a46815941
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 30c1e62..3258585 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3949,6 +3949,7 @@
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
// Cleanup hardware accelerated stuff
+ // TODO: Do we actually want to do this in response to all config changes?
WindowManagerGlobal.getInstance().trimLocalMemory();
freeTextLayoutCachesIfNeeded(configDiff);
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index c1eb6b7..859468a 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -477,17 +477,21 @@
@Override
void flushLayerUpdates() {
- mGlCanvas.flushLayerUpdates();
+ if (validate()) {
+ mGlCanvas.flushLayerUpdates();
+ }
}
@Override
HardwareLayer createTextureLayer() {
+ validate();
return HardwareLayer.createTextureLayer(this);
}
@Override
public HardwareLayer createDisplayListLayer(int width, int height) {
- return HardwareLayer.createRenderLayer(this, width, height);
+ validate();
+ return HardwareLayer.createDisplayListLayer(this, width, height);
}
@Override
@@ -510,6 +514,9 @@
@Override
boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+ if (!validate()) {
+ throw new IllegalStateException("Could not acquire hardware rendering context");
+ }
layer.flushChanges();
return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
}
@@ -538,35 +545,6 @@
}
@Override
- void destroyLayers(final View view) {
- if (view != null) {
- safelyRun(new Runnable() {
- @Override
- public void run() {
- if (mCanvas != null) {
- mCanvas.clearLayerUpdates();
- }
- destroyHardwareLayer(view);
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
- }
- });
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
- }
-
- @Override
void destroyHardwareResources(final View view) {
if (view != null) {
safelyRun(new Runnable() {
@@ -1069,7 +1047,6 @@
return true;
}
- @Override
boolean validate() {
return checkRenderContext() != SURFACE_STATE_ERROR;
}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 9bbcf7c..958c071 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -33,7 +33,7 @@
*/
final class HardwareLayer {
private static final int LAYER_TYPE_TEXTURE = 1;
- private static final int LAYER_TYPE_RENDER = 2;
+ private static final int LAYER_TYPE_DISPLAY_LIST = 2;
private HardwareRenderer mRenderer;
private Finalizer mFinalizer;
@@ -99,6 +99,10 @@
doDestroyLayerUpdater();
}
+ public long getDeferredLayerUpdater() {
+ return mFinalizer.mDeferredUpdater;
+ }
+
/**
* Destroys the deferred layer updater but not the backing layer. The
* backing layer is instead returned and is the caller's responsibility
@@ -120,7 +124,7 @@
}
public DisplayList startRecording() {
- assertType(LAYER_TYPE_RENDER);
+ assertType(LAYER_TYPE_DISPLAY_LIST);
if (mDisplayList == null) {
mDisplayList = DisplayList.create("HardwareLayer");
@@ -172,9 +176,17 @@
/**
* Indicates that this layer has lost its texture.
*/
- public void onTextureDestroyed() {
+ public void detachSurfaceTexture(final SurfaceTexture surface) {
assertType(LAYER_TYPE_TEXTURE);
- nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+ mRenderer.safelyRun(new Runnable() {
+ @Override
+ public void run() {
+ surface.detachFromGLContext();
+ // SurfaceTexture owns the texture name and detachFromGLContext
+ // should have deleted it
+ nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+ }
+ });
}
/**
@@ -226,12 +238,20 @@
return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
}
+ static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
+ return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
+ }
+
/**
* This should only be used by HardwareRenderer! Do not call directly
*/
- static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+ static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
int width, int height) {
- return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+ return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
+ }
+
+ static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
+ return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
}
/** This also creates the underlying layer */
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 93cc9d1..7a943f0 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,13 +234,6 @@
abstract void updateSurface(Surface surface) throws OutOfResourcesException;
/**
- * Destroys the layers used by the specified view hierarchy.
- *
- * @param view The root of the view hierarchy
- */
- abstract void destroyLayers(View view);
-
- /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
@@ -257,15 +250,6 @@
abstract void invalidate(Surface surface);
/**
- * This method should be invoked to ensure the hardware renderer is in
- * valid state (for instance, to ensure the correct EGL context is bound
- * to the current thread.)
- *
- * @return true if the renderer is now valid, false otherwise
- */
- abstract boolean validate();
-
- /**
* This method ensures the hardware renderer is in a valid state
* before executing the specified action.
*
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index e789407..ef0d80d 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -231,26 +231,12 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mLayer != null) {
- boolean success = executeHardwareAction(new Runnable() {
- @Override
- public void run() {
- destroySurface();
- }
- });
-
- if (!success) {
- Log.w(LOG_TAG, "TextureView was not able to destroy its surface: " + this);
- }
- }
+ destroySurface();
}
private void destroySurface() {
if (mLayer != null) {
- mSurface.detachFromGLContext();
- // SurfaceTexture owns the texture name and detachFromGLContext
- // should have deleted it
- mLayer.onTextureDestroyed();
+ mLayer.detachSurfaceTexture(mSurface);
boolean shouldRelease = true;
if (mListener != null) {
@@ -608,14 +594,6 @@
*/
public Bitmap getBitmap(Bitmap bitmap) {
if (bitmap != null && isAvailable()) {
- AttachInfo info = mAttachInfo;
- if (info != null && info.mHardwareRenderer != null &&
- info.mHardwareRenderer.isEnabled()) {
- if (!info.mHardwareRenderer.validate()) {
- throw new IllegalStateException("Could not acquire hardware rendering context");
- }
- }
-
applyUpdate();
applyTransformMatrix();
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1d7e5b2..e8f5e45 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -76,13 +76,7 @@
}
@Override
- void destroyLayers(View view) {
- throw new NoSuchMethodError();
- }
-
- @Override
void destroyHardwareResources(View view) {
- // TODO: canvas.clearLayerUpdates()
destroyResources(view);
// TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
}
@@ -106,12 +100,6 @@
}
@Override
- boolean validate() {
- // TODO Remove users of this API
- return false;
- }
-
- @Override
boolean safelyRun(Runnable action) {
nRunWithGlContext(mNativeProxy, action);
return true;
@@ -150,26 +138,6 @@
return false;
}
- @Override
- void pushLayerUpdate(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void onLayerCreated(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void onLayerDestroyed(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void flushLayerUpdates() {
- throw new NoSuchMethodError();
- }
-
/**
* TODO: Remove
* Temporary hack to allow RenderThreadTest prototype app to trigger
@@ -203,26 +171,6 @@
}
@Override
- HardwareLayer createTextureLayer() {
- throw new NoSuchMethodError();
- }
-
- @Override
- HardwareLayer createDisplayListLayer(int width, int height) {
- throw new NoSuchMethodError();
- }
-
- @Override
- SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
- throw new NoSuchMethodError();
- }
-
- @Override
void detachFunctor(long functor) {
nDetachFunctor(mNativeProxy, functor);
}
@@ -233,6 +181,56 @@
}
@Override
+ HardwareLayer createDisplayListLayer(int width, int height) {
+ long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
+ return HardwareLayer.adoptDisplayListLayer(this, layer);
+ }
+
+ @Override
+ HardwareLayer createTextureLayer() {
+ long layer = nCreateTextureLayer(mNativeProxy);
+ return HardwareLayer.adoptTextureLayer(this, layer);
+ }
+
+ @Override
+ SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
+ final SurfaceTexture[] ret = new SurfaceTexture[1];
+ nRunWithGlContext(mNativeProxy, new Runnable() {
+ @Override
+ public void run() {
+ ret[0] = layer.createSurfaceTexture();
+ }
+ });
+ return ret[0];
+ }
+
+ @Override
+ boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
+ return nCopyLayerInto(mNativeProxy,
+ layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+ }
+
+ @Override
+ void pushLayerUpdate(HardwareLayer layer) {
+ // TODO: Remove this, it's not needed outside of GLRenderer
+ }
+
+ @Override
+ void onLayerCreated(HardwareLayer layer) {
+ // TODO: Is this actually useful?
+ }
+
+ @Override
+ void flushLayerUpdates() {
+ // TODO: Figure out what this should do or remove it
+ }
+
+ @Override
+ void onLayerDestroyed(HardwareLayer layer) {
+ nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
+ }
+
+ @Override
void setName(String name) {
}
@@ -261,4 +259,9 @@
private static native void nAttachFunctor(long nativeProxy, long functor);
private static native void nDetachFunctor(long nativeProxy, long functor);
+
+ private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
+ private static native long nCreateTextureLayer(long nativeProxy);
+ private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+ private static native void nDestroyLayer(long nativeProxy, long layer);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49dc572..9e7046e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13584,19 +13584,15 @@
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- if (attachInfo.mHardwareRenderer != null &&
- attachInfo.mHardwareRenderer.isEnabled() &&
- attachInfo.mHardwareRenderer.validate()) {
- getHardwareLayer();
- // TODO: We need a better way to handle this case
- // If views have registered pre-draw listeners they need
- // to be notified before we build the layer. Those listeners
- // may however rely on other events to happen first so we
- // cannot just invoke them here until they don't cancel the
- // current frame
- if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
- attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
- }
+ getHardwareLayer();
+ // TODO: We need a better way to handle this case
+ // If views have registered pre-draw listeners they need
+ // to be notified before we build the layer. Those listeners
+ // may however rely on other events to happen first so we
+ // cannot just invoke them here until they don't cancel the
+ // current frame
+ if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
+ attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
}
break;
case LAYER_TYPE_SOFTWARE:
@@ -13617,8 +13613,6 @@
return null;
}
- if (!mAttachInfo.mHardwareRenderer.validate()) return null;
-
final int width = mRight - mLeft;
final int height = mBottom - mTop;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 11030d9..a68d06a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,16 +631,25 @@
}
} else {
invalidateDisplayLists();
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+ destroyHardwareLayer(mView);
+ }
+ }
+
+ private static void destroyHardwareLayer(View view) {
+ view.destroyLayer(true);
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyHardwareLayer(group.getChildAt(i));
}
}
}
void flushHardwareLayerUpdates() {
- if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
- mAttachInfo.mHardwareRenderer.validate()) {
+ if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
}
@@ -2845,10 +2854,6 @@
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.validate();
- }
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e86a2d4..bc5c06e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -76,20 +76,20 @@
static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
delete proxy;
}
static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
return proxy->initialize(window.get());
}
static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window;
if (jsurface) {
window = android_view_Surface_getNativeWindow(env, jsurface);
@@ -99,45 +99,74 @@
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
jlong proxyPtr, jint width, jint height) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->setup(width, height);
}
static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
jint dirtyRight, jint dirtyBottom) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
- DisplayList* displayList = reinterpret_cast<DisplayList*>( displayListPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
}
static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroyCanvas();
}
static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong functorPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
proxy->attachFunctor(functor);
}
static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong functorPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
proxy->detachFunctor(functor);
}
static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jrunnable) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
RenderTask* task = new JavaTask(env, jrunnable);
proxy->runWithGlContext(task);
}
+static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint width, jint height) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
+ return reinterpret_cast<jlong>(layer);
+}
+
+static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = proxy->createTextureLayer();
+ return reinterpret_cast<jlong>(layer);
+}
+
+static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+ return proxy->copyLayerInto(layer, bitmap);
+}
+
+static void android_view_ThreadedRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ proxy->destroyLayer(layer);
+}
+
#endif
// ----------------------------------------------------------------------------
@@ -159,6 +188,10 @@
{ "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
{ "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
+ { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
+ { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
+ { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+ { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
#endif
};
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5d3d393..efb1298 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -123,27 +123,5 @@
}
}
-void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
- // Default assignment operator doesn't quite work, and fails due to mCaches anyway
- deferredApply->mWidth = mWidth;
- deferredApply->mHeight = mHeight;
- deferredApply->mBlend = mBlend;
- deferredApply->mAlpha = mAlpha;
- deferredApply->mMode = mMode;
- deferredApply->mDirtyRect.set(mDirtyRect);
- deferredApply->mDisplayList = mDisplayList;
- deferredApply->mSurfaceTexture = mSurfaceTexture;
- deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
- deferredApply->mUpdateTexImage = mUpdateTexImage;
- deferredApply->setColorFilter(mColorFilter);
- deferredApply->setTransform(mTransform);
-
- mDisplayList = 0;
- mDirtyRect.setEmpty();
- mTransform = 0;
- mNeedsGLContextAttach = false;
- mUpdateTexImage = false;
-}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9800c2f..624db2c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -82,7 +82,6 @@
ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
ANDROID_API bool apply();
- ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
ANDROID_API Layer* backingLayer() {
return mLayer;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4e665d9..fe781bd 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -24,6 +24,8 @@
#include "RenderThread.h"
#include "../Caches.h"
+#include "../DeferredLayerUpdater.h"
+#include "../LayerRenderer.h"
#include "../OpenGLRenderer.h"
#include "../Stencil.h"
@@ -371,6 +373,17 @@
mCanvas->setViewport(width, height);
}
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+ mGlobalContext->makeCurrent(mEglSurface);
+ for (size_t i = 0; i < layerUpdaters->size(); i++) {
+ DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
+ LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+ if (update->backingLayer()->deferredUpdateScheduled) {
+ mCanvas->pushLayerUpdate(update->backingLayer());
+ }
+ }
+}
+
void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawDisplayList called on a context with no canvas or surface!");
@@ -462,14 +475,23 @@
mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
}
+bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ requireGlContext();
+ layer->apply();
+ return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
+}
+
void CanvasContext::runWithGlContext(RenderTask* task) {
+ requireGlContext();
+ task->run();
+}
+
+void CanvasContext::requireGlContext() {
if (mEglSurface != EGL_NO_SURFACE) {
mGlobalContext->makeCurrent(mEglSurface);
} else {
mGlobalContext->usePBufferSurface();
}
-
- task->run();
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3197df3..5fac582 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -19,7 +19,9 @@
#include <cutils/compiler.h>
#include <EGL/egl.h>
+#include <SkBitmap.h>
#include <utils/Functor.h>
+#include <utils/Vector.h>
#include "RenderTask.h"
@@ -28,6 +30,7 @@
namespace android {
namespace uirenderer {
+class DeferredLayerUpdater;
class DisplayList;
class OpenGLRenderer;
class Rect;
@@ -59,9 +62,12 @@
bool initialize(EGLNativeWindowType window);
void updateSurface(EGLNativeWindowType window);
void setup(int width, int height);
+ void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
void drawDisplayList(DisplayList* displayList, Rect* dirty);
void destroyCanvas();
+ bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+
void attachFunctor(Functor* functor);
void detachFunctor(Functor* functor);
@@ -78,6 +84,8 @@
void removeFunctorsTask();
void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
+ void requireGlContext();
+
GlobalContext* mGlobalContext;
RenderThread& mRenderThread;
EGLSurface mEglSurface;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f1961..0c667fd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,7 +22,9 @@
#include "RenderTask.h"
#include "RenderThread.h"
+#include "../DeferredLayerUpdater.h"
#include "../DisplayList.h"
+#include "../LayerRenderer.h"
#include "../Rect.h"
namespace android {
@@ -31,6 +33,7 @@
#define ARGS(method) method ## Args
+#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
@@ -114,13 +117,14 @@
post(task);
}
-CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
- Rect dirty) {
+CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList,
+ Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) {
Rect* dirty = &args->dirty;
if (dirty->bottom == -1 && dirty->left == -1 &&
dirty->top == -1 && dirty->right == -1) {
dirty = 0;
}
+ args->context->processLayerUpdates(args->layerUpdates);
args->context->drawDisplayList(args->displayList, dirty);
return NULL;
}
@@ -131,6 +135,7 @@
args->context = mContext;
args->displayList = displayList;
args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ args->layerUpdates = &mLayers;
// TODO: Switch to post() once some form of thread safety strategy is in place
postAndWait(task);
}
@@ -182,6 +187,70 @@
postAndWait(task);
}
+CREATE_BRIDGE2(createDisplayListLayer, int width, int height) {
+ Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height);
+ if (!layer) return 0;
+
+ OpenGLRenderer* renderer = new LayerRenderer(layer);
+ renderer->initProperties();
+ return new DeferredLayerUpdater(layer, renderer);
+}
+
+DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
+ SETUP_TASK(createDisplayListLayer);
+ args->width = width;
+ args->height = height;
+ void* retval = postAndWait(task);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+ mLayers.push(layer);
+ return layer;
+}
+
+CREATE_BRIDGE0(createTextureLayer) {
+ Layer* layer = LayerRenderer::createTextureLayer();
+ if (!layer) return 0;
+ return new DeferredLayerUpdater(layer);
+}
+
+DeferredLayerUpdater* RenderProxy::createTextureLayer() {
+ SETUP_TASK(createTextureLayer);
+ void* retval = postAndWait(task);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+ mLayers.push(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);
+ return (void*) success;
+}
+
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ SETUP_TASK(copyLayerInto);
+ args->context = mContext;
+ args->layer = layer;
+ args->bitmap = bitmap;
+ return (bool) postAndWait(task);
+}
+
+void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
+ for (size_t i = 0; i < mLayers.size(); i++) {
+ if (mLayers[i] == layer) {
+ mLayers.removeAt(i);
+ break;
+ }
+ }
+ SETUP_TASK(destroyLayer);
+ args->layer = layer->detachBackingLayer();
+ post(task);
+}
+
MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
// TODO: Consider having a small pool of these to avoid alloc churn
return new MethodInvokeRenderTask(method);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1ad0c2d..8ff3d63 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -21,15 +21,19 @@
#include <cutils/compiler.h>
#include <EGL/egl.h>
+#include <SkBitmap.h>
#include <utils/Condition.h>
#include <utils/Functor.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
namespace android {
namespace uirenderer {
+class DeferredLayerUpdater;
class DisplayList;
+class Layer;
class Rect;
namespace renderthread {
@@ -64,6 +68,11 @@
ANDROID_API void runWithGlContext(RenderTask* task);
+ 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);
+
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
@@ -71,6 +80,8 @@
Mutex mSyncMutex;
Condition mSyncCondition;
+ Vector<DeferredLayerUpdater*> mLayers;
+
void destroyContext();
MethodInvokeRenderTask* createTask(RunnableMethod method);