Merge branch 'arb_half_float_vertex'
[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
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <X11/Xlibint.h>
30 #include <X11/extensions/XShm.h>
31 #include "util/u_memory.h"
32 #include "util/u_math.h"
33 #include "util/u_format.h"
34 #include "xf86drm.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 uses code from egl_xdri.
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 XVisualInfo *visuals;
57 int num_visuals;
58
59 /* cached values for x11_drawable_get_depth */
60 Drawable last_drawable;
61 unsigned int last_depth;
62 };
63
64
65 /**
66 * Create a X11 screen.
67 */
68 struct x11_screen *
69 x11_screen_create(Display *dpy, int screen)
70 {
71 struct x11_screen *xscr;
72
73 if (screen >= ScreenCount(dpy))
74 return NULL;
75
76 xscr = CALLOC_STRUCT(x11_screen);
77 if (xscr) {
78 xscr->dpy = dpy;
79 xscr->number = screen;
80
81 xscr->dri_major = -1;
82 xscr->dri_fd = -1;
83 }
84 return xscr;
85 }
86
87 /**
88 * Destroy a X11 screen.
89 */
90 void
91 x11_screen_destroy(struct x11_screen *xscr)
92 {
93 if (xscr->dri_fd >= 0)
94 close(xscr->dri_fd);
95 if (xscr->dri_driver)
96 Xfree(xscr->dri_driver);
97 if (xscr->dri_device)
98 Xfree(xscr->dri_device);
99
100 /* xscr->glx_dpy will be destroyed with the X display */
101
102 if (xscr->visuals)
103 XFree(xscr->visuals);
104 free(xscr);
105 }
106
107 static boolean
108 x11_screen_init_dri2(struct x11_screen *xscr)
109 {
110 if (xscr->dri_major < 0) {
111 int eventBase, errorBase;
112
113 if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) ||
114 !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor))
115 xscr->dri_major = -1;
116 }
117 return (xscr->dri_major >= 0);
118 }
119
120 static boolean
121 x11_screen_init_glx(struct x11_screen *xscr)
122 {
123 if (!xscr->glx_dpy)
124 xscr->glx_dpy = __glXInitialize(xscr->dpy);
125 return (xscr->glx_dpy != NULL);
126 }
127
128 /**
129 * Return true if the screen supports the extension.
130 */
131 boolean
132 x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext)
133 {
134 boolean supported = FALSE;
135
136 switch (ext) {
137 case X11_SCREEN_EXTENSION_XSHM:
138 supported = XShmQueryExtension(xscr->dpy);
139 break;
140 case X11_SCREEN_EXTENSION_GLX:
141 supported = x11_screen_init_glx(xscr);
142 break;
143 case X11_SCREEN_EXTENSION_DRI2:
144 supported = x11_screen_init_dri2(xscr);
145 break;
146 default:
147 break;
148 }
149
150 return supported;
151 }
152
153 /**
154 * Return the X visuals.
155 */
156 const XVisualInfo *
157 x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals)
158 {
159 if (!xscr->visuals) {
160 XVisualInfo vinfo_template;
161 vinfo_template.screen = xscr->number;
162 xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask,
163 &vinfo_template, &xscr->num_visuals);
164 }
165
166 if (num_visuals)
167 *num_visuals = xscr->num_visuals;
168 return xscr->visuals;
169 }
170
171 void
172 x11_screen_convert_visual(struct x11_screen *xscr, const XVisualInfo *visual,
173 __GLcontextModes *mode)
174 {
175 int r, g, b, a;
176 int visual_type;
177
178 r = util_bitcount(visual->red_mask);
179 g = util_bitcount(visual->green_mask);
180 b = util_bitcount(visual->blue_mask);
181 a = visual->depth - (r + g + b);
182 #if defined(__cplusplus) || defined(c_plusplus)
183 visual_type = visual->c_class;
184 #else
185 visual_type = visual->class;
186 #endif
187
188 /* convert to GLX visual type */
189 switch (visual_type) {
190 case TrueColor:
191 visual_type = GLX_TRUE_COLOR;
192 break;
193 case DirectColor:
194 visual_type = GLX_DIRECT_COLOR;
195 break;
196 case PseudoColor:
197 visual_type = GLX_PSEUDO_COLOR;
198 break;
199 case StaticColor:
200 visual_type = GLX_STATIC_COLOR;
201 break;
202 case GrayScale:
203 visual_type = GLX_GRAY_SCALE;
204 break;
205 case StaticGray:
206 visual_type = GLX_STATIC_GRAY;
207 break;
208 default:
209 visual_type = GLX_NONE;
210 break;
211 }
212
213 mode->rgbBits = r + g + b + a;
214 mode->redBits = r;
215 mode->greenBits = g;
216 mode->blueBits = b;
217 mode->alphaBits = a;
218 mode->visualID = visual->visualid;
219 mode->visualType = visual_type;
220
221 /* sane defaults */
222 mode->renderType = GLX_RGBA_BIT;
223 mode->rgbMode = TRUE;
224 mode->visualRating = GLX_SLOW_CONFIG;
225 mode->xRenderable = TRUE;
226 }
227
228 /**
229 * Return the GLX fbconfigs.
230 */
231 const __GLcontextModes *
232 x11_screen_get_glx_configs(struct x11_screen *xscr)
233 {
234 return (x11_screen_init_glx(xscr))
235 ? xscr->glx_dpy->screenConfigs[xscr->number].configs
236 : NULL;
237 }
238
239 /**
240 * Return the GLX visuals.
241 */
242 const __GLcontextModes *
243 x11_screen_get_glx_visuals(struct x11_screen *xscr)
244 {
245 return (x11_screen_init_glx(xscr))
246 ? xscr->glx_dpy->screenConfigs[xscr->number].visuals
247 : NULL;
248 }
249
250 static boolean
251 x11_screen_is_driver_equal(struct x11_screen *xscr, const char *driver)
252 {
253 return (strcmp(xscr->dri_driver, driver) == 0);
254 }
255
256 /**
257 * Probe the screen for the DRI2 driver name.
258 */
259 const char *
260 x11_screen_probe_dri2(struct x11_screen *xscr)
261 {
262 /* get the driver name and the device name */
263 if (!xscr->dri_driver) {
264 if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number),
265 &xscr->dri_driver, &xscr->dri_device))
266 xscr->dri_driver = xscr->dri_device = NULL;
267 }
268
269 return xscr->dri_driver;
270 }
271
272 /**
273 * Enable DRI2 and returns the file descriptor of the DRM device. The file
274 * descriptor will be closed automatically when the screen is destoryed.
275 */
276 int
277 x11_screen_enable_dri2(struct x11_screen *xscr, const char *driver)
278 {
279 if (xscr->dri_fd < 0) {
280 int fd;
281 drm_magic_t magic;
282
283 /* get the driver name and the device name first */
284 if (!x11_screen_probe_dri2(xscr))
285 return -1;
286
287 if (!x11_screen_is_driver_equal(xscr, driver)) {
288 _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
289 xscr->dri_driver, driver);
290 return -1;
291 }
292
293 fd = open(xscr->dri_device, O_RDWR);
294 if (fd < 0) {
295 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
296 return -1;
297 }
298
299 memset(&magic, 0, sizeof(magic));
300 if (drmGetMagic(fd, &magic)) {
301 _eglLog(_EGL_WARNING, "failed to get magic");
302 close(fd);
303 return -1;
304 }
305
306 if (!DRI2Authenticate(xscr->dpy,
307 RootWindow(xscr->dpy, xscr->number), magic)) {
308 _eglLog(_EGL_WARNING, "failed to authenticate magic");
309 close(fd);
310 return -1;
311 }
312
313 xscr->dri_fd = fd;
314 }
315
316 return xscr->dri_fd;
317 }
318
319 /**
320 * Create/Destroy the DRI drawable.
321 */
322 void
323 x11_drawable_enable_dri2(struct x11_screen *xscr,
324 Drawable drawable, boolean on)
325 {
326 if (on)
327 DRI2CreateDrawable(xscr->dpy, drawable);
328 else
329 DRI2DestroyDrawable(xscr->dpy, drawable);
330 }
331
332 /**
333 * Copy between buffers of the DRI2 drawable.
334 */
335 void
336 x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable,
337 int x, int y, int width, int height,
338 int src_buf, int dst_buf)
339 {
340 XRectangle rect;
341 XserverRegion region;
342
343 rect.x = x;
344 rect.y = y;
345 rect.width = width;
346 rect.height = height;
347
348 region = XFixesCreateRegion(xscr->dpy, &rect, 1);
349 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
350 XFixesDestroyRegion(xscr->dpy, region);
351 }
352
353 /**
354 * Get the buffers of the DRI2 drawable. The returned array should be freed.
355 */
356 struct x11_drawable_buffer *
357 x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
358 int *width, int *height, unsigned int *attachments,
359 boolean with_format, int num_ins, int *num_outs)
360 {
361 DRI2Buffer *dri2bufs;
362
363 if (with_format)
364 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
365 attachments, num_ins, num_outs);
366 else
367 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
368 attachments, num_ins, num_outs);
369
370 return (struct x11_drawable_buffer *) dri2bufs;
371 }
372
373 /**
374 * Return the depth of a drawable.
375 *
376 * Unlike other drawable functions, the drawable needs not be a DRI2 drawable.
377 */
378 uint
379 x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable)
380 {
381 unsigned int depth;
382
383 if (drawable != xscr->last_drawable) {
384 Window root;
385 int x, y;
386 unsigned int w, h, border;
387 Status ok;
388
389 ok = XGetGeometry(xscr->dpy, drawable, &root,
390 &x, &y, &w, &h, &border, &depth);
391 if (!ok)
392 depth = 0;
393
394 xscr->last_drawable = drawable;
395 xscr->last_depth = depth;
396 }
397 else {
398 depth = xscr->last_depth;
399 }
400
401 return depth;
402 }
403
404 /**
405 * Create a mode list of the given size.
406 */
407 __GLcontextModes *
408 x11_context_modes_create(unsigned count)
409 {
410 const size_t size = sizeof(__GLcontextModes);
411 __GLcontextModes *base = NULL;
412 __GLcontextModes **next;
413 unsigned i;
414
415 next = &base;
416 for (i = 0; i < count; i++) {
417 *next = (__GLcontextModes *) calloc(1, size);
418 if (*next == NULL) {
419 x11_context_modes_destroy(base);
420 base = NULL;
421 break;
422 }
423 next = &((*next)->next);
424 }
425
426 return base;
427 }
428
429 /**
430 * Destroy a mode list.
431 */
432 void
433 x11_context_modes_destroy(__GLcontextModes *modes)
434 {
435 while (modes != NULL) {
436 __GLcontextModes *next = modes->next;
437 free(modes);
438 modes = next;
439 }
440 }
441
442 /**
443 * Return the number of the modes in the mode list.
444 */
445 unsigned
446 x11_context_modes_count(const __GLcontextModes *modes)
447 {
448 const __GLcontextModes *mode;
449 int count = 0;
450 for (mode = modes; mode; mode = mode->next)
451 count++;
452 return count;
453 }