Merge "Support buildLayer in new pipeline" into nyc-dev

This commit is contained in:
Chris Craik
2016-03-30 16:40:56 +00:00
committed by Android (Google) Code Review
5 changed files with 132 additions and 12 deletions

View File

@@ -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());

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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