diff options
author | 2016-03-29 15:01:41 -0700 | |
---|---|---|
committer | 2016-03-29 16:50:32 -0700 | |
commit | 6246d27813f25b85f6e4b5cb1121fe8484bcce2d (patch) | |
tree | 404d22648cb87d218312937f3ad8cf8fb68da7be | |
parent | af64f6341bdbca93aff3d68264af48e74faa9e58 (diff) |
Support buildLayer in new pipeline
bug:26561995
bug:27620686
Change-Id: I6c39f9a077e7e6002d3c01b8888238fd17b0f02a
-rw-r--r-- | libs/hwui/FrameBuilder.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/FrameBuilder.h | 16 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 3 | ||||
-rw-r--r-- | libs/hwui/tests/unit/FrameBuilderTests.cpp | 102 |
5 files changed, 132 insertions, 12 deletions
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index b18836f175ea..9c46c0058f68 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -37,7 +37,8 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip, const LightGeometry& lightGeometry, const Rect &contentDrawBounds, Caches& caches) : mCanvasState(*this) , mCaches(caches) - , mLightRadius(lightGeometry.radius) { + , mLightRadius(lightGeometry.radius) + , mDrawFbo0(!nodes.empty()) { ATRACE_NAME("prepare drawing commands"); mLayerBuilders.reserve(layers.entries().size()); diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h index 02c05cb1bbbe..e41822729695 100644 --- a/libs/hwui/FrameBuilder.h +++ b/libs/hwui/FrameBuilder.h @@ -137,12 +137,14 @@ public: } GL_CHECKPOINT(MODERATE); - const LayerBuilder& fbo0 = *(mLayerBuilders[0]); - renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); - GL_CHECKPOINT(MODERATE); - fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endFrame(fbo0.repaintRect); + if (CC_LIKELY(mDrawFbo0)) { + const LayerBuilder& fbo0 = *(mLayerBuilders[0]); + renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); + GL_CHECKPOINT(MODERATE); + fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); + GL_CHECKPOINT(MODERATE); + renderer.endFrame(fbo0.repaintRect); + } } void dump() const { @@ -239,6 +241,8 @@ private: // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches LinearAllocator mAllocator; + + const bool mDrawFbo0; }; }; // namespace uirenderer diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index eee527881a6a..6933b2f1e23c 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -86,10 +86,12 @@ void CanvasContext::destroy() { freePrefetechedLayers(); destroyHardwareResources(); mAnimationContext->destroy(); +#if !HWUI_NEW_OPS if (mCanvas) { delete mCanvas; mCanvas = nullptr; } +#endif } void CanvasContext::setSurface(Surface* surface) { @@ -587,9 +589,11 @@ void CanvasContext::freePrefetechedLayers() { void CanvasContext::buildLayer(RenderNode* node) { ATRACE_CALL(); - if (!mEglManager.hasEglContext() || !mCanvas) { - return; - } + if (!mEglManager.hasEglContext()) return; +#if !HWUI_NEW_OPS + if (!mCanvas) return; +#endif + // buildLayer() will leave the tree in an unknown state, so we must stop drawing stopDrawing(); @@ -609,7 +613,15 @@ void CanvasContext::buildLayer(RenderNode* node) { node->setPropertyFieldsDirty(RenderNode::GENERIC); #if HWUI_NEW_OPS - // TODO: support buildLayer + static const std::vector< sp<RenderNode> > emptyNodeList; + auto& caches = Caches::getInstance(); + FrameBuilder frameBuilder(mLayerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1, + emptyNodeList, mLightGeometry, mContentDrawBounds, caches); + mLayerUpdateQueue.clear(); + BakedOpRenderer renderer(caches, mRenderThread.renderState(), + mOpaque, mLightInfo); + LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); + frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); #else mCanvas->markLayersAsBuildLayers(); mCanvas->flushLayerUpdates(); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 6706c30f148b..6d0889ea7a54 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -196,10 +196,11 @@ private: RingBuffer<SwapHistory, 3> mSwapHistory; bool mOpaque; - OpenGLRenderer* mCanvas = nullptr; #if HWUI_NEW_OPS BakedOpRenderer::LightInfo mLightInfo; FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 }; +#else + OpenGLRenderer* mCanvas = nullptr; #endif bool mHaveNewSurface = false; diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index ba22f91cde9d..7dfafb9117de 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -30,6 +30,7 @@ namespace android { namespace uirenderer { const LayerUpdateQueue sEmptyLayerUpdateQueue; +const std::vector< sp<RenderNode> > sEmptyNodeList; const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50}; @@ -216,6 +217,49 @@ RENDERTHREAD_TEST(FrameBuilder, simpleBatching) { << "Expect number of ops = 2 * loop count"; } +RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) { + class EmptyNoFbo0TestRenderer : public TestRendererBase { + public: + void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { + ADD_FAILURE() << "Primary frame draw not expected in this test"; + } + void endFrame(const Rect& repaintRect) override { + ADD_FAILURE() << "Primary frame draw not expected in this test"; + } + }; + + // Pass empty node list, so no work is enqueued for Fbo0 + FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + sEmptyNodeList, sLightGeometry, Caches::getInstance()); + EmptyNoFbo0TestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); +} + +RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) { + class EmptyWithFbo0TestRenderer : public TestRendererBase { + public: + void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { + EXPECT_EQ(0, mIndex++); + } + void endFrame(const Rect& repaintRect) override { + EXPECT_EQ(1, mIndex++); + } + }; + auto node = TestUtils::createNode(10, 10, 110, 110, + [](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()); + EmptyWithFbo0TestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced," + " but fbo0 update lifecycle should still be observed"; +} + RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) { class AvoidOverdrawRectsTestRenderer : public TestRendererBase { public: @@ -1152,6 +1196,64 @@ RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) { *(parent->getLayerHandle()) = nullptr; } + +RENDERTHREAD_TEST(FrameBuilder, buildLayer) { + class BuildLayerTestRenderer : public TestRendererBase { + public: + void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { + EXPECT_EQ(0, mIndex++); + EXPECT_EQ(100u, offscreenBuffer->viewportWidth); + EXPECT_EQ(100u, offscreenBuffer->viewportHeight); + EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect); + } + void onColorOp(const ColorOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); + + EXPECT_TRUE(state.computedState.transform.isIdentity()) + << "Transform should be reset within layer"; + + EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect()) + << "Damage rect should be used to clip layer content"; + } + void endLayer() override { + EXPECT_EQ(2, mIndex++); + } + void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { + ADD_FAILURE() << "Primary frame draw not expected in this test"; + } + void endFrame(const Rect& repaintRect) override { + ADD_FAILURE() << "Primary frame draw not expected in this test"; + } + }; + + auto node = TestUtils::createNode(10, 10, 110, 110, + [](RenderProperties& props, RecordingCanvas& canvas) { + props.mutateLayerProperties().setType(LayerType::RenderLayer); + canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode); + }); + OffscreenBuffer** layerHandle = node->getLayerHandle(); + + // create RenderNode's layer here in same way prepareTree would + OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100); + *layerHandle = &layer; + + auto syncedNodeList = TestUtils::createSyncedNodeList(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()); + BuildLayerTestRenderer renderer; + frameBuilder.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(3, renderer.getIndex()); + + // clean up layer pointer, so we can safely destruct RenderNode + *layerHandle = nullptr; +} + static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) { SkPaint paint; paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel |