2 * uterm - Linux User-Space Terminal drm2d module
4 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * DRM Video backend using dumb buffer objects
39 #include <xf86drmMode.h>
43 #include "uterm_drm_shared_internal.h"
44 #include "uterm_drm2d_internal.h"
45 #include "uterm_video.h"
46 #include "uterm_video_internal.h"
48 #define LOG_SUBSYSTEM "video_drm2d"
50 static int display_init(struct uterm_display *disp)
52 struct uterm_drm2d_display *d2d;
55 d2d = malloc(sizeof(*d2d));
58 memset(d2d, 0, sizeof(*d2d));
60 ret = uterm_drm_display_init(disp, d2d);
69 static void display_destroy(struct uterm_display *disp)
71 free(uterm_drm_display_get_data(disp));
72 uterm_drm_display_destroy(disp);
75 static int init_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
78 struct uterm_video *video = disp->video;
79 struct uterm_drm_video *vdrm = video->data;
80 struct drm_mode_create_dumb req;
81 struct drm_mode_destroy_dumb dreq;
82 struct drm_mode_map_dumb mreq;
84 memset(&req, 0, sizeof(req));
85 req.width = uterm_drm_mode_get_width(disp->current_mode);
86 req.height = uterm_drm_mode_get_height(disp->current_mode);
90 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &req);
92 log_err("cannot create dumb drm buffer");
96 rb->handle = req.handle;
97 rb->stride = req.pitch;
100 ret = drmModeAddFB(vdrm->fd, req.width, req.height,
101 24, 32, rb->stride, rb->handle, &rb->fb);
103 log_err("cannot add drm-fb");
108 memset(&mreq, 0, sizeof(mreq));
109 mreq.handle = rb->handle;
111 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
113 log_err("cannot map dumb buffer");
118 rb->map = mmap(0, rb->size, PROT_READ | PROT_WRITE, MAP_SHARED,
119 vdrm->fd, mreq.offset);
120 if (rb->map == MAP_FAILED) {
121 log_err("cannot mmap dumb buffer");
125 memset(rb->map, 0, rb->size);
130 drmModeRmFB(vdrm->fd, rb->fb);
132 memset(&dreq, 0, sizeof(dreq));
133 dreq.handle = rb->handle;
134 r = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
136 log_warning("cannot destroy dumb buffer (%d/%d): %m",
142 static void destroy_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
144 struct uterm_drm_video *vdrm = disp->video->data;
145 struct drm_mode_destroy_dumb dreq;
148 munmap(rb->map, rb->size);
149 drmModeRmFB(vdrm->fd, rb->fb);
150 memset(&dreq, 0, sizeof(dreq));
151 dreq.handle = rb->handle;
152 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
155 log_warning("cannot destroy dumb buffer (%d/%d): %m",
159 static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
161 struct uterm_video *video = disp->video;
162 struct uterm_drm_video *vdrm = video->data;
163 struct uterm_drm_display *ddrm = disp->data;
164 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
166 drmModeModeInfo *minfo;
171 minfo = uterm_drm_mode_get_info(mode);;
172 log_info("activating display %p to %ux%u", disp,
173 minfo->hdisplay, minfo->vdisplay);
175 ret = uterm_drm_display_activate(disp, vdrm->fd);
180 disp->current_mode = mode;
182 ret = init_rb(disp, &d2d->rb[0]);
186 ret = init_rb(disp, &d2d->rb[1]);
190 ret = drmModeSetCrtc(vdrm->fd, ddrm->crtc_id,
191 d2d->rb[0].fb, 0, 0, &ddrm->conn_id, 1,
194 log_err("cannot set drm-crtc");
199 disp->flags |= DISPLAY_ONLINE;
203 destroy_rb(disp, &d2d->rb[1]);
205 destroy_rb(disp, &d2d->rb[0]);
207 disp->current_mode = NULL;
208 uterm_drm_display_deactivate(disp, vdrm->fd);
212 static void display_deactivate(struct uterm_display *disp)
214 struct uterm_drm_video *vdrm;
215 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
217 vdrm = disp->video->data;
218 log_info("deactivating display %p", disp);
220 uterm_drm_display_deactivate(disp, vdrm->fd);
222 destroy_rb(disp, &d2d->rb[1]);
223 destroy_rb(disp, &d2d->rb[0]);
224 disp->current_mode = NULL;
227 static int display_use(struct uterm_display *disp, bool *opengl)
229 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
234 return d2d->current_rb ^ 1;
237 static int display_get_buffers(struct uterm_display *disp,
238 struct uterm_video_buffer *buffer,
239 unsigned int formats)
241 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
242 struct uterm_drm2d_rb *rb;
245 if (!(formats & UTERM_FORMAT_XRGB32))
248 for (i = 0; i < 2; ++i) {
250 buffer[i].width = uterm_drm_mode_get_width(disp->current_mode);
251 buffer[i].height = uterm_drm_mode_get_height(disp->current_mode);
252 buffer[i].stride = rb->stride;
253 buffer[i].format = UTERM_FORMAT_XRGB32;
254 buffer[i].data = rb->map;
260 static int display_swap(struct uterm_display *disp, bool immediate)
263 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
265 rb = d2d->current_rb ^ 1;
266 ret = uterm_drm_display_swap(disp, d2d->rb[rb].fb, immediate);
270 d2d->current_rb = rb;
274 static const struct display_ops drm2d_display_ops = {
275 .init = display_init,
276 .destroy = display_destroy,
277 .activate = display_activate,
278 .deactivate = display_deactivate,
279 .set_dpms = uterm_drm_display_set_dpms,
281 .get_buffers = display_get_buffers,
282 .swap = display_swap,
283 .blit = uterm_drm2d_display_blit,
284 .fake_blendv = uterm_drm2d_display_fake_blendv,
285 .fill = uterm_drm2d_display_fill,
288 static void show_displays(struct uterm_video *video)
290 struct uterm_display *iter;
291 struct uterm_drm2d_display *d2d;
292 struct uterm_drm2d_rb *rb;
295 if (!video_is_awake(video))
298 shl_dlist_for_each(i, &video->displays) {
299 iter = shl_dlist_entry(i, struct uterm_display, list);
301 if (!display_is_online(iter))
303 if (iter->dpms != UTERM_DPMS_ON)
306 /* We use double-buffering so there might be no free back-buffer
307 * here. Hence, draw into the current (pending) front-buffer and
308 * wait for possible page-flips to complete. This might cause
309 * tearing but that's acceptable as this is only called during
312 d2d = uterm_drm_display_get_data(iter);
313 rb = &d2d->rb[d2d->current_rb];
314 memset(rb->map, 0, rb->size);
315 uterm_drm_display_wait_pflip(iter);
319 static int video_init(struct uterm_video *video, const char *node)
323 struct uterm_drm_video *vdrm;
325 ret = uterm_drm_video_init(video, node, NULL, NULL);
330 log_debug("initialize 2D layer on %p", video);
332 if (drmGetCap(vdrm->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
334 log_err("driver does not support dumb buffers");
335 uterm_drm_video_destroy(video);
342 static void video_destroy(struct uterm_video *video)
344 log_info("free drm video device %p", video);
345 uterm_drm_video_destroy(video);
348 static int video_poll(struct uterm_video *video)
350 return uterm_drm_video_poll(video, &drm2d_display_ops);
353 static void video_sleep(struct uterm_video *video)
355 show_displays(video);
356 uterm_drm_video_sleep(video);
359 static int video_wake_up(struct uterm_video *video)
363 ret = uterm_drm_video_wake_up(video, &drm2d_display_ops);
367 show_displays(video);
371 static const struct video_ops drm2d_video_ops = {
373 .destroy = video_destroy,
374 .segfault = NULL, /* TODO: reset all saved CRTCs on segfault */
376 .sleep = video_sleep,
377 .wake_up = video_wake_up,
380 static const struct uterm_video_module drm2d_module = {
381 .ops = &drm2d_video_ops,
385 const struct uterm_video_module *UTERM_VIDEO_DRM2D = &drm2d_module;