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/dri_wrapper.h" | 5 #include "ui/ozone/platform/dri/dri_wrapper.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <sys/mman.h> | 8 #include <sys/mman.h> |
9 #include <unistd.h> | 9 #include <unistd.h> |
10 #include <xf86drm.h> | 10 #include <xf86drm.h> |
11 #include <xf86drmMode.h> | 11 #include <xf86drmMode.h> |
12 | 12 |
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 "base/message_loop/message_loop.h" | |
15 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
17 #include "base/task_runner.h" | |
18 #include "base/thread_task_runner_handle.h" | |
16 #include "third_party/skia/include/core/SkImageInfo.h" | 19 #include "third_party/skia/include/core/SkImageInfo.h" |
17 #include "ui/ozone/platform/dri/dri_util.h" | 20 #include "ui/ozone/platform/dri/dri_util.h" |
18 #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" | 21 #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h" |
19 | 22 |
20 namespace ui { | 23 namespace ui { |
21 | 24 |
22 namespace { | 25 namespace { |
23 | 26 |
27 struct PageFlipPayload { | |
28 PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner, | |
alexst (slow to review)
2015/01/09 03:55:46
You should mention which thread this task runner b
dnicoara
2015/01/09 15:08:24
Added some comments. In principle it doesn't matte
| |
29 const DriWrapper::PageFlipCallback& callback) | |
30 : task_runner(task_runner), callback(callback) {} | |
31 | |
32 scoped_refptr<base::TaskRunner> task_runner; | |
33 DriWrapper::PageFlipCallback callback; | |
34 }; | |
35 | |
24 bool DrmCreateDumbBuffer(int fd, | 36 bool DrmCreateDumbBuffer(int fd, |
25 const SkImageInfo& info, | 37 const SkImageInfo& info, |
26 uint32_t* handle, | 38 uint32_t* handle, |
27 uint32_t* stride) { | 39 uint32_t* stride) { |
28 struct drm_mode_create_dumb request; | 40 struct drm_mode_create_dumb request; |
29 memset(&request, 0, sizeof(request)); | 41 memset(&request, 0, sizeof(request)); |
30 request.width = info.width(); | 42 request.width = info.width(); |
31 request.height = info.height(); | 43 request.height = info.height(); |
32 request.bpp = info.bytesPerPixel() << 3; | 44 request.bpp = info.bytesPerPixel() << 3; |
33 request.flags = 0; | 45 request.flags = 0; |
(...skipping 14 matching lines...) Expand all Loading... | |
48 return true; | 60 return true; |
49 } | 61 } |
50 | 62 |
51 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { | 63 void DrmDestroyDumbBuffer(int fd, uint32_t handle) { |
52 struct drm_mode_destroy_dumb destroy_request; | 64 struct drm_mode_destroy_dumb destroy_request; |
53 memset(&destroy_request, 0, sizeof(destroy_request)); | 65 memset(&destroy_request, 0, sizeof(destroy_request)); |
54 destroy_request.handle = handle; | 66 destroy_request.handle = handle; |
55 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); | 67 drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request); |
56 } | 68 } |
57 | 69 |
70 void HandlePageFlipEventOnIO(int fd, | |
71 unsigned int frame, | |
72 unsigned int seconds, | |
73 unsigned int useconds, | |
74 void* data) { | |
75 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | |
76 payload->task_runner->PostTask( | |
77 FROM_HERE, base::Bind(payload->callback, frame, seconds, useconds)); | |
78 } | |
79 | |
80 void HandlePageFlipEventOnUI(int fd, | |
81 unsigned int frame, | |
82 unsigned int seconds, | |
83 unsigned int useconds, | |
84 void* data) { | |
85 scoped_ptr<PageFlipPayload> payload(static_cast<PageFlipPayload*>(data)); | |
86 payload->callback.Run(frame, seconds, useconds); | |
87 } | |
88 | |
58 } // namespace | 89 } // namespace |
59 | 90 |
60 DriWrapper::DriWrapper(const char* device_path) | 91 class DriWrapper::IOWatcher |
61 : fd_(-1), device_path_(device_path) { | 92 : public base::RefCountedThreadSafe<DriWrapper::IOWatcher>, |
93 public base::MessagePumpLibevent::Watcher { | |
94 public: | |
95 IOWatcher(int fd, | |
96 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | |
97 : io_task_runner_(io_task_runner) { | |
98 io_task_runner_->PostTask(FROM_HERE, | |
99 base::Bind(&IOWatcher::RegisterOnIO, this, fd)); | |
100 } | |
101 | |
102 private: | |
103 friend class base::RefCountedThreadSafe<IOWatcher>; | |
104 | |
105 ~IOWatcher() override { | |
106 io_task_runner_->PostTask(FROM_HERE, | |
107 base::Bind(&IOWatcher::UnregisterOnIO, this)); | |
alexst (slow to review)
2015/01/09 03:55:46
I am pretty sure this is not safe, we are in the d
dnicoara
2015/01/09 15:08:24
Doh! You are right, move the post in a Shutdown()
| |
108 } | |
109 | |
110 void RegisterOnIO(int fd) { | |
111 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
112 base::MessageLoopForIO::current()->WatchFileDescriptor( | |
113 fd, true, base::MessageLoopForIO::WATCH_READ, &controller_, this); | |
114 } | |
115 | |
116 void UnregisterOnIO() { | |
117 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
alexst (slow to review)
2015/01/09 03:55:46
Is this checking that an IO type thread is current
dnicoara
2015/01/09 15:08:24
Yes. It would be hard to check which IO message lo
| |
118 controller_.StopWatchingFileDescriptor(); | |
119 } | |
120 | |
121 // base::MessagePumpLibevent::Watcher overrides: | |
122 void OnFileCanReadWithoutBlocking(int fd) override { | |
123 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
124 TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd); | |
125 | |
126 drmEventContext event; | |
127 event.version = DRM_EVENT_CONTEXT_VERSION; | |
128 event.page_flip_handler = HandlePageFlipEventOnIO; | |
129 event.vblank_handler = nullptr; | |
130 | |
131 drmHandleEvent(fd, &event); | |
132 } | |
133 | |
134 void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); } | |
135 | |
136 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | |
137 | |
138 base::MessagePumpLibevent::FileDescriptorWatcher controller_; | |
139 | |
140 DISALLOW_COPY_AND_ASSIGN(IOWatcher); | |
141 }; | |
142 | |
143 DriWrapper::DriWrapper(const char* device_path, bool software_mode) | |
144 : fd_(-1), | |
145 software_mode_(software_mode), | |
146 device_path_(device_path), | |
147 io_thread_("DriIOThread") { | |
62 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); | 148 plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy()); |
63 } | 149 } |
64 | 150 |
65 DriWrapper::~DriWrapper() { | 151 DriWrapper::~DriWrapper() { |
66 if (fd_ >= 0) | 152 if (fd_ >= 0) |
67 close(fd_); | 153 close(fd_); |
68 } | 154 } |
69 | 155 |
70 void DriWrapper::Initialize() { | 156 void DriWrapper::Initialize() { |
71 fd_ = open(device_path_, O_RDWR | O_CLOEXEC); | 157 fd_ = open(device_path_, O_RDWR | O_CLOEXEC); |
72 if (fd_ < 0) | 158 if (fd_ < 0) |
73 PLOG(FATAL) << "open: " << device_path_; | 159 PLOG(FATAL) << "open: " << device_path_; |
74 if (!plane_manager_->Initialize(this)) | 160 if (!plane_manager_->Initialize(this)) |
75 LOG(ERROR) << "Failed to initialize the plane manager"; | 161 LOG(ERROR) << "Failed to initialize the plane manager"; |
76 } | 162 } |
77 | 163 |
164 void DriWrapper::InitializeIOWatcher() { | |
165 if (!software_mode_ && !watcher_) { | |
166 if (!io_thread_.StartWithOptions( | |
167 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) | |
168 LOG(FATAL) << "Failed to start the IO helper thread"; | |
169 | |
170 watcher_ = new IOWatcher(fd_, io_thread_.task_runner()); | |
171 } | |
172 } | |
173 | |
78 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { | 174 ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) { |
79 DCHECK(fd_ >= 0); | 175 DCHECK(fd_ >= 0); |
80 return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); | 176 return ScopedDrmCrtcPtr(drmModeGetCrtc(fd_, crtc_id)); |
81 } | 177 } |
82 | 178 |
83 bool DriWrapper::SetCrtc(uint32_t crtc_id, | 179 bool DriWrapper::SetCrtc(uint32_t crtc_id, |
84 uint32_t framebuffer, | 180 uint32_t framebuffer, |
85 std::vector<uint32_t> connectors, | 181 std::vector<uint32_t> connectors, |
86 drmModeModeInfo* mode) { | 182 drmModeModeInfo* mode) { |
87 DCHECK(fd_ >= 0); | 183 DCHECK(fd_ >= 0); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 | 250 |
155 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { | 251 bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) { |
156 DCHECK(fd_ >= 0); | 252 DCHECK(fd_ >= 0); |
157 TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", | 253 TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer", |
158 "framebuffer", framebuffer); | 254 "framebuffer", framebuffer); |
159 return !drmModeRmFB(fd_, framebuffer); | 255 return !drmModeRmFB(fd_, framebuffer); |
160 } | 256 } |
161 | 257 |
162 bool DriWrapper::PageFlip(uint32_t crtc_id, | 258 bool DriWrapper::PageFlip(uint32_t crtc_id, |
163 uint32_t framebuffer, | 259 uint32_t framebuffer, |
164 void* data) { | 260 const PageFlipCallback& callback) { |
165 DCHECK(fd_ >= 0); | 261 DCHECK(fd_ >= 0); |
166 TRACE_EVENT2("dri", "DriWrapper::PageFlip", | 262 TRACE_EVENT2("dri", "DriWrapper::PageFlip", |
167 "crtc", crtc_id, | 263 "crtc", crtc_id, |
168 "framebuffer", framebuffer); | 264 "framebuffer", framebuffer); |
169 return !drmModePageFlip(fd_, | 265 |
170 crtc_id, | 266 // NOTE: Calling drmModeSetCrtc will immediately update the state, though |
171 framebuffer, | 267 // callbacks to already scheduled page flips will be honored by the kernel. |
172 DRM_MODE_PAGE_FLIP_EVENT, | 268 scoped_ptr<PageFlipPayload> payload( |
173 data); | 269 new PageFlipPayload(base::ThreadTaskRunnerHandle::Get(), callback)); |
270 if (!drmModePageFlip(fd_, crtc_id, framebuffer, DRM_MODE_PAGE_FLIP_EVENT, | |
271 payload.get())) { | |
272 // If successful the payload will be removed by a PageFlip event. | |
273 ignore_result(payload.release()); | |
274 if (software_mode_) { | |
275 TRACE_EVENT1("dri", "OnDrmEvent", "socket", fd_); | |
276 | |
277 drmEventContext event; | |
278 event.version = DRM_EVENT_CONTEXT_VERSION; | |
279 event.page_flip_handler = HandlePageFlipEventOnUI; | |
280 event.vblank_handler = nullptr; | |
281 | |
282 drmHandleEvent(fd_, &event); | |
283 } else { | |
284 InitializeIOWatcher(); | |
285 } | |
286 | |
287 return true; | |
288 } | |
289 | |
290 return false; | |
174 } | 291 } |
175 | 292 |
176 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, | 293 bool DriWrapper::PageFlipOverlay(uint32_t crtc_id, |
177 uint32_t framebuffer, | 294 uint32_t framebuffer, |
178 const gfx::Rect& location, | 295 const gfx::Rect& location, |
179 const gfx::Rect& source, | 296 const gfx::Rect& source, |
180 int overlay_plane) { | 297 int overlay_plane) { |
181 DCHECK(fd_ >= 0); | 298 DCHECK(fd_ >= 0); |
182 TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", | 299 TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay", |
183 "crtc", crtc_id, | 300 "crtc", crtc_id, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 DCHECK(fd_ >= 0); | 367 DCHECK(fd_ >= 0); |
251 TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); | 368 TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle); |
252 return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height()); | 369 return !drmModeSetCursor(fd_, crtc_id, handle, size.width(), size.height()); |
253 } | 370 } |
254 | 371 |
255 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { | 372 bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) { |
256 DCHECK(fd_ >= 0); | 373 DCHECK(fd_ >= 0); |
257 return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); | 374 return !drmModeMoveCursor(fd_, crtc_id, point.x(), point.y()); |
258 } | 375 } |
259 | 376 |
260 void DriWrapper::HandleEvent(drmEventContext& event) { | |
261 DCHECK(fd_ >= 0); | |
262 TRACE_EVENT0("dri", "DriWrapper::HandleEvent"); | |
263 drmHandleEvent(fd_, &event); | |
264 } | |
265 | |
266 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, | 377 bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info, |
267 uint32_t* handle, | 378 uint32_t* handle, |
268 uint32_t* stride, | 379 uint32_t* stride, |
269 void** pixels) { | 380 void** pixels) { |
270 DCHECK(fd_ >= 0); | 381 DCHECK(fd_ >= 0); |
271 | 382 |
272 TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); | 383 TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer"); |
273 if (!DrmCreateDumbBuffer(fd_, info, handle, stride)) | 384 if (!DrmCreateDumbBuffer(fd_, info, handle, stride)) |
274 return false; | 385 return false; |
275 | 386 |
(...skipping 19 matching lines...) Expand all Loading... | |
295 DCHECK(fd_ >= 0); | 406 DCHECK(fd_ >= 0); |
296 return (drmSetMaster(fd_) == 0); | 407 return (drmSetMaster(fd_) == 0); |
297 } | 408 } |
298 | 409 |
299 bool DriWrapper::DropMaster() { | 410 bool DriWrapper::DropMaster() { |
300 DCHECK(fd_ >= 0); | 411 DCHECK(fd_ >= 0); |
301 return (drmDropMaster(fd_) == 0); | 412 return (drmDropMaster(fd_) == 0); |
302 } | 413 } |
303 | 414 |
304 } // namespace ui | 415 } // namespace ui |
OLD | NEW |