xref: /aosp_15_r20/external/igt-gpu-tools/overlay/x11/x11-overlay.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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