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> {
private:
bool ResetCursor();
scoped_refptr<DrmDevice> drm_;
const scoped_refptr<DrmDevice> drm_;
// Buffers need to be declared first so that they are destroyed last. Needed
// since the controllers may reference the buffers.
......
......@@ -69,7 +69,7 @@ std::vector<OverlayCheckReturn_Params> DrmOverlayValidator::TestPageFlip(
DrmOverlayPlaneList test_list;
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)
reusable_buffers.push_back(plane.buffer);
......
......@@ -187,8 +187,7 @@ void DrmOverlayValidatorTest::InitializeDrmState(
}
void DrmOverlayValidatorTest::AddPlane(const ui::OverlayCheck_Params& params) {
scoped_refptr<ui::DrmDevice> drm =
window_->GetController()->GetAllocationDrmDevice();
scoped_refptr<ui::DrmDevice> drm = window_->GetController()->GetDrmDevice();
scoped_refptr<ui::ScanoutBuffer> scanout_buffer = buffer_generator_->Create(
drm, ui::GetFourCCFormatFromBufferFormat(params.format), {},
params.buffer_size);
......
......@@ -117,7 +117,7 @@ void DrmWindow::MoveCursor(const gfx::Point& location) {
bool DrmWindow::SchedulePageFlip(std::vector<DrmOverlayPlane> planes,
SwapCompletionOnceCallback callback) {
if (controller_) {
const DrmDevice* drm = controller_->GetAllocationDrmDevice().get();
const DrmDevice* drm = controller_->GetDrmDevice().get();
for (const auto& plane : planes) {
if (plane.buffer &&
plane.buffer->GetGbmDeviceLinux() != drm->AsGbmDeviceLinux()) {
......@@ -211,7 +211,7 @@ void DrmWindow::SetController(HardwareDisplayController* controller) {
controller_ = controller;
device_manager_->UpdateDrmDevice(
widget_, controller ? controller->GetAllocationDrmDevice() : nullptr);
widget_, controller ? controller->GetDrmDevice() : nullptr);
UpdateCursorBuffers();
// We changed displays, so we want to update the cursor as well.
......@@ -225,7 +225,7 @@ void DrmWindow::UpdateCursorBuffers() {
cursor_buffers_[i] = nullptr;
}
} else {
scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice();
scoped_refptr<DrmDevice> drm = controller_->GetDrmDevice();
gfx::Size max_cursor_size = GetMaximumCursorSize(drm->get_fd());
SkImageInfo info = SkImageInfo::MakeN32Premul(max_cursor_size.width(),
max_cursor_size.height());
......
......@@ -75,12 +75,9 @@ void HardwareDisplayController::Disable() {
for (const auto& controller : crtc_controllers_)
controller->Disable();
for (const auto& planes : owned_hardware_planes_) {
DrmDevice* drm = planes.first;
HardwareDisplayPlaneList* plane_list = planes.second.get();
bool ret = drm->plane_manager()->DisableOverlayPlanes(plane_list);
LOG_IF(ERROR, !ret) << "Can't disable overlays when disabling HDC.";
}
bool ret = GetDrmDevice()->plane_manager()->DisableOverlayPlanes(
&owned_hardware_planes_);
LOG_IF(ERROR, !ret) << "Can't disable overlays when disabling HDC.";
is_disabled_ = true;
}
......@@ -121,21 +118,17 @@ bool HardwareDisplayController::ActualSchedulePageFlip(
scoped_refptr<PageFlipRequest> page_flip_request =
new PageFlipRequest(crtc_controllers_.size(), std::move(callback));
for (const auto& planes : owned_hardware_planes_)
planes.first->plane_manager()->BeginFrame(planes.second.get());
GetDrmDevice()->plane_manager()->BeginFrame(&owned_hardware_planes_);
bool status = true;
for (const auto& controller : crtc_controllers_) {
status &= controller->SchedulePageFlip(
owned_hardware_planes_[controller->drm().get()].get(), pending_planes,
test_only, page_flip_request);
&owned_hardware_planes_, pending_planes, test_only, page_flip_request);
}
for (const auto& planes : owned_hardware_planes_) {
if (!planes.first->plane_manager()->Commit(planes.second.get(),
if (!GetDrmDevice()->plane_manager()->Commit(&owned_hardware_planes_,
test_only)) {
status = false;
}
status = false;
}
return status;
......@@ -215,20 +208,15 @@ bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
void HardwareDisplayController::AddCrtc(
std::unique_ptr<CrtcController> controller) {
scoped_refptr<DrmDevice> drm = controller->drm();
std::unique_ptr<HardwareDisplayPlaneList>& owned_planes =
owned_hardware_planes_[drm.get()];
if (!owned_planes)
owned_planes.reset(new HardwareDisplayPlaneList());
DCHECK(crtc_controllers_.empty() || drm == GetDrmDevice());
// Check if this controller owns any planes and ensure we keep track of them.
const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes =
drm->plane_manager()->planes();
HardwareDisplayPlaneList* crtc_plane_list = owned_planes.get();
uint32_t crtc = controller->crtc();
for (const auto& plane : all_planes) {
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));
......@@ -248,15 +236,11 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
std::unique_ptr<CrtcController> controller(std::move(*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
// CRTC at the end of the collection.
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) {
return plane->owning_crtc() != crtc;
});
......@@ -264,22 +248,14 @@ std::unique_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
// Disable the planes enabled with the last commit on |crtc|, otherwise
// the planes will be visible if the crtc is reassigned to another connector.
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));
drm->plane_manager()->DisableOverlayPlanes(&hardware_plane_list);
// If it was the only CRTC for this drm device, we can remove the hardware
// planes list in |owned_hardware_planes_|.
if (std::find_if(crtc_controllers_.begin(), crtc_controllers_.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());
}
// Remove the planes assigned to |crtc|.
owned_hardware_planes_.old_plane_list.erase(
first_plane_to_disable_it, owned_hardware_planes_.old_plane_list.end());
return controller;
}
......@@ -318,8 +294,7 @@ base::TimeTicks HardwareDisplayController::GetTimeOfLastFlip() const {
return time;
}
scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice()
const {
scoped_refptr<DrmDevice> HardwareDisplayController::GetDrmDevice() const {
DCHECK(!crtc_controllers_.empty());
// TODO(dnicoara) When we support mirroring across DRM devices, figure out
// which device should be used for allocations.
......
......@@ -161,15 +161,14 @@ class HardwareDisplayController {
return crtc_controllers_;
}
scoped_refptr<DrmDevice> GetAllocationDrmDevice() const;
scoped_refptr<DrmDevice> GetDrmDevice() const;
private:
bool ActualSchedulePageFlip(const DrmOverlayPlaneList& plane_list,
bool test_only,
SwapCompletionOnceCallback callback);
std::unordered_map<DrmDevice*, std::unique_ptr<HardwareDisplayPlaneList>>
owned_hardware_planes_;
HardwareDisplayPlaneList owned_hardware_planes_;
// Stores the CRTC configuration. This is used to identify monitors and
// configure them.
......
......@@ -321,6 +321,9 @@ TEST_F(HardwareDisplayControllerTest, PageflipMirroredControllers) {
}
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>(
new ui::MockScanoutBuffer(kDefaultModeSize)),
nullptr);
......@@ -332,28 +335,38 @@ TEST_F(HardwareDisplayControllerTest, PlaneStateAfterRemoveCrtc) {
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
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()) {
if (plane->in_use())
owned_plane = plane.get();
if (plane->in_use() && plane->owning_crtc() == kPrimaryCrtc)
primary_crtc_plane = plane.get();
if (plane->in_use() && plane->owning_crtc() == kSecondaryCrtc)
secondary_crtc_plane = plane.get();
}
ASSERT_TRUE(owned_plane != nullptr);
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc());
ASSERT_NE(nullptr, primary_crtc_plane);
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.
std::unique_ptr<ui::CrtcController> crtc =
controller_->RemoveCrtc(drm_, kPrimaryCrtc);
EXPECT_TRUE(owned_plane->in_use());
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc());
EXPECT_TRUE(primary_crtc_plane->in_use());
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
// subsequent page flip.
SchedulePageFlip(ui::DrmOverlayPlane::Clone(planes));
drm_->RunCallbacks();
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, last_swap_result_);
EXPECT_EQ(1, page_flips_);
EXPECT_TRUE(owned_plane->in_use());
EXPECT_EQ(kPrimaryCrtc, owned_plane->owning_crtc());
EXPECT_EQ(2, page_flips_);
EXPECT_TRUE(primary_crtc_plane->in_use());
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) {
......
......@@ -169,7 +169,7 @@ bool ScreenManager::ActualConfigureDisplayController(
origin == controller->origin()) {
if (controller->IsDisabled()) {
HardwareDisplayControllers::iterator mirror =
FindActiveDisplayControllerByLocation(modeset_bounds);
FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// If there is an active controller at the same location then start mirror
// mode.
if (mirror != controllers_.end())
......@@ -192,7 +192,7 @@ bool ScreenManager::ActualConfigureDisplayController(
}
HardwareDisplayControllers::iterator mirror =
FindActiveDisplayControllerByLocation(modeset_bounds);
FindActiveDisplayControllerByLocation(drm, modeset_bounds);
// Handle mirror mode.
if (mirror != controllers_.end() && it != mirror)
return HandleMirrorMode(it, mirror, drm, crtc, connector, mode);
......@@ -278,6 +278,20 @@ ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
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(
HardwareDisplayControllers::iterator original,
HardwareDisplayControllers::iterator mirror,
......@@ -357,7 +371,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
controller->GetFormatModifiersForModesetting(fourcc_format);
if (window) {
const DrmOverlayPlane* primary = window->GetLastModesetBuffer();
const DrmDevice* drm = controller->GetAllocationDrmDevice().get();
const DrmDevice* drm = controller->GetDrmDevice().get();
if (primary && primary->buffer->GetSize() == bounds.size() &&
primary->buffer->GetGbmDeviceLinux() == drm->AsGbmDeviceLinux()) {
// If the controller doesn't advertise modifiers, wont have a
......@@ -373,7 +387,7 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer(
}
}
scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
scoped_refptr<ScanoutBuffer> buffer =
buffer_generator_->Create(drm, fourcc_format, modifiers, bounds.size());
if (!buffer) {
......
......@@ -102,6 +102,12 @@ class ScreenManager {
HardwareDisplayControllers::iterator FindActiveDisplayControllerByLocation(
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
// those in |mirror|. |original| is an iterator to the HDC where the
// controller is currently present.
......
......@@ -22,6 +22,7 @@
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
#include "ui/ozone/platform/drm/gpu/screen_manager.h"
namespace ui {
namespace {
// Create a basic mode for a 6x4 screen.
......@@ -33,6 +34,10 @@ const uint32_t kPrimaryConnector = 2;
const uint32_t kSecondaryCrtc = 3;
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
class ScreenManagerTest : public testing::Test {
......@@ -547,3 +552,111 @@ TEST_F(ScreenManagerTest, RejectBufferWithIncompatibleModifiers) {
window = screen_manager_->RemoveWindow(1);
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