Fix some edge cases

Bug: 27709981

This desperately needs a refactor, but to keep
the current (really needed & nice) behavior of
dispatching after sync finishes would be difficult
to handle cleanly without lots of ripping so... #yolo

Change-Id: I831a06c6ae7412a062720d68ecbe3085190f0258
This commit is contained in:
John Reck
2016-04-06 07:50:47 -07:00
parent 3397c88f79
commit 51f2d606dc
17 changed files with 115 additions and 98 deletions

View File

@@ -794,8 +794,7 @@ public final class ThreadedRenderer {
}
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length,
mRootNode.mNativeRenderNode);
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
attachInfo.mViewRootImpl.mSurface.release();
@@ -994,8 +993,7 @@ public final class ThreadedRenderer {
private static native void nSetLightCenter(long nativeProxy,
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size,
long rootRenderNode);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);

View File

@@ -128,9 +128,22 @@ static void android_view_RenderNode_destroyRenderNode(JNIEnv* env,
static void android_view_RenderNode_setDisplayList(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong displayListPtr) {
class RemovedObserver : public TreeObserver {
public:
virtual void onMaybeRemovedFromTree(RenderNode* node) override {
maybeRemovedNodes.insert(sp<RenderNode>(node));
}
std::set< sp<RenderNode> > maybeRemovedNodes;
};
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
DisplayList* newData = reinterpret_cast<DisplayList*>(displayListPtr);
renderNode->setStagingDisplayList(newData);
RemovedObserver observer;
renderNode->setStagingDisplayList(newData, &observer);
for (auto& node : observer.maybeRemovedNodes) {
if (node->hasParents()) continue;
onRenderNodeRemoved(env, node.get());
}
}
// ----------------------------------------------------------------------------

View File

@@ -525,7 +525,7 @@ static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
UiFrameInfoBuilder(proxy->frameInfo())
.setVsync(vsync, vsync)
.addFlag(FrameInfoFlags::SurfaceCanvas);
proxy->syncAndDrawFrame();
proxy->syncAndDrawFrame(nullptr);
}
static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {

View File

@@ -72,6 +72,31 @@ static JNIEnv* getenv(JavaVM* vm) {
return env;
}
// TODO: Clean this up, it's a bit odd to need to call over to
// rendernode's jni layer. Probably means RootRenderNode should be pulled
// into HWUI with appropriate callbacks for the various JNI hooks so
// that RenderNode's JNI layer can handle its own thing
void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
class ScopedRemovedRenderNodeObserver : public TreeObserver {
public:
ScopedRemovedRenderNodeObserver(JNIEnv* env) : mEnv(env) {}
~ScopedRemovedRenderNodeObserver() {
for (auto& node : mMaybeRemovedNodes) {
if (node->hasParents()) continue;
onRenderNodeRemoved(mEnv, node.get());
}
}
virtual void onMaybeRemovedFromTree(RenderNode* node) override {
mMaybeRemovedNodes.insert(sp<RenderNode>(node));
}
private:
JNIEnv* mEnv;
std::set< sp<RenderNode> > mMaybeRemovedNodes;
};
class OnFinishedEvent {
public:
OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
@@ -120,13 +145,7 @@ private:
std::string mMessage;
};
// TODO: Clean this up, it's a bit odd to need to call over to
// rendernode's jni layer. Probably means RootRenderNode should be pulled
// into HWUI with appropriate callbacks for the various JNI hooks so
// that RenderNode's JNI layer can handle its own thing
void onRenderNodeRemoved(JNIEnv* env, RenderNode* node);
class RootRenderNode : public RenderNode, ErrorHandler, TreeObserver {
class RootRenderNode : public RenderNode, ErrorHandler {
public:
RootRenderNode(JNIEnv* env) : RenderNode() {
mLooper = Looper::getForThread();
@@ -143,9 +162,6 @@ public:
virtual void prepareTree(TreeInfo& info) override {
info.errorHandler = this;
if (info.mode == TreeInfo::MODE_FULL) {
info.observer = this;
}
// TODO: This is hacky
info.windowInsetLeft = -stagingProperties().getLeft();
info.windowInsetTop = -stagingProperties().getTop();
@@ -155,7 +171,6 @@ public:
info.windowInsetLeft = 0;
info.windowInsetTop = 0;
info.errorHandler = nullptr;
info.observer = nullptr;
}
void sendMessage(const sp<MessageHandler>& handler) {
@@ -181,27 +196,10 @@ public:
mPendingAnimatingRenderNodes.clear();
}
virtual void onMaybeRemovedFromTree(RenderNode* node) override {
mMaybeRemovedNodes.insert(sp<RenderNode>(node));
}
void processMaybeRemovedNodes(JNIEnv* env) {
// We can safely access mMaybeRemovedNodes here because
// we will only modify it in prepareTree calls that are
// MODE_FULL
for (auto& node : mMaybeRemovedNodes) {
if (node->hasParents()) continue;
onRenderNodeRemoved(env, node.get());
}
mMaybeRemovedNodes.clear();
}
private:
sp<Looper> mLooper;
JavaVM* mVm;
std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
std::set< sp<RenderNode> > mMaybeRemovedNodes;
};
class AnimationContextBridge : public AnimationContext {
@@ -500,24 +498,23 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize, jlong rootNodePtr) {
jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
"Mismatched size expectations, given %d expected %d",
frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
ScopedRemovedRenderNodeObserver observer(env);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
int ret = proxy->syncAndDrawFrame();
rootRenderNode->processMaybeRemovedNodes(env);
return ret;
return proxy->syncAndDrawFrame(&observer);
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong rootNodePtr) {
ScopedRemovedRenderNodeObserver observer(env);
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
rootRenderNode->destroy();
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroy();
proxy->destroy(&observer);
}
static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* env, jobject clazz,
@@ -542,9 +539,10 @@ static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobje
static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong nodePtr) {
ScopedRemovedRenderNodeObserver observer(env);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
proxy->buildLayer(node);
proxy->buildLayer(node, &observer);
}
static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
@@ -579,8 +577,9 @@ static void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobj
static void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
ScopedRemovedRenderNodeObserver observer(env);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroyHardwareResources();
proxy->destroyHardwareResources(&observer);
}
static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
@@ -736,7 +735,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSyncAndDrawFrame", "(J[JIJ)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },

View File

@@ -81,14 +81,14 @@ RenderNode::~RenderNode() {
#endif
}
void RenderNode::setStagingDisplayList(DisplayList* displayList) {
void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* observer) {
mNeedsDisplayListSync = true;
delete mStagingDisplayList;
mStagingDisplayList = displayList;
// If mParentCount == 0 we are the sole reference to this RenderNode,
// so immediately free the old display list
if (!mParentCount && !mStagingDisplayList) {
deleteDisplayList(nullptr);
deleteDisplayList(observer);
}
}

View File

@@ -117,7 +117,7 @@ public:
void debugDumpLayers(const char* prefix);
ANDROID_API void setStagingDisplayList(DisplayList* newData);
ANDROID_API void setStagingDisplayList(DisplayList* newData, TreeObserver* observer);
void computeOrdering();

View File

@@ -76,15 +76,15 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
}
CanvasContext::~CanvasContext() {
destroy();
destroy(nullptr);
mRenderThread.renderState().unregisterCanvasContext(this);
}
void CanvasContext::destroy() {
void CanvasContext::destroy(TreeObserver* observer) {
stopDrawing();
setSurface(nullptr);
freePrefetechedLayers();
destroyHardwareResources();
freePrefetchedLayers(observer);
destroyHardwareResources(observer);
mAnimationContext->destroy();
#if !HWUI_NEW_OPS
if (mCanvas) {
@@ -222,7 +222,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
mAnimationContext->runRemainingAnimations(info);
GL_CHECKPOINT(MODERATE);
freePrefetechedLayers();
freePrefetchedLayers(info.observer);
GL_CHECKPOINT(MODERATE);
if (CC_UNLIKELY(!mNativeSurface.get())) {
@@ -569,25 +569,24 @@ void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
}
void CanvasContext::markLayerInUse(RenderNode* node) {
if (mPrefetechedLayers.erase(node)) {
if (mPrefetchedLayers.erase(node)) {
node->decStrong(nullptr);
}
}
static void destroyPrefetechedNode(RenderNode* node) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
node->destroyHardwareResources(nullptr);
node->decStrong(nullptr);
}
void CanvasContext::freePrefetechedLayers() {
if (mPrefetechedLayers.size()) {
std::for_each(mPrefetechedLayers.begin(), mPrefetechedLayers.end(), destroyPrefetechedNode);
mPrefetechedLayers.clear();
void CanvasContext::freePrefetchedLayers(TreeObserver* observer) {
if (mPrefetchedLayers.size()) {
for (auto& node : mPrefetchedLayers) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
node->getName());
node->destroyHardwareResources(observer);
node->decStrong(observer);
}
mPrefetchedLayers.clear();
}
}
void CanvasContext::buildLayer(RenderNode* node) {
void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) {
ATRACE_CALL();
if (!mEglManager.hasEglContext()) return;
#if !HWUI_NEW_OPS
@@ -599,6 +598,7 @@ void CanvasContext::buildLayer(RenderNode* node) {
TreeInfo info(TreeInfo::MODE_FULL, *this);
info.damageAccumulator = &mDamageAccumulator;
info.observer = observer;
#if HWUI_NEW_OPS
info.layerUpdateQueue = &mLayerUpdateQueue;
#else
@@ -628,7 +628,7 @@ void CanvasContext::buildLayer(RenderNode* node) {
#endif
node->incStrong(nullptr);
mPrefetechedLayers.insert(node);
mPrefetchedLayers.insert(node);
}
bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
@@ -636,12 +636,12 @@ bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap)
return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
}
void CanvasContext::destroyHardwareResources() {
void CanvasContext::destroyHardwareResources(TreeObserver* observer) {
stopDrawing();
if (mEglManager.hasEglContext()) {
freePrefetechedLayers();
freePrefetchedLayers(observer);
for (const sp<RenderNode>& node : mRenderNodes) {
node->destroyHardwareResources(nullptr);
node->destroyHardwareResources(observer);
}
Caches& caches = Caches::getInstance();
// Make sure to release all the textures we were owning as there won't

View File

@@ -92,17 +92,17 @@ public:
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();
void destroy();
void destroy(TreeObserver* observer);
// IFrameCallback, Choreographer-driven frame callback entry point
virtual void doFrame() override;
void prepareAndDraw(RenderNode* node);
void buildLayer(RenderNode* node);
void buildLayer(RenderNode* node, TreeObserver* observer);
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
void markLayerInUse(RenderNode* node);
void destroyHardwareResources();
void destroyHardwareResources(TreeObserver* observer);
static void trimMemory(RenderThread& thread, int level);
static void invokeFunctor(RenderThread& thread, Functor* functor);
@@ -174,7 +174,7 @@ private:
void setSurface(Surface* window);
void requireSurface();
void freePrefetechedLayers();
void freePrefetchedLayers(TreeObserver* observer);
void waitOnFences();
@@ -218,7 +218,7 @@ private:
FrameInfoVisualizer mProfiler;
std::unique_ptr<FrameMetricsReporter> mFrameMetricsReporter;
std::set<RenderNode*> mPrefetechedLayers;
std::set<RenderNode*> mPrefetchedLayers;
// Stores the bounds of the main content.
Rect mContentDrawBounds;

View File

@@ -65,11 +65,12 @@ void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
}
}
int DrawFrameTask::drawFrame() {
int DrawFrameTask::drawFrame(TreeObserver* observer) {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
mSyncResult = kSync_OK;
mSyncQueued = systemTime(CLOCK_MONOTONIC);
mObserver = observer;
postAndWait();
return mSyncResult;
@@ -88,6 +89,7 @@ void DrawFrameTask::run() {
bool canDrawThisFrame;
{
TreeInfo info(TreeInfo::MODE_FULL, *mContext);
info.observer = mObserver;
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
}

View File

@@ -62,7 +62,7 @@ public:
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
int drawFrame();
int drawFrame(TreeObserver* observer);
int64_t* frameInfo() { return mFrameInfo; }
@@ -87,6 +87,7 @@ private:
int mSyncResult;
int64_t mSyncQueued;
TreeObserver* mObserver;
int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
};

View File

@@ -222,18 +222,19 @@ int64_t* RenderProxy::frameInfo() {
return mDrawFrameTask.frameInfo();
}
int RenderProxy::syncAndDrawFrame() {
return mDrawFrameTask.drawFrame();
int RenderProxy::syncAndDrawFrame(TreeObserver* observer) {
return mDrawFrameTask.drawFrame(observer);
}
CREATE_BRIDGE1(destroy, CanvasContext* context) {
args->context->destroy();
CREATE_BRIDGE2(destroy, CanvasContext* context, TreeObserver* observer) {
args->context->destroy(args->observer);
return nullptr;
}
void RenderProxy::destroy() {
void RenderProxy::destroy(TreeObserver* observer) {
SETUP_TASK(destroy);
args->context = mContext;
args->observer = observer;
// destroyCanvasAndSurface() needs a fence as when it returns the
// underlying BufferQueue is going to be released from under
// the render thread.
@@ -287,15 +288,16 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() {
return layer;
}
CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
args->context->buildLayer(args->node);
CREATE_BRIDGE3(buildLayer, CanvasContext* context, RenderNode* node, TreeObserver* observer) {
args->context->buildLayer(args->node, args->observer);
return nullptr;
}
void RenderProxy::buildLayer(RenderNode* node) {
void RenderProxy::buildLayer(RenderNode* node, TreeObserver* observer) {
SETUP_TASK(buildLayer);
args->context = mContext;
args->node = node;
args->observer = observer;
postAndWait(task);
}
@@ -332,15 +334,16 @@ void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
postAndWait(task);
}
CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
args->context->destroyHardwareResources();
CREATE_BRIDGE2(destroyHardwareResources, CanvasContext* context, TreeObserver* observer) {
args->context->destroyHardwareResources(args->observer);
return nullptr;
}
void RenderProxy::destroyHardwareResources() {
void RenderProxy::destroyHardwareResources(TreeObserver* observer) {
SETUP_TASK(destroyHardwareResources);
args->context = mContext;
post(task);
args->observer = observer;
postAndWait(task);
}
CREATE_BRIDGE2(trimMemory, RenderThread* thread, int level) {

View File

@@ -42,6 +42,7 @@ class RenderNode;
class DisplayList;
class Layer;
class Rect;
class TreeObserver;
namespace renderthread {
@@ -75,21 +76,21 @@ public:
ANDROID_API void setLightCenter(const Vector3& lightCenter);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API int64_t* frameInfo();
ANDROID_API int syncAndDrawFrame();
ANDROID_API void destroy();
ANDROID_API int syncAndDrawFrame(TreeObserver* observer);
ANDROID_API void destroy(TreeObserver* observer);
ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
ANDROID_API void runWithGlContext(RenderTask* task);
ANDROID_API DeferredLayerUpdater* createTextureLayer();
ANDROID_API void buildLayer(RenderNode* node);
ANDROID_API void buildLayer(RenderNode* node, TreeObserver* observer);
ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
ANDROID_API void destroyHardwareResources();
ANDROID_API void destroyHardwareResources(TreeObserver* observer);
ANDROID_API static void trimMemory(int level);
ANDROID_API static void overrideProperty(const char* name, const char* value);

View File

@@ -146,7 +146,7 @@ public:
if (setup) {
TestCanvas canvas(props.getWidth(), props.getHeight());
setup(props, canvas);
node->setStagingDisplayList(canvas.finishRecording());
node->setStagingDisplayList(canvas.finishRecording(), nullptr);
}
node->setPropertyFieldsDirty(0xFFFFFFFF);
return node;
@@ -157,7 +157,7 @@ public:
TestCanvas canvas(node.stagingProperties().getWidth(),
node.stagingProperties().getHeight());
contentCallback(canvas);
node.setStagingDisplayList(canvas.finishRecording());
node.setStagingDisplayList(canvas.finishRecording(), nullptr);
}
/**

View File

@@ -59,6 +59,6 @@ public:
0, 100 * (i + 2), kBidi_Force_LTR, paint, nullptr);
}
container->setStagingDisplayList(canvas.finishRecording());
container->setStagingDisplayList(canvas.finishRecording(), nullptr);
}
};

View File

@@ -76,7 +76,7 @@ public:
// draw it to parent DisplayList
canvas.drawRenderNode(cards[ci].get());
}
listView->setStagingDisplayList(canvas.finishRecording());
listView->setStagingDisplayList(canvas.finishRecording(), nullptr);
}
private:
SkBitmap createRandomCharIcon() {

View File

@@ -95,7 +95,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
proxy->syncAndDrawFrame();
proxy->syncAndDrawFrame(nullptr);
}
proxy->resetProfileInfo();
@@ -110,7 +110,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) {
ATRACE_NAME("UI-Draw Frame");
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
scene->doFrame(i);
proxy->syncAndDrawFrame();
proxy->syncAndDrawFrame(nullptr);
}
if (opts.reportFrametimeWeight) {
proxy->fence();

View File

@@ -104,8 +104,8 @@ public:
}
void finishDrawing() {
mRootNode->setStagingDisplayList(mCanvas->finishRecording());
mProxy->syncAndDrawFrame();
mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
mProxy->syncAndDrawFrame(nullptr);
// Surprisingly, calling mProxy->fence() here appears to make no difference to
// the timings we record.
}