Refactor pin/unpinImages to work across pipelines.
Test: existing CTS tests still pass
Change-Id: Ib2607e9853396bad42f298829b5c5da0d210af32
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 5213d48..5e4a7f7 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -25,6 +25,7 @@
#include "RecordedOp.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
+#include "renderthread/CanvasContext.h"
namespace android {
namespace uirenderer {
@@ -105,11 +106,8 @@
bool DisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
- TextureCache& cache = Caches::getInstance().textureCache;
- for (auto& bitmapResource : bitmapResources) {
- void* ownerToken = &info.canvasContext;
- info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource.get());
- }
+ info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
+
for (auto&& op : children) {
RenderNode* childNode = op->renderNode;
info.damageAccumulator->pushTransform(&op->localMatrix);
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index c734097e..4abaa90 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -20,7 +20,7 @@
#include "VectorDrawable.h"
#include <SkImagePriv.h>
-#include <SkMutex.h>
+
namespace android {
namespace uirenderer {
@@ -40,7 +40,7 @@
}
bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
- reset(context ? context->getGrContext() : nullptr, SkRect::MakeEmpty());
+ reset(SkRect::MakeEmpty());
node->attachAvailableList(this);
return true;
}
@@ -53,9 +53,12 @@
bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
- // force all mutable images to be pinned in the GPU cache for the duration
- // of this frame
- pinImages(info.canvasContext.getGrContext());
+ // If the prepare tree is triggered by the UI thread then we must force all
+ // mutable images to be pinned in the GPU cache until the next UI thread
+ // draw
+ if (info.mode == TreeInfo::MODE_FULL) {
+ info.prepareTextures = info.canvasContext.pinImages(mMutableImages);
+ }
for (auto& child : mChildNodes) {
RenderNode* childNode = child.getRenderNode();
@@ -78,45 +81,7 @@
return isDirty;
}
-static std::vector<sk_sp<SkImage>> gPinnedImages;
-static SkBaseMutex gLock;
-
-void SkiaDisplayList::pinImages(GrContext* context) {
- if (mPinnedImages) return;
- for (SkImage* image : mMutableImages) {
- SkImage_pinAsTexture(image, context);
- }
- mPinnedImages = true;
-}
-
-void SkiaDisplayList::unpinImages(GrContext* context) {
- if (!mPinnedImages) return;
- if (context) {
- for (SkImage* image : mMutableImages) {
- SkImage_unpinAsTexture(image, context);
- }
- } else {
- gLock.acquire();
- for (SkImage* image : mMutableImages) {
- gPinnedImages.emplace_back(sk_ref_sp(image));
- }
- gLock.release();
- }
- mPinnedImages = false;
-}
-
-void SkiaDisplayList::cleanupImages(GrContext* context) {
- gLock.acquire();
- for (auto& image : gPinnedImages) {
- SkImage_unpinAsTexture(image.get(), context);
- }
- gPinnedImages.clear();
- gLock.release();
-}
-
-void SkiaDisplayList::reset(GrContext* context, SkRect bounds) {
- unpinImages(context);
- SkASSERT(!mPinnedImages);
+void SkiaDisplayList::reset(SkRect bounds) {
mIsProjectionReceiver = false;
mDrawable->reset(bounds);
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 734aae4a..f34b485 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -51,7 +51,7 @@
* constructed with the provided bounds. The reuse avoids any overhead
* associated with destroying the SkLiteDL as well as the deques and vectors.
*/
- void reset(GrContext* context, SkRect bounds);
+ void reset(SkRect bounds);
/**
* Use the linear allocator to create any SkDrawables needed by the display
@@ -119,21 +119,6 @@
void updateChildren(std::function<void(RenderNode*)> updateFn) override;
/**
- * Pin/Unpin any mutable images to the GPU cache. A pinned images is
- * guaranteed to be remain in the cache until it has been unpinned which
- * we leverage to avoid making a CPU copy of the pixels.
- */
- void pinImages(GrContext* context);
- void unpinImages(GrContext* context);
-
- /**
- * If a SkiaDisplayList is deleted on the UI thread we cache a list of any
- * images that need unpinned from the GPU cache and call this function on
- * a subsequent frame to perform that cleanup.
- */
- static void cleanupImages(GrContext* context);
-
- /**
* We use std::deque here because (1) we need to iterate through these
* elements and (2) mDrawable holds pointers to the elements, so they cannot
* relocate.
@@ -145,9 +130,6 @@
sk_sp<SkLiteDL> mDrawable;
bool mIsProjectionReceiver = false;
-
-private:
- bool mPinnedImages = false;
};
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 03fa266..69e603b 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -46,6 +46,22 @@
// which will flush temporary resources over time.
}
+bool SkiaPipeline::pinImages(std::vector<SkImage*>& mutableImages) {
+ for (SkImage* image : mutableImages) {
+ mPinnedImages.emplace_back(sk_ref_sp(image));
+ // TODO: return false if texture creation fails (see b/32691999)
+ SkImage_pinAsTexture(image, mRenderThread.getGrContext());
+ }
+ return true;
+}
+
+void SkiaPipeline::unpinImages() {
+ for (auto& image : mPinnedImages) {
+ SkImage_unpinAsTexture(image.get(), mRenderThread.getGrContext());
+ }
+ mPinnedImages.clear();
+}
+
void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const BakedOpRenderer::LightInfo& lightInfo) {
@@ -154,9 +170,6 @@
const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
sk_sp<SkSurface> surface) {
- // unpin all mutable images that were attached to nodes deleted while on the UI thread
- SkiaDisplayList::cleanupImages(surface->getCanvas()->getGrContext());
-
// 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 160046a..877a353 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -34,6 +34,10 @@
void onDestroyHardwareResources() override;
+ bool pinImages(std::vector<SkImage*>& mutableImages) override;
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; }
+ void unpinImages() override;
+
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const BakedOpRenderer::LightInfo& lightInfo) override;
@@ -101,6 +105,7 @@
private:
TaskManager mTaskManager;
+ std::vector<sk_sp<SkImage>> mPinnedImages;
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 ecc6d51..621816a 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -41,7 +41,7 @@
}
SkRect bounds = SkRect::MakeWH(width, height);
if (mDisplayList) {
- mDisplayList->reset(nullptr, bounds);
+ mDisplayList->reset(bounds);
} else {
mDisplayList.reset(new SkiaDisplayList(bounds));
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index b61eef2..c322efb 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -80,6 +80,26 @@
}
/**
+ * Pin any mutable images to the GPU cache. A pinned images is guaranteed to
+ * remain in the cache until it has been unpinned. We leverage this feature
+ * to avoid making a CPU copy of the pixels.
+ *
+ * @return true if the images have been successfully pinned to the GPU cache
+ * and false otherwise (e.g. cache limits have been exceeded).
+ */
+ bool pinImages(std::vector<SkImage*>& mutableImages) {
+ return mRenderPipeline->pinImages(mutableImages);
+ }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+ return mRenderPipeline->pinImages(images);
+ }
+
+ /**
+ * Unpin any image that had be previously pinned to the GPU cache
+ */
+ void unpinImages() { mRenderPipeline->unpinImages(); }
+
+ /**
* Destroy any layers that have been attached to the provided RenderNode removing
* any state that may have been set during createOrUpdateLayer().
*/
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index e3b6dc6..4ff54a5 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -119,7 +119,7 @@
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
mRenderThread->timeLord().vsyncReceived(vsync);
bool canDraw = mContext->makeCurrent();
- Caches::getInstance().textureCache.resetMarkInUse(mContext);
+ mContext->unpinImages();
for (size_t i = 0; i < mLayers.size(); i++) {
mLayers[i]->apply();
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 52894ad..0e4000b 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -73,6 +73,9 @@
virtual TaskManager* getTaskManager() = 0;
virtual bool createOrUpdateLayer(RenderNode* node,
const DamageAccumulator& damageAccumulator) = 0;
+ virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
+ virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
+ virtual void unpinImages() = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index cca0fca..afeeef8 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -31,7 +31,8 @@
namespace renderthread {
OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
- : mEglManager(thread.eglManager()), mRenderThread(thread) {
+ : mEglManager(thread.eglManager())
+ , mRenderThread(thread) {
}
MakeCurrentResult OpenGLPipeline::makeCurrent() {
@@ -222,6 +223,19 @@
return transformUpdateNeeded;
}
+bool OpenGLPipeline::pinImages(LsaVector<sk_sp<Bitmap>>& images) {
+ TextureCache& cache = Caches::getInstance().textureCache;
+ bool prefetchSucceeded = true;
+ for (auto& bitmapResource : images) {
+ prefetchSucceeded &= cache.prefetchAndMarkInUse(this, bitmapResource.get());
+ }
+ return prefetchSucceeded;
+}
+
+void OpenGLPipeline::unpinImages() {
+ Caches::getInstance().textureCache.resetMarkInUse(this);
+}
+
void OpenGLPipeline::destroyLayer(RenderNode* node) {
if (OffscreenBuffer* layer = node->getLayer()) {
layer->renderState.layerPool().putOrDelete(layer);
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 8722d59..6df8be4 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -55,6 +55,9 @@
TaskManager* getTaskManager() override;
bool createOrUpdateLayer(RenderNode* node,
const DamageAccumulator& damageAccumulator) override;
+ bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
+ void unpinImages() override;
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
static void invokeFunctor(const RenderThread& thread, Functor* functor);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index fe6cea6..67fb78a 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -58,7 +58,7 @@
ASSERT_TRUE(skiaDL.mIsProjectionReceiver);
bounds = SkRect::MakeWH(100, 100);
- skiaDL.reset(nullptr, bounds);
+ skiaDL.reset(bounds);
ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
ASSERT_TRUE(skiaDL.mChildNodes.empty());