Commit 13185caf authored by boliu's avatar boliu Committed by Commit bot

Fix resourceless software draw crash

Resourceless software draw can only have a single root layer
render surface. Since decision to create render surface has
been moved to main thread, this condition no longer holds
and the mismatch causes a crash in LayerIterator.

Instead tweak the logic to only *use* the root layer render
surface, while being possible to to have more than one
render surface in the tree. This means only the root render
layer can be a render target.

BUG=466695

Review URL: https://codereview.chromium.org/1007623002

Cr-Commit-Position: refs/heads/master@{#320821}
parent 0d9f28dc
......@@ -172,12 +172,14 @@ bool LayerTreeHostCommon::RenderSurfaceContributesToTarget(
// A layer will either contribute its own content, or its render surface's
// content, to the target surface. The layer contributes its surface's content
// when both the following are true:
// (1) The layer actually has a render surface, and
// (1) The layer actually has a render surface and rendering into that
// surface, and
// (2) The layer's render surface is not the same as the target surface.
//
// Otherwise, the layer just contributes itself to the target surface.
return layer->render_surface() && layer->id() != target_surface_layer_id;
return layer->render_target() == layer &&
layer->id() != target_surface_layer_id;
}
template <typename LayerType>
......
......@@ -7031,6 +7031,27 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(2u, render_surface_layer_list.size());
int count_represents_target_render_surface = 0;
int count_represents_contributing_render_surface = 0;
int count_represents_itself = 0;
auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list);
for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list);
it != end; ++it) {
if (it.represents_target_render_surface())
count_represents_target_render_surface++;
if (it.represents_contributing_render_surface())
count_represents_contributing_render_surface++;
if (it.represents_itself())
count_represents_itself++;
}
// Two render surfaces.
EXPECT_EQ(2, count_represents_target_render_surface);
// Second render surface contributes to root render surface.
EXPECT_EQ(1, count_represents_contributing_render_surface);
// All 4 layers represent itself.
EXPECT_EQ(4, count_represents_itself);
}
{
......@@ -7041,6 +7062,27 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(1u, render_surface_layer_list.size());
int count_represents_target_render_surface = 0;
int count_represents_contributing_render_surface = 0;
int count_represents_itself = 0;
auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list);
for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list);
it != end; ++it) {
if (it.represents_target_render_surface())
count_represents_target_render_surface++;
if (it.represents_contributing_render_surface())
count_represents_contributing_render_surface++;
if (it.represents_itself())
count_represents_itself++;
}
// Only root layer has a render surface.
EXPECT_EQ(1, count_represents_target_render_surface);
// No layer contributes a render surface to root render surface.
EXPECT_EQ(0, count_represents_contributing_render_surface);
// All 4 layers represent itself.
EXPECT_EQ(4, count_represents_itself);
}
}
......
......@@ -2960,6 +2960,92 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize);
class LayerTreeHostTestResourcelessSoftwareDraw : public LayerTreeHostTest {
public:
void SetupTree() override {
root_layer_ = FakePictureLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(gfx::Size(50, 50));
parent_layer_ = FakePictureLayer::Create(&client_);
parent_layer_->SetIsDrawable(true);
parent_layer_->SetBounds(gfx::Size(50, 50));
parent_layer_->SetForceRenderSurface(true);
child_layer_ = FakePictureLayer::Create(&client_);
child_layer_->SetIsDrawable(true);
child_layer_->SetBounds(gfx::Size(50, 50));
root_layer_->AddChild(parent_layer_);
parent_layer_->AddChild(child_layer_);
layer_tree_host()->SetRootLayer(root_layer_);
LayerTreeHostTest::SetupTree();
}
scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
return FakeOutputSurface::CreateDeferredGL(
make_scoped_ptr(new SoftwareOutputDevice), delegating_renderer());
}
void BeginTest() override {
PostSetNeedsCommitToMainThread();
swap_count_ = 0;
}
DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame_data,
DrawResult draw_result) override {
if (host_impl->GetDrawMode() == DRAW_MODE_RESOURCELESS_SOFTWARE) {
EXPECT_EQ(1u, frame_data->render_passes.size());
// Has at least 3 quads for each layer.
RenderPass* render_pass = frame_data->render_passes[0];
EXPECT_GE(render_pass->quad_list.size(), 3u);
} else {
EXPECT_EQ(2u, frame_data->render_passes.size());
// At least root layer quad in root render pass.
EXPECT_GE(frame_data->render_passes[0]->quad_list.size(), 1u);
// At least parent and child layer quads in parent render pass.
EXPECT_GE(frame_data->render_passes[1]->quad_list.size(), 2u);
}
return draw_result;
}
void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) override {
swap_count_++;
switch (swap_count_) {
case 1: {
gfx::Transform identity;
gfx::Rect empty_rect;
bool resourceless_software_draw = true;
host_impl->SetExternalDrawConstraints(identity, empty_rect, empty_rect,
empty_rect, identity,
resourceless_software_draw);
host_impl->SetFullRootLayerDamage();
host_impl->SetNeedsRedraw();
break;
}
case 2:
EndTest();
break;
default:
NOTREACHED();
}
}
void AfterTest() override {}
private:
FakeContentLayerClient client_;
scoped_refptr<Layer> root_layer_;
scoped_refptr<Layer> parent_layer_;
scoped_refptr<Layer> child_layer_;
int swap_count_;
};
MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestResourcelessSoftwareDraw);
class LayerTreeHostTestDeferredInitializeWithGpuRasterization
: public LayerTreeHostTestDeferredInitialize {
void InitializeSettings(LayerTreeSettings* settings) override {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment