Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / ozone / platform / drm / gpu / screen_manager.cc
blob4b4d3f13d75a1e813425e82198ceaa5b333a542a
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"
21 namespace ui {
23 namespace {
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();
33 return;
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";
42 return;
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;
50 return;
53 // Don't copy anything if the sizes mismatch. This can happen when the user
54 // changes modes.
55 if (saved_buffer.canvas()->getBaseLayerSize() !=
56 modeset_buffer.canvas()->getBaseLayerSize()) {
57 VLOG(2) << "Previous buffer has a different size than modeset buffer";
58 return;
61 skia::RefPtr<SkImage> image = saved_buffer.image();
62 SkPaint paint;
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);
68 } // namespace
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,
79 uint32_t crtc,
80 uint32_t connector) {
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.";
88 return;
91 controllers_.push_back(new HardwareDisplayController(
92 scoped_ptr<CrtcController>(new CrtcController(drm, crtc, connector)),
93 gfx::Point()));
96 void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
97 uint32_t crtc) {
98 HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
99 if (it != controllers_.end()) {
100 bool is_mirrored = (*it)->IsMirrored();
101 (*it)->RemoveCrtc(drm, crtc);
102 if (!is_mirrored) {
103 controllers_.erase(it);
104 UpdateControllerToWindowMapping();
109 bool ScreenManager::ConfigureDisplayController(
110 const scoped_refptr<DrmDevice>& drm,
111 uint32_t crtc,
112 uint32_t connector,
113 const gfx::Point& origin,
114 const drmModeModeInfo& mode) {
115 bool status =
116 ActualConfigureDisplayController(drm, crtc, connector, origin, mode);
117 if (status)
118 UpdateControllerToWindowMapping();
120 return status;
123 bool ScreenManager::ActualConfigureDisplayController(
124 const scoped_refptr<DrmDevice>& drm,
125 uint32_t crtc,
126 uint32_t connector,
127 const gfx::Point& origin,
128 const drmModeModeInfo& mode) {
129 gfx::Rect modeset_bounds(origin.x(), origin.y(), mode.hdisplay,
130 mode.vdisplay);
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
144 // mode.
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,
176 uint32_t crtc) {
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();
188 return true;
191 LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
192 return false;
195 HardwareDisplayController* ScreenManager::GetDisplayController(
196 const gfx::Rect& bounds) {
197 HardwareDisplayControllers::iterator it =
198 FindActiveDisplayControllerByLocation(bounds);
199 if (it != controllers_.end())
200 return *it;
202 return nullptr;
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())
224 return it->second;
226 NOTREACHED() << "Attempting to get non-existing window for " << widget;
227 return nullptr;
230 ScreenManager::HardwareDisplayControllers::iterator
231 ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm,
232 uint32_t crtc) {
233 for (HardwareDisplayControllers::iterator it = controllers_.begin();
234 it != controllers_.end(); ++it) {
235 if ((*it)->HasCrtc(drm, crtc))
236 return it;
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())
248 return it;
251 return controllers_.end();
254 bool ScreenManager::HandleMirrorMode(
255 HardwareDisplayControllers::iterator original,
256 HardwareDisplayControllers::iterator mirror,
257 const scoped_refptr<DrmDevice>& drm,
258 uint32_t crtc,
259 uint32_t connector) {
260 (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
261 if (EnableController(*mirror, (*mirror)->origin(), (*mirror)->get_mode())) {
262 controllers_.erase(original);
263 return true;
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
270 // things fail.
271 (*original)->AddCrtc((*mirror)->RemoveCrtc(drm, crtc));
272 EnableController(*original, (*original)->origin(), (*original)->get_mode());
273 return false;
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())
282 continue;
284 DrmWindow* window = FindWindowAt(
285 gfx::Rect(controller->origin(), controller->GetModeSize()));
286 if (!window)
287 continue;
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);
297 else
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);
310 if (window) {
311 const OverlayPlane* primary = window->GetLastModesetBuffer();
312 if (primary) {
313 if (!controller->Modeset(*primary, mode)) {
314 LOG(ERROR) << "Failed to modeset controller";
315 return false;
318 return true;
322 scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
323 scoped_refptr<ScanoutBuffer> buffer =
324 buffer_generator_->Create(drm, rect.size());
325 if (!buffer) {
326 LOG(ERROR) << "Failed to create scanout buffer";
327 return false;
330 FillModesetBuffer(drm, controller, buffer.get());
331 if (!controller->Modeset(OverlayPlane(buffer), mode)) {
332 LOG(ERROR) << "Failed to modeset controller";
333 return false;
336 return true;
339 DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
340 for (auto pair : window_map_) {
341 if (pair.second->bounds() == bounds)
342 return pair.second;
345 return nullptr;
348 } // namespace ui