gallium: refactor/replace p_util.h with util/u_memory.h and util/u_math.h
[mesa.git] / src / gallium / winsys / egl_xlib / egl_xlib.c
index 99389970f55d4a3780ddaf473bf1fe51965ef0c8..e9f821d2764e52dc2084ce706455bd2a18b7ebaa 100644 (file)
  */
 
 
+#include <dlfcn.h>
 #include <X11/Xutil.h>
 
 #include "pipe/p_compiler.h"
 #include "pipe/p_format.h"
 #include "pipe/p_state.h"
-#include "pipe/p_util.h"
 #include "pipe/p_winsys.h"
+#include "util/u_memory.h"
 #include "softpipe/sp_winsys.h"
 
 #include "eglconfig.h"
@@ -115,34 +116,76 @@ lookup_context(EGLContext surf)
 }
 
 
+static unsigned int
+bitcount(unsigned int n)
+{
+   unsigned int bits;
+   for (bits = 0; n > 0; n = n >> 1) {
+      bits += (n & 1);
+   }
+   return bits;
+}
+
+
 /**
- * XXX temporary
- * Need to query X server's GLX visuals.
+ * Create the EGLConfigs.  (one per X visual)
  */
 static void
-init_configs(_EGLDriver *drv, EGLDisplay dpy)
+create_configs(_EGLDriver *drv, EGLDisplay dpy)
 {
+   static const EGLint all_apis = (EGL_OPENGL_ES_BIT |
+                                   EGL_OPENGL_ES2_BIT |
+                                   EGL_OPENVG_BIT |
+                                   EGL_OPENGL_BIT);
    _EGLDisplay *disp = _eglLookupDisplay(dpy);
-   int i;
+   XVisualInfo *visInfo, visTemplate;
+   int num_visuals, i;
+
+   /* get list of all X visuals, create an EGL config for each */
+   visTemplate.screen = DefaultScreen(disp->Xdpy);
+   visInfo = XGetVisualInfo(disp->Xdpy, VisualScreenMask,
+                            &visTemplate, &num_visuals);
+   if (!visInfo) {
+      printf("egl_xlib.c: couldn't get any X visuals\n");
+      abort();
+   }
 
-   for (i = 0; i < 2; i++) {
-      _EGLConfig config;
+   for (i = 0; i < num_visuals; i++) {
+      _EGLConfig *config = calloc(1, sizeof(_EGLConfig));
       int id = i + 1;
-      _eglInitConfig(&config, id);
-      SET_CONFIG_ATTRIB(&config, EGL_RED_SIZE, 8);
-      SET_CONFIG_ATTRIB(&config, EGL_GREEN_SIZE, 8);
-      SET_CONFIG_ATTRIB(&config, EGL_BLUE_SIZE, 8);
-      SET_CONFIG_ATTRIB(&config, EGL_ALPHA_SIZE, 8);
-      if (i > 0) {
-         SET_CONFIG_ATTRIB(&config, EGL_DEPTH_SIZE, 24);
-         SET_CONFIG_ATTRIB(&config, EGL_STENCIL_SIZE, 8);
-      }
-      _eglAddConfig(disp, &config);
+      int rbits = bitcount(visInfo[i].red_mask);
+      int gbits = bitcount(visInfo[i].green_mask);
+      int bbits = bitcount(visInfo[i].blue_mask);
+      int abits = bbits == 8 ? 8 : 0;
+      int zbits = 24;
+      int sbits = 8;
+      int visid = visInfo[i].visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+      int vistype = visInfo[i].c_class;
+#else
+      int vistype = visInfo[i].class;
+#endif
+
+      _eglInitConfig(config, id);
+      SET_CONFIG_ATTRIB(config, EGL_BUFFER_SIZE, rbits + gbits + bbits + abits);
+      SET_CONFIG_ATTRIB(config, EGL_RED_SIZE, rbits);
+      SET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE, gbits);
+      SET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE, bbits);
+      SET_CONFIG_ATTRIB(config, EGL_ALPHA_SIZE, abits);
+      SET_CONFIG_ATTRIB(config, EGL_DEPTH_SIZE, zbits);
+      SET_CONFIG_ATTRIB(config, EGL_STENCIL_SIZE, sbits);
+      SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_ID, visid);
+      SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, vistype);
+      SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_FALSE);
+      SET_CONFIG_ATTRIB(config, EGL_CONFORMANT, all_apis);
+      SET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE, all_apis);
+      SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
+
+      _eglAddConfig(disp, config);
    }
 }
 
 
-
 /**
  * Called via eglInitialize(), drv->API.Initialize().
  */
@@ -150,10 +193,7 @@ static EGLBoolean
 xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
                    EGLint *minor, EGLint *major)
 {
-   /* visual configs */
-
-   init_configs(drv, dpy);
-
+   create_configs(drv, dpy);
 
    drv->Initialized = EGL_TRUE;
 
@@ -171,7 +211,6 @@ xlib_eglInitialize(_EGLDriver *drv, EGLDisplay dpy,
 static EGLBoolean
 xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
 {
-
    return EGL_TRUE;
 }
 
@@ -179,11 +218,7 @@ xlib_eglTerminate(_EGLDriver *drv, EGLDisplay dpy)
 static _EGLProc
 xlib_eglGetProcAddress(const char *procname)
 {
-   /* XXX for each supported API, evaluate GetProcAddress(name) */
-   /*
-   return _glapi_get_proc_address(procname);
-   */
-   return NULL;
+   return (_EGLProc) st_get_proc_address(procname);
 }
 
 
@@ -263,7 +298,7 @@ display_surface(struct pipe_winsys *pws,
    ximage->data = data;
    ximage->width = psurf->width;
    ximage->height = psurf->height;
-   ximage->bytes_per_line = psurf->pitch * psurf->cpp;
+   ximage->bytes_per_line = psurf->stride;
    
    XPutImage(xsurf->Dpy, xsurf->Win, xsurf->Gc,
              ximage, 0, 0, 0, 0, psurf->width, psurf->height);
@@ -313,19 +348,26 @@ xlib_eglCreateContext(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
       return EGL_NO_CONTEXT;
    }
 
-   if (ctx->Base.ClientAPI != EGL_OPENGL_API) {
-      _eglError(EGL_BAD_MATCH, "eglCreateContext(only OpenGL API supported)");
+   /* API-dependent context creation */
+   switch (ctx->Base.ClientAPI) {
+   case EGL_OPENVG_API:
+   case EGL_OPENGL_ES_API:
+      _eglLog(_EGL_DEBUG, "Create Context for ES version %d\n",
+              ctx->Base.ClientVersion);
+      /* fall-through */
+   case EGL_OPENGL_API:
+      /* create a softpipe context */
+      ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
+      /* Now do xlib / state tracker inits here */
+      _eglConfigToContextModesRec(conf, &visual);
+      ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
+      break;
+   default:
+      _eglError(EGL_BAD_MATCH, "eglCreateContext(unsupported API)");
       free(ctx);
       return EGL_NO_CONTEXT;
    }
 
-   /* create a softpipe context */
-   ctx->pipe = softpipe_create(xdrv->screen, xdrv->winsys, NULL);
-
-   /* Now do xlib / state tracker inits here */
-   _eglConfigToContextModesRec(conf, &visual);
-   ctx->Context = st_create_context(ctx->pipe, &visual, share_ctx);
-
    _eglSaveContext(&ctx->Base);
 
    return _eglGetContextHandle(&ctx->Base);
@@ -341,7 +383,16 @@ xlib_eglDestroyContext(_EGLDriver *drv, EGLDisplay dpy, EGLContext ctx)
          context->Base.DeletePending = EGL_TRUE;
       }
       else {
-         st_destroy_context(context->Context);
+         /* API-dependent clean-up */
+         switch (context->Base.ClientAPI) {
+         case EGL_OPENGL_ES_API:
+            /* fall-through */
+         case EGL_OPENGL_API:
+            st_destroy_context(context->Context);
+            break;
+         default:
+            assert(0);
+         }
          free(context);
       }
       return EGL_TRUE;
@@ -371,7 +422,10 @@ xlib_eglMakeCurrent(_EGLDriver *drv, EGLDisplay dpy,
                    (draw_surf ? draw_surf->Framebuffer : NULL),
                    (read_surf ? read_surf->Framebuffer : NULL));
 
-   check_and_update_buffer_size(draw_surf);
+   if (draw_surf)
+      check_and_update_buffer_size(draw_surf);
+   if (read_surf && read_surf != draw_surf)
+      check_and_update_buffer_size(draw_surf);
 
    return EGL_TRUE;
 }
@@ -482,6 +536,7 @@ xlib_eglDestroySurface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
          surf->Base.DeletePending = EGL_TRUE;
       }
       else {
+         XFreeGC(surf->Dpy, surf->Gc);
          st_unreference_framebuffer(&surf->Framebuffer);
          free(surf);
       }
@@ -518,6 +573,36 @@ xlib_eglSwapBuffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
 }
 
 
+/**
+ * Determine which API(s) is(are) present by looking for some specific
+ * global symbols.
+ */
+static EGLint
+find_supported_apis(void)
+{
+   EGLint mask = 0;
+   void *handle;
+
+   handle = dlopen(NULL, 0);
+
+   if (dlsym(handle, "st_api_OpenGL_ES1"))
+      mask |= EGL_OPENGL_ES_BIT;
+
+   if (dlsym(handle, "st_api_OpenGL_ES2"))
+      mask |= EGL_OPENGL_ES2_BIT;
+
+   if (dlsym(handle, "st_api_OpenGL"))
+      mask |= EGL_OPENGL_BIT;
+
+   if (dlsym(handle, "st_api_OpenVG"))
+      mask |= EGL_OPENVG_BIT;
+
+   dlclose(handle);
+
+   return mask;
+}
+
+
 /**
  * This is the main entrypoint into the driver.
  * Called by libEGL to instantiate an _EGLDriver object.
@@ -533,6 +618,10 @@ _eglMain(_EGLDisplay *dpy, const char *args)
    if (!xdrv)
       return NULL;
 
+   if (!dpy->Xdpy) {
+      dpy->Xdpy = XOpenDisplay(NULL);
+   }
+
    _eglInitDriverFallbacks(&xdrv->Base);
    xdrv->Base.API.Initialize = xlib_eglInitialize;
    xdrv->Base.API.Terminate = xlib_eglTerminate;
@@ -544,7 +633,14 @@ _eglMain(_EGLDisplay *dpy, const char *args)
    xdrv->Base.API.MakeCurrent = xlib_eglMakeCurrent;
    xdrv->Base.API.SwapBuffers = xlib_eglSwapBuffers;
 
-   xdrv->Base.ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/;
+   xdrv->Base.ClientAPIsMask = find_supported_apis();
+   if (xdrv->Base.ClientAPIsMask == 0x0) {
+      /* the app isn't directly linked with any EGL-supprted APIs
+       * (such as libGLESv2.so) so use an EGL utility to see what
+       * APIs might be loaded dynamically on this system.
+       */
+      xdrv->Base.ClientAPIsMask = _eglFindAPIs();
+   }      
 
    xdrv->Base.Name = "Xlib/softpipe";