Merge branch 'gallium-vertexelementcso'
[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 /* dummy base class */
43 struct __GLXDRIdisplayRec base;
44
45 Display *dpy;
46 int number;
47
48 /*
49 * This is used to fetch GLX visuals/fbconfigs. It steals code from GLX.
50 * It might be better to rewrite the part in Xlib or XCB.
51 */
52 __GLXdisplayPrivate *glx_dpy;
53
54 int dri_major, dri_minor;
55 char *dri_driver;
56 char *dri_device;
57 int dri_fd;
58
59 x11_drawable_invalidate_buffers dri_invalidate_buffers;
60 void *dri_user_data;
61
62 XVisualInfo *visuals;
63 int num_visuals;
64
65 /* cached values for x11_drawable_get_depth */
66 Drawable last_drawable;
67 unsigned int last_depth;
68 };
69
70
71 /**
72 * Create a X11 screen.
73 */
74 struct x11_screen *
75 x11_screen_create(Display *dpy, int screen)
76 {
77 struct x11_screen *xscr;
78
79 if (screen >= ScreenCount(dpy))
80 return NULL;
81
82 xscr = CALLOC_STRUCT(x11_screen);
83 if (xscr) {
84 xscr->dpy = dpy;
85 xscr->number = screen;
86
87 xscr->dri_major = -1;
88 xscr->dri_fd = -1;
89 }
90 return xscr;
91 }
92
93 /**
94 * Destroy a X11 screen.
95 */
96 void
97 x11_screen_destroy(struct x11_screen *xscr)
98 {
99 if (xscr->dri_fd >= 0)
100 close(xscr->dri_fd);
101 if (xscr->dri_driver)
102 Xfree(xscr->dri_driver);
103 if (xscr->dri_device)
104 Xfree(xscr->dri_device);
105
106 /* xscr->glx_dpy will be destroyed with the X display */
107 if (xscr->glx_dpy)
108 xscr->glx_dpy->dri2Display = NULL;
109
110 if (xscr->visuals)
111 XFree(xscr->visuals);
112 free(xscr);
113 }
114
115 static boolean
116 x11_screen_init_dri2(struct x11_screen *xscr)
117 {
118 if (xscr->dri_major < 0) {
119 int eventBase, errorBase;
120
121 if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) ||
122 !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor))
123 xscr->dri_major = -1;
124 }
125 return (xscr->dri_major >= 0);
126 }
127
128 static boolean
129 x11_screen_init_glx(struct x11_screen *xscr)
130 {
131 if (!xscr->glx_dpy)
132 xscr->glx_dpy = __glXInitialize(xscr->dpy);
133 return (xscr->glx_dpy != NULL);
134 }
135
136 /**
137 * Return true if the screen supports the extension.
138 */
139 boolean
140 x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext)
141 {
142 boolean supported = FALSE;
143
144 switch (ext) {
145 case X11_SCREEN_EXTENSION_XSHM:
146 supported = XShmQueryExtension(xscr->dpy);
147 break;
148 case X11_SCREEN_EXTENSION_GLX:
149 supported = x11_screen_init_glx(xscr);
150 break;
151 case X11_SCREEN_EXTENSION_DRI2:
152 supported = x11_screen_init_dri2(xscr);
153 break;
154 default:
155 break;
156 }
157
158 return supported;
159 }
160
161 /**
162 * Return the X visuals.
163 */
164 const XVisualInfo *
165 x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals)
166 {
167 if (!xscr->visuals) {
168 XVisualInfo vinfo_template;
169 vinfo_template.screen = xscr->number;
170 xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask,
171 &vinfo_template, &xscr->num_visuals);
172 }
173
174 if (num_visuals)
175 *num_visuals = xscr->num_visuals;
176 return xscr->visuals;
177 }
178
179 void
180 x11_screen_convert_visual(struct x11_screen *xscr, const XVisualInfo *visual,
181 __GLcontextModes *mode)
182 {
183 int r, g, b, a;
184 int visual_type;
185
186 r = util_bitcount(visual->red_mask);
187 g = util_bitcount(visual->green_mask);
188 b = util_bitcount(visual->blue_mask);
189 a = visual->depth - (r + g + b);
190 #if defined(__cplusplus) || defined(c_plusplus)
191 visual_type = visual->c_class;
192 #else
193 visual_type = visual->class;
194 #endif
195
196 /* convert to GLX visual type */
197 switch (visual_type) {
198 case TrueColor:
199 visual_type = GLX_TRUE_COLOR;
200 break;
201 case DirectColor:
202 visual_type = GLX_DIRECT_COLOR;
203 break;
204 case PseudoColor:
205 visual_type = GLX_PSEUDO_COLOR;
206 break;
207 case StaticColor:
208 visual_type = GLX_STATIC_COLOR;
209 break;
210 case GrayScale:
211 visual_type = GLX_GRAY_SCALE;
212 break;
213 case StaticGray:
214 visual_type = GLX_STATIC_GRAY;
215 break;
216 default:
217 visual_type = GLX_NONE;
218 break;
219 }
220
221 mode->rgbBits = r + g + b + a;
222 mode->redBits = r;
223 mode->greenBits = g;
224 mode->blueBits = b;
225 mode->alphaBits = a;
226 mode->visualID = visual->visualid;
227 mode->visualType = visual_type;
228
229 /* sane defaults */
230 mode->renderType = GLX_RGBA_BIT;
231 mode->rgbMode = TRUE;
232 mode->visualRating = GLX_SLOW_CONFIG;
233 mode->xRenderable = TRUE;
234 }
235
236 /**
237 * Return the GLX fbconfigs.
238 */
239 const __GLcontextModes *
240 x11_screen_get_glx_configs(struct x11_screen *xscr)
241 {
242 return (x11_screen_init_glx(xscr))
243 ? xscr->glx_dpy->screenConfigs[xscr->number].configs
244 : NULL;
245 }
246
247 /**
248 * Return the GLX visuals.
249 */
250 const __GLcontextModes *
251 x11_screen_get_glx_visuals(struct x11_screen *xscr)
252 {
253 return (x11_screen_init_glx(xscr))
254 ? xscr->glx_dpy->screenConfigs[xscr->number].visuals
255 : NULL;
256 }
257
258 /**
259 * Probe the screen for the DRI2 driver name.
260 */
261 const char *
262 x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor)
263 {
264 if (!x11_screen_init_dri2(xscr))
265 return NULL;
266
267 /* get the driver name and the device name */
268 if (!xscr->dri_driver) {
269 if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number),
270 &xscr->dri_driver, &xscr->dri_device))
271 xscr->dri_driver = xscr->dri_device = NULL;
272 }
273 if (major)
274 *major = xscr->dri_major;
275 if (minor)
276 *minor = xscr->dri_minor;
277
278 return xscr->dri_driver;
279 }
280
281 /**
282 * Enable DRI2 and returns the file descriptor of the DRM device. The file
283 * descriptor will be closed automatically when the screen is destoryed.
284 */
285 int
286 x11_screen_enable_dri2(struct x11_screen *xscr,
287 x11_drawable_invalidate_buffers invalidate_buffers,
288 void *user_data)
289 {
290 if (xscr->dri_fd < 0) {
291 int fd;
292 drm_magic_t magic;
293
294 /* get the driver name and the device name first */
295 if (!x11_screen_probe_dri2(xscr, NULL, NULL))
296 return -1;
297
298 fd = open(xscr->dri_device, O_RDWR);
299 if (fd < 0) {
300 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device);
301 return -1;
302 }
303
304 memset(&magic, 0, sizeof(magic));
305 if (drmGetMagic(fd, &magic)) {
306 _eglLog(_EGL_WARNING, "failed to get magic");
307 close(fd);
308 return -1;
309 }
310
311 if (!DRI2Authenticate(xscr->dpy,
312 RootWindow(xscr->dpy, xscr->number), magic)) {
313 _eglLog(_EGL_WARNING, "failed to authenticate magic");
314 close(fd);
315 return -1;
316 }
317
318 if (!x11_screen_init_glx(xscr)) {
319 _eglLog(_EGL_WARNING, "failed to initialize GLX");
320 close(fd);
321 return -1;
322 }
323 if (xscr->glx_dpy->dri2Display) {
324 _eglLog(_EGL_WARNING,
325 "display is already managed by another x11 screen");
326 close(fd);
327 return -1;
328 }
329
330 xscr->glx_dpy->dri2Display = (__GLXDRIdisplay *) xscr;
331 xscr->dri_invalidate_buffers = invalidate_buffers;
332 xscr->dri_user_data = user_data;
333
334 xscr->dri_fd = fd;
335 }
336
337 return xscr->dri_fd;
338 }
339
340 /**
341 * Create/Destroy the DRI drawable.
342 */
343 void
344 x11_drawable_enable_dri2(struct x11_screen *xscr,
345 Drawable drawable, boolean on)
346 {
347 if (on)
348 DRI2CreateDrawable(xscr->dpy, drawable);
349 else
350 DRI2DestroyDrawable(xscr->dpy, drawable);
351 }
352
353 /**
354 * Copy between buffers of the DRI2 drawable.
355 */
356 void
357 x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable,
358 int x, int y, int width, int height,
359 int src_buf, int dst_buf)
360 {
361 XRectangle rect;
362 XserverRegion region;
363
364 rect.x = x;
365 rect.y = y;
366 rect.width = width;
367 rect.height = height;
368
369 region = XFixesCreateRegion(xscr->dpy, &rect, 1);
370 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf);
371 XFixesDestroyRegion(xscr->dpy, region);
372 }
373
374 /**
375 * Get the buffers of the DRI2 drawable. The returned array should be freed.
376 */
377 struct x11_drawable_buffer *
378 x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable,
379 int *width, int *height, unsigned int *attachments,
380 boolean with_format, int num_ins, int *num_outs)
381 {
382 DRI2Buffer *dri2bufs;
383
384 if (with_format)
385 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height,
386 attachments, num_ins, num_outs);
387 else
388 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height,
389 attachments, num_ins, num_outs);
390
391 return (struct x11_drawable_buffer *) dri2bufs;
392 }
393
394 /**
395 * Return the depth of a drawable.
396 *
397 * Unlike other drawable functions, the drawable needs not be a DRI2 drawable.
398 */
399 uint
400 x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable)
401 {
402 unsigned int depth;
403
404 if (drawable != xscr->last_drawable) {
405 Window root;
406 int x, y;
407 unsigned int w, h, border;
408 Status ok;
409
410 ok = XGetGeometry(xscr->dpy, drawable, &root,
411 &x, &y, &w, &h, &border, &depth);
412 if (!ok)
413 depth = 0;
414
415 xscr->last_drawable = drawable;
416 xscr->last_depth = depth;
417 }
418 else {
419 depth = xscr->last_depth;
420 }
421
422 return depth;
423 }
424
425 /**
426 * Create a mode list of the given size.
427 */
428 __GLcontextModes *
429 x11_context_modes_create(unsigned count)
430 {
431 const size_t size = sizeof(__GLcontextModes);
432 __GLcontextModes *base = NULL;
433 __GLcontextModes **next;
434 unsigned i;
435
436 next = &base;
437 for (i = 0; i < count; i++) {
438 *next = (__GLcontextModes *) calloc(1, size);
439 if (*next == NULL) {
440 x11_context_modes_destroy(base);
441 base = NULL;
442 break;
443 }
444 next = &((*next)->next);
445 }
446
447 return base;
448 }
449
450 /**
451 * Destroy a mode list.
452 */
453 void
454 x11_context_modes_destroy(__GLcontextModes *modes)
455 {
456 while (modes != NULL) {
457 __GLcontextModes *next = modes->next;
458 free(modes);
459 modes = next;
460 }
461 }
462
463 /**
464 * Return the number of the modes in the mode list.
465 */
466 unsigned
467 x11_context_modes_count(const __GLcontextModes *modes)
468 {
469 const __GLcontextModes *mode;
470 int count = 0;
471 for (mode = modes; mode; mode = mode->next)
472 count++;
473 return count;
474 }
475
476 /**
477 * This is called from src/glx/dri2.c.
478 */
479 void
480 dri2InvalidateBuffers(Display *dpy, XID drawable)
481 {
482 __GLXdisplayPrivate *priv = __glXInitialize(dpy);
483 struct x11_screen *xscr = NULL;
484
485 if (priv && priv->dri2Display)
486 xscr = (struct x11_screen *) priv->dri2Display;
487 if (!xscr || !xscr->dri_invalidate_buffers)
488 return;
489
490 xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data);
491 }