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

Side by Side 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 unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698