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

Commit 3a5811b5 authored by Chris Craik's avatar Chris Craik
Browse files

Precache/early kick off of op work for non-shadow ops.

bug:26562703
bug:27052145

Change-Id: Ic452bfe75da849ffdd47fecdd6eb1472fd0c806e
parent 68ffbba1
Loading
Loading
Loading
Loading
+35 −8
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ namespace uirenderer {
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
        uint32_t viewportWidth, uint32_t viewportHeight,
        const std::vector< sp<RenderNode> >& nodes,
        const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches* caches)
        const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches)
        : mCanvasState(*this)
        , mCaches(caches)
        , mLightRadius(lightGeometry.radius) {
@@ -364,15 +364,13 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
        casterPath = frameAllocatedPath;
    }


    if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
        Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
        Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
        node.applyViewPropertyTransforms(shadowMatrixXY, false);
        node.applyViewPropertyTransforms(shadowMatrixZ, true);

        LOG_ALWAYS_FATAL_IF(!mCaches, "Caches needed for shadows");
        sp<TessellationCache::ShadowTask> task = mCaches->tessellationCache.getShadowTask(
        sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask(
                mCanvasState.currentTransform(),
                mCanvasState.getLocalClipBounds(),
                casterAlpha >= 1.0f,
@@ -483,13 +481,14 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
 * Defers an unmergeable, strokeable op, accounting correctly
 * for paint's style on the bounds being computed.
 */
void FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
const BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
        BakedOpState::StrokeBehavior strokeBehavior) {
    // Note: here we account for stroke when baking the op
    BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
            mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
    if (!bakedState) return; // quick rejected
    if (!bakedState) return nullptr; // quick rejected
    currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
    return bakedState;
}

/**
@@ -607,7 +606,10 @@ void FrameBuilder::deferPatchOp(const PatchOp& op) {
}

void FrameBuilder::deferPathOp(const PathOp& op) {
    deferStrokeableOp(op, OpBatchType::Bitmap);
    auto state = deferStrokeableOp(op, OpBatchType::AlphaMaskTexture);
    if (CC_LIKELY(state)) {
        mCaches.pathCache.precache(op.path, op.paint);
    }
}

void FrameBuilder::deferPointsOp(const PointsOp& op) {
@@ -620,7 +622,12 @@ void FrameBuilder::deferRectOp(const RectOp& op) {
}

void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
    deferStrokeableOp(op, tessBatchId(op));
    auto state = deferStrokeableOp(op, tessBatchId(op));
    if (CC_LIKELY(state && !op.paint->getPathEffect())) {
        // TODO: consider storing tessellation task in BakedOpState
        mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint),
                op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
    }
}

void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
@@ -660,12 +667,28 @@ void FrameBuilder::deferTextOp(const TextOp& op) {
    } else {
        currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
    }

    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
    auto& totalTransform = bakedState->computedState.transform;
    if (totalTransform.isPureTranslate() || totalTransform.isPerspective()) {
        fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
    } else {
        // Partial transform case, see BakedOpDispatcher::renderTextOp
        float sx, sy;
        totalTransform.decomposeScale(sx, sy);
        fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale(
                roundf(std::max(1.0f, sx)),
                roundf(std::max(1.0f, sy))));
    }
}

void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
    if (!bakedState) return; // quick rejected
    currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));

    mCaches.fontRenderer.getFontRenderer().precache(
            op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
}

void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
@@ -826,5 +849,9 @@ void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignore
    }
}

void FrameBuilder::finishDefer() {
    mCaches.fontRenderer.endPrecaching();
}

} // namespace uirenderer
} // namespace android
+9 −6
Original line number Diff line number Diff line
@@ -65,14 +65,16 @@ public:
            uint32_t viewportWidth, uint32_t viewportHeight,
            const std::vector< sp<RenderNode> >& nodes,
            const LightGeometry& lightGeometry,
            Caches* caches)
            : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightGeometry, Rect(), caches) {}
            Caches& caches)
            : FrameBuilder(layers, clip, viewportWidth, viewportHeight,
                    nodes, lightGeometry, Rect(), caches) {}

    FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
            uint32_t viewportWidth, uint32_t viewportHeight,
            const std::vector< sp<RenderNode> >& nodes,
            const LightGeometry& lightGeometry,
            const Rect &contentDrawBounds, Caches* caches);
            const Rect &contentDrawBounds,
            Caches& caches);

    virtual ~FrameBuilder() {}

@@ -81,10 +83,10 @@ public:
     *
     * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use
     * state->op->opId to lookup a receiver that will be called when the op is replayed.
     *
     */
    template <typename StaticDispatcher, typename Renderer>
    void replayBakedOps(Renderer& renderer) {
        finishDefer();
        /**
         * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
         * dispatch the op via a method on a static dispatcher when the op is replayed.
@@ -157,6 +159,7 @@ public:
    virtual GLuint getTargetFbo() const override { return 0; }

private:
    void finishDefer();
    enum class ChildrenSelectMode {
        Negative,
        Positive
@@ -198,7 +201,7 @@ private:
        return mAllocator.create<SkPath>();
    }

    void deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
    const BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
            BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);

    /**
@@ -230,7 +233,7 @@ private:

    CanvasState mCanvasState;

    Caches* mCaches = nullptr;
    Caches& mCaches;

    float mLightRadius;

+2 −2
Original line number Diff line number Diff line
@@ -345,10 +345,10 @@ void CanvasContext::draw() {
    mEglManager.damageFrame(frame, dirty);

#if HWUI_NEW_OPS
    auto& caches = Caches::getInstance();
    FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
            mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
            mRenderNodes, mLightGeometry, mContentDrawBounds, caches);
    mLayerUpdateQueue.clear();
    auto&& caches = Caches::getInstance();
    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
            mOpaque, mLightInfo);
    frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 "TestSceneBase.h"
#include "utils/Color.h"

#include <minikin/Layout.h>
#include <hwui/Paint.h>

#include <cstdio>

class GlyphStressAnimation;

static TestScene::Registrar _GlyphStress(TestScene::Info{
    "glyphstress",
    "A stress test for both the glyph cache, and glyph rendering.",
    TestScene::simpleCreateScene<GlyphStressAnimation>
});

class GlyphStressAnimation : public TestScene {
public:
    sp<RenderNode> container;
    void createContent(int width, int height, TestCanvas& canvas) override {
        container = TestUtils::createNode(0, 0, width, height, nullptr);
        doFrame(0); // update container

        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
        canvas.drawRenderNode(container.get());
    }

    void doFrame(int frameNr) override {
        std::unique_ptr<uint16_t[]> text = TestUtils::utf8ToUtf16(
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
        ssize_t textLength = 26 * 2;

        TestCanvas canvas(
                container->stagingProperties().getWidth(),
                container->stagingProperties().getHeight());
        Paint paint;
        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        paint.setAntiAlias(true);
        paint.setColor(Color::Black);
        for (int i = 0; i < 5; i++) {
            paint.setTextSize(10 + (frameNr % 20) + i * 20);
            canvas.drawText(text.get(), 0, textLength, textLength,
                    0, 100 * (i + 2), kBidi_Force_LTR, paint, nullptr);
        }

        container->setStagingDisplayList(canvas.finishRecording());
    }
};
+4 −4
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ void BM_FrameBuilder_defer(benchmark::State& state) {
    auto nodes = createTestNodeList();
    while (state.KeepRunning()) {
        FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
                nodes, sLightGeometry, nullptr);
                nodes, sLightGeometry, Caches::getInstance());
        benchmark::DoNotOptimize(&frameBuilder);
    }
}
@@ -80,7 +80,7 @@ void BM_FrameBuilder_deferAndRender(benchmark::State& state) {

        while (state.KeepRunning()) {
            FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
                    nodes, sLightGeometry, nullptr);
                    nodes, sLightGeometry, Caches::getInstance());

            BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
            frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -119,7 +119,7 @@ void BM_FrameBuilder_defer_scene(benchmark::State& state) {
    while (state.KeepRunning()) {
        FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
                SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
                nodes, sLightGeometry, nullptr);
                nodes, sLightGeometry, Caches::getInstance());
        benchmark::DoNotOptimize(&frameBuilder);
    }
}
@@ -137,7 +137,7 @@ void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
        while (state.KeepRunning()) {
            FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
                    SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
                    nodes, sLightGeometry, nullptr);
                    nodes, sLightGeometry, Caches::getInstance());

            BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
            frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
Loading