summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorjbauman <jbauman@chromium.org>2014-11-06 15:26:44 -0800
committerCommit bot <commit-bot@chromium.org>2014-11-06 23:27:33 +0000
commitdbccae1ab081972ddee790058d817721d94d55dd (patch)
tree3b021ea9c528970a56343e79ee725f68db8a787d /cc
parent78e3d60d83366c66e82ec147a061be200088a656 (diff)
downloadchromium_src-dbccae1ab081972ddee790058d817721d94d55dd.zip
chromium_src-dbccae1ab081972ddee790058d817721d94d55dd.tar.gz
chromium_src-dbccae1ab081972ddee790058d817721d94d55dd.tar.bz2
Allow layers to signal that additional sequences are needed before surface destruction
A single surface can be referenced by multiple layers in separate compositors, so we need to be able to have every layer individually signal the manager that the Surface shouldn't be released until it's done with it. When a SurfaceLayer's added to a LayerTreeHost, a new SurfaceSequence is created for that compositor and sent to the SurfaceManager for it to wait on before the Surface is destroyed. When the Surface is destroyed, that set of sequences is waited for. When the SurfaceLayer is removed from a compositor, a SwapPromise is created on that compositor that will satisfy its SurfaceSequence in the next frame (which won't reference the Surface). BUG=411118 Review URL: https://codereview.chromium.org/666163006 Cr-Commit-Position: refs/heads/master@{#303119}
Diffstat (limited to 'cc')
-rw-r--r--cc/BUILD.gn1
-rw-r--r--cc/cc_tests.gyp1
-rw-r--r--cc/layers/surface_layer.cc76
-rw-r--r--cc/layers/surface_layer.h23
-rw-r--r--cc/layers/surface_layer_unittest.cc206
-rw-r--r--cc/surfaces/surface.cc17
-rw-r--r--cc/surfaces/surface.h14
-rw-r--r--cc/surfaces/surface_factory.cc16
-rw-r--r--cc/surfaces/surface_factory.h2
-rw-r--r--cc/surfaces/surface_factory_unittest.cc12
-rw-r--r--cc/surfaces/surface_manager.cc35
-rw-r--r--cc/surfaces/surface_manager.h15
-rw-r--r--cc/surfaces/surface_sequence.h12
-rw-r--r--cc/trees/layer_tree_host.cc20
-rw-r--r--cc/trees/layer_tree_host.h7
15 files changed, 392 insertions, 65 deletions
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index a578b61..9b417f0 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -705,6 +705,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",
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 1300d32..75267ef 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/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index ba577a0..f1909b4 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -4,21 +4,60 @@
#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) {
+ SatisfyDestroySequence();
surface_id_ = surface_id;
+ CreateNewDestroySequence();
+
UpdateDrawsContent(HasDrawableContent());
SetNeedsPushProperties();
}
@@ -31,6 +70,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 +88,22 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetSurfaceId(surface_id_);
}
+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 0b886eb..4292549 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -8,6 +8,7 @@
#include "cc/base/cc_export.h"
#include "cc/layers/layer.h"
#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_sequence.h"
namespace cc {
@@ -15,22 +16,40 @@ 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)>;
+
+ // 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);
// Layer overrides.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
+ void SetLayerTreeHost(LayerTreeHost* host) override;
void PushPropertiesTo(LayerImpl* layer) 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_;
+ 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 0000000..99d0e17
--- /dev/null
+++ b/cc/layers/surface_layer_unittest.cc
@@ -0,0 +1,206 @@
+// 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));
+ 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));
+ 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 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));
+
+ // 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/surfaces/surface.cc b/cc/surfaces/surface.cc
index 32e61c5..600455f 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_, &current_frame_->metadata.satisfies_sequences);
+ SurfaceIdAllocator::NamespaceForId(surface_id_),
+ &current_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 ffa5042..7b3fbc1 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 88c5455..574f5d1 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 13d1d63..8e9211c 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 e36636c..14a25fd 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 920f464..050f04b 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 66db9d9..d630352 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 4c99e45..72f4bc9 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/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 3898156..af7eb5b 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 1096416..a56a6cd 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);
};