Improve multi-window render clipping logic
Fixes: 28125010
Restructures 'scene defer', to implement window backdrop overdraw
avoidance in new render pipeline, and disable clipping to content draw
bounds.
Also restructures FrameBuilder's constructors, to separate out into
multiple defer methods.
Change-Id: I53facb904c1a4a4acc493d8a489921a79a50494e
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 6fc74a5..502f027 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -31,18 +31,16 @@
namespace android {
namespace uirenderer {
-FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+FrameBuilder::FrameBuilder(const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
- const std::vector< sp<RenderNode> >& nodes,
- const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches)
- : mCanvasState(*this)
+ const LightGeometry& lightGeometry, Caches& caches)
+ : mStdAllocator(mAllocator)
+ , mLayerBuilders(mStdAllocator)
+ , mLayerStack(mStdAllocator)
+ , mCanvasState(*this)
, mCaches(caches)
, mLightRadius(lightGeometry.radius)
- , mDrawFbo0(!nodes.empty()) {
- ATRACE_NAME("prepare drawing commands");
-
- mLayerBuilders.reserve(layers.entries().size());
- mLayerStack.reserve(layers.entries().size());
+ , mDrawFbo0(true) {
// Prepare to defer Fbo0
auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
@@ -51,7 +49,31 @@
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
lightGeometry.center);
+}
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
+ const LightGeometry& lightGeometry, Caches& caches)
+ : mStdAllocator(mAllocator)
+ , mLayerBuilders(mStdAllocator)
+ , mLayerStack(mStdAllocator)
+ , mCanvasState(*this)
+ , mCaches(caches)
+ , mLightRadius(lightGeometry.radius)
+ , mDrawFbo0(false) {
+ // TODO: remove, with each layer on its own save stack
+
+ // Prepare to defer Fbo0 (which will be empty)
+ auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1));
+ mLayerBuilders.push_back(fbo0);
+ mLayerStack.push_back(0);
+ mCanvasState.initializeSaveStack(1, 1,
+ 0, 0, 1, 1,
+ lightGeometry.center);
+
+ deferLayers(layers);
+}
+
+void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
// Render all layers to be updated, in order. Defer in reverse order, so that they'll be
// updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
for (int i = layers.entries().size() - 1; i >= 0; i--) {
@@ -76,10 +98,45 @@
restoreForLayer();
}
}
+}
+void FrameBuilder::deferRenderNode(RenderNode& renderNode) {
+ renderNode.computeOrdering();
+
+ mCanvasState.save(SaveFlags::MatrixClip);
+ deferNodePropsAndOps(renderNode);
+ mCanvasState.restore();
+}
+
+void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode) {
+ renderNode.computeOrdering();
+
+ mCanvasState.save(SaveFlags::MatrixClip);
+ mCanvasState.translate(tx, ty);
+ mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
+ SkRegion::kIntersect_Op);
+ deferNodePropsAndOps(renderNode);
+ mCanvasState.restore();
+}
+
+static Rect nodeBounds(RenderNode& node) {
+ auto& props = node.properties();
+ return Rect(props.getLeft(), props.getTop(),
+ props.getRight(), props.getBottom());
+}
+
+void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds) {
+ if (nodes.size() < 1) return;
+ if (nodes.size() == 1) {
+ if (!nodes[0]->nothingToDraw()) {
+ deferRenderNode(*nodes[0]);
+ }
+ return;
+ }
// It there are multiple render nodes, they are laid out as follows:
// #0 - backdrop (content + caption)
- // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
+ // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
// #2 - additional overlay nodes
// Usually the backdrop cannot be seen since it will be entirely covered by the content. While
// resizing however it might become partially visible. The following render loop will crop the
@@ -88,45 +145,52 @@
//
// Additional nodes will be drawn on top with no particular clipping semantics.
- // The bounds of the backdrop against which the content should be clipped.
- Rect backdropBounds = contentDrawBounds;
// Usually the contents bounds should be mContentDrawBounds - however - we will
// move it towards the fixed edge to give it a more stable appearance (for the moment).
// If there is no content bounds we ignore the layering as stated above and start with 2.
- int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
- for (const sp<RenderNode>& node : nodes) {
- if (node->nothingToDraw()) continue;
- node->computeOrdering();
- int count = mCanvasState.save(SaveFlags::MatrixClip);
+ // Backdrop bounds in render target space
+ const Rect backdrop = nodeBounds(*nodes[0]);
- if (layer == 0) {
- const RenderProperties& properties = node->properties();
- Rect targetBounds(properties.getLeft(), properties.getTop(),
- properties.getRight(), properties.getBottom());
- // Move the content bounds towards the fixed corner of the backdrop.
- const int x = targetBounds.left;
- const int y = targetBounds.top;
- // Remember the intersection of the target bounds and the intersection bounds against
- // which we have to crop the content.
- backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
- backdropBounds.doIntersect(targetBounds);
- } else if (layer == 1) {
- // We shift and clip the content to match its final location in the window.
- const float left = contentDrawBounds.left;
- const float top = contentDrawBounds.top;
- const float dx = backdropBounds.left - left;
- const float dy = backdropBounds.top - top;
- const float width = backdropBounds.getWidth();
- const float height = backdropBounds.getHeight();
- mCanvasState.translate(dx, dy);
- // It gets cropped against the bounds of the backdrop to stay inside.
- mCanvasState.clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op);
+ // Bounds that content will fill in render target space (note content node bounds may be bigger)
+ Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
+ content.translate(backdrop.left, backdrop.top);
+ if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
+ // Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
+
+ // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
+ // also fill left/top. Currently, both 2up and freeform position content at the top/left of
+ // the backdrop, so this isn't necessary.
+ if (content.right < backdrop.right) {
+ // draw backdrop to right side of content
+ deferRenderNode(0, 0, Rect(content.right, backdrop.top,
+ backdrop.right, backdrop.bottom), *nodes[0]);
}
+ if (content.bottom < backdrop.bottom) {
+ // draw backdrop to bottom of content
+ // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
+ deferRenderNode(0, 0, Rect(content.left, content.bottom,
+ content.right, backdrop.bottom), *nodes[0]);
+ }
+ }
- deferNodePropsAndOps(*node);
- mCanvasState.restoreToCount(count);
- layer++;
+ if (!backdrop.isEmpty()) {
+ // content node translation to catch up with backdrop
+ float dx = contentDrawBounds.left - backdrop.left;
+ float dy = contentDrawBounds.top - backdrop.top;
+
+ Rect contentLocalClip = backdrop;
+ contentLocalClip.translate(dx, dy);
+ deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]);
+ } else {
+ deferRenderNode(*nodes[1]);
+ }
+
+ // remaining overlay nodes, simply defer
+ for (size_t index = 2; index < nodes.size(); index++) {
+ if (!nodes[index]->nothingToDraw()) {
+ deferRenderNode(*nodes[index]);
+ }
}
}
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index a6fd761..b915443 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -37,8 +37,8 @@
class Rect;
/**
- * Traverses all of the drawing commands from the layers and RenderNodes passed into it, preparing
- * them to be rendered.
+ * Processes, optimizes, and stores rendering commands from RenderNodes and
+ * LayerUpdateQueue, building content needed to render a frame.
*
* Resolves final drawing state for each operation (including clip, alpha and matrix), and then
* reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either
@@ -60,21 +60,21 @@
float radius;
};
- // TODO: remove
- FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+ FrameBuilder(const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
- const std::vector< sp<RenderNode> >& nodes,
- const LightGeometry& lightGeometry,
- Caches& caches)
- : FrameBuilder(layers, clip, viewportWidth, viewportHeight,
- nodes, lightGeometry, Rect(), caches) {}
+ const LightGeometry& lightGeometry, Caches& caches);
- FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
- uint32_t viewportWidth, uint32_t viewportHeight,
- const std::vector< sp<RenderNode> >& nodes,
- const LightGeometry& lightGeometry,
- const Rect &contentDrawBounds,
- Caches& caches);
+ FrameBuilder(const LayerUpdateQueue& layerUpdateQueue,
+ const LightGeometry& lightGeometry, Caches& caches);
+
+ void deferLayers(const LayerUpdateQueue& layers);
+
+ void deferRenderNode(RenderNode& renderNode);
+
+ void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode);
+
+ void deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds);
virtual ~FrameBuilder() {}
@@ -223,8 +223,12 @@
MAP_DEFERRABLE_OPS(X)
#undef X
+ // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
+ LinearAllocator mAllocator;
+ LinearStdAllocator<void*> mStdAllocator;
+
// List of every deferred layer's render state. Replayed in reverse order to render a frame.
- std::vector<LayerBuilder*> mLayerBuilders;
+ LsaVector<LayerBuilder*> mLayerBuilders;
/*
* Stack of indices within mLayerBuilders representing currently active layers. If drawing
@@ -238,7 +242,7 @@
* won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing
* ops added to it.
*/
- std::vector<size_t> mLayerStack;
+ LsaVector<size_t> mLayerStack;
CanvasState mCanvasState;
@@ -246,9 +250,6 @@
float mLightRadius;
- // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches
- LinearAllocator mAllocator;
-
const bool mDrawFbo0;
};
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index eea11bf..3000777 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -244,7 +244,8 @@
if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
&& bakedState->computedState.opaqueOverClippedBounds
- && bakedState->computedState.clippedBounds.contains(repaintRect))) {
+ && bakedState->computedState.clippedBounds.contains(repaintRect)
+ && !Properties::debugOverdraw)) {
// discard all deferred drawing ops, since new one will occlude them
clear();
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ab66b2a..3053455 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -348,9 +348,13 @@
#if HWUI_NEW_OPS
auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
- mRenderNodes, mLightGeometry, mContentDrawBounds, caches);
+ FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), mLightGeometry, caches);
+
+ frameBuilder.deferLayers(mLayerUpdateQueue);
mLayerUpdateQueue.clear();
+
+ frameBuilder.deferRenderNodeScene(mRenderNodes, mContentDrawBounds);
+
BakedOpRenderer renderer(caches, mRenderThread.renderState(),
mOpaque, mLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -615,8 +619,7 @@
#if HWUI_NEW_OPS
static const std::vector< sp<RenderNode> > emptyNodeList;
auto& caches = Caches::getInstance();
- FrameBuilder frameBuilder(mLayerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
- emptyNodeList, mLightGeometry, mContentDrawBounds, caches);
+ FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches);
mLayerUpdateQueue.clear();
BakedOpRenderer renderer(caches, mRenderThread.renderState(),
mOpaque, mLightInfo);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 5f4ebc0..dbaefa4 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -171,11 +171,9 @@
syncHierarchyPropertiesAndDisplayListImpl(node.get());
}
- static std::vector<sp<RenderNode>> createSyncedNodeList(sp<RenderNode>& node) {
- TestUtils::syncHierarchyPropertiesAndDisplayList(node);
- std::vector<sp<RenderNode>> vec;
- vec.emplace_back(node);
- return vec;
+ static sp<RenderNode>& getSyncedNode(sp<RenderNode>& node) {
+ syncHierarchyPropertiesAndDisplayList(node);
+ return node;
}
typedef std::function<void(renderthread::RenderThread& thread)> RtCallback;
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 0aef620..84ef9c2 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -35,11 +35,10 @@
using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::test;
-const LayerUpdateQueue sEmptyLayerUpdateQueue;
const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
-static std::vector<sp<RenderNode>> createTestNodeList() {
+static sp<RenderNode> createTestNode() {
auto node = TestUtils::createNode(0, 0, 200, 200,
[](RenderProperties& props, RecordingCanvas& canvas) {
SkBitmap bitmap = TestUtils::createSkBitmap(10, 10);
@@ -56,31 +55,33 @@
canvas.restore();
});
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
- std::vector<sp<RenderNode>> vec;
- vec.emplace_back(node);
- return vec;
+ return node;
}
void BM_FrameBuilder_defer(benchmark::State& state) {
- auto nodes = createTestNodeList();
- while (state.KeepRunning()) {
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
- nodes, sLightGeometry, Caches::getInstance());
- benchmark::DoNotOptimize(&frameBuilder);
- }
+ TestUtils::runOnRenderThread([&state](RenderThread& thread) {
+ auto node = createTestNode();
+ while (state.KeepRunning()) {
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*node);
+ benchmark::DoNotOptimize(&frameBuilder);
+ }
+ });
}
BENCHMARK(BM_FrameBuilder_defer);
void BM_FrameBuilder_deferAndRender(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
- auto nodes = createTestNodeList();
+ auto node = createTestNode();
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
- nodes, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
+ sLightGeometry, caches);
+ frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -90,7 +91,7 @@
}
BENCHMARK(BM_FrameBuilder_deferAndRender);
-static std::vector<sp<RenderNode>> getSyncedSceneNodes(const char* sceneName) {
+static sp<RenderNode> getSyncedSceneNode(const char* sceneName) {
gDisplay = getBuiltInDisplay(); // switch to real display if present
TestContext testContext;
@@ -103,9 +104,7 @@
});
TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
- std::vector<sp<RenderNode>> nodes;
- nodes.emplace_back(rootNode);
- return nodes;
+ return rootNode;
}
static auto SCENES = {
@@ -116,11 +115,12 @@
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
const char* sceneName = *(SCENES.begin() + state.range_x());
state.SetLabel(sceneName);
- auto nodes = getSyncedSceneNodes(sceneName);
+ auto node = getSyncedSceneNode(sceneName);
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
- SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
- nodes, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
+ gDisplay.w, gDisplay.h,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*node);
benchmark::DoNotOptimize(&frameBuilder);
}
});
@@ -131,15 +131,16 @@
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
const char* sceneName = *(SCENES.begin() + state.range_x());
state.SetLabel(sceneName);
- auto nodes = getSyncedSceneNodes(sceneName);
+ auto node = getSyncedSceneNode(sceneName);
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
- SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
- nodes, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
+ gDisplay.w, gDisplay.h,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 209a104..1e5544d 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -29,11 +29,8 @@
namespace android {
namespace uirenderer {
-const LayerUpdateQueue sEmptyLayerUpdateQueue;
-const std::vector< sp<RenderNode> > sEmptyNodeList;
const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
-
/**
* Virtual class implemented by each test to redirect static operation / state transitions to
* virtual methods.
@@ -136,8 +133,10 @@
canvas.drawRect(0, 0, 100, 200, SkPaint());
canvas.drawBitmap(bitmap, 10, 10, nullptr);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
@@ -162,8 +161,10 @@
strokedPaint.setStrokeWidth(10);
canvas.drawPoint(50, 50, strokedPaint);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SimpleStrokeTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
@@ -177,8 +178,9 @@
canvas.drawRect(0, 0, 400, 400, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -211,15 +213,111 @@
}
canvas.restore();
});
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
SimpleBatchingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
<< "Expect number of ops = 2 * loop count";
}
+RENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
+ class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
+ EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
+ state.computedState.clipSideFlags);
+ }
+ };
+
+ auto node = TestUtils::createNode(0, 0, 100, 100,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
+ *TestUtils::getSyncedNode(node));
+
+ DeferRenderNodeTranslateClipTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex());
+}
+
+RENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
+ class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
+ public:
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ const Rect& clippedBounds = state.computedState.clippedBounds;
+ Matrix4 expected;
+ switch (mIndex++) {
+ case 0:
+ // background - left side
+ EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 1:
+ // background - top side
+ EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 2:
+ // content
+ EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(-50, -50, 0);
+ break;
+ case 3:
+ // overlay
+ EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
+ break;
+ default:
+ ADD_FAILURE() << "Too many rects observed";
+ }
+ EXPECT_EQ(expected, state.computedState.transform);
+ }
+ };
+
+ std::vector<sp<RenderNode>> nodes;
+ SkPaint transparentPaint;
+ transparentPaint.setAlpha(128);
+
+ // backdrop
+ nodes.push_back(TestUtils::createNode(100, 100, 700, 500, // 600x400
+ [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 600, 400, transparentPaint);
+ }));
+
+ // content
+ Rect contentDrawBounds(150, 150, 650, 450); // 500x300
+ nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
+ [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 600, transparentPaint);
+ }));
+
+ // overlay
+ nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
+ [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 200, transparentPaint);
+ }));
+
+ for (auto& node : nodes) {
+ TestUtils::syncHierarchyPropertiesAndDisplayList(node);
+ }
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
+
+ DeferRenderNodeSceneTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(4, renderer.getIndex());
+}
+
RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
class EmptyNoFbo0TestRenderer : public TestRendererBase {
public:
@@ -231,9 +329,9 @@
}
};
- // Pass empty node list, so no work is enqueued for Fbo0
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- sEmptyNodeList, sLightGeometry, Caches::getInstance());
+ // Use layer update constructor, so no work is enqueued for Fbo0
+ LayerUpdateQueue emptyLayerUpdateQueue;
+ FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance());
EmptyNoFbo0TestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -252,11 +350,12 @@
[](RenderProperties& props, RecordingCanvas& canvas) {
// no drawn content
});
- auto syncedNodeList = TestUtils::createSyncedNodeList(node);
- // Draw, but pass empty node list, so no work is done for primary frame
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- syncedNodeList, sLightGeometry, Caches::getInstance());
+ // Draw, but pass node without draw content, so no work is done for primary frame
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
EmptyWithFbo0TestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
@@ -281,9 +380,9 @@
// Damage (and therefore clip) is same as last draw, subset of renderable area.
// This means last op occludes other contents, and they'll be rejected to avoid overdraw.
- SkRect damageRect = SkRect::MakeLTRB(10, 10, 190, 190);
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, damageRect, 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
<< "Recording must not have rejected ops, in order for this test to be valid";
@@ -324,9 +423,9 @@
canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
});
-
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(50, 50), 50, 50,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
<< "Recording must not have rejected ops, in order for this test to be valid";
@@ -369,8 +468,10 @@
canvas.drawBitmap(bitmap, 40, 70, nullptr);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
ClippedMergingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -397,8 +498,10 @@
TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
TextMergingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
@@ -428,8 +531,11 @@
TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
}
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
TextStrikethroughTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
@@ -485,8 +591,9 @@
TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
}
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextStyleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
@@ -516,8 +623,11 @@
canvas.drawLayer(layerUpdater.get());
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
TextureLayerClipLocalMatrixTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
@@ -546,8 +656,10 @@
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
TextureLayerCombineMatricesTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
@@ -562,8 +674,11 @@
[&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
canvas.drawLayer(layerUpdater.get());
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
FailRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -584,9 +699,10 @@
canvas.callDrawGLFunction(&noopFunctor);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(scrolledFunctorView),
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
+
FunctorTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
@@ -608,9 +724,10 @@
canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(unclippedColorView),
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
+
ColorTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
@@ -654,8 +771,10 @@
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
RenderNodeTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
@@ -678,9 +797,11 @@
canvas.drawBitmap(bitmap, 0, 0, nullptr);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
- SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
- 200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ // clip to small area, should see in receiver
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
ClippedTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -725,8 +846,11 @@
canvas.drawRect(10, 10, 190, 190, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
@@ -806,8 +930,10 @@
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerNestedTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(12, renderer.getIndex());
@@ -826,8 +952,10 @@
canvas.restore();
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
// should see no ops, even within the layer, since the layer should be rejected
@@ -869,8 +997,11 @@
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerUnclippedSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -923,8 +1054,11 @@
canvas.drawRect(0, 0, 100, 100, SkPaint());
canvas.restoreToCount(restoreTo);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerUnclippedMergedClearsTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex())
@@ -964,8 +1098,10 @@
});
// draw with partial screen dirty, and assert we see that rect later
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerUnclippedClearClipTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -981,8 +1117,10 @@
});
// draw with partial screen dirty that doesn't intersect with savelayer
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
FailRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
@@ -1046,8 +1184,11 @@
canvas.restore();
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
SaveLayerUnclippedComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(13, renderer.getIndex());
@@ -1098,14 +1239,17 @@
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*layerHandle = &layer;
- auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+ auto syncedNode = TestUtils::getSyncedNode(node);
// only enqueue partial damage
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
- FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- syncedNodeList, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferLayers(layerUpdateQueue);
+ frameBuilder.deferRenderNode(*syncedNode);
+
HwLayerSimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(6, renderer.getIndex());
@@ -1202,14 +1346,17 @@
OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
*(parent->getLayerHandle()) = &parentLayer;
- auto syncedList = TestUtils::createSyncedNodeList(parent);
+ auto syncedNode = TestUtils::getSyncedNode(parent);
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
- FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- syncedList, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferLayers(layerUpdateQueue);
+ frameBuilder.deferRenderNode(*syncedNode);
+
HwLayerComplexTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(14, renderer.getIndex());
@@ -1260,15 +1407,14 @@
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*layerHandle = &layer;
- auto syncedNodeList = TestUtils::createSyncedNodeList(node);
+ TestUtils::syncHierarchyPropertiesAndDisplayList(node);
// only enqueue partial damage
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
// Draw, but pass empty node list, so no work is done for primary frame
- FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
- sEmptyNodeList, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance());
BuildLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(3, renderer.getIndex());
@@ -1315,8 +1461,10 @@
drawOrderedRect(&canvas, 8);
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
- TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ZReorderTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
@@ -1406,8 +1554,10 @@
canvas.restore();
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
- TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ProjectionReorderTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(3, renderer.getIndex());
@@ -1486,11 +1636,16 @@
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
- auto syncedList = TestUtils::createSyncedNodeList(parent);
+ auto syncedNode = TestUtils::getSyncedNode(parent);
+
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
- FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
- syncedList, sLightGeometry, Caches::getInstance());
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferLayers(layerUpdateQueue);
+ frameBuilder.deferRenderNode(*syncedNode);
+
ProjectionHwLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(6, renderer.getIndex());
@@ -1545,8 +1700,10 @@
canvas.drawRenderNode(child.get());
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
- TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ProjectionChildScrollTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
@@ -1588,8 +1745,10 @@
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ShadowTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
@@ -1632,9 +1791,10 @@
canvas.restoreToCount(count);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(parent),
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ShadowSaveLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(6, renderer.getIndex());
@@ -1681,12 +1841,15 @@
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
- auto syncedList = TestUtils::createSyncedNodeList(parent);
+ auto syncedNode = TestUtils::getSyncedNode(parent);
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
- FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- syncedList,
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
+ frameBuilder.deferLayers(layerUpdateQueue);
+ frameBuilder.deferRenderNode(*syncedNode);
+
ShadowHwLayerTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
@@ -1713,10 +1876,10 @@
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
});
-
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(parent),
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ShadowLayeringTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -1743,9 +1906,10 @@
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
- TestUtils::createSyncedNodeList(parent),
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
(FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
+
ShadowClippingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
@@ -1772,8 +1936,10 @@
canvas.drawRect(0, 0, 100, 100, paint);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
PropertyTestRenderer renderer(opValidateCallback);
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
@@ -1915,10 +2081,12 @@
paint.setColor(SK_ColorWHITE);
canvas.drawRect(0, 0, 10000, 10000, paint);
});
- auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
+ auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- nodes, sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*syncedNode);
+
SaveLayerAlphaClipTestRenderer renderer(outObservedData);
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -1991,8 +2159,10 @@
canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
});
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
- TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
ClipReplaceTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index e2fc376..6148b33 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -26,7 +26,6 @@
using namespace android;
using namespace android::uirenderer;
-const LayerUpdateQueue sEmptyLayerUpdateQueue;
const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
@@ -43,8 +42,9 @@
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
- TestUtils::createSyncedNodeList(node), sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
+ sLightGeometery, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
@@ -59,8 +59,9 @@
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
- TestUtils::createSyncedNodeList(node), sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
+ sLightGeometery, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}