diff options
Diffstat (limited to 'libs/hwui')
-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/DisplayListOp.h | 34 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 11 | ||||
-rw-r--r-- | libs/hwui/Layer.h | 6 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Outline.h | 1 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 46 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 3 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.cpp | 41 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.h | 29 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/RevealClip.h | 78 | ||||
-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 |
20 files changed, 489 insertions, 87 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/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 549b786..9e367fc 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -21,6 +21,8 @@ #define LOG_TAG "OpenGLRenderer" #endif +#include <SkPath.h> +#include <SkPathOps.h> #include <SkXfermode.h> #include <private/hwui/DrawGlInfo.h> @@ -1550,20 +1552,27 @@ private: */ class DrawShadowOp : public DrawOp { public: - DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha, const SkPath* outline, - float fallbackWidth, float fallbackHeight) - : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), - mAlpha(alpha), mOutline(outline), - mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {} + DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha, + float fallbackWidth, float fallbackHeight, + const SkPath* outline, const SkPath* revealClip) + : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), mAlpha(alpha), + mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight), + mOutline(outline), mRevealClip(revealClip) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { - if (mOutline->isEmpty()) { - SkPath fakeOutline; - fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); - return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &fakeOutline); + SkPath casterPerimeter; + if (!mOutline || mOutline->isEmpty()) { + casterPerimeter.addRect(0, 0, mFallbackWidth, mFallbackHeight); + } else { + casterPerimeter = *mOutline; + } + + if (mRevealClip) { + // intersect the outline with the convex reveal clip + Op(casterPerimeter, *mRevealClip, kIntersect_PathOp, &casterPerimeter); } - return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, mOutline); + return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &casterPerimeter); } virtual void output(int level, uint32_t logFlags) const { @@ -1576,9 +1585,12 @@ private: const mat4 mTransformXY; const mat4 mTransformZ; const float mAlpha; - const SkPath* mOutline; const float mFallbackWidth; const float mFallbackHeight; + + // these point at convex SkPaths owned by RenderProperties, or null + const SkPath* mOutline; + const SkPath* mRevealClip; }; class DrawLayerOp : public DrawOp { 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/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index cdd789d..d808735 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1919,6 +1919,7 @@ 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(); @@ -3202,7 +3203,7 @@ static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& t } status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, - float casterAlpha, const SkPath* casterOutline) { + float casterAlpha, const SkPath* casterPerimeter) { if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; // TODO: use quickRejectWithScissor. For now, always force enable scissor. @@ -3214,7 +3215,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c // tessellate caster outline into a 2d polygon Vector<Vertex> casterVertices2d; const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value - PathTessellator::approximatePathOutlineVertices(*casterOutline, + PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThresholdSquared, casterVertices2d); if (casterVertices2d.size() == 0) { @@ -3256,7 +3257,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c // We only have ortho projection, so we can just ignore the Z in caster for // simple rejection calculation. Rect localClip = mSnapshot->getLocalClip(); - Rect casterBounds(casterOutline->getBounds()); + Rect casterBounds(casterPerimeter->getBounds()); casterTransformXY.mapRect(casterBounds); bool isCasterOpaque = (casterAlpha == 1.0f); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 059c64f..054767e 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -210,7 +210,7 @@ public: virtual status_t drawRects(const float* rects, int count, const SkPaint* paint); status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, - float casterAlpha, const SkPath* casterOutline); + float casterAlpha, const SkPath* casterPerimeter); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h index 4e496e7..530be30 100644 --- a/libs/hwui/Outline.h +++ b/libs/hwui/Outline.h @@ -58,7 +58,6 @@ public: mShouldClip = clip; } - bool willClip() const { // only round rect outlines can be used for clipping return mShouldClip && (mType == kOutlineType_RoundRect); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d3daec8..675b215 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 @@ -152,18 +169,21 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler, } SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - 0, 0, properties().getWidth(), properties().getHeight(), properties().getAlpha() * 255, saveFlags); + 0, 0, properties().getWidth(), properties().getHeight(), + properties().getAlpha() * 255, saveFlags); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } } if (clipToBoundsNeeded) { - ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0, - properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op); + ClipRectOp* op = new (handler.allocator()) ClipRectOp( + 0, 0, properties().getWidth(), properties().getHeight(), SkRegion::kIntersect_Op); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } - if (CC_UNLIKELY(properties().getOutline().willClip())) { - ClipPathOp* op = new (handler.allocator()) ClipPathOp(properties().getOutline().getPath(), - SkRegion::kIntersect_Op); + + if (CC_UNLIKELY(properties().hasClippingPath())) { + // TODO: optimize for round rect/circle clipping + const SkPath* path = properties().getClippingPath(); + ClipPathOp* op = new (handler.allocator()) ClipPathOp(path, SkRegion::kIntersect_Op); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } } @@ -408,10 +428,15 @@ void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTransl mat4 shadowMatrixZ(casterOp->mTransformFromParent); caster->applyViewPropertyTransforms(shadowMatrixZ, true); + const SkPath* outlinePath = caster->properties().getOutline().getPath(); + const RevealClip& revealClip = caster->properties().getRevealClip(); + const SkPath* revealClipPath = revealClip.hasConvexClip() + ? revealClip.getPath() : NULL; // only pass the reveal clip's path if it's convex + DisplayListOp* shadowOp = new (alloc) DrawShadowOp( - shadowMatrixXY, shadowMatrixZ, - caster->properties().getAlpha(), caster->properties().getOutline().getPath(), - caster->properties().getWidth(), caster->properties().getHeight()); + shadowMatrixXY, shadowMatrixZ, caster->properties().getAlpha(), + caster->properties().getWidth(), caster->properties().getHeight(), + outlinePath, revealClipPath); handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } @@ -498,7 +523,8 @@ void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) setViewProperties<T>(renderer, handler, level + 1); - bool quickRejected = properties().getClipToBounds() && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); + bool quickRejected = properties().getClipToBounds() + && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); if (!quickRejected) { Vector<ZDrawDisplayListOpPair> zTranslatedNodes; buildZSortedChildList(zTranslatedNodes); 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/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index ca291a6..3975a76 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -22,6 +22,8 @@ #include <SkCanvas.h> #include <SkMatrix.h> +#include <SkPath.h> +#include <SkPathOps.h> #include "Matrix.h" @@ -51,13 +53,15 @@ RenderProperties::PrimitiveFields::PrimitiveFields() RenderProperties::ComputedFields::ComputedFields() : mTransformMatrix(NULL) , mTransformCamera(NULL) - , mTransformMatrix3D(NULL) { + , mTransformMatrix3D(NULL) + , mClipPath(NULL) { } RenderProperties::ComputedFields::~ComputedFields() { delete mTransformMatrix; delete mTransformCamera; delete mTransformMatrix3D; + delete mClipPath; } RenderProperties::RenderProperties() @@ -80,6 +84,7 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) { // Update the computed fields updateMatrix(); + updateClipPath(); } return *this; } @@ -181,5 +186,39 @@ void RenderProperties::updateMatrix() { } } +void RenderProperties::updateClipPath() { + const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip() + ? mPrimitiveFields.mOutline.getPath() : NULL; + const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath(); + + if (!outlineClipPath && !revealClipPath) { + // mComputedFields.mClipPath doesn't need to be updated, since it won't be used + return; + } + + if (mComputedFields.mClipPath == NULL) { + mComputedFields.mClipPath = new SkPath(); + } + SkPath* clipPath = mComputedFields.mClipPath; + mComputedFields.mClipPathOp = SkRegion::kIntersect_Op; + + if (outlineClipPath && revealClipPath) { + SkPathOp op = kIntersect_PathOp; + if (mPrimitiveFields.mRevealClip.isInverseClip()) { + op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time + } + + Op(*outlineClipPath, *revealClipPath, op, clipPath); + } else if (outlineClipPath) { + *clipPath = *outlineClipPath; + } else { + *clipPath = *revealClipPath; + if (mPrimitiveFields.mRevealClip.isInverseClip()) { + // apply difference step at draw time + mComputedFields.mClipPathOp = SkRegion::kDifference_Op; + } + } +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 504196d..061e469 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -22,8 +22,10 @@ #include <SkCamera.h> #include <SkMatrix.h> +#include <SkRegion.h> #include "Rect.h" +#include "RevealClip.h" #include "Outline.h" #define TRANSLATION 0x0001 @@ -34,7 +36,6 @@ class SkBitmap; class SkPaint; -class SkRegion; namespace android { namespace uirenderer { @@ -415,6 +416,10 @@ public: return mPrimitiveFields.mOutline; } + const RevealClip& getRevealClip() const { + return mPrimitiveFields.mRevealClip; + } + bool getProjectBackwards() const { return mPrimitiveFields.mProjectBackwards; } @@ -423,10 +428,29 @@ public: ANDROID_API void updateMatrix(); + ANDROID_API void updateClipPath(); + + // signals that mComputedFields.mClipPath is up to date, and should be used for clipping + bool hasClippingPath() const { + return mPrimitiveFields.mOutline.willClip() || mPrimitiveFields.mRevealClip.willClip(); + } + + const SkPath* getClippingPath() const { + return hasClippingPath() ? mComputedFields.mClipPath : NULL; + } + + SkRegion::Op getClippingPathOp() const { + return mComputedFields.mClipPathOp; + } + Outline& mutableOutline() { return mPrimitiveFields.mOutline; } + RevealClip& mutableRevealClip() { + return mPrimitiveFields.mRevealClip; + } + private: void onTranslationUpdate() { mPrimitiveFields.mMatrixDirty = true; @@ -442,6 +466,7 @@ private: PrimitiveFields(); Outline mOutline; + RevealClip mRevealClip; bool mClipToBounds; bool mProjectBackwards; bool mProjectionReceiver; @@ -483,6 +508,8 @@ private: Matrix4* mTransformMatrix; Sk3DView* mTransformCamera; SkMatrix* mTransformMatrix3D; + SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping + SkRegion::Op mClipPathOp; } mComputedFields; }; diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 5562f34..13a3e8e 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -31,9 +31,9 @@ void ResourceCache::logCache() { ALOGD("ResourceCache: cacheReport:"); for (size_t i = 0; i < mCache->size(); ++i) { ResourceReference* ref = mCache->valueAt(i); - ALOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", + ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i), mCache->valueAt(i)); - ALOGD(" ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d", + ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d", i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); } } diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h new file mode 100644 index 0000000..ece8498 --- /dev/null +++ b/libs/hwui/RevealClip.h @@ -0,0 +1,78 @@ +/* + * 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 REVEALCLIP_H +#define REVEALCLIP_H + +#include <SkPath.h> + +#include "Rect.h" + +namespace android { +namespace uirenderer { + +class RevealClip { +public: + RevealClip() + : mShouldClip(false) + , mInverseClip(false) + , mX(0) + , mY(0) + , mRadius(0) {} + + void set(bool shouldClip, bool inverseClip, float x, float y, float radius) { + mShouldClip = shouldClip; + mInverseClip = inverseClip; + mX = x; + mY = y; + mRadius = radius; + + mPath.rewind(); + if (mShouldClip) { + mPath.addCircle(x, y, radius); + } + } + + bool hasConvexClip() const { + return mShouldClip && !mInverseClip; + } + + bool isInverseClip() const { + return mInverseClip; + } + + bool willClip() const { + return mShouldClip; + } + + const SkPath* getPath() const { + if (!mShouldClip) return NULL; + + return &mPath; + } + +private: + bool mShouldClip; + bool mInverseClip; + float mX; + float mY; + float mRadius; + SkPath mPath; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* REVEALCLIP_H */ 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); |