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.
4
5 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
6
7 #include <xf86drmMode.h>
8 #include <memory>
9 #include <utility>
10
11 #include "base/files/platform_file.h"
12 #include "base/logging.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkSurface.h"
15 #include "ui/display/types/display_snapshot.h"
16 #include "ui/gfx/geometry/point.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/gfx/gpu_fence.h"
20 #include "ui/gfx/linux/gbm_buffer.h"
21 #include "ui/gfx/skia_util.h"
22 #include "ui/ozone/platform/drm/common/drm_util.h"
23 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
24 #include "ui/ozone/platform/drm/gpu/drm_device.h"
25 #include "ui/ozone/platform/drm/gpu/drm_dumb_buffer.h"
26 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
27 #include "ui/ozone/platform/drm/gpu/drm_window.h"
28 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
29
30 namespace ui {
31
32 namespace {
33
34 // Copies the contents of the saved framebuffer from the CRTCs in |controller|
35 // to the surface for the new modeset buffer |surface|.
FillModesetBuffer(const scoped_refptr<DrmDevice> & drm,HardwareDisplayController * controller,SkSurface * surface,uint32_t fourcc_format)36 bool FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
37 HardwareDisplayController* controller,
38 SkSurface* surface,
39 uint32_t fourcc_format) {
40 DCHECK(!controller->crtc_controllers().empty());
41 CrtcController* first_crtc = controller->crtc_controllers()[0].get();
42 ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(first_crtc->crtc()));
43 if (!saved_crtc || !saved_crtc->buffer_id) {
44 VLOG(2) << "Crtc has no saved state or wasn't modeset";
45 return false;
46 }
47
48 const auto& modifiers = controller->GetFormatModifiers(fourcc_format);
49 for (const uint64_t modifier : modifiers) {
50 // A value of 0 means DRM_FORMAT_MOD_NONE. If the CRTC has any other
51 // modifier (tiling, compression, etc.) we can't read the fb and assume it's
52 // a linear buffer.
53 if (modifier) {
54 VLOG(2) << "Crtc has a modifier and we might not know how to interpret "
55 "the fb.";
56 return false;
57 }
58 }
59
60 // If the display controller is in mirror mode, the CRTCs should be sharing
61 // the same framebuffer.
62 DrmDumbBuffer saved_buffer(drm);
63 if (!saved_buffer.InitializeFromFramebuffer(saved_crtc->buffer_id)) {
64 VLOG(2) << "Failed to grab saved framebuffer " << saved_crtc->buffer_id;
65 return false;
66 }
67
68 // Don't copy anything if the sizes mismatch. This can happen when the user
69 // changes modes.
70 if (saved_buffer.GetCanvas()->getBaseLayerSize() !=
71 surface->getCanvas()->getBaseLayerSize()) {
72 VLOG(2) << "Previous buffer has a different size than modeset buffer";
73 return false;
74 }
75
76 SkPaint paint;
77 // Copy the source buffer. Do not perform any blending.
78 paint.setBlendMode(SkBlendMode::kSrc);
79 surface->getCanvas()->drawImage(saved_buffer.surface()->makeImageSnapshot(),
80 0, 0, &paint);
81 return true;
82 }
83
GetCrtcController(HardwareDisplayController * controller,const scoped_refptr<DrmDevice> & drm,uint32_t crtc)84 CrtcController* GetCrtcController(HardwareDisplayController* controller,
85 const scoped_refptr<DrmDevice>& drm,
86 uint32_t crtc) {
87 for (const auto& crtc_controller : controller->crtc_controllers()) {
88 if (crtc_controller->crtc() == crtc)
89 return crtc_controller.get();
90 }
91
92 NOTREACHED();
93 return nullptr;
94 }
95
GetModifiersForPrimaryFormat(HardwareDisplayController * controller)96 std::vector<uint64_t> GetModifiersForPrimaryFormat(
97 HardwareDisplayController* controller) {
98 gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat();
99 uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format);
100 return controller->GetFormatModifiersForModesetting(fourcc_format);
101 }
102
AreAllStatusesTrue(base::flat_map<int64_t,bool> & display_statuses)103 bool AreAllStatusesTrue(base::flat_map<int64_t, bool>& display_statuses) {
104 auto it = find_if(display_statuses.begin(), display_statuses.end(),
105 [](const auto status) { return status.second == false; });
106 return (it == display_statuses.end());
107 }
108
109 } // namespace
110
111 ScreenManager::ScreenManager() = default;
112
~ScreenManager()113 ScreenManager::~ScreenManager() {
114 DCHECK(window_map_.empty());
115 }
116
ControllerConfigParams(int64_t display_id,scoped_refptr<DrmDevice> drm,uint32_t crtc,uint32_t connector,gfx::Point origin,std::unique_ptr<drmModeModeInfo> pmode)117 ScreenManager::ControllerConfigParams::ControllerConfigParams(
118 int64_t display_id,
119 scoped_refptr<DrmDevice> drm,
120 uint32_t crtc,
121 uint32_t connector,
122 gfx::Point origin,
123 std::unique_ptr<drmModeModeInfo> pmode)
124 : display_id(display_id),
125 drm(drm),
126 crtc(crtc),
127 connector(connector),
128 origin(origin),
129 mode(std::move(pmode)) {}
130
ControllerConfigParams(const ControllerConfigParams & other)131 ScreenManager::ControllerConfigParams::ControllerConfigParams(
132 const ControllerConfigParams& other)
133 : display_id(other.display_id),
134 drm(other.drm),
135 crtc(other.crtc),
136 connector(other.connector),
137 origin(other.origin) {
138 if (other.mode) {
139 drmModeModeInfo mode_obj = *other.mode.get();
140 mode = std::make_unique<drmModeModeInfo>(mode_obj);
141 }
142 }
143
ControllerConfigParams(ControllerConfigParams && other)144 ScreenManager::ControllerConfigParams::ControllerConfigParams(
145 ControllerConfigParams&& other)
146 : display_id(other.display_id),
147 drm(other.drm),
148 crtc(other.crtc),
149 connector(other.connector),
150 origin(other.origin) {
151 if (other.mode) {
152 drmModeModeInfo mode_obj = *other.mode.get();
153 mode = std::make_unique<drmModeModeInfo>(mode_obj);
154 }
155 }
156
157 ScreenManager::ControllerConfigParams::~ControllerConfigParams() = default;
158
AddDisplayController(const scoped_refptr<DrmDevice> & drm,uint32_t crtc,uint32_t connector)159 void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
160 uint32_t crtc,
161 uint32_t connector) {
162 HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
163 // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
164 // properly supported. (When there can't be a race between forcing initial
165 // display configuration in ScreenManager and display::NativeDisplayDelegate
166 // creating the display controllers.)
167 if (it != controllers_.end()) {
168 LOG(WARNING) << "Display controller (crtc=" << crtc << ") already present.";
169 return;
170 }
171
172 controllers_.push_back(std::make_unique<HardwareDisplayController>(
173 std::make_unique<CrtcController>(drm, crtc, connector), gfx::Point()));
174 }
175
RemoveDisplayControllers(const CrtcsWithDrmList & controllers_to_remove)176 void ScreenManager::RemoveDisplayControllers(
177 const CrtcsWithDrmList& controllers_to_remove) {
178 // Split them to different lists unique to each DRM Device.
179 base::flat_map<scoped_refptr<DrmDevice>, CrtcsWithDrmList>
180 controllers_for_drm_devices;
181 for (const auto& controller : controllers_to_remove) {
182 auto drm = controller.second;
183 auto it = controllers_for_drm_devices.find(drm);
184 if (it == controllers_for_drm_devices.end()) {
185 controllers_for_drm_devices.insert(
186 std::make_pair(drm, CrtcsWithDrmList()));
187 }
188 controllers_for_drm_devices[drm].emplace_back(controller);
189 }
190
191 bool should_update_controllers_to_window_mapping = false;
192 for (const auto& controllers_on_drm : controllers_for_drm_devices) {
193 CrtcsWithDrmList controllers_to_remove = controllers_on_drm.second;
194
195 CommitRequest commit_request;
196 auto drm = controllers_on_drm.first;
197 for (const auto& controller : controllers_to_remove) {
198 uint32_t crtc_id = controller.first;
199 auto it = FindDisplayController(drm, crtc_id);
200 if (it == controllers_.end())
201 continue;
202
203 bool is_mirrored = (*it)->IsMirrored();
204
205 std::unique_ptr<CrtcController> crtc = (*it)->RemoveCrtc(drm, crtc_id);
206 if (crtc->is_enabled()) {
207 commit_request.push_back(CrtcCommitRequest::DisableCrtcRequest(
208 crtc->crtc(), crtc->connector()));
209 }
210
211 if (!is_mirrored) {
212 controllers_.erase(it);
213 should_update_controllers_to_window_mapping = true;
214 }
215 }
216 if (!commit_request.empty()) {
217 drm->plane_manager()->Commit(std::move(commit_request),
218 DRM_MODE_ATOMIC_ALLOW_MODESET);
219 }
220 }
221
222 if (should_update_controllers_to_window_mapping)
223 UpdateControllerToWindowMapping();
224 }
225
ConfigureDisplayControllers(const ControllerConfigsList & controllers_params)226 base::flat_map<int64_t, bool> ScreenManager::ConfigureDisplayControllers(
227 const ControllerConfigsList& controllers_params) {
228 // Split them to different lists unique to each DRM Device.
229 base::flat_map<scoped_refptr<DrmDevice>, ControllerConfigsList>
230 displays_for_drm_devices;
231
232 for (auto& params : controllers_params) {
233 auto it = displays_for_drm_devices.find(params.drm);
234 if (it == displays_for_drm_devices.end()) {
235 displays_for_drm_devices.insert(
236 std::make_pair(params.drm, ControllerConfigsList()));
237 }
238 displays_for_drm_devices[params.drm].emplace_back(params);
239 }
240
241 base::flat_map<int64_t, bool> statuses;
242 // Perform display configurations together for the same DRM only.
243 for (const auto& configs_on_drm : displays_for_drm_devices) {
244 auto display_statuses = TestAndModeset(configs_on_drm.second);
245 statuses.insert(display_statuses.begin(), display_statuses.end());
246 }
247
248 if (AreAllStatusesTrue(statuses))
249 UpdateControllerToWindowMapping();
250
251 return statuses;
252 }
253
TestAndModeset(const ControllerConfigsList & controllers_params)254 base::flat_map<int64_t, bool> ScreenManager::TestAndModeset(
255 const ControllerConfigsList& controllers_params) {
256 if (!TestModeset(controllers_params)) {
257 base::flat_map<int64_t, bool> statuses;
258 for (const auto& params : controllers_params)
259 statuses.insert(std::make_pair(params.display_id, false));
260 return statuses;
261 }
262
263 return Modeset(controllers_params);
264 }
265
TestModeset(const ControllerConfigsList & controllers_params)266 bool ScreenManager::TestModeset(
267 const ControllerConfigsList& controllers_params) {
268 CommitRequest commit_request;
269 auto drm = controllers_params[0].drm;
270
271 for (const auto& params : controllers_params) {
272 auto it = FindDisplayController(params.drm, params.crtc);
273 DCHECK(controllers_.end() != it);
274 HardwareDisplayController* controller = it->get();
275
276 if (params.mode) {
277 DrmOverlayPlane primary_plane = GetModesetBuffer(
278 controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
279 GetModifiersForPrimaryFormat(controller));
280 if (!primary_plane.buffer)
281 return false;
282
283 GetModesetControllerProps(&commit_request, controller, params.origin,
284 *params.mode, primary_plane);
285 } else {
286 controller->GetDisableProps(&commit_request);
287 }
288 }
289
290 return drm->plane_manager()->Commit(
291 std::move(commit_request),
292 DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET);
293 }
294
Modeset(const ControllerConfigsList & controllers_params)295 base::flat_map<int64_t, bool> ScreenManager::Modeset(
296 const ControllerConfigsList& controllers_params) {
297 base::flat_map<int64_t, bool> statuses;
298
299 for (const auto& params : controllers_params) {
300 // Commit one controller at a time.
301 CommitRequest commit_request;
302 bool status = true;
303 if (params.mode) {
304 auto it = FindDisplayController(params.drm, params.crtc);
305 DCHECK(controllers_.end() != it);
306 HardwareDisplayController* controller = it->get();
307
308 DrmOverlayPlane primary_plane = GetModesetBuffer(
309 controller, gfx::Rect(params.origin, ModeSize(*params.mode)),
310 GetModifiersForPrimaryFormat(controller));
311 if (primary_plane.buffer) {
312 SetDisplayControllerForEnableAndGetProps(
313 &commit_request, params.drm, params.crtc, params.connector,
314 params.origin, *params.mode, primary_plane);
315 } else {
316 status = false;
317 }
318
319 } else {
320 status = SetDisableDisplayControllerForDisableAndGetProps(
321 &commit_request, params.drm, params.crtc);
322 }
323
324 CommitRequest request_for_update = commit_request;
325 if (status) {
326 status &= params.drm->plane_manager()->Commit(
327 std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
328 UpdateControllerStateAfterModeset(params, request_for_update, status);
329 }
330
331 statuses.insert(std::make_pair(params.display_id, status));
332 }
333
334 return statuses;
335 }
336
SetDisplayControllerForEnableAndGetProps(CommitRequest * commit_request,const scoped_refptr<DrmDevice> & drm,uint32_t crtc,uint32_t connector,const gfx::Point & origin,const drmModeModeInfo & mode,const DrmOverlayPlane & primary)337 void ScreenManager::SetDisplayControllerForEnableAndGetProps(
338 CommitRequest* commit_request,
339 const scoped_refptr<DrmDevice>& drm,
340 uint32_t crtc,
341 uint32_t connector,
342 const gfx::Point& origin,
343 const drmModeModeInfo& mode,
344 const DrmOverlayPlane& primary) {
345 HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
346 DCHECK(controllers_.end() != it)
347 << "Display controller (crtc=" << crtc << ") doesn't exist.";
348
349 HardwareDisplayController* controller = it->get();
350 CrtcController* crtc_controller = GetCrtcController(controller, drm, crtc);
351 // If nothing changed just enable the controller. Note, we perform an exact
352 // comparison on the mode since the refresh rate may have changed.
353 if (SameMode(mode, crtc_controller->mode()) &&
354 origin == controller->origin()) {
355 if (!controller->IsEnabled()) {
356 // Even if there is a mirrored display, Modeset the CRTC with its mode in
357 // the original controller so that only this CRTC is affected by the mode.
358 // Otherwise it could apply a mode with the same resolution and refresh
359 // rate but with different timings to the other CRTC.
360 GetModesetControllerProps(commit_request, controller,
361 controller->origin(), mode, primary);
362 } else {
363 // Just get props to re-enable the controller re-using the current state.
364 GetEnableControllerProps(commit_request, controller, primary);
365 }
366 return;
367 }
368
369 // Either the mode or the location of the display changed, so exit mirror
370 // mode and configure the display independently. If the caller still wants
371 // mirror mode, subsequent calls configuring the other controllers will
372 // restore mirror mode.
373 if (controller->IsMirrored()) {
374 controllers_.push_back(std::make_unique<HardwareDisplayController>(
375 controller->RemoveCrtc(drm, crtc), controller->origin()));
376 it = controllers_.end() - 1;
377 controller = it->get();
378 }
379
380 GetModesetControllerProps(commit_request, controller, origin, mode, primary);
381 }
382
SetDisableDisplayControllerForDisableAndGetProps(CommitRequest * commit_request,const scoped_refptr<DrmDevice> & drm,uint32_t crtc)383 bool ScreenManager::SetDisableDisplayControllerForDisableAndGetProps(
384 CommitRequest* commit_request,
385 const scoped_refptr<DrmDevice>& drm,
386 uint32_t crtc) {
387 HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
388 if (it != controllers_.end()) {
389 HardwareDisplayController* controller = it->get();
390 if (controller->IsMirrored()) {
391 controllers_.push_back(std::make_unique<HardwareDisplayController>(
392 controller->RemoveCrtc(drm, crtc), controller->origin()));
393 controller = controllers_.back().get();
394 }
395
396 controller->GetDisableProps(commit_request);
397 return true;
398 }
399
400 LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
401 return false;
402 }
403
UpdateControllerStateAfterModeset(const ControllerConfigParams & config,const CommitRequest & commit_request,bool did_succeed)404 void ScreenManager::UpdateControllerStateAfterModeset(
405 const ControllerConfigParams& config,
406 const CommitRequest& commit_request,
407 bool did_succeed) {
408 for (auto& crtc_request : commit_request) {
409 bool was_enabled = (crtc_request.should_enable());
410
411 HardwareDisplayControllers::iterator it =
412 FindDisplayController(config.drm, crtc_request.crtc_id());
413 if (it != controllers_.end()) {
414 it->get()->UpdateState(was_enabled, DrmOverlayPlane::GetPrimaryPlane(
415 crtc_request.overlays()));
416
417 // If the CRTC is mirrored, move it to the mirror controller.
418 if (did_succeed && was_enabled)
419 HandleMirrorIfExists(config, it);
420 }
421 }
422 }
423
HandleMirrorIfExists(const ControllerConfigParams & config,const HardwareDisplayControllers::iterator & controller)424 void ScreenManager::HandleMirrorIfExists(
425 const ControllerConfigParams& config,
426 const HardwareDisplayControllers::iterator& controller) {
427 gfx::Rect modeset_bounds(config.origin, ModeSize(*config.mode));
428 HardwareDisplayControllers::iterator mirror =
429 FindActiveDisplayControllerByLocation(config.drm, modeset_bounds);
430 // TODO(dnicoara): This is hacky, instead the DrmDisplay and
431 // CrtcController should be merged and picking the mode should be done
432 // properly within HardwareDisplayController.
433 if (mirror != controllers_.end() && controller != mirror) {
434 // TODO(markyacoub): RemoveCrtc makes a blocking commit to
435 // DisableOverlayPlanes. This should be redesigned and included as part of
436 // the Modeset commit.
437 (*mirror)->AddCrtc((*controller)->RemoveCrtc(config.drm, config.crtc));
438 controllers_.erase(controller);
439 }
440 }
441
GetDisplayController(const gfx::Rect & bounds)442 HardwareDisplayController* ScreenManager::GetDisplayController(
443 const gfx::Rect& bounds) {
444 HardwareDisplayControllers::iterator it =
445 FindActiveDisplayControllerByLocation(bounds);
446 if (it != controllers_.end())
447 return it->get();
448
449 return nullptr;
450 }
451
AddWindow(gfx::AcceleratedWidget widget,std::unique_ptr<DrmWindow> window)452 void ScreenManager::AddWindow(gfx::AcceleratedWidget widget,
453 std::unique_ptr<DrmWindow> window) {
454 std::pair<WidgetToWindowMap::iterator, bool> result =
455 window_map_.emplace(widget, std::move(window));
456 DCHECK(result.second) << "Window already added.";
457 UpdateControllerToWindowMapping();
458 }
459
RemoveWindow(gfx::AcceleratedWidget widget)460 std::unique_ptr<DrmWindow> ScreenManager::RemoveWindow(
461 gfx::AcceleratedWidget widget) {
462 std::unique_ptr<DrmWindow> window = std::move(window_map_[widget]);
463 window_map_.erase(widget);
464 DCHECK(window) << "Attempting to remove non-existing window for " << widget;
465 UpdateControllerToWindowMapping();
466 return window;
467 }
468
GetWindow(gfx::AcceleratedWidget widget)469 DrmWindow* ScreenManager::GetWindow(gfx::AcceleratedWidget widget) {
470 WidgetToWindowMap::iterator it = window_map_.find(widget);
471 if (it != window_map_.end())
472 return it->second.get();
473
474 return nullptr;
475 }
476
477 ScreenManager::HardwareDisplayControllers::iterator
FindDisplayController(const scoped_refptr<DrmDevice> & drm,uint32_t crtc)478 ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm,
479 uint32_t crtc) {
480 for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
481 if ((*it)->HasCrtc(drm, crtc))
482 return it;
483 }
484
485 return controllers_.end();
486 }
487
488 ScreenManager::HardwareDisplayControllers::iterator
FindActiveDisplayControllerByLocation(const gfx::Rect & bounds)489 ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
490 for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
491 gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
492 if (controller_bounds == bounds && (*it)->IsEnabled())
493 return it;
494 }
495
496 return controllers_.end();
497 }
498
499 ScreenManager::HardwareDisplayControllers::iterator
FindActiveDisplayControllerByLocation(const scoped_refptr<DrmDevice> & drm,const gfx::Rect & bounds)500 ScreenManager::FindActiveDisplayControllerByLocation(
501 const scoped_refptr<DrmDevice>& drm,
502 const gfx::Rect& bounds) {
503 for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
504 gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
505 if ((*it)->GetDrmDevice() == drm && controller_bounds == bounds &&
506 (*it)->IsEnabled())
507 return it;
508 }
509
510 return controllers_.end();
511 }
512
UpdateControllerToWindowMapping()513 void ScreenManager::UpdateControllerToWindowMapping() {
514 std::map<DrmWindow*, HardwareDisplayController*> window_to_controller_map;
515 // First create a unique mapping between a window and a controller. Note, a
516 // controller may be associated with at most 1 window.
517 for (const auto& controller : controllers_) {
518 if (!controller->IsEnabled())
519 continue;
520
521 DrmWindow* window = FindWindowAt(
522 gfx::Rect(controller->origin(), controller->GetModeSize()));
523 if (!window)
524 continue;
525
526 window_to_controller_map[window] = controller.get();
527 }
528
529 // Apply the new mapping to all windows.
530 for (auto& pair : window_map_) {
531 auto it = window_to_controller_map.find(pair.second.get());
532 HardwareDisplayController* controller = nullptr;
533 if (it != window_to_controller_map.end())
534 controller = it->second;
535
536 bool should_enable = controller && pair.second->GetController() &&
537 pair.second->GetController() != controller;
538 pair.second->SetController(controller);
539
540 // If we're moving windows between controllers modeset the controller
541 // otherwise the controller may be waiting for a page flip while the window
542 // tries to schedule another buffer.
543 if (should_enable) {
544 DrmOverlayPlane primary_plane = GetModesetBuffer(
545 controller,
546 gfx::Rect(controller->origin(), controller->GetModeSize()),
547 GetModifiersForPrimaryFormat(controller));
548 DCHECK(primary_plane.buffer);
549
550 CommitRequest commit_request;
551 GetEnableControllerProps(&commit_request, controller, primary_plane);
552 controller->GetDrmDevice()->plane_manager()->Commit(
553 std::move(commit_request), DRM_MODE_ATOMIC_ALLOW_MODESET);
554 }
555 }
556 }
557
GetModesetBuffer(HardwareDisplayController * controller,const gfx::Rect & bounds,const std::vector<uint64_t> & modifiers)558 DrmOverlayPlane ScreenManager::GetModesetBuffer(
559 HardwareDisplayController* controller,
560 const gfx::Rect& bounds,
561 const std::vector<uint64_t>& modifiers) {
562 scoped_refptr<DrmDevice> drm = controller->GetDrmDevice();
563 uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(
564 display::DisplaySnapshot::PrimaryFormat());
565 // Get the buffer that best reflects what the next Page Flip will look like,
566 // which is using the preferred modifiers from the controllers.
567 std::unique_ptr<GbmBuffer> buffer =
568 drm->gbm_device()->CreateBufferWithModifiers(
569 fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers);
570 if (!buffer) {
571 LOG(ERROR) << "Failed to create scanout buffer";
572 return DrmOverlayPlane::Error();
573 }
574
575 // If the current primary plane matches what we need for the next page flip,
576 // we can clone it.
577 DrmWindow* window = FindWindowAt(bounds);
578 if (window) {
579 const DrmOverlayPlane* primary = window->GetLastModesetBuffer();
580 const DrmDevice* drm = controller->GetDrmDevice().get();
581 if (primary && primary->buffer->size() == bounds.size() &&
582 primary->buffer->drm_device() == drm) {
583 if (primary->buffer->format_modifier() == buffer->GetFormatModifier())
584 return primary->Clone();
585 }
586 }
587
588 scoped_refptr<DrmFramebuffer> framebuffer = DrmFramebuffer::AddFramebuffer(
589 drm, buffer.get(), buffer->GetSize(), modifiers);
590 if (!framebuffer) {
591 LOG(ERROR) << "Failed to add framebuffer for scanout buffer";
592 return DrmOverlayPlane::Error();
593 }
594
595 sk_sp<SkSurface> surface = buffer->GetSurface();
596 if (!surface) {
597 VLOG(2) << "Can't get a SkSurface from the modeset gbm buffer.";
598 } else if (!FillModesetBuffer(drm, controller, surface.get(),
599 buffer->GetFormat())) {
600 // If we fail to fill the modeset buffer, clear it black to avoid displaying
601 // an uninitialized framebuffer.
602 surface->getCanvas()->clear(SK_ColorBLACK);
603 }
604 return DrmOverlayPlane(framebuffer, nullptr);
605 }
606
GetEnableControllerProps(CommitRequest * commit_request,HardwareDisplayController * controller,const DrmOverlayPlane & primary)607 void ScreenManager::GetEnableControllerProps(
608 CommitRequest* commit_request,
609 HardwareDisplayController* controller,
610 const DrmOverlayPlane& primary) {
611 DCHECK(!controller->crtc_controllers().empty());
612
613 controller->GetEnableProps(commit_request, primary);
614 }
615
GetModesetControllerProps(CommitRequest * commit_request,HardwareDisplayController * controller,const gfx::Point & origin,const drmModeModeInfo & mode,const DrmOverlayPlane & primary)616 void ScreenManager::GetModesetControllerProps(
617 CommitRequest* commit_request,
618 HardwareDisplayController* controller,
619 const gfx::Point& origin,
620 const drmModeModeInfo& mode,
621 const DrmOverlayPlane& primary) {
622 DCHECK(!controller->crtc_controllers().empty());
623
624 controller->set_origin(origin);
625 controller->GetModesetProps(commit_request, primary, mode);
626 }
627
FindWindowAt(const gfx::Rect & bounds) const628 DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
629 for (auto& pair : window_map_) {
630 if (pair.second->bounds() == bounds)
631 return pair.second.get();
632 }
633
634 return nullptr;
635 }
636
637 } // namespace ui
638