diff options
| -rw-r--r-- | libs/hwui/DisplayList.cpp | 17 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.h | 48 | ||||
| -rw-r--r-- | libs/hwui/DisplayListCanvas.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/OpReorderer.cpp | 17 | ||||
| -rw-r--r-- | libs/hwui/OpReorderer.h | 6 | ||||
| -rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/RenderNode.cpp | 39 | ||||
| -rw-r--r-- | libs/hwui/microbench/DisplayListCanvasBench.cpp | 35 | ||||
| -rw-r--r-- | libs/hwui/unit_tests/OpReordererTests.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/unit_tests/RecordingCanvasTests.cpp | 21 | ||||
| -rw-r--r-- | libs/hwui/utils/LinearAllocator.h | 9 |
11 files changed, 128 insertions, 78 deletions
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 4eb7066431c0..59f0d7cc7346 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -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; } diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index d32406f3d308..86796c5a5e0c 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -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(); diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp index f49482b65413..bad397219398 100644 --- a/libs/hwui/DisplayListCanvas.cpp +++ b/libs/hwui/DisplayListCanvas.cpp @@ -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 { diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index 7c34992164f1..7c0e2570972a 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -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(); } diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 9c77248b4338..6776a3c9fc18 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -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); diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 248a46e707b9..3b413aaec0e0 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -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 { diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 3d32f0256d1a..894a2bdf19df 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -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(); diff --git a/libs/hwui/microbench/DisplayListCanvasBench.cpp b/libs/hwui/microbench/DisplayListCanvasBench.cpp index 0be7634a03c9..7a620379d7b7 100644 --- a/libs/hwui/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/microbench/DisplayListCanvasBench.cpp @@ -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) {} diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp index 24cff7275107..e1249fbd2e96 100644 --- a/libs/hwui/unit_tests/OpReordererTests.cpp +++ b/libs/hwui/unit_tests/OpReordererTests.cpp @@ -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); diff --git a/libs/hwui/unit_tests/RecordingCanvasTests.cpp b/libs/hwui/unit_tests/RecordingCanvasTests.cpp index 7c19df5b19b5..ce25fc6189b4 100644 --- a/libs/hwui/unit_tests/RecordingCanvasTests.cpp +++ b/libs/hwui/unit_tests/RecordingCanvasTests.cpp @@ -23,30 +23,31 @@ 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); diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h index ade4ab308d86..e1c6f6c70428 100644 --- a/libs/hwui/utils/LinearAllocator.h +++ b/libs/hwui/utils/LinearAllocator.h @@ -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 |