diff options
Diffstat (limited to 'libs/hwui/tests/unit/RenderNodeDrawableTests.cpp')
-rw-r--r-- | libs/hwui/tests/unit/RenderNodeDrawableTests.cpp | 979 |
1 files changed, 581 insertions, 398 deletions
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 4c3e182ced2f..15c0ab1ad8d2 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -14,24 +14,24 @@ * limitations under the License. */ -#include <gtest/gtest.h> #include <VectorDrawable.h> +#include <gtest/gtest.h> +#include <SkClipStack.h> +#include <SkLiteRecorder.h> +#include <SkSurface_Base.h> +#include <string.h> #include "AnimationContext.h" #include "DamageAccumulator.h" +#include "FatalTestCanvas.h" #include "IContextFactory.h" +#include "SkiaCanvas.h" #include "pipeline/skia/SkiaDisplayList.h" +#include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaPipeline.h" #include "pipeline/skia/SkiaRecordingCanvas.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" -#include "SkiaCanvas.h" -#include <SkSurface_Base.h> -#include <SkLiteRecorder.h> -#include <SkClipStack.h> -#include "FatalTestCanvas.h" -#include <string.h> - using namespace android; using namespace android::uirenderer; @@ -39,8 +39,8 @@ using namespace android::uirenderer::renderthread; using namespace android::uirenderer::skiapipeline; TEST(RenderNodeDrawable, create) { - auto rootNode = TestUtils::createNode(0, 0, 200, 400, - [](RenderProperties& props, Canvas& canvas) { + auto rootNode = + TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) { canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver); }); @@ -65,47 +65,50 @@ static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) { } static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) { - auto node = TestUtils::createSkiaNode(0, 0, 100, 100, + auto node = TestUtils::createSkiaNode( + 0, 0, 100, 100, [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedRect(&canvas, expectedDrawOrder); - props.setTranslationZ(z); - }); - canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership + drawOrderedRect(&canvas, expectedDrawOrder); + props.setTranslationZ(z); + }); + canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership } -static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, +static void drawOrderedNode( + Canvas* canvas, uint8_t expectedDrawOrder, std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) { - auto node = TestUtils::createSkiaNode(0, 0, 100, 100, + auto node = TestUtils::createSkiaNode( + 0, 0, 100, 100, [expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedRect(&canvas, expectedDrawOrder); - if (setup) { - setup(props, canvas); - } - }); - canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership + drawOrderedRect(&canvas, expectedDrawOrder); + if (setup) { + setup(props, canvas); + } + }); + canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership } class ZReorderCanvas : public SkCanvas { public: ZReorderCanvas(int width, int height) : SkCanvas(width, height) {} void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel + int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order"; } int getIndex() { return mDrawCounter; } + protected: int mDrawCounter = 0; }; -} // end anonymous namespace +} // end anonymous namespace TEST(RenderNodeDrawable, zReorder) { - - auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { canvas.insertReorderBarrier(true); canvas.insertReorderBarrier(false); - drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder + drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder drawOrderedRect(&canvas, 1); canvas.insertReorderBarrier(true); drawOrderedNode(&canvas, 6, 2.0f); @@ -116,37 +119,36 @@ TEST(RenderNodeDrawable, zReorder) { drawOrderedNode(&canvas, 7, 2.0f); canvas.insertReorderBarrier(false); drawOrderedRect(&canvas, 8); - drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder - canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op + drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder + canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op drawOrderedRect(&canvas, 11); drawOrderedNode(&canvas, 10, -1.0f); canvas.insertReorderBarrier(false); - canvas.insertReorderBarrier(true); //test with two empty reorder sections + canvas.insertReorderBarrier(true); // test with two empty reorder sections canvas.insertReorderBarrier(true); canvas.insertReorderBarrier(false); drawOrderedRect(&canvas, 12); }); - //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection + // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection ZReorderCanvas canvas(100, 100); RenderNodeDrawable drawable(parent.get(), &canvas, false); canvas.drawDrawable(&drawable); EXPECT_EQ(13, canvas.getIndex()); } -TEST(RenderNodeDrawable, composeOnLayer) -{ +TEST(RenderNodeDrawable, composeOnLayer) { auto surface = SkSurface::MakeRasterN32Premul(1, 1); SkCanvas& canvas = *surface->getCanvas(); canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1, - [](RenderProperties& props, SkiaRecordingCanvas& recorder) { - recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); - }); + auto rootNode = TestUtils::createSkiaNode( + 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) { + recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); + }); - //attach a layer to the render node + // attach a layer to the render node auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1); auto canvas2 = surfaceLayer->getCanvas(); canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); @@ -181,39 +183,38 @@ static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) { } } -TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) -{ +TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) { auto surface = SkSurface::MakeRasterN32Premul(400, 800); SkCanvas& canvas = *surface->getCanvas(); canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); - auto rootNode = TestUtils::createSkiaNode(0, 0, 400, 800, - [](RenderProperties& props, SkiaRecordingCanvas& recorder) { - SkPaint layerPaint; - ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder)); - EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); + auto rootNode = TestUtils::createSkiaNode( + 0, 0, 400, 800, [](RenderProperties& props, SkiaRecordingCanvas& recorder) { + SkPaint layerPaint; + ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder)); + EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); - //note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved - recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer); - ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder)); - EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); + // note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved + recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer); + ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder)); + EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); - recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect); - ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder)); + recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect); + ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder)); - recorder.translate(300.0f, 400.0f); - EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder)); + recorder.translate(300.0f, 400.0f); + EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder)); - recorder.restore(); - ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder)); - EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); + recorder.restore(); + ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder)); + EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity()); - SkPaint paint; - paint.setAntiAlias(true); - paint.setColor(SK_ColorGREEN); - recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint); - }); + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(SK_ColorGREEN); + recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint); + }); RenderNodeDrawable drawable(rootNode.get(), &canvas, true); canvas.drawDrawable(&drawable); @@ -227,7 +228,7 @@ public: return new AnimationContext(clock); } }; -} // end anonymous namespace +} // end anonymous namespace RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) { static const int SCROLL_X = 5; @@ -237,33 +238,36 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) { ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {} void onDrawRect(const SkRect& rect, const SkPaint& paint) override { const int index = mDrawCounter++; - SkMatrix expectedMatrix;; + SkMatrix expectedMatrix; + ; switch (index) { - case 0: //this is node "B" - EXPECT_EQ(SkRect::MakeWH(100, 100), rect); - EXPECT_EQ(SK_ColorWHITE, paint.getColor()); - expectedMatrix.reset(); - EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this)); - break; - case 1: //this is node "P" - EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect); - EXPECT_EQ(SK_ColorDKGRAY, paint.getColor()); - expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y); - EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), TestUtils::getLocalClipBounds(this)); - break; - case 2: //this is node "C" - EXPECT_EQ(SkRect::MakeWH(100, 50), rect); - EXPECT_EQ(SK_ColorBLUE, paint.getColor()); - expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y); - EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this)); - break; - default: - ADD_FAILURE(); + case 0: // this is node "B" + EXPECT_EQ(SkRect::MakeWH(100, 100), rect); + EXPECT_EQ(SK_ColorWHITE, paint.getColor()); + expectedMatrix.reset(); + EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this)); + break; + case 1: // this is node "P" + EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect); + EXPECT_EQ(SK_ColorDKGRAY, paint.getColor()); + expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y); + EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), + TestUtils::getLocalClipBounds(this)); + break; + case 2: // this is node "C" + EXPECT_EQ(SkRect::MakeWH(100, 50), rect); + EXPECT_EQ(SK_ColorBLUE, paint.getColor()); + expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y); + EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this)); + break; + default: + ADD_FAILURE(); } EXPECT_EQ(expectedMatrix, getTotalMatrix()); } int getIndex() { return mDrawCounter; } + protected: int mDrawCounter = 0; }; @@ -276,66 +280,143 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) { * The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background * (which isn't affected by scroll). */ - auto receiverBackground = TestUtils::createSkiaNode(0, 0, 100, 100, + auto receiverBackground = TestUtils::createSkiaNode( + 0, 0, 100, 100, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver! - properties.setTranslationX(SCROLL_X); - properties.setTranslationY(SCROLL_Y); - - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }, "B"); - - auto projectingRipple = TestUtils::createSkiaNode(50, 0, 100, 50, + properties.setProjectionReceiver(true); + // scroll doesn't apply to background, so undone via translationX/Y + // NOTE: translationX/Y only! no other transform properties may be set for a proj + // receiver! + properties.setTranslationX(SCROLL_X); + properties.setTranslationY(SCROLL_Y); + + SkPaint paint; + paint.setColor(SK_ColorWHITE); + canvas.drawRect(0, 0, 100, 100, paint); + }, + "B"); + + auto projectingRipple = TestUtils::createSkiaNode( + 50, 0, 100, 50, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(-10, -10, 60, 60, paint); - }, "P"); - auto child = TestUtils::createSkiaNode(0, 50, 100, 100, + properties.setProjectBackwards(true); + properties.setClipToBounds(false); + SkPaint paint; + paint.setColor(SK_ColorDKGRAY); + canvas.drawRect(-10, -10, 60, 60, paint); + }, + "P"); + auto child = TestUtils::createSkiaNode( + 0, 50, 100, 100, [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorBLUE); - canvas.drawRect(0, 0, 100, 50, paint); - canvas.drawRenderNode(projectingRipple.get()); - }, "C"); - auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, - [&receiverBackground, &child](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - // Set a rect outline for the projecting ripple to be masked against. - properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f); - - canvas.save(SaveFlags::MatrixClip); - canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - canvas.restore(); - }, "A"); + SkPaint paint; + paint.setColor(SK_ColorBLUE); + canvas.drawRect(0, 0, 100, 50, paint); + canvas.drawRenderNode(projectingRipple.get()); + }, + "C"); + auto parent = TestUtils::createSkiaNode( + 0, 0, 100, 100, + [&receiverBackground, &child](RenderProperties& properties, + SkiaRecordingCanvas& canvas) { + // Set a rect outline for the projecting ripple to be masked against. + properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f); + + canvas.save(SaveFlags::MatrixClip); + canvas.translate(-SCROLL_X, + -SCROLL_Y); // Apply scroll (note: bg undoes this internally) + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + canvas.restore(); + }, + "A"); ContextFactory contextFactory; - std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create( - renderThread, false, parent.get(), &contextFactory)); + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; parent->prepareTree(info); - //parent(A) -> (receiverBackground, child) - //child(C) -> (rect[0, 0, 100, 50], projectingRipple) - //projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards - //receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver + // parent(A) -> (receiverBackground, child) + // child(C) -> (rect[0, 0, 100, 50], projectingRipple) + // projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards + // receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver - //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection + // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection ProjectionTestCanvas canvas(100, 100); RenderNodeDrawable drawable(parent.get(), &canvas, true); canvas.drawDrawable(&drawable); EXPECT_EQ(3, canvas.getIndex()); } -RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) { +RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { + class ProjectionTestCanvas : public SkCanvas { + public: + ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {} + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { + mDrawCounter++; + } + + int getDrawCounter() { return mDrawCounter; } + + private: + int mDrawCounter = 0; + }; + + auto receiverBackground = TestUtils::createSkiaNode( + 0, 0, 100, 100, + [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { + properties.setProjectionReceiver(true); + }, + "B"); // a receiver with an empty display list + + auto projectingRipple = TestUtils::createSkiaNode( + 0, 0, 100, 100, + [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { + properties.setProjectBackwards(true); + properties.setClipToBounds(false); + SkPaint paint; + canvas.drawRect(0, 0, 100, 100, paint); + }, + "P"); + auto child = TestUtils::createSkiaNode( + 0, 0, 100, 100, + [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) { + SkPaint paint; + canvas.drawRect(0, 0, 100, 100, paint); + canvas.drawRenderNode(projectingRipple.get()); + }, + "C"); + auto parent = TestUtils::createSkiaNode( + 0, 0, 100, 100, + [&receiverBackground, &child](RenderProperties& properties, + SkiaRecordingCanvas& canvas) { + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + }, + "A"); + ContextFactory contextFactory; + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); + TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); + DamageAccumulator damageAccumulator; + info.damageAccumulator = &damageAccumulator; + parent->prepareTree(info); + + // parent(A) -> (receiverBackground, child) + // child(C) -> (rect[0, 0, 100, 100], projectingRipple) + // projectingRipple(P) -> (rect[0, 0, 100, 100]) -> projects backwards + // receiverBackground(B) -> (empty) -> projection receiver + + // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection + ProjectionTestCanvas canvas(100, 100); + RenderNodeDrawable drawable(parent.get(), &canvas, true); + canvas.drawDrawable(&drawable); + EXPECT_EQ(2, canvas.getDrawCounter()); +} + +RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) { /* R is backward projected on B and C is a layer. A / \ @@ -352,17 +433,17 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) { class ProjectionTestCanvas : public SkCanvas { public: ProjectionTestCanvas(int* drawCounter) - : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) - , mDrawCounter(drawCounter) - {} + : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {} void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, - const SkPaint&) override { - EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer - EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), TestUtils::getClipBounds(this)); + const SkPaint&) override { + EXPECT_EQ(0, (*mDrawCounter)++); // part of painting the layer + EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), + TestUtils::getClipBounds(this)); } void onDrawRect(const SkRect& rect, const SkPaint& paint) override { EXPECT_EQ(1, (*mDrawCounter)++); - EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this)); + EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), + TestUtils::getClipBounds(this)); } void onDrawOval(const SkRect&, const SkPaint&) override { EXPECT_EQ(2, (*mDrawCounter)++); @@ -377,69 +458,74 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) { class ProjectionLayer : public SkSurface_Base { public: ProjectionLayer(int* drawCounter) - : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr) - , mDrawCounter(drawCounter) { - } - void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override { + : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr) + , mDrawCounter(drawCounter) {} + virtual sk_sp<SkImage> onNewImageSnapshot() override { EXPECT_EQ(3, (*mDrawCounter)++); EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X, - 300 - SCROLL_Y), TestUtils::getClipBounds(this->getCanvas())); - } - SkCanvas* onNewCanvas() override { - return new ProjectionTestCanvas(mDrawCounter); - } - sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { - return nullptr; - } - sk_sp<SkImage> onNewImageSnapshot() override { + 300 - SCROLL_Y), + TestUtils::getClipBounds(this->getCanvas())); return nullptr; } + SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); } + sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; } void onCopyOnWrite(ContentChangeMode) override {} int* mDrawCounter; + void onWritePixels(const SkPixmap&, int x, int y) {} }; - auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + auto receiverBackground = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver! - properties.setTranslationX(SCROLL_X); - properties.setTranslationY(SCROLL_Y); - - canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint()); - }, "B"); //B - auto projectingRipple = TestUtils::createSkiaNode(0, 0, LAYER_WIDTH, LAYER_HEIGHT, + properties.setProjectionReceiver(true); + // scroll doesn't apply to background, so undone via translationX/Y + // NOTE: translationX/Y only! no other transform properties may be set for a proj + // receiver! + properties.setTranslationX(SCROLL_X); + properties.setTranslationY(SCROLL_Y); + + canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint()); + }, + "B"); // B + auto projectingRipple = TestUtils::createSkiaNode( + 0, 0, LAYER_WIDTH, LAYER_HEIGHT, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds - }, "R"); //R - auto child = TestUtils::createSkiaNode(100, 100, 300, 300, + properties.setProjectBackwards(true); + properties.setClipToBounds(false); + canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds + }, + "R"); // R + auto child = TestUtils::createSkiaNode( + 100, 100, 300, 300, [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - canvas.drawRenderNode(projectingRipple.get()); - canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint()); - }, "C"); //C - auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + canvas.drawRenderNode(projectingRipple.get()); + canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint()); + }, + "C"); // C + auto parent = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [&receiverBackground, &child](RenderProperties& properties, - SkiaRecordingCanvas& canvas) { - // Set a rect outline for the projecting ripple to be masked against. - properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f); - canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }, "A"); //A - - //prepareTree is required to find, which receivers have backward projected nodes + SkiaRecordingCanvas& canvas) { + // Set a rect outline for the projecting ripple to be masked against. + properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f); + canvas.translate(-SCROLL_X, + -SCROLL_Y); // Apply scroll (note: bg undoes this internally) + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + }, + "A"); // A + + // prepareTree is required to find, which receivers have backward projected nodes ContextFactory contextFactory; - std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create( - renderThread, false, parent.get(), &contextFactory)); + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; parent->prepareTree(info); int drawCounter = 0; - //set a layer after prepareTree to avoid layer logic there + // set a layer after prepareTree to avoid layer logic there child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer); sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter)); child->setLayerSurface(surfaceLayer1); @@ -449,9 +535,10 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) { LayerUpdateQueue layerUpdateQueue; layerUpdateQueue.enqueueLayerWithDamage(child.get(), - android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT)); - SkiaPipeline::renderLayersImpl(layerUpdateQueue, true, false); - EXPECT_EQ(1, drawCounter); //assert index 0 is drawn on the layer + android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT)); + auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); + pipeline->renderLayersImpl(layerUpdateQueue, true, false); + EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true); surfaceLayer1->getCanvas()->drawDrawable(&drawable); @@ -488,40 +575,50 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) { int mDrawCounter = 0; }; - auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + auto receiverBackground = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint()); - }, "B"); //B - auto projectingRipple = TestUtils::createSkiaNode(0, 0, 200, 200, + properties.setProjectionReceiver(true); + canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint()); + }, + "B"); // B + auto projectingRipple = TestUtils::createSkiaNode( + 0, 0, 200, 200, [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver! - properties.setTranslationX(SCROLL_X); - properties.setTranslationY(SCROLL_Y); - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - canvas.drawOval(0, 0, 200, 200, SkPaint()); - }, "R"); //R - auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + // scroll doesn't apply to background, so undone via translationX/Y + // NOTE: translationX/Y only! no other transform properties may be set for a proj + // receiver! + properties.setTranslationX(SCROLL_X); + properties.setTranslationY(SCROLL_Y); + properties.setProjectBackwards(true); + properties.setClipToBounds(false); + canvas.drawOval(0, 0, 200, 200, SkPaint()); + }, + "R"); // R + auto child = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) { - // Record time clip will be ignored by projectee - canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect); - - canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(projectingRipple.get()); - }, "C"); //C - auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, - [&receiverBackground, &child](RenderProperties& properties, - SkiaRecordingCanvas& canvas) { - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }, "A"); //A - - //prepareTree is required to find, which receivers have backward projected nodes + // Record time clip will be ignored by projectee + canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect); + + canvas.translate(-SCROLL_X, + -SCROLL_Y); // Apply scroll (note: bg undoes this internally) + canvas.drawRenderNode(projectingRipple.get()); + }, + "C"); // C + auto parent = + TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + [&receiverBackground, &child](RenderProperties& properties, + SkiaRecordingCanvas& canvas) { + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + }, + "A"); // A + + // prepareTree is required to find, which receivers have backward projected nodes ContextFactory contextFactory; - std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create( - renderThread, false, parent.get(), &contextFactory)); + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; @@ -534,17 +631,16 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) { } namespace { -static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) -{ +static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) { ContextFactory contextFactory; - std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create( - renderThread, false, renderNode.get(), &contextFactory)); + std::unique_ptr<CanvasContext> canvasContext( + CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory)); TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; renderNode->prepareTree(info); - //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection + // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection ZReorderCanvas canvas(100, 100); RenderNodeDrawable drawable(renderNode.get(), &canvas, false); canvas.drawDrawable(&drawable); @@ -560,18 +656,18 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectionReceiver(true); - } ); //nodeB + }); // nodeB drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(3, drawNode(renderThread, nodeA)); } @@ -584,19 +680,21 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); //nodeB + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, nullptr); // nodeB drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 2 + drawOrderedNode(&canvas, 3, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { // drawn as 2 props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 3 - props.setProjectionReceiver(true); - } ); //nodeE - }); //nodeA + }); // nodeR + }); // nodeC + drawOrderedNode(&canvas, 2, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3 + props.setProjectionReceiver(true); + }); // nodeE + }); // nodeA EXPECT_EQ(4, drawNode(renderThread, nodeA)); } @@ -608,17 +706,17 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); //nodeB + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, nullptr); // nodeB drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - //not having a projection receiver is an undefined behavior + // not having a projection receiver is an undefined behavior props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(2, drawNode(renderThread, nodeA)); } @@ -630,17 +728,17 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); //nodeB + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, nullptr); // nodeB drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectionReceiver(true); drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(3, drawNode(renderThread, nodeA)); } @@ -652,22 +750,22 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); //nodeB + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, nullptr); // nodeB drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - //having a node that is projected on itself is an undefined/unexpected behavior + // having a node that is projected on itself is an undefined/unexpected behavior props.setProjectionReceiver(true); props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(2, drawNode(renderThread, nodeA)); } -//Note: the outcome for this test is different in HWUI +// Note: the outcome for this test is different in HWUI RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) { /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed. A @@ -675,18 +773,18 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) { / | \ B C R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectionReceiver(true); - } ); //nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - } ); //nodeC + }); // nodeB + drawOrderedNode(&canvas, 1, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - }); //nodeA + }); // nodeR + }); // nodeA EXPECT_EQ(2, drawNode(renderThread, nodeA)); } @@ -699,20 +797,20 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) { / | \ B C R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectionReceiver(true); - } ); //nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - } ); //nodeC + }); // nodeB + drawOrderedNode(&canvas, 2, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectBackwards(true); props.setClipToBounds(false); - } ); //nodeR - } ); //nodeG - }); //nodeA + }); // nodeR + }); // nodeG + }); // nodeA EXPECT_EQ(3, drawNode(renderThread, nodeA)); } @@ -726,18 +824,19 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { props.setProjectionReceiver(true); drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - props.setProjectBackwards(true); - props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - } ); //nodeB - }); //nodeA + drawOrderedNode(&canvas, 2, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + props.setProjectBackwards(true); + props.setClipToBounds(false); + }); // nodeR + }); // nodeC + }); // nodeB + }); // nodeA EXPECT_EQ(3, drawNode(renderThread, nodeA)); } @@ -749,21 +848,23 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) { / \ G R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B props.setProjectionReceiver(true); - } ); //nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C - drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G - props.setProjectionReceiver(true); - } ); //nodeG - drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R - props.setProjectBackwards(true); - props.setClipToBounds(false); - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeB + drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C + drawOrderedNode(&canvas, 3, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G + props.setProjectionReceiver(true); + }); // nodeG + drawOrderedNode(&canvas, 1, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R + props.setProjectBackwards(true); + props.setClipToBounds(false); + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(4, drawNode(renderThread, nodeA)); } @@ -775,21 +876,23 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScena / \ G R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B props.setProjectionReceiver(true); - } ); //nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C - drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G - props.setProjectionReceiver(true); - props.setProjectBackwards(true); - props.setClipToBounds(false); - } ); //nodeG - drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R - } ); //nodeR - } ); //nodeC - }); //nodeA + }); // nodeB + drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C + drawOrderedNode(&canvas, 1, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G + props.setProjectionReceiver(true); + props.setProjectBackwards(true); + props.setClipToBounds(false); + }); // nodeG + drawOrderedNode(&canvas, 3, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R + }); // nodeR + }); // nodeC + }); // nodeA EXPECT_EQ(4, drawNode(renderThread, nodeA)); } @@ -803,23 +906,26 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) { | R */ - auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B + auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { + drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B props.setProjectionReceiver(true); - } ); //nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C - drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G - props.setProjectionReceiver(true); - } ); //nodeG - drawOrderedNode(&canvas, 4, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //D - drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R - props.setProjectBackwards(true); - props.setClipToBounds(false); - } ); //nodeR - } ); //nodeD - } ); //nodeC - }); //nodeA + }); // nodeB + drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C + drawOrderedNode(&canvas, 2, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G + props.setProjectionReceiver(true); + }); // nodeG + drawOrderedNode(&canvas, 4, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D + drawOrderedNode(&canvas, 3, [](RenderProperties& props, + SkiaRecordingCanvas& canvas) { // R + props.setProjectBackwards(true); + props.setClipToBounds(false); + }); // nodeR + }); // nodeD + }); // nodeC + }); // nodeA EXPECT_EQ(5, drawNode(renderThread, nodeA)); } @@ -828,8 +934,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) { static const int CANVAS_HEIGHT = 200; class SimpleTestCanvas : public TestCanvasBase { public: - SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) { - } + SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawRect(const SkRect& rect, const SkPaint& paint) override { EXPECT_EQ(0, mDrawCounter++); } @@ -839,11 +944,12 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) { }; auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25)); - canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint()); - canvas.drawBitmap(*bitmap, 10, 10, nullptr); - }); + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25)); + canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + SkPaint()); + canvas.drawBitmap(*bitmap, 10, 10, nullptr); + }); SimpleTestCanvas canvas; RenderNodeDrawable drawable(node.get(), &canvas, true); @@ -856,33 +962,32 @@ RENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) { static const int CANVAS_HEIGHT = 200; class ColorTestCanvas : public TestCanvasBase { public: - ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) { - } + ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawPaint(const SkPaint&) { switch (mDrawCounter++) { - case 0: - EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), - TestUtils::getClipBounds(this)); - break; - case 1: - EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this)); - break; - default: - ADD_FAILURE(); + case 0: + EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), + TestUtils::getClipBounds(this)); + break; + case 1: + EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this)); + break; + default: + ADD_FAILURE(); } } }; - auto unclippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - props.setClipToBounds(false); - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - }); + auto unclippedColorView = TestUtils::createSkiaNode( + 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + props.setClipToBounds(false); + canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); + }); - auto clippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - }); + auto clippedColorView = TestUtils::createSkiaNode( + 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); + }); ColorTestCanvas canvas; RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true); @@ -898,42 +1003,43 @@ TEST(RenderNodeDrawable, renderNode) { static const int CANVAS_HEIGHT = 200; class RenderNodeTestCanvas : public TestCanvasBase { public: - RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) { - } + RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - switch(mDrawCounter++) { - case 0: - EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this)); - EXPECT_EQ(SK_ColorDKGRAY, paint.getColor()); - break; - case 1: - EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this)); - EXPECT_EQ(SK_ColorWHITE, paint.getColor()); - break; - default: - ADD_FAILURE(); + switch (mDrawCounter++) { + case 0: + EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), + TestUtils::getClipBounds(this)); + EXPECT_EQ(SK_ColorDKGRAY, paint.getColor()); + break; + case 1: + EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this)); + EXPECT_EQ(SK_ColorWHITE, paint.getColor()); + break; + default: + ADD_FAILURE(); } } }; - auto child = TestUtils::createSkiaNode(10, 10, 110, 110, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); + auto child = TestUtils::createSkiaNode( + 10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + SkPaint paint; + paint.setColor(SK_ColorWHITE); + canvas.drawRect(0, 0, 100, 100, paint); + }); - auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + auto parent = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint); - - canvas.save(SaveFlags::MatrixClip); - canvas.translate(40, 40); - canvas.drawRenderNode(child.get()); - canvas.restore(); - }); + SkPaint paint; + paint.setColor(SK_ColorDKGRAY); + canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint); + + canvas.save(SaveFlags::MatrixClip); + canvas.translate(40, 40); + canvas.drawRenderNode(child.get()); + canvas.restore(); + }); RenderNodeTestCanvas canvas; RenderNodeDrawable drawable(parent.get(), &canvas, true); @@ -941,6 +1047,39 @@ TEST(RenderNodeDrawable, renderNode) { EXPECT_EQ(2, canvas.mDrawCounter); } +// Verify that layers are composed with kLow_SkFilterQuality filter quality. +RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) { + static const int CANVAS_WIDTH = 1; + static const int CANVAS_HEIGHT = 1; + static const int LAYER_WIDTH = 1; + static const int LAYER_HEIGHT = 1; + class FrameTestCanvas : public TestCanvasBase { + public: + FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} + void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) override { + mDrawCounter++; + EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality()); + } + }; + + auto layerNode = TestUtils::createSkiaNode( + 0, 0, LAYER_WIDTH, LAYER_HEIGHT, + [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { + canvas.drawPaint(SkPaint()); + }); + + layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer); + layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT)); + + FrameTestCanvas canvas; + RenderNodeDrawable drawable(layerNode.get(), &canvas, true); + canvas.drawDrawable(&drawable); + EXPECT_EQ(1, canvas.mDrawCounter); //make sure the layer was composed + + // clean up layer pointer, so we can safely destruct RenderNode + layerNode->setLayerSurface(nullptr); +} TEST(ReorderBarrierDrawable, testShadowMatrix) { static const int CANVAS_WIDTH = 100; @@ -952,7 +1091,6 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { static const float CASTER_WIDTH = 20.0f; static const float CASTER_HEIGHT = 20.0f; - class ShadowTestCanvas : public SkCanvas { public: ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {} @@ -976,32 +1114,77 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { // matrix. mDrawCounter++; EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix); - EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X+TRANSLATE_X, CASTER_Y+TRANSLATE_Y), - getTotalMatrix()); + EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y), + getTotalMatrix()); } + protected: int mDrawCounter = 0; }; - auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + auto parent = TestUtils::createSkiaNode( + 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - canvas.translate(TRANSLATE_X, TRANSLATE_Y); - canvas.insertReorderBarrier(true); - - auto node = TestUtils::createSkiaNode(CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, - CASTER_Y + CASTER_HEIGHT, - [](RenderProperties& props, SkiaRecordingCanvas& canvas) { - props.setElevation(42); - props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1); - props.mutableOutline().setShouldClip(true); - }); - canvas.drawRenderNode(node.get()); - canvas.insertReorderBarrier(false); - }); + canvas.translate(TRANSLATE_X, TRANSLATE_Y); + canvas.insertReorderBarrier(true); + + auto node = TestUtils::createSkiaNode( + CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT, + [](RenderProperties& props, SkiaRecordingCanvas& canvas) { + props.setElevation(42); + props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1); + props.mutableOutline().setShouldClip(true); + }); + canvas.drawRenderNode(node.get()); + canvas.insertReorderBarrier(false); + }); - //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection + // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT); RenderNodeDrawable drawable(parent.get(), &canvas, false); canvas.drawDrawable(&drawable); EXPECT_EQ(6, canvas.getIndex()); -}
\ No newline at end of file +} + +// Draw a vector drawable twice but with different bounds and verify correct bounds are used. +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { + static const int CANVAS_WIDTH = 100; + static const int CANVAS_HEIGHT = 200; + class VectorDrawableTestCanvas : public TestCanvasBase { + public: + VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} + void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) override { + const int index = mDrawCounter++; + switch (index) { + case 0: + EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT)); + break; + case 1: + EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT)); + break; + default: + ADD_FAILURE(); + } + } + }; + + VectorDrawable::Group* group = new VectorDrawable::Group(); + sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group)); + vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10); + + auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + [&](RenderProperties& props, SkiaRecordingCanvas& canvas) { + vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH, + CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2, + CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + }); + + VectorDrawableTestCanvas canvas; + RenderNodeDrawable drawable(node.get(), &canvas, true); + canvas.drawDrawable(&drawable); + EXPECT_EQ(2, canvas.mDrawCounter); +} |