summaryrefslogtreecommitdiffstats
path: root/libs/hwui
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2014-06-11 18:39:44 -0700
committerJohn Reck <jreck@google.com>2014-06-12 09:13:45 -0700
commita447d29c65fb811cd184775a3476101a1cede929 (patch)
tree0be082c0fdf19035551bf3671208fd606b430ab2 /libs/hwui
parentf8333cc38126c7efb1b95958ca7d7c825253bc58 (diff)
downloadframeworks_base-a447d29c65fb811cd184775a3476101a1cede929.zip
frameworks_base-a447d29c65fb811cd184775a3476101a1cede929.tar.gz
frameworks_base-a447d29c65fb811cd184775a3476101a1cede929.tar.bz2
Fix DA bugs
* Now aware of transform of DrawDisplayListOp * Supports projection Bug: 15539677 Bug: 15506680 Change-Id: Ic16f482cd48c3add12e49eca529281be12b93491
Diffstat (limited to 'libs/hwui')
-rw-r--r--libs/hwui/DamageAccumulator.cpp149
-rw-r--r--libs/hwui/DamageAccumulator.h48
-rw-r--r--libs/hwui/Matrix.cpp2
-rw-r--r--libs/hwui/Matrix.h1
-rw-r--r--libs/hwui/RenderNode.cpp40
-rw-r--r--libs/hwui/RenderNode.h5
-rw-r--r--libs/hwui/RenderProperties.cpp1
-rw-r--r--libs/hwui/RenderProperties.h17
-rw-r--r--libs/hwui/TreeInfo.h7
9 files changed, 194 insertions, 76 deletions
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 8aa8c92..898e81a 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -26,8 +26,23 @@
namespace android {
namespace uirenderer {
+NullDamageAccumulator NullDamageAccumulator::sInstance;
+
+NullDamageAccumulator* NullDamageAccumulator::instance() {
+ return &sInstance;
+}
+
+enum TransformType {
+ TransformRenderNode,
+ TransformMatrix4,
+};
+
struct DirtyStack {
- const RenderNode* node;
+ TransformType type;
+ union {
+ const RenderNode* renderNode;
+ const Matrix4* matrix4;
+ };
// When this frame is pop'd, this rect is mapped through the above transform
// and applied to the previous (aka parent) frame
SkRect pendingDirty;
@@ -42,7 +57,7 @@ DamageAccumulator::DamageAccumulator() {
mHead->prev = mHead;
}
-void DamageAccumulator::pushNode(const RenderNode* node) {
+void DamageAccumulator::pushCommon() {
if (!mHead->next) {
DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
nextFrame->next = 0;
@@ -50,42 +65,120 @@ void DamageAccumulator::pushNode(const RenderNode* node) {
mHead->next = nextFrame;
}
mHead = mHead->next;
- mHead->node = node;
mHead->pendingDirty.setEmpty();
}
-void DamageAccumulator::popNode() {
+void DamageAccumulator::pushTransform(const RenderNode* transform) {
+ pushCommon();
+ mHead->type = TransformRenderNode;
+ mHead->renderNode = transform;
+}
+
+void DamageAccumulator::pushTransform(const Matrix4* transform) {
+ pushCommon();
+ mHead->type = TransformMatrix4;
+ mHead->matrix4 = transform;
+}
+
+void DamageAccumulator::popTransform() {
LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
- if (!dirtyFrame->pendingDirty.isEmpty()) {
- SkRect mappedDirty;
- const RenderProperties& props = dirtyFrame->node->properties();
- const SkMatrix* transform = props.getTransformMatrix();
- if (transform && !transform->isIdentity()) {
- transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
- } else {
- mappedDirty = dirtyFrame->pendingDirty;
+ if (dirtyFrame->type == TransformRenderNode) {
+ applyRenderNodeTransform(dirtyFrame);
+ } else {
+ applyMatrix4Transform(dirtyFrame);
+ }
+}
+
+static inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ Rect temp(in);
+ matrix->mapRect(temp);
+ out->join(RECT_ARGS(temp));
+}
+
+void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
+ mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
+}
+
+static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ const SkMatrix* transform = props.getTransformMatrix();
+ SkRect temp(in);
+ if (transform && !transform->isIdentity()) {
+ transform->mapRect(&temp);
+ }
+ temp.offset(props.getLeft(), props.getTop());
+ out->join(temp);
+}
+
+static DirtyStack* findParentRenderNode(DirtyStack* frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode) {
+ return frame;
}
- if (CC_LIKELY(mHead->node)) {
- const RenderProperties& parentProps = mHead->node->properties();
- mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
- props.getTop() - parentProps.getScrollY());
- if (props.getClipToBounds()) {
- if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
- mappedDirty.setEmpty();
- }
- }
- if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
- // TODO: Can we better bound the shadow damage area? For now
- // match the old damageShadowReceiver() path and just dirty
- // the entire parent bounds
- mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());
+ }
+ return NULL;
+}
+
+static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
+ if (frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode
+ && frame->renderNode->hasProjectionReceiver()) {
+ return frame;
}
+ }
+ }
+ return NULL;
+}
+
+static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
+ SkRect* rect = &frame->pendingDirty;
+ while (frame != end) {
+ if (frame->type == TransformRenderNode) {
+ mapRect(frame->renderNode->properties(), *rect, rect);
+ } else {
+ mapRect(frame->matrix4, *rect, rect);
+ }
+ frame = frame->prev;
+ }
+}
+
+void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
+ if (frame->pendingDirty.isEmpty()) {
+ return;
+ }
+
+ const RenderProperties& props = frame->renderNode->properties();
+
+ // Perform clipping
+ if (props.getClipToBounds() && !frame->pendingDirty.isEmpty()) {
+ if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
+ frame->pendingDirty.setEmpty();
+ }
+ }
+
+ // apply all transforms
+ mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
+
+ // project backwards if necessary
+ if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
+ // First, find our parent RenderNode:
+ DirtyStack* parentNode = findParentRenderNode(frame);
+ // Find our parent's projection receiver, which is what we project onto
+ DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
+ if (projectionReceiver) {
+ applyTransforms(frame, projectionReceiver);
+ projectionReceiver->pendingDirty.join(frame->pendingDirty);
} else {
- mappedDirty.offset(props.getLeft(), props.getTop());
+ ALOGW("Failed to find projection receiver? Dropping on the floor...");
}
- dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);
+
+ frame->pendingDirty.setEmpty();
}
}
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index c62a351..2ca30d4 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -16,6 +16,7 @@
#ifndef DAMAGEACCUMULATOR_H
#define DAMAGEACCUMULATOR_H
+#include <cutils/compiler.h>
#include <utils/LinearAllocator.h>
#include <SkMatrix.h>
@@ -28,8 +29,19 @@ namespace uirenderer {
struct DirtyStack;
class RenderNode;
+class Matrix4;
-class DamageAccumulator {
+class IDamageAccumulator {
+public:
+ virtual void pushTransform(const RenderNode* transform) = 0;
+ virtual void pushTransform(const Matrix4* transform) = 0;
+ virtual void popTransform() = 0;
+ virtual void dirty(float left, float top, float right, float bottom) = 0;
+protected:
+ virtual ~IDamageAccumulator() {}
+};
+
+class DamageAccumulator : public IDamageAccumulator {
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
public:
DamageAccumulator();
@@ -37,20 +49,44 @@ public:
// Push a transform node onto the stack. This should be called prior
// to any dirty() calls. Subsequent calls to dirty()
- // will be affected by the node's transform when popNode() is called.
- void pushNode(const RenderNode* node);
+ // will be affected by the transform when popTransform() is called.
+ virtual void pushTransform(const RenderNode* transform);
+ virtual void pushTransform(const Matrix4* transform);
+
// Pops a transform node from the stack, propagating the dirty rect
- // up to the parent node.
- void popNode();
- void dirty(float left, float top, float right, float bottom);
+ // up to the parent node. Returns the IDamageTransform that was just applied
+ virtual void popTransform();
+
+ virtual void dirty(float left, float top, float right, float bottom);
void finish(SkRect* totalDirty);
private:
+ void pushCommon();
+ void applyMatrix4Transform(DirtyStack* frame);
+ void applyRenderNodeTransform(DirtyStack* frame);
+
LinearAllocator mAllocator;
DirtyStack* mHead;
};
+class NullDamageAccumulator : public IDamageAccumulator {
+ PREVENT_COPY_AND_ASSIGN(NullDamageAccumulator);
+public:
+ virtual void pushTransform(const RenderNode* transform) { }
+ virtual void pushTransform(const Matrix4* transform) { }
+ virtual void popTransform() { }
+ virtual void dirty(float left, float top, float right, float bottom) { }
+
+ ANDROID_API static NullDamageAccumulator* instance();
+
+private:
+ NullDamageAccumulator() {}
+ ~NullDamageAccumulator() {}
+
+ static NullDamageAccumulator sInstance;
+};
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 2268386..9f2014f 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -417,6 +417,8 @@ void Matrix4::mapPoint(float& x, float& y) const {
}
void Matrix4::mapRect(Rect& r) const {
+ if (isIdentity()) return;
+
if (isSimple()) {
MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index e33a001..1c5c578 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -147,6 +147,7 @@ public:
data[kTranslateX] += x;
data[kTranslateY] += y;
data[kTranslateZ] += z;
+ mType |= kTypeUnknown;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c2f6df8..83ad76f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -15,6 +15,7 @@
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
+#define LOG_TAG "RenderNode"
#include "RenderNode.h"
@@ -111,26 +112,20 @@ void RenderNode::prepareTree(TreeInfo& info) {
prepareTreeImpl(info);
}
-static inline void pushNode(RenderNode* self, TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->pushNode(self);
- }
-}
-
-static inline void popNode(TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->popNode();
- }
-}
-
void RenderNode::damageSelf(TreeInfo& info) {
- if (info.damageAccumulator && isRenderable() && properties().getAlpha() > 0) {
- info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ if (isRenderable() && properties().getAlpha() > 0) {
+ if (properties().getClipToBounds()) {
+ info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ } else {
+ // Hope this is big enough?
+ // TODO: Get this from the display list ops or something
+ info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX);
+ }
}
}
void RenderNode::prepareTreeImpl(TreeInfo& info) {
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingChanges(info);
evaluateAnimations(info);
@@ -140,7 +135,7 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
evaluateAnimations(info);
}
prepareSubTree(info, mDisplayListData);
- popNode(info);
+ info.damageAccumulator->popTransform();
}
class PushAnimatorsFunctor {
@@ -173,14 +168,14 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
- pushNode(this, 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
// plus a rect join(). The parent's transform (and up) will only be
// performed once.
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
if (mNeedsDisplayListDataSync) {
@@ -217,7 +212,7 @@ void RenderNode::evaluateAnimations(TreeInfo& info) {
// property push and just damage self before and after animators are run
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
@@ -226,7 +221,7 @@ void RenderNode::evaluateAnimations(TreeInfo& info) {
mProperties.updateMatrix();
info.out.hasAnimations |= mAnimators.size();
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
@@ -243,8 +238,11 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}
for (size_t i = 0; i < subtree->children().size(); i++) {
- RenderNode* childNode = subtree->children()[i]->mDisplayList;
+ DrawDisplayListOp* op = subtree->children()[i];
+ RenderNode* childNode = op->mDisplayList;
+ info.damageAccumulator->pushTransform(&op->mTransformFromParent);
childNode->prepareTreeImpl(info);
+ info.damageAccumulator->popTransform();
}
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 393d4ea..f0f6e7c 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -39,6 +39,7 @@
#include <androidfw/ResourceTypes.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "Matrix.h"
#include "DeferredDisplayList.h"
@@ -125,6 +126,10 @@ public:
return mDisplayListData && mDisplayListData->hasDrawOps;
}
+ bool hasProjectionReceiver() const {
+ return mDisplayListData && mDisplayListData->projectionReceiveIndex >= 0;
+ }
+
const char* getName() const {
return mName.string();
}
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 6163df5..5f7d4e3 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -44,7 +44,6 @@ RenderProperties::PrimitiveFields::PrimitiveFields()
, mPivotX(0), mPivotY(0)
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
- , mScrollX(0), mScrollY(0)
, mPivotExplicitlySet(false)
, mMatrixOrPivotDirty(false)
, mCaching(false) {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c294f38..b012fc5 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -366,22 +366,6 @@ public:
return false;
}
- bool setScrollX(int scrollX) {
- return RP_SET(mPrimitiveFields.mScrollX, scrollX);
- }
-
- bool setScrollY(int scrollY) {
- return RP_SET(mPrimitiveFields.mScrollY, scrollY);
- }
-
- int getScrollX() const {
- return mPrimitiveFields.mScrollX;
- }
-
- int getScrollY() const {
- return mPrimitiveFields.mScrollY;
- }
-
bool setCaching(bool caching) {
return RP_SET(mPrimitiveFields.mCaching, caching);
}
@@ -481,7 +465,6 @@ private:
float mPivotX, mPivotY;
int mLeft, mTop, mRight, mBottom;
int mWidth, mHeight;
- int mScrollX, mScrollY;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
bool mCaching;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 2096f98..fd78f8e 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,6 +18,7 @@
#include <utils/Timers.h>
+#include "DamageAccumulator.h"
#include "utils/Macros.h"
namespace android {
@@ -25,7 +26,6 @@ namespace uirenderer {
class BaseRenderNodeAnimator;
class AnimationListener;
-class DamageAccumulator;
class AnimationHook {
public:
@@ -62,7 +62,7 @@ public:
, frameTimeMs(0)
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
- , damageAccumulator(0)
+ , damageAccumulator(NullDamageAccumulator::instance())
{}
const TraversalMode mode;
@@ -71,7 +71,8 @@ public:
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
- DamageAccumulator* damageAccumulator;
+ // Must not be null
+ IDamageAccumulator* damageAccumulator;
struct Out {
Out()