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/drm/gpu/screen_manager.h"
7 #include <xf86drmMode.h>
9 #include "third_party/skia/include/core/SkCanvas.h"
10 #include "ui/gfx/geometry/point.h"
11 #include "ui/gfx/geometry/rect.h"
12 #include "ui/gfx/geometry/size.h"
13 #include "ui/ozone/platform/drm/common/drm_util.h"
14 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
15 #include "ui/ozone/platform/drm/gpu/drm_console_buffer.h"
16 #include "ui/ozone/platform/drm/gpu/drm_device.h"
17 #include "ui/ozone/platform/drm/gpu/drm_window.h"
18 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
19 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
25 // Copies the contents of the saved framebuffer from the CRTCs in |controller|
26 // to the new modeset buffer |buffer|.
27 void FillModesetBuffer(const scoped_refptr
<DrmDevice
>& drm
,
28 HardwareDisplayController
* controller
,
29 ScanoutBuffer
* buffer
) {
30 DrmConsoleBuffer
modeset_buffer(drm
, buffer
->GetFramebufferId());
31 if (!modeset_buffer
.Initialize()) {
32 VLOG(2) << "Failed to grab framebuffer " << buffer
->GetFramebufferId();
36 auto crtcs
= controller
->crtc_controllers();
37 DCHECK(!crtcs
.empty());
39 ScopedDrmCrtcPtr
saved_crtc(drm
->GetCrtc(crtcs
[0]->crtc()));
40 if (!saved_crtc
|| !saved_crtc
->buffer_id
) {
41 VLOG(2) << "Crtc has no saved state or wasn't modeset";
45 // If the display controller is in mirror mode, the CRTCs should be sharing
46 // the same framebuffer.
47 DrmConsoleBuffer
saved_buffer(drm
, saved_crtc
->buffer_id
);
48 if (!saved_buffer
.Initialize()) {
49 VLOG(2) << "Failed to grab saved framebuffer " << saved_crtc
->buffer_id
;
53 // Don't copy anything if the sizes mismatch. This can happen when the user
55 if (saved_buffer
.canvas()->getBaseLayerSize() !=
56 modeset_buffer
.canvas()->getBaseLayerSize()) {
57 VLOG(2) << "Previous buffer has a different size than modeset buffer";
61 skia::RefPtr
<SkImage
> image
= saved_buffer
.image();
63 // Copy the source buffer. Do not perform any blending.
64 paint
.setXfermodeMode(SkXfermode::kSrc_Mode
);
65 modeset_buffer
.canvas()->drawImage(image
.get(), 0, 0, &paint
);
70 ScreenManager::ScreenManager(ScanoutBufferGenerator
* buffer_generator
)
71 : buffer_generator_(buffer_generator
) {
74 ScreenManager::~ScreenManager() {
75 DCHECK(window_map_
.empty());
78 void ScreenManager::AddDisplayController(const scoped_refptr
<DrmDevice
>& drm
,
81 HardwareDisplayControllers::iterator it
= FindDisplayController(drm
, crtc
);
82 // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
83 // properly supported. (When there can't be a race between forcing initial
84 // display configuration in ScreenManager and NativeDisplayDelegate creating
85 // the display controllers.)
86 if (it
!= controllers_
.end()) {
87 LOG(WARNING
) << "Display controller (crtc=" << crtc
<< ") already present.";
91 controllers_
.push_back(new HardwareDisplayController(
92 scoped_ptr
<CrtcController
>(new CrtcController(drm
, crtc
, connector
)),
96 void ScreenManager::RemoveDisplayController(const scoped_refptr
<DrmDevice
>& drm
,
98 HardwareDisplayControllers::iterator it
= FindDisplayController(drm
, crtc
);
99 if (it
!= controllers_
.end()) {
100 bool is_mirrored
= (*it
)->IsMirrored();
101 (*it
)->RemoveCrtc(drm
, crtc
);
103 controllers_
.erase(it
);
104 UpdateControllerToWindowMapping();
109 bool ScreenManager::ConfigureDisplayController(
110 const scoped_refptr
<DrmDevice
>& drm
,
113 const gfx::Point
& origin
,
114 const drmModeModeInfo
& mode
) {
116 ActualConfigureDisplayController(drm
, crtc
, connector
, origin
, mode
);
118 UpdateControllerToWindowMapping();
123 bool ScreenManager::ActualConfigureDisplayController(
124 const scoped_refptr
<DrmDevice
>& drm
,
127 const gfx::Point
& origin
,
128 const drmModeModeInfo
& mode
) {
129 gfx::Rect
modeset_bounds(origin
.x(), origin
.y(), mode
.hdisplay
,
131 HardwareDisplayControllers::iterator it
= FindDisplayController(drm
, crtc
);
132 DCHECK(controllers_
.end() != it
) << "Display controller (crtc=" << crtc
133 << ") doesn't exist.";
135 HardwareDisplayController
* controller
= *it
;
136 // If nothing changed just enable the controller. Note, we perform an exact
137 // comparison on the mode since the refresh rate may have changed.
138 if (SameMode(mode
, controller
->get_mode()) &&
139 origin
== controller
->origin()) {
140 if (controller
->IsDisabled()) {
141 HardwareDisplayControllers::iterator mirror
=
142 FindActiveDisplayControllerByLocation(modeset_bounds
);
143 // If there is an active controller at the same location then start mirror
145 if (mirror
!= controllers_
.end())
146 return HandleMirrorMode(it
, mirror
, drm
, crtc
, connector
);
149 // Just re-enable the controller to re-use the current state.
150 return EnableController(controller
, controller
->origin(),
151 controller
->get_mode());
154 // Either the mode or the location of the display changed, so exit mirror
155 // mode and configure the display independently. If the caller still wants
156 // mirror mode, subsequent calls configuring the other controllers will
157 // restore mirror mode.
158 if (controller
->IsMirrored()) {
159 controller
= new HardwareDisplayController(
160 controller
->RemoveCrtc(drm
, crtc
), controller
->origin());
161 controllers_
.push_back(controller
);
162 it
= controllers_
.end() - 1;
165 HardwareDisplayControllers::iterator mirror
=
166 FindActiveDisplayControllerByLocation(modeset_bounds
);
167 // Handle mirror mode.
168 if (mirror
!= controllers_
.end() && it
!= mirror
)
169 return HandleMirrorMode(it
, mirror
, drm
, crtc
, connector
);
171 return EnableController(controller
, origin
, mode
);
174 bool ScreenManager::DisableDisplayController(
175 const scoped_refptr
<DrmDevice
>& drm
,
177 HardwareDisplayControllers::iterator it
= FindDisplayController(drm
, crtc
);
178 if (it
!= controllers_
.end()) {
179 HardwareDisplayController
* controller
= *it
;
180 if (controller
->IsMirrored()) {
181 controller
= new HardwareDisplayController(
182 controller
->RemoveCrtc(drm
, crtc
), controller
->origin());
183 controllers_
.push_back(controller
);
186 controller
->Disable();
187 UpdateControllerToWindowMapping();
191 LOG(ERROR
) << "Failed to find display controller crtc=" << crtc
;
195 HardwareDisplayController
* ScreenManager::GetDisplayController(
196 const gfx::Rect
& bounds
) {
197 HardwareDisplayControllers::iterator it
=
198 FindActiveDisplayControllerByLocation(bounds
);
199 if (it
!= controllers_
.end())
205 void ScreenManager::AddWindow(gfx::AcceleratedWidget widget
,
206 scoped_ptr
<DrmWindow
> window
) {
207 std::pair
<WidgetToWindowMap::iterator
, bool> result
=
208 window_map_
.add(widget
, window
.Pass());
209 DCHECK(result
.second
) << "Window already added.";
210 UpdateControllerToWindowMapping();
213 scoped_ptr
<DrmWindow
> ScreenManager::RemoveWindow(
214 gfx::AcceleratedWidget widget
) {
215 scoped_ptr
<DrmWindow
> window
= window_map_
.take_and_erase(widget
);
216 DCHECK(window
) << "Attempting to remove non-existing window for " << widget
;
217 UpdateControllerToWindowMapping();
218 return window
.Pass();
221 DrmWindow
* ScreenManager::GetWindow(gfx::AcceleratedWidget widget
) {
222 WidgetToWindowMap::iterator it
= window_map_
.find(widget
);
223 if (it
!= window_map_
.end())
226 NOTREACHED() << "Attempting to get non-existing window for " << widget
;
230 ScreenManager::HardwareDisplayControllers::iterator
231 ScreenManager::FindDisplayController(const scoped_refptr
<DrmDevice
>& drm
,
233 for (HardwareDisplayControllers::iterator it
= controllers_
.begin();
234 it
!= controllers_
.end(); ++it
) {
235 if ((*it
)->HasCrtc(drm
, crtc
))
239 return controllers_
.end();
242 ScreenManager::HardwareDisplayControllers::iterator
243 ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect
& bounds
) {
244 for (HardwareDisplayControllers::iterator it
= controllers_
.begin();
245 it
!= controllers_
.end(); ++it
) {
246 gfx::Rect
controller_bounds((*it
)->origin(), (*it
)->GetModeSize());
247 if (controller_bounds
== bounds
&& !(*it
)->IsDisabled())
251 return controllers_
.end();
254 bool ScreenManager::HandleMirrorMode(
255 HardwareDisplayControllers::iterator original
,
256 HardwareDisplayControllers::iterator mirror
,
257 const scoped_refptr
<DrmDevice
>& drm
,
259 uint32_t connector
) {
260 (*mirror
)->AddCrtc((*original
)->RemoveCrtc(drm
, crtc
));
261 if (EnableController(*mirror
, (*mirror
)->origin(), (*mirror
)->get_mode())) {
262 controllers_
.erase(original
);
266 LOG(ERROR
) << "Failed to switch to mirror mode";
268 // When things go wrong revert back to the previous configuration since
269 // it is expected that the configuration would not have changed if
271 (*original
)->AddCrtc((*mirror
)->RemoveCrtc(drm
, crtc
));
272 EnableController(*original
, (*original
)->origin(), (*original
)->get_mode());
276 void ScreenManager::UpdateControllerToWindowMapping() {
277 std::map
<DrmWindow
*, HardwareDisplayController
*> window_to_controller_map
;
278 // First create a unique mapping between a window and a controller. Note, a
279 // controller may be associated with at most 1 window.
280 for (HardwareDisplayController
* controller
: controllers_
) {
281 if (controller
->IsDisabled())
284 DrmWindow
* window
= FindWindowAt(
285 gfx::Rect(controller
->origin(), controller
->GetModeSize()));
289 window_to_controller_map
[window
] = controller
;
292 // Apply the new mapping to all windows.
293 for (auto pair
: window_map_
) {
294 auto it
= window_to_controller_map
.find(pair
.second
);
295 if (it
!= window_to_controller_map
.end())
296 pair
.second
->SetController(it
->second
);
298 pair
.second
->SetController(nullptr);
302 bool ScreenManager::EnableController(HardwareDisplayController
* controller
,
303 const gfx::Point
& origin
,
304 const drmModeModeInfo
& mode
) {
305 DCHECK(!controller
->crtc_controllers().empty());
306 gfx::Rect
rect(origin
, gfx::Size(mode
.hdisplay
, mode
.vdisplay
));
307 controller
->set_origin(origin
);
309 DrmWindow
* window
= FindWindowAt(rect
);
311 const OverlayPlane
* primary
= window
->GetLastModesetBuffer();
313 if (!controller
->Modeset(*primary
, mode
)) {
314 LOG(ERROR
) << "Failed to modeset controller";
322 scoped_refptr
<DrmDevice
> drm
= controller
->GetAllocationDrmDevice();
323 scoped_refptr
<ScanoutBuffer
> buffer
=
324 buffer_generator_
->Create(drm
, rect
.size());
326 LOG(ERROR
) << "Failed to create scanout buffer";
330 FillModesetBuffer(drm
, controller
, buffer
.get());
331 if (!controller
->Modeset(OverlayPlane(buffer
), mode
)) {
332 LOG(ERROR
) << "Failed to modeset controller";
339 DrmWindow
* ScreenManager::FindWindowAt(const gfx::Rect
& bounds
) const {
340 for (auto pair
: window_map_
) {
341 if (pair
.second
->bounds() == bounds
)