1 /*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include <X11/Xlib.h>
26 #include <X11/extensions/Xvlib.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29 #include <cairo.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdbool.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <drm.h>
37 #include <xf86drm.h>
38 #include <i915_drm.h>
39 #include "../overlay.h"
40 #include "dri2.h"
41 #include "position.h"
42 #include "rgb2yuv.h"
43
44 #ifndef ALIGN
45 #define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
46 #endif
47
48 #define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
49 #define FOURCC_RGB565 ((16 << 24) + ('B' << 16) + ('G' << 8) + 'R')
50 #define FOURCC_RGB888 ((24 << 24) + ('B' << 16) + ('G' << 8) + 'R')
51
52 struct x11_overlay {
53 struct overlay base;
54 Display *dpy;
55 GC gc;
56 XvPortID port;
57 XvImage *image;
58 void *map, *mem;
59 int size;
60 unsigned name;
61 int x, y;
62 int visible;
63 };
to_x11_overlay(struct overlay * o)64 static inline struct x11_overlay *to_x11_overlay(struct overlay *o)
65 {
66 return (struct x11_overlay *)o;
67 }
68
noop(Display * dpy,XErrorEvent * event)69 static int noop(Display *dpy, XErrorEvent *event)
70 {
71 return 0;
72 }
73
x11_overlay_show(struct overlay * overlay)74 static void x11_overlay_show(struct overlay *overlay)
75 {
76 struct x11_overlay *priv = to_x11_overlay(overlay);
77
78 if (priv->image->id == FOURCC_XVMC)
79 rgb2yuv(priv->base.surface, priv->image, priv->map);
80 else
81 memcpy(priv->map, priv->mem, priv->size);
82
83 if (!priv->visible) {
84 XvPutImage(priv->dpy, priv->port, DefaultRootWindow(priv->dpy),
85 priv->gc, priv->image,
86 0, 0,
87 priv->image->width, priv->image->height,
88 priv->x, priv->y,
89 priv->image->width, priv->image->height);
90 XFlush(priv->dpy);
91 priv->visible = true;
92 }
93 }
94
x11_overlay_hide(struct overlay * overlay)95 static void x11_overlay_hide(struct overlay *overlay)
96 {
97 struct x11_overlay *priv = to_x11_overlay(overlay);
98 if (priv->visible) {
99 XClearWindow(priv->dpy, DefaultRootWindow(priv->dpy));
100 XFlush(priv->dpy);
101 priv->visible = false;
102 }
103 }
104
x11_overlay_destroy(void * data)105 static void x11_overlay_destroy(void *data)
106 {
107 struct x11_overlay *priv = data;
108 munmap(priv->map, priv->size);
109 free(priv->mem);
110 XCloseDisplay(priv->dpy);
111 free(priv);
112 }
113
114 static int x_error_count;
115
check_error_handler(Display * display,XErrorEvent * event)116 static int check_error_handler(Display *display, XErrorEvent *event)
117 {
118 x_error_count++;
119 return False; /* ignored */
120 }
121
122 cairo_surface_t *
x11_overlay_create(struct config * config,int * width,int * height)123 x11_overlay_create(struct config *config, int *width, int *height)
124 {
125 Display *dpy;
126 cairo_surface_t *surface;
127 struct drm_i915_gem_create create;
128 struct drm_gem_flink flink;
129 struct drm_i915_gem_mmap_gtt map;
130 struct x11_overlay *priv;
131 unsigned int count, i, j;
132 int fd, x, y, w, h;
133 XvAdaptorInfo *info;
134 XvImage *image;
135 XvPortID port = -1;
136 void *ptr, *mem;
137
138 dpy = XOpenDisplay(NULL);
139 if (dpy == NULL)
140 return NULL;
141
142 XSetErrorHandler(check_error_handler);
143
144 ScreenOfDisplay(dpy, DefaultScreen(dpy));
145
146 fd = dri2_open(dpy);
147 if (fd < 0)
148 goto err_dpy;
149
150 if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
151 goto err_fd;
152
153 for (i = 0; i < count; i++) {
154 unsigned long visual = 0;
155
156 if (info[i].num_ports != 1)
157 continue;
158
159 for (j = 0; j < info[j].num_formats; j++) {
160 if (info[i].formats[j].depth == 24) {
161 visual = info[i].formats[j].visual_id;
162 break;
163 }
164 }
165
166 if (visual == 0)
167 continue;
168
169 port = info[i].base_id;
170 }
171 XvFreeAdaptorInfo(info);
172 if (port == -1)
173 goto err_fd;
174
175 if (x_error_count)
176 goto err_fd;
177
178 XSetErrorHandler(noop);
179
180 x11_position(dpy, *width, *height, config, &x, &y, &w, &h);
181
182 image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, w, h);
183 if (image == NULL)
184 image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, w, h);
185 if (image == NULL) {
186 image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, w, h);
187 if (image->pitches[0] == 4) {
188 image->pitches[0] = ALIGN(image->width, 1024);
189 image->pitches[1] = ALIGN(image->width/2, 1024);
190 image->pitches[2] = ALIGN(image->width/2, 1024);
191 image->offsets[0] = 0;
192 image->offsets[1] = image->pitches[0] * image->height;
193 image->offsets[2] = image->offsets[1] + image->pitches[1] * image->height/2;
194 }
195 rgb2yuv_init();
196 }
197 if (image == NULL)
198 goto err_fd;
199
200 switch (image->id) {
201 case FOURCC_RGB888:
202 case FOURCC_RGB565:
203 create.size = image->pitches[0] * image->height;
204 break;
205 case FOURCC_XVMC:
206 create.size = image->pitches[0] * image->height;
207 create.size += image->pitches[1] * image->height;
208 break;
209 }
210
211 create.handle = 0;
212 create.size = ALIGN(create.size, 4096);
213 drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
214 if (create.handle == 0)
215 goto err_image;
216
217 flink.handle = create.handle;
218 if (drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink))
219 goto err_create;
220
221 map.handle = create.handle;
222 if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &map))
223 goto err_create;
224
225 ptr = mmap(0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset);
226 if (ptr == (void *)-1)
227 goto err_create;
228
229 mem = malloc(create.size);
230 if (mem == NULL)
231 goto err_map;
232
233 switch (image->id) {
234 default:
235 case FOURCC_RGB888:
236 i = CAIRO_FORMAT_RGB24;
237 j = image->pitches[0];
238 break;
239 case FOURCC_RGB565:
240 i = CAIRO_FORMAT_RGB16_565;
241 j = image->pitches[0];
242 break;
243 case FOURCC_XVMC:
244 i = CAIRO_FORMAT_RGB16_565;
245 j = cairo_format_stride_for_width(i, image->width);
246 break;
247 }
248
249 surface = cairo_image_surface_create_for_data(mem, i, image->width, image->height, j);
250 if (cairo_surface_status(surface))
251 goto err_mem;
252
253 priv = malloc(sizeof(*priv));
254 if (priv == NULL)
255 goto err_surface;
256
257 priv->base.surface = surface;
258 priv->base.show = x11_overlay_show;
259 priv->base.hide = x11_overlay_hide;
260
261 priv->dpy = dpy;
262 priv->gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
263 priv->port = port;
264 priv->map = ptr;
265 priv->mem = mem;
266 priv->size = create.size;
267 priv->name = flink.name;
268 priv->visible = false;
269
270 priv->x = x;
271 priv->y = y;
272
273 priv->image = image;
274 priv->image->data = (void *)&priv->name;
275
276 cairo_surface_set_user_data(surface, &overlay_key, priv, x11_overlay_destroy);
277
278 XvSetPortAttribute(dpy, port, XInternAtom(dpy, "XV_ALWAYS_ON_TOP", True), 1);
279
280 close(fd);
281
282 *width = image->width;
283 *height = image->height;
284 return surface;
285
286 err_surface:
287 cairo_surface_destroy(surface);
288 err_mem:
289 free(mem);
290 err_map:
291 munmap(ptr, create.size);
292 err_create:
293 drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &create.handle);
294 err_image:
295 err_fd:
296 close(fd);
297 err_dpy:
298 XCloseDisplay(dpy);
299 return NULL;
300 }
301
x11_overlay_stop(void)302 void x11_overlay_stop(void)
303 {
304 Display *dpy;
305 unsigned int count, i, j;
306 XvAdaptorInfo *info;
307 XvImage *image;
308 XvPortID port = -1;
309 uint32_t name;
310
311 dpy = XOpenDisplay(NULL);
312 if (dpy == NULL)
313 return;
314
315 if (XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &count, &info) != Success)
316 goto close;
317
318 for (i = 0; i < count; i++) {
319 unsigned long visual = 0;
320
321 if (info[i].num_ports != 1)
322 continue;
323
324 for (j = 0; j < info[j].num_formats; j++) {
325 if (info[i].formats[j].depth == 24) {
326 visual = info[i].formats[j].visual_id;
327 break;
328 }
329 }
330
331 if (visual == 0)
332 continue;
333
334 port = info[i].base_id;
335 }
336 XvFreeAdaptorInfo(info);
337 if (port == -1)
338 goto close;
339
340 XSetErrorHandler(noop);
341
342 image = XvCreateImage(dpy, port, FOURCC_RGB565, NULL, 16, 16);
343 if (image == NULL)
344 image = XvCreateImage(dpy, port, FOURCC_RGB888, NULL, 16, 16);
345 if (image == NULL)
346 image = XvCreateImage(dpy, port, FOURCC_XVMC, NULL, 16, 16);
347 if (image == NULL)
348 goto close;
349
350 name = 0;
351 image->data = (void *)&name;
352
353 XvPutImage(dpy, port, DefaultRootWindow(dpy),
354 XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL), image,
355 0, 0,
356 1, 1,
357 0, 0,
358 1, 1);
359 XSync(dpy, True);
360
361 close:
362 XCloseDisplay(dpy);
363 }
364