// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <drm_fourcc.h>
#include <stddef.h>
#include <stdint.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <memory>
#include <utility>
#include "base/containers/contains.h"
#include "build/chromeos_buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/types/display_constants.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/linux/gbm_buffer.h"
#include "ui/gfx/linux/test/mock_gbm_device.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
#include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
#include "ui/ozone/platform/drm/gpu/drm_window.h"
#include "ui/ozone/platform/drm/gpu/fake_drm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
#include "ui/ozone/platform/drm/gpu/screen_manager.h"
namespace ui {
namespace {
using ::testing::Eq;
using ::testing::Matcher;
using ::testing::Pointee;
using ::testing::Property;
using ::testing::UnorderedElementsAre;
constexpr drmModeModeInfo ConstructMode(uint16_t hdisplay, uint16_t vdisplay) {
return {.hdisplay = hdisplay, .vdisplay = vdisplay};
}
// Create a basic mode for a 6x4 screen.
const drmModeModeInfo kDefaultMode = ConstructMode(6, 4);
const uint32_t kPrimaryDisplayId = 1;
const uint32_t kSecondaryDisplayId = 2;
Matcher<const CrtcController&> EqualsCrtcConnectorIds(uint32_t crtc,
uint32_t connector) {
return AllOf(Property(&CrtcController::crtc, Eq(crtc)),
Property(&CrtcController::connector, Eq(connector)));
}
} // namespace
class ScreenManagerTest : public testing::Test {
public:
struct PlaneState {
std::vector<uint32_t> formats;
};
struct CrtcState {
std::vector<PlaneState> planes;
};
ScreenManagerTest() = default;
ScreenManagerTest(const ScreenManagerTest&) = delete;
ScreenManagerTest& operator=(const ScreenManagerTest&) = delete;
~ScreenManagerTest() override = default;
gfx::Rect GetPrimaryBounds() const {
return gfx::Rect(0, 0, kDefaultMode.hdisplay, kDefaultMode.vdisplay);
}
// Secondary is in extended mode, right-of primary.
gfx::Rect GetSecondaryBounds() const {
return gfx::Rect(kDefaultMode.hdisplay, 0, kDefaultMode.hdisplay,
kDefaultMode.vdisplay);
}
void InitializeDrmState(FakeDrmDevice* drm,
const std::vector<CrtcState>& crtc_states,
bool is_atomic,
bool use_modifiers_list = false,
const std::vector<PlaneState>& movable_planes = {}) {
size_t plane_count = crtc_states[0].planes.size();
for (const auto& crtc_state : crtc_states) {
ASSERT_EQ(plane_count, crtc_state.planes.size())
<< "FakeDrmDevice::CreateStateWithAllProperties currently expects "
"the same number of planes per CRTC";
}
std::vector<drm_format_modifier> drm_format_modifiers;
if (use_modifiers_list) {
for (const auto modifier : supported_modifiers_) {
drm_format_modifiers.push_back(
{.formats = 1, .offset = 0, .pad = 0, .modifier = modifier});
}
}
drm->ResetStateWithAllProperties();
std::vector<uint32_t> crtc_ids;
for (const auto& crtc_state : crtc_states) {
uint32_t crtc_id = drm->AddCrtcAndConnector().first.id;
crtc_ids.push_back(crtc_id);
for (size_t i = 0; i < crtc_state.planes.size(); ++i) {
auto in_formats_blob = drm->CreateInFormatsBlob(
crtc_state.planes[i].formats, drm_format_modifiers);
auto& plane = drm->AddPlane(
crtc_id, i == 0 ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY);
drm->AddProperty(
plane.id, {.id = kInFormatsPropId, .value = in_formats_blob->id()});
}
}
for (const auto& movable_plane : movable_planes) {
auto in_formats_blob =
drm->CreateInFormatsBlob(movable_plane.formats, drm_format_modifiers);
auto& plane = drm->AddPlane(crtc_ids, DRM_PLANE_TYPE_OVERLAY);
drm->AddProperty(
plane.id, {.id = kInFormatsPropId, .value = in_formats_blob->id()});
}
drm->SetModifiersOverhead(modifiers_overhead_);
drm->InitializeState(is_atomic);
}
void AddPlaneToCrtc(uint32_t crtc_id, uint32_t plane_type) {
auto in_formats_blob = drm_->CreateInFormatsBlob({DRM_FORMAT_XRGB8888}, {});
auto& plane = drm_->AddPlane(crtc_id, plane_type);
drm_->AddProperty(plane.id,
{.id = kInFormatsPropId, .value = in_formats_blob->id()});
}
void InitializeDrmStateWithDefault(FakeDrmDevice* drm,
bool is_atomic,
bool use_modifiers_list = false) {
// A Sample of CRTC states.
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm, crtc_states, is_atomic, use_modifiers_list);
}
void SetUp() override {
auto gbm = std::make_unique<MockGbmDevice>();
supported_modifiers_ = gbm->GetSupportedModifiers();
drm_ = new FakeDrmDevice(std::move(gbm));
drm2_ = new FakeDrmDevice(std::make_unique<MockGbmDevice>());
device_manager_ = std::make_unique<DrmDeviceManager>(nullptr);
screen_manager_ = std::make_unique<ScreenManager>();
}
void TearDown() override {
screen_manager_.reset();
drm_->ResetPlaneManagerForTesting();
drm2_->ResetPlaneManagerForTesting();
drm_ = nullptr;
drm2_ = nullptr;
}
scoped_refptr<DrmFramebuffer> CreateBuffer(uint32_t format,
const gfx::Size& size) {
return CreateBufferWithModifier(format, DRM_FORMAT_MOD_NONE, size);
}
scoped_refptr<DrmFramebuffer> CreateBufferWithModifier(
uint32_t format,
uint64_t format_modifier,
const gfx::Size& size) {
std::vector<uint64_t> modifiers;
if (format_modifier != DRM_FORMAT_MOD_NONE)
modifiers.push_back(format_modifier);
auto buffer = drm_->gbm_device()->CreateBufferWithModifiers(
format, size, GBM_BO_USE_SCANOUT, modifiers);
return DrmFramebuffer::AddFramebuffer(drm_, buffer.get(), size, modifiers);
}
protected:
scoped_refptr<FakeDrmDevice> drm_;
scoped_refptr<FakeDrmDevice> drm2_;
std::unique_ptr<DrmDeviceManager> device_manager_;
std::unique_ptr<ScreenManager> screen_manager_;
std::vector<uint64_t> supported_modifiers_;
base::flat_map<uint64_t /*modifier*/, int /*overhead*/> modifiers_overhead_{
{DRM_FORMAT_MOD_LINEAR, 1},
{I915_FORMAT_MOD_Yf_TILED_CCS, 100}};
};
TEST_F(ScreenManagerTest, CheckWithNoControllers) {
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_EQ(drm_->get_test_modeset_count(), 0);
EXPECT_EQ(drm_->get_commit_modeset_count(), 0);
EXPECT_EQ(drm_->get_commit_count(), 0);
}
TEST_F(ScreenManagerTest, CheckWithValidController) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(controller);
EXPECT_TRUE(controller->HasCrtc(drm_, crtc_id));
}
TEST_F(ScreenManagerTest, CheckWithSeamlessModeset) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kCommitModeset,
display::ModesetFlag::kSeamlessModeset});
EXPECT_EQ(drm_->get_commit_modeset_count(), 0);
EXPECT_EQ(drm_->get_seamless_modeset_count(), 1);
}
TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckForSecondValidController) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckMultipleDisplaysWithinModifiersLimit) {
int max_supported_displays_with_modifier = 2;
drm_->SetSystemLimitOfModifiers(
modifiers_overhead_[I915_FORMAT_MOD_Yf_TILED_CCS] *
max_supported_displays_with_modifier);
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
/*use_modifiers_list=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
}
TEST_F(ScreenManagerTest, CheckMultipleDisplaysOutsideModifiersLimit) {
int max_supported_displays_with_modifier = 2;
drm_->SetSystemLimitOfModifiers(modifiers_overhead_[DRM_FORMAT_MOD_LINEAR] *
max_supported_displays_with_modifier);
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
/*use_modifiers_list=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
// Testing for a failed test-modeset with modifiers + a fallback to Linear
// Modifier and a modeset commit.
EXPECT_EQ(drm_->get_test_modeset_count(), 2);
EXPECT_EQ(drm_->get_commit_modeset_count(), 1);
}
TEST_F(ScreenManagerTest, CheckDisplaysWith0Limit) {
drm_->SetSystemLimitOfModifiers(0);
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true,
/*use_modifiers_list=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
EXPECT_FALSE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
// Testing for a failed test-modeset with modifiers + failed test-modeset with
// Linear Modifier and no modeset due to failed tests.
EXPECT_EQ(drm_->get_test_modeset_count(), 2);
EXPECT_EQ(drm_->get_commit_modeset_count(), 0);
}
TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
ScreenManager::CrtcsWithDrmList controllers_to_remove;
controllers_to_remove.emplace_back(crtc_id, drm_);
screen_manager_->RemoveDisplayControllers(controllers_to_remove);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
}
TEST_F(ScreenManagerTest, CheckControllerAfterDisabled) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
// Enable
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
int test_modeset_count_before_disable = drm_->get_test_modeset_count();
int commit_modeset_count_before_disable = drm_->get_commit_modeset_count();
// Disable
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_, crtc_id,
connector_id, gfx::Point(), nullptr);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(drm_->get_test_modeset_count(),
test_modeset_count_before_disable + 1);
EXPECT_EQ(drm_->get_commit_modeset_count(),
commit_modeset_count_before_disable + 1);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingRemoved) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
int modeset_count_after_enable = drm_->get_commit_modeset_count();
ScreenManager::CrtcsWithDrmList controllers_to_remove;
controllers_to_remove.emplace_back(primary_crtc_id, drm_);
controllers_to_remove.emplace_back(secondary_crtc_id, drm_);
screen_manager_->RemoveDisplayControllers(controllers_to_remove);
// Removed displays are disabled in only 1 modeset commit.
EXPECT_EQ(drm_->get_commit_modeset_count(), modeset_count_after_enable + 1);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckMultipleControllersAfterBeingDisabled) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
// Enable
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
int test_modeset_count_before_disable = drm_->get_test_modeset_count();
int commit_modeset_count_before_disable = drm_->get_commit_modeset_count();
// Disable
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_, primary_crtc_id,
primary_connector_id, gfx::Point(),
nullptr);
controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_,
secondary_crtc_id, secondary_connector_id,
gfx::Point(), nullptr);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(drm_->get_test_modeset_count(),
test_modeset_count_before_disable + 1);
EXPECT_EQ(drm_->get_commit_modeset_count(),
commit_modeset_count_before_disable + 1);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic*/ false);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
uint32_t framebuffer = drm_->current_framebuffer();
controllers_to_enable.clear();
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// Should not hold onto buffers.
EXPECT_NE(framebuffer, drm_->current_framebuffer());
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckChangingMode) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
// Modeset with default mode.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
auto new_mode = kDefaultMode;
new_mode.vdisplay = new_mode.vdisplay++;
// Modeset with a changed Mode.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(new_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
gfx::Rect new_bounds(0, 0, new_mode.hdisplay, new_mode.vdisplay);
EXPECT_TRUE(screen_manager_->GetDisplayController(new_bounds));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
drmModeModeInfo mode = screen_manager_->GetDisplayController(new_bounds)
->crtc_controllers()[0]
->mode();
EXPECT_EQ(new_mode.vdisplay, mode.vdisplay);
EXPECT_EQ(new_mode.hdisplay, mode.hdisplay);
}
TEST_F(ScreenManagerTest, CheckChangingVrrState) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
// Modeset with default VRR state.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode), /*enable_vrr=*/false);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
const HardwareDisplayController* hdc =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_EQ(0U, hdc->crtc_controllers()[0]->vrr_enabled());
}
// Modeset with a changed VRR state.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode), /*enable_vrr=*/true);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
const HardwareDisplayController* hdc =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_EQ(1U, hdc->crtc_controllers()[0]->vrr_enabled());
}
}
TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12}}}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
controllers_to_enable.clear();
drmModeModeInfo transition1_primary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(transition1_primary_mode));
drmModeModeInfo transition1_secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(transition1_secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
controllers_to_enable.clear();
drmModeModeInfo transition2_primary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(transition2_primary_mode));
drmModeModeInfo transition2_secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(transition2_secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
}
// Make sure we're using each display's mode when doing mirror mode otherwise
// the timings may be off.
TEST_F(ScreenManagerTest, CheckMirrorModeModesettingWithDisplaysMode) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
// Copy the mode and use the copy so we can tell what mode the CRTC was
// configured with. The clock value is modified so we can tell which mode is
// being used.
drmModeModeInfo secondary_mode = kDefaultMode;
secondary_mode.clock++;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
for (const auto& crtc : controller->crtc_controllers()) {
if (crtc->crtc() == primary_crtc_id)
EXPECT_EQ(kDefaultMode.clock, crtc->mode().clock);
else if (crtc->crtc() == secondary_crtc_id)
EXPECT_EQ(secondary_mode.clock, crtc->mode().clock);
else
NOTREACHED_IN_MIGRATION();
}
}
TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
ScreenManager::CrtcsWithDrmList controllers_to_remove;
controllers_to_remove.emplace_back(secondary_crtc_id, drm_);
screen_manager_->RemoveDisplayControllers(controllers_to_remove);
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(controller);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
EXPECT_TRUE(controller->HasCrtc(drm_, primary_crtc_id));
EXPECT_FALSE(controller->HasCrtc(drm_, secondary_crtc_id));
}
TEST_F(ScreenManagerTest, MonitorDisabledInMirrorMode) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
// Enable in Mirror Mode.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
// Disable display Controller.
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(0, drm_, secondary_crtc_id, 0,
gfx::Point(), nullptr);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(controller);
EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
EXPECT_TRUE(controller->HasCrtc(drm_, primary_crtc_id));
EXPECT_FALSE(controller->HasCrtc(drm_, secondary_crtc_id));
}
TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
// Configure displays in extended mode.
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
{
auto new_mode = std::make_unique<drmModeModeInfo>(kDefaultMode);
new_mode->vdisplay = 10;
// Shouldn't enter mirror mode unless the display bounds are the same.
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(), std::move(new_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
EXPECT_FALSE(
screen_manager_->GetDisplayController(GetPrimaryBounds())->IsMirrored());
}
TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
uint32_t framebuffer = drm_->current_framebuffer();
controllers_to_enable.clear();
// Disable display controller.
controllers_to_enable.emplace_back(0, drm_, crtc_id, 0, gfx::Point(),
nullptr);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(0u, drm_->current_framebuffer());
controllers_to_enable.clear();
drmModeModeInfo reenable_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(reenable_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// Buffers are released when disabled.
EXPECT_NE(framebuffer, drm_->current_framebuffer());
}
TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t primary_crtc_id = drm_->crtc_property(0).id;
uint32_t primary_connector_id = drm_->connector_property(0).id;
uint32_t secondary_crtc_id = drm_->crtc_property(1).id;
uint32_t secondary_connector_id = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, primary_crtc_id,
primary_connector_id);
screen_manager_->AddDisplayController(drm_, secondary_crtc_id,
secondary_connector_id);
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, secondary_crtc_id, secondary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(0, drm_, primary_crtc_id, 0,
gfx::Point(), nullptr);
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(controller);
EXPECT_FALSE(controller->IsMirrored());
{
std::vector<ControllerConfigParams> controllers_to_enable;
drmModeModeInfo reenable_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, primary_crtc_id, primary_connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(reenable_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
EXPECT_TRUE(controller);
EXPECT_TRUE(controller->IsMirrored());
}
TEST_F(ScreenManagerTest, ConfigureOnDifferentDrmDevices) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm2_.get(), crtc_states, /*is_atomic=*/false);
uint32_t drm_1_crtc_1 = drm_->crtc_property(0).id;
uint32_t drm_1_connector_1 = drm_->connector_property(0).id;
uint32_t drm_2_crtc_1 = drm2_->crtc_property(0).id;
uint32_t drm_2_connector_1 = drm2_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, drm_1_crtc_1, drm_1_connector_1);
screen_manager_->AddDisplayController(drm2_, drm_2_crtc_1, drm_2_connector_1);
screen_manager_->AddDisplayController(drm2_, drm_2_crtc_1, drm_2_connector_1);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, drm_1_crtc_1, drm_1_connector_1,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm2_, drm_2_crtc_1, drm_2_connector_1,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
drmModeModeInfo secondary_mode2 = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId + 1, drm2_, drm_2_crtc_1, drm_2_connector_1,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode2));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(drm_->get_set_crtc_call_count(), 1);
EXPECT_EQ(drm2_->get_set_crtc_call_count(), 2);
}
// Tests that two devices that may share the same object IDs are
// treated independently.
TEST_F(ScreenManagerTest,
CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
InitializeDrmStateWithDefault(drm2_.get(), /*is_atomic=*/true);
uint32_t drm2_crtc_id = drm2_->crtc_property(0).id;
uint32_t drm2_connector_id = drm2_->connector_property(0).id;
ASSERT_EQ(crtc_id, drm2_crtc_id);
ASSERT_EQ(connector_id, drm2_connector_id);
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
screen_manager_->AddDisplayController(drm2_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
drmModeModeInfo secondary_mode = kDefaultMode;
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm2_, crtc_id, connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
HardwareDisplayController* controller1 =
screen_manager_->GetDisplayController(GetPrimaryBounds());
HardwareDisplayController* controller2 =
screen_manager_->GetDisplayController(GetSecondaryBounds());
EXPECT_NE(controller1, controller2);
EXPECT_EQ(drm_, controller1->crtc_controllers()[0]->drm());
EXPECT_EQ(drm2_, controller2->crtc_controllers()[0]->drm());
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithSameBounds) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, CheckControllerToWindowMappingWithDifferentBounds) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
gfx::Rect new_bounds = GetPrimaryBounds();
new_bounds.Inset(gfx::Insets::TLBR(0, 0, 1, 1));
window->SetBounds(new_bounds);
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_FALSE(screen_manager_->GetWindow(1)->GetController());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest,
CheckControllerToWindowMappingWithOverlappingWindows) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
const size_t kWindowCount = 2;
for (size_t i = 1; i < kWindowCount + 1; ++i) {
std::unique_ptr<DrmWindow> window(
new DrmWindow(i, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(i, std::move(window));
}
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
bool window1_has_controller = screen_manager_->GetWindow(1)->GetController();
bool window2_has_controller = screen_manager_->GetWindow(2)->GetController();
// Only one of the windows can have a controller.
EXPECT_TRUE(window1_has_controller ^ window2_has_controller);
for (size_t i = 1; i < kWindowCount + 1; ++i) {
std::unique_ptr<DrmWindow> window = screen_manager_->RemoveWindow(i);
window->Shutdown();
}
}
TEST_F(ScreenManagerTest, ShouldDissociateWindowOnControllerRemoval) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
gfx::AcceleratedWidget window_id = 1;
std::unique_ptr<DrmWindow> window(
new DrmWindow(window_id, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(window_id, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetWindow(window_id)->GetController());
ScreenManager::CrtcsWithDrmList controllers_to_remove;
controllers_to_remove.emplace_back(crtc_id, drm_);
screen_manager_->RemoveDisplayControllers(controllers_to_remove);
EXPECT_FALSE(screen_manager_->GetWindow(window_id)->GetController());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasNoBuffer) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_TRUE(screen_manager_->GetWindow(1)->GetController());
// There is a buffer after initial config.
uint32_t framebuffer = drm_->current_framebuffer();
EXPECT_NE(0U, framebuffer);
controllers_to_enable.clear();
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// There is a new buffer after we configured with the same mode but no
// pending frames on the window.
EXPECT_NE(framebuffer, drm_->current_framebuffer());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, EnableControllerWhenWindowHasBuffer) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(buffer));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
EXPECT_EQ(buffer->opaque_framebuffer_id(), drm_->current_framebuffer());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
// See crbug.com/868010
TEST_F(ScreenManagerTest, DISABLED_RejectBufferWithIncompatibleModifiers) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
auto buffer = CreateBufferWithModifier(
DRM_FORMAT_XRGB8888, I915_FORMAT_MOD_X_TILED, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(buffer));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// ScreenManager::GetModesetBuffer (called to get a buffer to
// modeset the new controller) should reject the buffer with
// I915_FORMAT_MOD_X_TILED modifier we created above and the two
// framebuffer IDs should be different.
EXPECT_NE(buffer->framebuffer_id(), drm_->current_framebuffer());
EXPECT_NE(buffer->opaque_framebuffer_id(), drm_->current_framebuffer());
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ConfigureDisplayControllerShouldModesetOnce) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// When a window that had no controller becomes associated with a new
// controller, expect the crtc to be modeset once.
EXPECT_EQ(drm_->get_set_crtc_call_count(), 1);
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ShouldNotHardwareMirrorDifferentDrmDevices) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
InitializeDrmStateWithDefault(drm2_.get(), /*is_atomic=*/true);
uint32_t crtc1 = drm_->crtc_property(0).id;
uint32_t connector1 = drm_->connector_property(0).id;
uint32_t crtc2 = drm_->crtc_property(1).id;
uint32_t connector2 = drm_->connector_property(1).id;
drmModeModeInfo k1920x1080Screen = ConstructMode(1920, 1080);
// Two displays on different DRM devices must not join a mirror pair.
//
// However, they may have the same bounds in a transitional state.
//
// This scenario generates the same sequence of display configuration
// events as a panther (kernel 3.8.11) chromebox with two identical
// 1080p displays connected, one of them via a DisplayLink adapter.
// Both displays connect at startup.
{
auto window1 = std::make_unique<DrmWindow>(1, device_manager_.get(),
screen_manager_.get());
window1->Initialize();
screen_manager_->AddWindow(1, std::move(window1));
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->AddDisplayController(drm_, crtc1, connector1);
screen_manager_->AddDisplayController(drm2_, crtc2, connector2);
std::vector<ControllerConfigParams> controllers_to_enable;
std::unique_ptr<drmModeModeInfo> primary_mode =
std::make_unique<drmModeModeInfo>(k1920x1080Screen);
std::unique_ptr<drmModeModeInfo> secondary_mode =
std::make_unique<drmModeModeInfo>(k1920x1080Screen);
controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_, crtc1,
connector1, gfx::Point(0, 0),
std::move(primary_mode));
controllers_to_enable.emplace_back(kSecondaryDisplayId, drm2_, crtc2,
connector2, gfx::Point(0, 1140),
std::move(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
auto window2 = std::make_unique<DrmWindow>(2, device_manager_.get(),
screen_manager_.get());
window2->Initialize();
screen_manager_->AddWindow(2, std::move(window2));
screen_manager_->GetWindow(2)->SetBounds(gfx::Rect(0, 1140, 1920, 1080));
}
// Displays are stacked vertically, window per display.
{
HardwareDisplayController* controller1 =
screen_manager_->GetWindow(1)->GetController();
HardwareDisplayController* controller2 =
screen_manager_->GetWindow(2)->GetController();
EXPECT_NE(controller1, controller2);
EXPECT_TRUE(controller1->HasCrtc(drm_, crtc1));
EXPECT_TRUE(controller2->HasCrtc(drm2_, crtc2));
}
// Disconnect first display. Second display moves to origin.
{
ScreenManager::CrtcsWithDrmList controllers_to_remove;
controllers_to_remove.emplace_back(crtc1, drm_);
screen_manager_->RemoveDisplayControllers(controllers_to_remove);
std::vector<ControllerConfigParams> controllers_to_enable;
std::unique_ptr<drmModeModeInfo> secondary_mode =
std::make_unique<drmModeModeInfo>(k1920x1080Screen);
controllers_to_enable.emplace_back(kSecondaryDisplayId, drm2_, crtc2,
connector2, gfx::Point(0, 0),
std::move(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->RemoveWindow(2)->Shutdown();
}
// Reconnect first display. Original configuration restored.
{
screen_manager_->AddDisplayController(drm_, crtc1, connector1);
std::vector<ControllerConfigParams> controllers_to_enable;
std::unique_ptr<drmModeModeInfo> primary_mode =
std::make_unique<drmModeModeInfo>(k1920x1080Screen);
controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_, crtc1,
connector1, gfx::Point(0, 0),
std::move(primary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
// At this point, both displays are in the same location.
{
HardwareDisplayController* controller =
screen_manager_->GetWindow(1)->GetController();
EXPECT_FALSE(controller->IsMirrored());
// We don't really care which crtc it has, but it should have just
EXPECT_EQ(1U, controller->crtc_controllers().size());
EXPECT_TRUE(controller->HasCrtc(drm_, crtc1) ||
controller->HasCrtc(drm2_, crtc2));
}
controllers_to_enable.clear();
std::unique_ptr<drmModeModeInfo> secondary_mode =
std::make_unique<drmModeModeInfo>(k1920x1080Screen);
controllers_to_enable.emplace_back(kSecondaryDisplayId, drm2_, crtc2,
connector2, gfx::Point(0, 1140),
std::move(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
auto window3 = std::make_unique<DrmWindow>(3, device_manager_.get(),
screen_manager_.get());
window3->Initialize();
screen_manager_->AddWindow(3, std::move(window3));
screen_manager_->GetWindow(3)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 1140, 1920, 1080));
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->GetWindow(3)->SetBounds(gfx::Rect(0, 1140, 1920, 1080));
}
// Everything is restored.
{
HardwareDisplayController* controller1 =
screen_manager_->GetWindow(1)->GetController();
HardwareDisplayController* controller3 =
screen_manager_->GetWindow(3)->GetController();
EXPECT_NE(controller1, controller3);
EXPECT_TRUE(controller1->HasCrtc(drm_, crtc1));
EXPECT_TRUE(controller3->HasCrtc(drm2_, crtc2));
}
// Cleanup.
screen_manager_->RemoveWindow(1)->Shutdown();
screen_manager_->RemoveWindow(3)->Shutdown();
}
// crbug.com/888553
TEST_F(ScreenManagerTest, ShouldNotUnbindFramebufferOnJoiningMirror) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/false);
uint32_t crtc1 = drm_->crtc_property(0).id;
uint32_t connector1 = drm_->connector_property(0).id;
uint32_t crtc2 = drm_->crtc_property(1).id;
uint32_t connector2 = drm_->connector_property(1).id;
constexpr drmModeModeInfo k1080p60Screen = {
.clock = 148500,
.hdisplay = 1920,
.hsync_start = 2008,
.hsync_end = 2052,
.htotal = 2200,
.hskew = 0,
.vdisplay = 1080,
.vsync_start = 1084,
.vsync_end = 1089,
.vtotal = 1125,
.vscan = 0,
.vrefresh = 60,
.flags = 0xa,
.type = 64,
.name = "1920x1080",
};
// Both displays connect at startup.
{
auto window1 = std::make_unique<DrmWindow>(1, device_manager_.get(),
screen_manager_.get());
window1->Initialize();
screen_manager_->AddWindow(1, std::move(window1));
screen_manager_->GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager_->AddDisplayController(drm_, crtc1, connector1);
screen_manager_->AddDisplayController(drm_, crtc2, connector2);
std::vector<ControllerConfigParams> controllers_to_enable;
std::unique_ptr<drmModeModeInfo> primary_mode =
std::make_unique<drmModeModeInfo>(k1080p60Screen);
std::unique_ptr<drmModeModeInfo> secondary_mode =
std::make_unique<drmModeModeInfo>(k1080p60Screen);
controllers_to_enable.emplace_back(kPrimaryDisplayId, drm_, crtc1,
connector1, gfx::Point(0, 0),
std::move(primary_mode));
controllers_to_enable.emplace_back(kSecondaryDisplayId, drm_, crtc2,
connector2, gfx::Point(0, 0),
std::move(secondary_mode));
screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset});
}
EXPECT_NE(0u, drm_->GetFramebufferForCrtc(crtc1));
EXPECT_NE(0u, drm_->GetFramebufferForCrtc(crtc2));
// Cleanup.
screen_manager_->RemoveWindow(1)->Shutdown();
}
TEST_F(ScreenManagerTest, DrmFramebufferSequenceIdIncrementingAtModeset) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
scoped_refptr<DrmFramebuffer> pre_modeset_buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
// Successful modeset
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
{
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
}
scoped_refptr<DrmFramebuffer> first_post_modeset_buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
// Unsuccessful modeset
{
drm_->set_set_crtc_expectation(false);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_FALSE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
}
scoped_refptr<DrmFramebuffer> second_post_modeset_buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
CHECK_EQ(second_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
CHECK_EQ(first_post_modeset_buffer->modeset_sequence_id_at_allocation(), 1);
CHECK_EQ(pre_modeset_buffer->modeset_sequence_id_at_allocation(), 0);
}
TEST_F(ScreenManagerTest, CloningPlanesOnModeset) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(buffer));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
buffer));
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, CloningMultiplePlanesOnModeset) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> primary =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
scoped_refptr<DrmFramebuffer> overlay =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(primary));
planes.push_back(DrmOverlayPlane::TestPlane(overlay));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
primary));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
overlay));
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ModesetWithClonedPlanesNoOverlays) {
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> buffer =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(buffer));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
ASSERT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
buffer));
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
EXPECT_EQ(drm_->last_planes_committed_count(), 1);
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlaySucceeding) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> primary =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
scoped_refptr<DrmFramebuffer> overlay =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(primary));
planes.push_back(DrmOverlayPlane::TestPlane(overlay));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
primary));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
overlay));
EXPECT_EQ(drm_->get_test_modeset_count(), 2);
EXPECT_EQ(drm_->last_planes_committed_count(), 2);
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ModesetWithClonedPlanesWithOverlayFailing) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> primary =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
scoped_refptr<DrmFramebuffer> overlay =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(primary));
planes.push_back(DrmOverlayPlane::TestPlane(overlay));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
drm_->set_overlay_modeset_expectation(false);
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_TRUE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
primary));
EXPECT_FALSE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
overlay));
EXPECT_EQ(drm_->get_test_modeset_count(), 2);
EXPECT_EQ(drm_->last_planes_committed_count(), 1);
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, ModesetWithNewBuffersOnModifiersChange) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}},
{.formats = {DRM_FORMAT_XRGB8888}}}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true,
/*use_modifiers_list=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
scoped_refptr<DrmFramebuffer> primary =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
scoped_refptr<DrmFramebuffer> overlay =
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size());
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(primary));
planes.push_back(DrmOverlayPlane::TestPlane(overlay));
window->SchedulePageFlip(std::move(planes), base::DoNothing(),
base::DoNothing());
screen_manager_->AddWindow(1, std::move(window));
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
ASSERT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
EXPECT_FALSE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
primary));
EXPECT_FALSE(base::Contains(drm_->plane_manager()
->GetCrtcStateForCrtcId(crtc_id)
.modeset_framebuffers,
overlay));
// Testing test modifiers only, no linear or overlays test.
EXPECT_EQ(drm_->get_test_modeset_count(), 1);
EXPECT_EQ(drm_->last_planes_committed_count(), 1);
window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, PinnedPlanesAndHwMirroring) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
};
std::vector<PlaneState> movable_planes = {{.formats = {DRM_FORMAT_XRGB8888}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true,
/*use_modifiers_list=*/true, movable_planes);
uint32_t crtc_id_1 = drm_->crtc_property(0).id;
uint32_t connector_id_1 = drm_->connector_property(0).id;
uint32_t crtc_id_2 = drm_->crtc_property(1).id;
uint32_t connector_id_2 = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, crtc_id_1, connector_id_1);
screen_manager_->AddDisplayController(drm_, crtc_id_2, connector_id_2);
// Set up the initial window:
{
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(1, std::move(window));
}
// Set up the first display only:
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id_1, connector_id_1,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
// The movable plane will be associated with the first display:
{
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size())));
planes.push_back(DrmOverlayPlane::TestPlane(
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size())));
screen_manager_->GetWindow(1)->SchedulePageFlip(
std::move(planes), base::DoNothing(), base::DoNothing());
drm_->RunCallbacks();
}
// We should now be able to set up a HW mirrored display:
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, crtc_id_2, connector_id_2,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
auto window = screen_manager_->RemoveWindow(1);
window->Shutdown();
}
TEST_F(ScreenManagerTest, PinnedPlanesAndModesetting) {
std::vector<CrtcState> crtc_states = {
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
{.planes = {{.formats = {DRM_FORMAT_XRGB8888}}}},
};
std::vector<PlaneState> movable_planes = {{.formats = {DRM_FORMAT_XRGB8888}}};
InitializeDrmState(drm_.get(), crtc_states, /*is_atomic=*/true,
/*use_modifiers_list=*/true, movable_planes);
uint32_t crtc_id_1 = drm_->crtc_property(0).id;
uint32_t connector_id_1 = drm_->connector_property(0).id;
uint32_t crtc_id_2 = drm_->crtc_property(1).id;
uint32_t connector_id_2 = drm_->connector_property(1).id;
screen_manager_->AddDisplayController(drm_, crtc_id_1, connector_id_1);
screen_manager_->AddDisplayController(drm_, crtc_id_2, connector_id_2);
// Set up the windows:
{
std::unique_ptr<DrmWindow> window(
new DrmWindow(1, device_manager_.get(), screen_manager_.get()));
std::unique_ptr<DrmWindow> window2(
new DrmWindow(2, device_manager_.get(), screen_manager_.get()));
window->Initialize();
window->SetBounds(GetPrimaryBounds());
screen_manager_->AddWindow(1, std::move(window));
window2->Initialize();
window2->SetBounds(GetSecondaryBounds());
screen_manager_->AddWindow(2, std::move(window2));
}
// Set up the first display only:
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id_1, connector_id_1,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
// The movable plane will be associated with the first display:
{
DrmOverlayPlaneList planes;
planes.push_back(DrmOverlayPlane::TestPlane(
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size())));
planes.push_back(DrmOverlayPlane::TestPlane(
CreateBuffer(DRM_FORMAT_XRGB8888, GetPrimaryBounds().size())));
screen_manager_->GetWindow(1)->SchedulePageFlip(
std::move(planes), base::DoNothing(), base::DoNothing());
drm_->RunCallbacks();
}
// We should now be able to set up a second display:
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, crtc_id_2, connector_id_2,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
screen_manager_->RemoveWindow(1)->Shutdown();
screen_manager_->RemoveWindow(2)->Shutdown();
}
TEST_F(ScreenManagerTest, ReplaceDisplayControllersCrtcs) {
// Initializes 2 CRTC-Connector pairs.
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
ASSERT_NE(controller, nullptr);
ConnectorCrtcMap current_pairings = {{connector_id, crtc_id}};
uint32_t new_crtc_id = drm_->crtc_property(1).id;
ConnectorCrtcMap new_pairings = {{connector_id, new_crtc_id}};
ASSERT_TRUE(screen_manager_->ReplaceDisplayControllersCrtcs(
drm_, current_pairings, new_pairings));
controllers_to_enable.back().crtc = new_crtc_id;
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
HardwareDisplayController* new_controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
EXPECT_TRUE(new_controller->HasCrtc(drm_, new_crtc_id));
EXPECT_FALSE(new_controller->HasCrtc(drm_, crtc_id));
}
// TODO(b/322831691): Deterministic failure.
#if BUILDFLAG(IS_CHROMEOS_ASH)
#define MAYBE_ReplaceDisplayControllersCrtcsNonexistent \
DISABLED_ReplaceDisplayControllersCrtcsNonexistent
#else
#define MAYBE_ReplaceDisplayControllersCrtcsNonexistent \
ReplaceDisplayControllersCrtcsNonexistent
#endif
TEST_F(ScreenManagerTest, MAYBE_ReplaceDisplayControllersCrtcsNonexistent) {
// Initializes 2 CRTC-Connector pairs.
InitializeDrmStateWithDefault(drm_.get(), /*is_atomic=*/true);
uint32_t crtc_id = drm_->crtc_property(0).id;
uint32_t connector_id = drm_->connector_property(0).id;
// But only configure 1 CRTC-connector pair.
screen_manager_->AddDisplayController(drm_, crtc_id, connector_id);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_id, connector_id,
GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
HardwareDisplayController* controller =
screen_manager_->GetDisplayController(GetPrimaryBounds());
ASSERT_NE(controller, nullptr);
// CRTC + 1 is not a current CRTC.
ConnectorCrtcMap current_pairings = {{connector_id, crtc_id + 1}};
uint32_t new_crtc_id = drm_->crtc_property(1).id;
ConnectorCrtcMap new_pairings = {{connector_id, new_crtc_id}};
EXPECT_DEATH_IF_SUPPORTED(screen_manager_->ReplaceDisplayControllersCrtcs(
drm_, current_pairings, new_pairings),
"controller not found for connector");
}
TEST_F(ScreenManagerTest, ReplaceDisplayControllersCrtcsComplex) {
// 3 CRTCs and 2 connectors.
// Original state: {crtc_1 - connector_1}, {crtc_2 - connector_2}
// After replacement: {crtc_2 - connector_1}, {crtc_3 - connector_2}
drm_->ResetStateWithAllProperties();
// Create 3 CRTCs
uint32_t crtc_1 = drm_->AddCrtc().id;
AddPlaneToCrtc(crtc_1, DRM_PLANE_TYPE_PRIMARY);
AddPlaneToCrtc(crtc_1, DRM_PLANE_TYPE_OVERLAY);
uint32_t crtc_2 = drm_->AddCrtc().id;
AddPlaneToCrtc(crtc_2, DRM_PLANE_TYPE_PRIMARY);
AddPlaneToCrtc(crtc_2, DRM_PLANE_TYPE_OVERLAY);
uint32_t crtc_3 = drm_->AddCrtc().id;
AddPlaneToCrtc(crtc_3, DRM_PLANE_TYPE_PRIMARY);
AddPlaneToCrtc(crtc_3, DRM_PLANE_TYPE_OVERLAY);
// Create 2 Connectors that can use all 3 CRTCs.
uint32_t connector_1, connector_2;
{
FakeDrmDevice::EncoderProperties& encoder = drm_->AddEncoder();
encoder.possible_crtcs = 0b111;
const uint32_t encoder_id = encoder.id;
FakeDrmDevice::ConnectorProperties& connector = drm_->AddConnector();
connector.connection = true;
connector.encoders = std::vector<uint32_t>{encoder_id};
connector_1 = connector.id;
}
{
FakeDrmDevice::EncoderProperties& encoder = drm_->AddEncoder();
encoder.possible_crtcs = 0b111;
const uint32_t encoder_id = encoder.id;
FakeDrmDevice::ConnectorProperties& connector = drm_->AddConnector();
connector.connection = true;
connector.encoders = std::vector<uint32_t>{encoder_id};
connector_2 = connector.id;
}
drm_->InitializeState(/*is_atomic=*/true);
// Configure to {crtc_1 - connector_1}, {crtc_2 - connector_2}.
screen_manager_->AddDisplayController(drm_, crtc_1, connector_1);
screen_manager_->AddDisplayController(drm_, crtc_2, connector_2);
std::vector<ControllerConfigParams> controllers_to_enable;
controllers_to_enable.emplace_back(
kPrimaryDisplayId, drm_, crtc_1, connector_1, GetPrimaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
controllers_to_enable.emplace_back(
kSecondaryDisplayId, drm_, crtc_2, connector_2,
GetSecondaryBounds().origin(),
std::make_unique<drmModeModeInfo>(kDefaultMode));
EXPECT_TRUE(screen_manager_->ConfigureDisplayControllers(
controllers_to_enable, {display::ModesetFlag::kTestModeset,
display::ModesetFlag::kCommitModeset}));
HardwareDisplayController* controller_1 =
screen_manager_->GetDisplayController(GetPrimaryBounds());
ASSERT_NE(controller_1, nullptr);
EXPECT_THAT(controller_1->crtc_controllers(),
UnorderedElementsAre(
Pointee(EqualsCrtcConnectorIds(crtc_1, connector_1))));
HardwareDisplayController* controller_2 =
screen_manager_->GetDisplayController(GetSecondaryBounds());
ASSERT_NE(controller_2, nullptr);
EXPECT_THAT(controller_2->crtc_controllers(),
UnorderedElementsAre(
Pointee(EqualsCrtcConnectorIds(crtc_2, connector_2))));
ConnectorCrtcMap current_pairings = {{connector_1, crtc_1},
{connector_2, crtc_2}};
ConnectorCrtcMap new_pairings = {{connector_1, crtc_2},
{connector_2, crtc_3}};
ASSERT_TRUE(screen_manager_->ReplaceDisplayControllersCrtcs(
drm_, current_pairings, new_pairings));
// Check that the HDCs now reflect the replaced CRTCs, and that no old
// CrtcControllers remain.
EXPECT_THAT(controller_1->crtc_controllers(),
UnorderedElementsAre(
Pointee(EqualsCrtcConnectorIds(crtc_2, connector_1))));
EXPECT_THAT(controller_2->crtc_controllers(),
UnorderedElementsAre(
Pointee(EqualsCrtcConnectorIds(crtc_3, connector_2))));
}
} // namespace ui