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

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 {
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698