1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
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.
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.
48 #include "glapi/glapi.h" /* for glapi functions */
50 #include "eglconfig.h"
51 #include "eglconfigutil.h"
52 #include "eglcontext.h"
53 #include "egldisplay.h"
54 #include "egldriver.h"
55 #include "eglglobals.h"
57 #include "eglsurface.h"
59 #define CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
61 /** subclass of _EGLDriver */
62 struct xdri_egl_driver
64 _EGLDriver Base
; /**< base class */
68 /** driver data of _EGLDisplay */
69 struct xdri_egl_display
72 __GLXdisplayPrivate
*dpyPriv
;
73 __GLXDRIdisplay
*driDisplay
;
75 __GLXscreenConfigs
*psc
;
80 /** subclass of _EGLContext */
81 struct xdri_egl_context
83 _EGLContext Base
; /**< base class */
85 /* just enough info to create dri contexts */
88 __GLXDRIcontext
*driContext
;
92 /** subclass of _EGLSurface */
93 struct xdri_egl_surface
95 _EGLSurface Base
; /**< base class */
98 __GLXDRIdrawable
*driDrawable
;
102 /** subclass of _EGLConfig */
103 struct xdri_egl_config
105 _EGLConfig Base
; /**< base class */
107 const __GLcontextModes
*mode
; /**< corresponding GLX mode */
108 EGLint window_render_buffer
;
114 static INLINE
struct xdri_egl_driver
*
115 xdri_egl_driver(_EGLDriver
*drv
)
117 return (struct xdri_egl_driver
*) drv
;
121 static INLINE
struct xdri_egl_display
*
122 lookup_display(_EGLDisplay
*dpy
)
124 return (struct xdri_egl_display
*) dpy
->DriverData
;
128 /** Map EGLSurface handle to xdri_egl_surface object */
129 static INLINE
struct xdri_egl_surface
*
130 lookup_surface(_EGLSurface
*surface
)
132 return (struct xdri_egl_surface
*) surface
;
136 /** Map EGLContext handle to xdri_egl_context object */
137 static INLINE
struct xdri_egl_context
*
138 lookup_context(_EGLContext
*context
)
140 return (struct xdri_egl_context
*) context
;
144 /** Map EGLConfig handle to xdri_egl_config object */
145 static INLINE
struct xdri_egl_config
*
146 lookup_config(_EGLConfig
*conf
)
148 return (struct xdri_egl_config
*) conf
;
152 /** Get size of given window */
154 get_drawable_size(Display
*dpy
, Drawable d
, uint
*width
, uint
*height
)
159 unsigned int w
, h
, bw
, depth
;
160 stat
= XGetGeometry(dpy
, d
, &root
, &xpos
, &ypos
, &w
, &h
, &bw
, &depth
);
168 convert_config(_EGLConfig
*conf
, EGLint id
, const __GLcontextModes
*m
)
170 static const EGLint all_apis
= (EGL_OPENGL_ES_BIT
|
176 _eglInitConfig(conf
, id
);
177 if (!_eglConfigFromContextModesRec(conf
, m
, all_apis
, all_apis
))
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
);
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
);
192 /* skip "empty" config */
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
);
203 /* EGL_NATIVE_RENDERABLE is a boolean */
204 val
= GET_CONFIG_ATTRIB(conf
, EGL_NATIVE_RENDERABLE
);
206 SET_CONFIG_ATTRIB(conf
, EGL_NATIVE_RENDERABLE
, EGL_FALSE
);
208 return _eglValidateConfig(conf
, EGL_FALSE
);
213 * Produce a set of EGL configs.
216 create_configs(_EGLDisplay
*disp
, const __GLcontextModes
*m
, EGLint first_id
)
220 for (; m
; m
= m
->next
) {
221 struct xdri_egl_config
*xdri_conf
;
225 if (!convert_config(&conf
, id
, m
))
228 rb
= (m
->doubleBufferMode
) ? EGL_BACK_BUFFER
: EGL_SINGLE_BUFFER
;
230 xdri_conf
= CALLOC_STRUCT(xdri_egl_config
);
232 memcpy(&xdri_conf
->Base
, &conf
, sizeof(conf
));
234 xdri_conf
->window_render_buffer
= rb
;
235 _eglAddConfig(disp
, &xdri_conf
->Base
);
245 * Called via eglInitialize(), xdri_dpy->API.Initialize().
248 xdri_eglInitialize(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
249 EGLint
*minor
, EGLint
*major
)
251 struct xdri_egl_display
*xdri_dpy
;
252 __GLXdisplayPrivate
*dpyPriv
;
253 __GLXDRIdisplay
*driDisplay
;
254 __GLXscreenConfigs
*psc
;
258 xdri_dpy
= CALLOC_STRUCT(xdri_egl_display
);
260 return _eglError(EGL_BAD_ALLOC
, "eglInitialize");
262 xdri_dpy
->dpy
= (Display
*) dpy
->NativeDisplay
;
263 if (!xdri_dpy
->dpy
) {
264 xdri_dpy
->dpy
= XOpenDisplay(NULL
);
265 if (!xdri_dpy
->dpy
) {
267 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
271 dpyPriv
= __glXInitialize(xdri_dpy
->dpy
);
273 _eglLog(_EGL_WARNING
, "failed to create GLX display");
275 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
278 driDisplay
= __driCreateDisplay(dpyPriv
, NULL
);
280 _eglLog(_EGL_WARNING
, "failed to create DRI display");
282 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
285 scr
= DefaultScreen(xdri_dpy
->dpy
);
286 psc
= &dpyPriv
->screenConfigs
[scr
];
288 xdri_dpy
->dpyPriv
= dpyPriv
;
289 xdri_dpy
->driDisplay
= driDisplay
;
293 psc
->driScreen
= driDisplay
->createScreen(psc
, scr
, dpyPriv
);
294 if (!psc
->driScreen
) {
295 _eglLog(_EGL_WARNING
, "failed to create DRI screen #%d", scr
);
297 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
300 /* add visuals and fbconfigs */
301 first_id
= create_configs(dpy
, psc
->visuals
, first_id
);
302 create_configs(dpy
, psc
->configs
, first_id
);
304 dpy
->DriverData
= xdri_dpy
;
305 dpy
->ClientAPIsMask
= (EGL_OPENGL_BIT
|
310 /* we're supporting EGL 1.4 */
319 * Called via eglTerminate(), drv->API.Terminate().
322 xdri_eglTerminate(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
324 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
325 __GLXscreenConfigs
*psc
;
327 _eglReleaseDisplayResources(drv
, dpy
);
328 _eglCleanupDisplay(dpy
);
331 if (psc
->driver_configs
) {
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
;
338 if (psc
->driScreen
) {
339 psc
->driScreen
->destroyScreen(psc
);
340 free(psc
->driScreen
);
341 psc
->driScreen
= NULL
;
344 xdri_dpy
->driDisplay
->destroyDisplay(xdri_dpy
->driDisplay
);
345 __glXRelease(xdri_dpy
->dpyPriv
);
348 dpy
->DriverData
= NULL
;
355 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
358 xdri_eglGetProcAddress(const char *procname
)
360 /* the symbol is defined in libGL.so */
361 return (_EGLProc
) _glapi_get_proc_address(procname
);
366 * Called via eglCreateContext(), drv->API.CreateContext().
369 xdri_eglCreateContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
370 _EGLContext
*share_list
, const EGLint
*attrib_list
)
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
;
379 xdri_ctx
= CALLOC_STRUCT(xdri_egl_context
);
381 _eglError(EGL_BAD_ALLOC
, "eglCreateContext");
385 xdri_ctx
->dummy_gc
= CALLOC_STRUCT(__GLXcontextRec
);
386 if (!xdri_ctx
->dummy_gc
) {
387 _eglError(EGL_BAD_ALLOC
, "eglCreateContext");
392 if (!_eglInitContext(drv
, &xdri_ctx
->Base
, &xdri_config
->Base
, attrib_list
)) {
393 free(xdri_ctx
->dummy_gc
);
398 /* the config decides the render buffer for the context */
399 xdri_ctx
->Base
.WindowRenderBuffer
= xdri_config
->window_render_buffer
;
401 xdri_ctx
->driContext
=
402 psc
->driScreen
->createContext(psc
,
405 (shared
) ? shared
->dummy_gc
: NULL
,
407 if (!xdri_ctx
->driContext
) {
408 free(xdri_ctx
->dummy_gc
);
413 /* fill in the required field */
414 xdri_ctx
->dummy_gc
->driContext
= xdri_ctx
->driContext
;
416 return &xdri_ctx
->Base
;
421 xdri_eglDestroyContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*ctx
)
423 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
424 struct xdri_egl_context
*xdri_ctx
= lookup_context(ctx
);
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
);
438 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
441 xdri_eglMakeCurrent(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*d
,
442 _EGLSurface
*r
, _EGLContext
*context
)
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
);
448 if (!_eglMakeCurrent(drv
, dpy
, d
, r
, context
))
451 /* the symbol is defined in libGL.so */
452 _glapi_check_multithread();
455 if (!xdri_ctx
->driContext
->bindContext(xdri_ctx
->driContext
,
457 read
->driDrawable
)) {
462 _EGLContext
*old
= _eglGetCurrentContext();
464 xdri_ctx
= lookup_context(old
);
465 xdri_ctx
->driContext
->unbindContext(xdri_ctx
->driContext
);
474 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
477 xdri_eglCreateWindowSurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
478 NativeWindowType window
, const EGLint
*attrib_list
)
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
;
485 xdri_surf
= CALLOC_STRUCT(xdri_egl_surface
);
487 _eglError(EGL_BAD_ALLOC
, "eglCreateWindowSurface");
491 if (!_eglInitSurface(drv
, &xdri_surf
->Base
, EGL_WINDOW_BIT
,
492 &xdri_config
->Base
, attrib_list
)) {
497 xdri_surf
->driDrawable
=
498 xdri_dpy
->psc
->driScreen
->createDrawable(xdri_dpy
->psc
,
500 (GLXDrawable
) window
,
502 if (!xdri_surf
->driDrawable
) {
507 xdri_surf
->drawable
= (Drawable
) window
;
509 get_drawable_size(xdri_dpy
->dpy
, window
, &width
, &height
);
510 xdri_surf
->Base
.Width
= width
;
511 xdri_surf
->Base
.Height
= height
;
513 return &xdri_surf
->Base
;
518 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
521 xdri_eglCreatePbufferSurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
522 const EGLint
*attrib_list
)
530 xdri_eglDestroySurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surface
)
532 struct xdri_egl_surface
*xdri_surf
= lookup_surface(surface
);
534 if (!_eglIsSurfaceBound(&xdri_surf
->Base
)) {
535 xdri_surf
->driDrawable
->destroyDrawable(xdri_surf
->driDrawable
);
544 xdri_eglBindTexImage(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
,
552 xdri_eglReleaseTexImage(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
,
560 xdri_eglSwapBuffers(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*draw
)
562 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
563 struct xdri_egl_surface
*xdri_surf
= lookup_surface(draw
);
565 xdri_dpy
->psc
->driScreen
->swapBuffers(xdri_surf
->driDrawable
);
572 xdri_Unload(_EGLDriver
*drv
)
574 struct xdri_egl_driver
*xdri_drv
= xdri_egl_driver(drv
);
580 * This is the main entrypoint into the driver, called by libEGL.
581 * Create a new _EGLDriver object and init its dispatch table.
584 _eglMain(const char *args
)
586 struct xdri_egl_driver
*xdri_drv
= CALLOC_STRUCT(xdri_egl_driver
);
590 _eglInitDriverFallbacks(&xdri_drv
->Base
);
591 xdri_drv
->Base
.API
.Initialize
= xdri_eglInitialize
;
592 xdri_drv
->Base
.API
.Terminate
= xdri_eglTerminate
;
594 xdri_drv
->Base
.API
.GetProcAddress
= xdri_eglGetProcAddress
;
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
;
606 xdri_drv
->Base
.Name
= "X/DRI";
607 xdri_drv
->Base
.Unload
= xdri_Unload
;
609 return &xdri_drv
->Base
;