Merge branch 'mesa_7_6_branch'
[mesa.git] / src / egl / drivers / xdri / egl_xdri.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 * Code to interface a DRI driver to libEGL.
31 * Note that unlike previous DRI/EGL interfaces, this one is meant to
32 * be used _with_ X. Applications will use eglCreateWindowSurface()
33 * to render into X-created windows.
34 *
35 * This is an EGL driver that, in turn, loads a regular DRI driver.
36 * There are some dependencies on code in libGL, but those could be
37 * removed with some effort.
38 *
39 * Authors: Brian Paul
40 */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <X11/Xlib.h>
45
46 #include "glxinit.h"
47 #include "driinit.h"
48 #include "glapi/glapi.h" /* for glapi functions */
49
50 #include "eglconfig.h"
51 #include "eglconfigutil.h"
52 #include "eglcontext.h"
53 #include "egldisplay.h"
54 #include "egldriver.h"
55 #include "eglglobals.h"
56 #include "egllog.h"
57 #include "eglsurface.h"
58
59 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
60
61 /** subclass of _EGLDriver */
62 struct xdri_egl_driver
63 {
64 _EGLDriver Base; /**< base class */
65 };
66
67
68 /** driver data of _EGLDisplay */
69 struct xdri_egl_display
70 {
71 Display *dpy;
72 __GLXdisplayPrivate *dpyPriv;
73 __GLXDRIdisplay *driDisplay;
74
75 __GLXscreenConfigs *psc;
76 EGLint scr;
77 };
78
79
80 /** subclass of _EGLContext */
81 struct xdri_egl_context
82 {
83 _EGLContext Base; /**< base class */
84
85 /* just enough info to create dri contexts */
86 GLXContext dummy_gc;
87
88 __GLXDRIcontext *driContext;
89 };
90
91
92 /** subclass of _EGLSurface */
93 struct xdri_egl_surface
94 {
95 _EGLSurface Base; /**< base class */
96
97 Drawable drawable;
98 __GLXDRIdrawable *driDrawable;
99 };
100
101
102 /** subclass of _EGLConfig */
103 struct xdri_egl_config
104 {
105 _EGLConfig Base; /**< base class */
106
107 const __GLcontextModes *mode; /**< corresponding GLX mode */
108 EGLint window_render_buffer;
109 };
110
111
112
113 /** cast wrapper */
114 static INLINE struct xdri_egl_driver *
115 xdri_egl_driver(_EGLDriver *drv)
116 {
117 return (struct xdri_egl_driver *) drv;
118 }
119
120
121 static INLINE struct xdri_egl_display *
122 lookup_display(_EGLDisplay *dpy)
123 {
124 return (struct xdri_egl_display *) dpy->DriverData;
125 }
126
127
128 /** Map EGLSurface handle to xdri_egl_surface object */
129 static INLINE struct xdri_egl_surface *
130 lookup_surface(_EGLSurface *surface)
131 {
132 return (struct xdri_egl_surface *) surface;
133 }
134
135
136 /** Map EGLContext handle to xdri_egl_context object */
137 static INLINE struct xdri_egl_context *
138 lookup_context(_EGLContext *context)
139 {
140 return (struct xdri_egl_context *) context;
141 }
142
143
144 /** Map EGLConfig handle to xdri_egl_config object */
145 static INLINE struct xdri_egl_config *
146 lookup_config(_EGLConfig *conf)
147 {
148 return (struct xdri_egl_config *) conf;
149 }
150
151
152 /** Get size of given window */
153 static Status
154 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
155 {
156 Window root;
157 Status stat;
158 int xpos, ypos;
159 unsigned int w, h, bw, depth;
160 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
161 *width = w;
162 *height = h;
163 return stat;
164 }
165
166
167 static EGLBoolean
168 convert_config(_EGLConfig *conf, EGLint id, const __GLcontextModes *m)
169 {
170 static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
171 EGL_OPENGL_ES2_BIT |
172 EGL_OPENVG_BIT |
173 EGL_OPENGL_BIT);
174 EGLint val;
175
176 _eglInitConfig(conf, id);
177 if (!_eglConfigFromContextModesRec(conf, m, all_apis, all_apis))
178 return EGL_FALSE;
179
180 if (m->doubleBufferMode) {
181 /* pixmap and pbuffer surfaces are always single-buffered */
182 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
183 val &= ~(EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
184 SET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE, val);
185 }
186 else {
187 /* EGL requires OpenGL ES context to be double-buffered */
188 val = GET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE);
189 val &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT);
190 SET_CONFIG_ATTRIB(conf, EGL_RENDERABLE_TYPE, val);
191 }
192 /* skip "empty" config */
193 if (!val)
194 return EGL_FALSE;
195
196 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
197 if (!(val & EGL_PBUFFER_BIT)) {
198 /* bind-to-texture cannot be EGL_TRUE without pbuffer bit */
199 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE);
200 SET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE);
201 }
202
203 /* EGL_NATIVE_RENDERABLE is a boolean */
204 val = GET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE);
205 if (val != EGL_TRUE)
206 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_RENDERABLE, EGL_FALSE);
207
208 return _eglValidateConfig(conf, EGL_FALSE);
209 }
210
211
212 /**
213 * Produce a set of EGL configs.
214 */
215 static EGLint
216 create_configs(_EGLDisplay *disp, const __GLcontextModes *m, EGLint first_id)
217 {
218 int id = first_id;
219
220 for (; m; m = m->next) {
221 struct xdri_egl_config *xdri_conf;
222 _EGLConfig conf;
223 EGLint rb;
224
225 if (!convert_config(&conf, id, m))
226 continue;
227
228 rb = (m->doubleBufferMode) ? EGL_BACK_BUFFER : EGL_SINGLE_BUFFER;
229
230 xdri_conf = CALLOC_STRUCT(xdri_egl_config);
231 if (xdri_conf) {
232 memcpy(&xdri_conf->Base, &conf, sizeof(conf));
233 xdri_conf->mode = m;
234 xdri_conf->window_render_buffer = rb;
235 _eglAddConfig(disp, &xdri_conf->Base);
236 id++;
237 }
238 }
239
240 return id;
241 }
242
243
244 /**
245 * Called via eglInitialize(), xdri_dpy->API.Initialize().
246 */
247 static EGLBoolean
248 xdri_eglInitialize(_EGLDriver *drv, _EGLDisplay *dpy,
249 EGLint *minor, EGLint *major)
250 {
251 struct xdri_egl_display *xdri_dpy;
252 __GLXdisplayPrivate *dpyPriv;
253 __GLXDRIdisplay *driDisplay;
254 __GLXscreenConfigs *psc;
255 EGLint first_id = 1;
256 int scr;
257
258 xdri_dpy = CALLOC_STRUCT(xdri_egl_display);
259 if (!xdri_dpy)
260 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
261
262 xdri_dpy->dpy = (Display *) dpy->NativeDisplay;
263 if (!xdri_dpy->dpy) {
264 xdri_dpy->dpy = XOpenDisplay(NULL);
265 if (!xdri_dpy->dpy) {
266 free(xdri_dpy);
267 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
268 }
269 }
270
271 dpyPriv = __glXInitialize(xdri_dpy->dpy);
272 if (!dpyPriv) {
273 _eglLog(_EGL_WARNING, "failed to create GLX display");
274 free(xdri_dpy);
275 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
276 }
277
278 driDisplay = __driCreateDisplay(dpyPriv, NULL);
279 if (!driDisplay) {
280 _eglLog(_EGL_WARNING, "failed to create DRI display");
281 free(xdri_dpy);
282 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
283 }
284
285 scr = DefaultScreen(xdri_dpy->dpy);
286 psc = &dpyPriv->screenConfigs[scr];
287
288 xdri_dpy->dpyPriv = dpyPriv;
289 xdri_dpy->driDisplay = driDisplay;
290 xdri_dpy->psc = psc;
291 xdri_dpy->scr = scr;
292
293 psc->driScreen = driDisplay->createScreen(psc, scr, dpyPriv);
294 if (!psc->driScreen) {
295 _eglLog(_EGL_WARNING, "failed to create DRI screen #%d", scr);
296 free(xdri_dpy);
297 return _eglError(EGL_NOT_INITIALIZED, "eglInitialize");
298 }
299
300 /* add visuals and fbconfigs */
301 first_id = create_configs(dpy, psc->visuals, first_id);
302 create_configs(dpy, psc->configs, first_id);
303
304 dpy->DriverData = xdri_dpy;
305 dpy->ClientAPIsMask = (EGL_OPENGL_BIT |
306 EGL_OPENGL_ES_BIT |
307 EGL_OPENGL_ES2_BIT |
308 EGL_OPENVG_BIT);
309
310 /* we're supporting EGL 1.4 */
311 *minor = 1;
312 *major = 4;
313
314 return EGL_TRUE;
315 }
316
317
318 /**
319 * Called via eglTerminate(), drv->API.Terminate().
320 */
321 static EGLBoolean
322 xdri_eglTerminate(_EGLDriver *drv, _EGLDisplay *dpy)
323 {
324 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
325 __GLXscreenConfigs *psc;
326
327 _eglReleaseDisplayResources(drv, dpy);
328 _eglCleanupDisplay(dpy);
329
330 psc = xdri_dpy->psc;
331 if (psc->driver_configs) {
332 unsigned int i;
333 for (i = 0; psc->driver_configs[i]; i++)
334 free((__DRIconfig *) psc->driver_configs[i]);
335 free(psc->driver_configs);
336 psc->driver_configs = NULL;
337 }
338 if (psc->driScreen) {
339 psc->driScreen->destroyScreen(psc);
340 free(psc->driScreen);
341 psc->driScreen = NULL;
342 }
343
344 xdri_dpy->driDisplay->destroyDisplay(xdri_dpy->driDisplay);
345 __glXRelease(xdri_dpy->dpyPriv);
346
347 free(xdri_dpy);
348 dpy->DriverData = NULL;
349
350 return EGL_TRUE;
351 }
352
353
354 /*
355 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
356 */
357 static _EGLProc
358 xdri_eglGetProcAddress(const char *procname)
359 {
360 /* the symbol is defined in libGL.so */
361 return (_EGLProc) _glapi_get_proc_address(procname);
362 }
363
364
365 /**
366 * Called via eglCreateContext(), drv->API.CreateContext().
367 */
368 static _EGLContext *
369 xdri_eglCreateContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
370 _EGLContext *share_list, const EGLint *attrib_list)
371 {
372 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
373 struct xdri_egl_config *xdri_config = lookup_config(conf);
374 struct xdri_egl_context *shared = lookup_context(share_list);
375 __GLXscreenConfigs *psc = xdri_dpy->psc;
376 int renderType = GLX_RGBA_BIT;
377 struct xdri_egl_context *xdri_ctx;
378
379 xdri_ctx = CALLOC_STRUCT(xdri_egl_context);
380 if (!xdri_ctx) {
381 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
382 return NULL;
383 }
384
385 xdri_ctx->dummy_gc = CALLOC_STRUCT(__GLXcontextRec);
386 if (!xdri_ctx->dummy_gc) {
387 _eglError(EGL_BAD_ALLOC, "eglCreateContext");
388 free(xdri_ctx);
389 return NULL;
390 }
391
392 if (!_eglInitContext(drv, &xdri_ctx->Base, &xdri_config->Base, attrib_list)) {
393 free(xdri_ctx->dummy_gc);
394 free(xdri_ctx);
395 return NULL;
396 }
397
398 /* the config decides the render buffer for the context */
399 xdri_ctx->Base.WindowRenderBuffer = xdri_config->window_render_buffer;
400
401 xdri_ctx->driContext =
402 psc->driScreen->createContext(psc,
403 xdri_config->mode,
404 xdri_ctx->dummy_gc,
405 (shared) ? shared->dummy_gc : NULL,
406 renderType);
407 if (!xdri_ctx->driContext) {
408 free(xdri_ctx->dummy_gc);
409 free(xdri_ctx);
410 return NULL;
411 }
412
413 /* fill in the required field */
414 xdri_ctx->dummy_gc->driContext = xdri_ctx->driContext;
415
416 return &xdri_ctx->Base;
417 }
418
419
420 static EGLBoolean
421 xdri_eglDestroyContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
422 {
423 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
424 struct xdri_egl_context *xdri_ctx = lookup_context(ctx);
425
426 if (!_eglIsContextBound(ctx)) {
427 xdri_ctx->driContext->destroyContext(xdri_ctx->driContext,
428 xdri_dpy->psc, xdri_dpy->dpy);
429 free(xdri_ctx->dummy_gc);
430 free(xdri_ctx);
431 }
432
433 return EGL_TRUE;
434 }
435
436
437 /**
438 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
439 */
440 static EGLBoolean
441 xdri_eglMakeCurrent(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *d,
442 _EGLSurface *r, _EGLContext *context)
443 {
444 struct xdri_egl_context *xdri_ctx = lookup_context(context);
445 struct xdri_egl_surface *draw = lookup_surface(d);
446 struct xdri_egl_surface *read = lookup_surface(r);
447
448 if (!_eglMakeCurrent(drv, dpy, d, r, context))
449 return EGL_FALSE;
450
451 /* the symbol is defined in libGL.so */
452 _glapi_check_multithread();
453
454 if (xdri_ctx) {
455 if (!xdri_ctx->driContext->bindContext(xdri_ctx->driContext,
456 draw->driDrawable,
457 read->driDrawable)) {
458 return EGL_FALSE;
459 }
460 }
461 else {
462 _EGLContext *old = _eglGetCurrentContext();
463 if (old) {
464 xdri_ctx = lookup_context(old);
465 xdri_ctx->driContext->unbindContext(xdri_ctx->driContext);
466 }
467 }
468
469 return EGL_TRUE;
470 }
471
472
473 /**
474 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
475 */
476 static _EGLSurface *
477 xdri_eglCreateWindowSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
478 NativeWindowType window, const EGLint *attrib_list)
479 {
480 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
481 struct xdri_egl_config *xdri_config = lookup_config(conf);
482 struct xdri_egl_surface *xdri_surf;
483 uint width, height;
484
485 xdri_surf = CALLOC_STRUCT(xdri_egl_surface);
486 if (!xdri_surf) {
487 _eglError(EGL_BAD_ALLOC, "eglCreateWindowSurface");
488 return NULL;
489 }
490
491 if (!_eglInitSurface(drv, &xdri_surf->Base, EGL_WINDOW_BIT,
492 &xdri_config->Base, attrib_list)) {
493 free(xdri_surf);
494 return NULL;
495 }
496
497 xdri_surf->driDrawable =
498 xdri_dpy->psc->driScreen->createDrawable(xdri_dpy->psc,
499 (XID) window,
500 (GLXDrawable) window,
501 xdri_config->mode);
502 if (!xdri_surf->driDrawable) {
503 free(xdri_surf);
504 return NULL;
505 }
506
507 xdri_surf->drawable = (Drawable) window;
508
509 get_drawable_size(xdri_dpy->dpy, window, &width, &height);
510 xdri_surf->Base.Width = width;
511 xdri_surf->Base.Height = height;
512
513 return &xdri_surf->Base;
514 }
515
516
517 /**
518 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
519 */
520 static _EGLSurface *
521 xdri_eglCreatePbufferSurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
522 const EGLint *attrib_list)
523 {
524 return NULL;
525 }
526
527
528
529 static EGLBoolean
530 xdri_eglDestroySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
531 {
532 struct xdri_egl_surface *xdri_surf = lookup_surface(surface);
533
534 if (!_eglIsSurfaceBound(&xdri_surf->Base)) {
535 xdri_surf->driDrawable->destroyDrawable(xdri_surf->driDrawable);
536 free(xdri_surf);
537 }
538
539 return EGL_TRUE;
540 }
541
542
543 static EGLBoolean
544 xdri_eglBindTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
545 EGLint buffer)
546 {
547 return EGL_FALSE;
548 }
549
550
551 static EGLBoolean
552 xdri_eglReleaseTexImage(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
553 EGLint buffer)
554 {
555 return EGL_FALSE;
556 }
557
558
559 static EGLBoolean
560 xdri_eglSwapBuffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw)
561 {
562 struct xdri_egl_display *xdri_dpy = lookup_display(dpy);
563 struct xdri_egl_surface *xdri_surf = lookup_surface(draw);
564
565 xdri_dpy->psc->driScreen->swapBuffers(xdri_surf->driDrawable);
566
567 return EGL_TRUE;
568 }
569
570
571 static void
572 xdri_Unload(_EGLDriver *drv)
573 {
574 struct xdri_egl_driver *xdri_drv = xdri_egl_driver(drv);
575 free(xdri_drv);
576 }
577
578
579 /**
580 * This is the main entrypoint into the driver, called by libEGL.
581 * Create a new _EGLDriver object and init its dispatch table.
582 */
583 _EGLDriver *
584 _eglMain(const char *args)
585 {
586 struct xdri_egl_driver *xdri_drv = CALLOC_STRUCT(xdri_egl_driver);
587 if (!xdri_drv)
588 return NULL;
589
590 _eglInitDriverFallbacks(&xdri_drv->Base);
591 xdri_drv->Base.API.Initialize = xdri_eglInitialize;
592 xdri_drv->Base.API.Terminate = xdri_eglTerminate;
593
594 xdri_drv->Base.API.GetProcAddress = xdri_eglGetProcAddress;
595
596 xdri_drv->Base.API.CreateContext = xdri_eglCreateContext;
597 xdri_drv->Base.API.DestroyContext = xdri_eglDestroyContext;
598 xdri_drv->Base.API.MakeCurrent = xdri_eglMakeCurrent;
599 xdri_drv->Base.API.CreateWindowSurface = xdri_eglCreateWindowSurface;
600 xdri_drv->Base.API.CreatePbufferSurface = xdri_eglCreatePbufferSurface;
601 xdri_drv->Base.API.DestroySurface = xdri_eglDestroySurface;
602 xdri_drv->Base.API.BindTexImage = xdri_eglBindTexImage;
603 xdri_drv->Base.API.ReleaseTexImage = xdri_eglReleaseTexImage;
604 xdri_drv->Base.API.SwapBuffers = xdri_eglSwapBuffers;
605
606 xdri_drv->Base.Name = "X/DRI";
607 xdri_drv->Base.Unload = xdri_Unload;
608
609 return &xdri_drv->Base;
610 }