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>
42 #include "uterm_drm_shared_internal.h"
43 #include "uterm_drm2d_internal.h"
44 #include "uterm_video.h"
45 #include "uterm_video_internal.h"
47 #define LOG_SUBSYSTEM "video_drm2d"
49 static int display_init(struct uterm_display *disp)
51 struct uterm_drm2d_display *d2d;
54 d2d = malloc(sizeof(*d2d));
57 memset(d2d, 0, sizeof(*d2d));
59 ret = uterm_drm_display_init(disp, d2d);
68 static void display_destroy(struct uterm_display *disp)
70 free(uterm_drm_display_get_data(disp));
71 uterm_drm_display_destroy(disp);
74 static int init_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
77 struct uterm_video *video = disp->video;
78 struct uterm_drm_video *vdrm = video->data;
79 struct drm_mode_create_dumb req;
80 struct drm_mode_destroy_dumb dreq;
81 struct drm_mode_map_dumb mreq;
83 memset(&req, 0, sizeof(req));
84 req.width = uterm_drm_mode_get_width(disp->current_mode);
85 req.height = uterm_drm_mode_get_height(disp->current_mode);
89 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &req);
91 log_err("cannot create dumb drm buffer");
95 rb->handle = req.handle;
96 rb->stride = req.pitch;
99 ret = drmModeAddFB(vdrm->fd, req.width, req.height,
100 24, 32, rb->stride, rb->handle, &rb->fb);
102 log_err("cannot add drm-fb");
107 memset(&mreq, 0, sizeof(mreq));
108 mreq.handle = rb->handle;
110 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
112 log_err("cannot map dumb buffer");
117 rb->map = mmap(0, rb->size, PROT_READ | PROT_WRITE, MAP_SHARED,
118 vdrm->fd, mreq.offset);
119 if (rb->map == MAP_FAILED) {
120 log_err("cannot mmap dumb buffer");
124 memset(rb->map, 0, rb->size);
129 drmModeRmFB(vdrm->fd, rb->fb);
131 memset(&dreq, 0, sizeof(dreq));
132 dreq.handle = rb->handle;
133 r = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
135 log_warning("cannot destroy dumb buffer (%d/%d): %m",
141 static void destroy_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
143 struct uterm_drm_video *vdrm = disp->video->data;
144 struct drm_mode_destroy_dumb dreq;
147 munmap(rb->map, rb->size);
148 drmModeRmFB(vdrm->fd, rb->fb);
149 memset(&dreq, 0, sizeof(dreq));
150 dreq.handle = rb->handle;
151 ret = drmIoctl(vdrm->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
154 log_warning("cannot destroy dumb buffer (%d/%d): %m",
158 static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
160 struct uterm_video *video = disp->video;
161 struct uterm_drm_video *vdrm = video->data;
162 struct uterm_drm_display *ddrm = disp->data;
163 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
165 drmModeModeInfo *minfo;
170 minfo = uterm_drm_mode_get_info(mode);;
171 log_info("activating display %p to %ux%u", disp,
172 minfo->hdisplay, minfo->vdisplay);
174 ret = uterm_drm_display_activate(disp, vdrm->fd);
179 disp->current_mode = mode;
181 ret = init_rb(disp, &d2d->rb[0]);
185 ret = init_rb(disp, &d2d->rb[1]);
189 ret = drmModeSetCrtc(vdrm->fd, ddrm->crtc_id,
190 d2d->rb[0].fb, 0, 0, &ddrm->conn_id, 1,
193 log_err("cannot set drm-crtc");
198 disp->flags |= DISPLAY_ONLINE;
202 destroy_rb(disp, &d2d->rb[1]);
204 destroy_rb(disp, &d2d->rb[0]);
206 disp->current_mode = NULL;
207 uterm_drm_display_deactivate(disp, vdrm->fd);
211 static void display_deactivate(struct uterm_display *disp)
213 struct uterm_drm_video *vdrm;
214 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
216 vdrm = disp->video->data;
217 log_info("deactivating display %p", disp);
219 uterm_drm_display_deactivate(disp, vdrm->fd);
221 destroy_rb(disp, &d2d->rb[1]);
222 destroy_rb(disp, &d2d->rb[0]);
223 disp->current_mode = NULL;
226 static int display_use(struct uterm_display *disp, bool *opengl)
228 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
233 return d2d->current_rb ^ 1;
236 static int display_get_buffers(struct uterm_display *disp,
237 struct uterm_video_buffer *buffer,
238 unsigned int formats)
240 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
241 struct uterm_drm2d_rb *rb;
244 if (!(formats & UTERM_FORMAT_XRGB32))
247 for (i = 0; i < 2; ++i) {
249 buffer[i].width = uterm_drm_mode_get_width(disp->current_mode);
250 buffer[i].height = uterm_drm_mode_get_height(disp->current_mode);
251 buffer[i].stride = rb->stride;
252 buffer[i].format = UTERM_FORMAT_XRGB32;
253 buffer[i].data = rb->map;
259 static int display_swap(struct uterm_display *disp, bool immediate)
262 struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
264 rb = d2d->current_rb ^ 1;
265 ret = uterm_drm_display_swap(disp, d2d->rb[rb].fb, immediate);
269 d2d->current_rb = rb;
273 static const struct display_ops drm2d_display_ops = {
274 .init = display_init,
275 .destroy = display_destroy,
276 .activate = display_activate,
277 .deactivate = display_deactivate,
278 .set_dpms = uterm_drm_display_set_dpms,
280 .get_buffers = display_get_buffers,
281 .swap = display_swap,
282 .blit = uterm_drm2d_display_blit,
283 .fake_blendv = uterm_drm2d_display_fake_blendv,
284 .fill = uterm_drm2d_display_fill,
287 static void show_displays(struct uterm_video *video)
289 struct uterm_display *iter;
290 struct uterm_drm2d_display *d2d;
291 struct uterm_drm2d_rb *rb;
294 if (!video_is_awake(video))
297 shl_dlist_for_each(i, &video->displays) {
298 iter = shl_dlist_entry(i, struct uterm_display, list);
300 if (!display_is_online(iter))
302 if (iter->dpms != UTERM_DPMS_ON)
305 /* We use double-buffering so there might be no free back-buffer
306 * here. Hence, draw into the current (pending) front-buffer and
307 * wait for possible page-flips to complete. This might cause
308 * tearing but that's acceptable as this is only called during
311 d2d = uterm_drm_display_get_data(iter);
312 rb = &d2d->rb[d2d->current_rb];
313 memset(rb->map, 0, rb->size);
314 uterm_drm_display_wait_pflip(iter);
318 static int video_init(struct uterm_video *video, const char *node)
322 struct uterm_drm_video *vdrm;
324 ret = uterm_drm_video_init(video, node, NULL, NULL);
329 log_debug("initialize 2D layer on %p", video);
331 if (drmGetCap(vdrm->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 ||
333 log_err("driver does not support dumb buffers");
334 uterm_drm_video_destroy(video);
341 static void video_destroy(struct uterm_video *video)
343 log_info("free drm video device %p", video);
344 uterm_drm_video_destroy(video);
347 static int video_poll(struct uterm_video *video)
349 return uterm_drm_video_poll(video, &drm2d_display_ops);
352 static void video_sleep(struct uterm_video *video)
354 show_displays(video);
355 uterm_drm_video_sleep(video);
358 static int video_wake_up(struct uterm_video *video)
362 ret = uterm_drm_video_wake_up(video, &drm2d_display_ops);
366 show_displays(video);
370 static const struct video_ops drm2d_video_ops = {
372 .destroy = video_destroy,
373 .segfault = NULL, /* TODO: reset all saved CRTCs on segfault */
375 .sleep = video_sleep,
376 .wake_up = video_wake_up,
379 static const struct uterm_video_module drm2d_module = {
380 .ops = &drm2d_video_ops,
383 const struct uterm_video_module *UTERM_VIDEO_DRM2D = &drm2d_module;