Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / egl / drivers / glx / egl_glx.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 /**
30 * This is an EGL driver that wraps GLX. This gives the benefit of being
31 * completely agnostic of the direct rendering implementation.
32 *
33 * Authors: Alan Hourihane <alanh@tungstengraphics.com>
34 */
35
36 /*
37 * TODO:
38 *
39 * Add GLXFBConfig support
40 * Pbuffer & Pixmap support
41 * test eglBind/ReleaseTexImage
42 */
43
44
45 #include <assert.h>
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include "dlfcn.h"
51 #include <X11/Xlib.h>
52 #include <GL/gl.h>
53 #include "glxclient.h"
54
55 #define _EGL_PLATFORM_X
56
57 #include "eglconfig.h"
58 #include "eglcontext.h"
59 #include "egldisplay.h"
60 #include "egldriver.h"
61 #include "eglglobals.h"
62 #include "eglhash.h"
63 #include "egllog.h"
64 #include "eglsurface.h"
65
66 #include <GL/gl.h>
67
68 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
69
70 static const EGLint all_apis = (EGL_OPENGL_ES_BIT
71 | EGL_OPENGL_ES2_BIT
72 | EGL_OPENVG_BIT
73 /* | EGL_OPENGL_BIT */); /* can't do */
74
75 struct visual_attribs
76 {
77 /* X visual attribs */
78 int id;
79 int klass;
80 int depth;
81 int redMask, greenMask, blueMask;
82 int colormapSize;
83 int bitsPerRGB;
84
85 /* GL visual attribs */
86 int supportsGL;
87 int transparentType;
88 int transparentRedValue;
89 int transparentGreenValue;
90 int transparentBlueValue;
91 int transparentAlphaValue;
92 int transparentIndexValue;
93 int bufferSize;
94 int level;
95 int render_type;
96 int doubleBuffer;
97 int stereo;
98 int auxBuffers;
99 int redSize, greenSize, blueSize, alphaSize;
100 int depthSize;
101 int stencilSize;
102 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
103 int numSamples, numMultisample;
104 int visualCaveat;
105 };
106
107 /** subclass of _EGLDriver */
108 struct GLX_egl_driver
109 {
110 _EGLDriver Base; /**< base class */
111
112 XVisualInfo *visuals;
113
114 /* GLXFBConfig *fbconfigs - todo */
115 };
116
117
118 /** subclass of _EGLContext */
119 struct GLX_egl_context
120 {
121 _EGLContext Base; /**< base class */
122
123 GLXContext context;
124 };
125
126
127 /** subclass of _EGLSurface */
128 struct GLX_egl_surface
129 {
130 _EGLSurface Base; /**< base class */
131
132 GLXDrawable drawable;
133 };
134
135
136 /** subclass of _EGLConfig */
137 struct GLX_egl_config
138 {
139 _EGLConfig Base; /**< base class */
140 };
141
142 /** cast wrapper */
143 static struct GLX_egl_driver *
144 GLX_egl_driver(_EGLDriver *drv)
145 {
146 return (struct GLX_egl_driver *) drv;
147 }
148
149 static struct GLX_egl_context *
150 GLX_egl_context(_EGLContext *ctx)
151 {
152 return (struct GLX_egl_context *) ctx;
153 }
154
155 static struct GLX_egl_surface *
156 GLX_egl_surface(_EGLSurface *surf)
157 {
158 return (struct GLX_egl_surface *) surf;
159 }
160
161 static GLboolean
162 get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
163 struct visual_attribs *attribs)
164 {
165 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
166 int rgba;
167
168 memset(attribs, 0, sizeof(struct visual_attribs));
169
170 attribs->id = vInfo->visualid;
171 #if defined(__cplusplus) || defined(c_plusplus)
172 attribs->klass = vInfo->c_class;
173 #else
174 attribs->klass = vInfo->class;
175 #endif
176 attribs->depth = vInfo->depth;
177 attribs->redMask = vInfo->red_mask;
178 attribs->greenMask = vInfo->green_mask;
179 attribs->blueMask = vInfo->blue_mask;
180 attribs->colormapSize = vInfo->colormap_size;
181 attribs->bitsPerRGB = vInfo->bits_per_rgb;
182
183 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
184 !attribs->supportsGL)
185 return GL_FALSE;
186 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
187 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
188 glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
189 if (!rgba)
190 return GL_FALSE;
191 attribs->render_type = GLX_RGBA_BIT;
192
193 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
194 if (!attribs->doubleBuffer)
195 return GL_FALSE;
196
197 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
198 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
199 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
200 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
201 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
202 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
203 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
204 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
205 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
206 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
207 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
208 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
209
210 /* get transparent pixel stuff */
211 glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
212 if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
213 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
214 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
215 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
216 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
217 }
218 else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
219 glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
220 }
221
222 /* multisample attribs */
223 #ifdef GLX_ARB_multisample
224 if (ext && strstr(ext, "GLX_ARB_multisample")) {
225 glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
226 glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
227 }
228 #endif
229 else {
230 attribs->numSamples = 0;
231 attribs->numMultisample = 0;
232 }
233
234 #if defined(GLX_EXT_visual_rating)
235 if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
236 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
237 }
238 else {
239 attribs->visualCaveat = GLX_NONE_EXT;
240 }
241 #else
242 attribs->visualCaveat = 0;
243 #endif
244
245 return GL_TRUE;
246 }
247
248 static EGLBoolean
249 create_configs(_EGLDisplay *disp, struct GLX_egl_driver *GLX_drv)
250 {
251 XVisualInfo theTemplate;
252 int numVisuals;
253 long mask;
254 int i;
255 struct visual_attribs attribs;
256
257 /* get list of all visuals on this screen */
258 theTemplate.screen = DefaultScreen(disp->Xdpy);
259 mask = VisualScreenMask;
260 GLX_drv->visuals = XGetVisualInfo(disp->Xdpy, mask, &theTemplate, &numVisuals);
261
262 for (i = 0; i < numVisuals; i++) {
263 struct GLX_egl_config *config;
264
265 if (!get_visual_attribs(disp->Xdpy, &GLX_drv->visuals[i], &attribs))
266 continue;
267
268 config = CALLOC_STRUCT(GLX_egl_config);
269
270 _eglInitConfig(&config->Base, i+1);
271 SET_CONFIG_ATTRIB(&config->Base, EGL_NATIVE_VISUAL_ID, attribs.id);
272 SET_CONFIG_ATTRIB(&config->Base, EGL_BUFFER_SIZE, attribs.bufferSize);
273 SET_CONFIG_ATTRIB(&config->Base, EGL_RED_SIZE, attribs.redSize);
274 SET_CONFIG_ATTRIB(&config->Base, EGL_GREEN_SIZE, attribs.greenSize);
275 SET_CONFIG_ATTRIB(&config->Base, EGL_BLUE_SIZE, attribs.blueSize);
276 SET_CONFIG_ATTRIB(&config->Base, EGL_ALPHA_SIZE, attribs.alphaSize);
277 SET_CONFIG_ATTRIB(&config->Base, EGL_DEPTH_SIZE, attribs.depthSize);
278 SET_CONFIG_ATTRIB(&config->Base, EGL_STENCIL_SIZE, attribs.stencilSize);
279 SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLES, attribs.numSamples);
280 SET_CONFIG_ATTRIB(&config->Base, EGL_SAMPLE_BUFFERS, attribs.numMultisample);
281 SET_CONFIG_ATTRIB(&config->Base, EGL_CONFORMANT, all_apis);
282 SET_CONFIG_ATTRIB(&config->Base, EGL_RENDERABLE_TYPE, all_apis);
283 SET_CONFIG_ATTRIB(&config->Base, EGL_SURFACE_TYPE,
284 (EGL_WINDOW_BIT /*| EGL_PBUFFER_BIT | EGL_PIXMAP_BIT*/));
285
286 /* XXX possibly other things to init... */
287
288 _eglAddConfig(disp, &config->Base);
289 }
290
291 return EGL_TRUE;
292 }
293
294 /**
295 * Called via eglInitialize(), GLX_drv->API.Initialize().
296 */
297 static EGLBoolean
298 GLX_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
299 EGLint *minor, EGLint *major)
300 {
301 struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
302 _EGLDisplay *disp = _eglLookupDisplay(dpy);
303
304 _eglLog(_EGL_DEBUG, "XDRI: eglInitialize");
305
306 if (!disp->Xdpy) {
307 disp->Xdpy = XOpenDisplay(NULL);
308 if (!disp->Xdpy) {
309 _eglLog(_EGL_WARNING, "XDRI: XOpenDisplay failed");
310 return EGL_FALSE;
311 }
312 }
313
314 GLX_drv->Base.Initialized = EGL_TRUE;
315
316 GLX_drv->Base.Name = "GLX";
317
318 /* we're supporting EGL 1.4 */
319 *minor = 1;
320 *major = 4;
321
322 create_configs(disp, GLX_drv);
323
324 return EGL_TRUE;
325 }
326
327
328 /**
329 * Called via eglTerminate(), drv->API.Terminate().
330 */
331 static EGLBoolean
332 GLX_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
333 {
334 _EGLDisplay *disp = _eglLookupDisplay(dpy);
335
336 _eglLog(_EGL_DEBUG, "XDRI: eglTerminate");
337
338 // XCloseDisplay(disp->Xdpy);
339
340 return EGL_TRUE;
341 }
342
343
344 /**
345 * Called via eglCreateContext(), drv->API.CreateContext().
346 */
347 static EGLContext
348 GLX_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
349 EGLContext share_list, const EGLint *attrib_list)
350 {
351 _EGLDisplay *disp = _eglLookupDisplay(dpy);
352 struct GLX_egl_context *GLX_ctx = CALLOC_STRUCT(GLX_egl_context);
353 struct GLX_egl_driver *GLX_drv = GLX_egl_driver(drv);
354 struct GLX_egl_context *GLX_ctx_shared = NULL;
355 _EGLConfig *conf;
356
357 if (!GLX_ctx)
358 return EGL_NO_CONTEXT;
359
360 if (!_eglInitContext(drv, dpy, &GLX_ctx->Base, config, attrib_list)) {
361 free(GLX_ctx);
362 return EGL_NO_CONTEXT;
363 }
364
365 if (share_list != EGL_NO_CONTEXT) {
366 _EGLContext *shareCtx = _eglLookupContext(share_list);
367 if (!shareCtx) {
368 _eglError(EGL_BAD_CONTEXT, "eglCreateContext(share_list)");
369 return EGL_FALSE;
370 }
371 GLX_ctx_shared = GLX_egl_context(shareCtx);
372 }
373
374 conf = _eglLookupConfig(drv, dpy, config);
375 assert(conf);
376
377 GLX_ctx->context = glXCreateContext(disp->Xdpy, &GLX_drv->visuals[(int)config-1], GLX_ctx_shared ? GLX_ctx_shared->context : NULL, GL_TRUE);
378 if (!GLX_ctx->context)
379 return EGL_FALSE;
380
381 /* need to have a direct rendering context */
382 if (!glXIsDirect(disp->Xdpy, GLX_ctx->context))
383 return EGL_FALSE;
384
385 return _eglGetContextHandle(&GLX_ctx->Base);
386 }
387
388
389 /**
390 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
391 */
392 static EGLBoolean
393 GLX_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy, EGLSurface d,
394 EGLSurface r, EGLContext context)
395 {
396 _EGLDisplay *disp = _eglLookupDisplay(dpy);
397 _EGLContext *ctx = _eglLookupContext(context);
398 _EGLSurface *dsurf = _eglLookupSurface(d);
399 _EGLSurface *rsurf = _eglLookupSurface(r);
400 struct GLX_egl_surface *GLX_dsurf = GLX_egl_surface(dsurf);
401 struct GLX_egl_surface *GLX_rsurf = GLX_egl_surface(rsurf);
402 struct GLX_egl_context *GLX_ctx = GLX_egl_context(ctx);
403
404 if (!_eglMakeCurrent(drv, dpy, d, r, context))
405 return EGL_FALSE;
406
407 // if (!glXMakeContextCurrent(disp->Xdpy, GLX_dsurf->drawable, GLX_rsurf->drawable, GLX_ctx->context))
408 if (!glXMakeCurrent(disp->Xdpy, GLX_dsurf ? GLX_dsurf->drawable : 0, GLX_ctx ? GLX_ctx->context : NULL))
409 return EGL_FALSE;
410
411 return EGL_TRUE;
412 }
413
414 /** Get size of given window */
415 static Status
416 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
417 {
418 Window root;
419 Status stat;
420 int xpos, ypos;
421 unsigned int w, h, bw, depth;
422 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
423 *width = w;
424 *height = h;
425 return stat;
426 }
427
428 /**
429 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
430 */
431 static EGLSurface
432 GLX_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
433 NativeWindowType window, const EGLint *attrib_list)
434 {
435 _EGLDisplay *disp = _eglLookupDisplay(dpy);
436 struct GLX_egl_surface *GLX_surf;
437 uint width, height;
438
439 GLX_surf = CALLOC_STRUCT(GLX_egl_surface);
440 if (!GLX_surf)
441 return EGL_NO_SURFACE;
442
443 if (!_eglInitSurface(drv, dpy, &GLX_surf->Base, EGL_WINDOW_BIT,
444 config, attrib_list)) {
445 free(GLX_surf);
446 return EGL_FALSE;
447 }
448
449 _eglSaveSurface(&GLX_surf->Base);
450
451 GLX_surf->drawable = window;
452 get_drawable_size(disp->Xdpy, window, &width, &height);
453 GLX_surf->Base.Width = width;
454 GLX_surf->Base.Height = height;
455
456 return _eglGetSurfaceHandle(&GLX_surf->Base);
457 }
458
459 static EGLBoolean
460 GLX_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
461 {
462 _EGLDisplay *disp = _eglLookupDisplay(dpy);
463 _EGLSurface *surf = _eglLookupSurface(surface);
464 return EGL_TRUE;
465 if (surf) {
466 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
467 if (surf->IsBound) {
468 surf->DeletePending = EGL_TRUE;
469 }
470 else {
471 free(surf);
472 }
473
474 return EGL_TRUE;
475 }
476 else {
477 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
478 return EGL_FALSE;
479 }
480 }
481
482
483 static EGLBoolean
484 GLX_eglBindTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
485 EGLint buffer)
486 {
487 _EGLDisplay *disp = _eglLookupDisplay(dpy);
488 _EGLSurface *surf = _eglLookupSurface(surface);
489 struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
490
491 /* buffer ?? */
492 glXBindTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT, NULL);
493
494 return EGL_TRUE;
495 }
496
497
498 static EGLBoolean
499 GLX_eglReleaseTexImage(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface,
500 EGLint buffer)
501 {
502 _EGLDisplay *disp = _eglLookupDisplay(dpy);
503 _EGLSurface *surf = _eglLookupSurface(surface);
504 struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
505
506 /* buffer ?? */
507 glXReleaseTexImageEXT(disp->Xdpy, GLX_surf->drawable, GLX_FRONT_LEFT_EXT);
508
509 return EGL_TRUE;
510 }
511
512
513 static EGLBoolean
514 GLX_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
515 {
516 _EGLDisplay *disp = _eglLookupDisplay(dpy);
517 _EGLSurface *surf = _eglLookupSurface(draw);
518 struct GLX_egl_surface *GLX_surf = GLX_egl_surface(surf);
519
520 _eglLog(_EGL_DEBUG, "XDRI: EGL SwapBuffers 0x%x",draw);
521
522 /* error checking step: */
523 if (!_eglSwapBuffers(drv, dpy, draw))
524 return EGL_FALSE;
525
526 glXSwapBuffers(disp->Xdpy, GLX_surf->drawable);
527
528 return EGL_TRUE;
529 }
530
531 /*
532 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
533 */
534 static _EGLProc
535 GLX_eglGetProcAddress(const char *procname)
536 {
537 return (_EGLProc)glXGetProcAddress((const GLubyte *)procname);
538 }
539
540
541 /**
542 * This is the main entrypoint into the driver, called by libEGL.
543 * Create a new _EGLDriver object and init its dispatch table.
544 */
545 _EGLDriver *
546 _eglMain(_EGLDisplay *disp, const char *args)
547 {
548 struct GLX_egl_driver *GLX_drv = CALLOC_STRUCT(GLX_egl_driver);
549 char *env;
550
551 if (!GLX_drv)
552 return NULL;
553
554 _eglInitDriverFallbacks(&GLX_drv->Base);
555 GLX_drv->Base.API.Initialize = GLX_eglInitialize;
556 GLX_drv->Base.API.Terminate = GLX_eglTerminate;
557 GLX_drv->Base.API.CreateContext = GLX_eglCreateContext;
558 GLX_drv->Base.API.MakeCurrent = GLX_eglMakeCurrent;
559 GLX_drv->Base.API.CreateWindowSurface = GLX_eglCreateWindowSurface;
560 GLX_drv->Base.API.DestroySurface = GLX_eglDestroySurface;
561 GLX_drv->Base.API.BindTexImage = GLX_eglBindTexImage;
562 GLX_drv->Base.API.ReleaseTexImage = GLX_eglReleaseTexImage;
563 GLX_drv->Base.API.SwapBuffers = GLX_eglSwapBuffers;
564 GLX_drv->Base.API.GetProcAddress = GLX_eglGetProcAddress;
565
566 GLX_drv->Base.ClientAPIsMask = all_apis;
567 GLX_drv->Base.Name = "GLX";
568
569 _eglLog(_EGL_DEBUG, "GLX: main(%s)", args);
570
571 /* set new DRI path to pick up EGL version (which doesn't contain any mesa
572 * code), but don't override if one is already set.
573 */
574 env = getenv("LIBGL_DRIVERS_PATH");
575 if (env) {
576 if (!strstr(env, "egl")) {
577 sprintf(env, "%s/egl", env);
578 setenv("LIBGL_DRIVERS_PATH", env, 1);
579 }
580 } else
581 setenv("LIBGL_DRIVERS_PATH", DEFAULT_DRIVER_DIR"/egl", 0);
582
583 return &GLX_drv->Base;
584 }