diff options
-rw-r--r-- | graphics/java/android/graphics/Outline.java | 6 | ||||
-rw-r--r-- | libs/hwui/Outline.h | 10 | ||||
-rw-r--r-- | libs/hwui/ProfileData.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.h | 6 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/tests/common/scenes/PathClippingAnimation.cpp | 153 | ||||
-rw-r--r-- | libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp | 31 |
7 files changed, 197 insertions, 14 deletions
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java index b77865f423c6..fc7f84c3c83e 100644 --- a/graphics/java/android/graphics/Outline.java +++ b/graphics/java/android/graphics/Outline.java @@ -118,13 +118,13 @@ public final class Outline { /** * Returns whether the outline can be used to clip a View. * <p> - * Currently, only Outlines that can be represented as a rectangle, circle, - * or round rect support clipping. + * As of API 33, all Outline shapes support clipping. Prior to API 33, only Outlines that + * could be represented as a rectangle, circle, or round rect supported clipping. * * @see android.view.View#setClipToOutline(boolean) */ public boolean canClip() { - return mMode != MODE_PATH; + return true; } /** diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h index 2eb2c7c7e299..e16fd8c38c75 100644 --- a/libs/hwui/Outline.h +++ b/libs/hwui/Outline.h @@ -88,14 +88,10 @@ public: bool getShouldClip() const { return mShouldClip; } - bool willClip() const { - // only round rect outlines can be used for clipping - return mShouldClip && (mType == Type::RoundRect); - } + bool willClip() const { return mShouldClip; } - bool willRoundRectClip() const { - // only round rect outlines can be used for clipping - return willClip() && MathUtils::isPositive(mRadius); + bool willComplexClip() const { + return mShouldClip && (mType != Type::RoundRect || MathUtils::isPositive(mRadius)); } bool getAsRoundRect(Rect* outRect, float* outRadius) const { diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp index dd8439647fd3..3d0ca0a10851 100644 --- a/libs/hwui/ProfileData.cpp +++ b/libs/hwui/ProfileData.cpp @@ -137,6 +137,7 @@ void ProfileData::dump(int fd) const { histogramGPUForEach([fd](HistogramEntry entry) { dprintf(fd, " %ums=%u", entry.renderTimeMs, entry.frameCount); }); + dprintf(fd, "\n"); } uint32_t ProfileData::findPercentile(int percentile) const { diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index cd622eba37b6..064ba7aee107 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -165,11 +165,11 @@ public: bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) { // parent may have already dictated that a descendant layer is needed bool functorsNeedLayer = - ancestorDictatesFunctorsNeedLayer - || CC_UNLIKELY(isClipMayBeComplex()) + ancestorDictatesFunctorsNeedLayer || + CC_UNLIKELY(isClipMayBeComplex()) // Round rect clipping forces layer for functors - || CC_UNLIKELY(getOutline().willRoundRectClip()) || + || CC_UNLIKELY(getOutline().willComplexClip()) || CC_UNLIKELY(getRevealClip().willClip()) // Complex matrices forces layer, due to stencil clipping diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 48145d2331ee..507d3dcdcde9 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -88,6 +88,10 @@ static void clipOutline(const Outline& outline, SkCanvas* canvas, const SkRect* if (pendingClip) { canvas->clipRect(*pendingClip); } + const SkPath* path = outline.getPath(); + if (path) { + canvas->clipPath(*path, SkClipOp::kIntersect, true); + } return; } diff --git a/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp new file mode 100644 index 000000000000..1e343c1dd283 --- /dev/null +++ b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <vector> + +#include "TestSceneBase.h" + +class PathClippingAnimation : public TestScene { +public: + int mSpacing, mSize; + bool mClip, mAnimateClip; + int mMaxCards; + std::vector<sp<RenderNode> > cards; + + PathClippingAnimation(int spacing, int size, bool clip, bool animateClip, int maxCards) + : mSpacing(spacing) + , mSize(size) + , mClip(clip) + , mAnimateClip(animateClip) + , mMaxCards(maxCards) {} + + PathClippingAnimation(int spacing, int size, bool clip, bool animateClip) + : PathClippingAnimation(spacing, size, clip, animateClip, INT_MAX) {} + + void createContent(int width, int height, Canvas& canvas) override { + canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); + canvas.enableZ(true); + int ci = 0; + int numCards = 0; + + for (int x = 0; x < width; x += mSpacing) { + for (int y = 0; y < height; y += mSpacing) { + auto color = BrightColors[ci++ % BrightColorsCount]; + auto card = TestUtils::createNode( + x, y, x + mSize, y + mSize, [&](RenderProperties& props, Canvas& canvas) { + canvas.drawColor(color, SkBlendMode::kSrcOver); + if (mClip) { + // Create circular path that rounds around the inside of all + // four corners of the given square defined by mSize*mSize + SkPath path = setPath(mSize); + props.mutableOutline().setPath(&path, 1); + props.mutableOutline().setShouldClip(true); + } + }); + canvas.drawRenderNode(card.get()); + cards.push_back(card); + ++numCards; + if (numCards >= mMaxCards) { + break; + } + } + if (numCards >= mMaxCards) { + break; + } + } + + canvas.enableZ(false); + } + + SkPath setPath(int size) { + SkPath path; + path.moveTo(0, size / 2); + path.cubicTo(0, size * .75, size * .25, size, size / 2, size); + path.cubicTo(size * .75, size, size, size * .75, size, size / 2); + path.cubicTo(size, size * .25, size * .75, 0, size / 2, 0); + path.cubicTo(size / 4, 0, 0, size / 4, 0, size / 2); + return path; + } + + void doFrame(int frameNr) override { + int curFrame = frameNr % 50; + if (curFrame > 25) curFrame = 50 - curFrame; + for (auto& card : cards) { + if (mAnimateClip) { + SkPath path = setPath(mSize - curFrame); + card->mutateStagingProperties().mutableOutline().setPath(&path, 1); + } + card->mutateStagingProperties().setTranslationX(curFrame); + card->mutateStagingProperties().setTranslationY(curFrame); + card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::DISPLAY_LIST); + } + } +}; + +static TestScene::Registrar _PathClippingUnclipped(TestScene::Info{ + "pathClipping-unclipped", "Multiple RenderNodes, unclipped.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), false, false); + }}); + +static TestScene::Registrar _PathClippingUnclippedSingle(TestScene::Info{ + "pathClipping-unclippedsingle", "A single RenderNode, unclipped.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), false, false, 1); + }}); + +static TestScene::Registrar _PathClippingUnclippedSingleLarge(TestScene::Info{ + "pathClipping-unclippedsinglelarge", "A single large RenderNode, unclipped.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(350), false, false, 1); + }}); + +static TestScene::Registrar _PathClippingClipped80(TestScene::Info{ + "pathClipping-clipped80", "Multiple RenderNodes, clipped by paths.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), true, false); + }}); + +static TestScene::Registrar _PathClippingClippedSingle(TestScene::Info{ + "pathClipping-clippedsingle", "A single RenderNode, clipped by a path.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), true, false, 1); + }}); + +static TestScene::Registrar _PathClippingClippedSingleLarge(TestScene::Info{ + "pathClipping-clippedsinglelarge", "A single large RenderNode, clipped by a path.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(350), true, false, 1); + }}); + +static TestScene::Registrar _PathClippingAnimated(TestScene::Info{ + "pathClipping-animated", + "Multiple RenderNodes, clipped by paths which are being altered every frame.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), true, true); + }}); + +static TestScene::Registrar _PathClippingAnimatedSingle(TestScene::Info{ + "pathClipping-animatedsingle", + "A single RenderNode, clipped by a path which is being altered every frame.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(80), true, true, 1); + }}); + +static TestScene::Registrar _PathClippingAnimatedSingleLarge(TestScene::Info{ + "pathClipping-animatedsinglelarge", + "A single large RenderNode, clipped by a path which is being altered every frame.", + [](const TestScene::Options&) -> test::TestScene* { + return new PathClippingAnimation(dp(100), dp(350), true, true, 1); + }}); diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp index 163745b04ed2..e9f353d887f2 100644 --- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp +++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp @@ -21,14 +21,17 @@ class RoundRectClippingAnimation : public TestScene { public: int mSpacing, mSize; + int mMaxCards; - RoundRectClippingAnimation(int spacing, int size) : mSpacing(spacing), mSize(size) {} + RoundRectClippingAnimation(int spacing, int size, int maxCards = INT_MAX) + : mSpacing(spacing), mSize(size), mMaxCards(maxCards) {} std::vector<sp<RenderNode> > cards; void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); canvas.enableZ(true); int ci = 0; + int numCards = 0; for (int x = 0; x < width; x += mSpacing) { for (int y = 0; y < height; y += mSpacing) { @@ -42,6 +45,13 @@ public: }); canvas.drawRenderNode(card.get()); cards.push_back(card); + ++numCards; + if (numCards >= mMaxCards) { + break; + } + } + if (numCards >= mMaxCards) { + break; } } @@ -71,3 +81,22 @@ static TestScene::Registrar _RoundRectClippingCpu(TestScene::Info{ [](const TestScene::Options&) -> test::TestScene* { return new RoundRectClippingAnimation(dp(20), dp(20)); }}); + +static TestScene::Registrar _RoundRectClippingGrid(TestScene::Info{ + "roundRectClipping-grid", "A grid of RenderNodes with round rect clipping outlines.", + [](const TestScene::Options&) -> test::TestScene* { + return new RoundRectClippingAnimation(dp(100), dp(80)); + }}); + +static TestScene::Registrar _RoundRectClippingSingle(TestScene::Info{ + "roundRectClipping-single", "A single RenderNodes with round rect clipping outline.", + [](const TestScene::Options&) -> test::TestScene* { + return new RoundRectClippingAnimation(dp(100), dp(80), 1); + }}); + +static TestScene::Registrar _RoundRectClippingSingleLarge(TestScene::Info{ + "roundRectClipping-singlelarge", + "A single large RenderNodes with round rect clipping outline.", + [](const TestScene::Options&) -> test::TestScene* { + return new RoundRectClippingAnimation(dp(100), dp(350), 1); + }}); |