Commit d358fb4f authored by kylechar's avatar kylechar Committed by Commit bot

Separate client surface reference tracking from FrameGenerator.

The logic to track surface references for surface embeddings was built
as part of FrameGenerator. Generalize the logic and remove from
FrameGenerator, creating the class EmbeddedSurfaceTracker.

EmbeddedSurfaceTracker keeps track of surface references from one client
surface to many embedded surfaces. It also handles generating new
references when the client surface changes. Includes unit tests.

This simplifies FrameGenerator and should make it easier to use surface
references in other clients.

BUG=659227
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel

Review-Url: https://codereview.chromium.org/2610063007
Cr-Commit-Position: refs/heads/master@{#442997}
parent b622b0bb
...@@ -936,6 +936,7 @@ cc_test("cc_unittests") { ...@@ -936,6 +936,7 @@ cc_test("cc_unittests") {
"surfaces/direct_compositor_frame_sink_unittest.cc", "surfaces/direct_compositor_frame_sink_unittest.cc",
"surfaces/display_scheduler_unittest.cc", "surfaces/display_scheduler_unittest.cc",
"surfaces/display_unittest.cc", "surfaces/display_unittest.cc",
"surfaces/embedded_surface_tracker_unittest.cc",
"surfaces/surface_aggregator_unittest.cc", "surfaces/surface_aggregator_unittest.cc",
"surfaces/surface_factory_unittest.cc", "surfaces/surface_factory_unittest.cc",
"surfaces/surface_hittest_unittest.cc", "surfaces/surface_hittest_unittest.cc",
......
...@@ -44,6 +44,8 @@ cc_component("surfaces") { ...@@ -44,6 +44,8 @@ cc_component("surfaces") {
"display_client.h", "display_client.h",
"display_scheduler.cc", "display_scheduler.cc",
"display_scheduler.h", "display_scheduler.h",
"embedded_surface_tracker.cc",
"embedded_surface_tracker.h",
"sequence_surface_reference_factory.cc", "sequence_surface_reference_factory.cc",
"sequence_surface_reference_factory.h", "sequence_surface_reference_factory.h",
"surface.cc", "surface.cc",
......
// Copyright 2016 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/surfaces/embedded_surface_tracker.h"
#include <utility>
#include "base/logging.h"
namespace cc {
EmbeddedSurfaceTracker::EmbeddedSurfaceTracker() {}
EmbeddedSurfaceTracker::~EmbeddedSurfaceTracker() {}
void EmbeddedSurfaceTracker::SetCurrentSurfaceId(const SurfaceId& surface_id) {
DCHECK(surface_id.is_valid());
DCHECK_NE(current_surface_id_, surface_id);
// The last submitted CompositorFrame for |current_surface_id_| still embeds
// the surfaces in |references_to_remove_| and hasn't embedded the surfaces in
// |references_to_add_| yet.
references_to_remove_.clear();
references_to_add_.clear();
current_surface_id_ = surface_id;
// Add references from updated |current_surface_id_| to all embedded surfaces.
for (auto& map_entry : embedded_surfaces_)
AddReference(current_surface_id_, map_entry.second);
}
bool EmbeddedSurfaceTracker::EmbedSurface(const SurfaceId& embedded_id) {
auto iter = embedded_surfaces_.find(embedded_id.frame_sink_id());
// This is the first surface for the FrameSinkId.
if (iter == embedded_surfaces_.end()) {
if (HasValidSurfaceId())
AddReference(current_surface_id_, embedded_id);
// Add record that surface is embedded.
embedded_surfaces_[embedded_id.frame_sink_id()] = embedded_id;
return true;
}
// This is not the first surface for the FrameSinkId, we are unembedding the
// old surface and embedding the new surface.
SurfaceId& stored_surface_id = iter->second;
DCHECK_NE(stored_surface_id, embedded_id);
if (HasValidSurfaceId()) {
RemoveReference(current_surface_id_, stored_surface_id);
AddReference(current_surface_id_, embedded_id);
}
stored_surface_id = embedded_id;
return false;
}
void EmbeddedSurfaceTracker::UnembedSurface(const FrameSinkId& frame_sink_id) {
auto iter = embedded_surfaces_.find(frame_sink_id);
if (iter == embedded_surfaces_.end())
return;
if (HasValidSurfaceId())
RemoveReference(current_surface_id_, iter->second);
// Remove record that surface is embedded.
embedded_surfaces_.erase(iter);
}
std::vector<SurfaceReference> EmbeddedSurfaceTracker::GetReferencesToAdd() {
std::vector<SurfaceReference> references;
std::swap(references, references_to_add_);
return references;
}
std::vector<SurfaceReference> EmbeddedSurfaceTracker::GetReferencesToRemove() {
std::vector<SurfaceReference> references;
std::swap(references, references_to_remove_);
return references;
}
void EmbeddedSurfaceTracker::AddReference(const SurfaceId& parent_id,
const SurfaceId& child_id) {
references_to_add_.push_back(SurfaceReference(parent_id, child_id));
}
void EmbeddedSurfaceTracker::RemoveReference(const SurfaceId& parent_id,
const SurfaceId& child_id) {
references_to_remove_.push_back(SurfaceReference(parent_id, child_id));
}
} // namespace cc
// Copyright 2016 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.
#ifndef CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
#define CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
#include <unordered_map>
#include <vector>
#include "base/macros.h"
#include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_reference.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
namespace test {
class EmbeddedSurfaceTrackerTest;
}
// Tracks surface references from a client surface to embedded surfaces. Handles
// updating the references when the client surface resizes.
class CC_SURFACES_EXPORT EmbeddedSurfaceTracker {
public:
EmbeddedSurfaceTracker();
~EmbeddedSurfaceTracker();
const SurfaceId& current_surface_id() const { return current_surface_id_; }
// Checks if the client has a valid SurfaceId. This will become true after
// SetCurrentSurfaceId() is called for the first time. No references will be
// added or removed until this is true.
bool HasValidSurfaceId() const { return current_surface_id_.is_valid(); }
// Sets |current_surface_id_| when the client switches surfaces. Clears all
// references waiting to be added or removed, since no CompositorFrame will be
// submitted for the previous surface now. Generates new references from the
// new surface to all embedded surfaces. Does not send IPC.
void SetCurrentSurfaceId(const SurfaceId& surface_id);
// Adds a reference from |current_surface_id_| to |embedded_id| and records
// |embedded_id|. If an existing surface with the same FrameSinkId is embedded
// removes the reference to it. Does not send IPC. Returns true for the first
// surface from a FrameSinkId and false for all subsequent surfaces.
bool EmbedSurface(const SurfaceId& embedded_id);
// Removes reference from |current_surface_id_| to latest embedded surface for
// |frame_sink_id|. Does not send IPC.
void UnembedSurface(const FrameSinkId& frame_sink_id);
// Returns |references_to_add_| and clears contents. It's expected this will
// be called immediately before submitting a CompositorFrame and caller will
// add references via IPC.
std::vector<SurfaceReference> GetReferencesToAdd();
bool HasReferencesToAdd() const { return !references_to_add_.empty(); }
// Returns |references_to_remove_| and clears contents. It's expected this
// will be called immediately after submitting a CompositorFrame and caller
// will remove references via IPC.
std::vector<SurfaceReference> GetReferencesToRemove();
bool HasReferencesToRemove() const { return !references_to_remove_.empty(); }
private:
friend class test::EmbeddedSurfaceTrackerTest;
// Records adding a reference from |parent_id| to |child_id|. References are
// not actually added until SendAddSurfaceReferences() is called.
void AddReference(const SurfaceId& parent_id, const SurfaceId& child_id);
// Records removing a reference from |parent_id| to |child_id|. References
// are not actually removed until SendRemoveSurfaceReferences() is called.
void RemoveReference(const SurfaceId& parent_id, const SurfaceId& child_id);
// The id of the client surface that is embedding other surfaces.
SurfaceId current_surface_id_;
// Surfaces that are embedded by the client surface. A reference from
// |current_surface_id_| will be added if it's valid.
std::unordered_map<FrameSinkId, SurfaceId, FrameSinkIdHash>
embedded_surfaces_;
// References to surfaces that should be removed after the next
// CompositorFrame has been submitted and the surfaces are no longer embedded.
std::vector<SurfaceReference> references_to_remove_;
// References that should be added before the next CompositorFrame is
// submitted.
std::vector<SurfaceReference> references_to_add_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedSurfaceTracker);
};
} // namespace cc
#endif // CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
// Copyright 2017 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/surfaces/embedded_surface_tracker.h"
#include <memory>
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_reference.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::ElementsAre;
using testing::IsEmpty;
using testing::SizeIs;
namespace cc {
namespace test {
namespace {
constexpr FrameSinkId kParentFrameSink(2, 1);
constexpr FrameSinkId kEmbeddedFrameSink(65563, 1);
SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
return SurfaceId(
frame_sink_id,
LocalFrameId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
}
} // namespace
class EmbeddedSurfaceTrackerTest : public testing::Test {
public:
EmbeddedSurfaceTrackerTest() {}
~EmbeddedSurfaceTrackerTest() override {}
EmbeddedSurfaceTracker& tracker() { return *tracker_; }
// Returns references to add without clearing them.
const std::vector<SurfaceReference>& peek_to_add() {
return tracker_->references_to_add_;
}
// Returns references to remove without clearing them.
const std::vector<SurfaceReference>& peek_to_remove() {
return tracker_->references_to_remove_;
}
// testing::Test:
void SetUp() override {
testing::Test::SetUp();
tracker_ = base::MakeUnique<EmbeddedSurfaceTracker>();
}
void TearDown() override { tracker_.reset(); }
private:
std::unique_ptr<EmbeddedSurfaceTracker> tracker_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedSurfaceTrackerTest);
};
TEST_F(EmbeddedSurfaceTrackerTest, SetCurrentSurfaceId) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
// Initially HasValidSurfaceId() should be false.
EXPECT_FALSE(tracker().HasValidSurfaceId());
// After setting current SurfaceId then HasValidSurfaceId() should be true.
tracker().SetCurrentSurfaceId(parent_id);
EXPECT_TRUE(tracker().HasValidSurfaceId());
EXPECT_EQ(parent_id, tracker().current_surface_id());
}
TEST_F(EmbeddedSurfaceTrackerTest, EmbedSurface) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceReference reference(parent_id, embedded_id);
// Set parent surface id then embed another surface. The tracker should have a
// reference to add from parent surface to embedded surface.
tracker().SetCurrentSurfaceId(parent_id);
EXPECT_TRUE(tracker().EmbedSurface(embedded_id));
EXPECT_THAT(peek_to_add(), ElementsAre(reference));
// Getting the references to add should return the correct reference and empty
// the reference the add.
EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference));
EXPECT_THAT(peek_to_add(), IsEmpty());
}
TEST_F(EmbeddedSurfaceTrackerTest, EmbedNewSurfaceForFrameSink) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId embedded_id_first = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceId embedded_id_second = MakeSurfaceId(kEmbeddedFrameSink, 2);
const SurfaceReference reference_first(parent_id, embedded_id_first);
const SurfaceReference reference_second(parent_id, embedded_id_second);
// Embed a surface and add references.
tracker().SetCurrentSurfaceId(parent_id);
EXPECT_TRUE(tracker().EmbedSurface(embedded_id_first));
EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference_first));
// Embed a newer surface with the same FrameSinkId as the first embedded
// surface. The first reference should be in the list to remove and the new
// reference in the last to add.
EXPECT_FALSE(tracker().EmbedSurface(embedded_id_second));
EXPECT_THAT(peek_to_remove(), ElementsAre(reference_first));
EXPECT_THAT(peek_to_add(), ElementsAre(reference_second));
}
TEST_F(EmbeddedSurfaceTrackerTest, UnembedSurface) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceReference reference(parent_id, embedded_id);
tracker().SetCurrentSurfaceId(parent_id);
tracker().EmbedSurface(embedded_id);
EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference));
EXPECT_THAT(peek_to_remove(), IsEmpty());
// Unembed the surface. The reference should be in the list to remove.
tracker().UnembedSurface(embedded_id.frame_sink_id());
EXPECT_THAT(peek_to_remove(), ElementsAre(reference));
// Getting the references to remove should return the correct reference and
// empty the reference the remove.
EXPECT_THAT(tracker().GetReferencesToRemove(), ElementsAre(reference));
EXPECT_THAT(peek_to_remove(), IsEmpty());
}
TEST_F(EmbeddedSurfaceTrackerTest, EmbedSurfaceBeforeSetCurrentSurfaceId) {
const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceReference reference(parent_id, embedded_id);
// Embed a surface before the parent id is set. There should be no references
// to add because we don't know the parent id yet.
tracker().EmbedSurface(embedded_id);
EXPECT_THAT(peek_to_add(), IsEmpty());
// Set the parent id, this should add a reference to add to the embedded
// surface.
tracker().SetCurrentSurfaceId(parent_id);
EXPECT_THAT(peek_to_add(), ElementsAre(reference));
}
TEST_F(EmbeddedSurfaceTrackerTest, UpdateCurrentSurfaceId) {
const SurfaceId parent_id_first = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId parent_id_second = MakeSurfaceId(kParentFrameSink, 2);
const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceReference reference(parent_id_second, embedded_id);
// Set parent id and embed a surface.
tracker().SetCurrentSurfaceId(parent_id_first);
tracker().EmbedSurface(embedded_id);
EXPECT_THAT(tracker().GetReferencesToAdd(), SizeIs(1));
// Update the current parent id. There should be a reference to add from the
// new parent id to the embedded surface.
tracker().SetCurrentSurfaceId(parent_id_second);
EXPECT_THAT(peek_to_add(), ElementsAre(reference));
}
TEST_F(EmbeddedSurfaceTrackerTest, UpdateCurrentSurfaceIdBeforeAdding) {
const SurfaceId parent_id_first = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId parent_id_second = MakeSurfaceId(kParentFrameSink, 2);
const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
const SurfaceReference reference_first(parent_id_first, embedded_id);
const SurfaceReference reference_second(parent_id_second, embedded_id);
// Set parent id and embed a surface. There should be a reference to add from
// the parent to embedded surface.
tracker().SetCurrentSurfaceId(parent_id_first);
tracker().EmbedSurface(embedded_id);
EXPECT_THAT(peek_to_add(), ElementsAre(reference_first));
// Update the parent id before sending IPC to add references. There should be
// a reference to add from the new parent id to the embedded surface and the
// previous reference to add was deleted.
tracker().SetCurrentSurfaceId(parent_id_second);
EXPECT_THAT(peek_to_add(), ElementsAre(reference_second));
EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference_second));
}
} // namespace test
} // namespace cc
This diff is collapsed.
...@@ -6,12 +6,11 @@ ...@@ -6,12 +6,11 @@
#define SERVICES_UI_WS_FRAME_GENERATOR_H_ #define SERVICES_UI_WS_FRAME_GENERATOR_H_
#include <memory> #include <memory>
#include <unordered_map>
#include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "cc/ipc/display_compositor.mojom.h" #include "cc/ipc/display_compositor.mojom.h"
#include "cc/surfaces/embedded_surface_tracker.h"
#include "cc/surfaces/frame_sink_id.h" #include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/surface_id.h" #include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_id_allocator.h" #include "cc/surfaces/surface_id_allocator.h"
...@@ -77,6 +76,9 @@ class FrameGenerator : public ServerWindowTracker, ...@@ -77,6 +76,9 @@ class FrameGenerator : public ServerWindowTracker,
void ReclaimResources(const cc::ReturnedResourceArray& resources) override; void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
void WillDrawSurface() override; void WillDrawSurface() override;
// Updates the display surface SurfaceId using new value in |local_frame_id_|.
void UpdateDisplaySurfaceId();
// Generates the CompositorFrame. // Generates the CompositorFrame.
cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect); cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect);
...@@ -84,36 +86,6 @@ class FrameGenerator : public ServerWindowTracker, ...@@ -84,36 +86,6 @@ class FrameGenerator : public ServerWindowTracker,
// appends it to the provided cc::RenderPass. // appends it to the provided cc::RenderPass.
void DrawWindow(cc::RenderPass* pass, ServerWindow* window); void DrawWindow(cc::RenderPass* pass, ServerWindow* window);
// Finds the parent surface id for |window|.
cc::SurfaceId FindParentSurfaceId(ServerWindow* window);
// Adds surface reference to local cache and surface manager.
void AddSurfaceReference(const cc::SurfaceId& parent_id,
const cc::SurfaceId& child_id);
// Does work necessary for adding the first surface reference.
void AddFirstReference(const cc::SurfaceId& surface_id, ServerWindow* window);
// Finds all Surfaces with references from |old_surface_id| and adds a new
// reference from |new_surface_id|. The caller should remove any references
// to |old_surface_id| afterwards to finish cleanup.
void AddNewParentReferences(const cc::SurfaceId& old_surface_id,
const cc::SurfaceId& new_surface_id);
// Sends IPC to add references in |references_to_add_|.
void PerformAddSurfaceReferences();
// Sends IPC to remove all references in |references_to_remove_|.
void PerformRemoveSurfaceReferences();
// Removes any retained references for |frame_sink_id_|.
void RemoveFrameSinkReference(const cc::FrameSinkId& frame_sink_id);
// Removes all retained references to surfaces.
void RemoveAllSurfaceReferences();
cc::mojom::DisplayCompositor* GetDisplayCompositor();
// ServerWindowObserver implementation. // ServerWindowObserver implementation.
void OnWindowDestroying(ServerWindow* window) override; void OnWindowDestroying(ServerWindow* window) override;
...@@ -127,24 +99,8 @@ class FrameGenerator : public ServerWindowTracker, ...@@ -127,24 +99,8 @@ class FrameGenerator : public ServerWindowTracker,
cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink_; cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink_;
cc::mojom::DisplayPrivatePtr display_private_; cc::mojom::DisplayPrivatePtr display_private_;
// Active references held by this client to surfaces that could be embedded in // Tracks surface references for embedded surfaces.
// a CompositorFrame submitted from FrameGenerator. cc::EmbeddedSurfaceTracker surface_tracker_;
std::unordered_map<cc::FrameSinkId, cc::SurfaceReference, cc::FrameSinkIdHash>
active_references_;
// References to surfaces that should be removed after a CompositorFrame has
// been submitted and the surfaces are not being used.
std::vector<cc::SurfaceReference> references_to_remove_;
// References that should be added before the next CompositorFrame is
// submitted.
std::vector<cc::SurfaceReference> references_to_add_;
// If a CompositorFrame for a child surface is submitted before the first
// display root CompositorFrame, we can't add a reference from the unknown
// display root SurfaceId. Track the child SurfaceId here and add a reference
// to it when the display root SurfaceId is available.
std::vector<cc::SurfaceId> waiting_for_references_;
mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_; mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment