cc: Make gpu rasterization flag per page instead of per layer.

BUG=367198

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268320 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index befedf7..60360d3 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1043,6 +1043,10 @@
   return false;
 }
 
+bool Layer::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
 scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
   if (client_)
     return client_->TakeDebugInfo();
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 5e4a4018..7e7d2861 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -363,6 +363,7 @@
   virtual void SetIsMask(bool is_mask) {}
   virtual void ReduceMemoryUsage() {}
   virtual void OnOutputSurfaceCreated() {}
+  virtual bool IsSuitableForGpuRasterization() const;
 
   virtual scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo();
 
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index ca30346..700d285 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -53,7 +53,7 @@
   }
 
   layer_impl->SetIsMask(is_mask_);
-  layer_impl->SetUseGpuRasterization(ShouldUseGpuRasterization());
+  layer_impl->SetUseGpuRasterization(layer_tree_host()->UseGpuRasterization());
 
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
@@ -142,17 +142,6 @@
   is_mask_ = is_mask;
 }
 
-bool PictureLayer::ShouldUseGpuRasterization() const {
-  if (layer_tree_host()->settings().gpu_rasterization_forced) {
-    return true;
-  } else if (layer_tree_host()->settings().gpu_rasterization_enabled) {
-    return layer_tree_host()->has_gpu_rasterization_trigger() &&
-           pile_->is_suitable_for_gpu_rasterization();
-  } else {
-    return false;
-  }
-}
-
 bool PictureLayer::SupportsLCDText() const {
   return true;
 }
@@ -178,6 +167,10 @@
   return picture;
 }
 
+bool PictureLayer::IsSuitableForGpuRasterization() const {
+  return pile_->is_suitable_for_gpu_rasterization();
+}
+
 void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
   benchmark->RunOnLayer(this);
 }
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 184eea78..dd1bbfe 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -35,13 +35,12 @@
   virtual void SetIsMask(bool is_mask) OVERRIDE;
   virtual bool SupportsLCDText() const OVERRIDE;
   virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
+  virtual bool IsSuitableForGpuRasterization() const OVERRIDE;
 
   virtual void RunMicroBenchmark(MicroBenchmark* benchmark) OVERRIDE;
 
   ContentLayerClient* client() { return client_; }
 
-  bool ShouldUseGpuRasterization() const;
-
   PicturePile* GetPicturePileForTesting() const { return pile_.get(); }
 
  protected:
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index dfc24a0..3edb9c8 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -69,88 +69,19 @@
   }
 }
 
-TEST(PictureLayerTest, ForcedCpuRaster) {
+TEST(PictureLayerTest, SuitableForGpuRasterization) {
   MockContentLayerClient client;
   scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
-  host->SetRootLayer(layer);
-
-  // The default value is false.
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization cannot be enabled even with raster hint.
-  host->set_has_gpu_rasterization_trigger(true);
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
-}
-
-TEST(PictureLayerTest, ForceGpuRaster) {
-  MockContentLayerClient client;
-  scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
-  LayerTreeSettings settings;
-  settings.gpu_rasterization_forced = true;
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(settings);
-  host->SetRootLayer(layer);
-
-  // The default value is true.
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization cannot be disabled even with raster hint.
-  host->set_has_gpu_rasterization_trigger(false);
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization cannot be disabled even with skia veto.
   PicturePile* pile = layer->GetPicturePileForTesting();
+
+  // Layer is suitable for gpu rasterization by default.
   EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
-  pile->SetUnsuitableForGpuRasterizationForTesting();
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
-}
-
-TEST(PictureLayerTest, EnableGpuRaster) {
-  MockContentLayerClient client;
-  scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
-  LayerTreeSettings settings;
-  settings.gpu_rasterization_enabled = true;
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(settings);
-  host->SetRootLayer(layer);
-
-  // The default value is false.
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization can be enabled.
-  host->set_has_gpu_rasterization_trigger(true);
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization can be disabled.
-  host->set_has_gpu_rasterization_trigger(false);
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
-
-  // Gpu rasterization can be enabled again.
-  host->set_has_gpu_rasterization_trigger(true);
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
-}
-
-TEST(PictureLayerTest, VetoGpuRaster) {
-  MockContentLayerClient client;
-  scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
-  LayerTreeSettings settings;
-  settings.gpu_rasterization_enabled = true;
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(settings);
-  host->SetRootLayer(layer);
-
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
-
-  host->set_has_gpu_rasterization_trigger(true);
-  EXPECT_TRUE(layer->ShouldUseGpuRasterization());
+  EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
 
   // Veto gpu rasterization.
-  PicturePile* pile = layer->GetPicturePileForTesting();
-  EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
   pile->SetUnsuitableForGpuRasterizationForTesting();
-  EXPECT_FALSE(layer->ShouldUseGpuRasterization());
+  EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+  EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
 }
 
 }  // namespace
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 65d5dd6f..7df31866 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -109,6 +109,7 @@
       max_page_scale_factor_(1.f),
       trigger_idle_updates_(true),
       has_gpu_rasterization_trigger_(false),
+      content_is_suitable_for_gpu_rasterization_(true),
       background_color_(SK_ColorWHITE),
       has_transparent_background_(false),
       partial_texture_update_requests_(0),
@@ -589,6 +590,10 @@
   if (hud_layer_.get())
     hud_layer_->RemoveFromParent();
 
+  // Reset gpu rasterization flag.
+  // This flag is sticky until a new tree comes along.
+  content_is_suitable_for_gpu_rasterization_ = true;
+
   SetNeedsFullTreeSync();
 }
 
@@ -608,6 +613,17 @@
   proxy_->SetDebugState(debug_state);
 }
 
+bool LayerTreeHost::UseGpuRasterization() const {
+  if (settings_.gpu_rasterization_forced) {
+    return true;
+  } else if (settings_.gpu_rasterization_enabled) {
+    return has_gpu_rasterization_trigger_ &&
+           content_is_suitable_for_gpu_rasterization_;
+  } else {
+    return false;
+  }
+}
+
 void LayerTreeHost::SetViewportSize(const gfx::Size& device_viewport_size) {
   if (device_viewport_size == device_viewport_size_)
     return;
@@ -982,6 +998,15 @@
       DCHECK(!it->paint_properties().bounds.IsEmpty());
       *did_paint_content |= it->Update(queue, &occlusion_tracker);
       *need_more_updates |= it->NeedMoreUpdates();
+      // Note the '&&' with previous is-suitable state.
+      // This means that once the layer-tree becomes unsuitable for gpu
+      // rasterization due to some content, it will continue to be unsuitable
+      // even if that content is replaced by gpu-friendly content.
+      // This is to avoid switching back-and-forth between gpu and sw
+      // rasterization which may be both bad for performance and visually
+      // jarring.
+      content_is_suitable_for_gpu_rasterization_ &=
+          it->IsSuitableForGpuRasterization();
     }
 
     occlusion_tracker.LeaveLayer(it);
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index b58ce39..380cc95f 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -197,6 +197,7 @@
   void set_has_gpu_rasterization_trigger(bool has_trigger) {
     has_gpu_rasterization_trigger_ = has_trigger;
   }
+  bool UseGpuRasterization() const;
 
   void SetViewportSize(const gfx::Size& device_viewport_size);
   void SetOverdrawBottomHeight(float overdraw_bottom_height);
@@ -399,6 +400,7 @@
   gfx::Transform impl_transform_;
   bool trigger_idle_updates_;
   bool has_gpu_rasterization_trigger_;
+  bool content_is_suitable_for_gpu_rasterization_;
 
   SkColor background_color_;
   bool has_transparent_background_;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 1bf42136..ff8c08d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -4970,55 +4970,135 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestHighResRequiredAfterEvictingUIResources);
 
+class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest {
+ protected:
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
+
+    EXPECT_FALSE(settings->gpu_rasterization_enabled);
+    EXPECT_FALSE(settings->gpu_rasterization_forced);
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    LayerTreeHostTest::SetupTree();
+
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
+  }
+
+  virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+    // Setting gpu rasterization trigger does not enable gpu rasterization.
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->pending_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
+
+    EXPECT_FALSE(layer_impl->ShouldUseGpuRasterization());
+  }
+
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
+
+    EXPECT_FALSE(layer_impl->ShouldUseGpuRasterization());
+    EndTest();
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+  FakeContentLayerClient layer_client_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationDefault);
+
 class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest {
  protected:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
     settings->impl_side_painting = true;
+
+    EXPECT_FALSE(settings->gpu_rasterization_enabled);
     settings->gpu_rasterization_enabled = true;
   }
 
   virtual void SetupTree() OVERRIDE {
     LayerTreeHostTest::SetupTree();
 
-    scoped_refptr<PictureLayer> parent = PictureLayer::Create(&client_);
-    parent->SetBounds(gfx::Size(10, 10));
-    layer_tree_host()->root_layer()->AddChild(parent);
-
-    scoped_refptr<Layer> child = PictureLayer::Create(&client_);
-    child->SetBounds(gfx::Size(10, 10));
-    parent->AddChild(child);
-
-    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+  virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+    // Gpu rasterization trigger is relevant.
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+    // Content-based veto is relevant as well.
+    pile->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+    // Veto will take effect when layers are updated.
+    // The results will be verified after commit is completed below.
+    // Since we are manually marking picture pile as unsuitable,
+    // make sure that the layer gets a chance to update.
+    layer->SetNeedsDisplay();
+    PostSetNeedsCommitToMainThread();
+  }
 
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     LayerImpl* root = host_impl->pending_tree()->root_layer();
-    PictureLayerImpl* parent =
+    PictureLayerImpl* layer_impl =
         static_cast<PictureLayerImpl*>(root->children()[0]);
-    PictureLayerImpl* child =
-        static_cast<PictureLayerImpl*>(parent->children()[0]);
 
-    EXPECT_TRUE(parent->ShouldUseGpuRasterization());
-    EXPECT_TRUE(child->ShouldUseGpuRasterization());
+    EXPECT_FALSE(layer_impl->ShouldUseGpuRasterization());
   }
 
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     LayerImpl* root = host_impl->active_tree()->root_layer();
-    PictureLayerImpl* parent =
+    PictureLayerImpl* layer_impl =
         static_cast<PictureLayerImpl*>(root->children()[0]);
-    PictureLayerImpl* child =
-        static_cast<PictureLayerImpl*>(parent->children()[0]);
 
-    EXPECT_TRUE(parent->ShouldUseGpuRasterization());
-    EXPECT_TRUE(child->ShouldUseGpuRasterization());
+    EXPECT_FALSE(layer_impl->ShouldUseGpuRasterization());
     EndTest();
   }
 
   virtual void AfterTest() OVERRIDE {}
 
-  FakeContentLayerClient client_;
+  FakeContentLayerClient layer_client_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled);
@@ -5027,55 +5107,69 @@
  protected:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
     settings->impl_side_painting = true;
+
+    EXPECT_FALSE(settings->gpu_rasterization_forced);
     settings->gpu_rasterization_forced = true;
   }
 
   virtual void SetupTree() OVERRIDE {
     LayerTreeHostTest::SetupTree();
 
-    scoped_refptr<PictureLayer> parent = PictureLayer::Create(&client_);
-    parent->SetBounds(gfx::Size(10, 10));
-    layer_tree_host()->root_layer()->AddChild(parent);
-
-    scoped_refptr<Layer> child = PictureLayer::Create(&client_);
-    child->SetBounds(gfx::Size(10, 10));
-    parent->AddChild(child);
-
-    layer_tree_host()->set_has_gpu_rasterization_trigger(false);
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+  virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+
+    // With gpu rasterization forced, gpu rasterization trigger is irrelevant.
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+    // Content-based veto is irrelevant as well.
+    pile->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+    // Veto will take effect when layers are updated.
+    // The results will be verified after commit is completed below.
+    // Since we are manually marking picture pile as unsuitable,
+    // make sure that the layer gets a chance to update.
+    layer->SetNeedsDisplay();
+    PostSetNeedsCommitToMainThread();
+  }
 
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     LayerImpl* root = host_impl->pending_tree()->root_layer();
-    PictureLayerImpl* parent =
+    PictureLayerImpl* layer_impl =
         static_cast<PictureLayerImpl*>(root->children()[0]);
-    PictureLayerImpl* child =
-        static_cast<PictureLayerImpl*>(parent->children()[0]);
 
-    // All layers should use GPU rasterization, regardless of whether a GPU
-    // rasterization trigger has been set.
-    EXPECT_TRUE(parent->ShouldUseGpuRasterization());
-    EXPECT_TRUE(child->ShouldUseGpuRasterization());
+    EXPECT_TRUE(layer_impl->ShouldUseGpuRasterization());
   }
 
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     LayerImpl* root = host_impl->active_tree()->root_layer();
-    PictureLayerImpl* parent =
+    PictureLayerImpl* layer_impl =
         static_cast<PictureLayerImpl*>(root->children()[0]);
-    PictureLayerImpl* child =
-        static_cast<PictureLayerImpl*>(parent->children()[0]);
 
-    // All layers should use GPU rasterization, regardless of whether a GPU
-    // rasterization trigger has been set.
-    EXPECT_TRUE(parent->ShouldUseGpuRasterization());
-    EXPECT_TRUE(child->ShouldUseGpuRasterization());
+    EXPECT_TRUE(layer_impl->ShouldUseGpuRasterization());
     EndTest();
   }
 
   virtual void AfterTest() OVERRIDE {}
 
-  FakeContentLayerClient client_;
+  FakeContentLayerClient layer_client_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced);