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_observer.h"
11 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
15 CrtcController::CrtcController(const scoped_refptr
<DrmDevice
>& drm
,
20 connector_(connector
),
21 saved_crtc_(drm
->GetCrtc(crtc
)),
23 page_flip_pending_(false),
24 time_of_last_flip_(0) {
27 CrtcController::~CrtcController() {
29 drm_
->SetCrtc(saved_crtc_
.get(), std::vector
<uint32_t>(1, connector_
));
34 bool CrtcController::Modeset(const OverlayPlane
& plane
, drmModeModeInfo mode
) {
35 if (!drm_
->SetCrtc(crtc_
, plane
.buffer
->GetFramebufferId(),
36 std::vector
<uint32_t>(1, connector_
), &mode
)) {
37 PLOG(ERROR
) << "Failed to modeset: crtc=" << crtc_
38 << " connector=" << connector_
39 << " framebuffer_id=" << plane
.buffer
->GetFramebufferId()
40 << " mode=" << mode
.hdisplay
<< "x" << mode
.vdisplay
<< "@"
46 pending_planes_
.clear();
49 // drmModeSetCrtc has an immediate effect, so we can assume that the current
50 // planes have been updated. However if a page flip is still pending, set the
51 // pending planes to the same values so that the callback keeps the correct
53 current_planes_
= std::vector
<OverlayPlane
>(1, plane
);
54 if (page_flip_pending_
)
55 pending_planes_
= current_planes_
;
60 bool CrtcController::Disable() {
65 return drm_
->DisableCrtc(crtc_
);
68 bool CrtcController::SchedulePageFlip(HardwareDisplayPlaneList
* plane_list
,
69 const OverlayPlaneList
& overlays
) {
70 DCHECK(!page_flip_pending_
);
71 DCHECK(!is_disabled_
);
72 const OverlayPlane
* primary
= OverlayPlane::GetPrimaryPlane(overlays
);
74 LOG(ERROR
) << "No primary plane to display on crtc " << crtc_
;
75 FOR_EACH_OBSERVER(PageFlipObserver
, observers_
, OnPageFlipEvent());
78 DCHECK(primary
->buffer
.get());
80 if (primary
->buffer
->GetSize() != gfx::Size(mode_
.hdisplay
, mode_
.vdisplay
)) {
81 VLOG(2) << "Trying to pageflip a buffer with the wrong size. Expected "
82 << mode_
.hdisplay
<< "x" << mode_
.vdisplay
<< " got "
83 << primary
->buffer
->GetSize().ToString() << " for"
84 << " crtc=" << crtc_
<< " connector=" << connector_
;
85 FOR_EACH_OBSERVER(PageFlipObserver
, observers_
, OnPageFlipEvent());
89 if (!drm_
->plane_manager()->AssignOverlayPlanes(plane_list
, overlays
, crtc_
,
91 PLOG(ERROR
) << "Failed to assign overlay planes for crtc " << crtc_
;
95 page_flip_pending_
= true;
96 pending_planes_
= overlays
;
101 void CrtcController::PageFlipFailed() {
102 pending_planes_
.clear();
103 page_flip_pending_
= false;
106 void CrtcController::OnPageFlipEvent(unsigned int frame
,
107 unsigned int seconds
,
108 unsigned int useconds
) {
109 page_flip_pending_
= false;
111 static_cast<uint64_t>(seconds
) * base::Time::kMicrosecondsPerSecond
+
114 current_planes_
.clear();
115 current_planes_
.swap(pending_planes_
);
117 FOR_EACH_OBSERVER(PageFlipObserver
, observers_
, OnPageFlipEvent());
120 bool CrtcController::SetCursor(const scoped_refptr
<ScanoutBuffer
>& buffer
) {
121 DCHECK(!is_disabled_
);
122 cursor_buffer_
= buffer
;
123 return drm_
->SetCursor(crtc_
, buffer
->GetHandle(), buffer
->GetSize());
126 bool CrtcController::UnsetCursor() {
127 bool state
= drm_
->SetCursor(crtc_
, 0, gfx::Size());
128 cursor_buffer_
= NULL
;
132 bool CrtcController::MoveCursor(const gfx::Point
& location
) {
133 DCHECK(!is_disabled_
);
134 return drm_
->MoveCursor(crtc_
, location
);
137 void CrtcController::AddObserver(PageFlipObserver
* observer
) {
138 observers_
.AddObserver(observer
);
141 void CrtcController::RemoveObserver(PageFlipObserver
* observer
) {
142 observers_
.RemoveObserver(observer
);