Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(722)

Unified Diff: ui/ozone/platform/dri/hardware_display_controller.cc

Issue 821023003: [Ozone-DRI] Listen for swap events (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@async-swap
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 7ec4f0dcbc95c4e1f5cc0b4e7883a3fffd9b2db1..7f81355ac93eb4ba436e05cb961114d26bb6286a 100644
--- a/ui/ozone/platform/dri/hardware_display_controller.cc
+++ b/ui/ozone/platform/dri/hardware_display_controller.cc
@@ -22,39 +22,19 @@
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::HardwareDisplayController(
scoped_ptr<CrtcController> controller)
: is_disabled_(true) {
memset(&mode_, 0, sizeof(mode_));
+ pending_planes_.push_back(OverlayPlaneList());
AddCrtc(controller.Pass());
}
HardwareDisplayController::~HardwareDisplayController() {
// Reset the cursor.
UnsetCursor();
+ if (!page_flip_callback_.is_null())
+ page_flip_callback_.Run();
}
bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
@@ -65,10 +45,25 @@ bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
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();
+
+ while (!callbacks_.empty()) {
+ callbacks_.front().Run();
+ callbacks_.pop_front();
+ }
+
+ // 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())
+ pending_planes_.push_back(current_planes_);
+
+ // Need to insert an empty list to accomodate future requests.
+ pending_planes_.push_back(OverlayPlaneList());
+
return status;
}
@@ -89,64 +84,28 @@ void HardwareDisplayController::Disable() {
}
void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) {
- pending_planes_.push_back(plane);
+ pending_planes_.back().push_back(plane);
}
-bool HardwareDisplayController::SchedulePageFlip() {
- DCHECK(!pending_planes_.empty());
+bool HardwareDisplayController::SchedulePageFlip(
+ const base::Closure& callback) {
+ TRACE_EVENT1("dri", "HDC::SchedulePageFlip", "this", this);
- if (is_disabled_)
+ if (pending_planes_.size() > 1) {
+ callbacks_.push_back(callback);
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;
- }
+ bool status =
+ ActualSchedulePageFlip(pending_planes_.front(), callbacks_.front());
+ if (!status) {
+ pending_planes_.pop_front();
+ callbacks_.pop_front();
}
return status;
}
-void HardwareDisplayController::WaitForPageFlipEvent() {
- TRACE_EVENT0("dri", "HDC::WaitForPageFlipEvent");
-
- drmEventContext drm_event;
- drm_event.version = DRM_EVENT_CONTEXT_VERSION;
- drm_event.page_flip_handler = HandlePageFlipEvent;
- drm_event.vblank_handler = NULL;
-
- 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);
- }
- }
-
- // 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_);
-
- pending_planes_.clear();
-}
-
bool HardwareDisplayController::SetCursor(
const scoped_refptr<ScanoutBuffer>& buffer) {
bool status = true;
@@ -183,6 +142,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());
}
@@ -192,6 +152,7 @@ scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
it != crtc_controllers_.end(); ++it) {
if ((*it)->crtc() == crtc) {
scoped_ptr<CrtcController> controller(*it);
+ controller->RemoveObserver(this);
crtc_controllers_.weak_erase(it);
// Remove entry from |owned_hardware_planes_| iff no other crtcs share it.
bool found = false;
@@ -205,6 +166,11 @@ scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
}
if (!found)
owned_hardware_planes_.erase(controller->drm());
+
+ // 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.
+ OnPageFlipEvent();
return controller.Pass();
}
}
@@ -241,4 +207,85 @@ uint64_t HardwareDisplayController::GetTimeOfLastFlip() const {
return time;
}
+void HardwareDisplayController::OnPageFlipEvent() {
+ TRACE_EVENT1("dri", "HDC::OnPageFlipEvent", "this", this);
+ if (page_flip_callback_.is_null())
+ return;
+
+ if (HasPendingPageFlips())
+ return;
+
+ current_planes_.swap(pending_planes_.front());
+ pending_planes_.pop_front();
+
+ // Modesetting can clear the callbacks.
+ if (!callbacks_.empty()) {
+ base::Closure callback = callbacks_.front();
+ callbacks_.pop_front();
+ callback.Run();
+ }
+
+ // If we have pending requests immediately start the next one.
+ if (!pending_planes_.empty() && !pending_planes_.front().empty() &&
+ !callbacks_.empty()) {
+ base::Closure callback = callbacks_.front();
+ bool status = ActualSchedulePageFlip(pending_planes_.front(), callback);
+ if (!status) {
+ pending_planes_.pop_front();
+ callbacks_.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.
+ 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(
+ OverlayPlaneList pending_planes,
+ const base::Closure& callback) {
+ TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip");
+ if (is_disabled_) {
+ callback.Run();
+ return true;
+ }
+
+ // Any overlays in the last list will be scheduled together. Insert an empty
+ // list for the next request.
+ if (!pending_planes_.back().empty())
+ pending_planes_.push_back(OverlayPlaneList());
+
+ 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;
+ }
+ }
+
+ if (!status)
+ callback.Run();
+
+ return status;
+}
+
} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698