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