diff options
author | John Reck <jreck@google.com> | 2014-03-26 15:10:40 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-03-27 10:00:04 -0700 |
commit | 668f0e38ef0277d55d3118af37e17b8c435df85c (patch) | |
tree | d0703be6cce376c8a982d7c491445d2e94009375 | |
parent | bcad68ad80e5a44e5dc6988eddb8acabdc01a737 (diff) | |
download | frameworks_base-668f0e38ef0277d55d3118af37e17b8c435df85c.zip frameworks_base-668f0e38ef0277d55d3118af37e17b8c435df85c.tar.gz frameworks_base-668f0e38ef0277d55d3118af37e17b8c435df85c.tar.bz2 |
Async drawing!
Change-Id: I7e728356f58af88174328a8c0b90d27b128bfe01
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 1 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 6 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 3 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 143 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 98 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 57 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 8 |
12 files changed, 294 insertions, 57 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 4de755d..52be531 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -54,6 +54,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) # RenderThread stuff LOCAL_SRC_FILES += \ renderthread/CanvasContext.cpp \ + renderthread/DrawFrameTask.cpp \ renderthread/RenderProxy.cpp \ renderthread/RenderTask.cpp \ renderthread/RenderThread.cpp diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 7380bbf..5b4e03f 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -29,7 +29,6 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* rendere , mNeedsGLContextAttach(false) , mUpdateTexImage(false) , mLayer(layer) - , mRenderer(renderer) , mCaches(Caches::getInstance()) { mWidth = mLayer->layer.getWidth(); mHeight = mLayer->layer.getHeight(); @@ -45,7 +44,6 @@ DeferredLayerUpdater::~DeferredLayerUpdater() { if (mLayer) { mCaches.resourceCache.decrementRefcount(mLayer); } - delete mRenderer; } void DeferredLayerUpdater::setPaint(const SkPaint* paint) { @@ -76,7 +74,7 @@ bool DeferredLayerUpdater::apply() { } mLayer->setBlend(mBlend); mDisplayList->updateProperties(); - mLayer->updateDeferred(mRenderer, mDisplayList, + mLayer->updateDeferred(mDisplayList, 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 cf745ee..10fa264 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -109,7 +109,6 @@ private: bool mUpdateTexImage; Layer* mLayer; - OpenGLRenderer* mRenderer; Caches& mCaches; void doUpdateTexImage(); diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index bd9bfe9..4457c61 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -58,6 +58,7 @@ Layer::~Layer() { delete[] mesh; delete deferredList; + delete renderer; } uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { @@ -68,6 +69,13 @@ uint32_t Layer::computeIdealHeight(uint32_t layerHeight) { return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); } +void Layer::requireRenderer() { + if (!renderer) { + renderer = new LayerRenderer(this); + renderer->initProperties(); + } +} + bool Layer::resize(const uint32_t width, const uint32_t height) { uint32_t desiredWidth = computeIdealWidth(width); uint32_t desiredHeight = computeIdealWidth(height); @@ -207,7 +215,6 @@ void Layer::defer() { } void Layer::cancelDefer() { - renderer = NULL; displayList = NULL; deferredUpdateScheduled = false; if (deferredList) { @@ -226,7 +233,6 @@ void Layer::flush() { deferredList->flush(*renderer, dirtyRect); renderer->finish(); - renderer = NULL; dirtyRect.setEmpty(); displayList = NULL; @@ -241,7 +247,6 @@ void Layer::render() { renderer->drawDisplayList(displayList, dirtyRect, RenderNode::kReplayFlag_ClipChildren); renderer->finish(); - renderer = NULL; dirtyRect.setEmpty(); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index d8440ea..b428404 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -84,9 +84,9 @@ public: regionRect.translate(layer.left, layer.top); } - void updateDeferred(OpenGLRenderer* renderer, RenderNode* displayList, + void updateDeferred(RenderNode* displayList, int left, int top, int right, int bottom) { - this->renderer = renderer; + requireRenderer(); this->displayList = displayList; const Rect r(left, top, right, bottom); dirtyRect.unionWith(r); @@ -300,6 +300,8 @@ public: bool hasDrawnSinceUpdate; private: + void requireRenderer(); + Caches& caches; /** diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d3daec8..f0cf42f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -107,6 +107,23 @@ void RenderNode::updateProperties() { } } +bool RenderNode::hasFunctors() { + if (!mDisplayListData) return false; + + if (mDisplayListData->functorCount) { + return true; + } + + for (size_t i = 0; i < mDisplayListData->children.size(); i++) { + RenderNode* childNode = mDisplayListData->children[i]->mDisplayList; + if (childNode->hasFunctors()) { + return true; + } + } + + return false; +} + /* * For property operations, we pass a savecount of 0, since the operations aren't part of the * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 756c944..291d03d 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -139,6 +139,9 @@ public: ANDROID_API void updateProperties(); + // Returns true if this RenderNode or any of its children have functors + bool hasFunctors(); + private: typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index b3b4173..8ebffc2 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -392,8 +392,6 @@ void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); - displayList->updateProperties(); - EGLint width, height; mGlobalContext->beginFrame(mEglSurface, &width, &height); if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) { diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp new file mode 100644 index 0000000..1e9089a --- /dev/null +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#define ATRACE_TAG ATRACE_TAG_VIEW + +#include "DrawFrameTask.h" + +#include <utils/Log.h> +#include <utils/Trace.h> + +#include "../DisplayList.h" +#include "../RenderNode.h" +#include "CanvasContext.h" +#include "RenderThread.h" + +namespace android { +namespace uirenderer { +namespace renderthread { + +DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) { +} + +DrawFrameTask::~DrawFrameTask() { +} + +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) { + mLayers.push(layer); +} + +void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) { + for (size_t i = 0; i < mLayers.size(); i++) { + if (mLayers[i] == layer) { + mLayers.removeAt(i); + break; + } + } +} + +void DrawFrameTask::setRenderNode(RenderNode* renderNode) { + mRenderNode = renderNode; +} + +void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { + mDirty.set(left, top, right, bottom); +} + +void DrawFrameTask::drawFrame(RenderThread* renderThread) { + LOG_ALWAYS_FATAL_IF(!mRenderNode, "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); + + // Reset the single-frame data + mDirty.setEmpty(); + mRenderNode = 0; +} + +void DrawFrameTask::run() { + ATRACE_NAME("DrawFrame"); + + syncFrameState(); + + // Grab a copy of everything we need + Rect dirtyCopy(mDirty); + RenderNode* renderNode = mRenderNode; + CanvasContext* context = mContext; + + // This is temporary until WebView has a solution for syncing frame state + bool canUnblockUiThread = !requiresSynchronousDraw(renderNode); + + // From this point on anything in "this" is *UNSAFE TO ACCESS* + if (canUnblockUiThread) { + unblockUiThread(); + } + + drawRenderNode(context, renderNode, &dirtyCopy); + + if (!canUnblockUiThread) { + unblockUiThread(); + } +} + +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(); +} + +void DrawFrameTask::unblockUiThread() { + AutoMutex _lock(mLock); + mSignal.signal(); +} + +void DrawFrameTask::drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty) { + ATRACE_CALL(); + + if (dirty->bottom == -1 && dirty->left == -1 + && dirty->top == -1 && dirty->right == -1) { + dirty = 0; + } + context->drawDisplayList(renderNode, dirty); +} + +bool DrawFrameTask::requiresSynchronousDraw(RenderNode* renderNode) { + return renderNode->hasFunctors(); +} + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h new file mode 100644 index 0000000..5450dd5 --- /dev/null +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -0,0 +1,98 @@ +/* + * 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 DRAWFRAMETASK_H +#define DRAWFRAMETASK_H + +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <utils/Vector.h> + +#include "RenderTask.h" + +#include "../Rect.h" + +namespace android { +namespace uirenderer { + +class DeferredLayerUpdater; +class DisplayListData; +class RenderNode; + +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 + * tracked across many frames not just a single frame. + * It is the sync-state task, and will kick off the post-sync draw + */ +class DrawFrameTask : public RenderTask { +public: + DrawFrameTask(); + virtual ~DrawFrameTask(); + + 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); + + virtual void run(); + +private: + void syncFrameState(); + void unblockUiThread(); + static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty); + + // This checks to see if there are any drawGlFunctors which would require + // a synchronous drawRenderNode() + static bool requiresSynchronousDraw(RenderNode* renderNode); + + Mutex mLock; + Condition mSignal; + + CanvasContext* mContext; + + /********************************************* + * Single frame data + *********************************************/ + RenderNode* mRenderNode; + Rect mDirty; + Vector<SetDisplayListData> mDisplayListDataUpdates; + + /********************************************* + * Multi frame data + *********************************************/ + Vector<DeferredLayerUpdater*> mLayers; +}; + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* DRAWFRAMETASK_H */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 93360fc..16b93c3 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -61,6 +61,7 @@ RenderProxy::RenderProxy(bool translucent) SETUP_TASK(createContext); args->translucent = translucent; mContext = (CanvasContext*) postAndWait(task); + mDrawFrameTask.setContext(mContext); } RenderProxy::~RenderProxy() { @@ -77,7 +78,10 @@ void RenderProxy::destroyContext() { SETUP_TASK(destroyContext); args->context = mContext; mContext = 0; - post(task); + mDrawFrameTask.setContext(0); + // This is also a fence as we need to be certain that there are no + // outstanding mDrawFrame tasks posted before it is destroyed + postAndWait(task); } } @@ -117,41 +121,15 @@ void RenderProxy::setup(int width, int height) { post(task); } -CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, RenderNode* displayList, - DisplayListData* newData) { - args->context->setDisplayListData(args->displayList, args->newData); - return NULL; -} - -void RenderProxy::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { - SETUP_TASK(setDisplayListData); - args->context = mContext; - args->displayList = displayList; - args->newData = newData; - post(task); -} - -CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, RenderNode* displayList, - Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) { - Rect* dirty = &args->dirty; - if (dirty->bottom == -1 && dirty->left == -1 && - dirty->top == -1 && dirty->right == -1) { - dirty = 0; - } - args->context->processLayerUpdates(args->layerUpdates); - args->context->drawDisplayList(args->displayList, dirty); - return NULL; +void RenderProxy::setDisplayListData(RenderNode* renderNode, DisplayListData* newData) { + mDrawFrameTask.setDisplayListData(renderNode, newData); } void RenderProxy::drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { - SETUP_TASK(drawDisplayList); - args->context = mContext; - args->displayList = displayList; - args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); - args->layerUpdates = &mLayers; - // TODO: Switch to post() once some form of thread safety strategy is in place - postAndWait(task); + mDrawFrameTask.setRenderNode(displayList); + mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); + mDrawFrameTask.drawFrame(&mRenderThread); } CREATE_BRIDGE1(destroyCanvas, CanvasContext* context) { @@ -205,9 +183,7 @@ CREATE_BRIDGE2(createDisplayListLayer, int width, int height) { Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height); if (!layer) return 0; - OpenGLRenderer* renderer = new LayerRenderer(layer); - renderer->initProperties(); - return new DeferredLayerUpdater(layer, renderer); + return new DeferredLayerUpdater(layer); } DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) { @@ -216,7 +192,7 @@ DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) args->height = height; void* retval = postAndWait(task); DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval); - mLayers.push(layer); + mDrawFrameTask.addLayer(layer); return layer; } @@ -230,7 +206,7 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() { SETUP_TASK(createTextureLayer); void* retval = postAndWait(task); DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval); - mLayers.push(layer); + mDrawFrameTask.addLayer(layer); return layer; } @@ -254,12 +230,7 @@ bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { } void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) { - for (size_t i = 0; i < mLayers.size(); i++) { - if (mLayers[i] == layer) { - mLayers.removeAt(i); - break; - } - } + mDrawFrameTask.removeLayer(layer); SETUP_TASK(destroyLayer); args->layer = layer->detachBackingLayer(); post(task); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 73e9805..ee7a4c7 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -28,6 +28,8 @@ #include <utils/StrongPointer.h> #include <utils/Vector.h> +#include "DrawFrameTask.h" + namespace android { namespace uirenderer { @@ -60,7 +62,7 @@ public: ANDROID_API bool initialize(EGLNativeWindowType window); ANDROID_API void updateSurface(EGLNativeWindowType window); ANDROID_API void setup(int width, int height); - ANDROID_API void setDisplayListData(RenderNode* displayList, DisplayListData* newData); + 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(); @@ -79,11 +81,11 @@ private: RenderThread& mRenderThread; CanvasContext* mContext; + DrawFrameTask mDrawFrameTask; + Mutex mSyncMutex; Condition mSyncCondition; - Vector<DeferredLayerUpdater*> mLayers; - void destroyContext(); MethodInvokeRenderTask* createTask(RunnableMethod method); |