Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aafb01d8 authored by Chris Craik's avatar Chris Craik
Browse files

Consume TextureView matrix safely

Fixes: 27825042

TextureView's matrix may not be set at record time - delay using it
until on RenderThread, when deferring the op.

Change-Id: Icf8b55d656e304ec049ca803b042dc2359482db2
parent 83b9db02
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -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);
}
+8 −0
Original line number Diff line number Diff line
@@ -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;
};

+1 −7
Original line number Diff line number Diff line
@@ -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()));
}
+1 −0
Original line number Diff line number Diff line
@@ -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);
+48 −3
Original line number Diff line number Diff line
@@ -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:
Loading