From d3eeddd6df799ad468fa58a631b8b2bbed4bd38c Mon Sep 17 00:00:00 2001 From: Subhransu Mohanty Date: Thu, 25 Jun 2020 16:41:15 +0900 Subject: [PATCH] optimization: added SurfaceCache to reduce intermediate buffers. During rendering layers with mask/matte we need intermediate buffers by keeping the surface cache we can reuse the same buffer for different layer rendering to reduce memory footprint. --- src/lottie/lottieitem.cpp | 47 ++++++++++++++++++++++++----------------------- src/lottie/lottieitem.h | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 8586a69..4791d4f 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -157,7 +157,7 @@ bool LOTCompItem::render(const rlottie::Surface &surface) painter.setDrawRegion( VRect(int(surface.drawRegionPosX()), int(surface.drawRegionPosY()), int(surface.drawRegionWidth()), int(surface.drawRegionHeight()))); - mRootLayer->render(&painter, {}, {}); + mRootLayer->render(&painter, {}, {}, mSurfaceCache); painter.end(); return true; } @@ -200,7 +200,7 @@ void LOTMaskItem::preprocess(const VRect &clip) } void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) + const VRle &matteRle, SurfaceCache& cache) { auto renderlist = renderList(); @@ -468,30 +468,30 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel, VArenaAlloc* alloca } void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) + const VRle &matteRle, SurfaceCache& cache) { if (vIsZero(combinedAlpha())) return; if (vCompare(combinedAlpha(), 1.0)) { - renderHelper(painter, inheritMask, matteRle); + renderHelper(painter, inheritMask, matteRle, cache); } else { if (complexContent()) { VSize size = painter->clipBoundingRect().size(); VPainter srcPainter; - VBitmap srcBitmap(size.width(), size.height(), - VBitmap::Format::ARGB32_Premultiplied); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); srcPainter.begin(&srcBitmap); - renderHelper(&srcPainter, inheritMask, matteRle); + renderHelper(&srcPainter, inheritMask, matteRle, cache); srcPainter.end(); painter->drawBitmap(VPoint(), srcBitmap, uchar(combinedAlpha() * 255.0f)); + cache.release_surface(srcBitmap); } else { - renderHelper(painter, inheritMask, matteRle); + renderHelper(painter, inheritMask, matteRle, cache); } } } void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) + const VRle &matteRle, SurfaceCache& cache) { VRle mask; if (mLayerMask) { @@ -517,9 +517,9 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, if (matte) { if (matte->visible()) renderMatteLayer(painter, mask, matteRle, matte, - layer); + layer, cache); } else { - layer->render(painter, mask, matteRle); + layer->render(painter, mask, matteRle, cache); } } matte = nullptr; @@ -529,24 +529,22 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, const VRle & matteRle, - LOTLayerItem *layer, LOTLayerItem *src) + LOTLayerItem *layer, LOTLayerItem *src, SurfaceCache& cache) { VSize size = painter->clipBoundingRect().size(); // Decide if we can use fast matte. // 1. draw src layer to matte buffer VPainter srcPainter; - src->bitmap().reset(size.width(), size.height(), - VBitmap::Format::ARGB32_Premultiplied); - srcPainter.begin(&src->bitmap()); - src->render(&srcPainter, mask, matteRle); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); + srcPainter.begin(&srcBitmap); + src->render(&srcPainter, mask, matteRle, cache); srcPainter.end(); // 2. draw layer to layer buffer VPainter layerPainter; - layer->bitmap().reset(size.width(), size.height(), - VBitmap::Format::ARGB32_Premultiplied); - layerPainter.begin(&layer->bitmap()); - layer->render(&layerPainter, mask, matteRle); + VBitmap layerBitmap = cache.make_surface(size.width(), size.height()); + layerPainter.begin(&layerBitmap); + layer->render(&layerPainter, mask, matteRle, cache); // 2.1update composition mode switch (layer->matteType()) { @@ -567,14 +565,17 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, // 2.2 update srcBuffer if the matte is luma type if (layer->matteType() == MatteType::Luma || layer->matteType() == MatteType::LumaInv) { - src->bitmap().updateLuma(); + srcBitmap.updateLuma(); } // 2.3 draw src buffer as mask - layerPainter.drawBitmap(VPoint(), src->bitmap()); + layerPainter.drawBitmap(VPoint(), srcBitmap); layerPainter.end(); // 3. draw the result buffer into painter - painter->drawBitmap(VPoint(), layer->bitmap()); + painter->drawBitmap(VPoint(), layerBitmap); + + cache.release_surface(srcBitmap); + cache.release_surface(layerBitmap); } void LOTClipperItem::update(const VMatrix &matrix) diff --git a/src/lottie/lottieitem.h b/src/lottie/lottieitem.h index 7bbed9c..09bc5d5 100644 --- a/src/lottie/lottieitem.h +++ b/src/lottie/lottieitem.h @@ -61,6 +61,31 @@ public: } }; +class SurfaceCache +{ +public: + SurfaceCache(){mCache.reserve(10);} + + VBitmap make_surface(size_t width, size_t height, VBitmap::Format format=VBitmap::Format::ARGB32_Premultiplied) + { + if (mCache.empty()) return {width, height, format}; + + auto surface = mCache.back(); + surface.reset(width, height, format); + + mCache.pop_back(); + return surface; + } + + void release_surface(VBitmap& surface) + { + mCache.push_back(surface); + } + +private: + std::vector mCache; +}; + class LOTCompItem { public: @@ -72,6 +97,7 @@ public: bool render(const rlottie::Surface &surface); void setValue(const std::string &keypath, LOTVariant &value); private: + SurfaceCache mSurfaceCache; VBitmap mSurface; VMatrix mScaleMatrix; VSize mViewSize; @@ -157,7 +183,7 @@ public: VMatrix matrix(int frameNo) const; void preprocess(const VRect& clip); virtual DrawableList renderList(){ return {};} - virtual void render(VPainter *painter, const VRle &mask, const VRle &matteRle); + virtual void render(VPainter *painter, const VRle &mask, const VRle &matteRle, SurfaceCache& cache); bool hasMatte() { if (mLayerData->mMatteType == MatteType::None) return false; return true; } MatteType matteType() const { return mLayerData->mMatteType;} bool visible() const; @@ -168,7 +194,6 @@ public: std::vector& cnodes() {return mCApiData->mCNodeList;} const char* name() const {return mLayerData->name();} virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value); - VBitmap& bitmap() {return mRenderBuffer;} protected: virtual void preprocessStage(const VRect& clip) = 0; virtual void updateContent() = 0; @@ -184,7 +209,6 @@ protected: LOTLayerData *mLayerData{nullptr}; LOTLayerItem *mParentLayer{nullptr}; VMatrix mCombinedMatrix; - VBitmap mRenderBuffer; float mCombinedAlpha{0.0}; int mFrameNo{-1}; DirtyFlag mDirtyFlag{DirtyFlagBit::All}; @@ -197,16 +221,16 @@ class LOTCompLayerItem: public LOTLayerItem public: explicit LOTCompLayerItem(LOTLayerData *layerData, VArenaAlloc* allocator); - void render(VPainter *painter, const VRle &mask, const VRle &matteRle) final; + void render(VPainter *painter, const VRle &mask, const VRle &matteRle, SurfaceCache& cache) final; void buildLayerNode() final; bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override; protected: void preprocessStage(const VRect& clip) final; void updateContent() final; private: - void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle); + void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle, SurfaceCache& cache); void renderMatteLayer(VPainter *painter, const VRle &inheritMask, const VRle &matteRle, - LOTLayerItem *layer, LOTLayerItem *src); + LOTLayerItem *layer, LOTLayerItem *src, SurfaceCache& cache); private: std::vector mLayers; std::unique_ptr mClipper; -- 2.7.4