summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2014-06-12 13:46:45 -0700
committerJohn Reck <jreck@google.com>2014-06-12 19:25:33 -0700
commit25fbb3fa1138675379102a44405852555cefccbd (patch)
tree510d62715f870f85fc4eea8a781c0265e7eebae5 /libs/hwui
parenta447d29c65fb811cd184775a3476101a1cede929 (diff)
downloadframeworks_base-25fbb3fa1138675379102a44405852555cefccbd.zip
frameworks_base-25fbb3fa1138675379102a44405852555cefccbd.tar.gz
frameworks_base-25fbb3fa1138675379102a44405852555cefccbd.tar.bz2
Move LayerType to RenderNode
Change-Id: Icb79a5015cb0362b1f3a66d09007450730135a97
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/DamageAccumulator.cpp20
-rw-r--r--libs/hwui/DamageAccumulator.h10
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp30
-rw-r--r--libs/hwui/DeferredLayerUpdater.h8
-rw-r--r--libs/hwui/RenderNode.cpp148
-rw-r--r--libs/hwui/RenderNode.h10
-rw-r--r--libs/hwui/RenderProperties.cpp51
-rw-r--r--libs/hwui/RenderProperties.h103
-rw-r--r--libs/hwui/TreeInfo.h5
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp1
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp3
11 files changed, 301 insertions, 88 deletions
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 898e81a..1cb87f2 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -35,6 +35,7 @@ NullDamageAccumulator* NullDamageAccumulator::instance() {
enum TransformType {
TransformRenderNode,
TransformMatrix4,
+ TransformNone,
};
struct DirtyStack {
@@ -80,14 +81,25 @@ void DamageAccumulator::pushTransform(const Matrix4* transform) {
mHead->matrix4 = transform;
}
+void DamageAccumulator::pushNullTransform() {
+ pushCommon();
+ mHead->type = TransformNone;
+}
+
void DamageAccumulator::popTransform() {
LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
- if (dirtyFrame->type == TransformRenderNode) {
+ switch (dirtyFrame->type) {
+ case TransformRenderNode:
applyRenderNodeTransform(dirtyFrame);
- } else {
+ break;
+ case TransformMatrix4:
applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
}
}
@@ -186,6 +198,10 @@ void DamageAccumulator::dirty(float left, float top, float right, float bottom)
mHead->pendingDirty.join(left, top, right, bottom);
}
+void DamageAccumulator::peekAtDirty(SkRect* dest) {
+ *dest = mHead->pendingDirty;
+}
+
void DamageAccumulator::finish(SkRect* totalDirty) {
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 2ca30d4..fc9b41b 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -35,8 +35,10 @@ class IDamageAccumulator {
public:
virtual void pushTransform(const RenderNode* transform) = 0;
virtual void pushTransform(const Matrix4* transform) = 0;
+ virtual void pushNullTransform() = 0;
virtual void popTransform() = 0;
virtual void dirty(float left, float top, float right, float bottom) = 0;
+ virtual void peekAtDirty(SkRect* dest) = 0;
protected:
virtual ~IDamageAccumulator() {}
};
@@ -52,6 +54,9 @@ public:
// will be affected by the transform when popTransform() is called.
virtual void pushTransform(const RenderNode* transform);
virtual void pushTransform(const Matrix4* transform);
+ // This is used in combination with peekAtDirty to inspect the damage
+ // area of a subtree
+ virtual void pushNullTransform();
// Pops a transform node from the stack, propagating the dirty rect
// up to the parent node. Returns the IDamageTransform that was just applied
@@ -59,6 +64,9 @@ public:
virtual void dirty(float left, float top, float right, float bottom);
+ // Returns the current dirty area, *NOT* transformed by pushed transforms
+ virtual void peekAtDirty(SkRect* dest);
+
void finish(SkRect* totalDirty);
private:
@@ -75,8 +83,10 @@ class NullDamageAccumulator : public IDamageAccumulator {
public:
virtual void pushTransform(const RenderNode* transform) { }
virtual void pushTransform(const Matrix4* transform) { }
+ virtual void pushNullTransform() { }
virtual void popTransform() { }
virtual void dirty(float left, float top, float right, float bottom) { }
+ virtual void peekAtDirty(SkRect* dest) { dest->setEmpty(); }
ANDROID_API static NullDamageAccumulator* instance();
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d494c4c..8e99b9a 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -27,8 +27,7 @@ static void defaultLayerDestroyer(Layer* layer) {
}
DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
- : mDisplayList(0)
- , mSurfaceTexture(0)
+ : mSurfaceTexture(0)
, mTransform(0)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
@@ -41,7 +40,6 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroye
mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
- mDirtyRect.setEmpty();
if (!mDestroyer) {
mDestroyer = defaultLayerDestroyer;
@@ -60,37 +58,13 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
-void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom) {
- mDisplayList = displayList;
- if (mDirtyRect.isEmpty()) {
- mDirtyRect.set(left, top, right, bottom);
- } else {
- mDirtyRect.unionWith(Rect(left, top, right, bottom));
- }
-}
-
bool DeferredLayerUpdater::apply(TreeInfo& info) {
bool success = true;
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
- if (mDisplayList.get()) {
- if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
- success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
- }
- mLayer->setBlend(mBlend);
- // TODO: Use DamageAccumulator to get the damage area for the layer's
- // subtree to only update that part of the layer. Do this as part of
- // reworking layers to be a RenderProperty instead of a View-managed object
- mDirtyRect.set(0, 0, mWidth, mHeight);
- mDisplayList->prepareTree(info);
- mLayer->updateDeferred(mDisplayList.get(),
- mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
- mDirtyRect.setEmpty();
- mDisplayList = 0;
- } else if (mSurfaceTexture.get()) {
+ if (mSurfaceTexture.get()) {
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(mLayer->getTexture());
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index b7cfe80..5082271 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -74,9 +74,6 @@ public:
mTransform = matrix ? new SkMatrix(*matrix) : 0;
}
- ANDROID_API void setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom);
-
ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply(TreeInfo& info);
@@ -94,11 +91,6 @@ private:
int mAlpha;
SkXfermode::Mode mMode;
- // Layer type specific properties
- // displayList and surfaceTexture are mutually exclusive, only 1 may be set
- // dirtyRect is only valid if displayList is set
- sp<RenderNode> mDisplayList;
- Rect mDirtyRect;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;
bool mNeedsGLContextAttach;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 83ad76f..378183a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -30,6 +30,8 @@
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
+#include "LayerRenderer.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
@@ -59,12 +61,14 @@ RenderNode::RenderNode()
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
- , mNeedsAnimatorsSync(false) {
+ , mNeedsAnimatorsSync(false)
+ , mLayer(0) {
}
RenderNode::~RenderNode() {
delete mDisplayListData;
delete mStagingDisplayListData;
+ LayerRenderer::destroyLayerDeferred(mLayer);
}
void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -124,17 +128,72 @@ void RenderNode::damageSelf(TreeInfo& info) {
}
}
+void RenderNode::prepareLayer(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+ // We push a null transform here as we don't care what the existing dirty
+ // area is, only what our display list dirty is as well as our children's
+ // dirty area
+ info.damageAccumulator->pushNullTransform();
+ }
+}
+
+void RenderNode::pushLayerUpdate(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ // If we are not a layer OR we cannot be rendered (eg, view was detached)
+ // we need to destroy any Layers we may have had previously
+ if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+ if (layerType == kLayerTypeRenderLayer) {
+ info.damageAccumulator->popTransform();
+ }
+ if (CC_UNLIKELY(mLayer)) {
+ LayerRenderer::destroyLayer(mLayer);
+ mLayer = NULL;
+ }
+ return;
+ }
+
+ if (!mLayer) {
+ mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+ applyLayerPropertiesToLayer(info);
+ damageSelf(info);
+ } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
+ LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
+ damageSelf(info);
+ }
+
+ SkRect dirty;
+ info.damageAccumulator->peekAtDirty(&dirty);
+ info.damageAccumulator->popTransform();
+
+ if (!dirty.isEmpty()) {
+ mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
+ }
+ // This is not inside the above if because we may have called
+ // updateDeferred on a previous prepare pass that didn't have a renderer
+ if (info.renderer && mLayer->deferredUpdateScheduled) {
+ info.renderer->pushLayerUpdate(mLayer);
+ }
+}
+
void RenderNode::prepareTreeImpl(TreeInfo& info) {
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
evaluateAnimations(info);
} else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
} else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
+
+ prepareLayer(info);
+ if (info.mode == TreeInfo::MODE_FULL) {
+ pushStagingDisplayListChanges(info);
+ }
prepareSubTree(info, mDisplayListData);
+ pushLayerUpdate(info);
+
info.damageAccumulator->popTransform();
}
@@ -152,7 +211,7 @@ private:
TreeInfo& mInfo;
};
-void RenderNode::pushStagingChanges(TreeInfo& info) {
+void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
@@ -170,6 +229,7 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
damageSelf(info);
info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
+ applyLayerPropertiesToLayer(info);
// We could try to be clever and only re-damage if the matrix changed.
// However, we don't need to worry about that. The cost of over-damaging
// here is only going to be a single additional map rect of this node
@@ -178,6 +238,18 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
+}
+
+void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
+ if (CC_LIKELY(!mLayer)) return;
+
+ const LayerProperties& props = properties().layerProperties();
+ mLayer->setAlpha(props.alpha(), props.xferMode());
+ mLayer->setColorFilter(props.colorFilter());
+ mLayer->setBlend(props.needsBlending());
+}
+
+void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -274,9 +346,10 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
renderer.concatMatrix(*properties().getTransformMatrix());
}
}
- bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds();
+ const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+ bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
if (properties().getAlpha() < 1) {
- if (properties().getCaching()) {
+ if (isLayer) {
renderer.setOverrideLayerAlpha(properties().getAlpha());
} else if (!properties().getHasOverlappingRendering()) {
renderer.scaleAlpha(properties().getAlpha());
@@ -691,8 +764,14 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
*/
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+ const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+ // If we are updating the contents of mLayer, we don't want to apply any of
+ // the RenderNode's properties to this issueOperations pass. Those will all
+ // be applied when the layer is drawn, aka when this is true.
+ const bool useViewProperties = (!mLayer || drawLayer);
+
const int level = handler.level();
- if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
+ if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
@@ -714,7 +793,9 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
- setViewProperties<T>(renderer, handler);
+ if (useViewProperties) {
+ setViewProperties<T>(renderer, handler);
+ }
bool quickRejected = properties().getClipToBounds()
&& renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -723,31 +804,36 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
}
- Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
- buildZSortedChildList(zTranslatedNodes);
-
- // for 3d root, draw children with negative z values
- issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
-
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
-
-#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
-#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCountOffset, properties().getClipToBounds());
-
- if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
- issueOperationsOfProjectedChildren(renderer, handler);
+ if (drawLayer) {
+ handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ renderer.getSaveCount() - 1, properties().getClipToBounds());
+ } else {
+ Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+ buildZSortedChildList(zTranslatedNodes);
+
+ // for 3d root, draw children with negative z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
+
+ #if DEBUG_DISPLAY_LIST
+ op->output(level + 1);
+ #endif
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, properties().getClipToBounds());
+
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+ issueOperationsOfProjectedChildren(renderer, handler);
+ }
}
- }
- // for 3d root, draw children with positive z values
- issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ // for 3d root, draw children with positive z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ }
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index f0f6e7c..b2fe849 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -254,9 +254,13 @@ private:
};
void prepareTreeImpl(TreeInfo& info);
- void pushStagingChanges(TreeInfo& info);
+ void pushStagingPropertiesChanges(TreeInfo& info);
+ void pushStagingDisplayListChanges(TreeInfo& info);
void evaluateAnimations(TreeInfo& info);
void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+ void applyLayerPropertiesToLayer(TreeInfo& info);
+ void prepareLayer(TreeInfo& info);
+ void pushLayerUpdate(TreeInfo& info);
String8 mName;
@@ -272,6 +276,10 @@ private:
std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
+ // being in ~RenderNode() which may happen on any thread.
+ Layer* mLayer;
+
/**
* Draw time state - these properties are only set and used during rendering
*/
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 5f7d4e3..8848b2f 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -21,16 +21,59 @@
#include <utils/Trace.h>
#include <SkCanvas.h>
+#include <SkColorFilter.h>
#include <SkMatrix.h>
#include <SkPath.h>
#include <SkPathOps.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
+LayerProperties::LayerProperties()
+ : mType(kLayerTypeNone)
+ , mColorFilter(NULL) {
+ reset();
+}
+
+LayerProperties::~LayerProperties() {
+ setType(kLayerTypeNone);
+}
+
+void LayerProperties::reset() {
+ mOpaque = false;
+ setFromPaint(NULL);
+}
+
+bool LayerProperties::setColorFilter(SkColorFilter* filter) {
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
+}
+
+bool LayerProperties::setFromPaint(const SkPaint* paint) {
+ bool changed = false;
+ SkXfermode::Mode mode;
+ int alpha;
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ changed |= setAlpha(static_cast<uint8_t>(alpha));
+ changed |= setXferMode(mode);
+ changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+ return changed;
+}
+
+LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
+ setType(other.type());
+ setOpaque(other.opaque());
+ setAlpha(other.alpha());
+ setXferMode(other.xferMode());
+ setColorFilter(other.colorFilter());
+ return *this;
+}
+
RenderProperties::PrimitiveFields::PrimitiveFields()
: mClipToBounds(true)
, mProjectBackwards(false)
@@ -45,8 +88,7 @@ RenderProperties::PrimitiveFields::PrimitiveFields()
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
, mPivotExplicitlySet(false)
- , mMatrixOrPivotDirty(false)
- , mCaching(false) {
+ , mMatrixOrPivotDirty(false) {
}
RenderProperties::ComputedFields::ComputedFields()
@@ -73,6 +115,7 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
setStaticMatrix(other.getStaticMatrix());
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
+ mLayerProperties = other.layerProperties();
// Force recalculation of the matrix, since other's dirty bit may be clear
mPrimitiveFields.mMatrixOrPivotDirty = true;
@@ -103,9 +146,9 @@ void RenderProperties::debugOutputProperties(const int level) const {
}
}
- bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
+ bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
if (mPrimitiveFields.mAlpha < 1) {
- if (mPrimitiveFields.mCaching) {
+ if (layerProperties().type() != kLayerTypeNone) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
} else if (!mPrimitiveFields.mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index b012fc5..8c6cc9e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -32,6 +32,7 @@
#include "Outline.h"
class SkBitmap;
+class SkColorFilter;
class SkPaint;
namespace android {
@@ -39,15 +40,95 @@ namespace uirenderer {
class Matrix4;
class RenderNode;
+class RenderProperties;
// The __VA_ARGS__ will be executed if a & b are not equal
#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
+// Keep in sync with View.java:LAYER_TYPE_*
+enum LayerType {
+ kLayerTypeNone = 0,
+ // Although we cannot build the software layer directly (must be done at
+ // record time), this information is used when applying alpha.
+ kLayerTypeSoftware = 1,
+ kLayerTypeRenderLayer = 2,
+ // TODO: LayerTypeSurfaceTexture? Maybe?
+};
+
+class ANDROID_API LayerProperties {
+public:
+ bool setType(LayerType type) {
+ if (RP_SET(mType, type)) {
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ LayerType type() const {
+ return mType;
+ }
+
+ bool setOpaque(bool opaque) {
+ return RP_SET(mOpaque, opaque);
+ }
+
+ bool opaque() const {
+ return mOpaque;
+ }
+
+ bool setAlpha(uint8_t alpha) {
+ return RP_SET(mAlpha, alpha);
+ }
+
+ uint8_t alpha() const {
+ return mAlpha;
+ }
+
+ bool setXferMode(SkXfermode::Mode mode) {
+ return RP_SET(mMode, mode);
+ }
+
+ SkXfermode::Mode xferMode() const {
+ return mMode;
+ }
+
+ bool setColorFilter(SkColorFilter* filter);
+
+ SkColorFilter* colorFilter() const {
+ return mColorFilter;
+ }
+
+ // Sets alpha, xfermode, and colorfilter from an SkPaint
+ // paint may be NULL, in which case defaults will be set
+ bool setFromPaint(const SkPaint* paint);
+
+ bool needsBlending() const {
+ return !opaque() || alpha() < 255;
+ }
+
+ LayerProperties& operator=(const LayerProperties& other);
+
+private:
+ LayerProperties();
+ ~LayerProperties();
+ void reset();
+
+ friend class RenderProperties;
+
+ LayerType mType;
+ // Whether or not that Layer's content is opaque, doesn't include alpha
+ bool mOpaque;
+ uint8_t mAlpha;
+ SkXfermode::Mode mMode;
+ SkColorFilter* mColorFilter;
+};
+
/*
* Data structure that holds the properties for a RenderNode
*/
-class RenderProperties {
+class ANDROID_API RenderProperties {
public:
RenderProperties();
virtual ~RenderProperties();
@@ -366,10 +447,6 @@ public:
return false;
}
- bool setCaching(bool caching) {
- return RP_SET(mPrimitiveFields.mCaching, caching);
- }
-
int getWidth() const {
return mPrimitiveFields.mWidth;
}
@@ -396,10 +473,6 @@ public:
return mComputedFields.mTransformMatrix;
}
- bool getCaching() const {
- return mPrimitiveFields.mCaching;
- }
-
bool getClipToBounds() const {
return mPrimitiveFields.mClipToBounds;
}
@@ -422,7 +495,7 @@ public:
void debugOutputProperties(const int level) const;
- ANDROID_API void updateMatrix();
+ void updateMatrix();
bool hasClippingPath() const {
return mPrimitiveFields.mRevealClip.willClip();
@@ -445,6 +518,14 @@ public:
return mPrimitiveFields.mRevealClip;
}
+ const LayerProperties& layerProperties() const {
+ return mLayerProperties;
+ }
+
+ LayerProperties& mutateLayerProperties() {
+ return mLayerProperties;
+ }
+
private:
// Rendering properties
@@ -467,11 +548,11 @@ private:
int mWidth, mHeight;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
- bool mCaching;
} mPrimitiveFields;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ LayerProperties mLayerProperties;
/**
* These fields are all generated from other properties and are not set directly.
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fd78f8e..0fc0cef 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -26,6 +26,7 @@ namespace uirenderer {
class BaseRenderNodeAnimator;
class AnimationListener;
+class OpenGLRenderer;
class AnimationHook {
public:
@@ -63,6 +64,7 @@ public:
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
, damageAccumulator(NullDamageAccumulator::instance())
+ , renderer(0)
{}
const TraversalMode mode;
@@ -73,6 +75,9 @@ public:
bool prepareTextures;
// Must not be null
IDamageAccumulator* damageAccumulator;
+ // The renderer that will be drawing the next frame. Use this to push any
+ // layer updates or similar. May be NULL.
+ OpenGLRenderer* renderer;
struct Out {
Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8a5c857..440f965 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,7 @@ void CanvasContext::prepareTree(TreeInfo& info) {
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
+ info.renderer = mCanvas;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index bdfdd21..797566f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,9 +130,6 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
mContext->processLayerUpdate(mLayers[i].get(), info);
}
mLayers.clear();
- if (info.out.hasAnimations) {
- // TODO: Uh... crap?
- }
mContext->prepareTree(info);
if (info.out.hasAnimations) {