ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / ui / ozone / platform / dri / hardware_display_controller.cc
blob061506739966078d78a4304f0672288bc32f2e83
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/drm_device.h"
21 #include "ui/ozone/public/native_pixmap.h"
23 namespace ui {
25 HardwareDisplayController::PageFlipRequest::PageFlipRequest(
26 const OverlayPlaneList& planes,
27 bool is_sync,
28 const base::Closure& callback)
29 : planes(planes), is_sync(is_sync), callback(callback) {
32 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() {
35 HardwareDisplayController::HardwareDisplayController(
36 scoped_ptr<CrtcController> controller)
37 : is_disabled_(true) {
38 memset(&mode_, 0, sizeof(mode_));
39 AddCrtc(controller.Pass());
42 HardwareDisplayController::~HardwareDisplayController() {
43 // Reset the cursor.
44 UnsetCursor();
45 ClearPendingRequests();
48 bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
49 drmModeModeInfo mode) {
50 TRACE_EVENT0("dri", "HDC::Modeset");
51 DCHECK(primary.buffer.get());
52 bool status = true;
53 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
54 status &= crtc_controllers_[i]->Modeset(primary, mode);
56 is_disabled_ = false;
57 mode_ = mode;
59 current_planes_ = std::vector<OverlayPlane>(1, primary);
60 pending_planes_.clear();
61 ClearPendingRequests();
63 // Because a page flip is pending we need to leave some state for the
64 // callback. We use the modeset state since it is the only valid state.
65 if (HasPendingPageFlips())
66 requests_.push_back(
67 PageFlipRequest(current_planes_, false, base::Bind(&base::DoNothing)));
69 return status;
72 bool HardwareDisplayController::Enable() {
73 TRACE_EVENT0("dri", "HDC::Enable");
74 DCHECK(!current_planes_.empty());
75 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_);
77 return Modeset(*primary, mode_);
80 void HardwareDisplayController::Disable() {
81 TRACE_EVENT0("dri", "HDC::Disable");
82 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
83 crtc_controllers_[i]->Disable();
85 is_disabled_ = true;
88 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) {
89 pending_planes_.push_back(plane);
92 bool HardwareDisplayController::SchedulePageFlip(
93 bool is_sync,
94 const base::Closure& callback) {
95 TRACE_EVENT0("dri", "HDC::SchedulePageFlip");
97 // Ignore requests with no planes to schedule.
98 if (pending_planes_.empty()) {
99 callback.Run();
100 return true;
103 requests_.push_back(PageFlipRequest(pending_planes_, is_sync, callback));
104 pending_planes_.clear();
106 // A request is being serviced right now.
107 if (HasPendingPageFlips())
108 return true;
110 bool status = ActualSchedulePageFlip();
112 // No page flip event on failure so discard failed request.
113 if (!status)
114 requests_.pop_front();
116 return status;
119 bool HardwareDisplayController::SetCursor(
120 const scoped_refptr<ScanoutBuffer>& buffer) {
121 bool status = true;
123 if (is_disabled_)
124 return true;
126 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
127 status &= crtc_controllers_[i]->SetCursor(buffer);
129 return status;
132 bool HardwareDisplayController::UnsetCursor() {
133 bool status = true;
134 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
135 status &= crtc_controllers_[i]->UnsetCursor();
137 return status;
140 bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
141 if (is_disabled_)
142 return true;
144 bool status = true;
145 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
146 status &= crtc_controllers_[i]->MoveCursor(location);
148 return status;
151 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) {
152 owned_hardware_planes_.add(
153 controller->drm().get(),
154 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList()));
155 controller->AddObserver(this);
156 crtc_controllers_.push_back(controller.release());
159 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
160 const scoped_refptr<DrmDevice>& drm,
161 uint32_t crtc) {
162 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin();
163 it != crtc_controllers_.end(); ++it) {
164 if ((*it)->drm() == drm && (*it)->crtc() == crtc) {
165 scoped_ptr<CrtcController> controller(*it);
166 crtc_controllers_.weak_erase(it);
167 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it.
168 bool found = false;
169 for (ScopedVector<CrtcController>::iterator it =
170 crtc_controllers_.begin();
171 it != crtc_controllers_.end(); ++it) {
172 if ((*it)->drm() == controller->drm()) {
173 found = true;
174 break;
177 if (!found)
178 owned_hardware_planes_.erase(controller->drm().get());
180 controller->RemoveObserver(this);
181 // If a display configuration happens mid page flip we want to make sure
182 // the HDC won't wait for an event from a CRTC that is no longer
183 // associated with it.
184 if (controller->page_flip_pending())
185 OnPageFlipEvent();
187 return controller.Pass();
191 return nullptr;
194 bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm,
195 uint32_t crtc) const {
196 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
197 if (crtc_controllers_[i]->drm() == drm &&
198 crtc_controllers_[i]->crtc() == crtc)
199 return true;
201 return false;
204 bool HardwareDisplayController::IsMirrored() const {
205 return crtc_controllers_.size() > 1;
208 bool HardwareDisplayController::IsDisabled() const {
209 return is_disabled_;
212 gfx::Size HardwareDisplayController::GetModeSize() const {
213 return gfx::Size(mode_.hdisplay, mode_.vdisplay);
216 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const {
217 uint64_t time = 0;
218 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
219 if (time < crtc_controllers_[i]->time_of_last_flip())
220 time = crtc_controllers_[i]->time_of_last_flip();
222 return time;
225 void HardwareDisplayController::OnPageFlipEvent() {
226 TRACE_EVENT0("dri", "HDC::OnPageFlipEvent");
227 // OnPageFlipEvent() needs to handle 2 cases:
228 // 1) Normal page flips in which case:
229 // a) HasPendingPageFlips() may return false if we're in mirror mode and
230 // one of the CRTCs hasn't finished page flipping. In this case we want
231 // to wait for all the CRTCs.
232 // b) HasPendingPageFlips() returns true in which case all CRTCs are ready
233 // for the next request. In this case we expect that |requests_| isn't
234 // empty.
235 // 2) A CRTC was added while it was page flipping. In this case a modeset
236 // must be performed. Modesetting clears all pending requests, however the
237 // CRTCs will honor the scheduled page flip. Thus we need to handle page
238 // flip events with no requests.
240 if (HasPendingPageFlips())
241 return;
243 if (!requests_.empty())
244 ProcessPageFlipRequest();
246 // ProcessPageFlipRequest() consumes a request.
247 if (requests_.empty())
248 return;
250 // At this point we still have requests pending, so schedule the next request.
251 bool status = ActualSchedulePageFlip();
252 if (!status) {
253 PageFlipRequest request = requests_.front();
254 requests_.pop_front();
256 // Normally the caller would handle the error call, but because we're in a
257 // delayed schedule the initial SchedulePageFlip() already returned true,
258 // thus we need to run the callback.
259 request.callback.Run();
263 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice()
264 const {
265 DCHECK(!crtc_controllers_.empty());
266 // TODO(dnicoara) When we support mirroring across DRM devices, figure out
267 // which device should be used for allocations.
268 return crtc_controllers_[0]->drm();
271 bool HardwareDisplayController::HasPendingPageFlips() const {
272 for (size_t i = 0; i < crtc_controllers_.size(); ++i)
273 if (crtc_controllers_[i]->page_flip_pending())
274 return true;
276 return false;
279 bool HardwareDisplayController::ActualSchedulePageFlip() {
280 TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip");
281 DCHECK(!requests_.empty());
283 if (is_disabled_) {
284 ProcessPageFlipRequest();
285 return true;
288 OverlayPlaneList pending_planes = requests_.front().planes;
289 std::sort(pending_planes.begin(), pending_planes.end(),
290 [](const OverlayPlane& l, const OverlayPlane& r) {
291 return l.z_order < r.z_order;
294 bool status = true;
295 for (size_t i = 0; i < crtc_controllers_.size(); ++i) {
296 status &= crtc_controllers_[i]->SchedulePageFlip(
297 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()),
298 pending_planes);
301 bool is_sync = requests_.front().is_sync;
302 for (const auto& planes : owned_hardware_planes_) {
303 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) {
304 status = false;
308 return status;
311 void HardwareDisplayController::ProcessPageFlipRequest() {
312 DCHECK(!requests_.empty());
313 PageFlipRequest request = requests_.front();
314 requests_.pop_front();
316 current_planes_.swap(request.planes);
317 request.callback.Run();
320 void HardwareDisplayController::ClearPendingRequests() {
321 while (!requests_.empty()) {
322 PageFlipRequest request = requests_.front();
323 requests_.pop_front();
324 request.callback.Run();
328 } // namespace ui