ozone: fix HDPMLegacy - do the PF after overlays, also clear old overlays
[chromium-blink-merge.git] / ui / ozone / platform / dri / hardware_display_controller.cc
blobcfbdf812ac0e8e1782afd16b911a17b35773fad8
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/dri/hardware_display_controller.h"
7 #include <drm.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <xf86drm.h>
12 #include "base/basictypes.h"
13 #include "base/logging.h"
14 #include "base/trace_event/trace_event.h"
15 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "ui/gfx/geometry/point.h"
17 #include "ui/gfx/geometry/size.h"
18 #include "ui/ozone/platform/dri/crtc_controller.h"
19 #include "ui/ozone/platform/dri/dri_buffer.h"
20 #include "ui/ozone/platform/dri/dri_wrapper.h"
21 #include "ui/ozone/public/native_pixmap.h"
23 namespace ui {
25 HardwareDisplayController::PageFlipRequest::PageFlipRequest(
26 const OverlayPlaneList& planes,
27 const base::Closure& callback)
28 : planes(planes), callback(callback) {
31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() {
34 HardwareDisplayController::HardwareDisplayController(
35 scoped_ptr<CrtcController> controller)
36 : is_disabled_(true) {
37 memset(&mode_, 0, sizeof(mode_));
38 AddCrtc(controller.Pass());
41 HardwareDisplayController::~HardwareDisplayController() {
42 // Reset the cursor.
43 UnsetCursor();
44 ClearPendingRequests();
47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
48 drmModeModeInfo mode) {
49 TRACE_EVENT0("dri", "HDC::Modeset");
50 DCHECK(primary.buffer.get());
51 bool status = true;
52 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
53 status &= crtc_controllers_[i]->Modeset(primary, mode);
55 is_disabled_ = false;
56 mode_ = mode;
58 current_planes_ = std::vector<OverlayPlane>(1, primary);
59 pending_planes_.clear();
60 ClearPendingRequests();
62 // Because a page flip is pending we need to leave some state for the
63 // callback. We use the modeset state since it is the only valid state.
64 if (HasPendingPageFlips())
65 requests_.push_back(
66 PageFlipRequest(current_planes_, base::Bind(&base::DoNothing)));
68 return status;
71 bool HardwareDisplayController::Enable() {
72 TRACE_EVENT0("dri", "HDC::Enable");
73 DCHECK(!current_planes_.empty());
74 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_);
76 return Modeset(*primary, mode_);
79 void HardwareDisplayController::Disable() {
80 TRACE_EVENT0("dri", "HDC::Disable");
81 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
82 crtc_controllers_[i]->Disable();
84 is_disabled_ = true;
87 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) {
88 pending_planes_.push_back(plane);
91 bool HardwareDisplayController::SchedulePageFlip(
92 const base::Closure& callback) {
93 TRACE_EVENT0("dri", "HDC::SchedulePageFlip");
95 // Ignore requests with no planes to schedule.
96 if (pending_planes_.empty()) {
97 callback.Run();
98 return true;
101 requests_.push_back(PageFlipRequest(pending_planes_, callback));
102 pending_planes_.clear();
104 // A request is being serviced right now.
105 if (HasPendingPageFlips())
106 return true;
108 bool status = ActualSchedulePageFlip();
110 // No page flip event on failure so discard failed request.
111 if (!status)
112 requests_.pop_front();
114 return status;
117 bool HardwareDisplayController::SetCursor(
118 const scoped_refptr<ScanoutBuffer>& buffer) {
119 bool status = true;
121 if (is_disabled_)
122 return true;
124 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
125 status &= crtc_controllers_[i]->SetCursor(buffer);
127 return status;
130 bool HardwareDisplayController::UnsetCursor() {
131 bool status = true;
132 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
133 status &= crtc_controllers_[i]->UnsetCursor();
135 return status;
138 bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
139 if (is_disabled_)
140 return true;
142 bool status = true;
143 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
144 status &= crtc_controllers_[i]->MoveCursor(location);
146 return status;
149 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) {
150 owned_hardware_planes_.add(
151 controller->drm(),
152 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList()));
153 controller->AddObserver(this);
154 crtc_controllers_.push_back(controller.release());
157 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
158 uint32_t crtc) {
159 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin();
160 it != crtc_controllers_.end(); ++it) {
161 if ((*it)->crtc() == crtc) {
162 scoped_ptr<CrtcController> controller(*it);
163 crtc_controllers_.weak_erase(it);
164 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it.
165 bool found = false;
166 for (ScopedVector<CrtcController>::iterator it =
167 crtc_controllers_.begin();
168 it != crtc_controllers_.end(); ++it) {
169 if ((*it)->drm() == controller->drm()) {
170 found = true;
171 break;
174 if (!found)
175 owned_hardware_planes_.erase(controller->drm());
177 controller->RemoveObserver(this);
178 // If a display configuration happens mid page flip we want to make sure
179 // the HDC won't wait for an event from a CRTC that is no longer
180 // associated with it.
181 if (controller->page_flip_pending())
182 OnPageFlipEvent();
184 return controller.Pass();
188 return nullptr;
191 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const {
192 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
193 if (crtc_controllers_[i]->crtc() == crtc)
194 return true;
196 return false;
199 bool HardwareDisplayController::IsMirrored() const {
200 return crtc_controllers_.size() > 1;
203 bool HardwareDisplayController::IsDisabled() const {
204 return is_disabled_;
207 gfx::Size HardwareDisplayController::GetModeSize() const {
208 return gfx::Size(mode_.hdisplay, mode_.vdisplay);
211 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const {
212 uint64_t time = 0;
213 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
214 if (time < crtc_controllers_[i]->time_of_last_flip())
215 time = crtc_controllers_[i]->time_of_last_flip();
217 return time;
220 void HardwareDisplayController::OnPageFlipEvent() {
221 TRACE_EVENT0("dri", "HDC::OnPageFlipEvent");
222 // OnPageFlipEvent() needs to handle 2 cases:
223 // 1) Normal page flips in which case:
224 // a) HasPendingPageFlips() may return false if we're in mirror mode and
225 // one of the CRTCs hasn't finished page flipping. In this case we want
226 // to wait for all the CRTCs.
227 // b) HasPendingPageFlips() returns true in which case all CRTCs are ready
228 // for the next request. In this case we expect that |requests_| isn't
229 // empty.
230 // 2) A CRTC was added while it was page flipping. In this case a modeset
231 // must be performed. Modesetting clears all pending requests, however the
232 // CRTCs will honor the scheduled page flip. Thus we need to handle page
233 // flip events with no requests.
235 if (HasPendingPageFlips())
236 return;
238 if (!requests_.empty())
239 ProcessPageFlipRequest();
241 // ProcessPageFlipRequest() consumes a request.
242 if (requests_.empty())
243 return;
245 // At this point we still have requests pending, so schedule the next request.
246 bool status = ActualSchedulePageFlip();
247 if (!status) {
248 PageFlipRequest request = requests_.front();
249 requests_.pop_front();
251 // Normally the caller would handle the error call, but because we're in a
252 // delayed schedule the initial SchedulePageFlip() already returned true,
253 // thus we need to run the callback.
254 request.callback.Run();
258 bool HardwareDisplayController::HasPendingPageFlips() const {
259 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
260 if (crtc_controllers_[i]->page_flip_pending())
261 return true;
263 return false;
266 bool HardwareDisplayController::ActualSchedulePageFlip() {
267 TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip");
268 DCHECK(!requests_.empty());
270 if (is_disabled_) {
271 ProcessPageFlipRequest();
272 return true;
275 OverlayPlaneList pending_planes = requests_.front().planes;
276 std::sort(pending_planes.begin(), pending_planes.end(),
277 [](const OverlayPlane& l, const OverlayPlane& r) {
278 return l.z_order < r.z_order;
281 bool status = true;
282 for (size_t i = 0; i < crtc_controllers_.size(); ++i) {
283 status &= crtc_controllers_[i]->SchedulePageFlip(
284 owned_hardware_planes_.get(crtc_controllers_[i]->drm()),
285 pending_planes);
288 for (const auto& planes : owned_hardware_planes_) {
289 if (!planes.first->plane_manager()->Commit(planes.second)) {
290 status = false;
294 return status;
297 void HardwareDisplayController::ProcessPageFlipRequest() {
298 DCHECK(!requests_.empty());
299 PageFlipRequest request = requests_.front();
300 requests_.pop_front();
302 current_planes_.swap(request.planes);
303 request.callback.Run();
306 void HardwareDisplayController::ClearPendingRequests() {
307 while (!requests_.empty()) {
308 PageFlipRequest request = requests_.front();
309 requests_.pop_front();
310 request.callback.Run();
314 } // namespace ui