OSDN Git Service

Use LinearStdAllocator in DisplayList
authorChris Craik <ccraik@google.com>
Fri, 16 Oct 2015 21:23:12 +0000 (14:23 -0700)
committerChris Craik <ccraik@google.com>
Mon, 19 Oct 2015 18:32:28 +0000 (11:32 -0700)
bug:24300128

This removes most of the remaining calls to malloc when
recording DisplayLists.

Change-Id: If928bd53dac0f145aadc436a62759086b67da0ed

libs/hwui/DisplayList.cpp
libs/hwui/DisplayList.h
libs/hwui/DisplayListCanvas.cpp
libs/hwui/OpReorderer.cpp
libs/hwui/OpReorderer.h
libs/hwui/RecordingCanvas.cpp
libs/hwui/RenderNode.cpp
libs/hwui/microbench/DisplayListCanvasBench.cpp
libs/hwui/unit_tests/OpReordererTests.cpp
libs/hwui/unit_tests/RecordingCanvasTests.cpp
libs/hwui/utils/LinearAllocator.h

index 4eb7066..59f0d7c 100644 (file)
@@ -34,6 +34,17 @@ namespace uirenderer {
 
 DisplayList::DisplayList()
         : projectionReceiveIndex(-1)
+        , stdAllocator(allocator)
+        , chunks(stdAllocator)
+        , ops(stdAllocator)
+        , children(stdAllocator)
+        , bitmapResources(stdAllocator)
+        , pathResources(stdAllocator)
+        , patchResources(stdAllocator)
+        , paints(stdAllocator)
+        , regions(stdAllocator)
+        , referenceHolders(stdAllocator)
+        , functors(stdAllocator)
         , hasDrawOps(false) {
 }
 
@@ -68,9 +79,9 @@ void DisplayList::cleanupResources() {
 }
 
 size_t DisplayList::addChild(NodeOpType* op) {
-    mReferenceHolders.push_back(op->renderNode);
-    size_t index = mChildren.size();
-    mChildren.push_back(op);
+    referenceHolders.push_back(op->renderNode);
+    size_t index = children.size();
+    children.push_back(op);
     return index;
 }
 
index d32406f..86796c5 100644 (file)
@@ -132,32 +132,22 @@ public:
     DisplayList();
     ~DisplayList();
 
-    // pointers to all ops within display list, pointing into allocator data
-    std::vector<DisplayListOp*> displayListOps;
-
     // index of DisplayListOp restore, after which projected descendents should be drawn
     int projectionReceiveIndex;
 
-    std::vector<const SkBitmap*> bitmapResources;
-    std::vector<const SkPath*> pathResources;
-    std::vector<const Res_png_9patch*> patchResources;
+    const LsaVector<Chunk>& getChunks() const { return chunks; }
+    const LsaVector<BaseOpType*>& getOps() const { return ops; }
 
-    std::vector<std::unique_ptr<const SkPaint>> paints;
-    std::vector<std::unique_ptr<const SkRegion>> regions;
-    Vector<Functor*> functors;
+    const LsaVector<NodeOpType*>& getChildren() const { return children; }
 
-    const std::vector<Chunk>& getChunks() const {
-            return chunks;
-    }
-    const std::vector<BaseOpType*>& getOps() const {
-        return ops;
-    }
+    const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
+    const LsaVector<Functor*>& getFunctors() const { return functors; }
 
     size_t addChild(NodeOpType* childOp);
-    const std::vector<NodeOpType*>& children() { return mChildren; }
+
 
     void ref(VirtualLightRefBase* prop) {
-        mReferenceHolders.push_back(prop);
+        referenceHolders.push_back(prop);
     }
 
     size_t getUsedSize() {
@@ -168,17 +158,27 @@ public:
     }
 
 private:
-    std::vector<BaseOpType*> ops;
+    // allocator into which all ops and LsaVector arrays allocated
+    LinearAllocator allocator;
+    LinearStdAllocator<void*> stdAllocator;
 
-    std::vector< sp<VirtualLightRefBase> > mReferenceHolders;
+    LsaVector<Chunk> chunks;
+    LsaVector<BaseOpType*> ops;
 
-    // list of children display lists for quick, non-drawing traversal
-    std::vector<NodeOpType*> mChildren;
+    // list of Ops referring to RenderNode children for quick, non-drawing traversal
+    LsaVector<NodeOpType*> children;
 
-    std::vector<Chunk> chunks;
+    // Resources - Skia objects + 9 patches referred to by this DisplayList
+    LsaVector<const SkBitmap*> bitmapResources;
+    LsaVector<const SkPath*> pathResources;
+    LsaVector<const Res_png_9patch*> patchResources;
+    LsaVector<std::unique_ptr<const SkPaint>> paints;
+    LsaVector<std::unique_ptr<const SkRegion>> regions;
+    LsaVector< sp<VirtualLightRefBase> > referenceHolders;
+
+    // List of functors
+    LsaVector<Functor*> functors;
 
-    // allocator into which all ops were allocated
-    LinearAllocator allocator;
     bool hasDrawOps;
 
     void cleanupResources();
index f49482b..bad3972 100644 (file)
@@ -82,7 +82,7 @@ DisplayList* DisplayListCanvas::finishRecording() {
 
 void DisplayListCanvas::callDrawGLFunction(Functor *functor) {
     addDrawOp(new (alloc()) DrawFunctorOp(functor));
-    mDisplayList->functors.add(functor);
+    mDisplayList->functors.push_back(functor);
 }
 
 SkCanvas* DisplayListCanvas::asSkCanvas() {
@@ -528,7 +528,7 @@ size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) {
         newChunk.endOpIndex = insertIndex + 1;
         newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
 
-        int nextChildIndex = mDisplayList->children().size();
+        int nextChildIndex = mDisplayList->children.size();
         newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
         mDeferredBarrierType = kBarrier_None;
     } else {
index 7c34992..7c0e257 100644 (file)
@@ -225,18 +225,17 @@ void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeigh
         if (node->applyViewProperties(mCanvasState)) {
             // not rejected do ops...
             const DisplayList& displayList = node->getDisplayList();
-            deferImpl(displayList.getChunks(), displayList.getOps());
+            deferImpl(displayList);
         }
         mCanvasState.restore();
     }
 }
 
-void OpReorderer::defer(int viewportWidth, int viewportHeight,
-        const std::vector<DisplayList::Chunk>& chunks, const std::vector<RecordedOp*>& ops) {
+void OpReorderer::defer(int viewportWidth, int viewportHeight, const DisplayList& displayList) {
     ATRACE_NAME("prepare drawing commands");
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             0, 0, viewportWidth, viewportHeight, Vector3());
-    deferImpl(chunks, ops);
+    deferImpl(displayList);
 }
 
 /**
@@ -247,14 +246,13 @@ void OpReorderer::defer(int viewportWidth, int viewportHeight,
  */
 #define OP_RECIEVER(Type) \
         [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
-void OpReorderer::deferImpl(const std::vector<DisplayList::Chunk>& chunks,
-        const std::vector<RecordedOp*>& ops) {
+void OpReorderer::deferImpl(const DisplayList& displayList) {
     static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
         MAP_OPS(OP_RECIEVER)
     };
-    for (const DisplayList::Chunk& chunk : chunks) {
+    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
         for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
-            const RecordedOp* op = ops[opIndex];
+            const RecordedOp* op = displayList.getOps()[opIndex];
             receivers[op->opId](*this, *op);
         }
     }
@@ -288,8 +286,7 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
     // apply RenderProperties state
     if (op.renderNode->applyViewProperties(mCanvasState)) {
         // not rejected do ops...
-        const DisplayList& displayList = op.renderNode->getDisplayList();
-        deferImpl(displayList.getChunks(), displayList.getOps());
+        deferImpl(op.renderNode->getDisplayList());
     }
     mCanvasState.restore();
 }
index 9c77248..6776a3c 100644 (file)
@@ -62,8 +62,7 @@ public:
     void defer(const SkRect& clip, int viewportWidth, int viewportHeight,
             const std::vector< sp<RenderNode> >& nodes);
 
-    void defer(int viewportWidth, int viewportHeight,
-            const std::vector<DisplayList::Chunk>& chunks, const std::vector<RecordedOp*>& ops);
+    void defer(int viewportWidth, int viewportHeight, const DisplayList& displayList);
     typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
 
     /**
@@ -92,8 +91,7 @@ public:
 private:
     BakedOpState* bakeOpState(const RecordedOp& recordedOp);
 
-    void deferImpl(const std::vector<DisplayList::Chunk>& chunks,
-            const std::vector<RecordedOp*>& ops);
+    void deferImpl(const DisplayList& displayList);
 
     void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
 
index 248a46e..3b413aa 100644 (file)
@@ -369,7 +369,7 @@ size_t RecordingCanvas::addOp(RecordedOp* op) {
         newChunk.endOpIndex = insertIndex + 1;
         newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
 
-        int nextChildIndex = mDisplayList->children().size();
+        int nextChildIndex = mDisplayList->children.size();
         newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
         mDeferredBarrierType = kBarrier_None;
     } else {
index 3d32f02..894a2bd 100644 (file)
@@ -49,7 +49,7 @@ void RenderNode::debugDumpLayers(const char* prefix) {
                 mLayer->wasBuildLayered ? "true" : "false");
     }
     if (mDisplayList) {
-        for (auto&& child : mDisplayList->children()) {
+        for (auto&& child : mDisplayList->getChildren()) {
             child->renderNode->debugDumpLayers(prefix);
         }
     }
@@ -178,7 +178,7 @@ void RenderNode::copyTo(proto::RenderNode *pnode) {
 
     pnode->clear_children();
     if (mDisplayList) {
-        for (auto&& child : mDisplayList->children()) {
+        for (auto&& child : mDisplayList->getChildren()) {
             child->renderNode->copyTo(pnode->add_children());
         }
     }
@@ -322,9 +322,9 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
 
     bool willHaveFunctor = false;
     if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayList) {
-        willHaveFunctor = !mStagingDisplayList->functors.isEmpty();
+        willHaveFunctor = !mStagingDisplayList->getFunctors().empty();
     } else if (mDisplayList) {
-        willHaveFunctor = !mDisplayList->functors.isEmpty();
+        willHaveFunctor = !mDisplayList->getFunctors().empty();
     }
     bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
             willHaveFunctor, functorsNeedLayer);
@@ -379,7 +379,7 @@ void RenderNode::syncDisplayList() {
     // Make sure we inc first so that we don't fluctuate between 0 and 1,
     // which would thrash the layer cache
     if (mStagingDisplayList) {
-        for (auto&& child : mStagingDisplayList->children()) {
+        for (auto&& child : mStagingDisplayList->getChildren()) {
             child->renderNode->incParentRefCount();
         }
     }
@@ -387,8 +387,8 @@ void RenderNode::syncDisplayList() {
     mDisplayList = mStagingDisplayList;
     mStagingDisplayList = nullptr;
     if (mDisplayList) {
-        for (size_t i = 0; i < mDisplayList->functors.size(); i++) {
-            (*mDisplayList->functors[i])(DrawGlInfo::kModeSync, nullptr);
+        for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) {
+            (*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr);
         }
     }
 }
@@ -406,7 +406,7 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
 
 void RenderNode::deleteDisplayList() {
     if (mDisplayList) {
-        for (auto&& child : mDisplayList->children()) {
+        for (auto&& child : mDisplayList->getChildren()) {
             child->renderNode->decParentRefCount();
         }
     }
@@ -417,12 +417,11 @@ void RenderNode::deleteDisplayList() {
 void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
-        info.out.hasFunctors |= subtree->functors.size();
-        for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
-            info.prepareTextures = cache.prefetchAndMarkInUse(
-                    info.canvasContext, subtree->bitmapResources[i]);
+        info.out.hasFunctors |= subtree->getFunctors().size();
+        for (auto&& bitmapResource : subtree->getBitmapResources()) {
+            info.prepareTextures = cache.prefetchAndMarkInUse(info.canvasContext, bitmapResource);
         }
-        for (auto&& op : subtree->children()) {
+        for (auto&& op : subtree->getChildren()) {
             RenderNode* childNode = op->renderNode;
 #if HWUI_NEW_OPS
             info.damageAccumulator->pushTransform(&op->localMatrix);
@@ -445,7 +444,7 @@ void RenderNode::destroyHardwareResources() {
         mLayer = nullptr;
     }
     if (mDisplayList) {
-        for (auto&& child : mDisplayList->children()) {
+        for (auto&& child : mDisplayList->getChildren()) {
             child->renderNode->destroyHardwareResources();
         }
         if (mNeedsDisplayListSync) {
@@ -634,8 +633,8 @@ void RenderNode::computeOrdering() {
     // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
     // transform properties are applied correctly to top level children
     if (mDisplayList == nullptr) return;
-    for (unsigned int i = 0; i < mDisplayList->children().size(); i++) {
-        DrawRenderNodeOp* childOp = mDisplayList->children()[i];
+    for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) {
+        DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
         childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity());
     }
 #endif
@@ -664,11 +663,11 @@ void RenderNode::computeOrderingImpl(
         opState->mSkipInOrderDraw = false;
     }
 
-    if (mDisplayList->children().size() > 0) {
+    if (mDisplayList->getChildren().size() > 0) {
         const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0;
         bool haveAppliedPropertiesToProjection = false;
-        for (unsigned int i = 0; i < mDisplayList->children().size(); i++) {
-            DrawRenderNodeOp* childOp = mDisplayList->children()[i];
+        for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) {
+            DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
             RenderNode* child = childOp->renderNode;
 
             std::vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
@@ -756,7 +755,7 @@ void RenderNode::buildZSortedChildList(const DisplayList::Chunk& chunk,
     if (chunk.beginChildIndex == chunk.endChildIndex) return;
 
     for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
-        DrawRenderNodeOp* childOp = mDisplayList->children()[i];
+        DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i];
         RenderNode* child = childOp->renderNode;
         float childZ = child->properties().getZ();
 
index 0be7634..7a62037 100644 (file)
@@ -23,6 +23,7 @@
 #include "DisplayListCanvas.h"
 #endif
 #include "microbench/MicroBench.h"
+#include "unit_tests/TestUtils.h"
 
 using namespace android;
 using namespace android::uirenderer;
@@ -102,6 +103,40 @@ void BM_DisplayListCanvas_record_translate::Run(int iters) {
     StopBenchmarkTiming();
 }
 
+/**
+ * Simulate a simple view drawing a background, overlapped by an image.
+ *
+ * Note that the recording commands are intentionally not perfectly efficient, as the
+ * View system frequently produces unneeded save/restores.
+ */
+BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_simpleBitmapView);
+void BM_DisplayListCanvas_record_simpleBitmapView::Run(int iters) {
+    TestCanvas canvas(100, 100);
+    delete canvas.finishRecording();
+
+    SkPaint rectPaint;
+    SkBitmap iconBitmap = TestUtils::createSkBitmap(80, 80);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; ++i) {
+        canvas.reset(100, 100);
+        {
+            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.drawRect(0, 0, 100, 100, rectPaint);
+            canvas.restore();
+        }
+        {
+            canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+            canvas.translate(10, 10);
+            canvas.drawBitmap(iconBitmap, 0, 0, nullptr);
+            canvas.restore();
+        }
+        MicroBench::DoNotOptimize(&canvas);
+        delete canvas.finishRecording();
+    }
+    StopBenchmarkTiming();
+}
+
 class NullClient: public CanvasStateClient {
     void onViewportInitialized() override {}
     void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
index 24cff72..e1249fb 100644 (file)
@@ -49,14 +49,14 @@ public:
     static void endFrame(Info& info) {}
 };
 TEST(OpReorderer, simple) {
-    auto dld = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
         canvas.drawRect(0, 0, 100, 200, SkPaint());
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
 
     OpReorderer reorderer;
-    reorderer.defer(200, 200, dld->getChunks(), dld->getOps());
+    reorderer.defer(200, 200, *dl);
 
     Info info;
     reorderer.replayBakedOps<SimpleReceiver>(&info);
@@ -78,7 +78,7 @@ public:
     static void endFrame(Info& info) {}
 };
 TEST(OpReorderer, simpleBatching) {
-    auto dld = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
 
         // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
@@ -93,7 +93,7 @@ TEST(OpReorderer, simpleBatching) {
     });
 
     OpReorderer reorderer;
-    reorderer.defer(200, 200, dld->getChunks(), dld->getOps());
+    reorderer.defer(200, 200, *dl);
 
     Info info;
     reorderer.replayBakedOps<SimpleBatchingReceiver>(&info);
index 7c19df5..ce25fc6 100644 (file)
 namespace android {
 namespace uirenderer {
 
-static void playbackOps(const std::vector<DisplayList::Chunk>& chunks,
-        const std::vector<RecordedOp*>& ops, std::function<void(const RecordedOp&)> opReciever) {
-    for (const DisplayList::Chunk& chunk : chunks) {
+static void playbackOps(const DisplayList& displayList,
+        std::function<void(const RecordedOp&)> opReciever) {
+    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
         for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
-            opReciever(*ops[opIndex]);
+            RecordedOp* op = displayList.getOps()[opIndex];
+            opReciever(*op);
         }
     }
 }
 
 TEST(RecordingCanvas, emptyPlayback) {
-    auto dld = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
         canvas.restore();
     });
-    playbackOps(dld->getChunks(), dld->getOps(), [](const RecordedOp& op) { FAIL(); });
+    playbackOps(*dl, [](const RecordedOp& op) { FAIL(); });
 }
 
 TEST(RecordingCanvas, testSimpleRectRecord) {
-    auto dld = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.drawRect(10, 20, 90, 180, SkPaint());
     });
 
     int count = 0;
-    playbackOps(dld->getChunks(), dld->getOps(), [&count](const RecordedOp& op) {
+    playbackOps(*dl, [&count](const RecordedOp& op) {
         count++;
         ASSERT_EQ(RecordedOpId::RectOp, op.opId);
         ASSERT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
@@ -56,7 +57,7 @@ TEST(RecordingCanvas, testSimpleRectRecord) {
 }
 
 TEST(RecordingCanvas, backgroundAndImage) {
-    auto dld = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkBitmap bitmap;
         bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25));
         SkPaint paint;
@@ -81,7 +82,7 @@ TEST(RecordingCanvas, backgroundAndImage) {
     });
 
     int count = 0;
-    playbackOps(dld->getChunks(), dld->getOps(), [&count](const RecordedOp& op) {
+    playbackOps(*dl, [&count](const RecordedOp& op) {
         if (count == 0) {
             ASSERT_EQ(RecordedOpId::RectOp, op.opId);
             ASSERT_NE(nullptr, op.paint);
index ade4ab3..e1c6f6c 100644 (file)
@@ -29,6 +29,8 @@
 #include <stddef.h>
 #include <type_traits>
 
+#include <vector>
+
 namespace android {
 namespace uirenderer {
 
@@ -175,6 +177,13 @@ bool operator== (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
 template <class T1, class T2>
 bool operator!= (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return false; }
 
+template <class T>
+class LsaVector : public std::vector<T, LinearStdAllocator<T>> {
+public:
+    LsaVector(const LinearStdAllocator<T>& allocator)
+            : std::vector<T, LinearStdAllocator<T>>(allocator) {}
+};
+
 }; // namespace uirenderer
 }; // namespace android