Support HardwareLayers in RenderThread
Also has a few HardwareLayer lifecycle fixes Change-Id: I6308cb05f8f199eed72189ace768013a46815941
This commit is contained in:
@@ -3949,6 +3949,7 @@ public final class ActivityThread {
|
||||
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);
|
||||
|
||||
@@ -477,17 +477,21 @@ public class GLRenderer extends HardwareRenderer {
|
||||
|
||||
@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 @@ public class GLRenderer extends HardwareRenderer {
|
||||
|
||||
@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);
|
||||
}
|
||||
@@ -537,35 +544,6 @@ public class GLRenderer extends HardwareRenderer {
|
||||
return true;
|
||||
}
|
||||
|
||||
@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) {
|
||||
@@ -1069,7 +1047,6 @@ public class GLRenderer extends HardwareRenderer {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean validate() {
|
||||
return checkRenderContext() != SURFACE_STATE_ERROR;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import android.graphics.SurfaceTexture;
|
||||
*/
|
||||
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 @@ final class HardwareLayer {
|
||||
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 @@ final class HardwareLayer {
|
||||
}
|
||||
|
||||
public DisplayList startRecording() {
|
||||
assertType(LAYER_TYPE_RENDER);
|
||||
assertType(LAYER_TYPE_DISPLAY_LIST);
|
||||
|
||||
if (mDisplayList == null) {
|
||||
mDisplayList = DisplayList.create("HardwareLayer");
|
||||
@@ -172,9 +176,17 @@ final class HardwareLayer {
|
||||
/**
|
||||
* 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 @@ final class HardwareLayer {
|
||||
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 */
|
||||
|
||||
@@ -233,13 +233,6 @@ public abstract class HardwareRenderer {
|
||||
*/
|
||||
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.
|
||||
@@ -256,15 +249,6 @@ public abstract class HardwareRenderer {
|
||||
*/
|
||||
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.
|
||||
|
||||
@@ -231,26 +231,12 @@ public class TextureView extends View {
|
||||
@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 class TextureView extends View {
|
||||
*/
|
||||
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();
|
||||
|
||||
|
||||
@@ -75,14 +75,8 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
nUpdateSurface(mNativeProxy, surface);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
@@ -105,12 +99,6 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
updateSurface(surface);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean validate() {
|
||||
// TODO Remove users of this API
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean safelyRun(Runnable action) {
|
||||
nRunWithGlContext(mNativeProxy, action);
|
||||
@@ -150,26 +138,6 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
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
|
||||
@@ -202,26 +170,6 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
dirty.left, dirty.top, dirty.right, dirty.bottom);
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -232,6 +180,56 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
nAttachFunctor(mNativeProxy, functor);
|
||||
}
|
||||
|
||||
@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 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -13584,19 +13584,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
|
||||
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 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!mAttachInfo.mHardwareRenderer.validate()) return null;
|
||||
|
||||
final int width = mRight - mLeft;
|
||||
final int height = mBottom - mTop;
|
||||
|
||||
|
||||
@@ -631,16 +631,25 @@ public final class ViewRootImpl implements ViewParent,
|
||||
}
|
||||
} 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 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
void dispatchDetachedFromWindow() {
|
||||
if (mView != null && mView.mAttachInfo != null) {
|
||||
if (mAttachInfo.mHardwareRenderer != null &&
|
||||
mAttachInfo.mHardwareRenderer.isEnabled()) {
|
||||
mAttachInfo.mHardwareRenderer.validate();
|
||||
}
|
||||
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
|
||||
mView.dispatchDetachedFromWindow();
|
||||
}
|
||||
|
||||
@@ -76,20 +76,20 @@ static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject claz
|
||||
|
||||
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_updateSurface(JNIEnv* env, jobject cla
|
||||
|
||||
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 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "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
|
||||
};
|
||||
|
||||
|
||||
@@ -123,27 +123,5 @@ void DeferredLayerUpdater::doUpdateTexImage() {
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
@@ -82,7 +82,6 @@ public:
|
||||
ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
|
||||
|
||||
ANDROID_API bool apply();
|
||||
ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
|
||||
|
||||
ANDROID_API Layer* backingLayer() {
|
||||
return mLayer;
|
||||
|
||||
@@ -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 @@ void CanvasContext::setup(int width, int height) {
|
||||
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 @@ void CanvasContext::queueFunctorsTask(int delayMs) {
|
||||
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 */
|
||||
|
||||
@@ -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 @@ public:
|
||||
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 @@ private:
|
||||
void removeFunctorsTask();
|
||||
void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
|
||||
|
||||
void requireGlContext();
|
||||
|
||||
GlobalContext* mGlobalContext;
|
||||
RenderThread& mRenderThread;
|
||||
EGLSurface mEglSurface;
|
||||
|
||||
@@ -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 @@ namespace renderthread {
|
||||
|
||||
#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 @@ void RenderProxy::setup(int width, int height) {
|
||||
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 @@ void RenderProxy::drawDisplayList(DisplayList* displayList,
|
||||
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 @@ void RenderProxy::runWithGlContext(RenderTask* gltask) {
|
||||
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);
|
||||
|
||||
@@ -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 @@ public:
|
||||
|
||||
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 @@ private:
|
||||
Mutex mSyncMutex;
|
||||
Condition mSyncCondition;
|
||||
|
||||
Vector<DeferredLayerUpdater*> mLayers;
|
||||
|
||||
void destroyContext();
|
||||
|
||||
MethodInvokeRenderTask* createTask(RunnableMethod method);
|
||||
|
||||
Reference in New Issue
Block a user