| 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 |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" | 14 #include "third_party/skia/include/core/SkCanvas.h" |
| 15 #include "ui/gfx/geometry/point.h" | 15 #include "ui/gfx/geometry/point.h" |
| 16 #include "ui/gfx/geometry/size.h" | 16 #include "ui/gfx/geometry/size.h" |
| 17 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" | 17 #include "ui/ozone/platform/drm/gpu/crtc_controller.h" |
| 18 #include "ui/ozone/platform/drm/gpu/drm_buffer.h" | 18 #include "ui/ozone/platform/drm/gpu/drm_buffer.h" |
| 19 #include "ui/ozone/platform/drm/gpu/drm_device.h" | 19 #include "ui/ozone/platform/drm/gpu/drm_device.h" |
| 20 #include "ui/ozone/platform/drm/gpu/page_flip_request.h" |
| 20 #include "ui/ozone/public/native_pixmap.h" | 21 #include "ui/ozone/public/native_pixmap.h" |
| 21 | 22 |
| 22 namespace ui { | 23 namespace ui { |
| 23 | 24 |
| 24 HardwareDisplayController::PageFlipRequest::PageFlipRequest( | |
| 25 const OverlayPlaneList& planes, | |
| 26 bool is_sync, | |
| 27 const base::Closure& callback) | |
| 28 : planes(planes), is_sync(is_sync), callback(callback) { | |
| 29 } | |
| 30 | |
| 31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { | |
| 32 } | |
| 33 | |
| 34 HardwareDisplayController::HardwareDisplayController( | 25 HardwareDisplayController::HardwareDisplayController( |
| 35 scoped_ptr<CrtcController> controller) | 26 scoped_ptr<CrtcController> controller) |
| 36 : is_disabled_(true) { | 27 : is_disabled_(true) { |
| 37 memset(&mode_, 0, sizeof(mode_)); | 28 memset(&mode_, 0, sizeof(mode_)); |
| 38 AddCrtc(controller.Pass()); | 29 AddCrtc(controller.Pass()); |
| 39 } | 30 } |
| 40 | 31 |
| 41 HardwareDisplayController::~HardwareDisplayController() { | 32 HardwareDisplayController::~HardwareDisplayController() { |
| 42 // Reset the cursor. | 33 // Reset the cursor. |
| 43 UnsetCursor(); | 34 UnsetCursor(); |
| 44 ClearPendingRequests(); | |
| 45 } | 35 } |
| 46 | 36 |
| 47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, | 37 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
| 48 drmModeModeInfo mode) { | 38 drmModeModeInfo mode) { |
| 49 TRACE_EVENT0("drm", "HDC::Modeset"); | 39 TRACE_EVENT0("drm", "HDC::Modeset"); |
| 50 DCHECK(primary.buffer.get()); | 40 DCHECK(primary.buffer.get()); |
| 51 bool status = true; | 41 bool status = true; |
| 52 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 42 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 53 status &= crtc_controllers_[i]->Modeset(primary, mode); | 43 status &= crtc_controllers_[i]->Modeset(primary, mode); |
| 54 | 44 |
| 55 is_disabled_ = false; | 45 is_disabled_ = false; |
| 56 mode_ = mode; | 46 mode_ = mode; |
| 57 | 47 |
| 58 current_planes_ = std::vector<OverlayPlane>(1, primary); | |
| 59 ClearPendingRequests(); | |
| 60 | |
| 61 // Because a page flip is pending we need to leave some state for the | |
| 62 // callback. We use the modeset state since it is the only valid state. | |
| 63 if (HasPendingPageFlips()) | |
| 64 requests_.push_back( | |
| 65 PageFlipRequest(current_planes_, false, base::Bind(&base::DoNothing))); | |
| 66 | |
| 67 return status; | 48 return status; |
| 68 } | 49 } |
| 69 | 50 |
| 70 void HardwareDisplayController::Disable() { | 51 void HardwareDisplayController::Disable() { |
| 71 TRACE_EVENT0("drm", "HDC::Disable"); | 52 TRACE_EVENT0("drm", "HDC::Disable"); |
| 72 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 53 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 73 crtc_controllers_[i]->Disable(); | 54 crtc_controllers_[i]->Disable(); |
| 74 | 55 |
| 75 // Don't hold onto any requests because we don't track fron buffer while | |
| 76 // disabled. | |
| 77 while (requests_.size()) | |
| 78 ProcessPageFlipRequest(); | |
| 79 | |
| 80 current_planes_.clear(); | |
| 81 | 56 |
| 82 is_disabled_ = true; | 57 is_disabled_ = true; |
| 83 } | 58 } |
| 84 | 59 |
| 85 bool HardwareDisplayController::SchedulePageFlip( | 60 bool HardwareDisplayController::SchedulePageFlip( |
| 86 const OverlayPlaneList& plane_list, | 61 const OverlayPlaneList& plane_list, |
| 87 bool is_sync, | 62 bool is_sync, |
| 88 const base::Closure& callback) { | 63 const base::Closure& callback) { |
| 89 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); | 64 TRACE_EVENT0("drm", "HDC::SchedulePageFlip"); |
| 90 | 65 |
| 66 DCHECK(!is_disabled_); |
| 67 |
| 91 // Ignore requests with no planes to schedule. | 68 // Ignore requests with no planes to schedule. |
| 92 if (plane_list.empty()) { | 69 if (plane_list.empty()) { |
| 93 callback.Run(); | 70 callback.Run(); |
| 94 return true; | 71 return true; |
| 95 } | 72 } |
| 96 | 73 |
| 97 requests_.push_back(PageFlipRequest(plane_list, is_sync, callback)); | 74 scoped_refptr<PageFlipRequest> page_flip_request = |
| 75 new PageFlipRequest(crtc_controllers_.size(), callback); |
| 98 | 76 |
| 99 // A request is being serviced right now. | 77 OverlayPlaneList pending_planes = plane_list; |
| 100 if (HasPendingPageFlips()) | 78 std::sort(pending_planes.begin(), pending_planes.end(), |
| 101 return true; | 79 [](const OverlayPlane& l, const OverlayPlane& r) { |
| 80 return l.z_order < r.z_order; |
| 81 }); |
| 102 | 82 |
| 103 bool status = ActualSchedulePageFlip(); | 83 bool status = true; |
| 84 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { |
| 85 status &= crtc_controllers_[i]->SchedulePageFlip( |
| 86 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), |
| 87 pending_planes, page_flip_request); |
| 88 } |
| 104 | 89 |
| 105 // No page flip event on failure so discard failed request. | 90 for (const auto& planes : owned_hardware_planes_) { |
| 106 if (!status) | 91 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { |
| 107 requests_.pop_front(); | 92 status = false; |
| 93 } |
| 94 } |
| 108 | 95 |
| 109 return status; | 96 return status; |
| 110 } | 97 } |
| 111 | 98 |
| 112 bool HardwareDisplayController::SetCursor( | 99 bool HardwareDisplayController::SetCursor( |
| 113 const scoped_refptr<ScanoutBuffer>& buffer) { | 100 const scoped_refptr<ScanoutBuffer>& buffer) { |
| 114 bool status = true; | 101 bool status = true; |
| 115 | 102 |
| 116 if (is_disabled_) | 103 if (is_disabled_) |
| 117 return true; | 104 return true; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 138 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 125 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 139 status &= crtc_controllers_[i]->MoveCursor(location); | 126 status &= crtc_controllers_[i]->MoveCursor(location); |
| 140 | 127 |
| 141 return status; | 128 return status; |
| 142 } | 129 } |
| 143 | 130 |
| 144 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { | 131 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { |
| 145 owned_hardware_planes_.add( | 132 owned_hardware_planes_.add( |
| 146 controller->drm().get(), | 133 controller->drm().get(), |
| 147 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); | 134 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); |
| 148 controller->AddObserver(this); | |
| 149 crtc_controllers_.push_back(controller.release()); | 135 crtc_controllers_.push_back(controller.release()); |
| 150 } | 136 } |
| 151 | 137 |
| 152 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( | 138 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
| 153 const scoped_refptr<DrmDevice>& drm, | 139 const scoped_refptr<DrmDevice>& drm, |
| 154 uint32_t crtc) { | 140 uint32_t crtc) { |
| 155 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); | 141 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); |
| 156 it != crtc_controllers_.end(); ++it) { | 142 it != crtc_controllers_.end(); ++it) { |
| 157 if ((*it)->drm() == drm && (*it)->crtc() == crtc) { | 143 if ((*it)->drm() == drm && (*it)->crtc() == crtc) { |
| 158 scoped_ptr<CrtcController> controller(*it); | 144 scoped_ptr<CrtcController> controller(*it); |
| 159 crtc_controllers_.weak_erase(it); | 145 crtc_controllers_.weak_erase(it); |
| 160 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. | 146 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. |
| 161 bool found = false; | 147 bool found = false; |
| 162 for (ScopedVector<CrtcController>::iterator it = | 148 for (ScopedVector<CrtcController>::iterator it = |
| 163 crtc_controllers_.begin(); | 149 crtc_controllers_.begin(); |
| 164 it != crtc_controllers_.end(); ++it) { | 150 it != crtc_controllers_.end(); ++it) { |
| 165 if ((*it)->drm() == controller->drm()) { | 151 if ((*it)->drm() == controller->drm()) { |
| 166 found = true; | 152 found = true; |
| 167 break; | 153 break; |
| 168 } | 154 } |
| 169 } | 155 } |
| 170 if (!found) | 156 if (!found) |
| 171 owned_hardware_planes_.erase(controller->drm().get()); | 157 owned_hardware_planes_.erase(controller->drm().get()); |
| 172 | 158 |
| 173 controller->RemoveObserver(this); | |
| 174 // If a display configuration happens mid page flip we want to make sure | |
| 175 // the HDC won't wait for an event from a CRTC that is no longer | |
| 176 // associated with it. | |
| 177 if (controller->page_flip_pending()) | |
| 178 OnPageFlipEvent(); | |
| 179 | |
| 180 return controller.Pass(); | 159 return controller.Pass(); |
| 181 } | 160 } |
| 182 } | 161 } |
| 183 | 162 |
| 184 return nullptr; | 163 return nullptr; |
| 185 } | 164 } |
| 186 | 165 |
| 187 bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, | 166 bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm, |
| 188 uint32_t crtc) const { | 167 uint32_t crtc) const { |
| 189 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 168 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 208 | 187 |
| 209 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { | 188 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { |
| 210 uint64_t time = 0; | 189 uint64_t time = 0; |
| 211 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 190 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 212 if (time < crtc_controllers_[i]->time_of_last_flip()) | 191 if (time < crtc_controllers_[i]->time_of_last_flip()) |
| 213 time = crtc_controllers_[i]->time_of_last_flip(); | 192 time = crtc_controllers_[i]->time_of_last_flip(); |
| 214 | 193 |
| 215 return time; | 194 return time; |
| 216 } | 195 } |
| 217 | 196 |
| 218 void HardwareDisplayController::OnPageFlipEvent() { | |
| 219 TRACE_EVENT0("drm", "HDC::OnPageFlipEvent"); | |
| 220 // OnPageFlipEvent() needs to handle 2 cases: | |
| 221 // 1) Normal page flips in which case: | |
| 222 // a) HasPendingPageFlips() may return false if we're in mirror mode and | |
| 223 // one of the CRTCs hasn't finished page flipping. In this case we want | |
| 224 // to wait for all the CRTCs. | |
| 225 // b) HasPendingPageFlips() returns true in which case all CRTCs are ready | |
| 226 // for the next request. In this case we expect that |requests_| isn't | |
| 227 // empty. | |
| 228 // 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 | |
| 230 // CRTCs will honor the scheduled page flip. Thus we need to handle page | |
| 231 // flip events with no requests. | |
| 232 | |
| 233 if (HasPendingPageFlips()) | |
| 234 return; | |
| 235 | |
| 236 if (!requests_.empty()) | |
| 237 ProcessPageFlipRequest(); | |
| 238 | |
| 239 // ProcessPageFlipRequest() consumes a request. | |
| 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 } | |
| 255 | |
| 256 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() | 197 scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice() |
| 257 const { | 198 const { |
| 258 DCHECK(!crtc_controllers_.empty()); | 199 DCHECK(!crtc_controllers_.empty()); |
| 259 // TODO(dnicoara) When we support mirroring across DRM devices, figure out | 200 // TODO(dnicoara) When we support mirroring across DRM devices, figure out |
| 260 // which device should be used for allocations. | 201 // which device should be used for allocations. |
| 261 return crtc_controllers_[0]->drm(); | 202 return crtc_controllers_[0]->drm(); |
| 262 } | 203 } |
| 263 | 204 |
| 264 bool HardwareDisplayController::HasPendingPageFlips() const { | |
| 265 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | |
| 266 if (crtc_controllers_[i]->page_flip_pending()) | |
| 267 return true; | |
| 268 | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 272 bool HardwareDisplayController::ActualSchedulePageFlip() { | |
| 273 TRACE_EVENT0("drm", "HDC::ActualSchedulePageFlip"); | |
| 274 DCHECK(!requests_.empty()); | |
| 275 | |
| 276 if (is_disabled_) { | |
| 277 ProcessPageFlipRequest(); | |
| 278 return true; | |
| 279 } | |
| 280 | |
| 281 OverlayPlaneList pending_planes = requests_.front().planes; | |
| 282 std::sort(pending_planes.begin(), pending_planes.end(), | |
| 283 [](const OverlayPlane& l, const OverlayPlane& r) { | |
| 284 return l.z_order < r.z_order; | |
| 285 }); | |
| 286 | |
| 287 bool status = true; | |
| 288 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
| 289 status &= crtc_controllers_[i]->SchedulePageFlip( | |
| 290 owned_hardware_planes_.get(crtc_controllers_[i]->drm().get()), | |
| 291 pending_planes); | |
| 292 } | |
| 293 | |
| 294 bool is_sync = requests_.front().is_sync; | |
| 295 for (const auto& planes : owned_hardware_planes_) { | |
| 296 if (!planes.first->plane_manager()->Commit(planes.second, is_sync)) { | |
| 297 status = false; | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 return status; | |
| 302 } | |
| 303 | |
| 304 void HardwareDisplayController::ProcessPageFlipRequest() { | |
| 305 DCHECK(!requests_.empty()); | |
| 306 PageFlipRequest request = requests_.front(); | |
| 307 requests_.pop_front(); | |
| 308 | |
| 309 current_planes_.swap(request.planes); | |
| 310 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 } | |
| 319 } | |
| 320 | |
| 321 } // namespace ui | 205 } // namespace ui |
| OLD | NEW |