#include <stddef.h>
#include <tuple>
#include "base/containers/contains.h"
#include "base/run_loop.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_trace_processor.h"
#include "components/input/features.h"
#include "components/viz/common/constants.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.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/input/mock_input_manager.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
#include "components/viz/test/begin_frame_source_test.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_external_begin_frame_source.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 "components/viz/test/test_output_surface_provider.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/perfetto/include/perfetto/tracing/tracing.h"
namespace viz {
namespace {
constexpr FrameSinkId kFrameSinkIdRoot(1, 1);
constexpr FrameSinkId kFrameSinkIdA(2, 1);
constexpr FrameSinkId kFrameSinkIdB(3, 1);
constexpr FrameSinkId kFrameSinkIdC(4, 1);
constexpr FrameSinkId kFrameSinkIdD(5, 1);
constexpr FrameSinkId kFrameSinkIdE(6, 1);
constexpr FrameSinkId kFrameSinkIdF(7, 1);
struct RootCompositorFrameSinkData { … };
}
class FrameSinkManagerTest : public testing::Test { … };
TEST_F(FrameSinkManagerTest, CreateRootCompositorFrameSink) { … }
TEST_F(FrameSinkManagerTest, InputManagerCreation) { … }
TEST_F(FrameSinkManagerTest, CreateCompositorFrameSink) { … }
TEST_F(FrameSinkManagerTest, CompositorFrameSinkConnectionLost) { … }
TEST_F(FrameSinkManagerTest, SingleClients) { … }
TEST_F(FrameSinkManagerTest, ClientRestart) { … }
TEST_F(FrameSinkManagerTest, MultipleDisplays) { … }
TEST_F(FrameSinkManagerTest, ParentWithoutClientRetained) { … }
TEST_F(FrameSinkManagerTest,
ParentWithoutClientRetained_LateBeginFrameRegistration) { … }
TEST_F(FrameSinkManagerTest, EvictSurfaces) { … }
TEST_F(FrameSinkManagerTest, DebugLabel) { … }
TEST_F(FrameSinkManagerTest, Throttle) { … }
TEST_F(FrameSinkManagerTest, GlobalThrottle) { … }
TEST_F(FrameSinkManagerTest, NoThrottleOnFrameSinksBeingCaptured) { … }
TEST_F(FrameSinkManagerTest, ThrottleUponHierarchyChange) { … }
TEST_F(FrameSinkManagerTest, EvictRootSurfaceId) { … }
TEST_F(FrameSinkManagerTest, EvictNewerRootSurfaceId) { … }
TEST_F(FrameSinkManagerTest, SubmitCompositorFrameWithEvictedSurfaceId) { … }
TEST_F(FrameSinkManagerTest,
CopyOutputRequestPreservedAfterDiscardPendingCopyOfOutputRequests) { … }
TEST_F(FrameSinkManagerTest, ExactCopyOutputRequestTakenBySurfaceRightAway) { … }
TEST_F(FrameSinkManagerTest,
ExactCopyOutputRequestQueuedInCompositorFrameSinkSupport) { … }
#if BUILDFLAG(IS_ANDROID)
class AndroidFrameSinkManagerTest : public FrameSinkManagerTest,
public ::testing::WithParamInterface<bool> {
public:
AndroidFrameSinkManagerTest() {
scoped_feature_list_.InitWithFeatureState(input::features::kInputOnViz,
GetParam());
}
bool ExpectedInputManagerCreation() { return input::TransferInputToViz(); }
private:
base::test::TracingEnvironment tracing_environment_;
};
TEST_P(AndroidFrameSinkManagerTest, InputManagerCreation) {
EXPECT_EQ(InputManagerExists(), ExpectedInputManagerCreation());
}
TEST_P(AndroidFrameSinkManagerTest, RenderInputRouterLifecycle) {
EXPECT_EQ(InputManagerExists(), ExpectedInputManagerCreation());
base::test::TestTraceProcessor ttp;
ttp.StartTrace("viz");
manager_.RegisterFrameSinkId(kFrameSinkIdA, true );
MockCompositorFrameSinkClient compositor_frame_sink_client;
mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink;
mojo::PendingRemote<blink::mojom::RenderInputRouterClient> rir_client;
auto config = input::mojom::RenderInputRouterConfig::New();
config->rir_client = std::move(rir_client);
manager_.CreateCompositorFrameSink(
kFrameSinkIdA, std::nullopt,
compositor_frame_sink.BindNewPipeAndPassReceiver(),
compositor_frame_sink_client.BindInterfaceRemote(), std::move(config));
EXPECT_TRUE(CompositorFrameSinkExists(kFrameSinkIdA));
if (InputManagerExists()) {
EXPECT_TRUE(GetMockInputManager()->RIRExistsForFrameSinkId(kFrameSinkIdA));
}
manager_.InvalidateFrameSinkId(kFrameSinkIdA);
EXPECT_FALSE(CompositorFrameSinkExists(kFrameSinkIdA));
if (InputManagerExists()) {
EXPECT_FALSE(GetMockInputManager()->RIRExistsForFrameSinkId(kFrameSinkIdA));
}
absl::Status status = ttp.StopAndParseTrace();
EXPECT_TRUE(status.ok()) << status.message();
std::string query = R"(
SELECT COUNT(*) AS cnt,
EXTRACT_ARG(arg_set_id, 'debug.config_is_null') as config_is_null,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_client_id')
as client_id,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_id') as sink_id
FROM slice
WHERE slice.name = 'InputManager::OnCreateCompositorFrameSink'
)";
auto result = ttp.RunQuery(query);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(result.value().size(), 2u);
EXPECT_EQ(result.value()[1].size(), 4u);
if (input::TransferInputToViz()) {
EXPECT_THAT(
result.value(),
testing::ElementsAre(
testing::ElementsAre("cnt", "config_is_null", "client_id",
"sink_id"),
testing::ElementsAre(
"1", "0", base::NumberToString(kFrameSinkIdA.client_id()),
base::NumberToString(kFrameSinkIdA.sink_id()))));
} else {
EXPECT_EQ(result.value()[1][0], "0");
}
std::string query2 = R"(
SELECT COUNT(*) AS cnt,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_client_id')
as client_id,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_id') as sink_id
FROM slice
WHERE slice.name = 'InputManager::OnDestroyedCompositorFrameSink'
)";
auto result2 = ttp.RunQuery(query2);
EXPECT_TRUE(result2.has_value());
if (input::TransferInputToViz()) {
EXPECT_THAT(result2.value(),
testing::ElementsAre(
testing::ElementsAre("cnt", "client_id", "sink_id"),
testing::ElementsAre(
"1", base::NumberToString(kFrameSinkIdA.client_id()),
base::NumberToString(kFrameSinkIdA.sink_id()))));
} else {
EXPECT_EQ(result2.value()[1][0], "0");
}
}
TEST_P(AndroidFrameSinkManagerTest,
RenderInputRouterLifecycleNonLayerFrameSink) {
EXPECT_EQ(InputManagerExists(), ExpectedInputManagerCreation());
base::test::TestTraceProcessor ttp;
ttp.StartTrace("viz");
MockCompositorFrameSinkClient compositor_frame_sink_client;
mojo::Remote<mojom::CompositorFrameSink> compositor_frame_sink;
manager_.RegisterFrameSinkId(kFrameSinkIdB, true );
manager_.CreateCompositorFrameSink(
kFrameSinkIdB, std::nullopt,
compositor_frame_sink.BindNewPipeAndPassReceiver(),
compositor_frame_sink_client.BindInterfaceRemote(),
nullptr);
EXPECT_TRUE(CompositorFrameSinkExists(kFrameSinkIdB));
if (InputManagerExists()) {
EXPECT_FALSE(GetMockInputManager()->RIRExistsForFrameSinkId(kFrameSinkIdB));
}
manager_.InvalidateFrameSinkId(kFrameSinkIdB);
EXPECT_FALSE(CompositorFrameSinkExists(kFrameSinkIdB));
if (InputManagerExists()) {
EXPECT_FALSE(GetMockInputManager()->RIRExistsForFrameSinkId(kFrameSinkIdB));
}
absl::Status status = ttp.StopAndParseTrace();
EXPECT_TRUE(status.ok()) << status.message();
std::string query = R"(
SELECT COUNT(*) AS cnt,
EXTRACT_ARG(arg_set_id, 'debug.config_is_null') as config_is_null,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_client_id')
as client_id,
EXTRACT_ARG(arg_set_id, 'debug.frame_sink_id.frame_sink_id') as sink_id
FROM slice
WHERE slice.name = 'InputManager::OnCreateCompositorFrameSink'
)";
auto result = ttp.RunQuery(query);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(result.value().size(), 2u);
EXPECT_EQ(result.value()[1].size(), 4u);
if (input::TransferInputToViz()) {
EXPECT_THAT(
result.value(),
testing::ElementsAre(
testing::ElementsAre("cnt", "config_is_null", "client_id",
"sink_id"),
testing::ElementsAre(
"1", "1", base::NumberToString(kFrameSinkIdB.client_id()),
base::NumberToString(kFrameSinkIdB.sink_id()))));
} else {
EXPECT_EQ(result.value()[1][0], "0");
}
}
INSTANTIATE_TEST_SUITE_P(All,
AndroidFrameSinkManagerTest,
::testing::Bool(),
[](auto& info) {
return info.param ? "InputOnViz_Enabled"
: "InputOnViz_Disabled";
});
#endif
namespace {
enum RegisterOrder { … };
enum UnregisterOrder { … };
enum BFSOrder { … };
static const RegisterOrder kRegisterOrderList[] = …;
static const UnregisterOrder kUnregisterOrderList[] = …;
static const BFSOrder kBFSOrderList[] = …;
}
class FrameSinkManagerOrderingTest : public FrameSinkManagerTest { … };
class FrameSinkManagerOrderingParamTest
: public FrameSinkManagerOrderingTest,
public ::testing::WithParamInterface<
std::tuple<RegisterOrder, UnregisterOrder, BFSOrder>> { … };
TEST_P(FrameSinkManagerOrderingParamTest, Ordering) { … }
INSTANTIATE_TEST_SUITE_P(…);
}