diff options
Diffstat (limited to 'libs')
34 files changed, 471 insertions, 250 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 442f327..cc62170 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 \ @@ -71,8 +72,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 @@ -80,16 +79,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 a0c7c55..203cdff 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 0000000..8aa8c92 --- /dev/null +++ b/libs/hwui/DamageAccumulator.cpp @@ -0,0 +1,105 @@ +/* + * 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 { + +struct DirtyStack { + const RenderNode* node; + // 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::pushNode(const RenderNode* node) { + if (!mHead->next) { + DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack)); + nextFrame->next = 0; + nextFrame->prev = mHead; + mHead->next = nextFrame; + } + mHead = mHead->next; + mHead->node = node; + mHead->pendingDirty.setEmpty(); +} + +void DamageAccumulator::popNode() { + 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 (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()); + } + } else { + mappedDirty.offset(props.getLeft(), props.getTop()); + } + dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom); + } +} + +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 0000000..c62a351 --- /dev/null +++ b/libs/hwui/DamageAccumulator.h @@ -0,0 +1,57 @@ +/* + * 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 <utils/LinearAllocator.h> + +#include <SkMatrix.h> +#include <SkRect.h> + +#include "utils/Macros.h" + +namespace android { +namespace uirenderer { + +struct DirtyStack; +class RenderNode; + +class DamageAccumulator { + 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 node's transform when popNode() is called. + void pushNode(const RenderNode* node); + // 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); + + void finish(SkRect* totalDirty); + +private: + LinearAllocator mAllocator; + DirtyStack* mHead; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* DAMAGEACCUMULATOR_H */ diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 97e9bf6..d494c4c 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 96c6292..f418c9b 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 11e78b0..7b7dc16 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 ea3e7a8..9212b9d 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 const char* name() { return "DrawRoundRect"; } @@ -1175,7 +1175,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"; } @@ -1195,7 +1195,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); } @@ -1232,7 +1232,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 229afdf..0e47c6e 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 dff4f6c..2eaa671 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 971a66e..2409554 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 c1aa1c6..7c06e5d 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 4407ab0..bf0ab5c 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 9259028..8ce22b0 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/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 71836dd..cd09f86 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2042,10 +2042,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 fc27947..0f953a5 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -170,7 +170,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 5a49f38..d9c06d3 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -346,7 +346,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; @@ -357,7 +357,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 847853a..bcfb367 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -293,7 +293,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() { @@ -301,7 +301,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 d964efc..c2f6df8 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -25,6 +25,7 @@ #include <utils/Trace.h> +#include "DamageAccumulator.h" #include "Debug.h" #include "DisplayListOp.h" #include "DisplayListLogBuffer.h" @@ -110,14 +111,36 @@ 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()); + } +} + void RenderNode::prepareTreeImpl(TreeInfo& info) { - if (info.performStagingPush) { + pushNode(this, info); + 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); + popNode(info); } class PushAnimatorsFunctor { @@ -149,18 +172,28 @@ void RenderNode::pushStagingChanges(TreeInfo& info) { } if (mDirtyPropertyFields) { mDirtyPropertyFields = 0; + damageSelf(info); + popNode(info); 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. + 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 +213,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); + popNode(info); + 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(); + + pushNode(this, info); + damageSelf(info); } void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) { @@ -223,9 +265,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 1a5377b..393d4ea 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -148,7 +148,7 @@ public: mDirtyPropertyFields |= fields; } - const RenderProperties& properties() { + const RenderProperties& properties() const { return mProperties; } @@ -187,6 +187,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.cpp b/libs/hwui/RenderProperties.cpp index 5f7d4e3..6163df5 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -44,6 +44,7 @@ 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 c0e3ce7..c294f38 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,47 @@ 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; + } + + 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; } - void setCaching(bool caching) { - mPrimitiveFields.mCaching = caching; + bool setCaching(bool caching) { + return RP_SET(mPrimitiveFields.mCaching, caching); } int getWidth() const { @@ -478,6 +481,7 @@ 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/Renderer.h b/libs/hwui/Renderer.h index 23cab0e..320895c 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 90039e9..fae25a6 100644 --- a/libs/hwui/StatefulBaseRenderer.cpp +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -121,20 +121,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 057006b..f38c752 100644 --- a/libs/hwui/StatefulBaseRenderer.h +++ b/libs/hwui/StatefulBaseRenderer.h @@ -75,9 +75,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 8355f83..2096f98 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -18,11 +18,14 @@ #include <utils/Timers.h> +#include "utils/Macros.h" + namespace android { namespace uirenderer { class BaseRenderNodeAnimator; class AnimationListener; +class DamageAccumulator; class AnimationHook { public: @@ -31,21 +34,44 @@ 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(0) {} + 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; + DamageAccumulator* damageAccumulator; struct Out { Out() diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9ebee1d..8a5c857 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 00c5bf0..d926b38 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 61d67ca..bdfdd21 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 d4129b6..96f0add 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 0901963..ded10a1 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -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 944ff9c..a95f8f0 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 c020b40..877a422 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 79aff65..b145333 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, |