summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp4
-rw-r--r--libs/hwui/DeferredLayerUpdater.h1
-rw-r--r--libs/hwui/DisplayListOp.h34
-rw-r--r--libs/hwui/Layer.cpp11
-rw-r--r--libs/hwui/Layer.h6
-rw-r--r--libs/hwui/OpenGLRenderer.cpp7
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/Outline.h1
-rw-r--r--libs/hwui/RenderNode.cpp46
-rw-r--r--libs/hwui/RenderNode.h3
-rw-r--r--libs/hwui/RenderProperties.cpp41
-rw-r--r--libs/hwui/RenderProperties.h29
-rw-r--r--libs/hwui/ResourceCache.cpp4
-rw-r--r--libs/hwui/RevealClip.h78
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp2
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp143
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h98
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp57
-rw-r--r--libs/hwui/renderthread/RenderProxy.h8
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);