summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Caches.cpp16
-rw-r--r--libs/hwui/Caches.h6
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp6
-rw-r--r--libs/hwui/DeferredLayerUpdater.h2
-rw-r--r--libs/hwui/DisplayList.cpp14
-rw-r--r--libs/hwui/DisplayList.h16
-rw-r--r--libs/hwui/DisplayListOp.h2
-rw-r--r--libs/hwui/DisplayListRenderer.cpp6
-rw-r--r--libs/hwui/Layer.cpp11
-rw-r--r--libs/hwui/Layer.h11
-rw-r--r--libs/hwui/OpenGLRenderer.cpp3
-rw-r--r--libs/hwui/RenderNode.cpp73
-rw-r--r--libs/hwui/RenderNode.h20
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp28
-rw-r--r--libs/hwui/renderthread/CanvasContext.h8
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp57
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h19
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp57
-rw-r--r--libs/hwui/renderthread/RenderProxy.h9
-rw-r--r--libs/hwui/utils/VirtualLightRefBase.h34
20 files changed, 253 insertions, 145 deletions
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 477d69172c78..df2123bb5db4 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -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);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 50c5fef633d7..ba3ccafc2879 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -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;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5b4e03f515e0..358e1af92aeb 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -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,
+ mDisplayList->pushStagingChanges();
+ mLayer->updateDeferred(mDisplayList.get(),
mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
mDirtyRect.setEmpty();
mDisplayList = 0;
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 10fa264d87fe..ce08c2de8960 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -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;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 9e6a96d38713..a5d8dcb3fe0f 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -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
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index df5cba61d7cb..fe70d13fb984 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -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();
};
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 5fa8f1d5e9ee..06f675efcf23 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1523,6 +1523,8 @@ public:
virtual const char* name() { return "DrawDisplayList"; }
+ RenderNode* renderNode() { return mDisplayList; }
+
private:
RenderNode* mDisplayList;
const int mFlags;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 78c97e14d363..140a07afc7c5 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -191,8 +191,10 @@ status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList,
DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
flags, *currentTransform());
addDrawOp(op);
- mDisplayListData->children.push(op);
- if (displayList->isProjectionReceiver()) {
+ mDisplayListData->addChild(op);
+
+ if (displayList->stagingProperties().isProjectionReceiver()) {
+ // use staging property, since recording on UI thread
mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 27409a2887c2..bfe4eda44ddc 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -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();
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index b428404f04e0..5375b4509db1 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -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;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e1f484d90fd7..f37487fcfd68 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -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;
@@ -1901,7 +1901,6 @@ status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty,
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
// compute 3d ordering
- displayList->updateProperties();
displayList->computeOrdering();
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 663b67ef053c..761fb84c25ab 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -49,7 +49,12 @@ void RenderNode::outputLogBuffer(int fd) {
fflush(file);
}
-RenderNode::RenderNode() : mDestroyed(false), mNeedsPropertiesSync(false), mDisplayListData(0) {
+RenderNode::RenderNode()
+ : mDestroyed(false)
+ , mNeedsPropertiesSync(false)
+ , mNeedsDisplayListDataSync(false)
+ , mDisplayListData(0)
+ , mStagingDisplayListData(0) {
}
RenderNode::~RenderNode() {
@@ -57,24 +62,15 @@ RenderNode::~RenderNode() {
mDestroyed = true;
delete mDisplayListData;
+ delete mStagingDisplayListData;
}
-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;
- if (mDisplayListData) {
- Caches::getInstance().registerFunctors(mDisplayListData->functorCount);
+void RenderNode::setStagingDisplayList(DisplayListData* data) {
+ mNeedsDisplayListDataSync = true;
+ delete mStagingDisplayListData;
+ mStagingDisplayListData = data;
+ if (mStagingDisplayListData) {
+ Caches::getInstance().registerFunctors(mStagingDisplayListData->functorCount);
}
}
@@ -97,16 +93,29 @@ void RenderNode::output(uint32_t level) {
ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
}
-void RenderNode::updateProperties() {
+void RenderNode::pushStagingChanges() {
if (mNeedsPropertiesSync) {
mNeedsPropertiesSync = false;
mProperties = mStagingProperties;
}
+ if (mNeedsDisplayListDataSync) {
+ mNeedsDisplayListDataSync = false;
+ // Do a push pass on the old tree to handle freeing DisplayListData
+ // that are no longer used
+ pushSubTreeStagingChanges(mDisplayListData);
+ delete mDisplayListData;
+ mDisplayListData = mStagingDisplayListData;
+ mStagingDisplayListData = 0;
+ }
+
+ pushSubTreeStagingChanges(mDisplayListData);
+}
- if (mDisplayListData) {
- for (size_t i = 0; i < mDisplayListData->children.size(); i++) {
- RenderNode* childNode = mDisplayListData->children[i]->mDisplayList;
- childNode->updateProperties();
+void RenderNode::pushSubTreeStagingChanges(DisplayListData* subtree) {
+ if (subtree) {
+ for (size_t i = 0; i < subtree->children().size(); i++) {
+ RenderNode* childNode = subtree->children()[i]->mDisplayList;
+ childNode->pushStagingChanges();
}
}
}
@@ -118,8 +127,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 +257,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 +286,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 +384,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();
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index fb5336d1277c..e5b9d7c395b6 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -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,10 +87,9 @@ public:
kReplayFlag_ClipChildren = 0x1
};
- ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList);
ANDROID_API static void outputLogBuffer(int fd);
- ANDROID_API void setData(DisplayListData* newData);
+ ANDROID_API void setStagingDisplayList(DisplayListData* newData);
void computeOrdering();
@@ -105,6 +105,10 @@ public:
return mDisplayListData && mDisplayListData->hasDrawOps;
}
+ const char* getName() const {
+ return mName.string();
+ }
+
void setName(const char* name) {
if (name) {
char* lastPeriod = strrchr(name, '.');
@@ -129,10 +133,6 @@ public:
return mStagingProperties;
}
- bool isProjectionReceiver() {
- return properties().isProjectionReceiver();
- }
-
int getWidth() {
return properties().getWidth();
}
@@ -141,7 +141,7 @@ public:
return properties().getHeight();
}
- ANDROID_API void updateProperties();
+ ANDROID_API void pushStagingChanges();
// Returns true if this RenderNode or any of its children have functors
bool hasFunctors();
@@ -203,6 +203,8 @@ private:
const char* mText;
};
+ static void pushSubTreeStagingChanges(DisplayListData* subtree);
+
String8 mName;
bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed
@@ -210,7 +212,9 @@ private:
RenderProperties mProperties;
RenderProperties mStagingProperties;
+ bool mNeedsDisplayListDataSync;
DisplayListData* mDisplayListData;
+ DisplayListData* mStagingDisplayListData;
/**
* Draw time state - these properties are only set and used during rendering
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fa8262705426..014c7d0332b6 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -347,6 +347,7 @@ void CanvasContext::setSurface(EGLNativeWindowType window) {
if (mEglSurface != EGL_NO_SURFACE) {
mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+ mGlobalContext->makeCurrent(mEglSurface);
mHaveNewSurface = true;
}
}
@@ -356,14 +357,15 @@ void CanvasContext::swapBuffers() {
mHaveNewSurface = false;
}
-void CanvasContext::makeCurrent() {
+void CanvasContext::requireSurface() {
+ LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+ "requireSurface() called but no surface set!");
mGlobalContext->makeCurrent(mEglSurface);
}
bool CanvasContext::initialize(EGLNativeWindowType window) {
if (mCanvas) return false;
setSurface(window);
- makeCurrent();
mCanvas = new OpenGLRenderer();
mCanvas->initProperties();
return true;
@@ -371,7 +373,11 @@ bool CanvasContext::initialize(EGLNativeWindowType window) {
void CanvasContext::updateSurface(EGLNativeWindowType window) {
setSurface(window);
- makeCurrent();
+}
+
+void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+ // TODO: For now we just need a fence, in the future suspend any animations
+ // and such to prevent from trying to render into this surface
}
void CanvasContext::setup(int width, int height) {
@@ -379,10 +385,6 @@ void CanvasContext::setup(int width, int height) {
mCanvas->setViewport(width, height);
}
-void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) {
- displayList->setData(newData);
-}
-
void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
mGlobalContext->makeCurrent(mEglSurface);
for (size_t i = 0; i < layerUpdaters->size(); i++) {
@@ -460,7 +462,7 @@ void CanvasContext::invokeFunctors() {
if (!mCanvas) return;
- makeCurrent();
+ requireSurface();
Rect dirty;
mCanvas->invokeFunctors(dirty);
}
@@ -490,6 +492,16 @@ void CanvasContext::runWithGlContext(RenderTask* task) {
task->run();
}
+Layer* CanvasContext::createRenderLayer(int width, int height) {
+ requireSurface();
+ return LayerRenderer::createRenderLayer(width, height);
+}
+
+Layer* CanvasContext::createTextureLayer() {
+ requireSurface();
+ return LayerRenderer::createTextureLayer();
+}
+
void CanvasContext::requireGlContext() {
if (mEglSurface != EGL_NO_SURFACE) {
mGlobalContext->makeCurrent(mEglSurface);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index eb9096d5d92c..4d830babfd6c 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -35,6 +35,7 @@ class RenderNode;
class DisplayListData;
class OpenGLRenderer;
class Rect;
+class Layer;
namespace renderthread {
@@ -62,8 +63,8 @@ public:
bool initialize(EGLNativeWindowType window);
void updateSurface(EGLNativeWindowType window);
+ void pauseSurface(EGLNativeWindowType window);
void setup(int width, int height);
- void setDisplayListData(RenderNode* displayList, DisplayListData* newData);
void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
void drawDisplayList(RenderNode* displayList, Rect* dirty);
void destroyCanvas();
@@ -76,10 +77,13 @@ public:
void runWithGlContext(RenderTask* task);
+ Layer* createRenderLayer(int width, int height);
+ Layer* createTextureLayer();
+
private:
void setSurface(EGLNativeWindowType window);
void swapBuffers();
- void makeCurrent();
+ void requireSurface();
friend class InvokeFunctorsTask;
void invokeFunctors();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 1e9089a30a46..6e7ec9b42ef9 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,7 +30,7 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) {
+DrawFrameTask::DrawFrameTask() : mContext(0), mTaskMode(MODE_INVALID), mRenderNode(0) {
}
DrawFrameTask::~DrawFrameTask() {
@@ -40,14 +40,9 @@ void DrawFrameTask::setContext(CanvasContext* context) {
mContext = context;
}
-void DrawFrameTask::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
- SetDisplayListData setter;
- setter.targetNode = renderNode;
- setter.newData = 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 +56,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 +66,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();
@@ -109,14 +124,12 @@ void DrawFrameTask::run() {
void DrawFrameTask::syncFrameState() {
ATRACE_CALL();
- for (size_t i = 0; i < mDisplayListDataUpdates.size(); i++) {
- const SetDisplayListData& setter = mDisplayListDataUpdates[i];
- setter.targetNode->setData(setter.newData);
- }
- mDisplayListDataUpdates.clear();
-
mContext->processLayerUpdates(&mLayers);
- mRenderNode->updateProperties();
+
+ // If we don't have an mRenderNode this is a state flush only
+ if (mRenderNode.get()) {
+ mRenderNode->pushStagingChanges();
+ }
}
void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 5450dd57133e..ddf756b71877 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -18,6 +18,7 @@
#include <utils/Condition.h>
#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
#include <utils/Vector.h>
#include "RenderTask.h"
@@ -36,11 +37,6 @@ namespace renderthread {
class CanvasContext;
class RenderThread;
-struct SetDisplayListData {
- RenderNode* targetNode;
- DisplayListData* newData;
-};
-
/*
* 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,17 +50,24 @@ public:
void setContext(CanvasContext* context);
- void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
void addLayer(DeferredLayerUpdater* layer);
void removeLayer(DeferredLayerUpdater* layer);
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,9 +84,9 @@ private:
/*********************************************
* Single frame data
*********************************************/
- RenderNode* mRenderNode;
+ TaskMode mTaskMode;
+ sp<RenderNode> mRenderNode;
Rect mDirty;
- Vector<SetDisplayListData> mDisplayListDataUpdates;
/*********************************************
* Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index cd711b030581..49b9acab1c17 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -48,7 +48,7 @@ namespace renderthread {
LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
"METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
- MethodInvokeRenderTask* task = createTask((RunnableMethod) Bridge_ ## method); \
+ MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
CREATE_BRIDGE1(createContext, bool translucent) {
@@ -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;
@@ -89,10 +92,10 @@ CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
return (void*) args->context->initialize(args->window);
}
-bool RenderProxy::initialize(EGLNativeWindowType window) {
+bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
SETUP_TASK(initialize);
args->context = mContext;
- args->window = window;
+ args->window = window.get();
return (bool) postAndWait(task);
}
@@ -101,11 +104,23 @@ CREATE_BRIDGE2(updateSurface, CanvasContext* context, EGLNativeWindowType window
return NULL;
}
-void RenderProxy::updateSurface(EGLNativeWindowType window) {
+void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
SETUP_TASK(updateSurface);
args->context = mContext;
- args->window = window;
- post(task);
+ args->window = window.get();
+ postAndWait(task);
+}
+
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) {
+ args->context->pauseSurface(args->window);
+ return NULL;
+}
+
+void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+ SETUP_TASK(pauseSurface);
+ args->context = mContext;
+ args->window = window.get();
+ postAndWait(task);
}
CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
@@ -121,10 +136,6 @@ void RenderProxy::setup(int width, int height) {
post(task);
}
-void RenderProxy::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) {
- mDrawFrameTask.setDisplayListData(renderNode, newData);
-}
-
void RenderProxy::drawDisplayList(RenderNode* displayList,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
mDrawFrameTask.setRenderNode(displayList);
@@ -138,6 +149,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);
@@ -195,10 +210,9 @@ void RenderProxy::runWithGlContext(RenderTask* gltask) {
postAndWait(task);
}
-CREATE_BRIDGE2(createDisplayListLayer, int width, int height) {
- Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height);
+CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
+ Layer* layer = args->context->createRenderLayer(args->width, args->height);
if (!layer) return 0;
-
return new DeferredLayerUpdater(layer);
}
@@ -206,20 +220,22 @@ DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height)
SETUP_TASK(createDisplayListLayer);
args->width = width;
args->height = height;
+ args->context = mContext;
void* retval = postAndWait(task);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
mDrawFrameTask.addLayer(layer);
return layer;
}
-CREATE_BRIDGE0(createTextureLayer) {
- Layer* layer = LayerRenderer::createTextureLayer();
+CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
+ Layer* layer = args->context->createTextureLayer();
if (!layer) return 0;
return new DeferredLayerUpdater(layer);
}
DeferredLayerUpdater* RenderProxy::createTextureLayer() {
SETUP_TASK(createTextureLayer);
+ args->context = mContext;
void* retval = postAndWait(task);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
mDrawFrameTask.addLayer(layer);
@@ -252,9 +268,14 @@ void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
post(task);
}
-MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
- // TODO: Consider having a small pool of these to avoid alloc churn
- return new MethodInvokeRenderTask(method);
+CREATE_BRIDGE0(fence) {
+ // Intentionally empty
+ return NULL;
+}
+
+void RenderProxy::fence() {
+ SETUP_TASK(fence);
+ postAndWait(task);
}
void RenderProxy::post(RenderTask* task) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index f1ca534e21d7..1ad3c85253c5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -59,10 +59,10 @@ public:
ANDROID_API RenderProxy(bool translucent);
ANDROID_API virtual ~RenderProxy();
- ANDROID_API bool initialize(EGLNativeWindowType window);
- ANDROID_API void updateSurface(EGLNativeWindowType window);
+ ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+ 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 setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
ANDROID_API void drawDisplayList(RenderNode* displayList,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
ANDROID_API void destroyCanvas();
@@ -78,6 +78,8 @@ public:
ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+ ANDROID_API void fence();
+
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
@@ -89,7 +91,6 @@ private:
void destroyContext();
- MethodInvokeRenderTask* createTask(RunnableMethod method);
void post(RenderTask* task);
void* postAndWait(MethodInvokeRenderTask* task);
diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/VirtualLightRefBase.h
new file mode 100644
index 000000000000..b545aabac802
--- /dev/null
+++ b/libs/hwui/utils/VirtualLightRefBase.h
@@ -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 */