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 */
65 void (*FlushCurrentContext
)(void);
69 /** driver data of _EGLDisplay */
70 struct xdri_egl_display
73 __GLXdisplayPrivate
*dpyPriv
;
74 __GLXDRIdisplay
*driDisplay
;
77 __GLXscreenConfigs
*psc
;
82 /** subclass of _EGLContext */
83 struct xdri_egl_context
85 _EGLContext Base
; /**< base class */
87 /* just enough info to create dri contexts */
90 __GLXDRIcontext
*driContext
;
94 /** subclass of _EGLSurface */
95 struct xdri_egl_surface
97 _EGLSurface Base
; /**< base class */
100 __GLXDRIdrawable
*driDrawable
;
104 /** subclass of _EGLConfig */
105 struct xdri_egl_config
107 _EGLConfig Base
; /**< base class */
109 const __GLcontextModes
*mode
; /**< corresponding GLX mode */
110 EGLint window_render_buffer
;
116 static INLINE
struct xdri_egl_driver
*
117 xdri_egl_driver(_EGLDriver
*drv
)
119 return (struct xdri_egl_driver
*) drv
;
123 static INLINE
struct xdri_egl_display
*
124 lookup_display(_EGLDisplay
*dpy
)
126 return (struct xdri_egl_display
*) dpy
->DriverData
;
130 /** Map EGLSurface handle to xdri_egl_surface object */
131 static INLINE
struct xdri_egl_surface
*
132 lookup_surface(_EGLSurface
*surface
)
134 return (struct xdri_egl_surface
*) surface
;
138 /** Map EGLContext handle to xdri_egl_context object */
139 static INLINE
struct xdri_egl_context
*
140 lookup_context(_EGLContext
*context
)
142 return (struct xdri_egl_context
*) context
;
146 /** Map EGLConfig handle to xdri_egl_config object */
147 static INLINE
struct xdri_egl_config
*
148 lookup_config(_EGLConfig
*conf
)
150 return (struct xdri_egl_config
*) conf
;
154 /** Get size of given window */
156 get_drawable_size(Display
*dpy
, Drawable d
, uint
*width
, uint
*height
)
161 unsigned int w
, h
, bw
, depth
;
162 stat
= XGetGeometry(dpy
, d
, &root
, &xpos
, &ypos
, &w
, &h
, &bw
, &depth
);
170 convert_config(_EGLConfig
*conf
, EGLint id
, const __GLcontextModes
*m
)
174 _eglInitConfig(conf
, id
);
175 if (!_eglConfigFromContextModesRec(conf
, m
, EGL_OPENGL_BIT
, EGL_OPENGL_BIT
))
178 if (m
->doubleBufferMode
) {
179 /* pixmap and pbuffer surfaces are always single-buffered */
180 val
= GET_CONFIG_ATTRIB(conf
, EGL_SURFACE_TYPE
);
181 val
&= ~(EGL_PIXMAP_BIT
| EGL_PBUFFER_BIT
);
182 SET_CONFIG_ATTRIB(conf
, EGL_SURFACE_TYPE
, val
);
185 /* EGL requires OpenGL ES context to be double-buffered */
186 val
= GET_CONFIG_ATTRIB(conf
, EGL_RENDERABLE_TYPE
);
187 val
&= ~(EGL_OPENGL_ES_BIT
| EGL_OPENGL_ES2_BIT
);
188 SET_CONFIG_ATTRIB(conf
, EGL_RENDERABLE_TYPE
, val
);
190 /* skip "empty" config */
194 val
= GET_CONFIG_ATTRIB(conf
, EGL_SURFACE_TYPE
);
195 if (!(val
& EGL_PBUFFER_BIT
)) {
196 /* bind-to-texture cannot be EGL_TRUE without pbuffer bit */
197 SET_CONFIG_ATTRIB(conf
, EGL_BIND_TO_TEXTURE_RGB
, EGL_FALSE
);
198 SET_CONFIG_ATTRIB(conf
, EGL_BIND_TO_TEXTURE_RGBA
, EGL_FALSE
);
201 /* EGL_NATIVE_RENDERABLE is a boolean */
202 val
= GET_CONFIG_ATTRIB(conf
, EGL_NATIVE_RENDERABLE
);
204 SET_CONFIG_ATTRIB(conf
, EGL_NATIVE_RENDERABLE
, EGL_FALSE
);
206 return _eglValidateConfig(conf
, EGL_FALSE
);
211 * Produce a set of EGL configs.
214 create_configs(_EGLDisplay
*disp
, const __GLcontextModes
*m
, EGLint first_id
)
216 struct xdri_egl_display
*xdri_dpy
= lookup_display(disp
);
219 for (; m
; m
= m
->next
) {
220 struct xdri_egl_config
*xdri_conf
;
224 if (!convert_config(&conf
, id
, m
))
226 if (m
->doubleBufferMode
) {
227 rb
= EGL_BACK_BUFFER
;
230 /* ignore single-buffered mode for DRISW */
231 if (xdri_dpy
->driVersion
== 0)
233 rb
= EGL_SINGLE_BUFFER
;
236 xdri_conf
= CALLOC_STRUCT(xdri_egl_config
);
238 memcpy(&xdri_conf
->Base
, &conf
, sizeof(conf
));
240 xdri_conf
->window_render_buffer
= rb
;
241 _eglAddConfig(disp
, &xdri_conf
->Base
);
251 * Called via eglInitialize(), xdri_dpy->API.Initialize().
254 xdri_eglInitialize(_EGLDriver
*drv
, _EGLDisplay
*dpy
,
255 EGLint
*minor
, EGLint
*major
)
257 struct xdri_egl_display
*xdri_dpy
;
258 __GLXdisplayPrivate
*dpyPriv
;
259 __GLXDRIdisplay
*driDisplay
;
260 __GLXscreenConfigs
*psc
;
264 xdri_dpy
= CALLOC_STRUCT(xdri_egl_display
);
266 return _eglError(EGL_BAD_ALLOC
, "eglInitialize");
268 xdri_dpy
->dpy
= (Display
*) dpy
->NativeDisplay
;
269 if (!xdri_dpy
->dpy
) {
270 xdri_dpy
->dpy
= XOpenDisplay(NULL
);
271 if (!xdri_dpy
->dpy
) {
273 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
277 dpyPriv
= __glXInitialize(xdri_dpy
->dpy
);
279 _eglLog(_EGL_WARNING
, "failed to create GLX display");
281 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
284 driDisplay
= __driCreateDisplay(dpyPriv
, &xdri_dpy
->driVersion
);
286 _eglLog(_EGL_WARNING
, "failed to create DRI display");
288 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
291 scr
= DefaultScreen(xdri_dpy
->dpy
);
292 psc
= &dpyPriv
->screenConfigs
[scr
];
294 xdri_dpy
->dpyPriv
= dpyPriv
;
295 xdri_dpy
->driDisplay
= driDisplay
;
299 psc
->driScreen
= driDisplay
->createScreen(psc
, scr
, dpyPriv
);
300 if (!psc
->driScreen
) {
301 _eglLog(_EGL_WARNING
, "failed to create DRI screen #%d", scr
);
303 return _eglError(EGL_NOT_INITIALIZED
, "eglInitialize");
306 dpy
->DriverData
= xdri_dpy
;
307 dpy
->ClientAPIsMask
= EGL_OPENGL_BIT
;
309 /* add visuals and fbconfigs */
310 first_id
= create_configs(dpy
, psc
->visuals
, first_id
);
311 create_configs(dpy
, psc
->configs
, first_id
);
313 /* we're supporting EGL 1.4 */
322 * Called via eglTerminate(), drv->API.Terminate().
325 xdri_eglTerminate(_EGLDriver
*drv
, _EGLDisplay
*dpy
)
327 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
328 __GLXscreenConfigs
*psc
;
330 _eglReleaseDisplayResources(drv
, dpy
);
331 _eglCleanupDisplay(dpy
);
334 if (psc
->driver_configs
) {
336 for (i
= 0; psc
->driver_configs
[i
]; i
++)
337 free((__DRIconfig
*) psc
->driver_configs
[i
]);
338 free(psc
->driver_configs
);
339 psc
->driver_configs
= NULL
;
341 if (psc
->driScreen
) {
342 psc
->driScreen
->destroyScreen(psc
);
343 free(psc
->driScreen
);
344 psc
->driScreen
= NULL
;
347 xdri_dpy
->driDisplay
->destroyDisplay(xdri_dpy
->driDisplay
);
350 dpy
->DriverData
= NULL
;
357 * Called from eglGetProcAddress() via drv->API.GetProcAddress().
360 xdri_eglGetProcAddress(_EGLDriver
*drv
, const char *procname
)
362 /* the symbol is defined in libGL.so */
363 return (_EGLProc
) _glapi_get_proc_address(procname
);
368 * Called via eglCreateContext(), drv->API.CreateContext().
371 xdri_eglCreateContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
372 _EGLContext
*share_list
, const EGLint
*attrib_list
)
374 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
375 struct xdri_egl_config
*xdri_config
= lookup_config(conf
);
376 struct xdri_egl_context
*shared
= lookup_context(share_list
);
377 __GLXscreenConfigs
*psc
= xdri_dpy
->psc
;
378 int renderType
= GLX_RGBA_BIT
;
379 struct xdri_egl_context
*xdri_ctx
;
381 xdri_ctx
= CALLOC_STRUCT(xdri_egl_context
);
383 _eglError(EGL_BAD_ALLOC
, "eglCreateContext");
387 xdri_ctx
->dummy_gc
= CALLOC_STRUCT(__GLXcontextRec
);
388 if (!xdri_ctx
->dummy_gc
) {
389 _eglError(EGL_BAD_ALLOC
, "eglCreateContext");
394 if (!_eglInitContext(drv
, &xdri_ctx
->Base
, &xdri_config
->Base
, attrib_list
)) {
395 free(xdri_ctx
->dummy_gc
);
400 /* the config decides the render buffer for the context */
401 xdri_ctx
->Base
.WindowRenderBuffer
= xdri_config
->window_render_buffer
;
403 xdri_ctx
->driContext
=
404 psc
->driScreen
->createContext(psc
,
407 (shared
) ? shared
->dummy_gc
: NULL
,
409 if (!xdri_ctx
->driContext
) {
410 free(xdri_ctx
->dummy_gc
);
415 /* fill in the required field */
416 xdri_ctx
->dummy_gc
->driContext
= xdri_ctx
->driContext
;
418 return &xdri_ctx
->Base
;
423 xdri_eglDestroyContext(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLContext
*ctx
)
425 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
426 struct xdri_egl_context
*xdri_ctx
= lookup_context(ctx
);
428 if (!_eglIsContextBound(ctx
)) {
429 xdri_ctx
->driContext
->destroyContext(xdri_ctx
->driContext
,
430 xdri_dpy
->psc
, xdri_dpy
->dpy
);
431 free(xdri_ctx
->dummy_gc
);
440 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
443 xdri_eglMakeCurrent(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*d
,
444 _EGLSurface
*r
, _EGLContext
*context
)
446 struct xdri_egl_driver
*xdri_driver
= xdri_egl_driver(drv
);
447 struct xdri_egl_context
*xdri_ctx
= lookup_context(context
);
448 struct xdri_egl_surface
*draw
= lookup_surface(d
);
449 struct xdri_egl_surface
*read
= lookup_surface(r
);
450 _EGLContext
*old
= _eglGetCurrentContext();
452 /* an unlinked context will be invalid after context switch */
453 if (!_eglIsContextLinked(old
))
456 if (!_eglMakeCurrent(drv
, dpy
, d
, r
, context
))
459 /* flush before context switch */
460 if (old
&& old
!= context
&& xdri_driver
->FlushCurrentContext
)
461 xdri_driver
->FlushCurrentContext();
463 /* the symbol is defined in libGL.so */
464 _glapi_check_multithread();
467 if (!xdri_ctx
->driContext
->bindContext(xdri_ctx
->driContext
,
469 read
->driDrawable
)) {
474 xdri_ctx
= lookup_context(old
);
475 xdri_ctx
->driContext
->unbindContext(xdri_ctx
->driContext
);
483 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
486 xdri_eglCreateWindowSurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
487 EGLNativeWindowType window
,
488 const EGLint
*attrib_list
)
490 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
491 struct xdri_egl_config
*xdri_config
= lookup_config(conf
);
492 struct xdri_egl_surface
*xdri_surf
;
495 xdri_surf
= CALLOC_STRUCT(xdri_egl_surface
);
497 _eglError(EGL_BAD_ALLOC
, "eglCreateWindowSurface");
501 if (!_eglInitSurface(drv
, &xdri_surf
->Base
, EGL_WINDOW_BIT
,
502 &xdri_config
->Base
, attrib_list
)) {
507 xdri_surf
->driDrawable
=
508 xdri_dpy
->psc
->driScreen
->createDrawable(xdri_dpy
->psc
,
510 (GLXDrawable
) window
,
512 if (!xdri_surf
->driDrawable
) {
517 xdri_surf
->drawable
= (Drawable
) window
;
519 get_drawable_size(xdri_dpy
->dpy
, window
, &width
, &height
);
520 xdri_surf
->Base
.Width
= width
;
521 xdri_surf
->Base
.Height
= height
;
523 return &xdri_surf
->Base
;
528 * Called via eglCreatePbufferSurface(), drv->API.CreatePbufferSurface().
531 xdri_eglCreatePbufferSurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLConfig
*conf
,
532 const EGLint
*attrib_list
)
540 xdri_eglDestroySurface(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surface
)
542 struct xdri_egl_surface
*xdri_surf
= lookup_surface(surface
);
544 if (!_eglIsSurfaceBound(&xdri_surf
->Base
)) {
545 xdri_surf
->driDrawable
->destroyDrawable(xdri_surf
->driDrawable
);
554 xdri_eglBindTexImage(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
,
562 xdri_eglReleaseTexImage(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*surf
,
570 xdri_eglSwapBuffers(_EGLDriver
*drv
, _EGLDisplay
*dpy
, _EGLSurface
*draw
)
572 struct xdri_egl_driver
*xdri_driver
= xdri_egl_driver(drv
);
573 struct xdri_egl_display
*xdri_dpy
= lookup_display(dpy
);
574 struct xdri_egl_surface
*xdri_surf
= lookup_surface(draw
);
576 /* swapBuffers does not flush commands */
577 if (draw
== _eglGetCurrentSurface(EGL_DRAW
) &&
578 xdri_driver
->FlushCurrentContext
)
579 xdri_driver
->FlushCurrentContext();
581 xdri_dpy
->psc
->driScreen
->swapBuffers(xdri_surf
->driDrawable
, 0, 0, 0);
588 xdri_Unload(_EGLDriver
*drv
)
590 struct xdri_egl_driver
*xdri_drv
= xdri_egl_driver(drv
);
596 * This is the main entrypoint into the driver, called by libEGL.
597 * Create a new _EGLDriver object and init its dispatch table.
600 _eglMain(const char *args
)
602 struct xdri_egl_driver
*xdri_drv
= CALLOC_STRUCT(xdri_egl_driver
);
606 _eglInitDriverFallbacks(&xdri_drv
->Base
);
607 xdri_drv
->Base
.API
.Initialize
= xdri_eglInitialize
;
608 xdri_drv
->Base
.API
.Terminate
= xdri_eglTerminate
;
610 xdri_drv
->Base
.API
.GetProcAddress
= xdri_eglGetProcAddress
;
612 xdri_drv
->Base
.API
.CreateContext
= xdri_eglCreateContext
;
613 xdri_drv
->Base
.API
.DestroyContext
= xdri_eglDestroyContext
;
614 xdri_drv
->Base
.API
.MakeCurrent
= xdri_eglMakeCurrent
;
615 xdri_drv
->Base
.API
.CreateWindowSurface
= xdri_eglCreateWindowSurface
;
616 xdri_drv
->Base
.API
.CreatePbufferSurface
= xdri_eglCreatePbufferSurface
;
617 xdri_drv
->Base
.API
.DestroySurface
= xdri_eglDestroySurface
;
618 xdri_drv
->Base
.API
.BindTexImage
= xdri_eglBindTexImage
;
619 xdri_drv
->Base
.API
.ReleaseTexImage
= xdri_eglReleaseTexImage
;
620 xdri_drv
->Base
.API
.SwapBuffers
= xdri_eglSwapBuffers
;
622 xdri_drv
->Base
.Name
= "X/DRI";
623 xdri_drv
->Base
.Unload
= xdri_Unload
;
625 /* we need a way to flush commands */
626 xdri_drv
->FlushCurrentContext
=
627 (void (*)(void)) xdri_eglGetProcAddress(&xdri_drv
->Base
, "glFlush");
629 return &xdri_drv
->Base
;