Make RenderNodeAnimator and WebView play nice
Change-Id: Ifaefcf510b2d377663fc86f60608d6ec9be8329a
This commit is contained in:
@@ -53,6 +53,12 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
|
||||
private static final long NANOS_PER_MS = 1000000;
|
||||
|
||||
// Keep in sync with DrawFrameTask.h SYNC_* flags
|
||||
// Nothing interesting to report
|
||||
private static final int SYNC_OK = 0x0;
|
||||
// Needs a ViewRoot invalidate
|
||||
private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
|
||||
|
||||
private int mWidth, mHeight;
|
||||
private long mNativeProxy;
|
||||
private boolean mInitialized = false;
|
||||
@@ -201,8 +207,11 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
if (dirty == null) {
|
||||
dirty = NULL_RECT;
|
||||
}
|
||||
nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
|
||||
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
|
||||
dirty.left, dirty.top, dirty.right, dirty.bottom);
|
||||
if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
|
||||
attachInfo.mViewRootImpl.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -304,7 +313,7 @@ public class ThreadedRenderer extends HardwareRenderer {
|
||||
private static native void nSetup(long nativeProxy, int width, int height);
|
||||
private static native void nSetDisplayListData(long nativeProxy, long displayList,
|
||||
long newData);
|
||||
private static native void nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
|
||||
private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
|
||||
private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
|
||||
private static native void nDestroyCanvasAndSurface(long nativeProxy);
|
||||
|
||||
@@ -191,11 +191,11 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
|
||||
proxy->setup(width, height);
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
|
||||
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
|
||||
jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
|
||||
jint dirtyRight, jint dirtyBottom) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
return proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
|
||||
@@ -272,7 +272,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
|
||||
{ "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
|
||||
{ "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
|
||||
{ "nSyncAndDrawFrame", "(JJIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
|
||||
{ "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
|
||||
{ "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
|
||||
{ "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
|
||||
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
|
||||
|
||||
@@ -160,13 +160,13 @@ void RenderNode::evaluateAnimations(TreeInfo& info) {
|
||||
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
|
||||
mAnimators.erase(newEnd, mAnimators.end());
|
||||
mProperties.updateMatrix();
|
||||
info.hasAnimations |= mAnimators.size();
|
||||
info.out.hasAnimations |= mAnimators.size();
|
||||
}
|
||||
|
||||
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
|
||||
if (subtree) {
|
||||
TextureCache& cache = Caches::getInstance().textureCache;
|
||||
info.hasFunctors |= subtree->functorCount;
|
||||
info.out.hasFunctors |= subtree->functorCount;
|
||||
// TODO: Fix ownedBitmapResources to not require disabling prepareTextures
|
||||
// and thus falling out of async drawing path.
|
||||
if (subtree->ownedBitmapResources.size()) {
|
||||
|
||||
@@ -34,25 +34,33 @@ protected:
|
||||
struct TreeInfo {
|
||||
// The defaults here should be safe for everyone but DrawFrameTask to use as-is.
|
||||
TreeInfo()
|
||||
: hasFunctors(false)
|
||||
, prepareTextures(false)
|
||||
, performStagingPush(true)
|
||||
, frameTimeMs(0)
|
||||
, evaluateAnimations(false)
|
||||
, hasAnimations(false)
|
||||
, animationHook(0)
|
||||
: frameTimeMs(0)
|
||||
, animationHook(NULL)
|
||||
, prepareTextures(false)
|
||||
, performStagingPush(true)
|
||||
, evaluateAnimations(false)
|
||||
{}
|
||||
|
||||
bool hasFunctors;
|
||||
nsecs_t frameTimeMs;
|
||||
AnimationHook* animationHook;
|
||||
bool prepareTextures;
|
||||
bool performStagingPush;
|
||||
|
||||
// Animations
|
||||
nsecs_t frameTimeMs;
|
||||
bool evaluateAnimations;
|
||||
// This is only updated if evaluateAnimations is true
|
||||
bool hasAnimations;
|
||||
AnimationHook* animationHook;
|
||||
|
||||
struct Out {
|
||||
Out()
|
||||
: hasFunctors(false)
|
||||
, hasAnimations(false)
|
||||
, requiresUiRedraw(false)
|
||||
{}
|
||||
bool hasFunctors;
|
||||
// This is only updated if evaluateAnimations is true
|
||||
bool hasAnimations;
|
||||
// This is set to true if there is an animation that RenderThread cannot
|
||||
// animate itself, such as if hasFunctors is true
|
||||
// This is only set if hasAnimations is true
|
||||
bool requiresUiRedraw;
|
||||
} out;
|
||||
|
||||
// TODO: Damage calculations
|
||||
};
|
||||
|
||||
@@ -391,10 +391,20 @@ void CanvasContext::makeCurrent() {
|
||||
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) {
|
||||
LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
|
||||
makeCurrent();
|
||||
for (size_t i = 0; i < layerUpdaters->size(); i++) {
|
||||
DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
|
||||
bool success = update->apply(info);
|
||||
@@ -406,13 +416,19 @@ void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* lay
|
||||
}
|
||||
|
||||
void CanvasContext::prepareTree(TreeInfo& info) {
|
||||
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
|
||||
mRenderThread.removeFrameCallback(this);
|
||||
|
||||
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
|
||||
mRootRenderNode->prepareTree(info);
|
||||
|
||||
if (info.hasAnimations && !info.hasFunctors) {
|
||||
// TODO: Functors
|
||||
mRenderThread.postFrameCallback(this);
|
||||
if (info.out.hasAnimations) {
|
||||
if (info.out.hasFunctors) {
|
||||
info.out.requiresUiRedraw = true;
|
||||
} else if (!info.out.requiresUiRedraw) {
|
||||
// If animationsNeedsRedraw is set don't bother posting for an RT anim
|
||||
// as we will just end up fighting the UI thread.
|
||||
mRenderThread.postFrameCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ public:
|
||||
void pauseSurface(EGLNativeWindowType window);
|
||||
void setup(int width, int height);
|
||||
void makeCurrent();
|
||||
void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
|
||||
void prepareTree(TreeInfo& info);
|
||||
void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
|
||||
void draw(Rect* dirty);
|
||||
void destroyCanvasAndSurface();
|
||||
|
||||
@@ -71,6 +70,9 @@ public:
|
||||
Layer* createTextureLayer();
|
||||
|
||||
private:
|
||||
void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
|
||||
void prepareTree(TreeInfo& info);
|
||||
|
||||
void setSurface(EGLNativeWindowType window);
|
||||
void swapBuffers();
|
||||
void requireSurface();
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace renderthread {
|
||||
DrawFrameTask::DrawFrameTask()
|
||||
: mRenderThread(NULL)
|
||||
, mContext(NULL)
|
||||
, mFrameTimeNanos(NULL) {
|
||||
, mFrameTimeNanos(0)
|
||||
, mSyncResult(kSync_OK) {
|
||||
}
|
||||
|
||||
DrawFrameTask::~DrawFrameTask() {
|
||||
@@ -63,15 +64,18 @@ void DrawFrameTask::setDirty(int left, int top, int right, int bottom) {
|
||||
mDirty.set(left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
|
||||
int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
|
||||
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
|
||||
|
||||
mSyncResult = kSync_OK;
|
||||
mFrameTimeNanos = frameTimeNanos;
|
||||
postAndWait();
|
||||
|
||||
// Reset the single-frame data
|
||||
mFrameTimeNanos = 0;
|
||||
mDirty.setEmpty();
|
||||
|
||||
return mSyncResult;
|
||||
}
|
||||
|
||||
void DrawFrameTask::postAndWait() {
|
||||
@@ -114,14 +118,16 @@ bool DrawFrameTask::syncFrameState() {
|
||||
Caches::getInstance().textureCache.resetMarkInUse();
|
||||
TreeInfo info;
|
||||
initTreeInfo(info);
|
||||
mContext->processLayerUpdates(&mLayers, info);
|
||||
mContext->prepareTree(info);
|
||||
if (info.hasAnimations) {
|
||||
mContext->prepareDraw(&mLayers, info);
|
||||
if (info.out.hasAnimations) {
|
||||
// TODO: dirty calculations, for now just do a full-screen inval
|
||||
mDirty.setEmpty();
|
||||
if (info.out.requiresUiRedraw) {
|
||||
mSyncResult |= kSync_UIRedrawRequired;
|
||||
}
|
||||
}
|
||||
// If prepareTextures is false, we ran out of texture cache space
|
||||
return !info.hasFunctors && info.prepareTextures;
|
||||
return !info.out.hasFunctors && info.prepareTextures;
|
||||
}
|
||||
|
||||
void DrawFrameTask::unblockUiThread() {
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace renderthread {
|
||||
class CanvasContext;
|
||||
class RenderThread;
|
||||
|
||||
enum SyncResult {
|
||||
kSync_OK = 0,
|
||||
kSync_UIRedrawRequired = 1 << 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a special Super Task. It is re-used multiple times by RenderProxy,
|
||||
* and contains state (such as layer updaters & new DisplayListDatas) that is
|
||||
@@ -54,7 +59,7 @@ public:
|
||||
void removeLayer(DeferredLayerUpdater* layer);
|
||||
|
||||
void setDirty(int left, int top, int right, int bottom);
|
||||
void drawFrame(nsecs_t frameTimeNanos);
|
||||
int drawFrame(nsecs_t frameTimeNanos);
|
||||
|
||||
virtual void run();
|
||||
|
||||
@@ -75,6 +80,8 @@ private:
|
||||
Rect mDirty;
|
||||
nsecs_t mFrameTimeNanos;
|
||||
|
||||
int mSyncResult;
|
||||
|
||||
/*********************************************
|
||||
* Multi frame data
|
||||
*********************************************/
|
||||
|
||||
@@ -146,10 +146,10 @@ void RenderProxy::setup(int width, int height) {
|
||||
post(task);
|
||||
}
|
||||
|
||||
void RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
|
||||
mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
|
||||
mDrawFrameTask.drawFrame(frameTimeNanos);
|
||||
return mDrawFrameTask.drawFrame(frameTimeNanos);
|
||||
}
|
||||
|
||||
CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
|
||||
ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
|
||||
ANDROID_API void setup(int width, int height);
|
||||
ANDROID_API void syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
|
||||
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
|
||||
ANDROID_API void destroyCanvasAndSurface();
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ import android.os.Trace;
|
||||
import android.view.HardwareCanvas;
|
||||
import android.view.RenderNodeAnimator;
|
||||
import android.view.View;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.LinearLayout.LayoutParams;
|
||||
import android.widget.ProgressBar;
|
||||
@@ -43,6 +46,12 @@ public class CirclePropActivity extends Activity {
|
||||
|
||||
ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
|
||||
layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
|
||||
// For testing with a functor in the tree
|
||||
// WebView wv = new WebView(this);
|
||||
// wv.setWebViewClient(new WebViewClient());
|
||||
// wv.setWebChromeClient(new WebChromeClient());
|
||||
// wv.loadUrl("http://theverge.com");
|
||||
// layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 100));
|
||||
|
||||
layout.addView(new CircleView(this),
|
||||
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
|
||||
Reference in New Issue
Block a user