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