blob: 9fcb12a70a6ce779da086d279a8fa9799e1c6686 [file] [log] [blame]
// 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 "components/viz/host/host_frame_sink_manager.h"
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/run_loop.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface_manager.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_host_frame_sink_client.h"
#include "components/viz/test/fake_surface_observer.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "components/viz/test/mock_display_client.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace viz {
namespace {
constexpr FrameSinkId kFrameSinkParent1(1, 1);
constexpr FrameSinkId kFrameSinkParent2(2, 1);
constexpr FrameSinkId kFrameSinkChild1(3, 1);
ACTION_P(InvokeClosure, closure) {
closure.Run();
}
// Makes a SurfaceId with a default nonce.
SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t parent_id) {
return SurfaceId(
frame_sink_id,
LocalSurfaceId(parent_id, base::UnguessableToken::Deserialize(0, 1u)));
}
// Holds the four interface objects needed to create a RootCompositorFrameSink.
struct RootCompositorFrameSinkData {
mojom::RootCompositorFrameSinkParamsPtr BuildParams(
const FrameSinkId& frame_sink_id) {
auto params = mojom::RootCompositorFrameSinkParams::New();
params->frame_sink_id = frame_sink_id;
params->widget = gpu::kNullSurfaceHandle;
params->compositor_frame_sink = MakeRequest(&compositor_frame_sink);
params->compositor_frame_sink_client =
compositor_frame_sink_client.BindInterfacePtr().PassInterface();
params->display_private = MakeRequest(&display_private);
params->display_client = display_client.BindInterfacePtr().PassInterface();
return params;
}
mojom::CompositorFrameSinkAssociatedPtr compositor_frame_sink;
MockCompositorFrameSinkClient compositor_frame_sink_client;
mojom::DisplayPrivateAssociatedPtr display_private;
MockDisplayClient display_client;
};
// A mock implementation of mojom::FrameSinkManager.
class MockFrameSinkManagerImpl : public FrameSinkManagerImpl {
public:
explicit MockFrameSinkManagerImpl(SharedBitmapManager* shared_bitmap_manager)
: FrameSinkManagerImpl(shared_bitmap_manager) {}
~MockFrameSinkManagerImpl() override = default;
// mojom::FrameSinkManager:
MOCK_METHOD2(RegisterFrameSinkId,
void(const FrameSinkId& frame_sink_id, bool report_activation));
MOCK_METHOD1(InvalidateFrameSinkId, void(const FrameSinkId& frame_sink_id));
MOCK_METHOD2(SetFrameSinkDebugLabel,
void(const FrameSinkId& frame_sink_id,
const std::string& debug_label));
// Work around for gmock not supporting move-only types.
void CreateCompositorFrameSink(
const FrameSinkId& frame_sink_id,
mojom::CompositorFrameSinkRequest request,
mojom::CompositorFrameSinkClientPtr client) override {
MockCreateCompositorFrameSink(frame_sink_id);
}
MOCK_METHOD1(MockCreateCompositorFrameSink,
void(const FrameSinkId& frame_sink_id));
void CreateRootCompositorFrameSink(
mojom::RootCompositorFrameSinkParamsPtr params) override {
MockCreateRootCompositorFrameSink(params->frame_sink_id);
}
MOCK_METHOD1(MockCreateRootCompositorFrameSink,
void(const FrameSinkId& frame_sink_id));
void DestroyCompositorFrameSink(
const FrameSinkId& frame_sink_id,
DestroyCompositorFrameSinkCallback callback) override {
MockDestroyCompositorFrameSink(frame_sink_id);
std::move(callback).Run();
}
MOCK_METHOD1(MockDestroyCompositorFrameSink,
void(const FrameSinkId& frame_sink_id));
MOCK_METHOD2(RegisterFrameSinkHierarchy,
void(const FrameSinkId& parent, const FrameSinkId& child));
MOCK_METHOD2(UnregisterFrameSinkHierarchy,
void(const FrameSinkId& parent, const FrameSinkId& child));
private:
DISALLOW_COPY_AND_ASSIGN(MockFrameSinkManagerImpl);
};
} // namespace
class HostFrameSinkManagerTestBase : public testing::Test {
public:
HostFrameSinkManagerTestBase() = default;
~HostFrameSinkManagerTestBase() override = default;
HostFrameSinkManager& host() { return *host_manager_; }
MockFrameSinkManagerImpl& impl() { return *manager_impl_; }
mojom::FrameSinkManagerClient* GetFrameSinkManagerClient() {
return static_cast<mojom::FrameSinkManagerClient*>(host_manager_.get());
}
bool FrameSinkDataExists(const FrameSinkId& frame_sink_id) const {
return host_manager_->frame_sink_data_map_.count(frame_sink_id) > 0;
}
bool IsBoundToFrameSinkManager() {
return host_manager_->frame_sink_manager_ptr_.is_bound() ||
host_manager_->binding_.is_bound();
}
bool DisplayHitTestQueryExists(const FrameSinkId& frame_sink_id) {
return host_manager_->display_hit_test_query_.count(frame_sink_id) > 0;
}
// testing::Test:
void TearDown() override {
host_manager_.reset();
manager_impl_.reset();
}
protected:
ServerSharedBitmapManager shared_bitmap_manager_;
std::unique_ptr<HostFrameSinkManager> host_manager_;
std::unique_ptr<testing::NiceMock<MockFrameSinkManagerImpl>> manager_impl_;
private:
DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManagerTestBase);
};
class HostFrameSinkManagerLocalTest : public HostFrameSinkManagerTestBase {
public:
HostFrameSinkManagerLocalTest() = default;
~HostFrameSinkManagerLocalTest() override = default;
std::unique_ptr<CompositorFrameSinkSupport> CreateCompositorFrameSinkSupport(
const FrameSinkId& frame_sink_id,
bool is_root) {
return host_manager_->CreateCompositorFrameSinkSupport(
nullptr /* client */, frame_sink_id, is_root,
false /* needs_sync_points */);
}
// testing::Test:
void SetUp() override {
manager_impl_ =
std::make_unique<testing::NiceMock<MockFrameSinkManagerImpl>>(
&shared_bitmap_manager_);
host_manager_ = std::make_unique<HostFrameSinkManager>();
manager_impl_->SetLocalClient(host_manager_.get());
host_manager_->SetLocalManager(manager_impl_.get());
}
private:
DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManagerLocalTest);
};
class HostFrameSinkManagerRemoteTest : public HostFrameSinkManagerTestBase {
public:
HostFrameSinkManagerRemoteTest() = default;
~HostFrameSinkManagerRemoteTest() override = default;
// Destroys FrameSinkManagerImpl which kills the message pipes.
void KillGpu() { manager_impl_.reset(); }
// Connects HostFrameSinkManager to FrameSinkManagerImpl using Mojo.
void ConnectToGpu() {
DCHECK(!manager_impl_);
manager_impl_ =
std::make_unique<testing::NiceMock<MockFrameSinkManagerImpl>>(
&shared_bitmap_manager_);
mojom::FrameSinkManagerPtr frame_sink_manager;
mojom::FrameSinkManagerRequest frame_sink_manager_request =
mojo::MakeRequest(&frame_sink_manager);
mojom::FrameSinkManagerClientPtr frame_sink_manager_client;
mojom::FrameSinkManagerClientRequest frame_sink_manager_client_request =
mojo::MakeRequest(&frame_sink_manager_client);
host_manager_->BindAndSetManager(
std::move(frame_sink_manager_client_request), nullptr,
std::move(frame_sink_manager));
manager_impl_->BindAndSetClient(std::move(frame_sink_manager_request),
nullptr,
std::move(frame_sink_manager_client));
}
// testing::Test:
void SetUp() override {
host_manager_ = std::make_unique<HostFrameSinkManager>();
ConnectToGpu();
}
private:
DISALLOW_COPY_AND_ASSIGN(HostFrameSinkManagerRemoteTest);
};
// Verify that creating and destroying a CompositorFrameSink using
// mojom::CompositorFrameSink works correctly.
TEST_F(HostFrameSinkManagerLocalTest, CreateMojomCompositorFrameSink) {
FakeHostFrameSinkClient host_client;
// Register then create CompositorFrameSink for child.
EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
true /* report_activation */));
host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
ReportFirstSurfaceActivation::kYes);
EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
EXPECT_CALL(impl(), MockCreateCompositorFrameSink(kFrameSinkChild1));
host().CreateCompositorFrameSink(kFrameSinkChild1, nullptr /* request */,
nullptr /* client */);
testing::Mock::VerifyAndClearExpectations(&impl());
// Register but don't actually create CompositorFrameSink for parent.
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
// Register should call through to FrameSinkManagerImpl and should work even
// though |kFrameSinkParent1| was not created yet.
EXPECT_CALL(impl(),
RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
// Destroy the CompositorFrameSink.
EXPECT_CALL(impl(), InvalidateFrameSinkId(kFrameSinkChild1));
host().InvalidateFrameSinkId(kFrameSinkChild1);
testing::Mock::VerifyAndClearExpectations(&impl());
// Unregister should work after the CompositorFrameSink is destroyed.
EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
kFrameSinkChild1));
host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
// Data for |kFrameSinkChild1| should be deleted now.
EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
}
// Verify that frame_token is sent HostFrameSinkClient if and only if the frame
// is active.
TEST_F(HostFrameSinkManagerLocalTest, CommunicateFrameToken) {
FakeHostFrameSinkClient host_client_parent;
FakeHostFrameSinkClient host_client_child;
FrameSinkId kParentFrameSink(3, 0);
FrameSinkId kChildFrameSink1(65563, 0);
const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
host().RegisterFrameSinkId(kParentFrameSink, &host_client_parent,
ReportFirstSurfaceActivation::kYes);
host().RegisterFrameSinkId(kChildFrameSink1, &host_client_child,
ReportFirstSurfaceActivation::kYes);
auto support =
CreateCompositorFrameSinkSupport(kParentFrameSink, true /* is_root */);
CompositorFrame compositor_frame = CompositorFrameBuilder()
.AddDefaultRenderPass()
.SetSendFrameTokenToEmbedder(true)
.SetActivationDependencies({child_id1})
.Build();
uint32_t frame_token = compositor_frame.metadata.frame_token;
ASSERT_NE(frame_token, 0u);
support->SubmitCompositorFrame(parent_id1.local_surface_id(),
std::move(compositor_frame));
Surface* parent_surface = support->GetLastCreatedSurfaceForTesting();
EXPECT_TRUE(parent_surface->has_deadline());
EXPECT_FALSE(parent_surface->HasActiveFrame());
EXPECT_TRUE(parent_surface->HasPendingFrame());
// Since the frame is not activated, |frame_token| is not sent to
// HostFrameSinkClient.
EXPECT_EQ(0u, host_client_parent.last_frame_token_seen());
parent_surface->ActivatePendingFrameForDeadline(base::nullopt);
EXPECT_FALSE(parent_surface->has_deadline());
EXPECT_TRUE(parent_surface->HasActiveFrame());
EXPECT_FALSE(parent_surface->HasPendingFrame());
// Since the frame is now activated, |frame_token| is sent to
// HostFrameSinkClient.
EXPECT_EQ(frame_token, host_client_parent.last_frame_token_seen());
}
// Verify that that creating two CompositorFrameSinkSupports works.
TEST_F(HostFrameSinkManagerLocalTest, CreateCompositorFrameSinkSupport) {
FakeHostFrameSinkClient host_client;
host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
ReportFirstSurfaceActivation::kYes);
auto support_child =
CreateCompositorFrameSinkSupport(kFrameSinkChild1, true /* is_root */);
EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
auto support_parent =
CreateCompositorFrameSinkSupport(kFrameSinkParent1, true /* is_root */);
EXPECT_TRUE(FrameSinkDataExists(kFrameSinkParent1));
// Verify that registering and unregistering frame sink hierarchy works.
EXPECT_CALL(impl(),
RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1));
host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
testing::Mock::VerifyAndClearExpectations(&impl());
EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(kFrameSinkParent1,
kFrameSinkChild1));
host().UnregisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
// We should still have the CompositorFrameSink data for |kFrameSinkChild1|.
EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
// Data for |kFrameSinkChild1| should be deleted when everything is destroyed.
support_child.reset();
host().InvalidateFrameSinkId(kFrameSinkChild1);
EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
// Data for |kFrameSinkParent1| should be deleted when everything is
// destroyed.
support_parent.reset();
host().InvalidateFrameSinkId(kFrameSinkParent1);
EXPECT_FALSE(FrameSinkDataExists(kFrameSinkParent1));
}
// Verify that multiple parents in the frame sink hierarchy works.
TEST_F(HostFrameSinkManagerLocalTest, HierarchyMultipleParents) {
FakeHostFrameSinkClient host_client;
// Register two parent and child CompositorFrameSink.
const FrameSinkId& id_parent1 = kFrameSinkParent1;
host().RegisterFrameSinkId(id_parent1, &host_client,
ReportFirstSurfaceActivation::kYes);
auto support_parent1 =
CreateCompositorFrameSinkSupport(id_parent1, true /* is_root */);
const FrameSinkId& id_parent2 = kFrameSinkChild1;
host().RegisterFrameSinkId(id_parent2, &host_client,
ReportFirstSurfaceActivation::kYes);
auto support_parent2 =
CreateCompositorFrameSinkSupport(id_parent2, true /* is_root */);
const FrameSinkId& id_child = kFrameSinkParent2;
host().RegisterFrameSinkId(id_child, &host_client,
ReportFirstSurfaceActivation::kYes);
auto support_child =
CreateCompositorFrameSinkSupport(id_child, false /* is_root */);
// Register |id_parent1| in hierarchy first, this is the original window
// embedding.
EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent1, id_child));
host().RegisterFrameSinkHierarchy(id_parent1, id_child);
// Register |id_parent2| in hierarchy second, this is a second embedding for
// something like alt-tab on a different monitor.
EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(id_parent2, id_child));
host().RegisterFrameSinkHierarchy(id_parent2, id_child);
testing::Mock::VerifyAndClearExpectations(&impl());
// Unregistering hierarchy with multiple parents should also work.
EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent2, id_child));
host().UnregisterFrameSinkHierarchy(id_parent2, id_child);
EXPECT_CALL(impl(), UnregisterFrameSinkHierarchy(id_parent1, id_child));
host().UnregisterFrameSinkHierarchy(id_parent1, id_child);
}
// Test the creation and desctruction of HitTestAggregator and HitTestQuery.
TEST_F(HostFrameSinkManagerLocalTest, HitTestAggregatorQuery) {
FakeHostFrameSinkClient client;
EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
host().RegisterFrameSinkId(kFrameSinkChild1, &client,
ReportFirstSurfaceActivation::kYes);
EXPECT_TRUE(FrameSinkDataExists(kFrameSinkChild1));
EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkChild1));
auto support =
CreateCompositorFrameSinkSupport(kFrameSinkChild1, true /* is_root */);
support->SetUpHitTest(nullptr /* local_surface_id_lookup_delegate */);
EXPECT_TRUE(DisplayHitTestQueryExists(kFrameSinkChild1));
EXPECT_TRUE(support->GetHitTestAggregator());
host().InvalidateFrameSinkId(kFrameSinkChild1);
support.reset();
EXPECT_FALSE(FrameSinkDataExists(kFrameSinkChild1));
EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkChild1));
}
TEST_F(HostFrameSinkManagerRemoteTest, FindRootFrameSinkId) {
FakeHostFrameSinkClient host_client;
EXPECT_FALSE(host().FindRootFrameSinkId(kFrameSinkParent1));
EXPECT_FALSE(host().FindRootFrameSinkId(kFrameSinkChild1));
// Register two FrameSinkIds, hierarchy between them and create a
// CompositorFrameSink for one.
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
ReportFirstSurfaceActivation::kYes);
host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
EXPECT_FALSE(host().FindRootFrameSinkId(kFrameSinkParent1));
EXPECT_FALSE(host().FindRootFrameSinkId(kFrameSinkChild1));
RootCompositorFrameSinkData root_data;
host().CreateRootCompositorFrameSink(
root_data.BuildParams(kFrameSinkParent1));
MockCompositorFrameSinkClient compositor_frame_sink_client;
mojom::CompositorFrameSinkPtr compositor_frame_sink;
host().CreateCompositorFrameSink(
kFrameSinkChild1, MakeRequest(&compositor_frame_sink),
compositor_frame_sink_client.BindInterfacePtr());
EXPECT_EQ(base::Optional<FrameSinkId>(kFrameSinkParent1),
host().FindRootFrameSinkId(kFrameSinkParent1));
EXPECT_EQ(base::Optional<FrameSinkId>(kFrameSinkParent1),
host().FindRootFrameSinkId(kFrameSinkChild1));
}
// Verify that HostFrameSinkManager can handle restarting after a GPU crash.
TEST_F(HostFrameSinkManagerRemoteTest, RestartOnGpuCrash) {
FakeHostFrameSinkClient host_client;
// Register two FrameSinkIds, hierarchy between them and create a
// CompositorFrameSink for one.
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
ReportFirstSurfaceActivation::kYes);
host().RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1);
RootCompositorFrameSinkData root_data;
host().CreateRootCompositorFrameSink(
root_data.BuildParams(kFrameSinkParent1));
MockCompositorFrameSinkClient compositor_frame_sink_client;
mojom::CompositorFrameSinkPtr compositor_frame_sink;
host().CreateCompositorFrameSink(
kFrameSinkChild1, MakeRequest(&compositor_frame_sink),
compositor_frame_sink_client.BindInterfacePtr());
EXPECT_TRUE(IsBoundToFrameSinkManager());
// Verify registration and CompositorFrameSink creation happened.
{
base::RunLoop run_loop;
EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkParent1,
true /* report_activation */));
EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
true /* report_activation */));
EXPECT_CALL(impl(), RegisterFrameSinkHierarchy(kFrameSinkParent1,
kFrameSinkChild1));
EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
EXPECT_CALL(impl(), MockCreateCompositorFrameSink(kFrameSinkChild1))
.WillOnce(InvokeClosure(run_loop.QuitClosure()));
run_loop.Run();
}
// Kill the GPU. HostFrameSinkManager will have a connection error on the
// message pipe and should clear state appropriately.
KillGpu();
{
base::RunLoop run_loop;
host().SetConnectionLostCallback(run_loop.QuitClosure());
run_loop.Run();
}
EXPECT_FALSE(IsBoundToFrameSinkManager());
// Verify that when HostFrameSinkManager is connected to the GPU again it
// reregisters FrameSinkIds and FrameSink hierarchy.
ConnectToGpu();
{
base::RunLoop run_loop;
EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkParent1,
true /* report_activation */));
EXPECT_CALL(impl(), RegisterFrameSinkId(kFrameSinkChild1,
true /* report_activation */));
EXPECT_CALL(impl(),
RegisterFrameSinkHierarchy(kFrameSinkParent1, kFrameSinkChild1))
.WillOnce(InvokeClosure(run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_TRUE(IsBoundToFrameSinkManager());
}
// Verify that HostFrameSinkManager does early return when trying to send
// hit-test data after HitTestQuery was deleted.
TEST_F(HostFrameSinkManagerRemoteTest, DeletedHitTestQuery) {
FakeHostFrameSinkClient host_client;
// Register a FrameSinkId, and create a RootCompositorFrameSink, which should
// create a HitTestQuery.
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
RootCompositorFrameSinkData root_data;
host().CreateRootCompositorFrameSink(
root_data.BuildParams(kFrameSinkParent1));
EXPECT_TRUE(DisplayHitTestQueryExists(kFrameSinkParent1));
// Verify RootCompositorFrameSink was created on other end of message pipe.
{
base::RunLoop run_loop;
EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1))
.WillOnce(InvokeClosure(run_loop.QuitClosure()));
run_loop.Run();
}
GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
kFrameSinkParent1, {});
// Continue to send hit-test data to HitTestQuery associated with
// kFrameSinkChild1.
host().InvalidateFrameSinkId(kFrameSinkParent1);
// Invalidating kFrameSinkChild1 would delete the corresponding HitTestQuery,
// so further msgs to that HitTestQuery should be dropped.
EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkParent1));
GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
kFrameSinkParent1, {});
}
// Verify that on lost context a RootCompositorFrameSink can be recreated.
TEST_F(HostFrameSinkManagerRemoteTest, ContextLossRecreateRoot) {
FakeHostFrameSinkClient host_client;
// Register a FrameSinkId, and create a RootCompositorFrameSink.
host().RegisterFrameSinkId(kFrameSinkParent1, &host_client,
ReportFirstSurfaceActivation::kYes);
RootCompositorFrameSinkData root_data1;
host().CreateRootCompositorFrameSink(
root_data1.BuildParams(kFrameSinkParent1));
// Verify RootCompositorFrameSink was created on other end of message pipe.
EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
root_data1.compositor_frame_sink.FlushForTesting();
testing::Mock::VerifyAndClearExpectations(&impl());
// Create a new RootCompositorFrameSink and try to connect it with the same
// FrameSinkId. This will happen if the browser GL context is lost.
RootCompositorFrameSinkData root_data2;
host().CreateRootCompositorFrameSink(
root_data2.BuildParams(kFrameSinkParent1));
// Verify RootCompositorFrameSink is destroyed and then recreated.
EXPECT_CALL(impl(), MockDestroyCompositorFrameSink(kFrameSinkParent1));
EXPECT_CALL(impl(), MockCreateRootCompositorFrameSink(kFrameSinkParent1));
root_data2.compositor_frame_sink.FlushForTesting();
}
// Verify that on lost context a CompositorFrameSink can be recreated.
TEST_F(HostFrameSinkManagerRemoteTest, ContextLossRecreateNonRoot) {
FakeHostFrameSinkClient host_client;
// Register a FrameSinkId and create a CompositorFrameSink.
host().RegisterFrameSinkId(kFrameSinkChild1, &host_client,
ReportFirstSurfaceActivation::kYes);
MockCompositorFrameSinkClient compositor_frame_sink_client1;
mojom::CompositorFrameSinkPtr compositor_frame_sink1;
host().CreateCompositorFrameSink(
kFrameSinkChild1, MakeRequest(&compositor_frame_sink1),
compositor_frame_sink_client1.BindInterfacePtr());
// Verify CompositorFrameSink was created on other end of message pipe.
EXPECT_CALL(impl(), MockCreateCompositorFrameSink(kFrameSinkChild1));
compositor_frame_sink1.FlushForTesting();
testing::Mock::VerifyAndClearExpectations(&impl());
// Create a new CompositorFrameSink and try to connect it with the same
// FrameSinkId. This will happen if the client GL context is lost.
MockCompositorFrameSinkClient compositor_frame_sink_client2;
mojom::CompositorFrameSinkPtr compositor_frame_sink2;
host().CreateCompositorFrameSink(
kFrameSinkChild1, MakeRequest(&compositor_frame_sink2),
compositor_frame_sink_client2.BindInterfacePtr());
// Verify CompositorFrameSink is destroyed and then recreated.
EXPECT_CALL(impl(), MockDestroyCompositorFrameSink(kFrameSinkChild1));
EXPECT_CALL(impl(), MockCreateCompositorFrameSink(kFrameSinkChild1));
compositor_frame_sink2.FlushForTesting();
}
} // namespace viz