Add a callback for when a gl functor is released
Bug: 27709981 Change-Id: Id5be3e8f88d6d84a9c59c7ed23e7e8862feefbe8
This commit is contained in:
@@ -163,17 +163,33 @@ public class DisplayListCanvas extends Canvas {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Calls the function specified with the drawGLFunction function pointer. This is
|
||||
* functionality used by webkit for calling into their renderer from our display lists.
|
||||
* This function may return true if an invalidation is needed after the call.
|
||||
* Records the functor specified with the drawGLFunction function pointer. This is
|
||||
* functionality used by webview for calling into their renderer from our display lists.
|
||||
*
|
||||
* @param drawGLFunction A native function pointer
|
||||
*/
|
||||
public void callDrawGLFunction2(long drawGLFunction) {
|
||||
nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction);
|
||||
nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null);
|
||||
}
|
||||
|
||||
private static native void nCallDrawGLFunction(long renderer, long drawGLFunction);
|
||||
/**
|
||||
* Records the functor specified with the drawGLFunction function pointer. This is
|
||||
* functionality used by webview for calling into their renderer from our display lists.
|
||||
*
|
||||
* @param drawGLFunction A native function pointer
|
||||
* @param releasedCallback Called when the display list is destroyed, and thus
|
||||
* the functor is no longer referenced by this canvas's display list.
|
||||
*
|
||||
* NOTE: The callback does *not* necessarily mean that there are no longer
|
||||
* any references to the functor, just that the reference from this specific
|
||||
* canvas's display list has been released.
|
||||
*/
|
||||
public void drawGLFunctor2(long drawGLFunctor, Runnable releasedCallback) {
|
||||
nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
|
||||
}
|
||||
|
||||
private static native void nCallDrawGLFunction(long renderer,
|
||||
long drawGLFunction, Runnable releasedCallback);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Display list
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
|
||||
#include <utils/Looper.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkRegion.h>
|
||||
|
||||
|
||||
#include <Rect.h>
|
||||
#include <RenderNode.h>
|
||||
#include <CanvasProperty.h>
|
||||
@@ -41,6 +41,52 @@ namespace android {
|
||||
|
||||
using namespace uirenderer;
|
||||
|
||||
jmethodID gRunnableMethodId;
|
||||
|
||||
static JNIEnv* jnienv(JavaVM* vm) {
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
class InvokeRunnableMessage : public MessageHandler {
|
||||
public:
|
||||
InvokeRunnableMessage(JNIEnv* env, jobject runnable) {
|
||||
mRunnable = env->NewGlobalRef(runnable);
|
||||
env->GetJavaVM(&mVm);
|
||||
}
|
||||
|
||||
virtual ~InvokeRunnableMessage() {
|
||||
jnienv(mVm)->DeleteGlobalRef(mRunnable);
|
||||
}
|
||||
|
||||
virtual void handleMessage(const Message&) {
|
||||
jnienv(mVm)->CallVoidMethod(mRunnable, gRunnableMethodId);
|
||||
}
|
||||
|
||||
private:
|
||||
JavaVM* mVm;
|
||||
jobject mRunnable;
|
||||
};
|
||||
|
||||
class GlFunctorReleasedCallbackBridge : public GlFunctorLifecycleListener {
|
||||
public:
|
||||
GlFunctorReleasedCallbackBridge(JNIEnv* env, jobject javaCallback) {
|
||||
mLooper = Looper::getForThread();
|
||||
mMessage = new InvokeRunnableMessage(env, javaCallback);
|
||||
}
|
||||
|
||||
virtual void onGlFunctorReleased(Functor* functor) override {
|
||||
mLooper->sendMessage(mMessage, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
sp<Looper> mLooper;
|
||||
sp<InvokeRunnableMessage> mMessage;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Setup
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -56,10 +102,12 @@ static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, job
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
|
||||
jlong canvasPtr, jlong functorPtr) {
|
||||
jlong canvasPtr, jlong functorPtr, jobject releasedCallback) {
|
||||
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
||||
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
|
||||
canvas->callDrawGLFunction(functor);
|
||||
sp<GlFunctorReleasedCallbackBridge> bridge(new GlFunctorReleasedCallbackBridge(
|
||||
env, releasedCallback));
|
||||
canvas->callDrawGLFunction(functor, bridge.get());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -184,7 +232,8 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nIsAvailable", "!()Z", (void*) android_view_DisplayListCanvas_isAvailable },
|
||||
{ "nInsertReorderBarrier","!(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier },
|
||||
|
||||
{ "nCallDrawGLFunction", "!(JJ)V", (void*) android_view_DisplayListCanvas_callDrawGLFunction },
|
||||
{ "nCallDrawGLFunction", "!(JJLjava/lang/Runnable;)V",
|
||||
(void*) android_view_DisplayListCanvas_callDrawGLFunction },
|
||||
|
||||
{ "nDrawRoundRect", "!(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps },
|
||||
{ "nDrawCircle", "!(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
|
||||
@@ -207,6 +256,9 @@ static JNINativeMethod gActivityThreadMethods[] = {
|
||||
};
|
||||
|
||||
int register_android_view_DisplayListCanvas(JNIEnv* env) {
|
||||
jclass runnableClass = FindClassOrDie(env, "java/lang/Runnable");
|
||||
gRunnableMethodId = GetMethodIDOrDie(env, runnableClass, "run", "()V");
|
||||
|
||||
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,12 @@ void DisplayList::cleanupResources() {
|
||||
delete path;
|
||||
}
|
||||
|
||||
for (auto& iter : functors) {
|
||||
if (iter.listener) {
|
||||
iter.listener->onGlFunctorReleased(iter.functor);
|
||||
}
|
||||
}
|
||||
|
||||
patchResources.clear();
|
||||
pathResources.clear();
|
||||
paints.clear();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "Debug.h"
|
||||
#include "CanvasProperty.h"
|
||||
#include "DeferredDisplayList.h"
|
||||
#include "GlFunctorLifecycleListener.h"
|
||||
#include "Matrix.h"
|
||||
#include "RenderProperties.h"
|
||||
|
||||
@@ -119,6 +120,11 @@ struct PushStagingFunctor {
|
||||
virtual void operator ()() {}
|
||||
};
|
||||
|
||||
struct FunctorContainer {
|
||||
Functor* functor;
|
||||
GlFunctorLifecycleListener* listener;
|
||||
};
|
||||
|
||||
/**
|
||||
* Data structure that holds the list of commands used in display list stream
|
||||
*/
|
||||
@@ -154,7 +160,7 @@ public:
|
||||
const LsaVector<NodeOpType*>& getChildren() const { return children; }
|
||||
|
||||
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
|
||||
const LsaVector<Functor*>& getFunctors() const { return functors; }
|
||||
const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
|
||||
const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
|
||||
|
||||
size_t addChild(NodeOpType* childOp);
|
||||
@@ -195,7 +201,7 @@ private:
|
||||
LsaVector< sp<VirtualLightRefBase> > referenceHolders;
|
||||
|
||||
// List of functors
|
||||
LsaVector<Functor*> functors;
|
||||
LsaVector<FunctorContainer> functors;
|
||||
|
||||
// List of functors that need to be notified of pushStaging. Note that this list gets nothing
|
||||
// but a callback during sync DisplayList, unlike the list of functors defined above, which
|
||||
|
||||
@@ -81,9 +81,11 @@ DisplayList* DisplayListCanvas::finishRecording() {
|
||||
return displayList;
|
||||
}
|
||||
|
||||
void DisplayListCanvas::callDrawGLFunction(Functor *functor) {
|
||||
void DisplayListCanvas::callDrawGLFunction(Functor* functor,
|
||||
GlFunctorLifecycleListener* listener) {
|
||||
addDrawOp(new (alloc()) DrawFunctorOp(functor));
|
||||
mDisplayList->functors.push_back(functor);
|
||||
mDisplayList->functors.push_back({functor, listener});
|
||||
mDisplayList->ref(listener);
|
||||
}
|
||||
|
||||
SkCanvas* DisplayListCanvas::asSkCanvas() {
|
||||
|
||||
@@ -93,7 +93,8 @@ public:
|
||||
// ----------------------------------------------------------------------------
|
||||
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
|
||||
virtual void drawRenderNode(RenderNode* renderNode) override;
|
||||
virtual void callDrawGLFunction(Functor* functor) override;
|
||||
virtual void callDrawGLFunction(Functor* functor,
|
||||
GlFunctorLifecycleListener* listener) override;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CanvasStateClient interface
|
||||
|
||||
32
libs/hwui/GlFunctorLifecycleListener.h
Normal file
32
libs/hwui/GlFunctorLifecycleListener.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/Functor.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
class GlFunctorLifecycleListener : public VirtualLightRefBase {
|
||||
public:
|
||||
virtual ~GlFunctorLifecycleListener() {}
|
||||
virtual void onGlFunctorReleased(Functor* functor) = 0;
|
||||
};
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
@@ -594,8 +594,10 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
|
||||
layerHandle->backingLayer()));
|
||||
}
|
||||
|
||||
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
|
||||
mDisplayList->functors.push_back(functor);
|
||||
void RecordingCanvas::callDrawGLFunction(Functor* functor,
|
||||
GlFunctorLifecycleListener* listener) {
|
||||
mDisplayList->functors.push_back({functor, listener});
|
||||
mDisplayList->ref(listener);
|
||||
addOp(alloc().create_trivial<FunctorOp>(
|
||||
*(mState.currentSnapshot()->transform),
|
||||
getRecordedClip(),
|
||||
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
|
||||
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
|
||||
virtual void drawRenderNode(RenderNode* renderNode) override;
|
||||
virtual void callDrawGLFunction(Functor* functor) override;
|
||||
virtual void callDrawGLFunction(Functor* functor,
|
||||
GlFunctorLifecycleListener* listener) override;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CanvasStateClient interface
|
||||
|
||||
@@ -474,8 +474,8 @@ void RenderNode::syncDisplayList(TreeObserver* observer) {
|
||||
mDisplayList = mStagingDisplayList;
|
||||
mStagingDisplayList = nullptr;
|
||||
if (mDisplayList) {
|
||||
for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
|
||||
(*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
|
||||
for (auto& iter : mDisplayList->getFunctors()) {
|
||||
(*iter.functor)(DrawGlInfo::kModeSync, nullptr);
|
||||
}
|
||||
for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
|
||||
(*mDisplayList->getPushStagingFunctors()[i])();
|
||||
|
||||
@@ -160,7 +160,8 @@ public:
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
|
||||
virtual void callDrawGLFunction(Functor* functor) override;
|
||||
virtual void callDrawGLFunction(Functor* functor,
|
||||
uirenderer::GlFunctorLifecycleListener* listener) override;
|
||||
|
||||
protected:
|
||||
virtual void drawGlyphs(const uint16_t* text, const float* positions, int count,
|
||||
@@ -846,6 +847,7 @@ void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layer) { }
|
||||
|
||||
void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { }
|
||||
|
||||
void SkiaCanvas::callDrawGLFunction(Functor* functor) { }
|
||||
void SkiaCanvas::callDrawGLFunction(Functor* functor,
|
||||
uirenderer::GlFunctorLifecycleListener* listener) { }
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <cutils/compiler.h>
|
||||
#include <utils/Functor.h>
|
||||
|
||||
#include "GlFunctorLifecycleListener.h"
|
||||
#include "utils/NinePatch.h"
|
||||
|
||||
#include <SkBitmap.h>
|
||||
@@ -124,7 +125,8 @@ public:
|
||||
|
||||
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
|
||||
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
|
||||
virtual void callDrawGLFunction(Functor* functor) = 0;
|
||||
virtual void callDrawGLFunction(Functor* functor,
|
||||
uirenderer::GlFunctorLifecycleListener* listener) = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Canvas state operations
|
||||
|
||||
@@ -581,7 +581,7 @@ RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
|
||||
auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
|
||||
[&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
|
||||
canvas.translate(0, -800000);
|
||||
canvas.callDrawGLFunction(&noopFunctor);
|
||||
canvas.callDrawGLFunction(&noopFunctor, nullptr);
|
||||
});
|
||||
|
||||
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
|
||||
|
||||
@@ -51,3 +51,41 @@ TEST(RenderNode, hasParents) {
|
||||
EXPECT_FALSE(child->hasParents()) << "Child should be removed";
|
||||
EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents";
|
||||
}
|
||||
|
||||
TEST(RenderNode, releasedCallback) {
|
||||
class DecRefOnReleased : public GlFunctorLifecycleListener {
|
||||
public:
|
||||
DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
|
||||
void onGlFunctorReleased(Functor* functor) override {
|
||||
*mRefCnt -= 1;
|
||||
}
|
||||
private:
|
||||
int* mRefCnt;
|
||||
};
|
||||
|
||||
int refcnt = 0;
|
||||
sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt));
|
||||
Functor noopFunctor;
|
||||
|
||||
auto node = TestUtils::createNode(0, 0, 200, 400,
|
||||
[&](RenderProperties& props, TestCanvas& canvas) {
|
||||
refcnt++;
|
||||
canvas.callDrawGLFunction(&noopFunctor, listener.get());
|
||||
});
|
||||
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
|
||||
EXPECT_EQ(1, refcnt);
|
||||
|
||||
TestUtils::recordNode(*node, [&](TestCanvas& canvas) {
|
||||
refcnt++;
|
||||
canvas.callDrawGLFunction(&noopFunctor, listener.get());
|
||||
});
|
||||
EXPECT_EQ(2, refcnt);
|
||||
|
||||
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
|
||||
EXPECT_EQ(1, refcnt);
|
||||
|
||||
TestUtils::recordNode(*node, [](TestCanvas& canvas) {});
|
||||
EXPECT_EQ(1, refcnt);
|
||||
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
|
||||
EXPECT_EQ(0, refcnt);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user