diff options
Diffstat (limited to 'libs')
| -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/SkiaDisplayList.h | 2 | ||||
| -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 | 22 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 2 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/SkiaBehaviorTests.cpp | 14 |
9 files changed, 121 insertions, 20 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/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 6ee5922f9cd6..66375d13826c 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -60,7 +60,7 @@ public: * Use the linear allocator to create any SkDrawables needed by the display * list. This could be dangerous as these objects are ref-counted, so we * need to monitor that they don't extend beyond the lifetime of the class - * that creates them. + * that creates them. Allocator dtor invokes all SkDrawable dtors. */ template<class T, typename... Params> SkDrawable* allocateDrawable(Params&&... params) { 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..b3173f2e1974 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -62,6 +62,7 @@ void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* lef uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) { + // Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator. drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry, paint)); } @@ -92,13 +93,14 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) { uirenderer::Layer* layer = layerUpdater->backingLayer(); + // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL. sk_sp<SkDrawable> drawable(new LayerDrawable(layer)); drawDrawable(drawable.get()); } } void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { - // record the child node + // Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared. mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier); auto& renderNodeDrawable = mDisplayList->mChildNodes.back(); drawDrawable(&renderNodeDrawable); @@ -113,6 +115,7 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) { + // Drawable dtor will be invoked when mChildFunctors deque is cleared. mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas()); drawDrawable(&mDisplayList->mChildFunctors.back()); } @@ -126,22 +129,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); diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp index 7ae58a68a76c..e15f5d95fc51 100644 --- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp +++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp @@ -17,6 +17,7 @@ #include "tests/common/TestUtils.h" #include <gtest/gtest.h> +#include <SkBlurDrawLooper.h> #include <SkColorMatrixFilter.h> #include <SkColorSpace.h> #include <SkImagePriv.h> @@ -95,3 +96,16 @@ TEST(SkiaBehavior, srgbColorSpaceIsSingleton) { sk_sp<SkColorSpace> sRGB2 = SkColorSpace::MakeSRGB(); ASSERT_EQ(sRGB1.get(), sRGB2.get()); } + +TEST(SkiaBehavior, blurDrawLooper) { + sk_sp<SkDrawLooper> looper = SkBlurDrawLooper::Make(SK_ColorRED, 5.0f, 3.0f, 4.0f); + + SkDrawLooper::BlurShadowRec blur; + bool success = looper->asABlurShadow(&blur); + ASSERT_TRUE(success); + + ASSERT_EQ(SK_ColorRED, blur.fColor); + ASSERT_EQ(5.0f, blur.fSigma); + ASSERT_EQ(3.0f, blur.fOffset.fX); + ASSERT_EQ(4.0f, blur.fOffset.fY); +} |