summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Stan Iliev <stani@google.com> 2017-03-23 00:12:50 -0400
committer Stan Iliev <stani@google.com> 2017-03-27 18:43:34 -0400
commit23c38a9ed9c28a9fda438e7d30532aad7a3844f7 (patch)
tree50c757670e0691327a730a8fc457f1cd7135594b
parent4110be3a153daed2d62a549a36e9f92986addf29 (diff)
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
-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/SkiaPipeline.cpp31
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h12
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp17
-rw-r--r--libs/hwui/renderthread/CanvasContext.h2
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);