Tizen 2.0 Release
[profile/ivi/osmesa.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       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
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       fd = open(xscr->dri_device, O_RDWR);
269       if (fd < 0) {
270          _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
271          return -1;
272       }
273
274       memset(&magic, 0, sizeof(magic));
275       if (drmGetMagic(fd, &magic)) {
276          _eglLog(_EGL_WARNING, "failed to get magic");
277          close(fd);
278          return -1;
279       }
280
281       if (!DRI2Authenticate(xscr->dpy,
282                RootWindow(xscr->dpy, xscr->number), magic)) {
283          _eglLog(_EGL_WARNING, "failed to authenticate magic");
284          close(fd);
285          return -1;
286       }
287
288       if (!x11_screen_init_glx(xscr)) {
289          _eglLog(_EGL_WARNING, "failed to initialize GLX");
290          close(fd);
291          return -1;
292       }
293       if (xscr->glx_dpy->xscr) {
294          _eglLog(_EGL_WARNING,
295                "display is already managed by another x11 screen");
296          close(fd);
297          return -1;
298       }
299
300       xscr->glx_dpy->xscr = xscr;
301       xscr->dri_invalidate_buffers = invalidate_buffers;
302       xscr->dri_user_data = user_data;
303
304       xscr->dri_fd = fd;
305    }
306
307    return xscr->dri_fd;
308 }
309
310 char *
311 x11_screen_get_device_name(struct x11_screen *xscr)
312 {
313    return xscr->dri_device;
314 }
315
316 int
317 x11_screen_authenticate(struct x11_screen *xscr, uint32_t id)
318 {
319    boolean authenticated;
320
321    authenticated = DRI2Authenticate(xscr->dpy,
322          RootWindow(xscr->dpy, xscr->number), id);
323    
324    return authenticated ? 0 : -1;
325 }
326
327 /**
328  * Create/Destroy the DRI drawable.
329  */
330 void
331 x11_drawable_enable_dri2(struct x11_screen *xscr,
332                          Drawable drawable, boolean on)
333 {
334    if (on)
335       DRI2CreateDrawable(xscr->dpy, drawable);
336    else
337       DRI2DestroyDrawable(xscr->dpy, drawable);
338 }
339
340 /**
341  * Copy between buffers of the DRI2 drawable.
342  */
343 void
344 x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable,
345                           int x, int y, int width, int height,
346                           int src_buf, int dst_buf)
347 {
348    XRectangle rect;
349    XserverRegion region;
350
351    rect.x = x;
352    rect.y = y;
353    rect.width = width;
354    rect.height = height;
355
356    region = XFixesCreateRegion(xscr->dpy, &rect, 1);
357    DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
358    XFixesDestroyRegion(xscr->dpy, region);
359 }
360
361 /**
362  * Get the buffers of the DRI2 drawable.  The returned array should be freed.
363  */
364 struct x11_drawable_buffer *
365 x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
366                          int *width, int *height, unsigned int *attachments,
367                          boolean with_format, int num_ins, int *num_outs)
368 {
369    DRI2Buffer *dri2bufs;
370
371    if (with_format)
372       dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
373             attachments, num_ins, num_outs);
374    else
375       dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
376             attachments, num_ins, num_outs);
377
378    return (struct x11_drawable_buffer *) dri2bufs;
379 }
380
381 /**
382  * Create a mode list of the given size.
383  */
384 __GLcontextModes *
385 x11_context_modes_create(unsigned count)
386 {
387    const size_t size = sizeof(__GLcontextModes);
388    __GLcontextModes *base = NULL;
389    __GLcontextModes **next;
390    unsigned i;
391
392    next = &base;
393    for (i = 0; i < count; i++) {
394       *next = (__GLcontextModes *) CALLOC(1, size);
395       if (*next == NULL) {
396          x11_context_modes_destroy(base);
397          base = NULL;
398          break;
399       }
400       next = &((*next)->next);
401    }
402
403    return base;
404 }
405
406 /**
407  * Destroy a mode list.
408  */
409 void
410 x11_context_modes_destroy(__GLcontextModes *modes)
411 {
412    while (modes != NULL) {
413       __GLcontextModes *next = modes->next;
414       FREE(modes);
415       modes = next;
416    }
417 }
418
419 /**
420  * Return the number of the modes in the mode list.
421  */
422 unsigned
423 x11_context_modes_count(const __GLcontextModes *modes)
424 {
425    const __GLcontextModes *mode;
426    int count = 0;
427    for (mode = modes; mode; mode = mode->next)
428       count++;
429    return count;
430 }
431
432 extern void
433 dri2InvalidateBuffers(Display *dpy, XID drawable);
434
435 /**
436  * This is called from src/glx/dri2.c.
437  */
438 void
439 dri2InvalidateBuffers(Display *dpy, XID drawable)
440 {
441    __GLXdisplayPrivate *priv = __glXInitialize(dpy);
442    struct x11_screen *xscr = NULL;
443
444    if (priv && priv->xscr)
445       xscr = priv->xscr;
446    if (!xscr || !xscr->dri_invalidate_buffers)
447       return;
448
449    xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data);
450 }
451
452 extern unsigned
453 dri2GetSwapEventType(Display *dpy, XID drawable);
454
455 /**
456  * This is also called from src/glx/dri2.c.
457  */
458 unsigned dri2GetSwapEventType(Display *dpy, XID drawable)
459 {
460    return 0;
461 }
462
463 #endif /* GLX_DIRECT_RENDERING */