OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" | 5 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h" |
6 | 6 |
7 #include <drm.h> | 7 #include <drm.h> |
8 #include <string.h> | 8 #include <string.h> |
9 #include <xf86drm.h> | 9 #include <xf86drm.h> |
10 | 10 |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
14 #include "third_party/skia/include/core/SkCanvas.h" | 14 #include "third_party/skia/include/core/SkCanvas.h" |
15 #include "ui/gfx/geometry/point.h" | 15 #include "ui/gfx/geometry/point.h" |
16 #include "ui/gfx/geometry/size.h" | 16 #include "ui/gfx/geometry/size.h" |
17 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" | 17 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" |
18 #include "ui/ozone/platform/drm/gpu/drm_buffer.h" | 18 #include "ui/ozone/platform/drm/gpu/drm_buffer.h" |
19 #include "ui/ozone/platform/drm/gpu/drm_device.h" | 19 #include "ui/ozone/platform/drm/gpu/drm_device.h" |
20 #include "ui/ozone/platform/drm/gpu/page_flip_request.h" | |
20 #include "ui/ozone/public/native_pixmap.h" | 21 #include "ui/ozone/public/native_pixmap.h" |
21 | 22 |
22 namespace ui { | 23 namespace ui { |
23 | 24 |
24 HardwareDisplayController::PageFlipRequest::PageFlipRequest( | |
25 const OverlayPlaneList& planes, | |
26 bool is_sync, | |
27 const base::Closure& callback) | |
28 : planes(planes), is_sync(is_sync), callback(callback) { | |
29 } | |
30 | |
31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { | |
32 } | |
33 | |
34 HardwareDisplayController::HardwareDisplayController( | 25 HardwareDisplayController::HardwareDisplayController( |
35 scoped_ptr<CrtcController> controller) | 26 scoped_ptr<CrtcController> controller) |
36 : is_disabled_(true) { | 27 : is_disabled_(true), ignore_page_flip_event_(false) { |
37 memset(&mode_, 0, sizeof(mode_)); | 28 memset(&mode_, 0, sizeof(mode_)); |
38 AddCrtc(controller.Pass()); | 29 AddCrtc(controller.Pass()); |
39 } | 30 } |
40 | 31 |
41 HardwareDisplayController::~HardwareDisplayController() { | 32 HardwareDisplayController::~HardwareDisplayController() { |
42 // Reset the cursor. | 33 // Reset the cursor. |
43 UnsetCursor(); | 34 UnsetCursor(); |
44 ClearPendingRequests(); | |
45 } | 35 } |
46 | 36 |
47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, | 37 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
48 drmModeModeInfo mode) { | 38 drmModeModeInfo mode) { |
49 TRACE_EVENT0("drm", "HDC::Modeset"); | 39 TRACE_EVENT0("drm", "HDC::Modeset"); |
50 DCHECK(primary.buffer.get()); | 40 DCHECK(primary.buffer.get()); |
51 bool status = true; | 41 bool status = true; |
52 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 42 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
53 status &= crtc_controllers_[i]->Modeset(primary, mode); | 43 status &= crtc_controllers_[i]->Modeset(primary, mode); |
54 | 44 |
55 is_disabled_ = false; | 45 is_disabled_ = false; |
56 mode_ = mode; | 46 mode_ = mode; |
57 | 47 |
58 current_planes_ = std::vector<OverlayPlane>(1, primary); | |
59 ClearPendingRequests(); | |
60 | |
61 // Because a page flip is pending we need to leave some state for the | |
62 // callback. We use the modeset state since it is the only valid state. | |
63 if (HasPendingPageFlips()) | |
64 requests_.push_back( | |
65 PageFlipRequest(current_planes_, false, base::Bind(&base::DoNothing))); | |
66 | |
67 return status; | 48 return status; |
68 } | 49 } |
69 | 50 |
70 void HardwareDisplayController::Disable() { | 51 void HardwareDisplayController::Disable() { |
71 TRACE_EVENT0("drm", "HDC::Disable"); | 52 TRACE_EVENT0("drm", "HDC::Disable"); |
72 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 53 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
73 crtc_controllers_[i]->Disable(); | 54 crtc_controllers_[i]->Disable(); |
74 | 55 |
75 // Don't hold onto any requests because we don't track fron buffer while | |
76 // disabled. | |
77 while (requests_.size()) | |
78 ProcessPageFlipRequest(); | |
79 | |
80 current_planes_.clear(); | |
81 | 56 |
82 is_disabled_ = true; | 57 is_disabled_ = true; |
83 } | 58 } |
84 | 59 |
85 bool HardwareDisplayController::SchedulePageFlip( | 60 bool HardwareDisplayController::SchedulePageFlip( |
86 const OverlayPlaneList& plane_list, | 61 const OverlayPlaneList& plane_list, |
87 bool is_sync, | 62 bool is_sync, |
88 const base::Closure& callback) { | 63 const base::Closure& callback) { |
89 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); | 64 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); |
90 | 65 |
66 // A request is being serviced right now. | |
dnicoara
2015/04/23 15:34:56
Remove comment since it's inconsistent.
| |
67 DCHECK(!HasPendingPageFlips()); | |
68 DCHECK(!is_disabled_); | |
69 | |
91 // Ignore requests with no planes to schedule. | 70 // Ignore requests with no planes to schedule. |
92 if (plane_list.empty()) { | 71 if (plane_list.empty()) { |
93 callback.Run(); | 72 callback.Run(); |
94 return true; | 73 return true; |
95 } | 74 } |
96 | 75 |
97 requests_.push_back(PageFlipRequest(plane_list, is_sync, callback)); | 76 scoped_refptr<PageFlipRequest> page_flip_request = |
77 new PageFlipRequest(crtc_controllers_.size(), callback); | |
98 | 78 |
99 // A request is being serviced right now. | 79 OverlayPlaneList pending_planes = plane_list; |
100 if (HasPendingPageFlips()) | 80 std::sort(pending_planes.begin(), pending_planes.end(), |
101 return true; | 81 [](const OverlayPlane& l, const OverlayPlane& r) { |
82 return l.z_order < r.z_order; | |
83 }); | |
102 | 84 |
103 bool status = ActualSchedulePageFlip(); | 85 bool status = true; |
86 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
87 status &= crtc_controllers_[i]->SchedulePageFlip( | |
88 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), | |
89 pending_planes, page_flip_request); | |
90 } | |
104 | 91 |
105 // No page flip event on failure so discard failed request. | 92 for (const auto& planes : owned_hardware_planes_) { |
106 if (!status) | 93 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { |
107 requests_.pop_front(); | 94 status = false; |
95 } | |
96 } | |
108 | 97 |
109 return status; | 98 return status; |
110 } | 99 } |
111 | 100 |
112 bool HardwareDisplayController::SetCursor( | 101 bool HardwareDisplayController::SetCursor( |
113 const scoped_refptr<ScanoutBuffer>& buffer) { | 102 const scoped_refptr<ScanoutBuffer>& buffer) { |
114 bool status = true; | 103 bool status = true; |
115 | 104 |
116 if (is_disabled_) | 105 if (is_disabled_) |
117 return true; | 106 return true; |
(...skipping 20 matching lines...) Expand all Loading... | |
138 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 127 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
139 status &= crtc_controllers_[i]->MoveCursor(location); | 128 status &= crtc_controllers_[i]->MoveCursor(location); |
140 | 129 |
141 return status; | 130 return status; |
142 } | 131 } |
143 | 132 |
144 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { | 133 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { |
145 owned_hardware_planes_.add( | 134 owned_hardware_planes_.add( |
146 controller->drm().get(), | 135 controller->drm().get(), |
147 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); | 136 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); |
148 controller->AddObserver(this); | |
149 crtc_controllers_.push_back(controller.release()); | 137 crtc_controllers_.push_back(controller.release()); |
150 } | 138 } |
151 | 139 |
152 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( | 140 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
153 const scoped_refptr<DrmDevice>& drm, | 141 const scoped_refptr<DrmDevice>& drm, |
154 uint32_t crtc) { | 142 uint32_t crtc) { |
155 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); | 143 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); |
156 it != crtc_controllers_.end(); ++it) { | 144 it != crtc_controllers_.end(); ++it) { |
157 if ((*it)->drm() == drm && (*it)->crtc() == crtc) { | 145 if ((*it)->drm() == drm && (*it)->crtc() == crtc) { |
158 scoped_ptr<CrtcController> controller(*it); | 146 scoped_ptr<CrtcController> controller(*it); |
159 crtc_controllers_.weak_erase(it); | 147 crtc_controllers_.weak_erase(it); |
160 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. | 148 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. |
161 bool found = false; | 149 bool found = false; |
162 for (ScopedVector<CrtcController>::iterator it = | 150 for (ScopedVector<CrtcController>::iterator it = |
163 crtc_controllers_.begin(); | 151 crtc_controllers_.begin(); |
164 it != crtc_controllers_.end(); ++it) { | 152 it != crtc_controllers_.end(); ++it) { |
165 if ((*it)->drm() == controller->drm()) { | 153 if ((*it)->drm() == controller->drm()) { |
166 found = true; | 154 found = true; |
167 break; | 155 break; |
168 } | 156 } |
169 } | 157 } |
170 if (!found) | 158 if (!found) |
171 owned_hardware_planes_.erase(controller->drm().get()); | 159 owned_hardware_planes_.erase(controller->drm().get()); |
172 | 160 |
173 controller->RemoveObserver(this); | |
174 // If a display configuration happens mid page flip we want to make sure | |
175 // the HDC won't wait for an event from a CRTC that is no longer | |
176 // associated with it. | |
177 if (controller->page_flip_pending()) | |
178 OnPageFlipEvent(); | |
179 | |
180 return controller.Pass(); | 161 return controller.Pass(); |
181 } | 162 } |
182 } | 163 } |
183 | 164 |
184 return nullptr; | 165 return nullptr; |
185 } | 166 } |
186 | 167 |
187 bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, | 168 bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, |
188 uint32_t crtc) const { | 169 uint32_t crtc) const { |
189 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 170 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
(...skipping 18 matching lines...) Expand all Loading... | |
208 | 189 |
209 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { | 190 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { |
210 uint64_t time = 0; | 191 uint64_t time = 0; |
211 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 192 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
212 if (time < crtc_controllers_[i]->time_of_last_flip()) | 193 if (time < crtc_controllers_[i]->time_of_last_flip()) |
213 time = crtc_controllers_[i]->time_of_last_flip(); | 194 time = crtc_controllers_[i]->time_of_last_flip(); |
214 | 195 |
215 return time; | 196 return time; |
216 } | 197 } |
217 | 198 |
218 void HardwareDisplayController::OnPageFlipEvent() { | |
219 TRACE_EVENT0("drm", "HDC::OnPageFlipEvent"); | |
220 // OnPageFlipEvent() needs to handle 2 cases: | |
221 // 1) Normal page flips in which case: | |
222 // a) HasPendingPageFlips() may return false if we're in mirror mode and | |
223 // one of the CRTCs hasn't finished page flipping. In this case we want | |
224 // to wait for all the CRTCs. | |
225 // b) HasPendingPageFlips() returns true in which case all CRTCs are ready | |
226 // for the next request. In this case we expect that |requests_| isn't | |
227 // empty. | |
228 // 2) A CRTC was added while it was page flipping. In this case a modeset | |
229 // must be performed. Modesetting clears all pending requests, however the | |
230 // CRTCs will honor the scheduled page flip. Thus we need to handle page | |
231 // flip events with no requests. | |
232 | |
233 if (HasPendingPageFlips()) | |
234 return; | |
235 | |
236 if (!requests_.empty()) | |
237 ProcessPageFlipRequest(); | |
238 | |
239 // ProcessPageFlipRequest() consumes a request. | |
240 if (requests_.empty()) | |
241 return; | |
242 | |
243 // At this point we still have requests pending, so schedule the next request. | |
244 bool status = ActualSchedulePageFlip(); | |
245 if (!status) { | |
246 PageFlipRequest request = requests_.front(); | |
247 requests_.pop_front(); | |
248 | |
249 // Normally the caller would handle the error call, but because we're in a | |
250 // delayed schedule the initial SchedulePageFlip() already returned true, | |
251 // thus we need to run the callback. | |
252 request.callback.Run(); | |
253 } | |
254 } | |
255 | |
256 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() | 199 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() |
257 const { | 200 const { |
258 DCHECK(!crtc_controllers_.empty()); | 201 DCHECK(!crtc_controllers_.empty()); |
259 // TODO(dnicoara) When we support mirroring across DRM devices, figure out | 202 // TODO(dnicoara) When we support mirroring across DRM devices, figure out |
260 // which device should be used for allocations. | 203 // which device should be used for allocations. |
261 return crtc_controllers_[0]->drm(); | 204 return crtc_controllers_[0]->drm(); |
262 } | 205 } |
263 | 206 |
264 bool HardwareDisplayController::HasPendingPageFlips() const { | 207 bool HardwareDisplayController::HasPendingPageFlips() const { |
dnicoara
2015/04/23 15:34:56
Lets just remove this since it is being used for a
| |
265 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 208 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
266 if (crtc_controllers_[i]->page_flip_pending()) | 209 if (crtc_controllers_[i]->page_flip_pending()) |
267 return true; | 210 return true; |
268 | 211 |
269 return false; | 212 return false; |
270 } | 213 } |
271 | 214 |
272 bool HardwareDisplayController::ActualSchedulePageFlip() { | |
273 TRACE_EVENT0("drm", "HDC::ActualSchedulePageFlip"); | |
274 DCHECK(!requests_.empty()); | |
275 | |
276 if (is_disabled_) { | |
277 ProcessPageFlipRequest(); | |
278 return true; | |
279 } | |
280 | |
281 OverlayPlaneList pending_planes = requests_.front().planes; | |
282 std::sort(pending_planes.begin(), pending_planes.end(), | |
283 [](const OverlayPlane& l, const OverlayPlane& r) { | |
284 return l.z_order < r.z_order; | |
285 }); | |
286 | |
287 bool status = true; | |
288 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
289 status &= crtc_controllers_[i]->SchedulePageFlip( | |
290 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), | |
291 pending_planes); | |
292 } | |
293 | |
294 bool is_sync = requests_.front().is_sync; | |
295 for (const auto& planes : owned_hardware_planes_) { | |
296 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { | |
297 status = false; | |
298 } | |
299 } | |
300 | |
301 return status; | |
302 } | |
303 | |
304 void HardwareDisplayController::ProcessPageFlipRequest() { | |
305 DCHECK(!requests_.empty()); | |
306 PageFlipRequest request = requests_.front(); | |
307 requests_.pop_front(); | |
308 | |
309 current_planes_.swap(request.planes); | |
310 request.callback.Run(); | |
311 } | |
312 | |
313 void HardwareDisplayController::ClearPendingRequests() { | |
314 while (!requests_.empty()) { | |
315 PageFlipRequest request = requests_.front(); | |
316 requests_.pop_front(); | |
317 request.callback.Run(); | |
318 } | |
319 } | |
320 | |
321 } // namespace ui | 215 } // namespace ui |
OLD | NEW |