summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/DisplayList.cpp17
-rw-r--r--libs/hwui/DisplayList.h48
-rw-r--r--libs/hwui/DisplayListCanvas.cpp4
-rw-r--r--libs/hwui/OpReorderer.cpp17
-rw-r--r--libs/hwui/OpReorderer.h6
-rw-r--r--libs/hwui/RecordingCanvas.cpp2
-rw-r--r--libs/hwui/RenderNode.cpp39
-rw-r--r--libs/hwui/microbench/DisplayListCanvasBench.cpp35
-rw-r--r--libs/hwui/unit_tests/OpReordererTests.cpp8
-rw-r--r--libs/hwui/unit_tests/RecordingCanvasTests.cpp21
-rw-r--r--libs/hwui/utils/LinearAllocator.h9
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