diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/hwui/Caches.cpp | 16 | ||||
| -rw-r--r-- | libs/hwui/Caches.h | 6 | ||||
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 6 | ||||
| -rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 2 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.cpp | 14 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.h | 16 | ||||
| -rw-r--r-- | libs/hwui/DisplayListOp.h | 2 | ||||
| -rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 6 | ||||
| -rw-r--r-- | libs/hwui/Layer.cpp | 11 | ||||
| -rw-r--r-- | libs/hwui/Layer.h | 11 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 3 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 73 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.h | 20 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 28 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 8 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 57 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 19 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 57 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 9 | ||||
| -rw-r--r-- | libs/hwui/utils/VirtualLightRefBase.h | 34 |
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 */ |