Remove Xcalloc/Xmalloc/Xfree calls
[mesa.git] / src / gallium / state_trackers / egl / x11 / x11_screen.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.8
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <xf86drm.h>
31 #include <X11/Xlibint.h>
32 #include <X11/extensions/XShm.h>
33
34 #include "util/u_memory.h"
35 #include "egllog.h"
36
37 #include "x11_screen.h"
38 #include "dri2.h"
39 #include "glxinit.h"
40
41 struct x11_screen {
42 Display *dpy;
43 int number;
44
45 /*
46 * This is used to fetch GLX visuals/fbconfigs. It steals code from GLX.
47 * It might be better to rewrite the part in Xlib or XCB.
48 */
49 __GLXdisplayPrivate *glx_dpy;
50
51 int dri_major, dri_minor;
52 char *dri_driver;
53 char *dri_device;
54 int dri_fd;
55
56 x11_drawable_invalidate_buffers dri_invalidate_buffers;
57 void *dri_user_data;
58
59 XVisualInfo *visuals;
60 int num_visuals;
61
62 /* cached values for x11_drawable_get_depth */
63 Drawable last_drawable;
64 unsigned int last_depth;
65 };
66
67
68 /**
69 * Create a X11 screen.
70 */
71 struct x11_screen *
72 x11_screen_create(Display *dpy, int screen)
73 {
74 struct x11_screen *xscr;
75
76 if (screen >= ScreenCount(dpy))
77 return NULL;
78
79 xscr = CALLOC_STRUCT(x11_screen);
80 if (xscr) {
81 xscr->dpy = dpy;
82 xscr->number = screen;
83
84 xscr->dri_major = -1;
85 xscr->dri_fd = -1;
86 }
87 return xscr;
88 }
89
90 /**
91 * Destroy a X11 screen.
92 */
93 void
94 x11_screen_destroy(struct x11_screen *xscr)
95 {
96 if (xscr->dri_fd >= 0)
97 close(xscr->dri_fd);
98 if (xscr->dri_driver)
99 free(xscr->dri_driver);
100 if (xscr->dri_device)
101 free(xscr->dri_device);
102
103 #ifdef GLX_DIRECT_RENDERING
104 /* xscr->glx_dpy will be destroyed with the X display */
105 if (xscr->glx_dpy)
106 xscr->glx_dpy->xscr = NULL;
107 #endif
108
109 if (xscr->visuals)
110 free(xscr->visuals);
111 FREE(xscr);
112 }
113
114 #ifdef GLX_DIRECT_RENDERING
115
116 static boolean
117 x11_screen_init_dri2(struct x11_screen *xscr)
118 {
119 if (xscr->dri_major < 0) {
120 int eventBase, errorBase;
121
122 if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) ||
123 !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor))
124 xscr->dri_major = -1;
125 }
126 return (xscr->dri_major >= 0);
127 }
128
129 static boolean
130 x11_screen_init_glx(struct x11_screen *xscr)
131 {
132 if (!xscr->glx_dpy)
133 xscr->glx_dpy = __glXInitialize(xscr->dpy);
134 return (xscr->glx_dpy != NULL);
135 }
136
137 #endif /* GLX_DIRECT_RENDERING */
138
139 /**
140 * Return true if the screen supports the extension.
141 */
142 boolean
143 x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext)
144 {
145 boolean supported = FALSE;
146
147 switch (ext) {
148 case X11_SCREEN_EXTENSION_XSHM:
149 supported = XShmQueryExtension(xscr->dpy);
150 break;
151 #ifdef GLX_DIRECT_RENDERING
152 case X11_SCREEN_EXTENSION_GLX:
153 supported = x11_screen_init_glx(xscr);
154 break;
155 case X11_SCREEN_EXTENSION_DRI2:
156 supported = x11_screen_init_dri2(xscr);
157 break;
158 #endif
159 default:
160 break;
161 }
162
163 return supported;
164 }
165
166 /**
167 * Return the X visuals.
168 */
169 const XVisualInfo *
170 x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals)
171 {
172 if (!xscr->visuals) {
173 XVisualInfo vinfo_template;
174 vinfo_template.screen = xscr->number;
175 xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask,
176 &vinfo_template, &xscr->num_visuals);
177 }
178
179 if (num_visuals)
180 *num_visuals = xscr->num_visuals;
181 return xscr->visuals;
182 }
183
184 /**
185 * Return the depth of a drawable.
186 *
187 * Unlike other drawable functions, the drawable needs not be a DRI2 drawable.
188 */
189 uint
190 x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable)
191 {
192 unsigned int depth;
193
194 if (drawable != xscr->last_drawable) {
195 Window root;
196 int x, y;
197 unsigned int w, h, border;
198 Status ok;
199
200 ok = XGetGeometry(xscr->dpy, drawable, &root,
201 &x, &y, &w, &h, &border, &depth);
202 if (!ok)
203 depth = 0;
204
205 xscr->last_drawable = drawable;
206 xscr->last_depth = depth;
207 }
208 else {
209 depth = xscr->last_depth;
210 }
211
212 return depth;
213 }
214
215 #ifdef GLX_DIRECT_RENDERING
216
217 /**
218 * Return the GLX fbconfigs.
219 */
220 const __GLcontextModes *
221 x11_screen_get_glx_configs(struct x11_screen *xscr)
222 {
223 return (x11_screen_init_glx(xscr))
224 ? xscr->glx_dpy->screenConfigs[xscr->number]->configs
225 : NULL;
226 }
227
228 /**
229 * Probe the screen for the DRI2 driver name.
230 */
231 const char *
232 x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor)
233 {
234 if (!x11_screen_init_dri2(xscr))
235 return NULL;
236
237 /* get the driver name and the device name */
238 if (!xscr->dri_driver) {
239 if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number),
240 &xscr->dri_driver, &xscr->dri_device))
241 xscr->dri_driver = xscr->dri_device = NULL;
242 }
243 if (major)
244 *major = xscr->dri_major;
245 if (minor)
246 *minor = xscr->dri_minor;
247
248 return xscr->dri_driver;
249 }
250
251 /**
252 * Enable DRI2 and returns the file descriptor of the DRM device. The file
253 * descriptor will be closed automatically when the screen is destoryed.
254 */
255 int
256 x11_screen_enable_dri2(struct x11_screen *xscr,
257 x11_drawable_invalidate_buffers invalidate_buffers,
258 void *user_data)
259 {
260 if (xscr->dri_fd < 0) {
261 int fd;
262 drm_magic_t magic;
263
264 /* get the driver name and the device name first */
265 if (!x11_screen_probe_dri2(xscr, NULL, NULL))
266 return -1;
267
268 #ifdef O_CLOEXEC
269 fd = open(xscr->dri_device, O_RDWR | O_CLOEXEC);
270 if (fd == -1 && errno == EINVAL)
271 #endif
272 {
273 fd = open(xscr->dri_device, O_RDWR);
274 if (fd != -1)
275 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
276 }
277 if (fd < 0) {
278 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
279 return -1;
280 }
281
282 memset(&magic, 0, sizeof(magic));
283 if (drmGetMagic(fd, &magic)) {
284 _eglLog(_EGL_WARNING, "failed to get magic");
285 close(fd);
286 return -1;
287 }
288
289 if (!DRI2Authenticate(xscr->dpy,
290 RootWindow(xscr->dpy, xscr->number), magic)) {
291 _eglLog(_EGL_WARNING, "failed to authenticate magic");
292 close(fd);
293 return -1;
294 }
295
296 if (!x11_screen_init_glx(xscr)) {
297 _eglLog(_EGL_WARNING, "failed to initialize GLX");
298 close(fd);
299 return -1;
300 }
301 if (xscr->glx_dpy->xscr) {
302 _eglLog(_EGL_WARNING,
303 "display is already managed by another x11 screen");
304 close(fd);
305 return -1;
306 }
307
308 xscr->glx_dpy->xscr = xscr;
309 xscr->dri_invalidate_buffers = invalidate_buffers;
310 xscr->dri_user_data = user_data;
311
312 xscr->dri_fd = fd;
313 }
314
315 return xscr->dri_fd;
316 }
317
318 char *
319 x11_screen_get_device_name(struct x11_screen *xscr)
320 {
321 return xscr->dri_device;
322 }
323
324 int
325 x11_screen_authenticate(struct x11_screen *xscr, uint32_t id)
326 {
327 boolean authenticated;
328
329 authenticated = DRI2Authenticate(xscr->dpy,
330 RootWindow(xscr->dpy, xscr->number), id);
331
332 return authenticated ? 0 : -1;
333 }
334
335 /**
336 * Create/Destroy the DRI drawable.
337 */
338 void
339 x11_drawable_enable_dri2(struct x11_screen *xscr,
340 Drawable drawable, boolean on)
341 {
342 if (on)
343 DRI2CreateDrawable(xscr->dpy, drawable);
344 else
345 DRI2DestroyDrawable(xscr->dpy, drawable);
346 }
347
348 /**
349 * Copy between buffers of the DRI2 drawable.
350 */
351 void
352 x11_drawable_copy_buffers_region(struct x11_screen *xscr, Drawable drawable,
353 int num_rects, const int *rects,
354 int src_buf, int dst_buf)
355 {
356 XserverRegion region;
357 XRectangle *rectangles = CALLOC(num_rects, sizeof(XRectangle));
358
359 for (int i = 0; i < num_rects; i++) {
360 rectangles[i].x = rects[i * 4 + 0];
361 rectangles[i].y = rects[i * 4 + 1];
362 rectangles[i].width = rects[i * 4 + 2];
363 rectangles[i].height = rects[i * 4 + 3];
364 }
365
366 region = XFixesCreateRegion(xscr->dpy, rectangles, num_rects);
367 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
368 XFixesDestroyRegion(xscr->dpy, region);
369 FREE(rectangles);
370 }
371
372 /**
373 * Get the buffers of the DRI2 drawable. The returned array should be freed.
374 */
375 struct x11_drawable_buffer *
376 x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
377 int *width, int *height, unsigned int *attachments,
378 boolean with_format, int num_ins, int *num_outs)
379 {
380 DRI2Buffer *dri2bufs;
381
382 if (with_format)
383 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
384 attachments, num_ins, num_outs);
385 else
386 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
387 attachments, num_ins, num_outs);
388
389 return (struct x11_drawable_buffer *) dri2bufs;
390 }
391
392 /**
393 * Create a mode list of the given size.
394 */
395 __GLcontextModes *
396 x11_context_modes_create(unsigned count)
397 {
398 const size_t size = sizeof(__GLcontextModes);
399 __GLcontextModes *base = NULL;
400 __GLcontextModes **next;
401 unsigned i;
402
403 next = &base;
404 for (i = 0; i < count; i++) {
405 *next = (__GLcontextModes *) CALLOC(1, size);
406 if (*next == NULL) {
407 x11_context_modes_destroy(base);
408 base = NULL;
409 break;
410 }
411 next = &((*next)->next);
412 }
413
414 return base;
415 }
416
417 /**
418 * Destroy a mode list.
419 */
420 void
421 x11_context_modes_destroy(__GLcontextModes *modes)
422 {
423 while (modes != NULL) {
424 __GLcontextModes *next = modes->next;
425 FREE(modes);
426 modes = next;
427 }
428 }
429
430 /**
431 * Return the number of the modes in the mode list.
432 */
433 unsigned
434 x11_context_modes_count(const __GLcontextModes *modes)
435 {
436 const __GLcontextModes *mode;
437 int count = 0;
438 for (mode = modes; mode; mode = mode->next)
439 count++;
440 return count;
441 }
442
443 extern void
444 dri2InvalidateBuffers(Display *dpy, XID drawable);
445
446 /**
447 * This is called from src/glx/dri2.c.
448 */
449 void
450 dri2InvalidateBuffers(Display *dpy, XID drawable)
451 {
452 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
453 struct x11_screen *xscr = NULL;
454
455 if (priv && priv->xscr)
456 xscr = priv->xscr;
457 if (!xscr || !xscr->dri_invalidate_buffers)
458 return;
459
460 xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data);
461 }
462
463 extern unsigned
464 dri2GetSwapEventType(Display *dpy, XID drawable);
465
466 extern void *
467 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id);
468
469 extern void *
470 GetGLXDrawable(Display *dpy, XID drawable);
471
472 /**
473 * This is also called from src/glx/dri2.c.
474 */
475 unsigned dri2GetSwapEventType(Display *dpy, XID drawable)
476 {
477 return 0;
478 }
479
480 void *
481 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
482 {
483 return NULL;
484 }
485
486 void *
487 GetGLXDrawable(Display *dpy, XID drawable)
488 {
489 return NULL;
490 }
491
492 #endif /* GLX_DIRECT_RENDERING */