1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/ozone/platform/dri/screen_manager.h"
7 #include <xf86drmMode.h>
9 #include "ui/gfx/geometry/point.h"
10 #include "ui/gfx/geometry/rect.h"
11 #include "ui/gfx/geometry/size.h"
12 #include "ui/ozone/platform/dri/crtc_state.h"
13 #include "ui/ozone/platform/dri/dri_util.h"
14 #include "ui/ozone/platform/dri/hardware_display_controller.h"
15 #include "ui/ozone/platform/dri/scanout_buffer.h"
19 ScreenManager::ScreenManager(DriWrapper* dri,
20 ScanoutBufferGenerator* buffer_generator)
21 : dri_(dri), buffer_generator_(buffer_generator) {
24 ScreenManager::~ScreenManager() {
27 void ScreenManager::AddDisplayController(uint32_t crtc, uint32_t connector) {
28 HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
29 // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
30 // properly supported. (When there can't be a race between forcing initial
31 // display configuration in ScreenManager and NativeDisplayDelegate creating
32 // the display controllers.)
33 if (it != controllers_.end()) {
34 LOG(WARNING) << "Display controller (crtc=" << crtc << ") already present.";
38 controllers_.push_back(new HardwareDisplayController(
39 dri_, scoped_ptr<CrtcState>(new CrtcState(dri_, crtc, connector))));
42 void ScreenManager::RemoveDisplayController(uint32_t crtc) {
43 HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
44 if (it != controllers_.end()) {
45 bool is_mirrored = (*it)->IsMirrored();
46 (*it)->RemoveCrtc(crtc);
48 controllers_.erase(it);
52 bool ScreenManager::ConfigureDisplayController(uint32_t crtc,
54 const gfx::Point& origin,
55 const drmModeModeInfo& mode) {
56 gfx::Rect modeset_bounds(
57 origin.x(), origin.y(), mode.hdisplay, mode.vdisplay);
58 HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
59 DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc
60 << ") doesn't exist.";
62 HardwareDisplayController* controller = *it;
64 // If nothing changed just enable the controller. Note, we perform an exact
65 // comparison on the mode since the refresh rate may have changed.
66 if (SameMode(mode, controller->get_mode()) &&
67 origin == controller->origin() && !controller->IsDisabled())
68 return controller->Enable();
70 // Either the mode or the location of the display changed, so exit mirror
71 // mode and configure the display independently. If the caller still wants
72 // mirror mode, subsequent calls configuring the other controllers will
73 // restore mirror mode.
74 if (controller->IsMirrored()) {
76 new HardwareDisplayController(dri_, controller->RemoveCrtc(crtc));
77 controllers_.push_back(controller);
78 it = controllers_.end() - 1;
81 HardwareDisplayControllers::iterator mirror =
82 FindActiveDisplayControllerByLocation(modeset_bounds);
83 // Handle mirror mode.
84 if (mirror != controllers_.end() && it != mirror)
85 return HandleMirrorMode(it, mirror, crtc, connector);
87 return ModesetDisplayController(controller, origin, mode);
90 bool ScreenManager::DisableDisplayController(uint32_t crtc) {
91 HardwareDisplayControllers::iterator it = FindDisplayController(crtc);
92 if (it != controllers_.end()) {
93 if ((*it)->IsMirrored()) {
94 HardwareDisplayController* controller =
95 new HardwareDisplayController(dri_, (*it)->RemoveCrtc(crtc));
96 controllers_.push_back(controller);
103 LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
107 base::WeakPtr<HardwareDisplayController> ScreenManager::GetDisplayController(
108 const gfx::Rect& bounds) {
109 // TODO(dnicoara): Remove hack once TestScreen uses a simple Ozone display
110 // configuration reader and ScreenManager is called from there to create the
111 // one display needed by the content_shell target.
112 if (controllers_.empty())
113 ForceInitializationOfPrimaryDisplay();
115 HardwareDisplayControllers::iterator it =
116 FindActiveDisplayControllerByLocation(bounds);
117 if (it != controllers_.end())
118 return (*it)->AsWeakPtr();
120 return base::WeakPtr<HardwareDisplayController>();
123 ScreenManager::HardwareDisplayControllers::iterator
124 ScreenManager::FindDisplayController(uint32_t crtc) {
125 for (HardwareDisplayControllers::iterator it = controllers_.begin();
126 it != controllers_.end();
128 if ((*it)->HasCrtc(crtc))
132 return controllers_.end();
135 ScreenManager::HardwareDisplayControllers::iterator
136 ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
137 for (HardwareDisplayControllers::iterator it = controllers_.begin();
138 it != controllers_.end();
140 gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
141 // We don't perform a strict check since content_shell will have windows
142 // smaller than the display size.
143 if (controller_bounds.Contains(bounds) && !(*it)->IsDisabled())
147 return controllers_.end();
150 void ScreenManager::ForceInitializationOfPrimaryDisplay() {
151 LOG(WARNING) << "Forcing initialization of primary display.";
152 ScopedVector<HardwareDisplayControllerInfo> displays =
153 GetAvailableDisplayControllerInfos(dri_->get_fd());
155 DCHECK_NE(0u, displays.size());
157 ScopedDrmPropertyPtr dpms(
158 dri_->GetProperty(displays[0]->connector(), "DPMS"));
160 dri_->SetProperty(displays[0]->connector()->connector_id,
164 AddDisplayController(displays[0]->crtc()->crtc_id,
165 displays[0]->connector()->connector_id);
166 ConfigureDisplayController(displays[0]->crtc()->crtc_id,
167 displays[0]->connector()->connector_id,
169 displays[0]->connector()->modes[0]);
172 bool ScreenManager::ModesetDisplayController(
173 HardwareDisplayController* controller,
174 const gfx::Point& origin,
175 const drmModeModeInfo& mode) {
176 controller->set_origin(origin);
177 // Create a surface suitable for the current controller.
178 scoped_refptr<ScanoutBuffer> buffer =
179 buffer_generator_->Create(gfx::Size(mode.hdisplay, mode.vdisplay));
182 LOG(ERROR) << "Failed to create scanout buffer";
186 if (!controller->Modeset(OverlayPlane(buffer), mode)) {
187 LOG(ERROR) << "Failed to modeset controller";
194 bool ScreenManager::HandleMirrorMode(
195 HardwareDisplayControllers::iterator original,
196 HardwareDisplayControllers::iterator mirror,
198 uint32_t connector) {
199 (*mirror)->AddCrtc((*original)->RemoveCrtc(crtc));
200 if ((*mirror)->Enable()) {
201 controllers_.erase(original);
205 LOG(ERROR) << "Failed to switch to mirror mode";
207 // When things go wrong revert back to the previous configuration since
208 // it is expected that the configuration would not have changed if
210 (*original)->AddCrtc((*mirror)->RemoveCrtc(crtc));
211 (*original)->Enable();