Commit 07be465d authored by Michael Spang's avatar Michael Spang Committed by Commit Bot

ozone: drm: Remove incomplete support for cross-device mirroring

Display configurator will not configure mirror pairs between devices (see
AllDisplaysOnSameDevice() in ui/display), so remove code attempting to
support this.

Bug: 851997
Test: hardware mirroring on cros

Change-Id: Ie2fdc9f42423be1cd8efe7c59d43001e6096e935
Reviewed-on: https://chromium-review.googlesource.com/1104858
Commit-Queue: Michael Spang <spang@chromium.org>
Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569971}
parent c0f770ef
...@@ -86,7 +86,7 @@ class CrtcController : public base::SupportsWeakPtr<CrtcController> { ...@@ -86,7 +86,7 @@ class CrtcController : public base::SupportsWeakPtr<CrtcController> {
private: private:
bool ResetCursor(); bool ResetCursor();
scoped_refptr<DrmDevice> drm_; const scoped_refptr<DrmDevice> drm_;
// Buffers need to be declared first so that they are destroyed last. Needed // Buffers need to be declared first so that they are destroyed last. Needed
// since the controllers may reference the buffers. // since the controllers may reference the buffers.
......
...@@ -69,7 +69,7 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip( ...@@ -69,7 +69,7 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip(
DrmOverlayPlaneList test_list; DrmOverlayPlaneList test_list;
std::vector<scoped_refptr<ScanoutBuffer>> reusable_buffers; std::vector<scoped_refptr<ScanoutBuffer>> reusable_buffers;
scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
for (const auto& plane : last_used_planes) for (const auto& plane : last_used_planes)
reusable_buffers.push_back(plane.buffer); reusable_buffers.push_back(plane.buffer);
......
...@@ -187,8 +187,7 @@ void DrmOverlayValidatorTest::InitializeDrmState( ...@@ -187,8 +187,7 @@ void DrmOverlayValidatorTest::InitializeDrmState(
} }
void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) { void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
scoped_refptr<ui::DrmDevice> drm = scoped_refptr<ui::DrmDevice> drm = window_->GetController()->GetDrmDevice();
window_->GetController()->GetAllocationDrmDevice();
scoped_refptr<ui::ScanoutBuffer> scanout_buffer = buffer_generator_->Create( scoped_refptr<ui::ScanoutBuffer> scanout_buffer = buffer_generator_->Create(
drm, ui::GetFourCCFormatFromBufferFormat(params.format), {}, drm, ui::GetFourCCFormatFromBufferFormat(params.format), {},
params.buffer_size); params.buffer_size);
......
...@@ -117,7 +117,7 @@ void DrmWindow::MoveCursor(const gfx::Point& location) { ...@@ -117,7 +117,7 @@ void DrmWindow::MoveCursor(const gfx::Point& location) {
bool DrmWindow::SchedulePageFlip(std::vector<DrmOverlayPlane> planes, bool DrmWindow::SchedulePageFlip(std::vector<DrmOverlayPlane> planes,
SwapCompletionOnceCallback callback) { SwapCompletionOnceCallback callback) {
if (controller_) { if (controller_) {
const DrmDevice* drm = controller_->GetAllocationDrmDevice().get(); const DrmDevice* drm = controller_->GetDrmDevice().get();
for (const auto& plane : planes) { for (const auto& plane : planes) {
if (plane.buffer && if (plane.buffer &&
plane.buffer->GetGbmDeviceLinux() != drm->AsGbmDeviceLinux()) { plane.buffer->GetGbmDeviceLinux() != drm->AsGbmDeviceLinux()) {
...@@ -211,7 +211,7 @@ void DrmWindow::SetController(HardwareDisplayController* controller) { ...@@ -211,7 +211,7 @@ void DrmWindow::SetController(HardwareDisplayController* controller) {
controller_ = controller; controller_ = controller;
device_manager_->UpdateDrmDevice( device_manager_->UpdateDrmDevice(
widget_, controller ? controller->GetAllocationDrmDevice() : nullptr); widget_, controller ? controller->GetDrmDevice() : nullptr);
UpdateCursorBuffers(); UpdateCursorBuffers();
// We changed displays, so we want to update the cursor as well. // We changed displays, so we want to update the cursor as well.
...@@ -225,7 +225,7 @@ void DrmWindow::UpdateCursorBuffers() { ...@@ -225,7 +225,7 @@ void DrmWindow::UpdateCursorBuffers() {
cursor_buffers_[i] = nullptr; cursor_buffers_[i] = nullptr;
} }
} else { } else {
scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); scoped_refptr<DrmDevice> drm = controller_->GetDrmDevice();
gfx::Size max_cursor_size = GetMaximumCursorSize(drm->get_fd()); gfx::Size max_cursor_size = GetMaximumCursorSize(drm->get_fd());
SkImageInfo info = SkImageInfo::MakeN32Premul(max_cursor_size.width(), SkImageInfo info = SkImageInfo::MakeN32Premul(max_cursor_size.width(),
max_cursor_size.height()); max_cursor_size.height());
......
...@@ -75,12 +75,9 @@ void HardwareDisplayController::Disable() { ...@@ -75,12 +75,9 @@ void HardwareDisplayController::Disable() {
for (const auto& controller : crtc_controllers_) for (const auto& controller : crtc_controllers_)
controller->Disable(); controller->Disable();
for (const auto& planes : owned_hardware_planes_) { bool ret = GetDrmDevice()->plane_manager()->DisableOverlayPlanes(
DrmDevice* drm = planes.first; &owned_hardware_planes_);
HardwareDisplayPlaneList* plane_list = planes.second.get(); LOG_IF(ERROR, !ret) << "Can't disable overlays when disabling HDC.";
bool ret = drm->plane_manager()->DisableOverlayPlanes(plane_list);
LOG_IF(ERROR, !ret) << "Can't disable overlays when disabling HDC.";
}
is_disabled_ = true; is_disabled_ = true;
} }
...@@ -121,21 +118,17 @@ bool HardwareDisplayController::ActualSchedulePageFlip( ...@@ -121,21 +118,17 @@ bool HardwareDisplayController::ActualSchedulePageFlip(
scoped_refptr<PageFlipRequest> page_flip_request = scoped_refptr<PageFlipRequest> page_flip_request =
new PageFlipRequest(crtc_controllers_.size(), std::move(callback)); new PageFlipRequest(crtc_controllers_.size(), std::move(callback));
for (const auto& planes : owned_hardware_planes_) GetDrmDevice()->plane_manager()->BeginFrame(&owned_hardware_planes_);
planes.first->plane_manager()->BeginFrame(planes.second.get());
bool status = true; bool status = true;
for (const auto& controller : crtc_controllers_) { for (const auto& controller : crtc_controllers_) {
status &= controller->SchedulePageFlip( status &= controller->SchedulePageFlip(
owned_hardware_planes_[controller->drm().get()].get(), pending_planes, &owned_hardware_planes_, pending_planes, test_only, page_flip_request);
test_only, page_flip_request);
} }
for (const auto& planes : owned_hardware_planes_) { if (!GetDrmDevice()->plane_manager()->Commit(&owned_hardware_planes_,
if (!planes.first->plane_manager()->Commit(planes.second.get(),
test_only)) { test_only)) {
status = false; status = false;
}
} }
return status; return status;
...@@ -215,20 +208,15 @@ bool HardwareDisplayController::MoveCursor(const gfx::Point& location) { ...@@ -215,20 +208,15 @@ bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
void HardwareDisplayController::AddCrtc( void HardwareDisplayController::AddCrtc(
std::unique_ptr<CrtcController> controller) { std::unique_ptr<CrtcController> controller) {
scoped_refptr<DrmDevice> drm = controller->drm(); scoped_refptr<DrmDevice> drm = controller->drm();
DCHECK(crtc_controllers_.empty() || drm == GetDrmDevice());
std::unique_ptr<HardwareDisplayPlaneList>& owned_planes =
owned_hardware_planes_[drm.get()];
if (!owned_planes)
owned_planes.reset(new HardwareDisplayPlaneList());
// Check if this controller owns any planes and ensure we keep track of them. // Check if this controller owns any planes and ensure we keep track of them.
const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes = const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes =
drm->plane_manager()->planes(); drm->plane_manager()->planes();
HardwareDisplayPlaneList* crtc_plane_list = owned_planes.get();
uint32_t crtc = controller->crtc(); uint32_t crtc = controller->crtc();
for (const auto& plane : all_planes) { for (const auto& plane : all_planes) {
if (plane->in_use() && (plane->owning_crtc() == crtc)) if (plane->in_use() && (plane->owning_crtc() == crtc))
crtc_plane_list->old_plane_list.push_back(plane.get()); owned_hardware_planes_.old_plane_list.push_back(plane.get());
} }
crtc_controllers_.push_back(std::move(controller)); crtc_controllers_.push_back(std::move(controller));
...@@ -248,15 +236,11 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( ...@@ -248,15 +236,11 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
std::unique_ptr<CrtcController> controller(std::move(*controller_it)); std::unique_ptr<CrtcController> controller(std::move(*controller_it));
crtc_controllers_.erase(controller_it); crtc_controllers_.erase(controller_it);
// Remove and disable only the planes owned by the CRTC we just
// removed.
std::vector<HardwareDisplayPlane*>& old_plane_list =
owned_hardware_planes_[drm.get()]->old_plane_list;
// Move all the planes that have been committed in the last pageflip for this // Move all the planes that have been committed in the last pageflip for this
// CRTC at the end of the collection. // CRTC at the end of the collection.
auto first_plane_to_disable_it = auto first_plane_to_disable_it =
std::partition(old_plane_list.begin(), old_plane_list.end(), std::partition(owned_hardware_planes_.old_plane_list.begin(),
owned_hardware_planes_.old_plane_list.end(),
[crtc](const HardwareDisplayPlane* plane) { [crtc](const HardwareDisplayPlane* plane) {
return plane->owning_crtc() != crtc; return plane->owning_crtc() != crtc;
}); });
...@@ -264,22 +248,14 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( ...@@ -264,22 +248,14 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
// Disable the planes enabled with the last commit on |crtc|, otherwise // Disable the planes enabled with the last commit on |crtc|, otherwise
// the planes will be visible if the crtc is reassigned to another connector. // the planes will be visible if the crtc is reassigned to another connector.
HardwareDisplayPlaneList hardware_plane_list; HardwareDisplayPlaneList hardware_plane_list;
std::copy(first_plane_to_disable_it, old_plane_list.end(), std::copy(first_plane_to_disable_it,
owned_hardware_planes_.old_plane_list.end(),
std::back_inserter(hardware_plane_list.old_plane_list)); std::back_inserter(hardware_plane_list.old_plane_list));
drm->plane_manager()->DisableOverlayPlanes(&hardware_plane_list); drm->plane_manager()->DisableOverlayPlanes(&hardware_plane_list);
// If it was the only CRTC for this drm device, we can remove the hardware // Remove the planes assigned to |crtc|.
// planes list in |owned_hardware_planes_|. owned_hardware_planes_.old_plane_list.erase(
if (std::find_if(crtc_controllers_.begin(), crtc_controllers_.end(), first_plane_to_disable_it, owned_hardware_planes_.old_plane_list.end());
[drm](const std::unique_ptr<CrtcController>& crtc) {
return crtc->drm() == drm;
}) == crtc_controllers_.end()) {
owned_hardware_planes_.erase(controller->drm().get());
} else {
// Otherwise we can remove the planes assigned to |crtc| but we can't
// remove the entry in |owned_hardware_planes_|.
old_plane_list.erase(first_plane_to_disable_it, old_plane_list.end());
}
return controller; return controller;
} }
...@@ -318,8 +294,7 @@ base::TimeTicks HardwareDisplayController::GetTimeOfLastFlip() const { ...@@ -318,8 +294,7 @@ base::TimeTicks HardwareDisplayController::GetTimeOfLastFlip() const {
return time; return time;
} }
scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() scoped_refptr<DrmDevice> HardwareDisplayController::GetDrmDevice() const {
const {
DCHECK(!crtc_controllers_.empty()); DCHECK(!crtc_controllers_.empty());
// TODO(dnicoara) When we support mirroring across DRM devices, figure out // TODO(dnicoara) When we support mirroring across DRM devices, figure out
// which device should be used for allocations. // which device should be used for allocations.
......
...@@ -161,15 +161,14 @@ class HardwareDisplayController { ...@@ -161,15 +161,14 @@ class HardwareDisplayController {
return crtc_controllers_; return crtc_controllers_;
} }
scoped_refptr<DrmDevice> GetAllocationDrmDevice() const; scoped_refptr<DrmDevice> GetDrmDevice() const;
private: private:
bool ActualSchedulePageFlip(const DrmOverlayPlaneList& plane_list, bool ActualSchedulePageFlip(const DrmOverlayPlaneList& plane_list,
bool test_only, bool test_only,
SwapCompletionOnceCallback callback); SwapCompletionOnceCallback callback);
std::unordered_map<DrmDevice*, std::unique_ptr<HardwareDisplayPlaneList>> HardwareDisplayPlaneList owned_hardware_planes_;
owned_hardware_planes_;
// Stores the CRTC configuration. This is used to identify monitors and // Stores the CRTC configuration. This is used to identify monitors and
// configure them. // configure them.
......
...@@ -321,6 +321,9 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) { ...@@ -321,6 +321,9 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
} }
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) { TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
controller_->AddCrtc(std::unique_ptr<ui::CrtcController>(
new ui::CrtcController(drm_.get(), kSecondaryCrtc, kSecondaryConnector)));
ui::DrmOverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>( ui::DrmOverlayPlane plane1(scoped_refptr<ui::ScanoutBuffer>(
new ui::MockScanoutBuffer(kDefaultModeSize)), new ui::MockScanoutBuffer(kDefaultModeSize)),
nullptr); nullptr);
...@@ -332,28 +335,38 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) { ...@@ -332,28 +335,38 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_); EXPECT_EQ(1, page_flips_);
const ui::HardwareDisplayPlane* owned_plane = nullptr; const ui::HardwareDisplayPlane* primary_crtc_plane = nullptr;
const ui::HardwareDisplayPlane* secondary_crtc_plane = nullptr;
for (const auto& plane : drm_->plane_manager()->planes()) { for (const auto& plane : drm_->plane_manager()->planes()) {
if (plane->in_use()) if (plane->in_use() && plane->owning_crtc() == kPrimaryCrtc)
owned_plane = plane.get(); primary_crtc_plane = plane.get();
if (plane->in_use() && plane->owning_crtc() == kSecondaryCrtc)
secondary_crtc_plane = plane.get();
} }
ASSERT_TRUE(owned_plane != nullptr); ASSERT_NE(nullptr, primary_crtc_plane);
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc()); ASSERT_NE(nullptr, secondary_crtc_plane);
EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
// Removing the crtc should not free the plane or change ownership. // Removing the crtc should not free the plane or change ownership.
std::unique_ptr<ui::CrtcController> crtc = std::unique_ptr<ui::CrtcController> crtc =
controller_->RemoveCrtc(drm_, kPrimaryCrtc); controller_->RemoveCrtc(drm_, kPrimaryCrtc);
EXPECT_TRUE(owned_plane->in_use()); EXPECT_TRUE(primary_crtc_plane->in_use());
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc()); EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
EXPECT_TRUE(secondary_crtc_plane->in_use());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
// Check that controller doesn't affect the state of removed plane in // Check that controller doesn't affect the state of removed plane in
// subsequent page flip. // subsequent page flip.
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes)); SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks(); drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_); EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_); EXPECT_EQ(2, page_flips_);
EXPECT_TRUE(owned_plane->in_use()); EXPECT_TRUE(primary_crtc_plane->in_use());
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc()); EXPECT_EQ(kPrimaryCrtc, primary_crtc_plane->owning_crtc());
EXPECT_TRUE(secondary_crtc_plane->in_use());
EXPECT_EQ(kSecondaryCrtc, secondary_crtc_plane->owning_crtc());
} }
TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) { TEST_F(HardwareDisplayControllerTest, PlaneStateAfterDestroyingCrtc) {
......
...@@ -169,7 +169,7 @@ bool ScreenManager::ActualConfigureDisplayController( ...@@ -169,7 +169,7 @@ bool ScreenManager::ActualConfigureDisplayController(
origin == controller->origin()) { origin == controller->origin()) {
if (controller->IsDisabled()) { if (controller->IsDisabled()) {
HardwareDisplayControllers::iterator mirror = HardwareDisplayControllers::iterator mirror =
FindActiveDisplayControllerByLocation(modeset_bounds); FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// If there is an active controller at the same location then start mirror // If there is an active controller at the same location then start mirror
// mode. // mode.
if (mirror != controllers_.end()) if (mirror != controllers_.end())
...@@ -192,7 +192,7 @@ bool ScreenManager::ActualConfigureDisplayController( ...@@ -192,7 +192,7 @@ bool ScreenManager::ActualConfigureDisplayController(
} }
HardwareDisplayControllers::iterator mirror = HardwareDisplayControllers::iterator mirror =
FindActiveDisplayControllerByLocation(modeset_bounds); FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// Handle mirror mode. // Handle mirror mode.
if (mirror != controllers_.end() && it != mirror) if (mirror != controllers_.end() && it != mirror)
return HandleMirrorMode(it, mirror, drm, crtc, connector, mode); return HandleMirrorMode(it, mirror, drm, crtc, connector, mode);
...@@ -278,6 +278,20 @@ ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) { ...@@ -278,6 +278,20 @@ ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
return controllers_.end(); return controllers_.end();
} }
ScreenManager::HardwareDisplayControllers::iterator
ScreenManager::FindActiveDisplayControllerByLocation(
const scoped_refptr<DrmDevice>& drm,
const gfx::Rect& bounds) {
for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
if ((*it)->GetDrmDevice() == drm && controller_bounds == bounds &&
!(*it)->IsDisabled())
return it;
}
return controllers_.end();
}
bool ScreenManager::HandleMirrorMode( bool ScreenManager::HandleMirrorMode(
HardwareDisplayControllers::iterator original, HardwareDisplayControllers::iterator original,
HardwareDisplayControllers::iterator mirror, HardwareDisplayControllers::iterator mirror,
...@@ -357,7 +371,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( ...@@ -357,7 +371,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
controller->GetFormatModifiersForModesetting(fourcc_format); controller->GetFormatModifiersForModesetting(fourcc_format);
if (window) { if (window) {
const DrmOverlayPlane* primary = window->GetLastModesetBuffer(); const DrmOverlayPlane* primary = window->GetLastModesetBuffer();
const DrmDevice* drm = controller->GetAllocationDrmDevice().get(); const DrmDevice* drm = controller->GetDrmDevice().get();
if (primary && primary->buffer->GetSize() == bounds.size() && if (primary && primary->buffer->GetSize() == bounds.size() &&
primary->buffer->GetGbmDeviceLinux() == drm->AsGbmDeviceLinux()) { primary->buffer->GetGbmDeviceLinux() == drm->AsGbmDeviceLinux()) {
// If the controller doesn't advertise modifiers, wont have a // If the controller doesn't advertise modifiers, wont have a
...@@ -373,7 +387,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( ...@@ -373,7 +387,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
} }
} }
scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice(); scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
scoped_refptr<ScanoutBuffer> buffer = scoped_refptr<ScanoutBuffer> buffer =
buffer_generator_->Create(drm, fourcc_format, modifiers, bounds.size()); buffer_generator_->Create(drm, fourcc_format, modifiers, bounds.size());
if (!buffer) { if (!buffer) {
......
...@@ -102,6 +102,12 @@ class ScreenManager { ...@@ -102,6 +102,12 @@ class ScreenManager {
HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation( HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation(
const gfx::Rect& bounds); const gfx::Rect& bounds);
// Returns an iterator into |controllers_| for the controller located at
// |origin| with matching DRM device.
HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation(
const scoped_refptr<DrmDevice>& drm,
const gfx::Rect& bounds);
// Tries to set the controller identified by (|crtc|, |connector|) to mirror // Tries to set the controller identified by (|crtc|, |connector|) to mirror
// those in |mirror|. |original| is an iterator to the HDC where the // those in |mirror|. |original| is an iterator to the HDC where the
// controller is currently present. // controller is currently present.
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
#include "ui/ozone/platform/drm/gpu/screen_manager.h" #include "ui/ozone/platform/drm/gpu/screen_manager.h"
namespace ui {
namespace { namespace {
// Create a basic mode for a 6x4 screen. // Create a basic mode for a 6x4 screen.
...@@ -33,6 +34,10 @@ const uint32_t kPrimaryConnector = 2; ...@@ -33,6 +34,10 @@ const uint32_t kPrimaryConnector = 2;
const uint32_t kSecondaryCrtc = 3; const uint32_t kSecondaryCrtc = 3;
const uint32_t kSecondaryConnector = 4; const uint32_t kSecondaryConnector = 4;
drmModeModeInfo Mode(uint16_t hdisplay, uint16_t vdisplay) {
return {0, hdisplay, 0, 0, 0, 0, vdisplay, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
}
} // namespace } // namespace
class ScreenManagerTest : public testing::Test { class ScreenManagerTest : public testing::Test {
...@@ -547,3 +552,111 @@ TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) { ...@@ -547,3 +552,111 @@ TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) {
window = screen_manager_->RemoveWindow(1); window = screen_manager_->RemoveWindow(1);
window->Shutdown(); window->Shutdown();
} }
TEST(ScreenManagerTest2, ShouldNotHardwareMirrorDifferentDrmDevices) {
auto drm_device1 = base::MakeRefCounted<MockDrmDevice>(false);
auto drm_device2 = base::MakeRefCounted<MockDrmDevice>(false);
DrmDeviceManager drm_device_manager(nullptr);
MockScanoutBufferGenerator buffer_generator;
ScreenManager screen_manager(&buffer_generator);
constexpr uint32_t kCrtc19 = 19;
constexpr uint32_t kConnector28 = 28;
constexpr uint32_t kCrtc20 = 20;
constexpr uint32_t kConnector22 = 22;
// 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, &drm_device_manager, &screen_manager);
window1->Initialize(&buffer_generator);
screen_manager.AddWindow(1, std::move(window1));
screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
screen_manager.AddDisplayController(drm_device1, kCrtc19, kConnector28);
screen_manager.AddDisplayController(drm_device2, kCrtc20, kConnector22);
screen_manager.ConfigureDisplayController(
drm_device1, kCrtc19, kConnector28, gfx::Point(0, 0), Mode(1920, 1080));
screen_manager.ConfigureDisplayController(drm_device2, kCrtc20,
kConnector22, gfx::Point(0, 1140),
Mode(1920, 1080));
auto window2 =
std::make_unique<DrmWindow>(2, &drm_device_manager, &screen_manager);
window2->Initialize(&buffer_generator);
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_device1, kCrtc19));
EXPECT_TRUE(controller2->HasCrtc(drm_device2, kCrtc20));
}
// Disconnect first display. Second display moves to origin.
{
screen_manager.RemoveDisplayController(drm_device1, kCrtc19);
screen_manager.ConfigureDisplayController(
drm_device2, kCrtc20, kConnector22, gfx::Point(0, 0), Mode(1920, 1080));
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_device1, kCrtc19, kConnector28);
screen_manager.ConfigureDisplayController(
drm_device1, kCrtc19, kConnector28, gfx::Point(0, 0), Mode(1920, 1080));
// 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 one.
EXPECT_EQ(1U, controller->crtc_controllers().size());
EXPECT_TRUE(controller->HasCrtc(drm_device1, kCrtc19) ||
controller->HasCrtc(drm_device2, kCrtc20));
}
screen_manager.ConfigureDisplayController(drm_device2, kCrtc20,
kConnector22, gfx::Point(0, 1140),
Mode(1920, 1080));
auto window3 =
std::make_unique<DrmWindow>(3, &drm_device_manager, &screen_manager);
window3->Initialize(&buffer_generator);
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_device1, kCrtc19));
EXPECT_TRUE(controller3->HasCrtc(drm_device2, kCrtc20));
}
// Cleanup.
screen_manager.RemoveWindow(1)->Shutdown();
screen_manager.RemoveWindow(3)->Shutdown();
}
} // namespace ui
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment