diff options
-rw-r--r-- | libs/hwui/VectorDrawable.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/VectorDrawable.h | 25 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.cpp | 31 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.h | 12 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 2 |
7 files changed, 102 insertions, 18 deletions
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp index 8823a9212958..f6b2912a6254 100644 --- a/libs/hwui/VectorDrawable.cpp +++ b/libs/hwui/VectorDrawable.cpp @@ -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); diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index 729a4dd4ba76..22cfe29d2aa5 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -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; }; diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 496f7babd3cc..3ddc09fbeca1 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -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); } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 10c1865ac50c..75f1adc7755c 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -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); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index c58fedf834ff..6f5e719fc2c2 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -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; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 559d268b71f7..27edc2511a19 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -126,22 +126,7 @@ class VectorDrawable : public SkDrawable { return SkRect::MakeLargest(); } virtual void onDraw(SkCanvas* canvas) override { - Bitmap& hwuiBitmap = mRoot->getBitmapUpdateIfDirty(); - SkBitmap bitmap; - hwuiBitmap.getSkBitmap(&bitmap); - SkPaint* paint = mRoot->getPaint(); - canvas->drawBitmapRect(bitmap, mRoot->mutateProperties()->getBounds(), paint); - /* - * TODO we can draw this directly but need to address the following... - * - * 1) Add drawDirect(SkCanvas*) to VectorDrawableRoot - * 2) fix VectorDrawable.cpp's Path::draw to not make a temporary path - * so that we don't break caching - * 3) figure out how to set path's as volatile during animation - * 4) if mRoot->getPaint() != null either promote to layer (during - * animation) or cache in SkSurface (for static content) - * - */ + mRoot->draw(canvas); } private: diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 738c09141a7a..33eda96a2d77 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -194,6 +194,8 @@ public: void waitOnFences(); + IRenderPipeline* getRenderPipeline() { return mRenderPipeline.get(); } + private: CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); |