diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index 1d8be2b47d438..2e02306dcc39a 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -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 >& nodes) { mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, - 0, 0, viewportWidth, viewportHeight, Vector3()); + clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, + Vector3()); for (const sp& node : nodes) { if (node->nothingToDraw()) continue; @@ -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; diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index b99172cb673e8..395a1baeebd05 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -25,6 +25,8 @@ #include #include +struct SkRect; + namespace android { namespace uirenderer { @@ -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 >& nodes); + void defer(const SkRect& clip, int viewportWidth, int viewportHeight, + const std::vector< sp >& nodes); void defer(int viewportWidth, int viewportHeight, const std::vector& chunks, const std::vector& ops); @@ -133,7 +136,7 @@ private: // contains ResolvedOps and Batches LinearAllocator mAllocator; - size_t mEarliestBatchIndex = 0; + int mEarliestBatchIndex = 0; }; }; // namespace uirenderer diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index e1d8abdd7034e..238cf06e77f67 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -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(); @@ -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(&info); + + bool drew = info.didDraw; + +#else mCanvas->prepareDirty(frame.width(), frame.height(), dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); @@ -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(&info); - - bool drew = info.didDraw; - SkRect screenDirty = SkRect::MakeWH(frame.width(), frame.height()); -#endif if (drew) { if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index e0cbabdc933a0..16956e6f1e47e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -141,6 +141,9 @@ private: void freePrefetechedLayers(); + int lastFrameWidth = 0; + int lastFrameHeight = 0; + RenderThread& mRenderThread; EglManager& mEglManager; sp mNativeWindow; diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp index fcaea1e36a699..cbfbb23ae25a9 100644 --- a/libs/hwui/unit_tests/OpReordererTests.cpp +++ b/libs/hwui/unit_tests/OpReordererTests.cpp @@ -50,9 +50,7 @@ public: }; TEST(OpReorderer, simple) { auto dld = TestUtils::createDLD(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); }); @@ -81,8 +79,7 @@ public: }; TEST(OpReorderer, simpleBatching) { auto dld = TestUtils::createDLD(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. @@ -134,14 +131,14 @@ TEST(OpReorderer, renderNode) { RenderNode* childPtr = child.get(); sp parent = TestUtils::createNode(0, 0, 200, 200, [childPtr](RecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(0, 0, 200, 200, paint); + SkPaint paint; + paint.setColor(SK_ColorDKGRAY); + canvas.drawRect(0, 0, 200, 200, paint); - canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); - canvas.translate(40, 40); - canvas.drawRenderNode(childPtr); - canvas.restore(); + canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + canvas.translate(40, 40); + canvas.drawRenderNode(childPtr); + canvas.restore(); }); TestUtils::syncNodePropertiesAndDisplayList(child); @@ -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(&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 node = TestUtils::createNode(0, 0, 200, 200, [](RecordingCanvas& canvas) { + SkBitmap bitmap = TestUtils::createSkBitmap(200, 200); + canvas.drawBitmap(bitmap, 0, 0, nullptr); + }); + TestUtils::syncNodePropertiesAndDisplayList(node); + std::vector< sp > 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(&info); +} + } } diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h index 257dd2806d38e..9b7d1b9d24eec 100644 --- a/libs/hwui/unit_tests/TestUtils.h +++ b/libs/hwui/unit_tests/TestUtils.h @@ -46,6 +46,12 @@ public: return snapshot; } + static SkBitmap createSkBitmap(int width, int height) { + SkBitmap bitmap; + bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); + return bitmap; + } + template static std::unique_ptr createDLD(int width, int height, std::function canvasCallback) {