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/crtc_controller.h"
6 
7 #include <memory>
8 
9 #include "base/logging.h"
10 #include "base/time/time.h"
11 #include "ui/gfx/presentation_feedback.h"
12 #include "ui/ozone/platform/drm/gpu/drm_device.h"
13 #include "ui/ozone/platform/drm/gpu/drm_dumb_buffer.h"
14 #include "ui/ozone/platform/drm/gpu/drm_framebuffer.h"
15 #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
16 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
17 
18 namespace ui {
19 
CrtcController(const scoped_refptr<DrmDevice> & drm,uint32_t crtc,uint32_t connector)20 CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm,
21                                uint32_t crtc,
22                                uint32_t connector)
23     : drm_(drm),
24       crtc_(crtc),
25       connector_(connector) {}
26 
~CrtcController()27 CrtcController::~CrtcController() {
28   if (!is_disabled_) {
29     const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes =
30         drm_->plane_manager()->planes();
31     for (const auto& plane : all_planes) {
32       if (plane->owning_crtc() == crtc_) {
33         plane->set_owning_crtc(0);
34         plane->set_in_use(false);
35       }
36     }
37 
38     DisableCursor();
39     drm_->plane_manager()->DisableModeset(crtc_, connector_);
40   }
41 }
42 
Modeset(const DrmOverlayPlane & plane,const drmModeModeInfo & mode,const ui::HardwareDisplayPlaneList & plane_list)43 bool CrtcController::Modeset(const DrmOverlayPlane& plane,
44                              const drmModeModeInfo& mode,
45                              const ui::HardwareDisplayPlaneList& plane_list) {
46   if (!drm_->plane_manager()->Modeset(crtc_,
47                                       plane.buffer->opaque_framebuffer_id(),
48                                       connector_, mode, plane_list)) {
49     PLOG(ERROR) << "Failed to modeset: crtc=" << crtc_
50                 << " connector=" << connector_
51                 << " framebuffer_id=" << plane.buffer->opaque_framebuffer_id()
52                 << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
53                 << mode.vrefresh;
54     return false;
55   }
56 
57   mode_ = mode;
58   is_disabled_ = false;
59 
60   // Hold modeset buffer until page flip. This fixes a crash on entering
61   // hardware mirror mode in some circumstances (bug 888553).
62   // TODO(spang): Fix this better by changing how mirrors are set up (bug
63   // 899352).
64   modeset_framebuffer_ = plane.buffer;
65 
66   return true;
67 }
68 
Disable()69 bool CrtcController::Disable() {
70   if (is_disabled_)
71     return true;
72 
73   is_disabled_ = true;
74   DisableCursor();
75   return drm_->plane_manager()->DisableModeset(crtc_, connector_);
76 }
77 
AssignOverlayPlanes(HardwareDisplayPlaneList * plane_list,const DrmOverlayPlaneList & overlays,bool is_modesetting)78 bool CrtcController::AssignOverlayPlanes(HardwareDisplayPlaneList* plane_list,
79                                          const DrmOverlayPlaneList& overlays,
80                                          bool is_modesetting) {
81   // If we're in the process of modesetting, the CRTC is still disabled.
82   // Once the modeset is done, we expect it to be enabled.
83   DCHECK(is_modesetting || !is_disabled_);
84 
85   const DrmOverlayPlane* primary = DrmOverlayPlane::GetPrimaryPlane(overlays);
86   if (primary && !drm_->plane_manager()->ValidatePrimarySize(*primary, mode_)) {
87     VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
88             << mode_.hdisplay << "x" << mode_.vdisplay << " got "
89             << primary->buffer->size().ToString() << " for"
90             << " crtc=" << crtc_ << " connector=" << connector_;
91     return true;
92   }
93 
94   if (!drm_->plane_manager()->AssignOverlayPlanes(plane_list, overlays,
95                                                   crtc_)) {
96     PLOG(ERROR) << "Failed to assign overlay planes for crtc " << crtc_;
97     return false;
98   }
99 
100   return true;
101 }
102 
GetFormatModifiers(uint32_t format)103 std::vector<uint64_t> CrtcController::GetFormatModifiers(uint32_t format) {
104   return drm_->plane_manager()->GetFormatModifiers(crtc_, format);
105 }
106 
SetCursor(uint32_t handle,const gfx::Size & size)107 void CrtcController::SetCursor(uint32_t handle, const gfx::Size& size) {
108   if (is_disabled_)
109     return;
110   if (!drm_->SetCursor(crtc_, handle, size)) {
111     PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
112                 << " crtc " << crtc_ << " handle " << handle << " size "
113                 << size.ToString();
114   }
115 }
116 
MoveCursor(const gfx::Point & location)117 void CrtcController::MoveCursor(const gfx::Point& location) {
118   if (is_disabled_)
119     return;
120   drm_->MoveCursor(crtc_, location);
121 }
122 
OnPageFlipComplete()123 void CrtcController::OnPageFlipComplete() {
124   modeset_framebuffer_ = nullptr;
125 }
126 
DisableCursor()127 void CrtcController::DisableCursor() {
128   if (!drm_->SetCursor(crtc_, 0, gfx::Size())) {
129     PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
130                 << " crtc " << crtc_ << " disable";
131   }
132 }
133 
134 }  // namespace ui
135