diff options
| -rw-r--r-- | libs/hwui/FrameBuilder.cpp | 12 | ||||
| -rw-r--r-- | libs/hwui/RecordedOp.h | 8 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/tests/common/TestUtils.cpp | 1 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/FrameBuilderTests.cpp | 51 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/RecordingCanvasTests.cpp | 22 |
6 files changed, 91 insertions, 11 deletions
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 0ebb8866bdb3..b1314feebf34 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -699,7 +699,17 @@ void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) { if (CC_UNLIKELY(!op.layer->isRenderable())) return; - BakedOpState* bakedState = tryBakeOpState(op); + + const TextureLayerOp* textureLayerOp = &op; + // Now safe to access transform (which was potentially unready at record time) + if (!op.layer->getTransform().isIdentity()) { + // non-identity transform present, so 'inject it' into op by copying + replacing matrix + Matrix4 combinedMatrix(op.localMatrix); + combinedMatrix.multiply(op.layer->getTransform()); + textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix); + } + BakedOpState* bakedState = tryBakeOpState(*textureLayerOp); + if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); } diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 64c604a5ee44..0271a80d4c17 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -419,6 +419,14 @@ struct TextureLayerOp : RecordedOp { TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer) : SUPER_PAINTLESS(TextureLayerOp) , layer(layer) {} + + // Copy an existing TextureLayerOp, replacing the underlying matrix + TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix) + : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix, + op.localClip, op.paint) + , layer(op.layer) { + + } Layer* layer; }; diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index f43dadeca034..4f9cd688d4b6 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -576,15 +576,9 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { // Note that the backing layer has *not* yet been updated, so don't trust // its width, height, transform, etc...! - Matrix4 totalTransform(*(mState.currentSnapshot()->transform)); - if (layerHandle->getTransform()) { - Matrix4 layerTransform(*layerHandle->getTransform()); - totalTransform.multiply(layerTransform); - } - addOp(alloc().create_trivial<TextureLayerOp>( Rect(layerHandle->getWidth(), layerHandle->getHeight()), - totalTransform, + *(mState.currentSnapshot()->transform), getRecordedClip(), layerHandle->backingLayer())); } diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 059e9ae56a21..c762eed616e4 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -44,6 +44,7 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( renderthread::RenderThread& renderThread, uint32_t width, uint32_t height, const SkMatrix& transform) { Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState()); + layer->getTransform().load(transform); sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer); layerUpdater->setSize(width, height); diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index dca56d425f3a..e97aaa6ac688 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -372,8 +372,8 @@ RENDERTHREAD_TEST(FrameBuilder, textStyle) { EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops"; } -RENDERTHREAD_TEST(FrameBuilder, textureLayer) { - class TextureLayerTestRenderer : public TestRendererBase { +RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) { + class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase { public: void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { EXPECT_EQ(0, mIndex++); @@ -398,11 +398,56 @@ RENDERTHREAD_TEST(FrameBuilder, textureLayer) { }); FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance()); - TextureLayerTestRenderer renderer; + TextureLayerClipLocalMatrixTestRenderer renderer; frameBuilder.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(1, renderer.getIndex()); } +RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) { + class TextureLayerCombineMatricesTestRenderer : public TestRendererBase { + public: + void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); + + Matrix4 expected; + expected.loadTranslate(35, 45, 0); + EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); + } + }; + + auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100, + SkMatrix::MakeTrans(5, 5)); + + auto node = TestUtils::createNode(0, 0, 200, 200, + [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { + canvas.save(SaveFlags::MatrixClip); + canvas.translate(30, 40); + canvas.drawLayer(layerUpdater.get()); + canvas.restore(); + }); + + FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance()); + TextureLayerCombineMatricesTestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(1, renderer.getIndex()); +} + +RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) { + auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100, + SkMatrix::MakeTrans(5, 5)); + layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected + + auto node = TestUtils::createNode(0, 0, 200, 200, + [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { + canvas.drawLayer(layerUpdater.get()); + }); + FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance()); + FailRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); +} + RENDERTHREAD_TEST(FrameBuilder, functor_reject) { class FunctorTestRenderer : public TestRendererBase { public: diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index 33108c75e97d..58376c64d518 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -16,6 +16,7 @@ #include <gtest/gtest.h> +#include <DeferredLayerUpdater.h> #include <RecordedOp.h> #include <RecordingCanvas.h> #include <hwui/Paint.h> @@ -39,6 +40,12 @@ static void playbackOps(const DisplayList& displayList, } } +static void validateSingleOp(std::unique_ptr<DisplayList>& dl, + std::function<void(const RecordedOp& op)> opValidator) { + ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; + opValidator(*(dl->getOps()[0])); +} + TEST(RecordingCanvas, emptyPlayback) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { canvas.save(SaveFlags::MatrixClip); @@ -284,6 +291,21 @@ TEST(RecordingCanvas, backgroundAndImage) { ASSERT_EQ(2, count); } +RENDERTHREAD_TEST(RecordingCanvas, textureLayer) { + auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100, + SkMatrix::MakeTrans(5, 5)); + + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, + [&layerUpdater](RecordingCanvas& canvas) { + canvas.drawLayer(layerUpdater.get()); + }); + + validateSingleOp(dl, [] (const RecordedOp& op) { + ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId); + ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time."; + }); +} + TEST(RecordingCanvas, saveLayer_simple) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer); |