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 **************************************************************************/
29 * EGL / softpipe / xlib winsys module
35 #include <X11/Xutil.h>
37 #include "pipe/p_compiler.h"
38 #include "pipe/p_format.h"
39 #include "pipe/p_state.h"
40 #include "pipe/p_util.h"
41 #include "pipe/p_winsys.h"
42 #include "softpipe/sp_winsys.h"
44 #include "eglconfig.h"
45 #include "eglconfigutil.h"
46 #include "eglcontext.h"
47 #include "egldisplay.h"
48 #include "egldriver.h"
49 #include "eglglobals.h"
51 #include "eglsurface.h"
53 #include "state_tracker/st_public.h"
55 #include "sw_winsys.h"
58 /** subclass of _EGLDriver */
59 struct xlib_egl_driver
61 _EGLDriver Base; /**< base class */
63 struct pipe_winsys *winsys;
64 struct pipe_screen *screen;
68 /** subclass of _EGLContext */
69 struct xlib_egl_context
71 _EGLContext Base; /**< base class */
73 struct pipe_context *pipe; /**< Gallium driver context */
74 struct st_context *Context; /**< Mesa/gallium state tracker context */
78 /** subclass of _EGLSurface */
79 struct xlib_egl_surface
81 _EGLSurface Base; /**< base class */
83 Display *Dpy; /**< The X Display of the window */
84 Window Win; /**< The user-created window ID */
88 struct pipe_winsys *winsys;
90 struct st_framebuffer *Framebuffer;
95 static INLINE struct xlib_egl_driver *
96 xlib_egl_driver(_EGLDriver *drv)
98 return (struct xlib_egl_driver *) drv;
102 static struct xlib_egl_surface *
103 lookup_surface(EGLSurface surf)
105 _EGLSurface *surface = _eglLookupSurface(surf);
106 return (struct xlib_egl_surface *) surface;
110 static struct xlib_egl_context *
111 lookup_context(EGLContext surf)
113 _EGLContext *context = _eglLookupContext(surf);
114 return (struct xlib_egl_context *) context;
120 * Need to query X server's GLX visuals.
123 init_configs(_EGLDriver *drv, EGLDisplay dpy)
125 _EGLDisplay *disp = _eglLookupDisplay(dpy);
128 for (i = 0; i < 2; i++) {
131 _eglInitConfig(&config, id);
132 SET_CONFIG_ATTRIB(&config, EGL_RED_SIZE, 8);
133 SET_CONFIG_ATTRIB(&config, EGL_GREEN_SIZE, 8);
134 SET_CONFIG_ATTRIB(&config, EGL_BLUE_SIZE, 8);
135 SET_CONFIG_ATTRIB(&config, EGL_ALPHA_SIZE, 8);
137 SET_CONFIG_ATTRIB(&config, EGL_DEPTH_SIZE, 24);
138 SET_CONFIG_ATTRIB(&config, EGL_STENCIL_SIZE, 8);
140 _eglAddConfig(disp, &config);
147 * Called via eglInitialize(), drv->API.Initialize().
150 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
151 EGLint *minor, EGLint *major)
155 init_configs(drv, dpy);
158 drv->Initialized = EGL_TRUE;
160 /* we're supporting EGL 1.4 */
169 * Called via eglTerminate(), drv->API.Terminate().
172 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
180 xlib_eglGetProcAddress(const char *procname)
182 /* XXX for each supported API, evaluate GetProcAddress(name) */
184 return _glapi_get_proc_address(procname);
191 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
193 XWindowAttributes attr;
194 XVisualInfo visTemp, *vis;
197 XGetWindowAttributes(dpy, d, &attr);
199 visTemp.screen = DefaultScreen(dpy);
200 visTemp.visualid = attr.visual->visualid;
201 vis = XGetVisualInfo(dpy,
202 (VisualScreenMask | VisualIDMask),
203 &visTemp, &num_visuals);
212 /** Get size of given window */
214 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
219 unsigned int w, h, bw, depth;
220 stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
228 check_and_update_buffer_size(struct xlib_egl_surface *surface)
231 get_drawable_size(surface->Dpy, surface->Win, &width, &height);
232 st_resize_framebuffer(surface->Framebuffer, width, height);
233 surface->Base.Width = width;
234 surface->Base.Height = height;
240 display_surface(struct pipe_winsys *pws,
241 struct pipe_surface *psurf,
242 struct xlib_egl_surface *xsurf)
247 ximage = XCreateImage(xsurf->Dpy,
248 xsurf->VisInfo.visual,
249 xsurf->VisInfo.depth,
250 ZPixmap, 0, /* format, offset */
254 0); /* bytes_per_line */
257 assert(ximage->format);
258 assert(ximage->bitmap_unit);
260 data = pws->buffer_map(pws, psurf->buffer, 0);
262 /* update XImage's fields */
264 ximage->width = psurf->width;
265 ximage->height = psurf->height;
266 ximage->bytes_per_line = psurf->pitch * psurf->cpp;
268 XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
269 ximage, 0, 0, 0, 0, psurf->width, psurf->height);
271 XSync(xsurf->Dpy, 0);
274 XDestroyImage(ximage);
276 pws->buffer_unmap(pws, psurf->buffer);
281 /** Display gallium surface in X window */
283 flush_frontbuffer(struct pipe_winsys *pws,
284 struct pipe_surface *psurf,
285 void *context_private)
287 struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
288 display_surface(pws, psurf, xsurf);
294 * Called via eglCreateContext(), drv->API.CreateContext().
297 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
298 EGLContext share_list, const EGLint *attrib_list)
300 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
301 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
302 struct xlib_egl_context *ctx;
303 struct st_context *share_ctx = NULL; /* XXX fix */
304 __GLcontextModes visual;
306 ctx = CALLOC_STRUCT(xlib_egl_context);
308 return EGL_NO_CONTEXT;
310 /* let EGL lib init the common stuff */
311 if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
313 return EGL_NO_CONTEXT;
316 if (ctx->Base.ClientAPI != EGL_OPENGL_API) {
317 _eglError(EGL_BAD_MATCH, "eglCreateContext(only OpenGL API supported)");
319 return EGL_NO_CONTEXT;
322 /* create a softpipe context */
323 ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
325 /* Now do xlib / state tracker inits here */
326 _eglConfigToContextModesRec(conf, &visual);
327 ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
329 _eglSaveContext(&ctx->Base);
331 return _eglGetContextHandle(&ctx->Base);
336 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
338 struct xlib_egl_context *context = lookup_context(ctx);
340 if (context->Base.IsBound) {
341 context->Base.DeletePending = EGL_TRUE;
344 st_destroy_context(context->Context);
350 _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
357 * Called via eglMakeCurrent(), drv->API.MakeCurrent().
360 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
361 EGLSurface draw, EGLSurface read, EGLContext ctx)
363 struct xlib_egl_context *context = lookup_context(ctx);
364 struct xlib_egl_surface *draw_surf = lookup_surface(draw);
365 struct xlib_egl_surface *read_surf = lookup_surface(read);
367 if (!_eglMakeCurrent(drv, dpy, draw, read, context))
370 st_make_current((context ? context->Context : NULL),
371 (draw_surf ? draw_surf->Framebuffer : NULL),
372 (read_surf ? read_surf->Framebuffer : NULL));
374 check_and_update_buffer_size(draw_surf);
380 static enum pipe_format
381 choose_color_format(const __GLcontextModes *visual)
383 if (visual->redBits == 8 &&
384 visual->greenBits == 8 &&
385 visual->blueBits == 8 &&
386 visual->alphaBits == 8) {
387 /* XXX this really also depends on the ordering of R,G,B,A */
388 return PIPE_FORMAT_A8R8G8B8_UNORM;
392 return PIPE_FORMAT_NONE;
397 static enum pipe_format
398 choose_depth_format(const __GLcontextModes *visual)
400 if (visual->depthBits > 0)
401 return PIPE_FORMAT_S8Z24_UNORM;
403 return PIPE_FORMAT_NONE;
407 static enum pipe_format
408 choose_stencil_format(const __GLcontextModes *visual)
410 if (visual->stencilBits > 0)
411 return PIPE_FORMAT_S8Z24_UNORM;
413 return PIPE_FORMAT_NONE;
418 * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
421 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
422 NativeWindowType window, const EGLint *attrib_list)
424 struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
425 _EGLDisplay *disp = _eglLookupDisplay(dpy);
426 _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
428 struct xlib_egl_surface *surf;
429 __GLcontextModes visual;
432 surf = CALLOC_STRUCT(xlib_egl_surface);
434 return EGL_NO_SURFACE;
436 /* Let EGL lib init the common stuff */
437 if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
438 config, attrib_list)) {
440 return EGL_NO_SURFACE;
443 _eglSaveSurface(&surf->Base);
446 * Now init the Xlib and gallium stuff
448 surf->Win = (Window) window; /* The X window ID */
449 surf->Dpy = disp->Xdpy; /* The X display */
450 surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
452 surf->winsys = xdrv->winsys;
454 _eglConfigToContextModesRec(conf, &visual);
455 get_drawable_size(surf->Dpy, surf->Win, &width, &height);
456 get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
458 surf->Base.Width = width;
459 surf->Base.Height = height;
461 /* Create GL statetracker framebuffer */
462 surf->Framebuffer = st_create_framebuffer(&visual,
463 choose_color_format(&visual),
464 choose_depth_format(&visual),
465 choose_stencil_format(&visual),
469 st_resize_framebuffer(surf->Framebuffer, width, height);
471 return _eglGetSurfaceHandle(&surf->Base);
476 xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
478 struct xlib_egl_surface *surf = lookup_surface(surface);
480 _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
481 if (surf->Base.IsBound) {
482 surf->Base.DeletePending = EGL_TRUE;
485 st_unreference_framebuffer(&surf->Framebuffer);
491 _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
498 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
500 /* error checking step: */
501 if (!_eglSwapBuffers(drv, dpy, draw))
505 struct xlib_egl_surface *xsurf = lookup_surface(draw);
506 struct pipe_winsys *pws = xsurf->winsys;
507 struct pipe_surface *psurf =
508 st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
510 st_notify_swapbuffers(xsurf->Framebuffer);
512 display_surface(pws, psurf, xsurf);
514 check_and_update_buffer_size(xsurf);
522 * This is the main entrypoint into the driver.
523 * Called by libEGL to instantiate an _EGLDriver object.
526 _eglMain(_EGLDisplay *dpy, const char *args)
528 struct xlib_egl_driver *xdrv;
530 _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
532 xdrv = CALLOC_STRUCT(xlib_egl_driver);
536 _eglInitDriverFallbacks(&xdrv->Base);
537 xdrv->Base.API.Initialize = xlib_eglInitialize;
538 xdrv->Base.API.Terminate = xlib_eglTerminate;
539 xdrv->Base.API.GetProcAddress = xlib_eglGetProcAddress;
540 xdrv->Base.API.CreateContext = xlib_eglCreateContext;
541 xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
542 xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
543 xdrv->Base.API.DestroySurface = xlib_eglDestroySurface;
544 xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
545 xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
547 xdrv->Base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
549 xdrv->Base.Name = "Xlib/softpipe";
551 /* create one winsys and use it for all contexts/surfaces */
552 xdrv->winsys = create_sw_winsys();
553 xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
555 xdrv->screen = softpipe_create_screen(xdrv->winsys);