summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/VectorDrawable.cpp30
-rw-r--r--libs/hwui/VectorDrawable.h25
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp3
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp31
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h12
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp22
-rw-r--r--libs/hwui/renderthread/CanvasContext.h2
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp14
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);
+}