Chromium Code Reviews| Index: ui/ozone/platform/dri/hardware_display_controller.cc |
| diff --git a/ui/ozone/platform/dri/hardware_display_controller.cc b/ui/ozone/platform/dri/hardware_display_controller.cc |
| index 275467db9ea95903a584fd3aca813dfa5f42e0f4..d23365aa27089f0eb9919d4f88a36ef32468b8f8 100644 |
| --- a/ui/ozone/platform/dri/hardware_display_controller.cc |
| +++ b/ui/ozone/platform/dri/hardware_display_controller.cc |
| @@ -22,28 +22,14 @@ |
| namespace ui { |
| -namespace { |
| - |
| -// DRM callback on page flip events. This callback is triggered after the |
| -// page flip has happened and the backbuffer is now the new frontbuffer |
| -// The old frontbuffer is no longer used by the hardware and can be used for |
| -// future draw operations. |
| -// |
| -// |device| will contain a reference to the |ScanoutSurface| object which |
| -// the event belongs to. |
| -// |
| -// TODO(dnicoara) When we have a FD handler for the DRM calls in the message |
| -// loop, we can move this function in the handler. |
| -void HandlePageFlipEvent(int fd, |
| - unsigned int frame, |
| - unsigned int seconds, |
| - unsigned int useconds, |
| - void* controller) { |
| - static_cast<CrtcController*>(controller) |
| - ->OnPageFlipEvent(frame, seconds, useconds); |
| -} |
| - |
| -} // namespace |
| +HardwareDisplayController::PageFlipRequest::PageFlipRequest( |
| + const OverlayPlaneList& planes, |
| + const base::Closure& callback) |
| + : planes(planes), callback(callback) { |
| +} |
| + |
| +HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { |
| +} |
| HardwareDisplayController::HardwareDisplayController( |
| scoped_ptr<CrtcController> controller) |
| @@ -55,20 +41,31 @@ HardwareDisplayController::HardwareDisplayController( |
| HardwareDisplayController::~HardwareDisplayController() { |
| // Reset the cursor. |
| UnsetCursor(); |
| + ClearPendingRequests(); |
| } |
| bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
| drmModeModeInfo mode) { |
| TRACE_EVENT0("dri", "HDC::Modeset"); |
| + LOG(ERROR) << "modeset"; |
|
alexst (slow to review)
2015/01/09 03:55:46
Debug message.
dnicoara
2015/01/09 15:08:24
Removed.
|
| DCHECK(primary.buffer.get()); |
| bool status = true; |
| for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| status &= crtc_controllers_[i]->Modeset(primary, mode); |
| - current_planes_ = std::vector<OverlayPlane>(1, primary); |
| - pending_planes_.clear(); |
| is_disabled_ = false; |
| mode_ = mode; |
| + |
| + current_planes_ = std::vector<OverlayPlane>(1, primary); |
| + pending_planes_.clear(); |
| + ClearPendingRequests(); |
| + |
| + // Because a page flip is pending we need to leave some state for the |
| + // callback. We use the modeset state since it is the only valid state. |
| + if (HasPendingPageFlips()) |
| + requests_.push_back( |
| + PageFlipRequest(current_planes_, base::Bind(&base::DoNothing))); |
| + |
| return status; |
| } |
| @@ -92,59 +89,30 @@ void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) { |
| pending_planes_.push_back(plane); |
| } |
| -bool HardwareDisplayController::SchedulePageFlip() { |
| - DCHECK(!pending_planes_.empty()); |
| +bool HardwareDisplayController::SchedulePageFlip( |
| + const base::Closure& callback) { |
| + TRACE_EVENT0("dri", "HDC::SchedulePageFlip"); |
| - if (is_disabled_) |
| + // Ignore requests with no planes to schedule. |
| + if (pending_planes_.empty()) { |
| + callback.Run(); |
| return true; |
| - |
| - std::sort(pending_planes_.begin(), pending_planes_.end(), |
| - [](const OverlayPlane& l, const OverlayPlane& r) { |
| - return l.z_order < r.z_order; |
| - }); |
| - |
| - bool status = true; |
| - for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| - status &= crtc_controllers_[i]->SchedulePageFlip( |
| - owned_hardware_planes_.get(crtc_controllers_[i]->drm()), |
| - pending_planes_); |
| } |
| - for (const auto& planes : owned_hardware_planes_) { |
| - if (!planes.first->plane_manager()->Commit(planes.second)) { |
| - status = false; |
| - } |
| - } |
| - |
| - return status; |
| -} |
| - |
| -void HardwareDisplayController::WaitForPageFlipEvent() { |
| - TRACE_EVENT0("dri", "HDC::WaitForPageFlipEvent"); |
| + requests_.push_back(PageFlipRequest(pending_planes_, callback)); |
| + pending_planes_.clear(); |
| - drmEventContext drm_event; |
| - drm_event.version = DRM_EVENT_CONTEXT_VERSION; |
| - drm_event.page_flip_handler = HandlePageFlipEvent; |
| - drm_event.vblank_handler = NULL; |
| + // A request is being serviced right now. |
| + if (HasPendingPageFlips()) |
| + return true; |
| - bool has_pending_page_flips = false; |
| - // Wait for the page-flips to complete. |
| - for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| - // In mirror mode the page flip callbacks can happen in different order than |
| - // scheduled, so we need to make sure that the event for the current CRTC is |
| - // processed before moving to the next CRTC. |
| - while (crtc_controllers_[i]->page_flip_pending()) { |
| - has_pending_page_flips = true; |
| - crtc_controllers_[i]->drm()->HandleEvent(drm_event); |
| - } |
| - } |
| + bool status = ActualSchedulePageFlip(); |
| - // In case there are no pending pageflips do not replace the current planes |
| - // since they are still being used. |
| - if (has_pending_page_flips) |
| - current_planes_.swap(pending_planes_); |
| + // No page flip event on failure so discard failed request. |
| + if (!status) |
| + requests_.pop_front(); |
| - pending_planes_.clear(); |
| + return status; |
| } |
| bool HardwareDisplayController::SetCursor( |
| @@ -183,6 +151,7 @@ void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { |
| owned_hardware_planes_.add( |
| controller->drm(), |
| scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); |
| + controller->AddObserver(this); |
| crtc_controllers_.push_back(controller.release()); |
| } |
| @@ -193,9 +162,6 @@ scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
| if ((*it)->crtc() == crtc) { |
| scoped_ptr<CrtcController> controller(*it); |
| crtc_controllers_.weak_erase(it); |
| - // Release any planes this crtc might own. |
| - HardwareDisplayPlaneManager::ResetPlanes( |
| - owned_hardware_planes_.find(controller->drm())->second, crtc); |
| // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. |
| bool found = false; |
| for (ScopedVector<CrtcController>::iterator it = |
| @@ -208,6 +174,14 @@ scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
| } |
| if (!found) |
| owned_hardware_planes_.erase(controller->drm()); |
| + |
| + controller->RemoveObserver(this); |
| + // If a display configuration happens mid page flip we want to make sure |
| + // the HDC won't wait for an event from a CRTC that is no longer |
| + // associated with it. |
| + if (controller->page_flip_pending()) |
| + OnPageFlipEvent(); |
| + |
| return controller.Pass(); |
| } |
| } |
| @@ -244,4 +218,85 @@ uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { |
| return time; |
| } |
| +void HardwareDisplayController::OnPageFlipEvent() { |
| + TRACE_EVENT0("dri", "HDC::OnPageFlipEvent"); |
| + if (HasPendingPageFlips()) |
| + return; |
| + |
| + // If a CRTC was moved between HDCs while page-flipping, it will report a page |
| + // flip without any scheduled requests. |
| + if (!requests_.empty()) |
| + ProcessPageFlipRequest(); |
| + |
| + if (requests_.empty()) |
| + return; |
| + |
| + bool status = ActualSchedulePageFlip(); |
| + if (!status) { |
| + PageFlipRequest request = requests_.front(); |
| + requests_.pop_front(); |
| + |
| + // Normally the caller would handle the error call, but because we're in a |
| + // delayed schedule the initial SchedulePageFlip() already returned true, |
| + // this we need to run the callback. |
| + request.callback.Run(); |
| + } |
| +} |
| + |
| +bool HardwareDisplayController::HasPendingPageFlips() const { |
| + for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| + if (crtc_controllers_[i]->page_flip_pending()) |
| + return true; |
| + |
| + return false; |
| +} |
| + |
| +bool HardwareDisplayController::ActualSchedulePageFlip() { |
| + TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip"); |
| + DCHECK(!requests_.empty()); |
| + |
| + if (is_disabled_) { |
| + ProcessPageFlipRequest(); |
| + return true; |
| + } |
| + |
| + OverlayPlaneList pending_planes = requests_.front().planes; |
| + std::sort(pending_planes.begin(), pending_planes.end(), |
| + [](const OverlayPlane& l, const OverlayPlane& r) { |
| + return l.z_order < r.z_order; |
| + }); |
| + |
| + bool status = true; |
| + for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| + status &= crtc_controllers_[i]->SchedulePageFlip( |
| + owned_hardware_planes_.get(crtc_controllers_[i]->drm()), |
| + pending_planes); |
| + } |
| + |
| + for (const auto& planes : owned_hardware_planes_) { |
| + if (!planes.first->plane_manager()->Commit(planes.second)) { |
| + status = false; |
| + } |
| + } |
| + |
| + return status; |
| +} |
| + |
| +void HardwareDisplayController::ProcessPageFlipRequest() { |
| + DCHECK(!requests_.empty()); |
| + PageFlipRequest request = requests_.front(); |
| + requests_.pop_front(); |
| + |
| + current_planes_.swap(request.planes); |
| + request.callback.Run(); |
| +} |
| + |
| +void HardwareDisplayController::ClearPendingRequests() { |
| + while (!requests_.empty()) { |
| + PageFlipRequest request = requests_.front(); |
| + requests_.pop_front(); |
| + request.callback.Run(); |
| + } |
| +} |
| + |
| } // namespace ui |