diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-11-12 17:59:43 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-11-12 17:59:43 +0000 |
commit | 1850ca92fc5c5faa2907b3befcf40067265148cc (patch) | |
tree | 7d10585f25356b3ee63b5ab4255161fe27725ee4 /cc | |
parent | e9e1f6521e4fef99aa1a1928c70ef3dfb55a8d9e (diff) | |
download | chromium_org-1850ca92fc5c5faa2907b3befcf40067265148cc.tar.gz |
Merge from Chromium at DEPS revision 03655fd3f6d7
This commit was generated by merge_to_master.py.
Change-Id: Ifba5396691b9164ba027be04398f7bc8e938750d
Diffstat (limited to 'cc')
54 files changed, 1309 insertions, 560 deletions
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index a578b61c93..e9ef9e2728 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn @@ -112,6 +112,7 @@ component("cc") { "debug/unittest_only_benchmark.h", "debug/unittest_only_benchmark_impl.cc", "debug/unittest_only_benchmark_impl.h", + "input/input_handler.cc", "input/input_handler.h", "input/page_scale_animation.cc", "input/page_scale_animation.h", @@ -705,6 +706,7 @@ test("cc_unittests") { "layers/scrollbar_layer_unittest.cc", "layers/solid_color_layer_impl_unittest.cc", "layers/solid_color_scrollbar_layer_impl_unittest.cc", + "layers/surface_layer_unittest.cc", "layers/surface_layer_impl_unittest.cc", "layers/texture_layer_unittest.cc", "layers/texture_layer_impl_unittest.cc", @@ -140,6 +140,7 @@ 'debug/unittest_only_benchmark.h', 'debug/unittest_only_benchmark_impl.cc', 'debug/unittest_only_benchmark_impl.h', + 'input/input_handler.cc', 'input/input_handler.h', 'input/page_scale_animation.cc', 'input/page_scale_animation.h', diff --git a/cc/cc.target.darwin-arm.mk b/cc/cc.target.darwin-arm.mk index 250260e286..e8bdae628e 100644 --- a/cc/cc.target.darwin-arm.mk +++ b/cc/cc.target.darwin-arm.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.darwin-arm64.mk b/cc/cc.target.darwin-arm64.mk index bfb600b457..4561606db7 100644 --- a/cc/cc.target.darwin-arm64.mk +++ b/cc/cc.target.darwin-arm64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.darwin-mips.mk b/cc/cc.target.darwin-mips.mk index 4e8b2b331c..5239409cd0 100644 --- a/cc/cc.target.darwin-mips.mk +++ b/cc/cc.target.darwin-mips.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.darwin-mips64.mk b/cc/cc.target.darwin-mips64.mk index 4e8b2b331c..5239409cd0 100644 --- a/cc/cc.target.darwin-mips64.mk +++ b/cc/cc.target.darwin-mips64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.darwin-x86.mk b/cc/cc.target.darwin-x86.mk index ce5a3ee8dd..af5e231d79 100644 --- a/cc/cc.target.darwin-x86.mk +++ b/cc/cc.target.darwin-x86.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.darwin-x86_64.mk b/cc/cc.target.darwin-x86_64.mk index 2da1bf8654..124e9da220 100644 --- a/cc/cc.target.darwin-x86_64.mk +++ b/cc/cc.target.darwin-x86_64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-arm.mk b/cc/cc.target.linux-arm.mk index 250260e286..e8bdae628e 100644 --- a/cc/cc.target.linux-arm.mk +++ b/cc/cc.target.linux-arm.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-arm64.mk b/cc/cc.target.linux-arm64.mk index bfb600b457..4561606db7 100644 --- a/cc/cc.target.linux-arm64.mk +++ b/cc/cc.target.linux-arm64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-mips.mk b/cc/cc.target.linux-mips.mk index 4e8b2b331c..5239409cd0 100644 --- a/cc/cc.target.linux-mips.mk +++ b/cc/cc.target.linux-mips.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-mips64.mk b/cc/cc.target.linux-mips64.mk index 4e8b2b331c..5239409cd0 100644 --- a/cc/cc.target.linux-mips64.mk +++ b/cc/cc.target.linux-mips64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-x86.mk b/cc/cc.target.linux-x86.mk index ce5a3ee8dd..af5e231d79 100644 --- a/cc/cc.target.linux-x86.mk +++ b/cc/cc.target.linux-x86.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc.target.linux-x86_64.mk b/cc/cc.target.linux-x86_64.mk index 2da1bf8654..124e9da220 100644 --- a/cc/cc.target.linux-x86_64.mk +++ b/cc/cc.target.linux-x86_64.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ cc/debug/traced_value.cc \ cc/debug/unittest_only_benchmark.cc \ cc/debug/unittest_only_benchmark_impl.cc \ + cc/input/input_handler.cc \ cc/input/page_scale_animation.cc \ cc/input/layer_selection_bound.cc \ cc/input/top_controls_manager.cc \ diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 1300d3203f..75267ef287 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -50,6 +50,7 @@ 'layers/scrollbar_layer_unittest.cc', 'layers/solid_color_layer_impl_unittest.cc', 'layers/solid_color_scrollbar_layer_impl_unittest.cc', + 'layers/surface_layer_unittest.cc', 'layers/surface_layer_impl_unittest.cc', 'layers/texture_layer_unittest.cc', 'layers/texture_layer_impl_unittest.cc', diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc new file mode 100644 index 0000000000..336d0d4896 --- /dev/null +++ b/cc/input/input_handler.cc @@ -0,0 +1,13 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/input/input_handler.h" + +namespace cc { + +InputHandlerScrollResult::InputHandlerScrollResult() + : did_scroll(false), did_overscroll_root(false) { +} + +} // namespace cc diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h index b3205a8a64..7a9c991968 100644 --- a/cc/input/input_handler.h +++ b/cc/input/input_handler.h @@ -6,6 +6,7 @@ #define CC_INPUT_INPUT_HANDLER_H_ #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "cc/base/cc_export.h" #include "cc/base/swap_promise_monitor.h" @@ -24,6 +25,21 @@ namespace cc { class LayerScrollOffsetDelegate; +struct CC_EXPORT InputHandlerScrollResult { + InputHandlerScrollResult(); + // Did any layer scroll as a result this ScrollBy call? + bool did_scroll; + // Was any of the scroll delta argument to this ScrollBy call not used? + bool did_overscroll_root; + // The total overscroll that has been accumulated by all ScrollBy calls that + // have had overscroll since the last ScrollBegin call. This resets upon a + // ScrollBy with no overscroll. + gfx::Vector2dF accumulated_root_overscroll; + // The amount of the scroll delta argument to this ScrollBy call that was not + // used for scrolling. + gfx::Vector2dF unused_scroll_delta; +}; + class CC_EXPORT InputHandlerClient { public: virtual ~InputHandlerClient() {} @@ -32,13 +48,6 @@ class CC_EXPORT InputHandlerClient { virtual void Animate(base::TimeTicks time) = 0; virtual void MainThreadHasStoppedFlinging() = 0; - // Called when scroll deltas reaching the root scrolling layer go unused. - // The accumulated overscroll is scoped by the most recent call to - // InputHandler::ScrollBegin. - virtual void DidOverscroll(const gfx::PointF& causal_event_viewport_point, - const gfx::Vector2dF& accumulated_overscroll, - const gfx::Vector2dF& latest_overscroll_delta) = 0; - protected: InputHandlerClient() {} @@ -85,15 +94,16 @@ class CC_EXPORT InputHandler { // should be in viewport (logical pixel) coordinates. Otherwise they are in // scrolling layer's (logical pixel) space. If there is no room to move the // layer in the requested direction, its first ancestor layer that can be - // scrolled will be moved instead. If no layer can be moved in the requested - // direction at all, then false is returned. If any layer is moved, then - // true is returned. + // scrolled will be moved instead. The return value's |did_scroll| field is + // set to false if no layer can be moved in the requested direction at all, + // and set to true if any layer is moved. // If the scroll delta hits the root layer, and the layer can no longer move, // the root overscroll accumulated within this ScrollBegin() scope is reported - // to the client. + // in the return value's |accumulated_overscroll| field. // Should only be called if ScrollBegin() returned ScrollStarted. - virtual bool ScrollBy(const gfx::Point& viewport_point, - const gfx::Vector2dF& scroll_delta) = 0; + virtual InputHandlerScrollResult ScrollBy( + const gfx::Point& viewport_point, + const gfx::Vector2dF& scroll_delta) = 0; virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point, ScrollDirection direction) = 0; diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index f608ba7ae9..c56ff8be08 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc @@ -35,16 +35,22 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { Layer::PushPropertiesTo(base_layer); PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); - if (layer_impl->bounds().IsEmpty()) { - // Update may not get called for an empty layer, so resize here instead. - // Using layer_impl because either bounds() or paint_properties().bounds - // may disagree and either one could have been pushed to layer_impl. + int source_frame_number = layer_tree_host()->source_frame_number(); + gfx::Size impl_bounds = layer_impl->bounds(); + gfx::Size pile_bounds = pile_.tiling_size(); + + // If update called, then pile size must match bounds pushed to impl layer. + DCHECK_IMPLIES(update_source_frame_number_ == source_frame_number, + impl_bounds == pile_bounds) + << " bounds " << impl_bounds.ToString() << " pile " + << pile_bounds.ToString(); + + if (update_source_frame_number_ != source_frame_number && + pile_bounds != impl_bounds) { + // Update may not get called for the layer (if it's not in the viewport + // for example, even though it has resized making the pile no longer + // valid. In this case just destroy the pile. pile_.SetEmptyBounds(); - } else { - // If update called, then pile size must match bounds pushed to impl layer. - DCHECK_IMPLIES( - update_source_frame_number_ == layer_tree_host()->source_frame_number(), - layer_impl->bounds().ToString() == pile_.tiling_size().ToString()); } // Unlike other properties, invalidation must always be set on layer_impl. diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 9f59263d65..822fcf3dc2 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc @@ -173,10 +173,11 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass, AppendQuadsData* append_quads_data) { DCHECK(!needs_post_commit_initialization_); // The bounds and the pile size may differ if the pile wasn't updated (ie. - // PictureLayer::Update didn't happen). But that should never be the case if - // the layer is part of the visible frame, which is why we're appending quads - // in the first place - DCHECK_EQ(bounds().ToString(), pile_->tiling_size().ToString()); + // PictureLayer::Update didn't happen). In that case the pile will be empty. + DCHECK_IMPLIES(!pile_->tiling_size().IsEmpty(), + bounds() == pile_->tiling_size()) + << " bounds " << bounds().ToString() << " pile " + << pile_->tiling_size().ToString(); SharedQuadState* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); @@ -628,7 +629,7 @@ skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() { scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling, const gfx::Rect& content_rect) { DCHECK(!pile_->is_solid_color()); - if (!pile_->CanRaster(tiling->contents_scale(), content_rect)) + if (!pile_->CoversRect(content_rect, tiling->contents_scale())) return scoped_refptr<Tile>(); int flags = 0; diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index a46386cf55..4b42eca413 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc @@ -658,10 +658,10 @@ TEST_F(PictureLayerImplTest, AddTilesFromNewRecording) { ++iter) { EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty()); // Ensure there is a recording for this tile. - bool in_pending = pending_pile->CanRaster(tiling->contents_scale(), - iter.full_tile_geometry_rect()); - bool in_active = active_pile->CanRaster(tiling->contents_scale(), - iter.full_tile_geometry_rect()); + bool in_pending = pending_pile->CoversRect(iter.full_tile_geometry_rect(), + tiling->contents_scale()); + bool in_active = active_pile->CoversRect(iter.full_tile_geometry_rect(), + tiling->contents_scale()); if (in_pending && !in_active) EXPECT_EQ(pending_pile.get(), iter->raster_source()); @@ -1132,8 +1132,15 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) { } TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) { - gfx::Size tile_size(host_impl_.settings().default_tile_size); - SetupDefaultTrees(tile_size); + gfx::Size layer_bounds(host_impl_.settings().default_tile_size); + gfx::Size tile_size(100, 100); + + scoped_refptr<FakePicturePileImpl> pending_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakePicturePileImpl> active_pile = + FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + SetupTrees(pending_pile, active_pile); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; float device_scale = 1.f; @@ -1181,8 +1188,8 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) { ResetTilingsAndRasterScales(); // Mask layers dont create low res since they always fit on one tile. - pending_layer_->pile()->set_is_mask(true); - active_layer_->pile()->set_is_mask(true); + pending_pile->SetIsMask(true); + active_pile->SetIsMask(true); SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale, @@ -1197,7 +1204,7 @@ TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) { scoped_refptr<FakePicturePileImpl> valid_pile = FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000)); - valid_pile->set_is_mask(true); + valid_pile->SetIsMask(true); SetupPendingTree(valid_pile); SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false); @@ -1224,7 +1231,7 @@ TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) { scoped_refptr<FakePicturePileImpl> huge_pile = FakePicturePileImpl::CreateFilledPile( tile_size, gfx::Size(max_texture_size + 1, 10)); - huge_pile->set_is_mask(true); + huge_pile->SetIsMask(true); SetupPendingTree(huge_pile); SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false); @@ -1249,7 +1256,7 @@ TEST_F(PictureLayerImplTest, ScaledMaskLayer) { scoped_refptr<FakePicturePileImpl> valid_pile = FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000)); - valid_pile->set_is_mask(true); + valid_pile->SetIsMask(true); SetupPendingTree(valid_pile); float ideal_contents_scale = 1.3f; @@ -3708,7 +3715,7 @@ TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) { scoped_refptr<FakePicturePileImpl> pending_pile = FakePicturePileImpl::CreateFilledPile(tile_size, bounds); - pending_pile->set_is_mask(true); + pending_pile->SetIsMask(true); scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile( host_impl_.pending_tree(), 3, pending_pile); diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc index 78182d9135..ca622aa3c0 100644 --- a/cc/layers/picture_layer_unittest.cc +++ b/cc/layers/picture_layer_unittest.cc @@ -43,6 +43,10 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) { scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue); layer->Update(queue.get(), &occlusion); + EXPECT_EQ(0, host->source_frame_number()); + host->CommitComplete(); + EXPECT_EQ(1, host->source_frame_number()); + layer->SetBounds(gfx::Size(0, 0)); layer->SavePaintProperties(); // Intentionally skipping Update since it would normally be skipped on diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc index ba577a00d5..ee376aad4e 100644 --- a/cc/layers/surface_layer.cc +++ b/cc/layers/surface_layer.cc @@ -4,21 +4,61 @@ #include "cc/layers/surface_layer.h" +#include "cc/base/swap_promise.h" #include "cc/layers/surface_layer_impl.h" +#include "cc/trees/layer_tree_host.h" namespace cc { -scoped_refptr<SurfaceLayer> SurfaceLayer::Create() { - return make_scoped_refptr(new SurfaceLayer); +class SatisfySwapPromise : public SwapPromise { + public: + SatisfySwapPromise(SurfaceSequence sequence, + const SurfaceLayer::SatisfyCallback& satisfy_callback) + : sequence_(sequence), satisfy_callback_(satisfy_callback) {} + + ~SatisfySwapPromise() override {} + + private: + void DidSwap(CompositorFrameMetadata* metadata) override { + metadata->satisfies_sequences.push_back(sequence_.sequence); + } + + void DidNotSwap(DidNotSwapReason reason) override { + satisfy_callback_.Run(sequence_); + } + int64 TraceId() const override { return 0; } + + SurfaceSequence sequence_; + SurfaceLayer::SatisfyCallback satisfy_callback_; + + DISALLOW_COPY_AND_ASSIGN(SatisfySwapPromise); +}; + +scoped_refptr<SurfaceLayer> SurfaceLayer::Create( + const SatisfyCallback& satisfy_callback, + const RequireCallback& require_callback) { + return make_scoped_refptr( + new SurfaceLayer(satisfy_callback, require_callback)); } -SurfaceLayer::SurfaceLayer() : Layer() { +SurfaceLayer::SurfaceLayer(const SatisfyCallback& satisfy_callback, + const RequireCallback& require_callback) + : Layer(), + satisfy_callback_(satisfy_callback), + require_callback_(require_callback) { } -SurfaceLayer::~SurfaceLayer() {} +SurfaceLayer::~SurfaceLayer() { + DCHECK(!layer_tree_host()); + DCHECK(destroy_sequence_.is_null()); +} -void SurfaceLayer::SetSurfaceId(SurfaceId surface_id) { +void SurfaceLayer::SetSurfaceId(SurfaceId surface_id, const gfx::Size& size) { + SatisfyDestroySequence(); surface_id_ = surface_id; + surface_size_ = size; + CreateNewDestroySequence(); + UpdateDrawsContent(HasDrawableContent()); SetNeedsPushProperties(); } @@ -31,6 +71,17 @@ bool SurfaceLayer::HasDrawableContent() const { return !surface_id_.is_null() && Layer::HasDrawableContent(); } +void SurfaceLayer::SetLayerTreeHost(LayerTreeHost* host) { + if (layer_tree_host() == host) { + Layer::SetLayerTreeHost(host); + return; + } + + SatisfyDestroySequence(); + Layer::SetLayerTreeHost(host); + CreateNewDestroySequence(); +} + void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer); @@ -38,4 +89,35 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) { layer_impl->SetSurfaceId(surface_id_); } +void SurfaceLayer::CalculateContentsScale(float ideal_contents_scale, + float* contents_scale_x, + float* contents_scale_y, + gfx::Size* content_bounds) { + *content_bounds = surface_size_; + *contents_scale_x = + bounds().IsEmpty() ? 1.f : static_cast<float>(content_bounds->width()) / + bounds().width(); + *contents_scale_y = + bounds().IsEmpty() ? 1.f : static_cast<float>(content_bounds->height()) / + bounds().height(); +} + +void SurfaceLayer::CreateNewDestroySequence() { + DCHECK(destroy_sequence_.is_null()); + if (layer_tree_host()) { + destroy_sequence_ = layer_tree_host()->CreateSurfaceSequence(); + require_callback_.Run(surface_id_, destroy_sequence_); + } +} + +void SurfaceLayer::SatisfyDestroySequence() { + if (!layer_tree_host()) + return; + DCHECK(!destroy_sequence_.is_null()); + scoped_ptr<SatisfySwapPromise> satisfy( + new SatisfySwapPromise(destroy_sequence_, satisfy_callback_)); + layer_tree_host()->QueueSwapPromise(satisfy.Pass()); + destroy_sequence_ = SurfaceSequence(); +} + } // namespace cc diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h index 0b886ebe2c..29d821f53d 100644 --- a/cc/layers/surface_layer.h +++ b/cc/layers/surface_layer.h @@ -8,6 +8,8 @@ #include "cc/base/cc_export.h" #include "cc/layers/layer.h" #include "cc/surfaces/surface_id.h" +#include "cc/surfaces/surface_sequence.h" +#include "ui/gfx/size.h" namespace cc { @@ -15,22 +17,45 @@ namespace cc { // instance or client. class CC_EXPORT SurfaceLayer : public Layer { public: - static scoped_refptr<SurfaceLayer> Create(); + // This callback is run when a SurfaceSequence needs to be satisfied, but + // the parent compositor is unable to. It can be called on either the main + // or impl threads. + using SatisfyCallback = base::Callback<void(SurfaceSequence)>; - void SetSurfaceId(SurfaceId surface_id); + // This callback is run to require that a specific SurfaceSequence is + // received before a SurfaceId is destroyed. + using RequireCallback = base::Callback<void(SurfaceId, SurfaceSequence)>; + + static scoped_refptr<SurfaceLayer> Create( + const SatisfyCallback& satisfy_callback, + const RequireCallback& require_callback); + + void SetSurfaceId(SurfaceId surface_id, const gfx::Size& size); // Layer overrides. scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; + void SetLayerTreeHost(LayerTreeHost* host) override; void PushPropertiesTo(LayerImpl* layer) override; + void CalculateContentsScale(float ideal_contents_scale, + float* contents_scale_x, + float* contents_scale_y, + gfx::Size* content_bounds) override; protected: - SurfaceLayer(); + SurfaceLayer(const SatisfyCallback& satisfy_callback, + const RequireCallback& require_callback); bool HasDrawableContent() const override; private: ~SurfaceLayer() override; + void CreateNewDestroySequence(); + void SatisfyDestroySequence(); SurfaceId surface_id_; + gfx::Size surface_size_; + SurfaceSequence destroy_sequence_; + SatisfyCallback satisfy_callback_; + RequireCallback require_callback_; DISALLOW_COPY_AND_ASSIGN(SurfaceLayer); }; diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc new file mode 100644 index 0000000000..7323bf4c45 --- /dev/null +++ b/cc/layers/surface_layer_unittest.cc @@ -0,0 +1,233 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop/message_loop_proxy.h" +#include "cc/layers/solid_color_layer.h" +#include "cc/layers/surface_layer.h" +#include "cc/test/fake_impl_proxy.h" +#include "cc/test/fake_layer_tree_host.h" +#include "cc/test/fake_layer_tree_host_client.h" +#include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/layer_tree_test.h" +#include "cc/test/test_shared_bitmap_manager.h" +#include "cc/trees/layer_tree_host.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class SurfaceLayerTest : public testing::Test { + public: + SurfaceLayerTest() + : fake_client_( + FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)) {} + + protected: + virtual void SetUp() { + layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_); + layer_tree_host_->SetViewportSize(gfx::Size(10, 10)); + } + + virtual void TearDown() { + if (layer_tree_host_) { + layer_tree_host_->SetRootLayer(nullptr); + layer_tree_host_ = nullptr; + } + } + + scoped_ptr<FakeLayerTreeHost> layer_tree_host_; + FakeLayerTreeHostClient fake_client_; + TestSharedBitmapManager shared_bitmap_manager_; +}; + +void SatisfyCallback(SurfaceSequence* out, SurfaceSequence in) { + *out = in; +} + +void RequireCallback(SurfaceId* out_id, + std::set<SurfaceSequence>* out, + SurfaceId in_id, + SurfaceSequence in) { + *out_id = in_id; + out->insert(in); +} + +// Check that one surface can be referenced by multiple LayerTreeHosts, and +// each will create its own SurfaceSequence that's satisfied on destruction. +TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) { + SurfaceSequence blank_change; // Receives sequence if commit doesn't happen. + + SurfaceId required_id; + std::set<SurfaceSequence> required_seq; + scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create( + base::Bind(&SatisfyCallback, &blank_change), + base::Bind(&RequireCallback, &required_id, &required_seq))); + layer->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1)); + layer_tree_host_->set_surface_id_namespace(1); + layer_tree_host_->SetRootLayer(layer); + + scoped_ptr<FakeLayerTreeHost> layer_tree_host2 = + FakeLayerTreeHost::Create(&fake_client_); + scoped_refptr<SurfaceLayer> layer2(SurfaceLayer::Create( + base::Bind(&SatisfyCallback, &blank_change), + base::Bind(&RequireCallback, &required_id, &required_seq))); + layer2->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1)); + layer_tree_host2->set_surface_id_namespace(2); + layer_tree_host2->SetRootLayer(layer2); + + // Layers haven't been removed, so no sequence should be satisfied. + EXPECT_TRUE(blank_change.is_null()); + + SurfaceSequence expected1(1u, 1u); + SurfaceSequence expected2(2u, 1u); + + layer_tree_host2->SetRootLayer(nullptr); + layer_tree_host2.reset(); + + // Layer was removed so sequence from second LayerTreeHost should be + // satisfied. + EXPECT_TRUE(blank_change == expected2); + + // Set of sequences that need to be satisfied should include sequences from + // both trees. + EXPECT_TRUE(required_id == SurfaceId(1)); + EXPECT_EQ(2u, required_seq.size()); + EXPECT_TRUE(required_seq.count(expected1)); + EXPECT_TRUE(required_seq.count(expected2)); + + layer_tree_host_->SetRootLayer(nullptr); + layer_tree_host_.reset(); + + // Layer was removed so sequence from first LayerTreeHost should be + // satisfied. + EXPECT_TRUE(blank_change == expected1); + + // No more SurfaceSequences should have been generated that need to have be + // satisfied. + EXPECT_EQ(2u, required_seq.size()); +} + +// Check that setting content scale on the surface works. +TEST_F(SurfaceLayerTest, ScaleSurface) { + SurfaceSequence blank_change; + SurfaceId required_id; + std::set<SurfaceSequence> required_seq; + scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create( + base::Bind(&SatisfyCallback, &blank_change), + base::Bind(&RequireCallback, &required_id, &required_seq))); + gfx::Size surface_size(10, 15); + layer->SetSurfaceId(SurfaceId(1), surface_size); + layer->SetBounds(gfx::Size(25, 45)); + + float scale_x; + float scale_y; + gfx::Size bounds; + layer->CalculateContentsScale(2.f, &scale_x, &scale_y, &bounds); + EXPECT_EQ(10.f / 25.f, scale_x); + EXPECT_EQ(15.f / 45.f, scale_y); + EXPECT_EQ(surface_size.ToString(), bounds.ToString()); + + layer->SetBounds(gfx::Size(0, 0)); + layer->CalculateContentsScale(2.f, &scale_x, &scale_y, &bounds); + EXPECT_EQ(1.f, scale_x); + EXPECT_EQ(1.f, scale_y); + EXPECT_EQ(surface_size.ToString(), bounds.ToString()); +} + +// Check that SurfaceSequence is sent through swap promise. +class SurfaceLayerSwapPromise : public LayerTreeTest { + public: + SurfaceLayerSwapPromise() + : commit_count_(0), sequence_was_satisfied_(false) {} + + void BeginTest() override { + layer_tree_host()->set_surface_id_namespace(1); + layer_ = SurfaceLayer::Create( + base::Bind(&SatisfyCallback, &satisfied_sequence_), + base::Bind(&RequireCallback, &required_id_, &required_set_)); + layer_->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1)); + + // Layer hasn't been added to tree so no SurfaceSequence generated yet. + EXPECT_EQ(0u, required_set_.size()); + + layer_tree_host()->SetRootLayer(layer_); + + // Should have SurfaceSequence from first tree. + SurfaceSequence expected(1u, 1u); + EXPECT_TRUE(required_id_ == SurfaceId(1)); + EXPECT_EQ(1u, required_set_.size()); + EXPECT_TRUE(required_set_.count(expected)); + + gfx::Size bounds(100, 100); + layer_tree_host()->SetViewportSize(bounds); + PostSetNeedsCommitToMainThread(); + } + + void DidCommit() override { + base::MessageLoopProxy::current()->PostTask( + FROM_HERE, base::Bind(&SurfaceLayerSwapPromise::ChangeTree, + base::Unretained(this))); + } + + void ChangeTree() { + ++commit_count_; + switch (commit_count_) { + case 1: + // Remove SurfaceLayer from tree to cause SwapPromise to be created. + blank_layer_ = SolidColorLayer::Create(); + blank_layer_->SetIsDrawable(true); + blank_layer_->SetBounds(gfx::Size(10, 10)); + layer_tree_host()->SetRootLayer(blank_layer_); + break; + case 2: + break; + default: + NOTREACHED(); + break; + } + } + + void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { + EXPECT_TRUE(result); + std::vector<uint32_t>& satisfied = + output_surface()->last_sent_frame().metadata.satisfies_sequences; + EXPECT_LE(satisfied.size(), 1u); + if (satisfied.size() == 1) { + // Eventually the one SurfaceSequence should be satisfied, but only + // after the layer was removed from the tree, and only once. + EXPECT_EQ(1u, satisfied[0]); + EXPECT_LE(1, commit_count_); + EXPECT_FALSE(sequence_was_satisfied_); + sequence_was_satisfied_ = true; + EndTest(); + } + } + + void AfterTest() override { + EXPECT_TRUE(required_id_ == SurfaceId(1)); + EXPECT_EQ(1u, required_set_.size()); + // Sequence should have been satisfied through Swap, not with the + // callback. + EXPECT_TRUE(satisfied_sequence_.is_null()); + } + + private: + int commit_count_; + bool sequence_was_satisfied_; + scoped_refptr<SurfaceLayer> layer_; + scoped_refptr<Layer> blank_layer_; + SurfaceSequence satisfied_sequence_; + + SurfaceId required_id_; + std::set<SurfaceSequence> required_set_; +}; + +// TODO(jbauman): Reenable on single thread once http://crbug.com/421923 is +// fixed. +MULTI_THREAD_TEST_F(SurfaceLayerSwapPromise); + +} // namespace +} // namespace cc diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc index 02303ace6c..a472475d23 100644 --- a/cc/output/gl_renderer.cc +++ b/cc/output/gl_renderer.cc @@ -870,7 +870,7 @@ scoped_ptr<ScopedResource> GLRenderer::ApplyInverseTransformForBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, - const gfx::Transform& contents_device_transform_inverse, + const gfx::Transform& contents_device_transform, skia::RefPtr<SkImage> filtered_device_background, const gfx::Rect& backdrop_bounding_rect) { // This method draws a background filter, which applies a filter to any pixels @@ -915,6 +915,12 @@ GLRenderer::ApplyInverseTransformForBackgroundFilters( if (using_background_texture) { // Copy the readback pixels from device to the background texture for the // surface. + + gfx::Transform contents_device_transform_inverse( + gfx::Transform::kSkipInitialization); + bool did_invert = contents_device_transform.GetInverse( + &contents_device_transform_inverse); + DCHECK(did_invert); gfx::Transform device_to_framebuffer_transform; QuadRectTransform( &device_to_framebuffer_transform, gfx::Transform(), quad->rect); @@ -965,20 +971,18 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, contents_device_transform.FlattenTo2d(); // Can only draw surface if device matrix is invertible. - gfx::Transform contents_device_transform_inverse( - gfx::Transform::kSkipInitialization); - if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) + if (!contents_device_transform.IsInvertible()) return; - bool clipped = false; - gfx::QuadF device_quad = MathUtil::MapQuad( - contents_device_transform, SharedGeometryQuad(), &clipped); - // Use anti-aliasing programs only when necessary. - bool use_aa = - !clipped && - (settings_->force_antialiasing || !device_quad.IsRectilinear() || - !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(), - kAntiAliasingEpsilon)); + gfx::QuadF surface_quad = SharedGeometryQuad(); + float edge[24]; + bool use_aa = settings_->allow_antialiasing && + ShouldAntialiasQuad(contents_device_transform, quad, + settings_->force_antialiasing); + + if (use_aa) + SetupQuadForAntialiasing(contents_device_transform, quad, + &surface_quad, edge); bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) || ShouldApplyBackgroundFilters(frame, quad); @@ -1021,10 +1025,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // the quad since the destination texture has bounds matching the quad's // content. background_texture = ApplyInverseTransformForBackgroundFilters( - frame, - quad, - contents_device_transform_inverse, - background_with_filters, + frame, quad, contents_device_transform, background_with_filters, background_rect); } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) { if (background_with_filters) { @@ -1090,13 +1091,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, flip_vertically); } - LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox())); - LayerQuad device_layer_edges(device_quad); - if (use_aa) { - device_layer_bounds.InflateAntiAliasingDistance(); - device_layer_edges.InflateAntiAliasingDistance(); - } - scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock; unsigned mask_texture_id = 0; SamplerType mask_sampler = SamplerTypeNA; @@ -1360,12 +1354,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, last_texture_unit = 1; } - if (shader_edge_location != -1) { - float edge[24]; - device_layer_edges.ToFloatArray(edge); - device_layer_bounds.ToFloatArray(&edge[12]); + if (shader_edge_location != -1) GLC(gl_, gl_->Uniform3fv(shader_edge_location, 8, edge)); - } if (shader_viewport_location != -1) { float viewport[4] = {static_cast<float>(viewport_.x()), @@ -1424,12 +1414,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, } } - // Map device space quad to surface space. contents_device_transform has no 3d - // component since it was flattened, so we don't need to project. - gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse, - device_layer_edges.ToQuadF(), - &clipped); - SetShaderOpacity(quad->opacity(), shader_alpha_location); SetShaderQuadF(surface_quad, shader_quad_location); DrawQuadGeometry( @@ -1464,41 +1448,16 @@ static void SolidColorUniformLocation(T program, uniforms->color_location = program->fragment_shader().color_location(); } -// static -bool GLRenderer::SetupQuadForAntialiasing( +static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges( + const LayerQuad& device_layer_edges, const gfx::Transform& device_transform, - const DrawQuad* quad, - gfx::QuadF* local_quad, - float edge[24]) { + const DrawQuad* quad) { gfx::Rect tile_rect = quad->visible_rect; - - bool clipped = false; - gfx::QuadF device_layer_quad = MathUtil::MapQuad( - device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped); - - bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); - bool is_nearest_rect_within_epsilon = - is_axis_aligned_in_target && - gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(), - kAntiAliasingEpsilon); - // AAing clipped quads is not supported by the code yet. - bool use_aa = !clipped && !is_nearest_rect_within_epsilon && quad->IsEdge(); - if (!use_aa) - return false; - - LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox())); - device_layer_bounds.InflateAntiAliasingDistance(); - - LayerQuad device_layer_edges(device_layer_quad); - device_layer_edges.InflateAntiAliasingDistance(); - - device_layer_edges.ToFloatArray(edge); - device_layer_bounds.ToFloatArray(&edge[12]); - gfx::PointF bottom_right = tile_rect.bottom_right(); gfx::PointF bottom_left = tile_rect.bottom_left(); gfx::PointF top_left = tile_rect.origin(); gfx::PointF top_right = tile_rect.top_right(); + bool clipped = false; // Map points to device space. We ignore |clipped|, since the result of // |MapPoint()| still produces a valid point to draw the quad with. When @@ -1530,7 +1489,72 @@ bool GLRenderer::SetupQuadForAntialiasing( right_edge.scale(sign); // Create device space quad. - LayerQuad device_quad(left_edge, top_edge, right_edge, bottom_edge); + return LayerQuad(left_edge, top_edge, right_edge, bottom_edge).ToQuadF(); +} + +// static +bool GLRenderer::ShouldAntialiasQuad(const gfx::Transform& device_transform, + const DrawQuad* quad, + bool force_antialiasing) { + bool is_render_pass_quad = (quad->material == DrawQuad::RENDER_PASS); + // For render pass quads, |device_transform| already contains quad's rect. + // TODO(rosca@adobe.com): remove branching on is_render_pass_quad + // crbug.com/429702 + if (!is_render_pass_quad && !quad->IsEdge()) + return false; + gfx::RectF content_rect = + is_render_pass_quad ? QuadVertexRect() : quad->visibleContentRect(); + + bool clipped = false; + gfx::QuadF device_layer_quad = + MathUtil::MapQuad(device_transform, gfx::QuadF(content_rect), &clipped); + + if (device_layer_quad.BoundingBox().IsEmpty()) + return false; + + bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); + bool is_nearest_rect_within_epsilon = + is_axis_aligned_in_target && + gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(), + kAntiAliasingEpsilon); + // AAing clipped quads is not supported by the code yet. + bool use_aa = !clipped && !is_nearest_rect_within_epsilon; + return use_aa || force_antialiasing; +} + +// static +void GLRenderer::SetupQuadForAntialiasing( + const gfx::Transform& device_transform, + const DrawQuad* quad, + gfx::QuadF* local_quad, + float edge[24]) { + bool is_render_pass_quad = (quad->material == DrawQuad::RENDER_PASS); + gfx::RectF content_rect = + is_render_pass_quad ? QuadVertexRect() : quad->visibleContentRect(); + + bool clipped = false; + gfx::QuadF device_layer_quad = + MathUtil::MapQuad(device_transform, gfx::QuadF(content_rect), &clipped); + + LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox())); + device_layer_bounds.InflateAntiAliasingDistance(); + + LayerQuad device_layer_edges(device_layer_quad); + device_layer_edges.InflateAntiAliasingDistance(); + + device_layer_edges.ToFloatArray(edge); + device_layer_bounds.ToFloatArray(&edge[12]); + + bool use_aa_on_all_four_edges = + is_render_pass_quad || + (quad->IsTopEdge() && quad->IsLeftEdge() && quad->IsBottomEdge() && + quad->IsRightEdge() && quad->visible_rect == quad->rect); + + gfx::QuadF device_quad = + use_aa_on_all_four_edges + ? device_layer_edges.ToQuadF() + : GetDeviceQuadWithAntialiasingOnExteriorEdges( + device_layer_edges, device_transform, quad); // Map device space quad to local space. device_transform has no 3d // component since it was flattened, so we don't need to project. We should @@ -1538,13 +1562,11 @@ bool GLRenderer::SetupQuadForAntialiasing( gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization); bool did_invert = device_transform.GetInverse(&inverse_device_transform); DCHECK(did_invert); - *local_quad = MathUtil::MapQuad( - inverse_device_transform, device_quad.ToQuadF(), &clipped); + *local_quad = + MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped); // We should not DCHECK(!clipped) here, because anti-aliasing inflation may // cause device_quad to become clipped. To our knowledge this scenario does // not need to be handled differently than the unclipped case. - - return true; } void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, @@ -1566,17 +1588,20 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, if (!device_transform.IsInvertible()) return; + bool force_aa = false; gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); float edge[24]; - bool use_aa = - settings_->allow_antialiasing && !quad->force_anti_aliasing_off && - SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge); + bool use_aa = settings_->allow_antialiasing && + !quad->force_anti_aliasing_off && + ShouldAntialiasQuad(device_transform, quad, force_aa); SolidColorProgramUniforms uniforms; - if (use_aa) + if (use_aa) { + SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge); SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms); - else + } else { SolidColorUniformLocation(GetSolidColorProgram(), &uniforms); + } SetUseProgram(uniforms.program); GLC(gl_, @@ -1650,6 +1675,29 @@ void GLRenderer::DrawTileQuad(const DrawingFrame* frame, void GLRenderer::DrawContentQuad(const DrawingFrame* frame, const ContentDrawQuadBase* quad, ResourceProvider::ResourceId resource_id) { + gfx::Transform device_transform = + frame->window_matrix * frame->projection_matrix * quad->quadTransform(); + device_transform.FlattenTo2d(); + + bool use_aa = settings_->allow_antialiasing && + ShouldAntialiasQuad(device_transform, quad, false); + + // TODO(timav): simplify coordinate transformations in DrawContentQuadAA + // similar to the way DrawContentQuadNoAA works and then consider + // combining DrawContentQuadAA and DrawContentQuadNoAA into one method. + if (use_aa) + DrawContentQuadAA(frame, quad, resource_id, device_transform); + else + DrawContentQuadNoAA(frame, quad, resource_id); +} + +void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame, + const ContentDrawQuadBase* quad, + ResourceProvider::ResourceId resource_id, + const gfx::Transform& device_transform) { + if (!device_transform.IsInvertible()) + return; + gfx::Rect tile_rect = quad->visible_rect; gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( @@ -1689,25 +1737,12 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); - gfx::Transform device_transform = - frame->window_matrix * frame->projection_matrix * quad->quadTransform(); - device_transform.FlattenTo2d(); - if (!device_transform.IsInvertible()) - return; - gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); float edge[24]; - bool use_aa = - settings_->allow_antialiasing && - SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge); + SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge); - bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); - GLenum filter = (use_aa || scaled || - !quad->quadTransform().IsIdentityOrIntegerTranslation()) - ? GL_LINEAR - : GL_NEAREST; ResourceProvider::ScopedSamplerGL quad_resource_lock( - resource_provider_, resource_id, filter); + resource_provider_, resource_id, GL_LINEAR); SamplerType sampler = SamplerTypeFromTextureTarget(quad_resource_lock.target()); @@ -1727,81 +1762,41 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, } TileProgramUniforms uniforms; - if (use_aa) { - if (quad->swizzle_contents) { - TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision, sampler), - &uniforms); - } else { - TileUniformLocation(GetTileProgramAA(tex_coord_precision, sampler), - &uniforms); - } + if (quad->swizzle_contents) { + TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision, sampler), + &uniforms); } else { - if (quad->ShouldDrawWithBlending()) { - if (quad->swizzle_contents) { - TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision, sampler), - &uniforms); - } else { - TileUniformLocation(GetTileProgram(tex_coord_precision, sampler), - &uniforms); - } - } else { - if (quad->swizzle_contents) { - TileUniformLocation( - GetTileProgramSwizzleOpaque(tex_coord_precision, sampler), - &uniforms); - } else { - TileUniformLocation(GetTileProgramOpaque(tex_coord_precision, sampler), - &uniforms); - } - } + TileUniformLocation(GetTileProgramAA(tex_coord_precision, sampler), + &uniforms); } SetUseProgram(uniforms.program); GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0)); - if (use_aa) { - float viewport[4] = {static_cast<float>(viewport_.x()), - static_cast<float>(viewport_.y()), - static_cast<float>(viewport_.width()), - static_cast<float>(viewport_.height()), }; - GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); - GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); - - GLC(gl_, - gl_->Uniform4f(uniforms.vertex_tex_transform_location, - vertex_tex_translate_x, - vertex_tex_translate_y, - vertex_tex_scale_x, - vertex_tex_scale_y)); - GLC(gl_, - gl_->Uniform4f(uniforms.fragment_tex_transform_location, - fragment_tex_translate_x, - fragment_tex_translate_y, - fragment_tex_scale_x, - fragment_tex_scale_y)); - } else { - // Move fragment shader transform to vertex shader. We can do this while - // still producing correct results as fragment_tex_transform_location - // should always be non-negative when tiles are transformed in a way - // that could result in sampling outside the layer. - vertex_tex_scale_x *= fragment_tex_scale_x; - vertex_tex_scale_y *= fragment_tex_scale_y; - vertex_tex_translate_x *= fragment_tex_scale_x; - vertex_tex_translate_y *= fragment_tex_scale_y; - vertex_tex_translate_x += fragment_tex_translate_x; - vertex_tex_translate_y += fragment_tex_translate_y; + float viewport[4] = { + static_cast<float>(viewport_.x()), + static_cast<float>(viewport_.y()), + static_cast<float>(viewport_.width()), + static_cast<float>(viewport_.height()), + }; + GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); + GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); - GLC(gl_, - gl_->Uniform4f(uniforms.vertex_tex_transform_location, - vertex_tex_translate_x, - vertex_tex_translate_y, - vertex_tex_scale_x, - vertex_tex_scale_y)); - } + GLC(gl_, + gl_->Uniform4f(uniforms.vertex_tex_transform_location, + vertex_tex_translate_x, + vertex_tex_translate_y, + vertex_tex_scale_x, + vertex_tex_scale_y)); + GLC(gl_, + gl_->Uniform4f(uniforms.fragment_tex_transform_location, + fragment_tex_translate_x, + fragment_tex_translate_y, + fragment_tex_scale_x, + fragment_tex_scale_y)); - // Enable blending when the quad properties require it or if we decided - // to use antialiasing. - SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); + // Blending is required for antialiasing. + SetBlendEnabled(true); // Normalize to tile_rect. local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); @@ -1820,6 +1815,103 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, frame, quad->quadTransform(), centered_rect, uniforms.matrix_location); } +void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame, + const ContentDrawQuadBase* quad, + ResourceProvider::ResourceId resource_id) { + gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( + quad->tex_coord_rect, quad->rect, quad->visible_rect); + float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width(); + float tex_to_geom_scale_y = + quad->rect.height() / quad->tex_coord_rect.height(); + + bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); + GLenum filter = + (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation()) + ? GL_LINEAR + : GL_NEAREST; + + ResourceProvider::ScopedSamplerGL quad_resource_lock( + resource_provider_, resource_id, filter); + SamplerType sampler = + SamplerTypeFromTextureTarget(quad_resource_lock.target()); + + float vertex_tex_translate_x = tex_coord_rect.x(); + float vertex_tex_translate_y = tex_coord_rect.y(); + float vertex_tex_scale_x = tex_coord_rect.width(); + float vertex_tex_scale_y = tex_coord_rect.height(); + + // Map to normalized texture coordinates. + if (sampler != SamplerType2DRect) { + gfx::Size texture_size = quad->texture_size; + DCHECK(!texture_size.IsEmpty()); + vertex_tex_translate_x /= texture_size.width(); + vertex_tex_translate_y /= texture_size.height(); + vertex_tex_scale_x /= texture_size.width(); + vertex_tex_scale_y /= texture_size.height(); + } + + TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( + gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); + + TileProgramUniforms uniforms; + if (quad->ShouldDrawWithBlending()) { + if (quad->swizzle_contents) { + TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision, sampler), + &uniforms); + } else { + TileUniformLocation(GetTileProgram(tex_coord_precision, sampler), + &uniforms); + } + } else { + if (quad->swizzle_contents) { + TileUniformLocation( + GetTileProgramSwizzleOpaque(tex_coord_precision, sampler), &uniforms); + } else { + TileUniformLocation(GetTileProgramOpaque(tex_coord_precision, sampler), + &uniforms); + } + } + + SetUseProgram(uniforms.program); + GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0)); + + GLC(gl_, + gl_->Uniform4f(uniforms.vertex_tex_transform_location, + vertex_tex_translate_x, + vertex_tex_translate_y, + vertex_tex_scale_x, + vertex_tex_scale_y)); + + SetBlendEnabled(quad->ShouldDrawWithBlending()); + + SetShaderOpacity(quad->opacity(), uniforms.alpha_location); + + // Pass quad coordinates to the uniform in the same order as GeometryBinding + // does, then vertices will match the texture mapping in the vertex buffer. + // The method SetShaderQuadF() changes the order of vertices and so it's + // not used here. + + gfx::RectF tile_rect = quad->visible_rect; + float gl_quad[8] = { + tile_rect.x(), + tile_rect.bottom(), + tile_rect.x(), + tile_rect.y(), + tile_rect.right(), + tile_rect.y(), + tile_rect.right(), + tile_rect.bottom(), + }; + GLC(gl_, gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad)); + + static float gl_matrix[16]; + ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad->quadTransform()); + GLC(gl_, + gl_->UniformMatrix4fv(uniforms.matrix_location, 1, false, &gl_matrix[0])); + + GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); +} + void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, const YUVVideoDrawQuad* quad) { SetBlendEnabled(quad->ShouldDrawWithBlending()); @@ -2063,7 +2155,7 @@ struct TexTransformTextureProgramBinding : TextureProgramBinding { void GLRenderer::FlushTextureQuadCache() { // Check to see if we have anything to draw. - if (draw_cache_.program_id == 0) + if (draw_cache_.program_id == -1) return; // Set the correct blending mode. @@ -2119,7 +2211,7 @@ void GLRenderer::FlushTextureQuadCache() { 0)); // Clear the cache. - draw_cache_.program_id = 0; + draw_cache_.program_id = -1; draw_cache_.uv_xform_data.resize(0); draw_cache_.vertex_opacity_data.resize(0); draw_cache_.matrix_data.resize(0); diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h index dc3160a67a..4930204eb4 100644 --- a/cc/output/gl_renderer.h +++ b/cc/output/gl_renderer.h @@ -124,13 +124,15 @@ class CC_EXPORT GLRenderer : public DirectRenderer { scoped_ptr<CopyOutputRequest> request) override; void FinishDrawingQuadList() override; - // Check if quad needs antialiasing and if so, inflate the quad and - // fill edge array for fragment shader. local_quad is set to - // inflated quad if antialiasing is required, otherwise it is left - // unchanged. edge array is filled with inflated quad's edge data - // if antialiasing is required, otherwise it is left unchanged. // Returns true if quad requires antialiasing and false otherwise. - static bool SetupQuadForAntialiasing(const gfx::Transform& device_transform, + static bool ShouldAntialiasQuad(const gfx::Transform& device_transform, + const DrawQuad* quad, + bool force_antialiasing); + + // Inflate the quad and fill edge array for fragment shader. + // |local_quad| is set to inflated quad. |edge| array is filled with + // inflated quad's edge data. + static void SetupQuadForAntialiasing(const gfx::Transform& device_transform, const DrawQuad* quad, gfx::QuadF* local_quad, float edge[24]); @@ -168,7 +170,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { scoped_ptr<ScopedResource> ApplyInverseTransformForBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, - const gfx::Transform& contents_device_transform_inverse, + const gfx::Transform& contents_device_transform, skia::RefPtr<SkImage> backdrop_bitmap, const gfx::Rect& backdrop_bounding_rect); @@ -186,6 +188,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer { void DrawContentQuad(const DrawingFrame* frame, const ContentDrawQuadBase* quad, ResourceProvider::ResourceId resource_id); + void DrawContentQuadAA(const DrawingFrame* frame, + const ContentDrawQuadBase* quad, + ResourceProvider::ResourceId resource_id, + const gfx::Transform& device_transform); + void DrawContentQuadNoAA(const DrawingFrame* frame, + const ContentDrawQuadBase* quad, + ResourceProvider::ResourceId resource_id); void DrawYUVVideoQuad(const DrawingFrame* frame, const YUVVideoDrawQuad* quad); void DrawPictureQuad(const DrawingFrame* frame, diff --git a/cc/output/gl_renderer_draw_cache.cc b/cc/output/gl_renderer_draw_cache.cc index 51834c4602..a0004f2a06 100644 --- a/cc/output/gl_renderer_draw_cache.cc +++ b/cc/output/gl_renderer_draw_cache.cc @@ -7,7 +7,16 @@ namespace cc { TexturedQuadDrawCache::TexturedQuadDrawCache() - : program_id(0) {} + : program_id(-1), + resource_id(-1), + needs_blending(false), + background_color(0), + uv_xform_location(-1), + background_color_location(-1), + vertex_opacity_location(-1), + matrix_location(-1), + sampler_location(-1) { +} TexturedQuadDrawCache::~TexturedQuadDrawCache() {} diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc index c1728698ba..bdb030f063 100644 --- a/cc/output/renderer_pixeltest.cc +++ b/cc/output/renderer_pixeltest.cc @@ -1759,14 +1759,9 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) { blue_quad->SetNew(blue_shared_state, viewport, // Intentionally bigger than clip. - gfx::Rect(), - viewport, - gfx::RectF(viewport), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(blue_pile.get())); + gfx::Rect(), viewport, gfx::RectF(viewport), + viewport.size(), texture_format, viewport, 1.f, + blue_pile.get()); // One viewport-filling green quad. scoped_refptr<FakePicturePileImpl> green_pile = @@ -1782,16 +1777,9 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) { PictureDrawQuad* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - green_quad->SetNew(green_shared_state, - viewport, - gfx::Rect(), - viewport, - gfx::RectF(0.f, 0.f, 1.f, 1.f), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(green_pile.get())); + green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport, + gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(), + texture_format, viewport, 1.f, green_pile.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -1828,16 +1816,9 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { PictureDrawQuad* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - green_quad->SetNew(green_shared_state, - viewport, - gfx::Rect(), - viewport, - gfx::RectF(0, 0, 1, 1), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(green_pile.get())); + green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport, + gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format, + viewport, 1.f, green_pile.get()); // One viewport-filling white quad. scoped_refptr<FakePicturePileImpl> white_pile = @@ -1853,16 +1834,9 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) { PictureDrawQuad* white_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - white_quad->SetNew(white_shared_state, - viewport, - gfx::Rect(), - viewport, - gfx::RectF(0, 0, 1, 1), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(white_pile.get())); + white_quad->SetNew(white_shared_state, viewport, gfx::Rect(), viewport, + gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format, + viewport, 1.f, white_pile.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -1927,16 +1901,9 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) { content_to_target_transform, viewport, pass.get()); PictureDrawQuad* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - quad->SetNew(shared_state, - viewport, - gfx::Rect(), - viewport, - gfx::RectF(0, 0, 2, 2), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(pile.get())); + quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, + gfx::RectF(0, 0, 2, 2), viewport.size(), texture_format, + viewport, 1.f, pile.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -1984,29 +1951,17 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) { PictureDrawQuad* green_quad1 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - green_quad1->SetNew(top_right_green_shared_quad_state, - green_rect1, - gfx::Rect(), - green_rect1, - gfx::RectF(green_rect1.size()), - green_rect1.size(), - texture_format, - green_rect1, - 1.f, - PicturePileImpl::CreateFromOther(green_pile.get())); + green_quad1->SetNew(top_right_green_shared_quad_state, green_rect1, + gfx::Rect(), green_rect1, gfx::RectF(green_rect1.size()), + green_rect1.size(), texture_format, green_rect1, 1.f, + green_pile.get()); PictureDrawQuad* green_quad2 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - green_quad2->SetNew(top_right_green_shared_quad_state, - green_rect2, - gfx::Rect(), - green_rect2, - gfx::RectF(green_rect2.size()), - green_rect2.size(), - texture_format, - green_rect2, - 1.f, - PicturePileImpl::CreateFromOther(green_pile.get())); + green_quad2->SetNew(top_right_green_shared_quad_state, green_rect2, + gfx::Rect(), green_rect2, gfx::RectF(green_rect2.size()), + green_rect2.size(), texture_format, green_rect2, 1.f, + green_pile.get()); // Add a green clipped checkerboard in the bottom right to help test // interleaving picture quad content and solid color content. @@ -2072,16 +2027,10 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) { content_to_target_transform, quad_content_rect, pass.get()); PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - blue_quad->SetNew(blue_shared_state, - quad_content_rect, - gfx::Rect(), - quad_content_rect, - gfx::RectF(quad_content_rect), - content_union_rect.size(), - texture_format, - content_union_rect, - contents_scale, - PicturePileImpl::CreateFromOther(pile.get())); + blue_quad->SetNew(blue_shared_state, quad_content_rect, gfx::Rect(), + quad_content_rect, gfx::RectF(quad_content_rect), + content_union_rect.size(), texture_format, + content_union_rect, contents_scale, pile.get()); // Fill left half of viewport with green. gfx::Transform half_green_content_to_target_transform; @@ -2284,16 +2233,9 @@ TEST_F(GLRendererPixelTest, PictureDrawQuadTexture4444) { blue_content_to_target_transform, viewport, pass.get()); PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); - blue_quad->SetNew(blue_shared_state, - viewport, - gfx::Rect(), - viewport, - gfx::RectF(0.f, 0.f, 1.f, 1.f), - viewport.size(), - texture_format, - viewport, - 1.f, - PicturePileImpl::CreateFromOther(blue_pile.get())); + blue_quad->SetNew(blue_shared_state, viewport, gfx::Rect(), viewport, + gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(), + texture_format, viewport, 1.f, blue_pile.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); diff --git a/cc/output/shader.cc b/cc/output/shader.cc index eb5041ac58..b962d4ace9 100644 --- a/cc/output/shader.cc +++ b/cc/output/shader.cc @@ -546,6 +546,7 @@ std::string VertexShaderTile::GetShaderString() const { return VERTEX_SHADER( // clang-format on attribute TexCoordPrecision vec4 a_position; + attribute TexCoordPrecision vec2 a_texCoord; attribute float a_index; uniform mat4 matrix; uniform TexCoordPrecision vec2 quad[4]; @@ -554,7 +555,7 @@ std::string VertexShaderTile::GetShaderString() const { void main() { vec2 pos = quad[int(a_index)]; // NOLINT gl_Position = matrix * vec4(pos, a_position.z, a_position.w); - v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy; + v_texCoord = a_texCoord * vertexTexTransform.zw + vertexTexTransform.xy; } // clang-format off ); // NOLINT(whitespace/parens) diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc index e00ed54eab..1ebb1cff15 100644 --- a/cc/resources/picture_pile.cc +++ b/cc/resources/picture_pile.cc @@ -538,9 +538,20 @@ bool PicturePile::UpdateAndExpandInvalidation( void PicturePile::SetEmptyBounds() { tiling_.SetTilingSize(gfx::Size()); - picture_map_.clear(); - has_any_recordings_ = false; - recorded_viewport_ = gfx::Rect(); + Clear(); +} + +bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const { + bool include_borders = false; + for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + return false; + if (!map_iter->second.GetPicture()) + return false; + } + return true; } void PicturePile::DetermineIfSolidColor() { diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h index 7cd22296c5..18e1e5273a 100644 --- a/cc/resources/picture_pile.h +++ b/cc/resources/picture_pile.h @@ -55,6 +55,11 @@ class CC_EXPORT PicturePile : public PicturePileBase { void SetPixelRecordDistanceForTesting(int d) { pixel_record_distance_ = d; } + protected: + // An internal CanRaster check that goes to the picture_map rather than + // using the recorded_viewport hint. + bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; + private: friend class PicturePileImpl; diff --git a/cc/resources/picture_pile_base.cc b/cc/resources/picture_pile_base.cc index e7888f799f..1184cf1e2a 100644 --- a/cc/resources/picture_pile_base.cc +++ b/cc/resources/picture_pile_base.cc @@ -130,6 +130,8 @@ void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { void PicturePileBase::Clear() { picture_map_.clear(); recorded_viewport_ = gfx::Rect(); + has_any_recordings_ = false; + is_solid_color_ = false; } bool PicturePileBase::HasRecordingAt(int x, int y) { @@ -139,39 +141,6 @@ bool PicturePileBase::HasRecordingAt(int x, int y) { return !!found->second.GetPicture(); } -bool PicturePileBase::CanRaster(float contents_scale, - const gfx::Rect& content_rect) const { - if (tiling_.tiling_size().IsEmpty()) - return false; - gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.f / contents_scale); - layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); - - // Common case inside of viewport to avoid the slower map lookups. - if (recorded_viewport_.Contains(layer_rect)) { - // Sanity check that there are no false positives in recorded_viewport_. - DCHECK(CanRasterSlowTileCheck(layer_rect)); - return true; - } - - return CanRasterSlowTileCheck(layer_rect); -} - -bool PicturePileBase::CanRasterSlowTileCheck( - const gfx::Rect& layer_rect) const { - bool include_borders = false; - for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); - tile_iter; - ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - return false; - if (!map_iter->second.GetPicture()) - return false; - } - return true; -} - gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const { gfx::Rect tile = tiling_.TileBounds(key.first, key.second); return PadRect(tile); @@ -184,25 +153,6 @@ gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const { return padded_rect; } -void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const { - gfx::Rect tiling_rect(tiling_.tiling_size()); - std::set<const void*> appended_pictures; - bool include_borders = true; - for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); - tile_iter; - ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - continue; - - const Picture* picture = map_iter->second.GetPicture(); - if (picture && (appended_pictures.count(picture) == 0)) { - appended_pictures.insert(picture); - TracedValue::AppendIDRef(picture, pictures); - } - } -} - PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {} PicturePileBase::PictureInfo::~PictureInfo() {} diff --git a/cc/resources/picture_pile_base.h b/cc/resources/picture_pile_base.h index 71e5bad185..66d37d81b8 100644 --- a/cc/resources/picture_pile_base.h +++ b/cc/resources/picture_pile_base.h @@ -42,16 +42,11 @@ class CC_EXPORT PicturePileBase { int num_tiles_y() const { return tiling_.num_tiles_y(); } gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); } bool HasRecordingAt(int x, int y); - bool CanRaster(float contents_scale, const gfx::Rect& content_rect) const; - - // If this pile contains any valid recordings. May have false positives. - bool HasRecordings() const { return has_any_recordings_; } bool is_solid_color() const { return is_solid_color_; } SkColor solid_color() const { return solid_color_; } void set_is_mask(bool is_mask) { is_mask_ = is_mask; } - bool is_mask() const { return is_mask_; } static void ComputeTileGridInfo(const gfx::Size& tile_grid_size, SkTileGridFactory::TileGridInfo* info); @@ -59,12 +54,17 @@ class CC_EXPORT PicturePileBase { void SetTileGridSize(const gfx::Size& tile_grid_size); TilingData& tiling() { return tiling_; } - void AsValueInto(base::debug::TracedValue* array) const; - SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const { return tile_grid_info_; } + void SetRecordedViewportForTesting(const gfx::Rect& viewport) { + recorded_viewport_ = viewport; + } + void SetHasAnyRecordingsForTesting(bool has_recordings) { + has_any_recordings_ = has_recordings; + } + protected: class CC_EXPORT PictureInfo { public: @@ -104,10 +104,6 @@ class CC_EXPORT PicturePileBase { gfx::Rect PaddedRect(const PictureMapKey& key) const; gfx::Rect PadRect(const gfx::Rect& rect) const; - // An internal CanRaster check that goes to the picture_map rather than - // using the recorded_viewport hint. - bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; - // A picture pile is a tiled set of pictures. The picture map is a map of tile // indices to picture infos. PictureMap picture_map_; @@ -129,6 +125,8 @@ class CC_EXPORT PicturePileBase { SkColor solid_color_; private: + friend class PicturePileImpl; + void SetBufferPixels(int buffer_pixels); DISALLOW_COPY_AND_ASSIGN(PicturePileBase); diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc index 0ad746c853..de25c04721 100644 --- a/cc/resources/picture_pile_impl.cc +++ b/cc/resources/picture_pile_impl.cc @@ -26,11 +26,34 @@ scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther( } PicturePileImpl::PicturePileImpl() - : likely_to_be_used_for_transform_animation_(false) { + : background_color_(SK_ColorTRANSPARENT), + contents_opaque_(false), + contents_fill_bounds_completely_(false), + is_solid_color_(false), + solid_color_(SK_ColorTRANSPARENT), + has_any_recordings_(false), + is_mask_(false), + clear_canvas_with_debug_color_(false), + min_contents_scale_(0.f), + slow_down_raster_scale_factor_for_debug_(0), + likely_to_be_used_for_transform_animation_(false) { } PicturePileImpl::PicturePileImpl(const PicturePileBase* other) - : PicturePileBase(other), + : picture_map_(other->picture_map_), + tiling_(other->tiling_), + background_color_(other->background_color_), + contents_opaque_(other->contents_opaque_), + contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), + is_solid_color_(other->is_solid_color_), + solid_color_(other->solid_color_), + recorded_viewport_(other->recorded_viewport_), + has_any_recordings_(other->has_any_recordings_), + is_mask_(other->is_mask_), + clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), + min_contents_scale_(other->min_contents_scale_), + slow_down_raster_scale_factor_for_debug_( + other->slow_down_raster_scale_factor_for_debug_), likely_to_be_used_for_transform_animation_(false) { } @@ -320,13 +343,65 @@ void PicturePileImpl::GatherPixelRefs( bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect, float contents_scale) const { - return CanRaster(contents_scale, content_rect); + if (tiling_.tiling_size().IsEmpty()) + return false; + gfx::Rect layer_rect = + gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); + layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); + + // Common case inside of viewport to avoid the slower map lookups. + if (recorded_viewport_.Contains(layer_rect)) { + // Sanity check that there are no false positives in recorded_viewport_. + DCHECK(CanRasterSlowTileCheck(layer_rect)); + return true; + } + + return CanRasterSlowTileCheck(layer_rect); +} + +gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const { + gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second); + padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(), + -buffer_pixels()); + return padded_rect; +} + +bool PicturePileImpl::CanRasterSlowTileCheck( + const gfx::Rect& layer_rect) const { + bool include_borders = false; + for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + return false; + if (!map_iter->second.GetPicture()) + return false; + } + return true; } bool PicturePileImpl::SuitableForDistanceFieldText() const { return likely_to_be_used_for_transform_animation_; } +void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const { + gfx::Rect tiling_rect(tiling_.tiling_size()); + std::set<const void*> appended_pictures; + bool include_borders = true; + for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); + tile_iter; ++tile_iter) { + PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); + if (map_iter == picture_map_.end()) + continue; + + const Picture* picture = map_iter->second.GetPicture(); + if (picture && (appended_pictures.count(picture) == 0)) { + appended_pictures.insert(picture); + TracedValue::AppendIDRef(picture, pictures); + } + } +} + PicturePileImpl::PixelRefIterator::PixelRefIterator( const gfx::Rect& content_rect, float contents_scale, diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h index 9f350a9933..479846bb0f 100644 --- a/cc/resources/picture_pile_impl.h +++ b/cc/resources/picture_pile_impl.h @@ -22,7 +22,7 @@ namespace cc { // TODO(vmpstr): Clean up PicturePileBase and make it a member. -class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource { +class CC_EXPORT PicturePileImpl : public RasterSource { public: static scoped_refptr<PicturePileImpl> Create(); static scoped_refptr<PicturePileImpl> CreateFromOther( @@ -59,6 +59,14 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource { likely_to_be_used_for_transform_animation_ = true; } + gfx::Size tiling_size() const { return tiling_.tiling_size(); } + bool is_solid_color() const { return is_solid_color_; } + SkColor solid_color() const { return solid_color_; } + // If this pile contains any valid recordings. May have false positives. + bool HasRecordings() const { return has_any_recordings_; } + void AsValueInto(base::debug::TracedValue* array) const; + bool is_mask() const { return is_mask_; } + // Iterator used to return SkPixelRefs from this picture pile. // Public for testing. class CC_EXPORT PixelRefIterator { @@ -87,10 +95,32 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource { friend class PicturePile; friend class PixelRefIterator; + // TODO(vmpstr): Change this when pictures are split from invalidation info, + // and when PicturePileBase goes away. + using PictureMapKey = PicturePileBase::PictureMapKey; + using PictureMap = PicturePileBase::PictureMap; + using PictureInfo = PicturePileBase::PictureInfo; + PicturePileImpl(); explicit PicturePileImpl(const PicturePileBase* other); ~PicturePileImpl() override; + int buffer_pixels() const { return tiling_.border_texels(); } + + PictureMap picture_map_; + TilingData tiling_; + SkColor background_color_; + bool contents_opaque_; + bool contents_fill_bounds_completely_; + bool is_solid_color_; + SkColor solid_color_; + gfx::Rect recorded_viewport_; + bool has_any_recordings_; + bool is_mask_; + bool clear_canvas_with_debug_color_; + float min_contents_scale_; + int slow_down_raster_scale_factor_for_debug_; + private: typedef std::map<const Picture*, Region> PictureRegionMap; @@ -112,6 +142,12 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource { float contents_scale, bool is_analysis) const; + // An internal CanRaster check that goes to the picture_map rather than + // using the recorded_viewport hint. + bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; + + gfx::Rect PaddedRect(const PictureMapKey& key) const; + bool likely_to_be_used_for_transform_animation_; DISALLOW_COPY_AND_ASSIGN(PicturePileImpl); diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc index 98415ca396..60a1f0b71a 100644 --- a/cc/resources/picture_pile_unittest.cc +++ b/cc/resources/picture_pile_unittest.cc @@ -26,10 +26,15 @@ class TestPicturePile : public PicturePile { PictureMap& picture_map() { return picture_map_; } const gfx::Rect& recorded_viewport() const { return recorded_viewport_; } - bool CanRasterLayerRect(const gfx::Rect& layer_rect) { - return CanRaster(1.f, layer_rect); + bool CanRasterLayerRect(gfx::Rect layer_rect) { + layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); + if (recorded_viewport_.Contains(layer_rect)) + return true; + return CanRasterSlowTileCheck(layer_rect); } + bool HasRecordings() const { return has_any_recordings_; } + typedef PicturePile::PictureInfo PictureInfo; typedef PicturePile::PictureMapKey PictureMapKey; typedef PicturePile::PictureMap PictureMap; @@ -1456,5 +1461,17 @@ TEST_F(PicturePileTest, NonSolidRectangleOnOffsettedLayerIsNonSolid) { EXPECT_FALSE(pile_.is_solid_color()); } +TEST_F(PicturePileTest, SetEmptyBounds) { + EXPECT_TRUE(pile_.is_solid_color()); + EXPECT_FALSE(pile_.tiling_size().IsEmpty()); + EXPECT_FALSE(pile_.picture_map().empty()); + EXPECT_TRUE(pile_.HasRecordings()); + pile_.SetEmptyBounds(); + EXPECT_FALSE(pile_.is_solid_color()); + EXPECT_TRUE(pile_.tiling_size().IsEmpty()); + EXPECT_TRUE(pile_.picture_map().empty()); + EXPECT_FALSE(pile_.HasRecordings()); +} + } // namespace } // namespace cc diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc index 9229db686e..ca26edd6a4 100644 --- a/cc/resources/raster_worker_pool.cc +++ b/cc/resources/raster_worker_pool.cc @@ -12,7 +12,9 @@ #include "base/threading/simple_thread.h" #include "cc/base/scoped_ptr_deque.h" #include "cc/resources/raster_source.h" +#include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" namespace cc { namespace { @@ -194,51 +196,72 @@ void RasterWorkerPool::InsertNodesForRasterTask( InsertNodeForTask(graph, raster_task, priority, dependencies); } -// static -void RasterWorkerPool::PlaybackToMemory(void* memory, - ResourceFormat format, - const gfx::Size& size, - int stride, - const RasterSource* raster_source, - const gfx::Rect& rect, - float scale) { - SkBitmap bitmap; +static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) { switch (format) { case RGBA_4444: - bitmap.allocN32Pixels(size.width(), size.height()); - break; case RGBA_8888: - case BGRA_8888: { - SkImageInfo info = - SkImageInfo::MakeN32Premul(size.width(), size.height()); - if (!stride) - stride = info.minRowBytes(); - bitmap.installPixels(info, memory, stride); - break; - } + case BGRA_8888: + return true; case ALPHA_8: case LUMINANCE_8: case RGB_565: case ETC1: - NOTREACHED(); - break; + return false; } + NOTREACHED(); + return false; +} - SkCanvas canvas(bitmap); - raster_source->PlaybackToCanvas(&canvas, rect, scale); +// static +void RasterWorkerPool::PlaybackToMemory(void* memory, + ResourceFormat format, + const gfx::Size& size, + int stride, + const RasterSource* raster_source, + const gfx::Rect& rect, + float scale) { + DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format; + // Uses kPremul_SkAlphaType since the result is not known to be opaque. + SkImageInfo info = + SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType); SkColorType buffer_color_type = ResourceFormatToSkColorType(format); - if (buffer_color_type != bitmap.colorType()) { - SkImageInfo dst_info = bitmap.info(); - dst_info.fColorType = buffer_color_type; - // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the - // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728 - // is fixed. - const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes()); - DCHECK_EQ(0u, dst_row_bytes % 4); - bool success = bitmap.readPixels(dst_info, memory, dst_row_bytes, 0, 0); - DCHECK_EQ(true, success); + bool needs_copy = buffer_color_type != info.colorType(); + + // TODO(danakj): Make a SkSurfaceProps with an SkPixelGeometry to enable or + // disable LCD text. + // TODO(danakj): Disable LCD text on Mac during layout tests: + // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm&l=55 + // TODO(danakj): On Windows when LCD text is disabled, ask skia to draw LCD + // text offscreen and downsample it to AA text. + // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp&l=86 + SkSurfaceProps* surface_props = nullptr; + + if (!stride) + stride = info.minRowBytes(); + + if (!needs_copy) { + skia::RefPtr<SkSurface> surface = skia::AdoptRef( + SkSurface::NewRasterDirect(info, memory, stride, surface_props)); + skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + raster_source->PlaybackToCanvas(canvas.get(), rect, scale); + return; } + + skia::RefPtr<SkSurface> surface = + skia::AdoptRef(SkSurface::NewRaster(info, surface_props)); + skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + raster_source->PlaybackToCanvas(canvas.get(), rect, scale); + + SkImageInfo dst_info = info; + dst_info.fColorType = buffer_color_type; + // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the + // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728 + // is fixed. + const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes()); + DCHECK_EQ(0u, dst_row_bytes % 4); + bool success = canvas->readPixels(dst_info, memory, dst_row_bytes, 0, 0); + DCHECK_EQ(true, success); } } // namespace cc diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc index 755fe1ab59..8b6a72afc6 100644 --- a/cc/resources/tile_manager.cc +++ b/cc/resources/tile_manager.cc @@ -561,6 +561,7 @@ void TileManager::AssignGpuMemoryToTiles( ManagedTileState& mts = tile->managed_state(); mts.scheduled_priority = schedule_priority++; + mts.resolution = priority.resolution; DCHECK(mts.draw_info.mode() == ManagedTileState::DrawInfo::PICTURE_PILE_MODE || diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc index 32e61c5ed7..600455f126 100644 --- a/cc/surfaces/surface.cc +++ b/cc/surfaces/surface.cc @@ -9,6 +9,7 @@ #include "cc/output/compositor_frame.h" #include "cc/output/copy_output_request.h" #include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_id_allocator.h" #include "cc/surfaces/surface_manager.h" namespace cc { @@ -57,7 +58,8 @@ void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame, draw_callback_.Run(); draw_callback_ = callback; factory_->manager()->DidSatisfySequences( - surface_id_, ¤t_frame_->metadata.satisfies_sequences); + SurfaceIdAllocator::NamespaceForId(surface_id_), + ¤t_frame_->metadata.satisfies_sequences); } void Surface::RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> copy_request) { @@ -111,6 +113,19 @@ void Surface::RunDrawCallbacks() { } } +void Surface::AddDestructionDependency(SurfaceSequence sequence) { + destruction_dependencies_.push_back(sequence); +} + +void Surface::SatisfyDestructionDependencies( + base::hash_set<SurfaceSequence>* sequences) { + destruction_dependencies_.erase( + std::remove_if( + destruction_dependencies_.begin(), destruction_dependencies_.end(), + [sequences](SurfaceSequence seq) { return !!sequences->erase(seq); }), + destruction_dependencies_.end()); +} + void Surface::ClearCopyRequests() { if (current_frame_) { for (const auto& render_pass : diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h index ffa50420c0..7b3fbc125b 100644 --- a/cc/surfaces/surface.h +++ b/cc/surfaces/surface.h @@ -17,6 +17,7 @@ #include "cc/output/copy_output_request.h" #include "cc/quads/render_pass_id.h" #include "cc/surfaces/surface_id.h" +#include "cc/surfaces/surface_sequence.h" #include "cc/surfaces/surfaces_export.h" #include "ui/gfx/geometry/size.h" @@ -57,6 +58,18 @@ class CC_SURFACES_EXPORT Surface { base::WeakPtr<SurfaceFactory> factory() { return factory_; } + // Add a SurfaceSequence that must be satisfied before the Surface is + // destroyed. + void AddDestructionDependency(SurfaceSequence sequence); + + // Satisfy all destruction dependencies that are contained in sequences, and + // remove them from sequences. + void SatisfyDestructionDependencies( + base::hash_set<SurfaceSequence>* sequences); + size_t GetDestructionDependencyCount() const { + return destruction_dependencies_.size(); + } + private: void ClearCopyRequests(); @@ -66,6 +79,7 @@ class CC_SURFACES_EXPORT Surface { // TODO(jamesr): Support multiple frames in flight. scoped_ptr<CompositorFrame> current_frame_; int frame_index_; + std::vector<SurfaceSequence> destruction_dependencies_; base::Closure draw_callback_; diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc index 88c54557cb..574f5d1fae 100644 --- a/cc/surfaces/surface_factory.cc +++ b/cc/surfaces/surface_factory.cc @@ -25,8 +25,8 @@ SurfaceFactory::~SurfaceFactory() { } void SurfaceFactory::DestroyAll() { - for (auto& surface : surface_map_) - manager_->DeregisterSurface(surface.first); + for (auto it = surface_map_.begin(); it != surface_map_.end(); ++it) + manager_->Destroy(surface_map_.take(it)); surface_map_.clear(); } @@ -41,17 +41,7 @@ void SurfaceFactory::Destroy(SurfaceId surface_id) { OwningSurfaceMap::iterator it = surface_map_.find(surface_id); DCHECK(it != surface_map_.end()); DCHECK(it->second->factory().get() == this); - manager_->DeregisterSurface(surface_id); - surface_map_.erase(it); -} - -void SurfaceFactory::DestroyOnSequence( - SurfaceId surface_id, - const std::set<SurfaceSequence>& dependency_set) { - OwningSurfaceMap::iterator it = surface_map_.find(surface_id); - DCHECK(it != surface_map_.end()); - DCHECK(it->second->factory().get() == this); - manager_->DestroyOnSequence(surface_map_.take_and_erase(it), dependency_set); + manager_->Destroy(surface_map_.take_and_erase(it)); } void SurfaceFactory::SubmitFrame(SurfaceId surface_id, diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h index 13d1d63fb1..8e9211c57b 100644 --- a/cc/surfaces/surface_factory.h +++ b/cc/surfaces/surface_factory.h @@ -40,8 +40,6 @@ class CC_SURFACES_EXPORT SurfaceFactory void Create(SurfaceId surface_id, const gfx::Size& size); void Destroy(SurfaceId surface_id); - void DestroyOnSequence(SurfaceId surface_id, - const std::set<SurfaceSequence>& dependency_set); void DestroyAll(); // A frame can only be submitted to a surface created by this factory, // although the frame may reference surfaces created by other factories. diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc index e36636c5f1..14a25fdf71 100644 --- a/cc/surfaces/surface_factory_unittest.cc +++ b/cc/surfaces/surface_factory_unittest.cc @@ -381,9 +381,9 @@ TEST_F(SurfaceFactoryTest, DestroySequence) { factory_.Create(id2, gfx::Size(5, 5)); // Check that waiting before the sequence is satisfied works. - std::set<SurfaceSequence> sequence; - sequence.insert(SurfaceSequence(0, 4)); - factory_.DestroyOnSequence(id2, sequence); + manager_.GetSurfaceForId(id2) + ->AddDestructionDependency(SurfaceSequence(0, 4)); + factory_.Destroy(id2); scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); scoped_ptr<CompositorFrame> frame(new CompositorFrame); @@ -396,10 +396,10 @@ TEST_F(SurfaceFactoryTest, DestroySequence) { // Check that waiting after the sequence is satisfied works. factory_.Create(id2, gfx::Size(5, 5)); - sequence.clear(); - sequence.insert(SurfaceSequence(0, 6)); DCHECK(manager_.GetSurfaceForId(id2)); - factory_.DestroyOnSequence(id2, sequence); + manager_.GetSurfaceForId(id2) + ->AddDestructionDependency(SurfaceSequence(0, 6)); + factory_.Destroy(id2); DCHECK(!manager_.GetSurfaceForId(id2)); } diff --git a/cc/surfaces/surface_manager.cc b/cc/surfaces/surface_manager.cc index 920f464cdd..050f04b062 100644 --- a/cc/surfaces/surface_manager.cc +++ b/cc/surfaces/surface_manager.cc @@ -19,8 +19,8 @@ SurfaceManager::~SurfaceManager() { for (SurfaceDestroyList::iterator it = surfaces_to_destroy_.begin(); it != surfaces_to_destroy_.end(); ++it) { - DeregisterSurface(it->first->surface_id()); - delete it->first; + DeregisterSurface((*it)->surface_id()); + delete *it; } } @@ -38,20 +38,19 @@ void SurfaceManager::DeregisterSurface(SurfaceId surface_id) { surface_map_.erase(it); } -void SurfaceManager::DestroyOnSequence( - scoped_ptr<Surface> surface, - const std::set<SurfaceSequence>& dependency_set) { - surfaces_to_destroy_.push_back(make_pair(surface.release(), dependency_set)); +void SurfaceManager::Destroy(scoped_ptr<Surface> surface) { + DCHECK(thread_checker_.CalledOnValidThread()); + surfaces_to_destroy_.push_back(surface.release()); SearchForSatisfaction(); } -void SurfaceManager::DidSatisfySequences(SurfaceId id, +void SurfaceManager::DidSatisfySequences(uint32_t id_namespace, std::vector<uint32_t>* sequence) { + DCHECK(thread_checker_.CalledOnValidThread()); for (std::vector<uint32_t>::iterator it = sequence->begin(); it != sequence->end(); ++it) { - satisfied_sequences_.insert( - SurfaceSequence(SurfaceIdAllocator::NamespaceForId(id), *it)); + satisfied_sequences_.insert(SurfaceSequence(id_namespace, *it)); } sequence->clear(); SearchForSatisfaction(); @@ -60,21 +59,9 @@ void SurfaceManager::DidSatisfySequences(SurfaceId id, void SurfaceManager::SearchForSatisfaction() { for (SurfaceDestroyList::iterator dest_it = surfaces_to_destroy_.begin(); dest_it != surfaces_to_destroy_.end();) { - std::set<SurfaceSequence>& dependency_set = dest_it->second; - - for (std::set<SurfaceSequence>::iterator it = dependency_set.begin(); - it != dependency_set.end();) { - if (satisfied_sequences_.count(*it) > 0) { - satisfied_sequences_.erase(*it); - std::set<SurfaceSequence>::iterator old_it = it; - ++it; - dependency_set.erase(old_it); - } else { - ++it; - } - } - if (dependency_set.empty()) { - scoped_ptr<Surface> surf(dest_it->first); + (*dest_it)->SatisfyDestructionDependencies(&satisfied_sequences_); + if (!(*dest_it)->GetDestructionDependencyCount()) { + scoped_ptr<Surface> surf(*dest_it); DeregisterSurface(surf->surface_id()); dest_it = surfaces_to_destroy_.erase(dest_it); } else { diff --git a/cc/surfaces/surface_manager.h b/cc/surfaces/surface_manager.h index 66db9d90ee..d6303523b4 100644 --- a/cc/surfaces/surface_manager.h +++ b/cc/surfaces/surface_manager.h @@ -6,7 +6,6 @@ #define CC_SURFACES_SURFACE_MANAGER_H_ #include <list> -#include <set> #include <vector> #include "base/containers/hash_tables.h" @@ -31,8 +30,7 @@ class CC_SURFACES_EXPORT SurfaceManager { void DeregisterSurface(SurfaceId surface_id); // Destroy the Surface once a set of sequence numbers has been satisfied. - void DestroyOnSequence(scoped_ptr<Surface> surface, - const std::set<SurfaceSequence>& dependency_set); + void Destroy(scoped_ptr<Surface> surface); Surface* GetSurfaceForId(SurfaceId surface_id); @@ -46,8 +44,10 @@ class CC_SURFACES_EXPORT SurfaceManager { void SurfaceModified(SurfaceId surface_id); - // A frame for a surface satisfies a set of sequence numbers. - void DidSatisfySequences(SurfaceId id, std::vector<uint32_t>* sequence); + // A frame for a surface satisfies a set of sequence numbers in a particular + // id namespace. + void DidSatisfySequences(uint32_t id_namespace, + std::vector<uint32_t>* sequence); private: void SearchForSatisfaction(); @@ -59,13 +59,12 @@ class CC_SURFACES_EXPORT SurfaceManager { // List of surfaces to be destroyed, along with what sequences they're still // waiting on. - typedef std::list<std::pair<Surface*, std::set<SurfaceSequence>>> - SurfaceDestroyList; + typedef std::list<Surface*> SurfaceDestroyList; SurfaceDestroyList surfaces_to_destroy_; // Set of SurfaceSequences that have been satisfied by a frame but not yet // waited on. - std::set<SurfaceSequence> satisfied_sequences_; + base::hash_set<SurfaceSequence> satisfied_sequences_; DISALLOW_COPY_AND_ASSIGN(SurfaceManager); }; diff --git a/cc/surfaces/surface_sequence.h b/cc/surfaces/surface_sequence.h index 4c99e45858..72f4bc9926 100644 --- a/cc/surfaces/surface_sequence.h +++ b/cc/surfaces/surface_sequence.h @@ -5,6 +5,8 @@ #ifndef CC_SURFACES_SURFACE_SEQUENCE_H_ #define CC_SURFACES_SURFACE_SEQUENCE_H_ +#include "base/containers/hash_tables.h" + namespace cc { // A per-surface-namespace sequence number that's used to coordinate @@ -14,6 +16,7 @@ struct SurfaceSequence { SurfaceSequence() : id_namespace(0u), sequence(0u) {} SurfaceSequence(uint32_t id_namespace, uint32_t sequence) : id_namespace(id_namespace), sequence(sequence) {} + bool is_null() const { return id_namespace == 0u && sequence == 0u; } uint32_t id_namespace; uint32_t sequence; @@ -35,4 +38,13 @@ inline bool operator<(const SurfaceSequence& a, const SurfaceSequence& b) { } // namespace cc +namespace BASE_HASH_NAMESPACE { +template <> +struct hash<cc::SurfaceSequence> { + size_t operator()(cc::SurfaceSequence key) const { + return base::HashPair(key.id_namespace, key.sequence); + } +}; +} // namespace BASE_HASH_NAMESPACE + #endif // CC_SURFACES_SURFACE_SEQUENCE_H_ diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc index 32a6589ee9..e688d22020 100644 --- a/cc/test/fake_picture_pile_impl.cc +++ b/cc/test/fake_picture_pile_impl.cc @@ -4,9 +4,11 @@ #include "cc/test/fake_picture_pile_impl.h" +#include <algorithm> #include <limits> #include <utility> +#include "cc/resources/picture_pile.h" #include "cc/test/impl_side_painting_settings.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,62 +16,71 @@ namespace cc { FakePicturePileImpl::FakePicturePileImpl() {} +FakePicturePileImpl::FakePicturePileImpl(const PicturePileBase* other) + : PicturePileImpl(other), + tile_grid_info_(other->GetTileGridInfoForTesting()) { +} + FakePicturePileImpl::~FakePicturePileImpl() {} scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFilledPile( const gfx::Size& tile_size, const gfx::Size& layer_bounds) { - scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl()); - pile->tiling().SetTilingSize(layer_bounds); - pile->tiling().SetMaxTextureSize(tile_size); - pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); - pile->recorded_viewport_ = gfx::Rect(layer_bounds); - pile->has_any_recordings_ = true; - for (int x = 0; x < pile->tiling().num_tiles_x(); ++x) { - for (int y = 0; y < pile->tiling().num_tiles_y(); ++y) - pile->AddRecordingAt(x, y); + PicturePile pile; + pile.tiling().SetTilingSize(layer_bounds); + pile.tiling().SetMaxTextureSize(tile_size); + pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); + pile.SetRecordedViewportForTesting(gfx::Rect(layer_bounds)); + pile.SetHasAnyRecordingsForTesting(true); + + auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile)); + for (int x = 0; x < pile_impl->tiling().num_tiles_x(); ++x) { + for (int y = 0; y < pile_impl->tiling().num_tiles_y(); ++y) + pile_impl->AddRecordingAt(x, y); } - return pile; + return pile_impl; } scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateEmptyPile( const gfx::Size& tile_size, const gfx::Size& layer_bounds) { - scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl()); - pile->tiling().SetTilingSize(layer_bounds); - pile->tiling().SetMaxTextureSize(tile_size); - pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); - pile->recorded_viewport_ = gfx::Rect(); - pile->has_any_recordings_ = false; - return pile; + PicturePile pile; + pile.tiling().SetTilingSize(layer_bounds); + pile.tiling().SetMaxTextureSize(tile_size); + pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); + pile.SetRecordedViewportForTesting(gfx::Rect()); + pile.SetHasAnyRecordingsForTesting(false); + return make_scoped_refptr(new FakePicturePileImpl(&pile)); } scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings( const gfx::Size& tile_size, const gfx::Size& layer_bounds) { - scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl()); - pile->tiling().SetTilingSize(layer_bounds); - pile->tiling().SetMaxTextureSize(tile_size); - pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); + PicturePile pile; + pile.tiling().SetTilingSize(layer_bounds); + pile.tiling().SetMaxTextureSize(tile_size); + pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size); // This simulates a false positive for this flag. - pile->recorded_viewport_ = gfx::Rect(); - pile->has_any_recordings_ = true; - return pile; + pile.SetRecordedViewportForTesting(gfx::Rect()); + pile.SetHasAnyRecordingsForTesting(true); + return make_scoped_refptr(new FakePicturePileImpl(&pile)); } scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateInfiniteFilledPile() { - scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl()); + PicturePile pile; gfx::Size size(std::numeric_limits<int>::max(), std::numeric_limits<int>::max()); - pile->tiling().SetTilingSize(size); - pile->tiling().SetMaxTextureSize(size); - pile->SetTileGridSize(size); - pile->recorded_viewport_ = gfx::Rect(size); - pile->has_any_recordings_ = true; - pile->AddRecordingAt(0, 0); - return pile; + pile.tiling().SetTilingSize(size); + pile.tiling().SetMaxTextureSize(size); + pile.SetTileGridSize(size); + pile.SetRecordedViewportForTesting(gfx::Rect(size)); + pile.SetHasAnyRecordingsForTesting(true); + + auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile)); + pile_impl->AddRecordingAt(0, 0); + return pile_impl; } void FakePicturePileImpl::AddRecordingAt(int x, int y) { @@ -103,6 +114,13 @@ void FakePicturePileImpl::RemoveRecordingAt(int x, int y) { EXPECT_FALSE(HasRecordingAt(x, y)); } +bool FakePicturePileImpl::HasRecordingAt(int x, int y) const { + PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y)); + if (found == picture_map_.end()) + return false; + return !!found->second.GetPicture(); +} + void FakePicturePileImpl::RerecordPile() { for (int y = 0; y < num_tiles_y(); ++y) { for (int x = 0; x < num_tiles_x(); ++x) { @@ -112,4 +130,37 @@ void FakePicturePileImpl::RerecordPile() { } } +void FakePicturePileImpl::SetMinContentsScale(float min_contents_scale) { + if (min_contents_scale_ == min_contents_scale) + return; + + // Picture contents are played back scaled. When the final contents scale is + // less than 1 (i.e. low res), then multiple recorded pixels will be used + // to raster one final pixel. To avoid splitting a final pixel across + // pictures (which would result in incorrect rasterization due to blending), a + // buffer margin is added so that any picture can be snapped to integral + // final pixels. + // + // For example, if a 1/4 contents scale is used, then that would be 3 buffer + // pixels, since that's the minimum number of pixels to add so that resulting + // content can be snapped to a four pixel aligned grid. + int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1); + buffer_pixels = std::max(0, buffer_pixels); + SetBufferPixels(buffer_pixels); + min_contents_scale_ = min_contents_scale; +} + +void FakePicturePileImpl::SetBufferPixels(int new_buffer_pixels) { + if (new_buffer_pixels == buffer_pixels()) + return; + + Clear(); + tiling_.SetBorderTexels(new_buffer_pixels); +} + +void FakePicturePileImpl::Clear() { + picture_map_.clear(); + recorded_viewport_ = gfx::Rect(); +} + } // namespace cc diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h index 10c769aefa..ab27238bc7 100644 --- a/cc/test/fake_picture_pile_impl.h +++ b/cc/test/fake_picture_pile_impl.h @@ -72,12 +72,24 @@ class FakePicturePileImpl : public PicturePileImpl { is_solid_color_ = is_solid_color; } + bool HasRecordingAt(int x, int y) const; + void SetIsMask(bool mask) { is_mask_ = mask; } + + int num_tiles_x() const { return tiling_.num_tiles_x(); } + int num_tiles_y() const { return tiling_.num_tiles_y(); } + + void SetMinContentsScale(float scale); + void SetBufferPixels(int new_buffer_pixels); + void Clear(); + protected: FakePicturePileImpl(); + explicit FakePicturePileImpl(const PicturePileBase* other); ~FakePicturePileImpl() override; FakeContentLayerClient client_; SkPaint default_paint_; + SkTileGridFactory::TileGridInfo tile_grid_info_; }; } // namespace cc diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 3898156776..af7eb5bc96 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc @@ -128,7 +128,9 @@ LayerTreeHost::LayerTreeHost( id_(s_layer_tree_host_sequence_number.GetNext() + 1), next_commit_forces_redraw_(false), shared_bitmap_manager_(shared_bitmap_manager), - gpu_memory_buffer_manager_(gpu_memory_buffer_manager) { + gpu_memory_buffer_manager_(gpu_memory_buffer_manager), + surface_id_namespace_(0u), + next_surface_sequence_(1u) { if (settings_.accelerated_animation_enabled) animation_registrar_ = AnimationRegistrar::Create(); rendering_stats_instrumentation_->set_record_rendering_stats( @@ -167,15 +169,15 @@ void LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) { LayerTreeHost::~LayerTreeHost() { TRACE_EVENT0("cc", "LayerTreeHost::~LayerTreeHost"); - DCHECK(swap_promise_monitor_.empty()); - - BreakSwapPromises(SwapPromise::COMMIT_FAILS); - overhang_ui_resource_ = nullptr; if (root_layer_.get()) root_layer_->SetLayerTreeHost(NULL); + DCHECK(swap_promise_monitor_.empty()); + + BreakSwapPromises(SwapPromise::COMMIT_FAILS); + if (proxy_) { DCHECK(proxy_->IsMainThread()); proxy_->Stop(); @@ -1336,4 +1338,12 @@ void LayerTreeHost::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { swap_promise_list_.clear(); } +void LayerTreeHost::set_surface_id_namespace(uint32_t id_namespace) { + surface_id_namespace_ = id_namespace; +} + +SurfaceSequence LayerTreeHost::CreateSurfaceSequence() { + return SurfaceSequence(surface_id_namespace_, next_surface_sequence_++); +} + } // namespace cc diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 10964160bb..a56a6cd43d 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h @@ -34,6 +34,7 @@ #include "cc/output/output_surface.h" #include "cc/resources/resource_format.h" #include "cc/resources/scoped_ui_resource.h" +#include "cc/surfaces/surface_sequence.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_settings.h" @@ -307,6 +308,9 @@ class CC_EXPORT LayerTreeHost { size_t num_queued_swap_promises() const { return swap_promise_list_.size(); } + void set_surface_id_namespace(uint32_t id_namespace); + SurfaceSequence CreateSurfaceSequence(); + protected: LayerTreeHost(LayerTreeHostClient* client, SharedBitmapManager* shared_bitmap_manager, @@ -464,6 +468,9 @@ class CC_EXPORT LayerTreeHost { ScopedPtrVector<SwapPromise> swap_promise_list_; std::set<SwapPromiseMonitor*> swap_promise_monitor_; + uint32_t surface_id_namespace_; + uint32_t next_surface_sequence_; + DISALLOW_COPY_AND_ASSIGN(LayerTreeHost); }; diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 20f0c6dfb0..00be57f29e 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -152,8 +152,14 @@ size_t GetMaxTransferBufferUsageBytes( unsigned GetMapImageTextureTarget( const ContextProvider::Capabilities& context_capabilities) { +// TODO(reveman): This should be a setting passed to the compositor instead +// of hard-coded here. The target that need to be used depends on our choice +// of GpuMemoryBuffer type. Note: SURFACE_TEXTURE needs EXTERNAL_OES, +// IO_SURFACE needs RECTANGLE_ARB. crbug.com/431059 +#if defined(OS_ANDROID) if (context_capabilities.gpu.egl_image_external) return GL_TEXTURE_EXTERNAL_OES; +#endif if (context_capabilities.gpu.texture_rectangle) return GL_TEXTURE_RECTANGLE_ARB; @@ -2632,11 +2638,12 @@ bool LayerTreeHostImpl::ShouldTopControlsConsumeScroll( return false; } -bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point, - const gfx::Vector2dF& scroll_delta) { +InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( + const gfx::Point& viewport_point, + const gfx::Vector2dF& scroll_delta) { TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy"); if (!CurrentlyScrollingLayer()) - return false; + return InputHandlerScrollResult(); gfx::Vector2dF pending_delta = scroll_delta; gfx::Vector2dF unused_root_delta; @@ -2757,15 +2764,14 @@ bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point, accumulated_root_overscroll_.set_x(0); if (did_scroll_y) accumulated_root_overscroll_.set_y(0); - accumulated_root_overscroll_ += unused_root_delta; - bool did_overscroll = !unused_root_delta.IsZero(); - if (did_overscroll && input_handler_client_) { - input_handler_client_->DidOverscroll( - viewport_point, accumulated_root_overscroll_, unused_root_delta); - } - return did_scroll_content || did_scroll_top_controls; + InputHandlerScrollResult scroll_result; + scroll_result.did_scroll = did_scroll_content || did_scroll_top_controls; + scroll_result.did_overscroll_root = !unused_root_delta.IsZero(); + scroll_result.accumulated_root_overscroll = accumulated_root_overscroll_; + scroll_result.unused_scroll_delta = unused_root_delta; + return scroll_result; } // This implements scrolling by page as described here: diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 157fe00eb6..2309ef77d5 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h @@ -136,8 +136,9 @@ class CC_EXPORT LayerTreeHostImpl InputHandler::ScrollStatus ScrollAnimated( const gfx::Point& viewport_point, const gfx::Vector2dF& scroll_delta) override; - bool ScrollBy(const gfx::Point& viewport_point, - const gfx::Vector2dF& scroll_delta) override; + InputHandlerScrollResult ScrollBy( + const gfx::Point& viewport_point, + const gfx::Vector2dF& scroll_delta) override; bool ScrollVerticallyByPage(const gfx::Point& viewport_point, ScrollDirection direction) override; void SetRootLayerScrollOffsetDelegate( diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 773fd1f878..45d636a547 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -777,27 +777,40 @@ TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) { host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); // Trying to scroll to the left/top will not succeed. - EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); - EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10))); - EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10))); + EXPECT_FALSE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll); + EXPECT_FALSE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll); + EXPECT_FALSE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll); // Scrolling to the right/bottom will succeed. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)).did_scroll); // Scrolling to left/top will now succeed. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll); // Scrolling diagonally against an edge will succeed. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)).did_scroll); // Trying to scroll more than the available space will also succeed. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)).did_scroll); } TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) { @@ -3710,6 +3723,7 @@ TEST_F(LayerTreeHostImplTest, } TEST_F(LayerTreeHostImplTest, OverscrollRoot) { + InputHandlerScrollResult scroll_result; SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); @@ -3719,38 +3733,105 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) { // In-bounds scrolling does not affect overscroll. EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_FALSE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); // Overscroll events are reflected immediately. - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); // In-bounds scrolling resets accumulated overscroll for the scrolled axes. - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_FALSE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)); + EXPECT_FALSE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_FALSE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(-5, 0), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(-5, -10), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(-5, 10), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); // Overscroll accumulates within the scope of ScrollBegin/ScrollEnd as long // as no scroll occurs. - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + EXPECT_FALSE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -30), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + EXPECT_FALSE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -50), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + // Overscroll resets on valid scroll. - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_FALSE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll()); - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20)); + EXPECT_TRUE(scroll_result.did_scroll); + EXPECT_TRUE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta); EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll()); + EXPECT_EQ(scroll_result.accumulated_root_overscroll, + host_impl_->accumulated_root_overscroll()); + host_impl_->ScrollEnd(); } @@ -5964,7 +6045,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) { class GLRendererWithSetupQuadForAntialiasing : public GLRenderer { public: - using GLRenderer::SetupQuadForAntialiasing; + using GLRenderer::ShouldAntialiasQuad; }; TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { @@ -6022,11 +6103,9 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { ASSERT_LE(1u, frame.render_passes[0]->quad_list.size()); const DrawQuad* quad = frame.render_passes[0]->quad_list.front(); - float edge[24]; - gfx::QuadF device_layer_quad; bool antialiased = - GLRendererWithSetupQuadForAntialiasing::SetupQuadForAntialiasing( - quad->quadTransform(), quad, &device_layer_quad, edge); + GLRendererWithSetupQuadForAntialiasing::ShouldAntialiasQuad( + quad->quadTransform(), quad, false); EXPECT_FALSE(antialiased); host_impl_->DrawLayers(&frame, gfx::FrameTime::Now()); @@ -6556,7 +6635,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { gfx::Vector2d scroll_delta(0, -2); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta)); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); // The grand child should have scrolled up to its limit. scroll_info = host_impl_->ProcessScrollDeltas(); @@ -6566,7 +6645,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { // The child should have received the bubbled delta, but the locked // scrolling layer should remain set as the grand child. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta)); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); scroll_info = host_impl_->ProcessScrollDeltas(); ASSERT_EQ(2u, scroll_info->scrolls.size()); ExpectContains(*scroll_info, grand_child->id(), scroll_delta); @@ -6576,7 +6655,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { // The first |ScrollBy| after the fling should re-lock the scrolling // layer to the first layer that scrolled, which is the child. EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin()); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta)); + EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); // The child should have scrolled up to its limit. @@ -6586,7 +6665,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { ExpectContains(*scroll_info, child->id(), scroll_delta + scroll_delta); // As the locked layer is at it's limit, no further scrolling can occur. - EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta)); + EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); host_impl_->ScrollEnd(); } @@ -6984,7 +7063,8 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) { // Scrolling normally should not trigger any forwarding. EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll); host_impl_->ScrollEnd(); EXPECT_EQ(0, set_needs_commit_count); @@ -6996,7 +7076,8 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) { scroll_layer->SetHaveScrollEventHandlers(true); EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll); host_impl_->ScrollEnd(); EXPECT_EQ(0, set_needs_commit_count); @@ -7051,7 +7132,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // Scroll just the top controls and verify that the scroll succeeds. const float residue = 10; float offset = top_controls_height_ - residue; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->TotalScrollOffset().ToString()); @@ -7059,7 +7141,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // Scroll across the boundary const float content_scroll = 20; offset = residue + content_scroll; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(-top_controls_height_, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(), @@ -7067,7 +7150,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // Now scroll back to the top of the content offset = -content_scroll; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(-top_controls_height_, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), @@ -7075,13 +7159,15 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // And scroll the top controls completely into view offset = -top_controls_height_; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->TotalScrollOffset().ToString()); // And attempt to scroll past the end - EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_FALSE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->TotalScrollOffset().ToString()); @@ -7105,7 +7191,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) { // Scroll the top controls partially. const float residue = 35; float offset = top_controls_height_ - residue; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->TotalScrollOffset().ToString()); @@ -7173,7 +7260,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) { // Scroll the top controls partially. const float residue = 15; float offset = top_controls_height_ - residue; - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset))); + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), scroll_layer->TotalScrollOffset().ToString()); diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index e922f21712..8e7d220d1a 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc @@ -1091,13 +1091,6 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient { *received_stop_flinging_ = true; } - void DidOverscroll(const gfx::PointF& causal_event_viewport_point, - const gfx::Vector2dF& accumulated_overscroll, - const gfx::Vector2dF& latest_overscroll_delta) override { - if (!task_runner_->BelongsToCurrentThread()) - ADD_FAILURE() << "DidOverscroll called on wrong thread"; - } - private: base::SingleThreadTaskRunner* task_runner_; bool* received_stop_flinging_; |