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

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

Powered by Google App Engine
This is Rietveld 408576698