Merge "Support buildLayer in new pipeline" into nyc-dev
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user