| 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/dri/hardware_display_controller.h" | 5 #include "ui/ozone/platform/dri/hardware_display_controller.h" |
| 6 | 6 |
| 7 #include <drm.h> | 7 #include <drm.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <xf86drm.h> | 10 #include <xf86drm.h> |
| 11 | 11 |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "third_party/skia/include/core/SkCanvas.h" | 15 #include "third_party/skia/include/core/SkCanvas.h" |
| 16 #include "ui/gfx/geometry/point.h" | 16 #include "ui/gfx/geometry/point.h" |
| 17 #include "ui/gfx/geometry/size.h" | 17 #include "ui/gfx/geometry/size.h" |
| 18 #include "ui/ozone/platform/dri/crtc_controller.h" | 18 #include "ui/ozone/platform/dri/crtc_controller.h" |
| 19 #include "ui/ozone/platform/dri/dri_buffer.h" | 19 #include "ui/ozone/platform/dri/dri_buffer.h" |
| 20 #include "ui/ozone/platform/dri/dri_wrapper.h" | 20 #include "ui/ozone/platform/dri/dri_wrapper.h" |
| 21 #include "ui/ozone/public/native_pixmap.h" | 21 #include "ui/ozone/public/native_pixmap.h" |
| 22 | 22 |
| 23 namespace ui { | 23 namespace ui { |
| 24 | 24 |
| 25 namespace { | |
| 26 | |
| 27 // DRM callback on page flip events. This callback is triggered after the | |
| 28 // page flip has happened and the backbuffer is now the new frontbuffer | |
| 29 // The old frontbuffer is no longer used by the hardware and can be used for | |
| 30 // future draw operations. | |
| 31 // | |
| 32 // |device| will contain a reference to the |ScanoutSurface| object which | |
| 33 // the event belongs to. | |
| 34 // | |
| 35 // TODO(dnicoara) When we have a FD handler for the DRM calls in the message | |
| 36 // loop, we can move this function in the handler. | |
| 37 void HandlePageFlipEvent(int fd, | |
| 38 unsigned int frame, | |
| 39 unsigned int seconds, | |
| 40 unsigned int useconds, | |
| 41 void* controller) { | |
| 42 static_cast<CrtcController*>(controller) | |
| 43 ->OnPageFlipEvent(frame, seconds, useconds); | |
| 44 } | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 48 HardwareDisplayController::HardwareDisplayController( | 25 HardwareDisplayController::HardwareDisplayController( |
| 49 scoped_ptr<CrtcController> controller) | 26 scoped_ptr<CrtcController> controller) |
| 50 : is_disabled_(true) { | 27 : is_disabled_(true) { |
| 51 memset(&mode_, 0, sizeof(mode_)); | 28 memset(&mode_, 0, sizeof(mode_)); |
| 29 pending_planes_.push_back(OverlayPlaneList()); |
| 52 AddCrtc(controller.Pass()); | 30 AddCrtc(controller.Pass()); |
| 53 } | 31 } |
| 54 | 32 |
| 55 HardwareDisplayController::~HardwareDisplayController() { | 33 HardwareDisplayController::~HardwareDisplayController() { |
| 56 // Reset the cursor. | 34 // Reset the cursor. |
| 57 UnsetCursor(); | 35 UnsetCursor(); |
| 36 if (!page_flip_callback_.is_null()) |
| 37 page_flip_callback_.Run(); |
| 58 } | 38 } |
| 59 | 39 |
| 60 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, | 40 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
| 61 drmModeModeInfo mode) { | 41 drmModeModeInfo mode) { |
| 62 TRACE_EVENT0("dri", "HDC::Modeset"); | 42 TRACE_EVENT0("dri", "HDC::Modeset"); |
| 63 DCHECK(primary.buffer.get()); | 43 DCHECK(primary.buffer.get()); |
| 64 bool status = true; | 44 bool status = true; |
| 65 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 45 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 66 status &= crtc_controllers_[i]->Modeset(primary, mode); | 46 status &= crtc_controllers_[i]->Modeset(primary, mode); |
| 67 | 47 |
| 48 is_disabled_ = false; |
| 49 mode_ = mode; |
| 50 |
| 68 current_planes_ = std::vector<OverlayPlane>(1, primary); | 51 current_planes_ = std::vector<OverlayPlane>(1, primary); |
| 69 pending_planes_.clear(); | 52 pending_planes_.clear(); |
| 70 is_disabled_ = false; | 53 |
| 71 mode_ = mode; | 54 while (!callbacks_.empty()) { |
| 55 callbacks_.front().Run(); |
| 56 callbacks_.pop_front(); |
| 57 } |
| 58 |
| 59 // Because a page flip is pending we need to leave some state for the |
| 60 // callback. We use the modeset state since it is the only valid state. |
| 61 if (HasPendingPageFlips()) |
| 62 pending_planes_.push_back(current_planes_); |
| 63 |
| 64 // Need to insert an empty list to accomodate future requests. |
| 65 pending_planes_.push_back(OverlayPlaneList()); |
| 66 |
| 72 return status; | 67 return status; |
| 73 } | 68 } |
| 74 | 69 |
| 75 bool HardwareDisplayController::Enable() { | 70 bool HardwareDisplayController::Enable() { |
| 76 TRACE_EVENT0("dri", "HDC::Enable"); | 71 TRACE_EVENT0("dri", "HDC::Enable"); |
| 77 DCHECK(!current_planes_.empty()); | 72 DCHECK(!current_planes_.empty()); |
| 78 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_); | 73 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_); |
| 79 | 74 |
| 80 return Modeset(*primary, mode_); | 75 return Modeset(*primary, mode_); |
| 81 } | 76 } |
| 82 | 77 |
| 83 void HardwareDisplayController::Disable() { | 78 void HardwareDisplayController::Disable() { |
| 84 TRACE_EVENT0("dri", "HDC::Disable"); | 79 TRACE_EVENT0("dri", "HDC::Disable"); |
| 85 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 80 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 86 crtc_controllers_[i]->Disable(); | 81 crtc_controllers_[i]->Disable(); |
| 87 | 82 |
| 88 is_disabled_ = true; | 83 is_disabled_ = true; |
| 89 } | 84 } |
| 90 | 85 |
| 91 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) { | 86 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) { |
| 92 pending_planes_.push_back(plane); | 87 pending_planes_.back().push_back(plane); |
| 93 } | 88 } |
| 94 | 89 |
| 95 bool HardwareDisplayController::SchedulePageFlip() { | 90 bool HardwareDisplayController::SchedulePageFlip( |
| 96 DCHECK(!pending_planes_.empty()); | 91 const base::Closure& callback) { |
| 92 TRACE_EVENT1("dri", "HDC::SchedulePageFlip", "this", this); |
| 97 | 93 |
| 98 if (is_disabled_) | 94 if (pending_planes_.size() > 1) { |
| 95 callbacks_.push_back(callback); |
| 99 return true; | 96 return true; |
| 100 | |
| 101 std::sort(pending_planes_.begin(), pending_planes_.end(), | |
| 102 [](const OverlayPlane& l, const OverlayPlane& r) { | |
| 103 return l.z_order < r.z_order; | |
| 104 }); | |
| 105 | |
| 106 bool status = true; | |
| 107 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
| 108 status &= crtc_controllers_[i]->SchedulePageFlip( | |
| 109 owned_hardware_planes_.get(crtc_controllers_[i]->drm()), | |
| 110 pending_planes_); | |
| 111 } | 97 } |
| 112 | 98 |
| 113 for (const auto& planes : owned_hardware_planes_) { | 99 bool status = |
| 114 if (!planes.first->plane_manager()->Commit(planes.second)) { | 100 ActualSchedulePageFlip(pending_planes_.front(), callbacks_.front()); |
| 115 status = false; | 101 if (!status) { |
| 116 } | 102 pending_planes_.pop_front(); |
| 103 callbacks_.pop_front(); |
| 117 } | 104 } |
| 118 | 105 |
| 119 return status; | 106 return status; |
| 120 } | 107 } |
| 121 | 108 |
| 122 void HardwareDisplayController::WaitForPageFlipEvent() { | |
| 123 TRACE_EVENT0("dri", "HDC::WaitForPageFlipEvent"); | |
| 124 | |
| 125 drmEventContext drm_event; | |
| 126 drm_event.version = DRM_EVENT_CONTEXT_VERSION; | |
| 127 drm_event.page_flip_handler = HandlePageFlipEvent; | |
| 128 drm_event.vblank_handler = NULL; | |
| 129 | |
| 130 bool has_pending_page_flips = false; | |
| 131 // Wait for the page-flips to complete. | |
| 132 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
| 133 // In mirror mode the page flip callbacks can happen in different order than | |
| 134 // scheduled, so we need to make sure that the event for the current CRTC is | |
| 135 // processed before moving to the next CRTC. | |
| 136 while (crtc_controllers_[i]->page_flip_pending()) { | |
| 137 has_pending_page_flips = true; | |
| 138 crtc_controllers_[i]->drm()->HandleEvent(drm_event); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 // In case there are no pending pageflips do not replace the current planes | |
| 143 // since they are still being used. | |
| 144 if (has_pending_page_flips) | |
| 145 current_planes_.swap(pending_planes_); | |
| 146 | |
| 147 pending_planes_.clear(); | |
| 148 } | |
| 149 | |
| 150 bool HardwareDisplayController::SetCursor( | 109 bool HardwareDisplayController::SetCursor( |
| 151 const scoped_refptr<ScanoutBuffer>& buffer) { | 110 const scoped_refptr<ScanoutBuffer>& buffer) { |
| 152 bool status = true; | 111 bool status = true; |
| 153 | 112 |
| 154 if (is_disabled_) | 113 if (is_disabled_) |
| 155 return true; | 114 return true; |
| 156 | 115 |
| 157 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 116 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 158 status &= crtc_controllers_[i]->SetCursor(buffer); | 117 status &= crtc_controllers_[i]->SetCursor(buffer); |
| 159 | 118 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 176 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 135 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 177 status &= crtc_controllers_[i]->MoveCursor(location); | 136 status &= crtc_controllers_[i]->MoveCursor(location); |
| 178 | 137 |
| 179 return status; | 138 return status; |
| 180 } | 139 } |
| 181 | 140 |
| 182 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { | 141 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { |
| 183 owned_hardware_planes_.add( | 142 owned_hardware_planes_.add( |
| 184 controller->drm(), | 143 controller->drm(), |
| 185 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); | 144 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); |
| 145 controller->AddObserver(this); |
| 186 crtc_controllers_.push_back(controller.release()); | 146 crtc_controllers_.push_back(controller.release()); |
| 187 } | 147 } |
| 188 | 148 |
| 189 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( | 149 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
| 190 uint32_t crtc) { | 150 uint32_t crtc) { |
| 191 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); | 151 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); |
| 192 it != crtc_controllers_.end(); ++it) { | 152 it != crtc_controllers_.end(); ++it) { |
| 193 if ((*it)->crtc() == crtc) { | 153 if ((*it)->crtc() == crtc) { |
| 194 scoped_ptr<CrtcController> controller(*it); | 154 scoped_ptr<CrtcController> controller(*it); |
| 155 controller->RemoveObserver(this); |
| 195 crtc_controllers_.weak_erase(it); | 156 crtc_controllers_.weak_erase(it); |
| 196 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. | 157 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. |
| 197 bool found = false; | 158 bool found = false; |
| 198 for (ScopedVector<CrtcController>::iterator it = | 159 for (ScopedVector<CrtcController>::iterator it = |
| 199 crtc_controllers_.begin(); | 160 crtc_controllers_.begin(); |
| 200 it != crtc_controllers_.end(); ++it) { | 161 it != crtc_controllers_.end(); ++it) { |
| 201 if ((*it)->drm() == controller->drm()) { | 162 if ((*it)->drm() == controller->drm()) { |
| 202 found = true; | 163 found = true; |
| 203 break; | 164 break; |
| 204 } | 165 } |
| 205 } | 166 } |
| 206 if (!found) | 167 if (!found) |
| 207 owned_hardware_planes_.erase(controller->drm()); | 168 owned_hardware_planes_.erase(controller->drm()); |
| 169 |
| 170 // If a display configuration happens mid page flip we want to make sure |
| 171 // the HDC won't wait for an event from a CRTC that is no longer |
| 172 // associated with it. |
| 173 OnPageFlipEvent(); |
| 208 return controller.Pass(); | 174 return controller.Pass(); |
| 209 } | 175 } |
| 210 } | 176 } |
| 211 | 177 |
| 212 return scoped_ptr<CrtcController>(); | 178 return scoped_ptr<CrtcController>(); |
| 213 } | 179 } |
| 214 | 180 |
| 215 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const { | 181 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const { |
| 216 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 182 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 217 if (crtc_controllers_[i]->crtc() == crtc) | 183 if (crtc_controllers_[i]->crtc() == crtc) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 234 | 200 |
| 235 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { | 201 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { |
| 236 uint64_t time = 0; | 202 uint64_t time = 0; |
| 237 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 203 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 238 if (time < crtc_controllers_[i]->time_of_last_flip()) | 204 if (time < crtc_controllers_[i]->time_of_last_flip()) |
| 239 time = crtc_controllers_[i]->time_of_last_flip(); | 205 time = crtc_controllers_[i]->time_of_last_flip(); |
| 240 | 206 |
| 241 return time; | 207 return time; |
| 242 } | 208 } |
| 243 | 209 |
| 210 void HardwareDisplayController::OnPageFlipEvent() { |
| 211 TRACE_EVENT1("dri", "HDC::OnPageFlipEvent", "this", this); |
| 212 if (page_flip_callback_.is_null()) |
| 213 return; |
| 214 |
| 215 if (HasPendingPageFlips()) |
| 216 return; |
| 217 |
| 218 current_planes_.swap(pending_planes_.front()); |
| 219 pending_planes_.pop_front(); |
| 220 |
| 221 // Modesetting can clear the callbacks. |
| 222 if (!callbacks_.empty()) { |
| 223 base::Closure callback = callbacks_.front(); |
| 224 callbacks_.pop_front(); |
| 225 callback.Run(); |
| 226 } |
| 227 |
| 228 // If we have pending requests immediately start the next one. |
| 229 if (!pending_planes_.empty() && !pending_planes_.front().empty() && |
| 230 !callbacks_.empty()) { |
| 231 base::Closure callback = callbacks_.front(); |
| 232 bool status = ActualSchedulePageFlip(pending_planes_.front(), callback); |
| 233 if (!status) { |
| 234 pending_planes_.pop_front(); |
| 235 callbacks_.pop_front(); |
| 236 |
| 237 // Normally the caller would handle the error call, but because we're in a |
| 238 // delayed schedule the initial SchedulePageFlip() already returned true, |
| 239 // this we need to run the callback. |
| 240 callback.Run(); |
| 241 } |
| 242 } |
| 243 } |
| 244 |
| 245 bool HardwareDisplayController::HasPendingPageFlips() const { |
| 246 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 247 if (crtc_controllers_[i]->page_flip_pending()) |
| 248 return true; |
| 249 |
| 250 return false; |
| 251 } |
| 252 |
| 253 bool HardwareDisplayController::ActualSchedulePageFlip( |
| 254 OverlayPlaneList pending_planes, |
| 255 const base::Closure& callback) { |
| 256 TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip"); |
| 257 if (is_disabled_) { |
| 258 callback.Run(); |
| 259 return true; |
| 260 } |
| 261 |
| 262 // Any overlays in the last list will be scheduled together. Insert an empty |
| 263 // list for the next request. |
| 264 if (!pending_planes_.back().empty()) |
| 265 pending_planes_.push_back(OverlayPlaneList()); |
| 266 |
| 267 std::sort(pending_planes.begin(), pending_planes.end(), |
| 268 [](const OverlayPlane& l, const OverlayPlane& r) { |
| 269 return l.z_order < r.z_order; |
| 270 }); |
| 271 |
| 272 bool status = true; |
| 273 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| 274 status &= crtc_controllers_[i]->SchedulePageFlip( |
| 275 owned_hardware_planes_.get(crtc_controllers_[i]->drm()), |
| 276 pending_planes); |
| 277 } |
| 278 |
| 279 for (const auto& planes : owned_hardware_planes_) { |
| 280 if (!planes.first->plane_manager()->Commit(planes.second)) { |
| 281 status = false; |
| 282 } |
| 283 } |
| 284 |
| 285 if (!status) |
| 286 callback.Run(); |
| 287 |
| 288 return status; |
| 289 } |
| 290 |
| 244 } // namespace ui | 291 } // namespace ui |
| OLD | NEW |