Merge "Refcount RenderNode"

This commit is contained in:
John Reck
2014-04-07 22:42:21 +00:00
committed by Android (Google) Code Review
18 changed files with 175 additions and 83 deletions

View File

@@ -59,13 +59,14 @@ static void android_view_RenderNode_output(JNIEnv* env,
static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz) {
RenderNode* displayList = new RenderNode();
displayList->incStrong(0);
return reinterpret_cast<jlong>(displayList);
}
static void android_view_RenderNode_destroyDisplayList(JNIEnv* env,
jobject clazz, jlong displayListPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
RenderNode::destroyDisplayListDeferred(displayList);
displayList->decStrong(0);
}
// ----------------------------------------------------------------------------

View File

@@ -315,24 +315,15 @@ void Caches::clearGarbage() {
pathCache.clearGarbage();
patchCache.clearGarbage();
Vector<RenderNode*> displayLists;
Vector<Layer*> layers;
{ // scope for the lock
Mutex::Autolock _l(mGarbageLock);
displayLists = mDisplayListGarbage;
layers = mLayerGarbage;
mDisplayListGarbage.clear();
mLayerGarbage.clear();
}
size_t count = displayLists.size();
for (size_t i = 0; i < count; i++) {
RenderNode* displayList = displayLists.itemAt(i);
delete displayList;
}
count = layers.size();
size_t count = layers.size();
for (size_t i = 0; i < count; i++) {
Layer* layer = layers.itemAt(i);
delete layer;
@@ -345,11 +336,6 @@ void Caches::deleteLayerDeferred(Layer* layer) {
mLayerGarbage.push(layer);
}
void Caches::deleteDisplayListDeferred(RenderNode* displayList) {
Mutex::Autolock _l(mGarbageLock);
mDisplayListGarbage.push(displayList);
}
void Caches::flush(FlushMode mode) {
FLUSH_LOGD("Flushing caches (mode %d)", mode);

View File

@@ -166,11 +166,6 @@ public:
*/
void deleteLayerDeferred(Layer* layer);
/*
* Can be used to delete a display list from a non EGL thread.
*/
void deleteDisplayListDeferred(RenderNode* layer);
/**
* Binds the VBO used to render simple textured quads.
*/
@@ -420,7 +415,6 @@ private:
mutable Mutex mGarbageLock;
Vector<Layer*> mLayerGarbage;
Vector<RenderNode*> mDisplayListGarbage;
DebugLevel mDebugLevel;
bool mInitialized;

View File

@@ -68,13 +68,13 @@ bool DeferredLayerUpdater::apply() {
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
if (mDisplayList) {
if (mDisplayList.get()) {
if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
}
mLayer->setBlend(mBlend);
mDisplayList->updateProperties();
mLayer->updateDeferred(mDisplayList,
mLayer->updateDeferred(mDisplayList.get(),
mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
mDirtyRect.setEmpty();
mDisplayList = 0;

View File

@@ -101,7 +101,7 @@ private:
// Layer type specific properties
// displayList and surfaceTexture are mutually exclusive, only 1 may be set
// dirtyRect is only valid if displayList is set
RenderNode* mDisplayList;
sp<RenderNode> mDisplayList;
Rect mDirtyRect;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;

View File

@@ -29,6 +29,13 @@
namespace android {
namespace uirenderer {
DisplayListData::DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {
}
DisplayListData::~DisplayListData() {
cleanupResources();
}
void DisplayListData::cleanupResources() {
Caches& caches = Caches::getInstance();
caches.unregisterFunctors(functorCount);
@@ -91,5 +98,12 @@ void DisplayListData::cleanupResources() {
layers.clear();
}
void DisplayListData::addChild(DrawDisplayListOp* op) {
LOG_ALWAYS_FATAL_IF(!op->renderNode(), "DrawDisplayListOp with no render node!");
mChildren.push(op);
mReferenceHolders.push(op->renderNode());
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -41,6 +41,7 @@
#include "Matrix.h"
#include "DeferredDisplayList.h"
#include "RenderProperties.h"
#include "utils/VirtualLightRefBase.h"
class SkBitmap;
class SkPaint;
@@ -106,8 +107,8 @@ public:
*/
class DisplayListData {
public:
DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {}
virtual ~DisplayListData() { cleanupResources(); }
DisplayListData();
~DisplayListData();
// allocator into which all ops were allocated
LinearAllocator allocator;
@@ -115,9 +116,6 @@ public:
// pointers to all ops within display list, pointing into allocator data
Vector<DisplayListOp*> displayListOps;
// list of children display lists for quick, non-drawing traversal
Vector<DrawDisplayListOp*> children;
// index of DisplayListOp restore, after which projected descendents should be drawn
int projectionReceiveIndex;
@@ -139,7 +137,15 @@ public:
return !displayListOps.size();
}
void addChild(DrawDisplayListOp* childOp);
const Vector<DrawDisplayListOp*>& children() { return mChildren; }
private:
Vector< sp<VirtualLightRefBase> > mReferenceHolders;
// list of children display lists for quick, non-drawing traversal
Vector<DrawDisplayListOp*> mChildren;
void cleanupResources();
};

View File

@@ -1523,6 +1523,8 @@ public:
virtual const char* name() { return "DrawDisplayList"; }
RenderNode* renderNode() { return mDisplayList; }
private:
RenderNode* mDisplayList;
const int mFlags;

View File

@@ -191,7 +191,7 @@ status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList,
DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->children.push(op);
mDisplayListData->addChild(op);
if (displayList->isProjectionReceiver()) {
mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
}

View File

@@ -140,6 +140,15 @@ void Layer::removeFbo(bool flush) {
}
}
void Layer::updateDeferred(RenderNode* displayList,
int left, int top, int right, int bottom) {
requireRenderer();
this->displayList = displayList;
const Rect r(left, top, right, bottom);
dirtyRect.unionWith(r);
deferredUpdateScheduled = true;
}
void Layer::setPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
setColorFilter((paint) ? paint->getColorFilter() : NULL);
@@ -244,7 +253,7 @@ void Layer::render() {
renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
!isBlend());
renderer->drawDisplayList(displayList, dirtyRect, RenderNode::kReplayFlag_ClipChildren);
renderer->drawDisplayList(displayList.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
renderer->finish();

View File

@@ -19,6 +19,7 @@
#include <cutils/compiler.h>
#include <sys/types.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -85,13 +86,7 @@ public:
}
void updateDeferred(RenderNode* displayList,
int left, int top, int right, int bottom) {
requireRenderer();
this->displayList = displayList;
const Rect r(left, top, right, bottom);
dirtyRect.unionWith(r);
deferredUpdateScheduled = true;
}
int left, int top, int right, int bottom);
inline uint32_t getWidth() const {
return texture.width;
@@ -294,7 +289,7 @@ public:
*/
bool deferredUpdateScheduled;
OpenGLRenderer* renderer;
RenderNode* displayList;
sp<RenderNode> displayList;
Rect dirtyRect;
bool debugDrawUpdate;
bool hasDrawnSinceUpdate;

View File

@@ -537,7 +537,7 @@ void OpenGLRenderer::countOverdraw() {
bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
if (layer->deferredUpdateScheduled && layer->renderer &&
layer->displayList && layer->displayList->isRenderable()) {
layer->displayList.get() && layer->displayList->isRenderable()) {
ATRACE_CALL();
Rect& dirty = layer->dirtyRect;

View File

@@ -59,17 +59,6 @@ RenderNode::~RenderNode() {
delete mDisplayListData;
}
void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) {
if (displayList) {
if (Caches::hasInstance()) {
DISPLAY_LIST_LOGD("Deferring display list destruction");
Caches::getInstance().deleteDisplayListDeferred(displayList);
} else {
delete displayList;
}
}
}
void RenderNode::setData(DisplayListData* data) {
delete mDisplayListData;
mDisplayListData = data;
@@ -104,8 +93,8 @@ void RenderNode::updateProperties() {
}
if (mDisplayListData) {
for (size_t i = 0; i < mDisplayListData->children.size(); i++) {
RenderNode* childNode = mDisplayListData->children[i]->mDisplayList;
for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
childNode->updateProperties();
}
}
@@ -118,8 +107,8 @@ bool RenderNode::hasFunctors() {
return true;
}
for (size_t i = 0; i < mDisplayListData->children.size(); i++) {
RenderNode* childNode = mDisplayListData->children[i]->mDisplayList;
for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
RenderNode* childNode = mDisplayListData->children()[i]->mDisplayList;
if (childNode->hasFunctors()) {
return true;
}
@@ -248,8 +237,8 @@ void RenderNode::computeOrdering() {
// TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
// transform properties are applied correctly to top level children
if (mDisplayListData == NULL) return;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
&mProjectedNodes, &mat4::identity());
}
@@ -277,11 +266,11 @@ void RenderNode::computeOrderingImpl(
opState->mSkipInOrderDraw = false;
}
if (mDisplayListData->children.size() > 0) {
if (mDisplayListData->children().size() > 0) {
const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
bool haveAppliedPropertiesToProjection = false;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mDisplayList;
Vector<DrawDisplayListOp*>* projectionChildren = NULL;
@@ -375,10 +364,10 @@ void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int l
}
void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) {
if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return;
if (mDisplayListData == NULL || mDisplayListData->children().size() == 0) return;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mDisplayList;
float childZ = child->properties().getTranslationZ();

View File

@@ -41,6 +41,7 @@
#include "DeferredDisplayList.h"
#include "DisplayList.h"
#include "RenderProperties.h"
#include "utils/VirtualLightRefBase.h"
class SkBitmap;
class SkPaint;
@@ -76,7 +77,7 @@ class DrawDisplayListOp;
* recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
* attached.
*/
class RenderNode {
class RenderNode : public VirtualLightRefBase {
public:
ANDROID_API RenderNode();
ANDROID_API ~RenderNode();
@@ -86,7 +87,6 @@ public:
kReplayFlag_ClipChildren = 0x1
};
ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList);
ANDROID_API static void outputLogBuffer(int fd);
ANDROID_API void setData(DisplayListData* newData);

View File

@@ -30,7 +30,19 @@ namespace android {
namespace uirenderer {
namespace renderthread {
DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
SetDisplayListData::SetDisplayListData() : mNewData(0) {}
SetDisplayListData::SetDisplayListData(RenderNode* node, DisplayListData* newData)
: mTargetNode(node), mNewData(newData) {
}
SetDisplayListData::~SetDisplayListData() {}
void SetDisplayListData::apply() const {
mTargetNode->setData(mNewData);
}
DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
}
DrawFrameTask::~DrawFrameTask() {
@@ -41,13 +53,15 @@ void DrawFrameTask::setContext(CanvasContext* context) {
}
void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
SetDisplayListData setter;
setter.targetNode = renderNode;
setter.newData = newData;
LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setDisplayListData with!");
SetDisplayListData setter(renderNode, newData);
mDisplayListDataUpdates.push(setter);
}
void DrawFrameTask::addLayer(DeferredLayerUpdater* layer) {
LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to addLayer with!");
mLayers.push(layer);
}
@@ -61,6 +75,8 @@ void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) {
}
void DrawFrameTask::setRenderNode(RenderNode* renderNode) {
LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setRenderNode with!");
mRenderNode = renderNode;
}
@@ -69,37 +85,55 @@ void DrawFrameTask::setDirty(int left, int top, int right, int bottom) {
}
void DrawFrameTask::drawFrame(RenderThread* renderThread) {
LOG_ALWAYS_FATAL_IF(!mRenderNode, "Cannot drawFrame with no render node!");
LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!");
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
AutoMutex _lock(mLock);
renderThread->queue(this);
mSignal.wait(mLock);
postAndWait(renderThread, MODE_FULL);
// Reset the single-frame data
mDirty.setEmpty();
mRenderNode = 0;
}
void DrawFrameTask::flushStateChanges(RenderThread* renderThread) {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
postAndWait(renderThread, MODE_STATE_ONLY);
}
void DrawFrameTask::postAndWait(RenderThread* renderThread, TaskMode mode) {
LOG_ALWAYS_FATAL_IF(mode == MODE_INVALID, "That's not a real mode, silly!");
mTaskMode = mode;
AutoMutex _lock(mLock);
renderThread->queue(this);
mSignal.wait(mLock);
}
void DrawFrameTask::run() {
ATRACE_NAME("DrawFrame");
syncFrameState();
if (mTaskMode == MODE_STATE_ONLY) {
unblockUiThread();
return;
}
// Grab a copy of everything we need
Rect dirtyCopy(mDirty);
RenderNode* renderNode = mRenderNode;
sp<RenderNode> renderNode = mRenderNode;
CanvasContext* context = mContext;
// This is temporary until WebView has a solution for syncing frame state
bool canUnblockUiThread = !requiresSynchronousDraw(renderNode);
bool canUnblockUiThread = !requiresSynchronousDraw(renderNode.get());
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
unblockUiThread();
}
drawRenderNode(context, renderNode, &dirtyCopy);
drawRenderNode(context, renderNode.get(), &dirtyCopy);
if (!canUnblockUiThread) {
unblockUiThread();
@@ -111,12 +145,16 @@ void DrawFrameTask::syncFrameState() {
for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) {
const SetDisplayListData& setter = mDisplayListDataUpdates[i];
setter.targetNode->setData(setter.newData);
setter.apply();
}
mDisplayListDataUpdates.clear();
mContext->processLayerUpdates(&mLayers);
mRenderNode->updateProperties();
// If we don't have an mRenderNode this is a state flush only
if (mRenderNode.get()) {
mRenderNode->updateProperties();
}
}
void DrawFrameTask::unblockUiThread() {

View File

@@ -18,6 +18,7 @@
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
#include "RenderTask.h"
@@ -36,9 +37,16 @@ namespace renderthread {
class CanvasContext;
class RenderThread;
struct SetDisplayListData {
RenderNode* targetNode;
DisplayListData* newData;
class SetDisplayListData {
public:
// This ctor exists for Vector's usage
SetDisplayListData();
SetDisplayListData(RenderNode* node, DisplayListData* newData);
~SetDisplayListData();
void apply() const;
private:
sp<RenderNode> mTargetNode;
DisplayListData* mNewData;
};
/*
@@ -61,10 +69,18 @@ public:
void setRenderNode(RenderNode* renderNode);
void setDirty(int left, int top, int right, int bottom);
void drawFrame(RenderThread* renderThread);
void flushStateChanges(RenderThread* renderThread);
virtual void run();
private:
enum TaskMode {
MODE_INVALID,
MODE_FULL,
MODE_STATE_ONLY,
};
void postAndWait(RenderThread* renderThread, TaskMode mode);
void syncFrameState();
void unblockUiThread();
static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty);
@@ -81,7 +97,8 @@ private:
/*********************************************
* Single frame data
*********************************************/
RenderNode* mRenderNode;
TaskMode mTaskMode;
sp<RenderNode> mRenderNode;
Rect mDirty;
Vector<SetDisplayListData> mDisplayListDataUpdates;

View File

@@ -75,6 +75,9 @@ CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
void RenderProxy::destroyContext() {
if (mContext) {
// Flush any pending changes to ensure all garbage is destroyed
mDrawFrameTask.flushStateChanges(&mRenderThread);
SETUP_TASK(destroyContext);
args->context = mContext;
mContext = 0;
@@ -138,6 +141,10 @@ CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) {
}
void RenderProxy::destroyCanvas() {
// If the canvas is being destroyed we won't be drawing again anytime soon
// So flush any pending state changes to allow for resource cleanup.
mDrawFrameTask.flushStateChanges(&mRenderThread);
SETUP_TASK(destroyCanvas);
args->context = mContext;
post(task);

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2014 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.
*/
#ifndef VIRTUALLIGHTREFBASE_H
#define VIRTUALLIGHTREFBASE_H
#include <utils/RefBase.h>
namespace android {
namespace uirenderer {
// This is a wrapper around LightRefBase that simply enforces a virtual
// destructor to eliminate the template requirement of LightRefBase
class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
public:
virtual ~VirtualLightRefBase() {}
};
} /* namespace uirenderer */
} /* namespace android */
#endif /* VIRTUALLIGHTREFBASE_H */