diff options
| author | 2016-11-04 10:46:18 -0400 | |
|---|---|---|
| committer | 2016-11-07 10:05:56 -0500 | |
| commit | b7d34b64dd32e3d84bd43344c9c3d9ad098129af (patch) | |
| tree | bf7125fc5a53b95f4bffd81cc724eef6b478e5fa | |
| parent | 3d36fac2350cbce6dbdcd7502dc9adb0210d3d8b (diff) | |
Refactor pin/unpinImages to work across pipelines.
Test: existing CTS tests still pass
Change-Id: Ib2607e9853396bad42f298829b5c5da0d210af32
| -rw-r--r-- | libs/hwui/DisplayList.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 53 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.h | 20 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.cpp | 19 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaPipeline.h | 5 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 20 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/renderthread/IRenderPipeline.h | 3 | ||||
| -rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.cpp | 16 | ||||
| -rw-r--r-- | libs/hwui/renderthread/OpenGLPipeline.h | 3 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 2 |
12 files changed, 78 insertions, 75 deletions
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 5213d4857e5b..5e4a7f7a8d2f 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 @@ void DisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) { 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 c734097e12c6..4abaa90974a6 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 @@ void SkiaDisplayList::syncContents() { } 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 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) 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 @@ bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLa 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 734aae4a968e..f34b48541953 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -51,7 +51,7 @@ public: * 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 @@ public: 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 @@ public: 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 03fa266a5c20..69e603b6c927 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -46,6 +46,22 @@ void SkiaPipeline::onDestroyHardwareResources() { // 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 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli 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 160046af63a6..877a3538254c 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -34,6 +34,10 @@ public: 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 @@ protected: 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 ecc6d5115eda..621816add1ed 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -41,7 +41,7 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in } 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 b61eef21087a..c322efb183a9 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -80,6 +80,26 @@ public: } /** + * 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 e3b6dc6fd9fe..4ff54a5299f8 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -119,7 +119,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) { 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 52894adf987b..0e4000b09e1a 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -73,6 +73,9 @@ public: 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 cca0fca41817..afeeef86d22c 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.cpp +++ b/libs/hwui/renderthread/OpenGLPipeline.cpp @@ -31,7 +31,8 @@ namespace uirenderer { namespace renderthread { OpenGLPipeline::OpenGLPipeline(RenderThread& thread) - : mEglManager(thread.eglManager()), mRenderThread(thread) { + : mEglManager(thread.eglManager()) + , mRenderThread(thread) { } MakeCurrentResult OpenGLPipeline::makeCurrent() { @@ -222,6 +223,19 @@ bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node, 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 8722d5983ff9..6df8be477e9c 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.h +++ b/libs/hwui/renderthread/OpenGLPipeline.h @@ -55,6 +55,9 @@ public: 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 fe6cea6dfb4b..67fb78a69c9a 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -58,7 +58,7 @@ TEST(SkiaDisplayList, reset) { 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()); |