Loading libs/hwui/OpReorderer.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -212,10 +212,11 @@ OpReorderer::OpReorderer() : mCanvasState(sNullClient) { } void OpReorderer::defer(int viewportWidth, int viewportHeight, void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes) { mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 0, 0, viewportWidth, viewportHeight, Vector3()); clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, Vector3()); for (const sp<RenderNode>& node : nodes) { if (node->nothingToDraw()) continue; Loading Loading @@ -325,7 +326,7 @@ void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { // if no target, merging ops still interate to find similar batch to insert after void OpReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch, size_t* insertBatchIndex) const { for (size_t i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { BatchBase* overBatch = mBatches[i]; if (overBatch == *targetBatch) break; Loading libs/hwui/OpReorderer.h +5 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include <vector> #include <unordered_map> struct SkRect; namespace android { namespace uirenderer { Loading Loading @@ -57,7 +59,8 @@ public: OpReorderer(); // TODO: not final, just presented this way for simplicity. Layers too? void defer(int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes); void defer(const SkRect& clip, int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes); void defer(int viewportWidth, int viewportHeight, const std::vector<DisplayListData::Chunk>& chunks, const std::vector<RecordedOp*>& ops); Loading Loading @@ -133,7 +136,7 @@ private: // contains ResolvedOps and Batches LinearAllocator mAllocator; size_t mEarliestBatchIndex = 0; int mEarliestBatchIndex = 0; }; }; // namespace uirenderer Loading libs/hwui/renderthread/CanvasContext.cpp +16 −14 Original line number Diff line number Diff line Loading @@ -266,11 +266,11 @@ void CanvasContext::draw() { Frame frame = mEglManager.beginFrame(mEglSurface); #if !HWUI_NEW_OPS if (frame.width() != mCanvas->getViewportWidth() || frame.height() != mCanvas->getViewportHeight()) { if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) { // can't rely on prior content of window if viewport size changes dirty.setEmpty(); lastFrameWidth = frame.width(); lastFrameHeight = frame.height(); } else if (mHaveNewSurface || frame.bufferAge() == 0) { // New surface needs a full draw dirty.setEmpty(); Loading Loading @@ -316,6 +316,18 @@ void CanvasContext::draw() { mDamageHistory.next() = screenDirty; mEglManager.damageFrame(frame, dirty); #if HWUI_NEW_OPS OpReorderer reorderer; reorderer.defer(dirty, frame.width(), frame.height(), mRenderNodes); BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), frame.width(), frame.height(), mOpaque); // TODO: profiler().draw(mCanvas); reorderer.replayBakedOps<BakedOpRenderer>(&info); bool drew = info.didDraw; #else mCanvas->prepareDirty(frame.width(), frame.height(), dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); Loading Loading @@ -426,20 +438,10 @@ void CanvasContext::draw() { profiler().draw(mCanvas); bool drew = mCanvas->finish(); #endif // Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point mCurrentFrameInfo->markSwapBuffers(); #else OpReorderer reorderer; reorderer.defer(frame.width(), frame.height(), mRenderNodes); BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), frame.width(), frame.height(), mOpaque); reorderer.replayBakedOps<BakedOpRenderer>(&info); bool drew = info.didDraw; SkRect screenDirty = SkRect::MakeWH(frame.width(), frame.height()); #endif if (drew) { if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) { Loading libs/hwui/renderthread/CanvasContext.h +3 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ private: void freePrefetechedLayers(); int lastFrameWidth = 0; int lastFrameHeight = 0; RenderThread& mRenderThread; EglManager& mEglManager; sp<ANativeWindow> mNativeWindow; Loading libs/hwui/unit_tests/OpReordererTests.cpp +42 −14 Original line number Diff line number Diff line Loading @@ -50,9 +50,7 @@ public: }; TEST(OpReorderer, simple) { auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25)); SkBitmap bitmap = TestUtils::createSkBitmap(25, 25); canvas.drawRect(0, 0, 100, 200, SkPaint()); canvas.drawBitmap(bitmap, 10, 10, nullptr); }); Loading Loading @@ -81,8 +79,7 @@ public: }; TEST(OpReorderer, simpleBatching) { auto dld = TestUtils::createDLD<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeUnknown(10, 10)); SkBitmap bitmap = TestUtils::createSkBitmap(10, 10); // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. Loading Loading @@ -151,11 +148,42 @@ TEST(OpReorderer, renderNode) { nodes.push_back(parent.get()); OpReorderer reorderer; reorderer.defer(200, 200, nodes); reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes); Info info; reorderer.replayBakedOps<RenderNodeReceiver>(&info); } class ClippedReceiver { public: static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) { EXPECT_EQ(0, info->index++); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect); EXPECT_TRUE(state.computedState.transform.isIdentity()); } UNSUPPORTED_OP(Info, RectOp) UNSUPPORTED_OP(Info, RenderNodeOp) UNSUPPORTED_OP(Info, SimpleRectsOp) static void startFrame(Info& info) {} static void endFrame(Info& info) {} }; TEST(OpReorderer, clipped) { sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap = TestUtils::createSkBitmap(200, 200); canvas.drawBitmap(bitmap, 0, 0, nullptr); }); TestUtils::syncNodePropertiesAndDisplayList(node); std::vector< sp<RenderNode> > nodes; nodes.push_back(node.get()); OpReorderer reorderer; reorderer.defer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver 200, 200, nodes); Info info; reorderer.replayBakedOps<ClippedReceiver>(&info); } } } Loading
libs/hwui/OpReorderer.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -212,10 +212,11 @@ OpReorderer::OpReorderer() : mCanvasState(sNullClient) { } void OpReorderer::defer(int viewportWidth, int viewportHeight, void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes) { mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 0, 0, viewportWidth, viewportHeight, Vector3()); clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, Vector3()); for (const sp<RenderNode>& node : nodes) { if (node->nothingToDraw()) continue; Loading Loading @@ -325,7 +326,7 @@ void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { // if no target, merging ops still interate to find similar batch to insert after void OpReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch, size_t* insertBatchIndex) const { for (size_t i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { BatchBase* overBatch = mBatches[i]; if (overBatch == *targetBatch) break; Loading
libs/hwui/OpReorderer.h +5 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include <vector> #include <unordered_map> struct SkRect; namespace android { namespace uirenderer { Loading Loading @@ -57,7 +59,8 @@ public: OpReorderer(); // TODO: not final, just presented this way for simplicity. Layers too? void defer(int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes); void defer(const SkRect& clip, int viewportWidth, int viewportHeight, const std::vector< sp<RenderNode> >& nodes); void defer(int viewportWidth, int viewportHeight, const std::vector<DisplayListData::Chunk>& chunks, const std::vector<RecordedOp*>& ops); Loading Loading @@ -133,7 +136,7 @@ private: // contains ResolvedOps and Batches LinearAllocator mAllocator; size_t mEarliestBatchIndex = 0; int mEarliestBatchIndex = 0; }; }; // namespace uirenderer Loading
libs/hwui/renderthread/CanvasContext.cpp +16 −14 Original line number Diff line number Diff line Loading @@ -266,11 +266,11 @@ void CanvasContext::draw() { Frame frame = mEglManager.beginFrame(mEglSurface); #if !HWUI_NEW_OPS if (frame.width() != mCanvas->getViewportWidth() || frame.height() != mCanvas->getViewportHeight()) { if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) { // can't rely on prior content of window if viewport size changes dirty.setEmpty(); lastFrameWidth = frame.width(); lastFrameHeight = frame.height(); } else if (mHaveNewSurface || frame.bufferAge() == 0) { // New surface needs a full draw dirty.setEmpty(); Loading Loading @@ -316,6 +316,18 @@ void CanvasContext::draw() { mDamageHistory.next() = screenDirty; mEglManager.damageFrame(frame, dirty); #if HWUI_NEW_OPS OpReorderer reorderer; reorderer.defer(dirty, frame.width(), frame.height(), mRenderNodes); BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), frame.width(), frame.height(), mOpaque); // TODO: profiler().draw(mCanvas); reorderer.replayBakedOps<BakedOpRenderer>(&info); bool drew = info.didDraw; #else mCanvas->prepareDirty(frame.width(), frame.height(), dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); Loading Loading @@ -426,20 +438,10 @@ void CanvasContext::draw() { profiler().draw(mCanvas); bool drew = mCanvas->finish(); #endif // Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point mCurrentFrameInfo->markSwapBuffers(); #else OpReorderer reorderer; reorderer.defer(frame.width(), frame.height(), mRenderNodes); BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(), frame.width(), frame.height(), mOpaque); reorderer.replayBakedOps<BakedOpRenderer>(&info); bool drew = info.didDraw; SkRect screenDirty = SkRect::MakeWH(frame.width(), frame.height()); #endif if (drew) { if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) { Loading
libs/hwui/renderthread/CanvasContext.h +3 −0 Original line number Diff line number Diff line Loading @@ -141,6 +141,9 @@ private: void freePrefetechedLayers(); int lastFrameWidth = 0; int lastFrameHeight = 0; RenderThread& mRenderThread; EglManager& mEglManager; sp<ANativeWindow> mNativeWindow; Loading
libs/hwui/unit_tests/OpReordererTests.cpp +42 −14 Original line number Diff line number Diff line Loading @@ -50,9 +50,7 @@ public: }; TEST(OpReorderer, simple) { auto dld = TestUtils::createDLD<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25)); SkBitmap bitmap = TestUtils::createSkBitmap(25, 25); canvas.drawRect(0, 0, 100, 200, SkPaint()); canvas.drawBitmap(bitmap, 10, 10, nullptr); }); Loading Loading @@ -81,8 +79,7 @@ public: }; TEST(OpReorderer, simpleBatching) { auto dld = TestUtils::createDLD<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap; bitmap.setInfo(SkImageInfo::MakeUnknown(10, 10)); SkBitmap bitmap = TestUtils::createSkBitmap(10, 10); // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. Loading Loading @@ -151,11 +148,42 @@ TEST(OpReorderer, renderNode) { nodes.push_back(parent.get()); OpReorderer reorderer; reorderer.defer(200, 200, nodes); reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes); Info info; reorderer.replayBakedOps<RenderNodeReceiver>(&info); } class ClippedReceiver { public: static void onBitmapOp(Info* info, const BitmapOp& op, const BakedOpState& state) { EXPECT_EQ(0, info->index++); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds); EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect); EXPECT_TRUE(state.computedState.transform.isIdentity()); } UNSUPPORTED_OP(Info, RectOp) UNSUPPORTED_OP(Info, RenderNodeOp) UNSUPPORTED_OP(Info, SimpleRectsOp) static void startFrame(Info& info) {} static void endFrame(Info& info) {} }; TEST(OpReorderer, clipped) { sp<RenderNode> node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RecordingCanvas& canvas) { SkBitmap bitmap = TestUtils::createSkBitmap(200, 200); canvas.drawBitmap(bitmap, 0, 0, nullptr); }); TestUtils::syncNodePropertiesAndDisplayList(node); std::vector< sp<RenderNode> > nodes; nodes.push_back(node.get()); OpReorderer reorderer; reorderer.defer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver 200, 200, nodes); Info info; reorderer.replayBakedOps<ClippedReceiver>(&info); } } }