Index: cc/trees/layer_tree_host_unittest_context.cc |
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc |
index c250b0c6bb9154ff79f0f48bfd0b94fdc355c9c2..1674f5647150cd2be6229e60cd014f5d56edde95 100644 |
--- a/cc/trees/layer_tree_host_unittest_context.cc |
+++ b/cc/trees/layer_tree_host_unittest_context.cc |
@@ -1461,6 +1461,29 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit |
EXPECT_EQ(1, times_output_surface_created_); |
} |
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, |
+ LayerTreeHostImpl::FrameData* frame_data, |
+ bool result) OVERRIDE { |
+ EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0); |
+ EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1); |
+ return true; |
+ } |
+ |
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { |
+ // We should only draw for the readback and the replacement commit. |
+ // The replacement commit will also be the first commit after output |
+ // surface initialization. |
+ EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0); |
+ EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1); |
+ } |
+ |
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, |
+ bool result) OVERRIDE { |
+ // We should only swap for the replacement commit. |
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1); |
+ EndTest(); |
+ } |
+ |
private: |
int times_output_surface_created_; |
}; |
@@ -1468,6 +1491,164 @@ class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit |
SINGLE_AND_MULTI_THREAD_TEST_F( |
LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit); |
+// This test verifies that losing an output surface right during a |
+// simultaneous readback and forced redraw works and does not deadlock. |
+class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw |
+ : public LayerTreeHostContextTest { |
+ protected: |
+ static const int kCommitAfterFirstOutputSurfaceInitSourceFrameNumber = 0; |
+ static const int kReadbackCommitSourceFrameNumber = 1; |
+ static const int kReadbackReplacementCommitSourceFrameNumber = 2; |
+ static const int kCommitAfterSecondOutputSurfaceInitSourceFrameNumber = 3; |
+ |
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { |
+ // This enables forced draws after a single prepare to draw failure. |
+ settings->timeout_and_draw_when_animation_checkerboards = true; |
+ settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1; |
+ } |
+ |
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } |
+ |
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, |
+ LayerTreeHostImpl::FrameData* frame_data, |
+ bool result) OVERRIDE { |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterFirstOutputSurfaceInitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterSecondOutputSurfaceInitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kReadbackCommitSourceFrameNumber); |
+ |
+ // Before we react to the failed draw by initiating the forced draw |
+ // sequence, start a readback on the main thread and then lose the context |
+ // to start output surface initialization all at the same time. |
+ if (host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterFirstOutputSurfaceInitSourceFrameNumber) { |
+ PostReadbackToMainThread(); |
+ LoseContext(); |
+ } |
+ |
+ // Returning false will eventually result in a forced draw. |
+ return false; |
+ } |
+ |
+ virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, |
+ bool success) OVERRIDE { |
+ // -1 is for the first output surface initialization. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == -1 || |
+ host_impl->active_tree()->source_frame_number() == |
+ kReadbackReplacementCommitSourceFrameNumber); |
+ } |
+ |
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { |
+ // We should only draw the first commit after output surface initialization |
+ // and attempt to draw the readback commit (which will fail). |
+ // All others should abort because the output surface is lost. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterSecondOutputSurfaceInitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kReadbackCommitSourceFrameNumber); |
+ } |
+ |
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, |
+ bool result) OVERRIDE { |
+ // We should only swap the first commit after the second output surface |
+ // initialization. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterSecondOutputSurfaceInitSourceFrameNumber); |
+ EndTest(); |
+ } |
+ |
+ virtual void AfterTest() OVERRIDE {} |
+}; |
+ |
+MULTI_THREAD_TEST_F( |
+ LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw); |
+ |
+// This test verifies that losing an output surface right before a |
+// simultaneous readback and forced redraw works and does not deadlock. |
+class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit |
+ : public LayerTreeHostContextTest { |
+ protected: |
+ static const int kCommitAfterFirstOutputSurfaceInitSourceFrameNumber = 0; |
+ static const int kReadbackCommitSourceFrameNumber = 1; |
+ static const int kReadbackReplacementCommitSourceFrameNumber = 2; |
+ static const int kForcedDrawCommitSourceFrameNumber = 2; |
+ static const int kCommitAfterSecondOutputSurfaceInitSourceFrameNumber = 2; |
+ |
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE { |
+ // This enables forced draws after a single prepare to draw failure. |
+ settings->timeout_and_draw_when_animation_checkerboards = true; |
+ settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1; |
+ } |
+ |
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); } |
+ |
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, |
+ LayerTreeHostImpl::FrameData* frame_data, |
+ bool result) OVERRIDE { |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterFirstOutputSurfaceInitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterSecondOutputSurfaceInitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kReadbackCommitSourceFrameNumber); |
+ |
+ // Before we react to the failed draw by initiating the forced draw |
+ // sequence, start a readback on the main thread and then lose the context |
+ // to start output surface initialization all at the same time. |
+ if (host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterFirstOutputSurfaceInitSourceFrameNumber) { |
+ LoseContext(); |
+ } |
+ |
+ // Returning false will eventually result in a forced draw. |
+ return false; |
+ } |
+ |
+ virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE { |
+ EXPECT_TRUE(succeeded); |
+ if (layer_tree_host()->source_frame_number() > 0) { |
+ // Perform a readback right after the second output surface |
+ // initialization. |
+ char pixels[4]; |
+ layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1)); |
+ } |
+ } |
+ |
+ virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, |
+ bool success) OVERRIDE { |
+ // -1 is for the first output surface initialization. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == -1 || |
+ host_impl->active_tree()->source_frame_number() == |
+ kCommitAfterFirstOutputSurfaceInitSourceFrameNumber); |
+ } |
+ |
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { |
+ // We should only draw the first commit after output surface initialization |
+ // and attempt to draw the readback commit (which will fail). |
+ // All others should abort because the output surface is lost. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kForcedDrawCommitSourceFrameNumber || |
+ host_impl->active_tree()->source_frame_number() == |
+ kReadbackCommitSourceFrameNumber); |
+ } |
+ |
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, |
+ bool result) OVERRIDE { |
+ // We should only swap the first commit after the second output surface |
+ // initialization. |
+ EXPECT_TRUE(host_impl->active_tree()->source_frame_number() == |
+ kForcedDrawCommitSourceFrameNumber); |
+ EndTest(); |
+ } |
+ |
+ virtual void AfterTest() OVERRIDE {} |
+}; |
+ |
+MULTI_THREAD_TEST_F( |
+ LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit); |
+ |
class ImplSidePaintingLayerTreeHostContextTest |
: public LayerTreeHostContextTest { |
public: |