Add partial damage support to new draw path
Change-Id: I612578fd181240de71297c9a28bc9a8f350764a7
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index 1d8be2b..2e02306 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -212,10 +212,11 @@
: 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;
@@ -325,7 +326,7 @@
// 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 b99172c..395a1ba 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -25,6 +25,8 @@
#include <vector>
#include <unordered_map>
+struct SkRect;
+
namespace android {
namespace uirenderer {
@@ -57,7 +59,8 @@
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);
@@ -133,7 +136,7 @@
// 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 e1d8abd..238cf06 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -266,11 +266,11 @@
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 @@
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);
@@ -426,20 +438,10 @@
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))) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index e0cbabd..16956e6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -141,6 +141,9 @@
void freePrefetechedLayers();
+ int lastFrameWidth = 0;
+ int lastFrameHeight = 0;
+
RenderThread& mRenderThread;
EglManager& mEglManager;
sp<ANativeWindow> mNativeWindow;
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index fcaea1e..cbfbb23 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -50,9 +50,7 @@
};
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);
});
@@ -81,8 +79,7 @@
};
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.
@@ -134,14 +131,14 @@
RenderNode* childPtr = child.get();
sp<RenderNode> parent = TestUtils::createNode<RecordingCanvas>(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 @@
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);
+}
+
}
}
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index 257dd28..9b7d1b9 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -46,6 +46,12 @@
return snapshot;
}
+ static SkBitmap createSkBitmap(int width, int height) {
+ SkBitmap bitmap;
+ bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
+ return bitmap;
+ }
+
template<class CanvasType>
static std::unique_ptr<DisplayListData> createDLD(int width, int height,
std::function<void(CanvasType& canvas)> canvasCallback) {