• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
x11_screen_create(Display * dpy,int 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
x11_screen_destroy(struct x11_screen * xscr)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       Xfree(xscr->dri_driver);
100    if (xscr->dri_device)
101       Xfree(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       XFree(xscr->visuals);
111    FREE(xscr);
112 }
113 
114 #ifdef GLX_DIRECT_RENDERING
115 
116 static boolean
x11_screen_init_dri2(struct x11_screen * xscr)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
x11_screen_init_glx(struct x11_screen * xscr)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
x11_screen_support(struct x11_screen * xscr,enum x11_screen_extension ext)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 *
x11_screen_get_visuals(struct x11_screen * xscr,int * num_visuals)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
x11_drawable_get_depth(struct x11_screen * xscr,Drawable drawable)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 *
x11_screen_get_glx_configs(struct x11_screen * xscr)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 *
x11_screen_probe_dri2(struct x11_screen * xscr,int * major,int * minor)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
x11_screen_enable_dri2(struct x11_screen * xscr,x11_drawable_invalidate_buffers invalidate_buffers,void * user_data)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 *
x11_screen_get_device_name(struct x11_screen * xscr)319 x11_screen_get_device_name(struct x11_screen *xscr)
320 {
321    return xscr->dri_device;
322 }
323 
324 int
x11_screen_authenticate(struct x11_screen * xscr,uint32_t id)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
x11_drawable_enable_dri2(struct x11_screen * xscr,Drawable drawable,boolean on)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
x11_drawable_copy_buffers_region(struct x11_screen * xscr,Drawable drawable,int num_rects,const int * rects,int src_buf,int dst_buf)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 *
x11_drawable_get_buffers(struct x11_screen * xscr,Drawable drawable,int * width,int * height,unsigned int * attachments,boolean with_format,int num_ins,int * num_outs)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 *
x11_context_modes_create(unsigned count)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
x11_context_modes_destroy(__GLcontextModes * modes)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
x11_context_modes_count(const __GLcontextModes * modes)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
dri2InvalidateBuffers(Display * dpy,XID drawable)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  */
dri2GetSwapEventType(Display * dpy,XID drawable)475 unsigned dri2GetSwapEventType(Display *dpy, XID drawable)
476 {
477    return 0;
478 }
479 
480 void *
dri2GetGlxDrawableFromXDrawableId(Display * dpy,XID id)481 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
482 {
483    return NULL;
484 }
485 
486 void *
GetGLXDrawable(Display * dpy,XID drawable)487 GetGLXDrawable(Display *dpy, XID drawable)
488 {
489    return NULL;
490 }
491 
492 #endif /* GLX_DIRECT_RENDERING */
493