egl_xlib.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00035 #include <dlfcn.h>
00036 #include <X11/Xutil.h>
00037 
00038 #include "pipe/p_compiler.h"
00039 #include "pipe/p_format.h"
00040 #include "pipe/p_state.h"
00041 #include "pipe/p_winsys.h"
00042 #include "util/u_memory.h"
00043 #include "softpipe/sp_winsys.h"
00044 
00045 #include "eglconfig.h"
00046 #include "eglconfigutil.h"
00047 #include "eglcontext.h"
00048 #include "egldisplay.h"
00049 #include "egldriver.h"
00050 #include "eglglobals.h"
00051 #include "egllog.h"
00052 #include "eglsurface.h"
00053 
00054 #include "state_tracker/st_public.h"
00055 
00056 #include "sw_winsys.h"
00057 
00058 
00060 struct xlib_egl_driver
00061 {
00062    _EGLDriver Base;   
00064    struct pipe_winsys *winsys;
00065    struct pipe_screen *screen;
00066 };
00067 
00068 
00070 struct xlib_egl_context
00071 {
00072    _EGLContext Base;   
00074    struct pipe_context *pipe;   
00075    struct st_context *Context;  
00076 };
00077 
00078 
00080 struct xlib_egl_surface
00081 {
00082    _EGLSurface Base;   
00084    Display *Dpy;  
00085    Window Win;    
00086    GC Gc;
00087    XVisualInfo VisInfo;
00088 
00089    struct pipe_winsys *winsys;
00090 
00091    struct st_framebuffer *Framebuffer;
00092 };
00093 
00094 
00096 static INLINE struct xlib_egl_driver *
00097 xlib_egl_driver(_EGLDriver *drv)
00098 {
00099    return (struct xlib_egl_driver *) drv;
00100 }
00101 
00102 
00103 static struct xlib_egl_surface *
00104 lookup_surface(EGLSurface surf)
00105 {
00106    _EGLSurface *surface = _eglLookupSurface(surf);
00107    return (struct xlib_egl_surface *) surface;
00108 }
00109 
00110 
00111 static struct xlib_egl_context *
00112 lookup_context(EGLContext surf)
00113 {
00114    _EGLContext *context = _eglLookupContext(surf);
00115    return (struct xlib_egl_context *) context;
00116 }
00117 
00118 
00119 static unsigned int
00120 bitcount(unsigned int n)
00121 {
00122    unsigned int bits;
00123    for (bits = 0; n > 0; n = n >> 1) {
00124       bits += (n & 1);
00125    }
00126    return bits;
00127 }
00128 
00129 
00133 static void
00134 create_configs(_EGLDriver *drv, EGLDisplay dpy)
00135 {
00136    static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
00137                                    EGL_OPENGL_ES2_BIT |
00138                                    EGL_OPENVG_BIT |
00139                                    EGL_OPENGL_BIT);
00140    _EGLDisplay *disp = _eglLookupDisplay(dpy);
00141    XVisualInfo *visInfo, visTemplate;
00142    int num_visuals, i;
00143 
00144    /* get list of all X visuals, create an EGL config for each */
00145    visTemplate.screen = DefaultScreen(disp->Xdpy);
00146    visInfo = XGetVisualInfo(disp->Xdpy, VisualScreenMask,
00147                             &visTemplate, &num_visuals);
00148    if (!visInfo) {
00149       printf("egl_xlib.c: couldn't get any X visuals\n");
00150       abort();
00151    }
00152 
00153    for (i = 0; i < num_visuals; i++) {
00154       _EGLConfig *config = calloc(1, sizeof(_EGLConfig));
00155       int id = i + 1;
00156       int rbits = bitcount(visInfo[i].red_mask);
00157       int gbits = bitcount(visInfo[i].green_mask);
00158       int bbits = bitcount(visInfo[i].blue_mask);
00159       int abits = bbits == 8 ? 8 : 0;
00160       int zbits = 24;
00161       int sbits = 8;
00162       int visid = visInfo[i].visualid;
00163 #if defined(__cplusplus) || defined(c_plusplus)
00164       int vistype = visInfo[i].c_class;
00165 #else
00166       int vistype = visInfo[i].class;
00167 #endif
00168 
00169       _eglInitConfig(config, id);
00170       SET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE, rbits + gbits + bbits + abits);
00171       SET_CONFIG_ATTRIB(config, EGL_RED_SIZE, rbits);
00172       SET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE, gbits);
00173       SET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE, bbits);
00174       SET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE, abits);
00175       SET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE, zbits);
00176       SET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE, sbits);
00177       SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_ID, visid);
00178       SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, vistype);
00179       SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_FALSE);
00180       SET_CONFIG_ATTRIB(config, EGL_CONFORMANT, all_apis);
00181       SET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE, all_apis);
00182       SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
00183 
00184       _eglAddConfig(disp, config);
00185    }
00186 }
00187 
00188 
00192 static EGLBoolean
00193 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
00194                    EGLint *minor, EGLint *major)
00195 {
00196    create_configs(drv, dpy);
00197 
00198    drv->Initialized = EGL_TRUE;
00199 
00200    /* we're supporting EGL 1.4 */
00201    *minor = 1;
00202    *major = 4;
00203 
00204    return EGL_TRUE;
00205 }
00206 
00207 
00211 static EGLBoolean
00212 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
00213 {
00214    return EGL_TRUE;
00215 }
00216 
00217 
00218 static _EGLProc
00219 xlib_eglGetProcAddress(const char *procname)
00220 {
00221    return (_EGLProc) st_get_proc_address(procname);
00222 }
00223 
00224 
00225 static void
00226 get_drawable_visual_info(Display *dpy, Drawable d, XVisualInfo *visInfo)
00227 {
00228    XWindowAttributes attr;
00229    XVisualInfo visTemp, *vis;
00230    int num_visuals;
00231 
00232    XGetWindowAttributes(dpy, d, &attr);
00233 
00234    visTemp.screen = DefaultScreen(dpy);
00235    visTemp.visualid = attr.visual->visualid;
00236    vis = XGetVisualInfo(dpy,
00237                         (VisualScreenMask | VisualIDMask),
00238                         &visTemp, &num_visuals);
00239    if (vis)
00240       *visInfo = *vis;
00241 
00242    XFree(vis);
00243 }
00244 
00245 
00246 
00248 static Status
00249 get_drawable_size(Display *dpy, Drawable d, uint *width, uint *height)
00250 {
00251    Window root;
00252    Status stat;
00253    int xpos, ypos;
00254    unsigned int w, h, bw, depth;
00255    stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth);
00256    *width = w;
00257    *height = h;
00258    return stat;
00259 }
00260 
00261 
00262 static void
00263 check_and_update_buffer_size(struct xlib_egl_surface *surface)
00264 {
00265    uint width, height;
00266    get_drawable_size(surface->Dpy, surface->Win, &width, &height);
00267    st_resize_framebuffer(surface->Framebuffer, width, height);
00268    surface->Base.Width = width;
00269    surface->Base.Height = height;
00270 }
00271 
00272 
00273 
00274 static void
00275 display_surface(struct pipe_winsys *pws,
00276                 struct pipe_surface *psurf,
00277                 struct xlib_egl_surface *xsurf)
00278 {
00279    XImage *ximage;
00280    void *data;
00281 
00282    ximage = XCreateImage(xsurf->Dpy,
00283                          xsurf->VisInfo.visual,
00284                          xsurf->VisInfo.depth,
00285                          ZPixmap, 0,   /* format, offset */
00286                          NULL,         /* data */
00287                          0, 0,         /* size */
00288                          32,           /* bitmap_pad */
00289                          0);           /* bytes_per_line */
00290 
00291 
00292    assert(ximage->format);
00293    assert(ximage->bitmap_unit);
00294 
00295    data = pws->buffer_map(pws, psurf->buffer, 0);
00296 
00297    /* update XImage's fields */
00298    ximage->data = data;
00299    ximage->width = psurf->width;
00300    ximage->height = psurf->height;
00301    ximage->bytes_per_line = psurf->stride;
00302    
00303    XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
00304              ximage, 0, 0, 0, 0, psurf->width, psurf->height);
00305 
00306    XSync(xsurf->Dpy, 0);
00307 
00308    ximage->data = NULL;
00309    XDestroyImage(ximage);
00310 
00311    pws->buffer_unmap(pws, psurf->buffer);
00312 }
00313 
00314 
00315 
00317 static void
00318 flush_frontbuffer(struct pipe_winsys *pws,
00319                   struct pipe_surface *psurf,
00320                   void *context_private)
00321 {
00322    struct xlib_egl_surface *xsurf = (struct xlib_egl_surface *) context_private;
00323    display_surface(pws, psurf, xsurf);
00324 }
00325 
00326 
00327 
00331 static EGLContext
00332 xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
00333                       EGLContext share_list, const EGLint *attrib_list)
00334 {
00335    struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
00336    _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
00337    struct xlib_egl_context *ctx;
00338    struct st_context *share_ctx = NULL; /* XXX fix */
00339    __GLcontextModes visual;
00340 
00341    ctx = CALLOC_STRUCT(xlib_egl_context);
00342    if (!ctx)
00343       return EGL_NO_CONTEXT;
00344 
00345    /* let EGL lib init the common stuff */
00346    if (!_eglInitContext(drv, dpy, &ctx->Base, config, attrib_list)) {
00347       free(ctx);
00348       return EGL_NO_CONTEXT;
00349    }
00350 
00351    /* API-dependent context creation */
00352    switch (ctx->Base.ClientAPI) {
00353    case EGL_OPENVG_API:
00354    case EGL_OPENGL_ES_API:
00355       _eglLog(_EGL_DEBUG, "Create Context for ES version %d\n",
00356               ctx->Base.ClientVersion);
00357       /* fall-through */
00358    case EGL_OPENGL_API:
00359       /* create a softpipe context */
00360       ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
00361       /* Now do xlib / state tracker inits here */
00362       _eglConfigToContextModesRec(conf, &visual);
00363       ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
00364       break;
00365    default:
00366       _eglError(EGL_BAD_MATCH, "eglCreateContext(unsupported API)");
00367       free(ctx);
00368       return EGL_NO_CONTEXT;
00369    }
00370 
00371    _eglSaveContext(&ctx->Base);
00372 
00373    return _eglGetContextHandle(&ctx->Base);
00374 }
00375 
00376 
00377 static EGLBoolean
00378 xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
00379 {
00380    struct xlib_egl_context *context = lookup_context(ctx);
00381    if (context) {
00382       if (context->Base.IsBound) {
00383          context->Base.DeletePending = EGL_TRUE;
00384       }
00385       else {
00386          /* API-dependent clean-up */
00387          switch (context->Base.ClientAPI) {
00388          case EGL_OPENGL_ES_API:
00389             /* fall-through */
00390          case EGL_OPENGL_API:
00391             st_destroy_context(context->Context);
00392             break;
00393          default:
00394             assert(0);
00395          }
00396          free(context);
00397       }
00398       return EGL_TRUE;
00399    }
00400    else {
00401       _eglError(EGL_BAD_CONTEXT, "eglDestroyContext");
00402       return EGL_TRUE;
00403    }
00404 }
00405 
00406 
00410 static EGLBoolean
00411 xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
00412                     EGLSurface draw, EGLSurface read, EGLContext ctx)
00413 {
00414    struct xlib_egl_context *context = lookup_context(ctx);
00415    struct xlib_egl_surface *draw_surf = lookup_surface(draw);
00416    struct xlib_egl_surface *read_surf = lookup_surface(read);
00417 
00418    if (!_eglMakeCurrent(drv, dpy, draw, read, context))
00419       return EGL_FALSE;
00420 
00421    st_make_current((context ? context->Context : NULL),
00422                    (draw_surf ? draw_surf->Framebuffer : NULL),
00423                    (read_surf ? read_surf->Framebuffer : NULL));
00424 
00425    if (draw_surf)
00426       check_and_update_buffer_size(draw_surf);
00427    if (read_surf && read_surf != draw_surf)
00428       check_and_update_buffer_size(draw_surf);
00429 
00430    return EGL_TRUE;
00431 }
00432 
00433 
00434 static enum pipe_format
00435 choose_color_format(const __GLcontextModes *visual)
00436 {
00437    if (visual->redBits == 8 &&
00438        visual->greenBits == 8 &&
00439        visual->blueBits == 8 &&
00440        visual->alphaBits == 8) {
00441       /* XXX this really also depends on the ordering of R,G,B,A */
00442       return PIPE_FORMAT_A8R8G8B8_UNORM;
00443    }
00444    else {
00445       assert(0);
00446       return PIPE_FORMAT_NONE;
00447    }
00448 }
00449 
00450 
00451 static enum pipe_format
00452 choose_depth_format(const __GLcontextModes *visual)
00453 {
00454    if (visual->depthBits > 0)
00455       return PIPE_FORMAT_S8Z24_UNORM;
00456    else
00457       return PIPE_FORMAT_NONE;
00458 }
00459 
00460 
00461 static enum pipe_format
00462 choose_stencil_format(const __GLcontextModes *visual)
00463 {
00464    if (visual->stencilBits > 0)
00465       return PIPE_FORMAT_S8Z24_UNORM;
00466    else
00467       return PIPE_FORMAT_NONE;
00468 }
00469 
00470 
00474 static EGLSurface
00475 xlib_eglCreateWindowSurface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
00476                             NativeWindowType window, const EGLint *attrib_list)
00477 {
00478    struct xlib_egl_driver *xdrv = xlib_egl_driver(drv);
00479    _EGLDisplay *disp = _eglLookupDisplay(dpy);
00480    _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
00481 
00482    struct xlib_egl_surface *surf;
00483    __GLcontextModes visual;
00484    uint width, height;
00485 
00486    surf = CALLOC_STRUCT(xlib_egl_surface);
00487    if (!surf)
00488       return EGL_NO_SURFACE;
00489 
00490    /* Let EGL lib init the common stuff */
00491    if (!_eglInitSurface(drv, dpy, &surf->Base, EGL_WINDOW_BIT,
00492                         config, attrib_list)) {
00493       free(surf);
00494       return EGL_NO_SURFACE;
00495    }
00496 
00497    _eglSaveSurface(&surf->Base);
00498 
00499    /*
00500     * Now init the Xlib and gallium stuff
00501     */
00502    surf->Win = (Window) window;  /* The X window ID */
00503    surf->Dpy = disp->Xdpy;  /* The X display */
00504    surf->Gc = XCreateGC(surf->Dpy, surf->Win, 0, NULL);
00505 
00506    surf->winsys = xdrv->winsys;
00507 
00508    _eglConfigToContextModesRec(conf, &visual);
00509    get_drawable_size(surf->Dpy, surf->Win, &width, &height);
00510    get_drawable_visual_info(surf->Dpy, surf->Win, &surf->VisInfo);
00511 
00512    surf->Base.Width = width;
00513    surf->Base.Height = height;
00514 
00515    /* Create GL statetracker framebuffer */
00516    surf->Framebuffer = st_create_framebuffer(&visual,
00517                                              choose_color_format(&visual),
00518                                              choose_depth_format(&visual),
00519                                              choose_stencil_format(&visual),
00520                                              width, height,
00521                                              (void *) surf);
00522 
00523    st_resize_framebuffer(surf->Framebuffer, width, height);
00524 
00525    return _eglGetSurfaceHandle(&surf->Base);
00526 }
00527 
00528 
00529 static EGLBoolean
00530 xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
00531 {
00532    struct xlib_egl_surface *surf = lookup_surface(surface);
00533    if (surf) {
00534       _eglHashRemove(_eglGlobal.Surfaces, (EGLuint) surface);
00535       if (surf->Base.IsBound) {
00536          surf->Base.DeletePending = EGL_TRUE;
00537       }
00538       else {
00539          XFreeGC(surf->Dpy, surf->Gc);
00540          st_unreference_framebuffer(&surf->Framebuffer);
00541          free(surf);
00542       }
00543       return EGL_TRUE;
00544    }
00545    else {
00546       _eglError(EGL_BAD_SURFACE, "eglDestroySurface");
00547       return EGL_FALSE;
00548    }
00549 }
00550 
00551 
00552 static EGLBoolean
00553 xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
00554 {
00555    /* error checking step: */
00556    if (!_eglSwapBuffers(drv, dpy, draw))
00557       return EGL_FALSE;
00558 
00559    {
00560       struct xlib_egl_surface *xsurf = lookup_surface(draw);
00561       struct pipe_winsys *pws = xsurf->winsys;
00562       struct pipe_surface *psurf =
00563          st_get_framebuffer_surface(xsurf->Framebuffer, ST_SURFACE_BACK_LEFT);
00564 
00565       st_notify_swapbuffers(xsurf->Framebuffer);
00566 
00567       display_surface(pws, psurf, xsurf);
00568 
00569       check_and_update_buffer_size(xsurf);
00570    }
00571 
00572    return EGL_TRUE;
00573 }
00574 
00575 
00580 static EGLint
00581 find_supported_apis(void)
00582 {
00583    EGLint mask = 0;
00584    void *handle;
00585 
00586    handle = dlopen(NULL, 0);
00587 
00588    if (dlsym(handle, "st_api_OpenGL_ES1"))
00589       mask |= EGL_OPENGL_ES_BIT;
00590 
00591    if (dlsym(handle, "st_api_OpenGL_ES2"))
00592       mask |= EGL_OPENGL_ES2_BIT;
00593 
00594    if (dlsym(handle, "st_api_OpenGL"))
00595       mask |= EGL_OPENGL_BIT;
00596 
00597    if (dlsym(handle, "st_api_OpenVG"))
00598       mask |= EGL_OPENVG_BIT;
00599 
00600    dlclose(handle);
00601 
00602    return mask;
00603 }
00604 
00605 
00610 _EGLDriver *
00611 _eglMain(_EGLDisplay *dpy, const char *args)
00612 {
00613    struct xlib_egl_driver *xdrv;
00614 
00615    _eglLog(_EGL_INFO, "Entering EGL/Xlib _eglMain(%s)", args);
00616 
00617    xdrv = CALLOC_STRUCT(xlib_egl_driver);
00618    if (!xdrv)
00619       return NULL;
00620 
00621    if (!dpy->Xdpy) {
00622       dpy->Xdpy = XOpenDisplay(NULL);
00623    }
00624 
00625    _eglInitDriverFallbacks(&xdrv->Base);
00626    xdrv->Base.API.Initialize = xlib_eglInitialize;
00627    xdrv->Base.API.Terminate = xlib_eglTerminate;
00628    xdrv->Base.API.GetProcAddress = xlib_eglGetProcAddress;
00629    xdrv->Base.API.CreateContext = xlib_eglCreateContext;
00630    xdrv->Base.API.DestroyContext = xlib_eglDestroyContext;
00631    xdrv->Base.API.CreateWindowSurface = xlib_eglCreateWindowSurface;
00632    xdrv->Base.API.DestroySurface = xlib_eglDestroySurface;
00633    xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
00634    xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
00635 
00636    xdrv->Base.ClientAPIsMask = find_supported_apis();
00637    if (xdrv->Base.ClientAPIsMask == 0x0) {
00638       /* the app isn't directly linked with any EGL-supprted APIs
00639        * (such as libGLESv2.so) so use an EGL utility to see what
00640        * APIs might be loaded dynamically on this system.
00641        */
00642       xdrv->Base.ClientAPIsMask = _eglFindAPIs();
00643    }      
00644 
00645    xdrv->Base.Name = "Xlib/softpipe";
00646 
00647    /* create one winsys and use it for all contexts/surfaces */
00648    xdrv->winsys = create_sw_winsys();
00649    xdrv->winsys->flush_frontbuffer = flush_frontbuffer;
00650 
00651    xdrv->screen = softpipe_create_screen(xdrv->winsys);
00652 
00653    return &xdrv->Base;
00654 }
00655 

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4