blob: 209ffaf3eba7268f36d7eda2a15ceff98e212cff [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/display/mirror_window_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/shell.h"
#include "cc/trees/layer_tree_host.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/page_transition_types.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/layer.h"
#include "ui/display/display_observer.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
#include "ui/display/test/display_manager_test_api.h"
namespace {
void SimulateGpuCrash() {
const cc::LayerTreeHost* host = ash::Shell::GetPrimaryRootWindow()
->layer()
->GetCompositor()
->host_for_testing();
const_cast<cc::LayerTreeHost*>(host)->CrashGpuProcessForTesting();
}
display::DisplayManager* GetDisplayManager() {
return ash::Shell::Get()->display_manager();
}
using DisplayGpuCrashBrowserTest = InProcessBrowserTest;
class TestDisplayObserver : public display::DisplayObserver {
public:
explicit TestDisplayObserver(base::OnceClosure quit_closure)
: quit_closure_(std::move(quit_closure)) {
display::Screen::Get()->AddObserver(this);
}
TestDisplayObserver(const TestDisplayObserver&) = delete;
const TestDisplayObserver& operator=(const TestDisplayObserver&) = delete;
~TestDisplayObserver() override {
display::Screen::Get()->RemoveObserver(this);
}
// display::DisplayObserver:
void OnDisplaysRemoved(const display::Displays& removed_displays) override {
std::move(quit_closure_).Run();
}
private:
base::OnceClosure quit_closure_;
};
class TestSurfaceIdObserver : public ui::CompositorObserver {
public:
TestSurfaceIdObserver(ui::Compositor* compositor,
base::OnceClosure quit_closure)
: compositor_(compositor), quit_closure_(std::move(quit_closure)) {
compositor_->AddObserver(this);
}
TestSurfaceIdObserver(const TestSurfaceIdObserver&) = delete;
const TestSurfaceIdObserver& operator=(const TestSurfaceIdObserver&) = delete;
~TestSurfaceIdObserver() override { compositor_->RemoveObserver(this); }
void OnFirstSurfaceActivation(ui::Compositor* compositor,
const viz::SurfaceInfo& surface_info) override {
std::move(quit_closure_).Run();
}
private:
raw_ptr<ui::Compositor> compositor_;
base::OnceClosure quit_closure_;
};
} // namespace
// TODO(crbug.com/388451843): Flaky on ChromeOS release.
IN_PROC_BROWSER_TEST_F(DisplayGpuCrashBrowserTest, DISABLED_CrashInMirror) {
display::test::DisplayManagerTestApi test_api(GetDisplayManager());
test_api.UpdateDisplay("1300x1000,1000x800");
ASSERT_EQ(2u, GetDisplayManager()->GetNumDisplays());
int64_t secondary_id = test_api.GetSecondaryDisplay().id();
{
base::RunLoop loop;
TestDisplayObserver observer(loop.QuitClosure());
GetDisplayManager()->SetMirrorMode(display::MirrorMode::kNormal,
std::nullopt);
loop.Run();
}
{
auto* primary_root = ash::Shell::GetPrimaryRootWindow();
auto local_surface_id = primary_root->GetLocalSurfaceId();
base::RunLoop loop;
TestSurfaceIdObserver surface_id_observer(
primary_root->GetHost()->compositor(), loop.QuitClosure());
SimulateGpuCrash();
loop.Run();
EXPECT_NE(local_surface_id, primary_root->GetLocalSurfaceId());
ash::MirrorWindowController* mirror = ash::Shell::Get()
->window_tree_host_manager()
->mirror_window_controller();
ASSERT_EQ(mirror->GetAllRootWindows().size(), 1u);
const aura::Window* mirror_window =
mirror->GetMirrorWindowForDisplayIdForTest(secondary_id);
EXPECT_TRUE(mirror_window->layer()->has_external_content());
EXPECT_EQ(primary_root->GetSurfaceId(),
mirror_window->layer()->external_content_surface_id());
}
}
// TODO(crbug.com/368538284): Debug build prints too many error messages while
// waiting for GPU restart, which causes test failure on bots.
IN_PROC_BROWSER_TEST_F(DisplayGpuCrashBrowserTest, CrashInUnified) {
auto* display_manager = GetDisplayManager();
display_manager->SetUnifiedDesktopEnabled(true);
display::test::DisplayManagerTestApi test_api(display_manager);
test_api.UpdateDisplay("1300x1000,1000x800");
const auto mirroring_displays =
display_manager->software_mirroring_display_list();
ASSERT_EQ(1u, display_manager->GetNumDisplays());
ASSERT_EQ(2u, mirroring_displays.size());
auto* primary_root = ash::Shell::GetPrimaryRootWindow();
auto local_surface_id = primary_root->GetLocalSurfaceId();
base::RunLoop loop;
TestSurfaceIdObserver surface_id_observer(
primary_root->GetHost()->compositor(), loop.QuitClosure());
SimulateGpuCrash();
loop.Run();
EXPECT_NE(local_surface_id, primary_root->GetLocalSurfaceId());
auto* mirror_window_controller =
ash::Shell::Get()->window_tree_host_manager()->mirror_window_controller();
ASSERT_EQ(mirror_window_controller->GetAllRootWindows().size(), 2u);
for (auto display : mirroring_displays) {
SCOPED_TRACE("mirroring_display=" + display.ToString());
const aura::Window* mirror_window =
mirror_window_controller->GetMirrorWindowForDisplayIdForTest(
display.id());
EXPECT_TRUE(mirror_window->layer()->has_external_content());
EXPECT_EQ(primary_root->GetSurfaceId(),
mirror_window->layer()->external_content_surface_id());
}
}