Chromium Code Reviews| 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 { | 25 HardwareDisplayController::PageFlipRequest::PageFlipRequest( |
| 26 | 26 const OverlayPlaneList& planes, |
| 27 // DRM callback on page flip events. This callback is triggered after the | 27 const base::Closure& callback) |
| 28 // page flip has happened and the backbuffer is now the new frontbuffer | 28 : planes(planes), callback(callback) { |
| 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 } | 29 } |
| 45 | 30 |
| 46 } // namespace | 31 HardwareDisplayController::PageFlipRequest::~PageFlipRequest() { |
| 32 } | |
| 47 | 33 |
| 48 HardwareDisplayController::HardwareDisplayController( | 34 HardwareDisplayController::HardwareDisplayController( |
| 49 scoped_ptr<CrtcController> controller) | 35 scoped_ptr<CrtcController> controller) |
| 50 : is_disabled_(true) { | 36 : is_disabled_(true) { |
| 51 memset(&mode_, 0, sizeof(mode_)); | 37 memset(&mode_, 0, sizeof(mode_)); |
| 52 AddCrtc(controller.Pass()); | 38 AddCrtc(controller.Pass()); |
| 53 } | 39 } |
| 54 | 40 |
| 55 HardwareDisplayController::~HardwareDisplayController() { | 41 HardwareDisplayController::~HardwareDisplayController() { |
| 56 // Reset the cursor. | 42 // Reset the cursor. |
| 57 UnsetCursor(); | 43 UnsetCursor(); |
| 44 ClearPendingRequests(); | |
| 58 } | 45 } |
| 59 | 46 |
| 60 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, | 47 bool HardwareDisplayController::Modeset(const OverlayPlane& primary, |
| 61 drmModeModeInfo mode) { | 48 drmModeModeInfo mode) { |
| 62 TRACE_EVENT0("dri", "HDC::Modeset"); | 49 TRACE_EVENT0("dri", "HDC::Modeset"); |
| 50 LOG(ERROR) << "modeset"; | |
|
alexst (slow to review)
2015/01/09 03:55:46
Debug message.
dnicoara
2015/01/09 15:08:24
Removed.
| |
| 63 DCHECK(primary.buffer.get()); | 51 DCHECK(primary.buffer.get()); |
| 64 bool status = true; | 52 bool status = true; |
| 65 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 53 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 66 status &= crtc_controllers_[i]->Modeset(primary, mode); | 54 status &= crtc_controllers_[i]->Modeset(primary, mode); |
| 67 | 55 |
| 56 is_disabled_ = false; | |
| 57 mode_ = mode; | |
| 58 | |
| 68 current_planes_ = std::vector<OverlayPlane>(1, primary); | 59 current_planes_ = std::vector<OverlayPlane>(1, primary); |
| 69 pending_planes_.clear(); | 60 pending_planes_.clear(); |
| 70 is_disabled_ = false; | 61 ClearPendingRequests(); |
| 71 mode_ = mode; | 62 |
| 63 // Because a page flip is pending we need to leave some state for the | |
| 64 // callback. We use the modeset state since it is the only valid state. | |
| 65 if (HasPendingPageFlips()) | |
| 66 requests_.push_back( | |
| 67 PageFlipRequest(current_planes_, base::Bind(&base::DoNothing))); | |
| 68 | |
| 72 return status; | 69 return status; |
| 73 } | 70 } |
| 74 | 71 |
| 75 bool HardwareDisplayController::Enable() { | 72 bool HardwareDisplayController::Enable() { |
| 76 TRACE_EVENT0("dri", "HDC::Enable"); | 73 TRACE_EVENT0("dri", "HDC::Enable"); |
| 77 DCHECK(!current_planes_.empty()); | 74 DCHECK(!current_planes_.empty()); |
| 78 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_); | 75 const OverlayPlane* primary = OverlayPlane::GetPrimaryPlane(current_planes_); |
| 79 | 76 |
| 80 return Modeset(*primary, mode_); | 77 return Modeset(*primary, mode_); |
| 81 } | 78 } |
| 82 | 79 |
| 83 void HardwareDisplayController::Disable() { | 80 void HardwareDisplayController::Disable() { |
| 84 TRACE_EVENT0("dri", "HDC::Disable"); | 81 TRACE_EVENT0("dri", "HDC::Disable"); |
| 85 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 82 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 86 crtc_controllers_[i]->Disable(); | 83 crtc_controllers_[i]->Disable(); |
| 87 | 84 |
| 88 is_disabled_ = true; | 85 is_disabled_ = true; |
| 89 } | 86 } |
| 90 | 87 |
| 91 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) { | 88 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) { |
| 92 pending_planes_.push_back(plane); | 89 pending_planes_.push_back(plane); |
| 93 } | 90 } |
| 94 | 91 |
| 95 bool HardwareDisplayController::SchedulePageFlip() { | 92 bool HardwareDisplayController::SchedulePageFlip( |
| 96 DCHECK(!pending_planes_.empty()); | 93 const base::Closure& callback) { |
| 94 TRACE_EVENT0("dri", "HDC::SchedulePageFlip"); | |
| 97 | 95 |
| 98 if (is_disabled_) | 96 // Ignore requests with no planes to schedule. |
| 97 if (pending_planes_.empty()) { | |
| 98 callback.Run(); | |
| 99 return true; | |
| 100 } | |
| 101 | |
| 102 requests_.push_back(PageFlipRequest(pending_planes_, callback)); | |
| 103 pending_planes_.clear(); | |
| 104 | |
| 105 // A request is being serviced right now. | |
| 106 if (HasPendingPageFlips()) | |
| 99 return true; | 107 return true; |
| 100 | 108 |
| 101 std::sort(pending_planes_.begin(), pending_planes_.end(), | 109 bool status = ActualSchedulePageFlip(); |
| 102 [](const OverlayPlane& l, const OverlayPlane& r) { | |
| 103 return l.z_order < r.z_order; | |
| 104 }); | |
| 105 | 110 |
| 106 bool status = true; | 111 // No page flip event on failure so discard failed request. |
| 107 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | 112 if (!status) |
| 108 status &= crtc_controllers_[i]->SchedulePageFlip( | 113 requests_.pop_front(); |
| 109 owned_hardware_planes_.get(crtc_controllers_[i]->drm()), | |
| 110 pending_planes_); | |
| 111 } | |
| 112 | |
| 113 for (const auto& planes : owned_hardware_planes_) { | |
| 114 if (!planes.first->plane_manager()->Commit(planes.second)) { | |
| 115 status = false; | |
| 116 } | |
| 117 } | |
| 118 | 114 |
| 119 return status; | 115 return status; |
| 120 } | 116 } |
| 121 | 117 |
| 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( | 118 bool HardwareDisplayController::SetCursor( |
| 151 const scoped_refptr<ScanoutBuffer>& buffer) { | 119 const scoped_refptr<ScanoutBuffer>& buffer) { |
| 152 bool status = true; | 120 bool status = true; |
| 153 | 121 |
| 154 if (is_disabled_) | 122 if (is_disabled_) |
| 155 return true; | 123 return true; |
| 156 | 124 |
| 157 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 125 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 158 status &= crtc_controllers_[i]->SetCursor(buffer); | 126 status &= crtc_controllers_[i]->SetCursor(buffer); |
| 159 | 127 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 176 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 144 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 177 status &= crtc_controllers_[i]->MoveCursor(location); | 145 status &= crtc_controllers_[i]->MoveCursor(location); |
| 178 | 146 |
| 179 return status; | 147 return status; |
| 180 } | 148 } |
| 181 | 149 |
| 182 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { | 150 void HardwareDisplayController::AddCrtc(scoped_ptr<CrtcController> controller) { |
| 183 owned_hardware_planes_.add( | 151 owned_hardware_planes_.add( |
| 184 controller->drm(), | 152 controller->drm(), |
| 185 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); | 153 scoped_ptr<HardwareDisplayPlaneList>(new HardwareDisplayPlaneList())); |
| 154 controller->AddObserver(this); | |
| 186 crtc_controllers_.push_back(controller.release()); | 155 crtc_controllers_.push_back(controller.release()); |
| 187 } | 156 } |
| 188 | 157 |
| 189 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( | 158 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc( |
| 190 uint32_t crtc) { | 159 uint32_t crtc) { |
| 191 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); | 160 for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin(); |
| 192 it != crtc_controllers_.end(); ++it) { | 161 it != crtc_controllers_.end(); ++it) { |
| 193 if ((*it)->crtc() == crtc) { | 162 if ((*it)->crtc() == crtc) { |
| 194 scoped_ptr<CrtcController> controller(*it); | 163 scoped_ptr<CrtcController> controller(*it); |
| 195 crtc_controllers_.weak_erase(it); | 164 crtc_controllers_.weak_erase(it); |
| 196 // Release any planes this crtc might own. | |
| 197 HardwareDisplayPlaneManager::ResetPlanes( | |
| 198 owned_hardware_planes_.find(controller->drm())->second, crtc); | |
| 199 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. | 165 // Remove entry from |owned_hardware_planes_| iff no other crtcs share it. |
| 200 bool found = false; | 166 bool found = false; |
| 201 for (ScopedVector<CrtcController>::iterator it = | 167 for (ScopedVector<CrtcController>::iterator it = |
| 202 crtc_controllers_.begin(); | 168 crtc_controllers_.begin(); |
| 203 it != crtc_controllers_.end(); ++it) { | 169 it != crtc_controllers_.end(); ++it) { |
| 204 if ((*it)->drm() == controller->drm()) { | 170 if ((*it)->drm() == controller->drm()) { |
| 205 found = true; | 171 found = true; |
| 206 break; | 172 break; |
| 207 } | 173 } |
| 208 } | 174 } |
| 209 if (!found) | 175 if (!found) |
| 210 owned_hardware_planes_.erase(controller->drm()); | 176 owned_hardware_planes_.erase(controller->drm()); |
| 177 | |
| 178 controller->RemoveObserver(this); | |
| 179 // If a display configuration happens mid page flip we want to make sure | |
| 180 // the HDC won't wait for an event from a CRTC that is no longer | |
| 181 // associated with it. | |
| 182 if (controller->page_flip_pending()) | |
| 183 OnPageFlipEvent(); | |
| 184 | |
| 211 return controller.Pass(); | 185 return controller.Pass(); |
| 212 } | 186 } |
| 213 } | 187 } |
| 214 | 188 |
| 215 return scoped_ptr<CrtcController>(); | 189 return scoped_ptr<CrtcController>(); |
| 216 } | 190 } |
| 217 | 191 |
| 218 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const { | 192 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const { |
| 219 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 193 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 220 if (crtc_controllers_[i]->crtc() == crtc) | 194 if (crtc_controllers_[i]->crtc() == crtc) |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 237 | 211 |
| 238 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { | 212 uint64_t HardwareDisplayController::GetTimeOfLastFlip() const { |
| 239 uint64_t time = 0; | 213 uint64_t time = 0; |
| 240 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | 214 for (size_t i = 0; i < crtc_controllers_.size(); ++i) |
| 241 if (time < crtc_controllers_[i]->time_of_last_flip()) | 215 if (time < crtc_controllers_[i]->time_of_last_flip()) |
| 242 time = crtc_controllers_[i]->time_of_last_flip(); | 216 time = crtc_controllers_[i]->time_of_last_flip(); |
| 243 | 217 |
| 244 return time; | 218 return time; |
| 245 } | 219 } |
| 246 | 220 |
| 221 void HardwareDisplayController::OnPageFlipEvent() { | |
| 222 TRACE_EVENT0("dri", "HDC::OnPageFlipEvent"); | |
| 223 if (HasPendingPageFlips()) | |
| 224 return; | |
| 225 | |
| 226 // If a CRTC was moved between HDCs while page-flipping, it will report a page | |
| 227 // flip without any scheduled requests. | |
| 228 if (!requests_.empty()) | |
| 229 ProcessPageFlipRequest(); | |
| 230 | |
| 231 if (requests_.empty()) | |
| 232 return; | |
| 233 | |
| 234 bool status = ActualSchedulePageFlip(); | |
| 235 if (!status) { | |
| 236 PageFlipRequest request = requests_.front(); | |
| 237 requests_.pop_front(); | |
| 238 | |
| 239 // Normally the caller would handle the error call, but because we're in a | |
| 240 // delayed schedule the initial SchedulePageFlip() already returned true, | |
| 241 // this we need to run the callback. | |
| 242 request.callback.Run(); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 bool HardwareDisplayController::HasPendingPageFlips() const { | |
| 247 for (size_t i = 0; i < crtc_controllers_.size(); ++i) | |
| 248 if (crtc_controllers_[i]->page_flip_pending()) | |
| 249 return true; | |
| 250 | |
| 251 return false; | |
| 252 } | |
| 253 | |
| 254 bool HardwareDisplayController::ActualSchedulePageFlip() { | |
| 255 TRACE_EVENT0("dri", "HDC::ActualSchedulePageFlip"); | |
| 256 DCHECK(!requests_.empty()); | |
| 257 | |
| 258 if (is_disabled_) { | |
| 259 ProcessPageFlipRequest(); | |
| 260 return true; | |
| 261 } | |
| 262 | |
| 263 OverlayPlaneList pending_planes = requests_.front().planes; | |
| 264 std::sort(pending_planes.begin(), pending_planes.end(), | |
| 265 [](const OverlayPlane& l, const OverlayPlane& r) { | |
| 266 return l.z_order < r.z_order; | |
| 267 }); | |
| 268 | |
| 269 bool status = true; | |
| 270 for (size_t i = 0; i < crtc_controllers_.size(); ++i) { | |
| 271 status &= crtc_controllers_[i]->SchedulePageFlip( | |
| 272 owned_hardware_planes_.get(crtc_controllers_[i]->drm()), | |
| 273 pending_planes); | |
| 274 } | |
| 275 | |
| 276 for (const auto& planes : owned_hardware_planes_) { | |
| 277 if (!planes.first->plane_manager()->Commit(planes.second)) { | |
| 278 status = false; | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 return status; | |
| 283 } | |
| 284 | |
| 285 void HardwareDisplayController::ProcessPageFlipRequest() { | |
| 286 DCHECK(!requests_.empty()); | |
| 287 PageFlipRequest request = requests_.front(); | |
| 288 requests_.pop_front(); | |
| 289 | |
| 290 current_planes_.swap(request.planes); | |
| 291 request.callback.Run(); | |
| 292 } | |
| 293 | |
| 294 void HardwareDisplayController::ClearPendingRequests() { | |
| 295 while (!requests_.empty()) { | |
| 296 PageFlipRequest request = requests_.front(); | |
| 297 requests_.pop_front(); | |
| 298 request.callback.Run(); | |
| 299 } | |
| 300 } | |
| 301 | |
| 247 } // namespace ui | 302 } // namespace ui |
| OLD | NEW |