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 |