summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk12
-rw-r--r--libs/hwui/Animator.h2
-rw-r--r--libs/hwui/DamageAccumulator.cpp198
-rw-r--r--libs/hwui/DamageAccumulator.h93
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp4
-rw-r--r--libs/hwui/DisplayList.cpp5
-rw-r--r--libs/hwui/DisplayList.h1
-rw-r--r--libs/hwui/DisplayListOp.h38
-rw-r--r--libs/hwui/DisplayListRenderer.cpp9
-rw-r--r--libs/hwui/DisplayListRenderer.h17
-rw-r--r--libs/hwui/DrawProfiler.cpp2
-rw-r--r--libs/hwui/DrawProfiler.h2
-rw-r--r--libs/hwui/FontRenderer.cpp24
-rw-r--r--libs/hwui/FontRenderer.h4
-rw-r--r--libs/hwui/Matrix.cpp2
-rw-r--r--libs/hwui/Matrix.h1
-rw-r--r--libs/hwui/OpenGLRenderer.cpp4
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/PathCache.cpp4
-rw-r--r--libs/hwui/PathCache.h5
-rw-r--r--libs/hwui/RenderNode.cpp56
-rw-r--r--libs/hwui/RenderNode.h10
-rw-r--r--libs/hwui/RenderProperties.h205
-rw-r--r--libs/hwui/Renderer.h6
-rw-r--r--libs/hwui/StatefulBaseRenderer.cpp12
-rw-r--r--libs/hwui/StatefulBaseRenderer.h4
-rw-r--r--libs/hwui/TreeInfo.h45
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp26
-rw-r--r--libs/hwui/renderthread/CanvasContext.h4
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp19
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp5
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/utils/Blur.cpp12
-rw-r--r--libs/hwui/utils/Blur.h6
35 files changed, 591 insertions, 252 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 900a72e71373..02e85fe534ac 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -14,6 +14,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
AmbientShadow.cpp \
Animator.cpp \
AssetAtlas.cpp \
+ DamageAccumulator.cpp \
FontRenderer.cpp \
GammaFontRenderer.cpp \
Caches.cpp \
@@ -72,8 +73,6 @@ ifeq ($(USE_OPENGL_RENDERER),true)
$(LOCAL_PATH)/../../include/utils \
external/skia/src/core
- include external/stlport/libstlport.mk
-
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
@@ -81,16 +80,15 @@ ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_MODULE := libhwui
LOCAL_MODULE_TAGS := optional
+ include external/stlport/libstlport.mk
+
ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
- LOCAL_SHARED_LIBRARIES += libRS libRScpp libstlport
+ LOCAL_SHARED_LIBRARIES += libRS libRScpp
LOCAL_C_INCLUDES += \
$(intermediates) \
frameworks/rs/cpp \
- frameworks/rs \
- external/stlport/stlport \
- bionic/ \
- bionic/libstdc++/include
+ frameworks/rs
endif
ifndef HWUI_COMPILE_SYMBOLS
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index a0c7c554bda2..203cdffea433 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -117,7 +117,7 @@ protected:
virtual void setValue(RenderNode* target, float value);
private:
- typedef void (RenderProperties::*SetFloatProperty)(float value);
+ typedef bool (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
struct PropertyAccessors;
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
new file mode 100644
index 000000000000..898e81a1a822
--- /dev/null
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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 LOG_TAG "DamageAccumulator"
+
+#include "DamageAccumulator.h"
+
+#include <cutils/log.h>
+
+#include "RenderNode.h"
+#include "utils/MathUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+NullDamageAccumulator NullDamageAccumulator::sInstance;
+
+NullDamageAccumulator* NullDamageAccumulator::instance() {
+ return &sInstance;
+}
+
+enum TransformType {
+ TransformRenderNode,
+ TransformMatrix4,
+};
+
+struct DirtyStack {
+ 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;
+ DirtyStack* prev;
+ DirtyStack* next;
+};
+
+DamageAccumulator::DamageAccumulator() {
+ mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ memset(mHead, 0, sizeof(DirtyStack));
+ // Create a root that we will not pop off
+ mHead->prev = mHead;
+}
+
+void DamageAccumulator::pushCommon() {
+ if (!mHead->next) {
+ DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ nextFrame->next = 0;
+ nextFrame->prev = mHead;
+ mHead->next = nextFrame;
+ }
+ mHead = mHead->next;
+ mHead->pendingDirty.setEmpty();
+}
+
+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->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;
+ }
+ }
+ 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 {
+ ALOGW("Failed to find projection receiver? Dropping on the floor...");
+ }
+
+ frame->pendingDirty.setEmpty();
+ }
+}
+
+void DamageAccumulator::dirty(float left, float top, float right, float bottom) {
+ mHead->pendingDirty.join(left, top, right, bottom);
+}
+
+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
+ *totalDirty = mHead->pendingDirty;
+ totalDirty->roundOut();
+ mHead->pendingDirty.setEmpty();
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
new file mode 100644
index 000000000000..2ca30d481687
--- /dev/null
+++ b/libs/hwui/DamageAccumulator.h
@@ -0,0 +1,93 @@
+/*
+ * 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 DAMAGEACCUMULATOR_H
+#define DAMAGEACCUMULATOR_H
+
+#include <cutils/compiler.h>
+#include <utils/LinearAllocator.h>
+
+#include <SkMatrix.h>
+#include <SkRect.h>
+
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+struct DirtyStack;
+class RenderNode;
+class Matrix4;
+
+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();
+ // mAllocator will clean everything up for us, no need for a dtor
+
+ // 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 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. 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 */
+
+#endif /* DAMAGEACCUMULATOR_H */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 97e9bf627d65..d494c4c5a4e2 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -81,6 +81,10 @@ bool DeferredLayerUpdater::apply(TreeInfo& info) {
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);
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 96c6292a91e9..f418c9bf8f9a 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -80,10 +80,6 @@ void DisplayListData::cleanupResources() {
delete paths.itemAt(i);
}
- for (size_t i = 0; i < matrices.size(); i++) {
- delete matrices.itemAt(i);
- }
-
bitmapResources.clear();
ownedBitmapResources.clear();
patchResources.clear();
@@ -91,7 +87,6 @@ void DisplayListData::cleanupResources() {
paints.clear();
regions.clear();
paths.clear();
- matrices.clear();
layers.clear();
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 11e78b006311..7b7dc16daecb 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -125,7 +125,6 @@ public:
Vector<const SkPath*> paths;
SortedVector<const SkPath*> sourcePaths;
Vector<const SkRegion*> regions;
- Vector<const SkMatrix*> matrices;
Vector<Layer*> layers;
uint32_t functorCount;
bool hasDrawOps;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 3281116c2638..233f3f0a31b8 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -472,7 +472,7 @@ private:
class SetMatrixOp : public StateOp {
public:
- SetMatrixOp(const SkMatrix* matrix)
+ SetMatrixOp(const SkMatrix& matrix)
: mMatrix(matrix) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -480,22 +480,22 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- if (mMatrix) {
- OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
- } else {
+ if (mMatrix.isIdentity()) {
OP_LOGS("SetMatrix (reset)");
+ } else {
+ OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
}
}
virtual const char* name() { return "SetMatrix"; }
private:
- const SkMatrix* mMatrix;
+ const SkMatrix mMatrix;
};
class ConcatMatrixOp : public StateOp {
public:
- ConcatMatrixOp(const SkMatrix* matrix)
+ ConcatMatrixOp(const SkMatrix& matrix)
: mMatrix(matrix) {}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -503,13 +503,13 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
+ OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
}
virtual const char* name() { return "ConcatMatrix"; }
private:
- const SkMatrix* mMatrix;
+ const SkMatrix mMatrix;
};
class ClipOp : public StateOp {
@@ -746,10 +746,10 @@ protected:
class DrawBitmapMatrixOp : public DrawBoundedOp {
public:
- DrawBitmapMatrixOp(const SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint)
+ DrawBitmapMatrixOp(const SkBitmap* bitmap, const SkMatrix& matrix, const SkPaint* paint)
: DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
- const mat4 transform(*matrix);
+ const mat4 transform(matrix);
transform.mapRect(mLocalBounds);
}
@@ -758,7 +758,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(mMatrix));
+ OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(&mMatrix));
}
virtual const char* name() { return "DrawBitmapMatrix"; }
@@ -770,7 +770,7 @@ public:
private:
const SkBitmap* mBitmap;
- const SkMatrix* mMatrix;
+ const SkMatrix mMatrix;
};
class DrawBitmapRectOp : public DrawBoundedOp {
@@ -788,7 +788,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
+ OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING,
mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
}
@@ -978,7 +978,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw patch " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawPatch"; }
@@ -1060,7 +1060,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
@@ -1111,7 +1111,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
+ OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
@@ -1184,7 +1184,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawOval"; }
@@ -1204,7 +1204,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
+ OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d",
RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
}
@@ -1241,7 +1241,7 @@ public:
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawPath"; }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 229afdfa89f2..0e47c6e2b92d 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -141,14 +141,12 @@ void DisplayListRenderer::skew(float sx, float sy) {
StatefulBaseRenderer::skew(sx, sy);
}
-void DisplayListRenderer::setMatrix(const SkMatrix* matrix) {
- matrix = refMatrix(matrix);
+void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
addStateOp(new (alloc()) SetMatrixOp(matrix));
StatefulBaseRenderer::setMatrix(matrix);
}
-void DisplayListRenderer::concatMatrix(const SkMatrix* matrix) {
- matrix = refMatrix(matrix);
+void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
addStateOp(new (alloc()) ConcatMatrixOp(matrix));
StatefulBaseRenderer::concatMatrix(matrix);
}
@@ -203,10 +201,9 @@ status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float left, flo
return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
+status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
bitmap = refBitmap(bitmap);
- matrix = refMatrix(matrix);
paint = refPaint(paint);
addDrawOp(new (alloc()) DrawBitmapMatrixOp(bitmap, matrix, paint));
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index dff4f6c54d7e..2eaa671b6226 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -86,8 +86,8 @@ public:
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
- virtual void setMatrix(const SkMatrix* matrix);
- virtual void concatMatrix(const SkMatrix* matrix);
+ virtual void setMatrix(const SkMatrix& matrix);
+ virtual void concatMatrix(const SkMatrix& matrix);
// Clip
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
@@ -106,7 +106,7 @@ public:
// Bitmap-based
virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
const SkPaint* paint);
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
+ virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
const SkPaint* paint);
virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
@@ -238,17 +238,6 @@ private:
return regionCopy;
}
- inline const SkMatrix* refMatrix(const SkMatrix* matrix) {
- if (matrix) {
- // Copying the matrix is cheap and prevents against the user changing
- // the original matrix before the operation that uses it
- const SkMatrix* copy = new SkMatrix(*matrix);
- mDisplayListData->matrices.add(copy);
- return copy;
- }
- return matrix;
- }
-
inline Layer* refLayer(Layer* layer) {
mDisplayListData->layers.add(layer);
mCaches.resourceCache.incrementRefcount(layer);
diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp
index 971a66eebe0e..2409554e14b0 100644
--- a/libs/hwui/DrawProfiler.cpp
+++ b/libs/hwui/DrawProfiler.cpp
@@ -109,7 +109,7 @@ void DrawProfiler::finishFrame() {
mCurrentFrame = (mCurrentFrame + 1) % mDataSize;
}
-void DrawProfiler::unionDirty(Rect* dirty) {
+void DrawProfiler::unionDirty(SkRect* dirty) {
RETURN_IF_DISABLED();
// Not worth worrying about minimizing the dirty region for debugging, so just
// dirty the entire viewport.
diff --git a/libs/hwui/DrawProfiler.h b/libs/hwui/DrawProfiler.h
index c1aa1c6e71b8..7c06e5dd111a 100644
--- a/libs/hwui/DrawProfiler.h
+++ b/libs/hwui/DrawProfiler.h
@@ -37,7 +37,7 @@ public:
void markPlaybackEnd();
void finishFrame();
- void unionDirty(Rect* dirty);
+ void unionDirty(SkRect* dirty);
void draw(OpenGLRenderer* canvas);
void dumpData(int fd);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 4407ab0d3f14..bf0ab5cae7d7 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -592,7 +592,7 @@ void FontRenderer::setFont(const SkPaint* paint, const mat4& matrix) {
}
FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
- uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
+ uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
checkInit();
DropShadow image;
@@ -613,8 +613,9 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
Rect bounds;
mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
- uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
- uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
+ uint32_t intRadius = Blur::convertRadiusToInt(radius);
+ uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
+ uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
uint32_t maxSize = Caches::getInstance().maxTextureSize;
if (paddedWidth > maxSize || paddedHeight > maxSize) {
@@ -635,8 +636,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
memset(dataBuffer, 0, size);
- int penX = radius - bounds.left;
- int penY = radius - bounds.bottom;
+ int penX = intRadius - bounds.left;
+ int penY = intRadius - bounds.bottom;
if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
// text has non-whitespace, so draw and blur to create the shadow
@@ -727,9 +728,10 @@ void FontRenderer::removeFont(const Font* font) {
}
}
-void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
+void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
+ uint32_t intRadius = Blur::convertRadiusToInt(radius);
#ifdef ANDROID_ENABLE_RENDERSCRIPT
- if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
+ if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
if (mRs == 0) {
@@ -768,12 +770,12 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int
}
#endif
- float *gaussian = new float[2 * radius + 1];
- Blur::generateGaussianWeights(gaussian, radius);
+ float *gaussian = new float[2 * intRadius + 1];
+ Blur::generateGaussianWeights(gaussian, intRadius);
uint8_t* scratch = new uint8_t[width * height];
- Blur::horizontal(gaussian, radius, *image, scratch, width, height);
- Blur::vertical(gaussian, radius, scratch, *image, width, height);
+ Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
+ Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
delete[] gaussian;
delete[] scratch;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 92590287374f..8ce22b07d7b6 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -129,7 +129,7 @@ public:
// After renderDropShadow returns, the called owns the memory in DropShadow.image
// and is responsible for releasing it when it's done with it
DropShadow renderDropShadow(const SkPaint* paint, const char *text, uint32_t startIndex,
- uint32_t len, int numGlyphs, uint32_t radius, const float* positions);
+ uint32_t len, int numGlyphs, float radius, const float* positions);
void setTextureFiltering(bool linearFiltering) {
mLinearFiltering = linearFiltering;
@@ -218,7 +218,7 @@ private:
int32_t width, int32_t height);
// the input image handle may have its pointer replaced (to avoid copies)
- void blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius);
+ void blurImage(uint8_t** image, int32_t width, int32_t height, float radius);
};
}; // namespace uirenderer
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 22683865c7a6..9f2014f89f46 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 e33a0013a929..1c5c5783bde9 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/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 31f399a1f72a..8f3872a42a8b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2043,10 +2043,10 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float to
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
+status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
- const mat4 transform(*matrix);
+ const mat4 transform(matrix);
transform.mapRect(r);
if (quickRejectSetupScissor(r.left, r.top, r.right, r.bottom)) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b9b369fa226b..346a65cca007 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -164,7 +164,7 @@ public:
const SkPaint* paint);
status_t drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
+ virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
const SkPaint* paint);
virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index ab6b742f8f4f..9dd5aa514d3f 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -339,7 +339,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
float left, top, offset;
uint32_t width, height;
- PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height);
+ PathCache::computePathBounds(t->path, &t->paint, left, top, offset, width, height);
PathTexture* texture = t->texture;
texture->left = left;
@@ -350,7 +350,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
SkBitmap* bitmap = new SkBitmap();
- drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
+ drawPath(t->path, &t->paint, *bitmap, left, top, offset, width, height);
t->setResult(bitmap);
} else {
texture->width = 0;
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 6177ff1980a6..eee138b8fddf 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -272,7 +272,7 @@ private:
class PathTask: public Task<SkBitmap*> {
public:
PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
- path(path), paint(paint), texture(texture) {
+ path(path), paint(*paint), texture(texture) {
}
~PathTask() {
@@ -280,7 +280,8 @@ private:
}
const SkPath* path;
- const SkPaint* paint;
+ //copied, since input paint may not be immutable
+ const SkPaint paint;
PathTexture* texture;
};
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d964efc1c3e4..83ad76f02b4d 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"
@@ -25,6 +26,7 @@
#include <utils/Trace.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
@@ -110,14 +112,30 @@ void RenderNode::prepareTree(TreeInfo& info) {
prepareTreeImpl(info);
}
+void RenderNode::damageSelf(TreeInfo& info) {
+ 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) {
- if (info.performStagingPush) {
+ info.damageAccumulator->pushTransform(this);
+ if (info.mode == TreeInfo::MODE_FULL) {
pushStagingChanges(info);
- }
- if (info.evaluateAnimations) {
+ evaluateAnimations(info);
+ } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
+ pushStagingChanges(info);
+ } else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
prepareSubTree(info, mDisplayListData);
+ info.damageAccumulator->popTransform();
}
class PushAnimatorsFunctor {
@@ -149,18 +167,28 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
}
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
+ damageSelf(info);
+ info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
+ // 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) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
// that are no longer used
- TreeInfo oldTreeInfo;
+ TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING);
+ oldTreeInfo.damageAccumulator = info.damageAccumulator;
prepareSubTree(oldTreeInfo, mDisplayListData);
- // TODO: The damage for the old tree should be accounted for
delete mDisplayListData;
mDisplayListData = mStagingDisplayListData;
mStagingDisplayListData = 0;
+ damageSelf(info);
}
}
@@ -180,12 +208,21 @@ private:
void RenderNode::evaluateAnimations(TreeInfo& info) {
if (!mAnimators.size()) return;
+ // TODO: Can we target this better? For now treat it like any other staging
+ // property push and just damage self before and after animators are run
+
+ damageSelf(info);
+ info.damageAccumulator->popTransform();
+
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.erase(newEnd, mAnimators.end());
mProperties.updateMatrix();
info.out.hasAnimations |= mAnimators.size();
+
+ info.damageAccumulator->pushTransform(this);
+ damageSelf(info);
}
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
@@ -201,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();
}
}
}
@@ -223,9 +263,9 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
renderer.translate(properties().getLeft(), properties().getTop());
}
if (properties().getStaticMatrix()) {
- renderer.concatMatrix(properties().getStaticMatrix());
+ renderer.concatMatrix(*properties().getStaticMatrix());
} else if (properties().getAnimationMatrix()) {
- renderer.concatMatrix(properties().getAnimationMatrix());
+ renderer.concatMatrix(*properties().getAnimationMatrix());
}
if (properties().hasTransformMatrix()) {
if (properties().isTransformTranslateOnly()) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 1a5377b7dad8..f0f6e7c86c94 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();
}
@@ -148,7 +153,7 @@ public:
mDirtyPropertyFields |= fields;
}
- const RenderProperties& properties() {
+ const RenderProperties& properties() const {
return mProperties;
}
@@ -187,6 +192,9 @@ public:
mNeedsAnimatorsSync = true;
}
+protected:
+ virtual void damageSelf(TreeInfo& info);
+
private:
typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c0e3ce7dae49..b012fc5c0234 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -40,6 +40,10 @@ namespace uirenderer {
class Matrix4;
class RenderNode;
+// 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)
+
/*
* Data structure that holds the properties for a RenderNode
*/
@@ -50,29 +54,30 @@ public:
RenderProperties& operator=(const RenderProperties& other);
- void setClipToBounds(bool clipToBounds) {
- mPrimitiveFields.mClipToBounds = clipToBounds;
+ bool setClipToBounds(bool clipToBounds) {
+ return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds);
}
- void setProjectBackwards(bool shouldProject) {
- mPrimitiveFields.mProjectBackwards = shouldProject;
+ bool setProjectBackwards(bool shouldProject) {
+ return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject);
}
- void setProjectionReceiver(bool shouldRecieve) {
- mPrimitiveFields.mProjectionReceiver = shouldRecieve;
+ bool setProjectionReceiver(bool shouldRecieve) {
+ return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve);
}
bool isProjectionReceiver() const {
return mPrimitiveFields.mProjectionReceiver;
}
- void setStaticMatrix(const SkMatrix* matrix) {
+ bool setStaticMatrix(const SkMatrix* matrix) {
delete mStaticMatrix;
if (matrix) {
mStaticMatrix = new SkMatrix(*matrix);
} else {
mStaticMatrix = NULL;
}
+ return true;
}
// Can return NULL
@@ -80,72 +85,61 @@ public:
return mStaticMatrix;
}
- void setAnimationMatrix(const SkMatrix* matrix) {
+ bool setAnimationMatrix(const SkMatrix* matrix) {
delete mAnimationMatrix;
if (matrix) {
mAnimationMatrix = new SkMatrix(*matrix);
} else {
mAnimationMatrix = NULL;
}
+ return true;
}
- void setAlpha(float alpha) {
+ bool setAlpha(float alpha) {
alpha = fminf(1.0f, fmaxf(0.0f, alpha));
- if (alpha != mPrimitiveFields.mAlpha) {
- mPrimitiveFields.mAlpha = alpha;
- }
+ return RP_SET(mPrimitiveFields.mAlpha, alpha);
}
float getAlpha() const {
return mPrimitiveFields.mAlpha;
}
- void setHasOverlappingRendering(bool hasOverlappingRendering) {
- mPrimitiveFields.mHasOverlappingRendering = hasOverlappingRendering;
+ bool setHasOverlappingRendering(bool hasOverlappingRendering) {
+ return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering);
}
bool hasOverlappingRendering() const {
return mPrimitiveFields.mHasOverlappingRendering;
}
- void setElevation(float elevation) {
- if (elevation != mPrimitiveFields.mElevation) {
- mPrimitiveFields.mElevation = elevation;
- // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
- }
+ bool setElevation(float elevation) {
+ return RP_SET(mPrimitiveFields.mElevation, elevation);
+ // Don't dirty matrix/pivot, since they don't respect Z
}
float getElevation() const {
return mPrimitiveFields.mElevation;
}
- void setTranslationX(float translationX) {
- if (translationX != mPrimitiveFields.mTranslationX) {
- mPrimitiveFields.mTranslationX = translationX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setTranslationX(float translationX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX);
}
float getTranslationX() const {
return mPrimitiveFields.mTranslationX;
}
- void setTranslationY(float translationY) {
- if (translationY != mPrimitiveFields.mTranslationY) {
- mPrimitiveFields.mTranslationY = translationY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setTranslationY(float translationY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY);
}
float getTranslationY() const {
return mPrimitiveFields.mTranslationY;
}
- void setTranslationZ(float translationZ) {
- if (translationZ != mPrimitiveFields.mTranslationZ) {
- mPrimitiveFields.mTranslationZ = translationZ;
- // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
- }
+ bool setTranslationZ(float translationZ) {
+ return RP_SET(mPrimitiveFields.mTranslationZ, translationZ);
+ // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
}
float getTranslationZ() const {
@@ -153,8 +147,8 @@ public:
}
// Animation helper
- void setX(float value) {
- setTranslationX(value - getLeft());
+ bool setX(float value) {
+ return setTranslationX(value - getLeft());
}
// Animation helper
@@ -163,8 +157,8 @@ public:
}
// Animation helper
- void setY(float value) {
- setTranslationY(value - getTop());
+ bool setY(float value) {
+ return setTranslationY(value - getTop());
}
// Animation helper
@@ -173,87 +167,80 @@ public:
}
// Animation helper
- void setZ(float value) {
- setTranslationZ(value - getElevation());
+ bool setZ(float value) {
+ return setTranslationZ(value - getElevation());
}
float getZ() const {
return getElevation() + getTranslationZ();
}
- void setRotation(float rotation) {
- if (rotation != mPrimitiveFields.mRotation) {
- mPrimitiveFields.mRotation = rotation;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotation(float rotation) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation);
}
float getRotation() const {
return mPrimitiveFields.mRotation;
}
- void setRotationX(float rotationX) {
- if (rotationX != mPrimitiveFields.mRotationX) {
- mPrimitiveFields.mRotationX = rotationX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotationX(float rotationX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX);
}
float getRotationX() const {
return mPrimitiveFields.mRotationX;
}
- void setRotationY(float rotationY) {
- if (rotationY != mPrimitiveFields.mRotationY) {
- mPrimitiveFields.mRotationY = rotationY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotationY(float rotationY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY);
}
float getRotationY() const {
return mPrimitiveFields.mRotationY;
}
- void setScaleX(float scaleX) {
- if (scaleX != mPrimitiveFields.mScaleX) {
- mPrimitiveFields.mScaleX = scaleX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setScaleX(float scaleX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
}
float getScaleX() const {
return mPrimitiveFields.mScaleX;
}
- void setScaleY(float scaleY) {
- if (scaleY != mPrimitiveFields.mScaleY) {
- mPrimitiveFields.mScaleY = scaleY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setScaleY(float scaleY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
}
float getScaleY() const {
return mPrimitiveFields.mScaleY;
}
- void setPivotX(float pivotX) {
- mPrimitiveFields.mPivotX = pivotX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- mPrimitiveFields.mPivotExplicitlySet = true;
+ bool setPivotX(float pivotX) {
+ if (RP_SET(mPrimitiveFields.mPivotX, pivotX)
+ || !mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
+ mPrimitiveFields.mPivotExplicitlySet = true;
+ return true;
+ }
+ return false;
}
/* Note that getPivotX and getPivotY are adjusted by updateMatrix(),
- * so the value returned mPrimitiveFields.may be stale if the RenderProperties has been
- * mPrimitiveFields.modified since the last call to updateMatrix()
+ * so the value returned may be stale if the RenderProperties has been
+ * modified since the last call to updateMatrix()
*/
float getPivotX() const {
return mPrimitiveFields.mPivotX;
}
- void setPivotY(float pivotY) {
- mPrimitiveFields.mPivotY = pivotY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- mPrimitiveFields.mPivotExplicitlySet = true;
+ bool setPivotY(float pivotY) {
+ if (RP_SET(mPrimitiveFields.mPivotY, pivotY)
+ || !mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
+ mPrimitiveFields.mPivotExplicitlySet = true;
+ return true;
+ }
+ return false;
}
float getPivotY() const {
@@ -264,11 +251,13 @@ public:
return mPrimitiveFields.mPivotExplicitlySet;
}
- void setCameraDistance(float distance) {
+ bool setCameraDistance(float distance) {
if (distance != getCameraDistance()) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
+ return true;
}
+ return false;
}
float getCameraDistance() const {
@@ -276,75 +265,73 @@ public:
return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ();
}
- void setLeft(int left) {
- if (left != mPrimitiveFields.mLeft) {
- mPrimitiveFields.mLeft = left;
+ bool setLeft(int left) {
+ if (RP_SET(mPrimitiveFields.mLeft, left)) {
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getLeft() const {
return mPrimitiveFields.mLeft;
}
- void setTop(int top) {
- if (top != mPrimitiveFields.mTop) {
- mPrimitiveFields.mTop = top;
+ bool setTop(int top) {
+ if (RP_SET(mPrimitiveFields.mTop, top)) {
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getTop() const {
return mPrimitiveFields.mTop;
}
- void setRight(int right) {
- if (right != mPrimitiveFields.mRight) {
- mPrimitiveFields.mRight = right;
+ bool setRight(int right) {
+ if (RP_SET(mPrimitiveFields.mRight, right)) {
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getRight() const {
return mPrimitiveFields.mRight;
}
- void setBottom(int bottom) {
- if (bottom != mPrimitiveFields.mBottom) {
- mPrimitiveFields.mBottom = bottom;
+ bool setBottom(int bottom) {
+ if (RP_SET(mPrimitiveFields.mBottom, bottom)) {
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getBottom() const {
return mPrimitiveFields.mBottom;
}
- void setLeftTop(int left, int top) {
- if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop) {
- mPrimitiveFields.mLeft = left;
- mPrimitiveFields.mTop = top;
- mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
- mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
- }
+ bool setLeftTop(int left, int top) {
+ bool leftResult = setLeft(left);
+ bool topResult = setTop(top);
+ return leftResult || topResult;
}
- void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+ bool setLeftTopRightBottom(int left, int top, int right, int bottom) {
if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
|| right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mLeft = left;
@@ -356,31 +343,31 @@ public:
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
- void offsetLeftRight(float offset) {
+ bool offsetLeftRight(float offset) {
if (offset != 0) {
mPrimitiveFields.mLeft += offset;
mPrimitiveFields.mRight += offset;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ return true;
}
+ return false;
}
- void offsetTopBottom(float offset) {
+ bool offsetTopBottom(float offset) {
if (offset != 0) {
mPrimitiveFields.mTop += offset;
mPrimitiveFields.mBottom += offset;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ return true;
}
+ return false;
}
- void setCaching(bool caching) {
- mPrimitiveFields.mCaching = caching;
+ bool setCaching(bool caching) {
+ return RP_SET(mPrimitiveFields.mCaching, caching);
}
int getWidth() const {
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 23cab0e969d4..320895c2605b 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -170,8 +170,8 @@ public:
virtual void scale(float sx, float sy) = 0;
virtual void skew(float sx, float sy) = 0;
- virtual void setMatrix(const SkMatrix* matrix) = 0;
- virtual void concatMatrix(const SkMatrix* matrix) = 0;
+ virtual void setMatrix(const SkMatrix& matrix) = 0;
+ virtual void concatMatrix(const SkMatrix& matrix) = 0;
// clip
virtual const Rect& getLocalClipBounds() const = 0;
@@ -193,7 +193,7 @@ public:
// Bitmap-based
virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top,
const SkPaint* paint) = 0;
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix* matrix,
+ virtual status_t drawBitmap(const SkBitmap* bitmap, const SkMatrix& matrix,
const SkPaint* paint) = 0;
virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index f2e28e1d83d5..95c0ee5745b9 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -125,20 +125,16 @@ void StatefulBaseRenderer::skew(float sx, float sy) {
mSnapshot->transform->skew(sx, sy);
}
-void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) {
- if (matrix) {
- mSnapshot->transform->load(*matrix);
- } else {
- mSnapshot->transform->loadIdentity();
- }
+void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
+ mSnapshot->transform->load(matrix);
}
void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
mSnapshot->transform->load(matrix);
}
-void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) {
- mat4 transform(*matrix);
+void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
+ mat4 transform(matrix);
mSnapshot->transform->multiply(transform);
}
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index dbb1d8547278..e8e024f342b0 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -76,9 +76,9 @@ public:
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
- virtual void setMatrix(const SkMatrix* matrix);
+ virtual void setMatrix(const SkMatrix& matrix);
void setMatrix(const Matrix4& matrix); // internal only convenience method
- virtual void concatMatrix(const SkMatrix* matrix);
+ virtual void concatMatrix(const SkMatrix& matrix);
void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 8355f83ea37c..fd78f8e3a4d6 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,6 +18,9 @@
#include <utils/Timers.h>
+#include "DamageAccumulator.h"
+#include "utils/Macros.h"
+
namespace android {
namespace uirenderer {
@@ -31,21 +34,45 @@ protected:
~AnimationHook() {}
};
-struct TreeInfo {
- // The defaults here should be safe for everyone but DrawFrameTask to use as-is.
- TreeInfo()
- : frameTimeMs(0)
+// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
+class TreeInfo {
+ PREVENT_COPY_AND_ASSIGN(TreeInfo);
+public:
+ enum TraversalMode {
+ // The full monty - sync, push, run animators, etc... Used by DrawFrameTask
+ // May only be used if both the UI thread and RT thread are blocked on the
+ // prepare
+ MODE_FULL,
+ // Run only what can be done safely on RT thread. Currently this only means
+ // animators, but potentially things like SurfaceTexture updates
+ // could be handled by this as well if there are no listeners
+ MODE_RT_ONLY,
+ // The subtree is being detached. Maybe. If the RenderNode is present
+ // in both the old and new display list's children then it will get a
+ // MODE_MAYBE_DETACHING followed shortly by a MODE_FULL.
+ // Push any pending display list changes in case it is detached,
+ // but don't evaluate animators and such as if it isn't detached as a
+ // MODE_FULL will follow shortly.
+ MODE_MAYBE_DETACHING,
+ // TODO: TRIM_MEMORY?
+ };
+
+ explicit TreeInfo(TraversalMode mode)
+ : mode(mode)
+ , frameTimeMs(0)
, animationHook(NULL)
- , prepareTextures(false)
- , performStagingPush(true)
- , evaluateAnimations(false)
+ , prepareTextures(mode == MODE_FULL)
+ , damageAccumulator(NullDamageAccumulator::instance())
{}
+ const TraversalMode mode;
nsecs_t frameTimeMs;
AnimationHook* animationHook;
+ // TODO: Remove this? Currently this is used to signal to stop preparing
+ // textures if we run out of cache space.
bool prepareTextures;
- bool performStagingPush;
- bool evaluateAnimations;
+ // Must not be null
+ IDamageAccumulator* damageAccumulator;
struct Out {
Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9ebee1d7fbd4..8a5c85751c9f 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -439,6 +439,7 @@ void CanvasContext::prepareTree(TreeInfo& info) {
mRenderThread.removeFrameCallback(this);
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
+ info.damageAccumulator = &mDamageAccumulator;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
@@ -465,27 +466,30 @@ void CanvasContext::notifyFramePending() {
mRenderThread.pushBackFrameCallback(this);
}
-void CanvasContext::draw(Rect* dirty) {
+void CanvasContext::draw() {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawDisplayList called on a context with no canvas or surface!");
profiler().markPlaybackStart();
+ SkRect dirty;
+ mDamageAccumulator.finish(&dirty);
+
EGLint width, height;
mGlobalContext->beginFrame(mEglSurface, &width, &height);
if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
mCanvas->setViewport(width, height);
- dirty = NULL;
+ dirty.setEmpty();
} else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
- dirty = NULL;
+ dirty.setEmpty();
} else {
- profiler().unionDirty(dirty);
+ profiler().unionDirty(&dirty);
}
status_t status;
- if (dirty && !dirty->isEmpty()) {
- status = mCanvas->prepareDirty(dirty->left, dirty->top,
- dirty->right, dirty->bottom, mOpaque);
+ if (!dirty.isEmpty()) {
+ status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
+ dirty.fRight, dirty.fBottom, mOpaque);
} else {
status = mCanvas->prepare(mOpaque);
}
@@ -516,14 +520,12 @@ void CanvasContext::doFrame() {
profiler().startFrame();
- TreeInfo info;
- info.evaluateAnimations = true;
- info.performStagingPush = false;
+ TreeInfo info(TreeInfo::MODE_RT_ONLY);
info.prepareTextures = false;
prepareTree(info);
if (info.out.canDrawThisFrame) {
- draw(NULL);
+ draw();
}
}
@@ -543,7 +545,7 @@ void CanvasContext::invokeFunctor(Functor* functor) {
bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
requireGlContext();
- TreeInfo info;
+ TreeInfo info(TreeInfo::MODE_FULL);
layer->apply(info);
return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 00c5bf0ee77e..d926b38c94ee 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -23,6 +23,7 @@
#include <utils/Functor.h>
#include <utils/Vector.h>
+#include "../DamageAccumulator.h"
#include "../DrawProfiler.h"
#include "../RenderNode.h"
#include "RenderTask.h"
@@ -57,7 +58,7 @@ public:
void makeCurrent();
void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
void prepareTree(TreeInfo& info);
- void draw(Rect* dirty);
+ void draw();
void destroyCanvasAndSurface();
// IFrameCallback, Chroreographer-driven frame callback entry point
@@ -99,6 +100,7 @@ private:
bool mOpaque;
OpenGLRenderer* mCanvas;
bool mHaveNewSurface;
+ DamageAccumulator mDamageAccumulator;
const sp<RenderNode> mRootRenderNode;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 61d67ca3f608..bdfdd21994ee 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -68,10 +68,6 @@ void DrawFrameTask::removeLayerUpdate(DeferredLayerUpdater* layer) {
}
}
-void DrawFrameTask::setDirty(int left, int top, int right, int bottom) {
- mDirty.set(left, top, right, bottom);
-}
-
int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
@@ -83,7 +79,6 @@ int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos
// Reset the single-frame data
mFrameTimeNanos = 0;
mRecordDurationNanos = 0;
- mDirty.setEmpty();
return mSyncResult;
}
@@ -103,13 +98,12 @@ void DrawFrameTask::run() {
bool canUnblockUiThread;
bool canDrawThisFrame;
{
- TreeInfo info;
+ TreeInfo info(TreeInfo::MODE_FULL);
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
}
// Grab a copy of everything we need
- Rect dirty(mDirty);
CanvasContext* context = mContext;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
@@ -118,7 +112,7 @@ void DrawFrameTask::run() {
}
if (CC_LIKELY(canDrawThisFrame)) {
- context->draw(&dirty);
+ context->draw();
}
if (!canUnblockUiThread) {
@@ -126,18 +120,11 @@ void DrawFrameTask::run() {
}
}
-static void initTreeInfo(TreeInfo& info) {
- info.prepareTextures = true;
- info.performStagingPush = true;
- info.evaluateAnimations = true;
-}
-
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse();
- initTreeInfo(info);
for (size_t i = 0; i < mLayers.size(); i++) {
mContext->processLayerUpdate(mLayers[i].get(), info);
@@ -149,8 +136,6 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
mContext->prepareTree(info);
if (info.out.hasAnimations) {
- // TODO: dirty calculations, for now just do a full-screen inval
- mDirty.setEmpty();
if (info.out.requiresUiRedraw) {
mSyncResult |= kSync_UIRedrawRequired;
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index d4129b646d68..96f0add4c08c 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -60,7 +60,6 @@ public:
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
- void setDirty(int left, int top, int right, int bottom);
void setDensity(float density) { mDensity = density; }
int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
@@ -80,7 +79,6 @@ private:
/*********************************************
* Single frame data
*********************************************/
- Rect mDirty;
nsecs_t mFrameTimeNanos;
nsecs_t mRecordDurationNanos;
float mDensity;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 09019637693f..4988f1940b6b 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -47,7 +47,7 @@ namespace renderthread {
#define SETUP_TASK(method) \
LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
- "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
+ "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
@@ -180,8 +180,7 @@ void RenderProxy::setOpaque(bool opaque) {
}
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
- mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ float density) {
mDrawFrameTask.setDensity(density);
return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 944ff9c6804b..a95f8f01ef39 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -70,7 +70,7 @@ public:
ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+ float density);
ANDROID_API void destroyCanvasAndSurface();
ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index c020b40a31ee..877a42216c27 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -19,6 +19,7 @@
#include <math.h>
#include "Blur.h"
+#include "MathUtils.h"
namespace android {
namespace uirenderer {
@@ -35,6 +36,17 @@ float Blur::convertSigmaToRadius(float sigma) {
return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
}
+// if the original radius was on an integer boundary and the resulting radius
+// is within the conversion error tolerance then we attempt to snap to the
+// original integer boundary.
+uint32_t Blur::convertRadiusToInt(float radius) {
+ const float radiusCeil = ceilf(radius);
+ if (MathUtils::areEqual(radiusCeil, radius)) {
+ return radiusCeil;
+ }
+ return radius;
+}
+
/**
* HWUI has used a slightly different equation than Skia to generate the value
* for sigma and to preserve compatibility we have kept that logic.
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 79aff652ca4e..b14533312719 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -27,8 +27,12 @@ class Blur {
public:
// If radius > 0, return the corresponding sigma, else return 0
ANDROID_API static float convertRadiusToSigma(float radius);
- // If sigma > 0.6, return the corresponding radius, else return 0
+ // If sigma > 0.5, return the corresponding radius, else return 0
ANDROID_API static float convertSigmaToRadius(float sigma);
+ // If the original radius was on an integer boundary then after the sigma to
+ // radius conversion a small rounding error may be introduced. This function
+ // accounts for that error and snaps to the appropriate integer boundary.
+ static uint32_t convertRadiusToInt(float radius);
static void generateGaussianWeights(float* weights, int32_t radius);
static void horizontal(float* weights, int32_t radius, const uint8_t* source,