Chromium Code Reviews| 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 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 bool is_sync, | 26 bool is_sync, |
| 27 const base::Closure& callback) | 27 const base::Closure& callback) |
| 28 : planes(planes), is_sync(is_sync), callback(callback) { | 28 : planes(planes), is_sync(is_sync), callback(callback) { |
| 29 } | 29 } |
| 30 | 30 |
| 31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { | 31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { |
| 32 } | 32 } |
| 33 | 33 |
| 34 HardwareDisplayController::HardwareDisplayController( | 34 HardwareDisplayController::HardwareDisplayController( |
| 35 scoped_ptr<CrtcController> controller) | 35 scoped_ptr<CrtcController> controller) |
| 36 : is_disabled_(true) { | 36 : is_disabled_(true), ignore_page_flip_event_(false) { |
| 37 memset(&mode_, 0, sizeof(mode_)); | 37 memset(&mode_, 0, sizeof(mode_)); |
| 38 AddCrtc(controller.Pass()); | 38 AddCrtc(controller.Pass()); |
| 39 } | 39 } |
| 40 | 40 |
| 41 HardwareDisplayController::~HardwareDisplayController() { | 41 HardwareDisplayController::~HardwareDisplayController() { |
| 42 // Reset the cursor. | 42 // Reset the cursor. |
| 43 UnsetCursor(); | 43 UnsetCursor(); |
| 44 ClearPendingRequests(); | 44 ProcessPageFlipRequest(); |
| 45 } | 45 } |
| 46 | 46 |
| 47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, | 47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
| 48 drmModeModeInfo mode) { | 48 drmModeModeInfo mode) { |
| 49 TRACE_EVENT0("drm", "HDC::Modeset"); | 49 TRACE_EVENT0("drm", "HDC::Modeset"); |
| 50 DCHECK(primary.buffer.get()); | 50 DCHECK(primary.buffer.get()); |
| 51 bool status = true; | 51 bool status = true; |
| 52 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 52 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 53 status &= crtc_controllers_[i]->Modeset(primary, mode); | 53 status &= crtc_controllers_[i]->Modeset(primary, mode); |
| 54 | 54 |
| 55 is_disabled_ = false; | 55 is_disabled_ = false; |
| 56 mode_ = mode; | 56 mode_ = mode; |
| 57 | 57 |
| 58 current_planes_ = std::vector<OverlayPlane>(1, primary); | 58 ProcessPageFlipRequest(); |
| 59 ClearPendingRequests(); | |
| 60 | 59 |
| 61 // Because a page flip is pending we need to leave some state for the | 60 // Because a page flip is pending we need to leave some state for the |
|
dnicoara
2015/04/21 18:50:42
Could you please update the comment.
| |
| 62 // callback. We use the modeset state since it is the only valid state. | 61 // callback. |
| 63 if (HasPendingPageFlips()) | 62 if (HasPendingPageFlips()) |
| 64 requests_.push_back( | 63 ignore_page_flip_event_ = true; |
|
dnicoara
2015/04/21 18:50:42
nit: Simplity it to 'ignore_page_flip_event_ = Has
alexst (slow to review)
2015/04/21 19:19:55
Done.
spang
2015/04/21 19:39:36
This is funky.
Could we pass a callback w/ weak p
alexst (slow to review)
2015/04/21 19:46:17
Yes, that's a good idea.
| |
| 65 PageFlipRequest(current_planes_, false, base::Bind(&base::DoNothing))); | |
| 66 | 64 |
| 67 return status; | 65 return status; |
| 68 } | 66 } |
| 69 | 67 |
| 70 void HardwareDisplayController::Disable() { | 68 void HardwareDisplayController::Disable() { |
| 71 TRACE_EVENT0("drm", "HDC::Disable"); | 69 TRACE_EVENT0("drm", "HDC::Disable"); |
| 72 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 70 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 73 crtc_controllers_[i]->Disable(); | 71 crtc_controllers_[i]->Disable(); |
| 74 | 72 |
| 75 // Don't hold onto any requests because we don't track fron buffer while | 73 // Don't hold onto any requests because we don't track fron buffer while |
| 76 // disabled. | 74 // disabled. |
| 77 while (requests_.size()) | 75 ProcessPageFlipRequest(); |
| 78 ProcessPageFlipRequest(); | |
| 79 | |
| 80 current_planes_.clear(); | |
| 81 | 76 |
| 82 is_disabled_ = true; | 77 is_disabled_ = true; |
| 83 } | 78 } |
| 84 | 79 |
| 85 bool HardwareDisplayController::SchedulePageFlip( | 80 bool HardwareDisplayController::SchedulePageFlip( |
| 86 const OverlayPlaneList& plane_list, | 81 const OverlayPlaneList& plane_list, |
| 87 bool is_sync, | 82 bool is_sync, |
| 88 const base::Closure& callback) { | 83 const base::Closure& callback) { |
| 89 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); | 84 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); |
| 90 | 85 |
| 86 // A request is being serviced right now. | |
|
dnicoara
2015/04/21 18:50:42
Shouldn't this be reversed? When we schedule the p
alexst (slow to review)
2015/04/21 19:19:55
of course!
| |
| 87 DCHECK(HasPendingPageFlips()); | |
| 88 DCHECK(page_flip_request_.get()); | |
| 89 | |
| 91 // Ignore requests with no planes to schedule. | 90 // Ignore requests with no planes to schedule. |
| 92 if (plane_list.empty()) { | 91 if (plane_list.empty()) { |
| 93 callback.Run(); | 92 callback.Run(); |
| 94 return true; | 93 return true; |
| 95 } | 94 } |
| 96 | 95 |
| 97 requests_.push_back(PageFlipRequest(plane_list, is_sync, callback)); | 96 page_flip_request_.reset(new PageFlipRequest(plane_list, is_sync, callback)); |
| 98 | 97 |
| 99 // A request is being serviced right now. | 98 return ActualSchedulePageFlip(); |
| 100 if (HasPendingPageFlips()) | |
| 101 return true; | |
| 102 | |
| 103 bool status = ActualSchedulePageFlip(); | |
| 104 | |
| 105 // No page flip event on failure so discard failed request. | |
| 106 if (!status) | |
| 107 requests_.pop_front(); | |
| 108 | |
| 109 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; |
| 118 | 107 |
| 119 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 108 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 226 // for the next request. In this case we expect that |requests_| isn't | 215 // for the next request. In this case we expect that |requests_| isn't |
| 227 // empty. | 216 // empty. |
| 228 // 2) A CRTC was added while it was page flipping. In this case a modeset | 217 // 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 | 218 // must be performed. Modesetting clears all pending requests, however the |
| 230 // CRTCs will honor the scheduled page flip. Thus we need to handle page | 219 // CRTCs will honor the scheduled page flip. Thus we need to handle page |
| 231 // flip events with no requests. | 220 // flip events with no requests. |
| 232 | 221 |
| 233 if (HasPendingPageFlips()) | 222 if (HasPendingPageFlips()) |
| 234 return; | 223 return; |
| 235 | 224 |
| 236 if (!requests_.empty()) | 225 if (ignore_page_flip_event_) { |
| 237 ProcessPageFlipRequest(); | 226 ignore_page_flip_event_ = false; |
| 227 return; | |
| 228 } | |
| 238 | 229 |
| 239 // ProcessPageFlipRequest() consumes a request. | 230 ProcessPageFlipRequest(); |
| 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 } | 231 } |
| 255 | 232 |
| 256 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() | 233 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() |
| 257 const { | 234 const { |
| 258 DCHECK(!crtc_controllers_.empty()); | 235 DCHECK(!crtc_controllers_.empty()); |
| 259 // TODO(dnicoara) When we support mirroring across DRM devices, figure out | 236 // TODO(dnicoara) When we support mirroring across DRM devices, figure out |
| 260 // which device should be used for allocations. | 237 // which device should be used for allocations. |
| 261 return crtc_controllers_[0]->drm(); | 238 return crtc_controllers_[0]->drm(); |
| 262 } | 239 } |
| 263 | 240 |
| 264 bool HardwareDisplayController::HasPendingPageFlips() const { | 241 bool HardwareDisplayController::HasPendingPageFlips() const { |
| 265 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 242 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 266 if (crtc_controllers_[i]->page_flip_pending()) | 243 if (crtc_controllers_[i]->page_flip_pending()) |
| 267 return true; | 244 return true; |
| 268 | 245 |
| 269 return false; | 246 return false; |
| 270 } | 247 } |
| 271 | 248 |
| 272 bool HardwareDisplayController::ActualSchedulePageFlip() { | 249 bool HardwareDisplayController::ActualSchedulePageFlip() { |
| 273 TRACE_EVENT0("drm", "HDC::ActualSchedulePageFlip"); | 250 TRACE_EVENT0("drm", "HDC::ActualSchedulePageFlip"); |
| 274 DCHECK(!requests_.empty()); | 251 DCHECK(page_flip_request_.get()); |
| 252 DCHECK(!is_disabled_); | |
| 275 | 253 |
| 276 if (is_disabled_) { | 254 OverlayPlaneList& pending_planes = page_flip_request_->planes; |
| 277 ProcessPageFlipRequest(); | |
| 278 return true; | |
| 279 } | |
| 280 | |
| 281 OverlayPlaneList pending_planes = requests_.front().planes; | |
| 282 std::sort(pending_planes.begin(), pending_planes.end(), | 255 std::sort(pending_planes.begin(), pending_planes.end(), |
| 283 [](const OverlayPlane& l, const OverlayPlane& r) { | 256 [](const OverlayPlane& l, const OverlayPlane& r) { |
| 284 return l.z_order < r.z_order; | 257 return l.z_order < r.z_order; |
| 285 }); | 258 }); |
| 286 | 259 |
| 287 bool status = true; | 260 bool status = true; |
| 288 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | 261 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| 289 status &= crtc_controllers_[i]->SchedulePageFlip( | 262 status &= crtc_controllers_[i]->SchedulePageFlip( |
| 290 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), | 263 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), |
| 291 pending_planes); | 264 pending_planes); |
| 292 } | 265 } |
| 293 | 266 |
| 294 bool is_sync = requests_.front().is_sync; | 267 bool is_sync = page_flip_request_->is_sync; |
| 295 for (const auto& planes : owned_hardware_planes_) { | 268 for (const auto& planes : owned_hardware_planes_) { |
| 296 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { | 269 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { |
| 297 status = false; | 270 status = false; |
| 298 } | 271 } |
| 299 } | 272 } |
| 300 | 273 |
| 301 return status; | 274 return status; |
| 302 } | 275 } |
| 303 | 276 |
| 304 void HardwareDisplayController::ProcessPageFlipRequest() { | 277 void HardwareDisplayController::ProcessPageFlipRequest() { |
| 305 DCHECK(!requests_.empty()); | 278 if (page_flip_request_.get()) { |
| 306 PageFlipRequest request = requests_.front(); | 279 scoped_ptr<PageFlipRequest> last_request; |
| 307 requests_.pop_front(); | 280 // We are done with the last request, so clear it before we execute the |
| 308 | 281 // callback since it may schedule a new frame. |
| 309 current_planes_.swap(request.planes); | 282 swap(last_request, page_flip_request_); |
| 310 request.callback.Run(); | 283 last_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 } | 284 } |
| 319 } | 285 } |
| 320 | 286 |
| 321 } // namespace ui | 287 } // namespace ui |
| OLD | NEW |