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

Commit 23c38a9e authored by Stan Iliev's avatar Stan Iliev
Browse files

Update VectorDrawables cache at frame start

Draw VectorDrawables in GPU backed surface. Render VD cache
at the beginning of the frame to avoid context switching.

Test: CTS graphics tests pass.
Change-Id: Ia14e0ec4049c3fa87f03547fbda44043bf8dd793
parent 4110be3a
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -491,6 +491,36 @@ Bitmap& Tree::getBitmapUpdateIfDirty() {
    return *mCache.bitmap;
}

void Tree::updateCache(sk_sp<SkSurface> surface) {
    if (surface.get()) {
        mCache.surface = surface;
    }
    if (surface.get() || mCache.dirty) {
        SkSurface* vdSurface = mCache.surface.get();
        SkCanvas* canvas = vdSurface->getCanvas();
        float scaleX = vdSurface->width() / mProperties.getViewportWidth();
        float scaleY = vdSurface->height() / mProperties.getViewportHeight();
        SkAutoCanvasRestore acr(canvas, true);
        canvas->clear(SK_ColorTRANSPARENT);
        canvas->scale(scaleX, scaleY);
        mRootNode->draw(canvas, false);
        mCache.dirty = false;
        canvas->flush();
    }
}

void Tree::draw(SkCanvas* canvas) {
   /*
    * TODO address the following...
    *
    * 1) figure out how to set path's as volatile during animation
    * 2) if mRoot->getPaint() != null either promote to layer (during
    *    animation) or cache in SkSurface (for static content)
    */
    canvas->drawImageRect(mCache.surface->makeImageSnapshot().get(),
        mutateProperties()->getBounds(), getPaint());
}

void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
    SkBitmap outCache;
    bitmap.getSkBitmap(&outCache);
+24 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <SkPathMeasure.h>
#include <SkRect.h>
#include <SkShader.h>
#include <SkSurface.h>

#include <cutils/compiler.h>
#include <stddef.h>
@@ -677,15 +678,37 @@ public:
    // This should only be called from animations on RT
    TreeProperties* mutateProperties() { return &mProperties; }

    // called from RT only
    const TreeProperties& properties() const { return mProperties; }

    // This should always be called from RT.
    void markDirty() { mCache.dirty = true; }
    bool isDirty() const { return mCache.dirty; }
    bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
    void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }

    // Returns true if VD cache surface is big enough. This should always be called from RT and it
    // works with Skia pipelines only.
    bool canReuseSurface() {
        SkSurface* surface = mCache.surface.get();
        return surface && surface->width() >= mProperties.getScaledWidth()
              && surface->height() >= mProperties.getScaledHeight();
    }

    // Draws VD cache into a canvas. This should always be called from RT and it works with Skia
    // pipelines only.
    void draw(SkCanvas* canvas);

    // Draws VD into a GPU backed surface. If canReuseSurface returns false, then "surface" must
    // contain a new surface. This should always be called from RT and it works with Skia pipelines
    // only.
    void updateCache(sk_sp<SkSurface> surface);

private:
    struct Cache {
        sk_sp<Bitmap> bitmap;
        sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
        //TODO: use surface instead of bitmap when drawing in software canvas
        sk_sp<SkSurface> surface; //used only by Skia pipelines
        bool dirty = true;
    };

+3 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "renderthread/CanvasContext.h"
#include "VectorDrawable.h"
#include "DumpOpsCanvas.h"
#include "SkiaPipeline.h"

#include <SkImagePriv.h>

@@ -92,6 +93,8 @@ bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& i
        // If any vector drawable in the display list needs update, damage the node.
        if (vectorDrawable->isDirty()) {
            isDirty = true;
            static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
                ->getVectorDrawables()->push_back(vectorDrawable);
        }
        vectorDrawable->setPropertyChangeWillBeConsumed(true);
    }
+30 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <SkPictureRecorder.h>
#include <SkPixelSerializer.h>
#include <SkStream.h>
#include "VectorDrawable.h"

#include <unistd.h>

@@ -40,7 +41,9 @@ uint8_t SkiaPipeline::mSpotShadowAlpha = 0;

Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};

SkiaPipeline::SkiaPipeline(RenderThread& thread) :  mRenderThread(thread) { }
SkiaPipeline::SkiaPipeline(RenderThread& thread) :  mRenderThread(thread) {
    mVectorDrawables.reserve(30);
}

TaskManager* SkiaPipeline::getTaskManager() {
    return &mTaskManager;
@@ -74,6 +77,7 @@ void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry
        const BakedOpRenderer::LightInfo& lightInfo) {
    updateLighting(lightGeometry, lightInfo);
    ATRACE_NAME("draw layers");
    renderVectorDrawableCache();
    renderLayersImpl(*layerUpdateQueue, opaque);
    layerUpdateQueue->clear();
}
@@ -176,10 +180,35 @@ public:
    }
};

void SkiaPipeline::renderVectorDrawableCache() {
    //render VectorDrawables into offscreen buffers
    for (auto vd : mVectorDrawables) {
        sk_sp<SkSurface> surface;
        if (!vd->canReuseSurface()) {
#ifndef ANDROID_ENABLE_LINEAR_BLENDING
            sk_sp<SkColorSpace> colorSpace = nullptr;
#else
            sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
#endif
            int scaledWidth = SkScalarCeilToInt(vd->properties().getScaledWidth());
            int scaledHeight = SkScalarCeilToInt(vd->properties().getScaledHeight());
            SkImageInfo info = SkImageInfo::MakeN32(scaledWidth, scaledHeight,
                    kPremul_SkAlphaType, colorSpace);
            SkASSERT(mRenderThread.getGrContext() != nullptr);
            surface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
                    info);
        }
        vd->updateCache(surface);
    }
    mVectorDrawables.clear();
}

void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
        const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
        sk_sp<SkSurface> surface) {

    renderVectorDrawableCache();

    // draw all layers up front
    renderLayersImpl(layers, opaque);

+12 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ public:
            const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
            sk_sp<SkSurface> surface);

    std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }

    static void destroyLayer(RenderNode* node);

    static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
@@ -119,8 +121,18 @@ private:
            const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
            sk_sp<SkSurface>);

    /**
     *  Render mVectorDrawables into offscreen buffers.
     */
    void renderVectorDrawableCache();

    TaskManager mTaskManager;
    std::vector<sk_sp<SkImage>> mPinnedImages;

    /**
     *  populated by prepareTree with dirty VDs
     */
    std::vector<VectorDrawableRoot*> mVectorDrawables;
    static float mLightRadius;
    static uint8_t mAmbientShadowAlpha;
    static uint8_t mSpotShadowAlpha;
Loading