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/crtc_controller.h"
7 #include "base/logging.h"
8 #include "base/time/time.h"
9 #include "ui/ozone/platform/drm/gpu/drm_device.h"
10 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
11 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
15 CrtcController::CrtcController(const scoped_refptr
<DrmDevice
>& drm
,
19 overlay_plane_manager_(nullptr),
21 connector_(connector
) {}
23 CrtcController::~CrtcController() {
26 drm_
->DisableCrtc(crtc_
);
27 SignalPageFlipRequest();
31 bool CrtcController::Modeset(const OverlayPlane
& plane
, drmModeModeInfo mode
) {
32 if (!drm_
->SetCrtc(crtc_
, plane
.buffer
->GetFramebufferId(),
33 std::vector
<uint32_t>(1, connector_
), &mode
)) {
34 PLOG(ERROR
) << "Failed to modeset: crtc=" << crtc_
35 << " connector=" << connector_
36 << " framebuffer_id=" << plane
.buffer
->GetFramebufferId()
37 << " mode=" << mode
.hdisplay
<< "x" << mode
.vdisplay
<< "@"
43 pending_planes_
.clear();
46 // drmModeSetCrtc has an immediate effect, so we can assume that the current
47 // planes have been updated. However if a page flip is still pending, set the
48 // pending planes to the same values so that the callback keeps the correct
50 current_planes_
= std::vector
<OverlayPlane
>(1, plane
);
51 if (page_flip_request_
.get())
52 pending_planes_
= current_planes_
;
59 bool CrtcController::Disable() {
64 return drm_
->DisableCrtc(crtc_
);
67 bool CrtcController::SchedulePageFlip(
68 HardwareDisplayPlaneList
* plane_list
,
69 const OverlayPlaneList
& overlays
,
71 scoped_refptr
<PageFlipRequest
> page_flip_request
) {
72 DCHECK(!page_flip_request_
.get() || test_only
);
73 DCHECK(!is_disabled_
);
74 const OverlayPlane
* primary
= OverlayPlane::GetPrimaryPlane(overlays
);
76 LOG(ERROR
) << "No primary plane to display on crtc " << crtc_
;
77 page_flip_request
->Signal(gfx::SwapResult::SWAP_ACK
);
80 DCHECK(primary
->buffer
.get());
82 if (primary
->buffer
->GetSize() != gfx::Size(mode_
.hdisplay
, mode_
.vdisplay
)) {
83 VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
84 << mode_
.hdisplay
<< "x" << mode_
.vdisplay
<< " got "
85 << primary
->buffer
->GetSize().ToString() << " for"
86 << " crtc=" << crtc_
<< " connector=" << connector_
;
87 page_flip_request
->Signal(gfx::SwapResult::SWAP_ACK
);
91 if (!drm_
->plane_manager()->AssignOverlayPlanes(plane_list
, overlays
, crtc_
,
93 PLOG(ERROR
) << "Failed to assign overlay planes for crtc " << crtc_
;
94 page_flip_request
->Signal(gfx::SwapResult::SWAP_FAILED
);
99 page_flip_request
->Signal(gfx::SwapResult::SWAP_ACK
);
101 pending_planes_
= overlays
;
102 page_flip_request_
= page_flip_request
;
108 void CrtcController::PageFlipFailed() {
109 pending_planes_
.clear();
110 SignalPageFlipRequest();
113 void CrtcController::OnPageFlipEvent(unsigned int frame
,
114 unsigned int seconds
,
115 unsigned int useconds
) {
117 static_cast<uint64_t>(seconds
) * base::Time::kMicrosecondsPerSecond
+
120 current_planes_
.clear();
121 current_planes_
.swap(pending_planes_
);
123 SignalPageFlipRequest();
126 bool CrtcController::SetCursor(const scoped_refptr
<ScanoutBuffer
>& buffer
) {
127 DCHECK(!is_disabled_
|| !buffer
);
128 cursor_buffer_
= buffer
;
130 return ResetCursor();
133 bool CrtcController::MoveCursor(const gfx::Point
& location
) {
134 DCHECK(!is_disabled_
);
135 return drm_
->MoveCursor(crtc_
, location
);
138 bool CrtcController::ResetCursor() {
142 if (cursor_buffer_
) {
143 handle
= cursor_buffer_
->GetHandle();
144 size
= cursor_buffer_
->GetSize();
147 bool status
= drm_
->SetCursor(crtc_
, handle
, size
);
149 PLOG(ERROR
) << "drmModeSetCursor: device " << drm_
->device_path().value()
150 << " crtc " << crtc_
<< " handle " << handle
<< " size "
157 void CrtcController::SignalPageFlipRequest() {
158 if (page_flip_request_
.get()) {
159 // If another frame is queued up and available immediately, calling Signal()
160 // may result in a call to SchedulePageFlip(), which will override
161 // page_flip_request_ and possibly release the ref. Stash previous request
162 // locally to avoid deleting the object we are making a call on.
163 scoped_refptr
<PageFlipRequest
> last_request
;
164 last_request
.swap(page_flip_request_
);
165 last_request
->Signal(gfx::SwapResult::SWAP_ACK
);