[Mesa-dev] [PATCH] egl: Introduce eglGetDisplayMESA()

Kristian Høgsberg krh at bitplanet.net
Thu May 27 07:23:31 PDT 2010


This patch introduces a new extension to allow different ways to
create an EGLDisplay to exist within the same libEGL.so.  The new
extension, EGL_MESA_get_display, introduces a new entrypoint:

  EGLDisplay eglGetDisplayMESA(EGLint type, void *display)

which takes an integer to identify the type of display to get and a
void pointer to provide extra parameters for the display type in
question.  At this point, three different display types are supported,
EGLNativeDisplayType, DRM display and XCB display.

Since an application needs to have an EGLDisplay before it can query
for extensions, the way to discover this extension is to just use
eglGetProcAddress().
---

Ok, thinking about this some more, the whole deal with passing in a
custom struct to eglGetDisplay() and relying on the layout of the X
Display struct was just a little too magic.  And since any application
using that needs to know about those structs and the display type
defines anyway, we may just as well make a new entrypoint.  This feels
a lot simpler and more robust, and we trade the eglplatform.h
additions that Chia-I didn't like for a new extension in eglext.h.

Kristian

 configs/autoconf.in             |    6 +-
 configure.ac                    |   15 +++-
 include/EGL/eglext.h            |   15 +++
 src/egl/drivers/dri2/Makefile   |    6 +-
 src/egl/drivers/dri2/egl_dri2.c |  182 +++++++++++++++++++++++++++++++++-----
 src/egl/drivers/glx/egl_glx.c   |    5 +
 src/egl/main/eglapi.c           |   13 +++-
 src/egl/main/egldisplay.c       |    8 +-
 src/egl/main/egldisplay.h       |    4 +-
 9 files changed, 219 insertions(+), 35 deletions(-)

diff --git a/configs/autoconf.in b/configs/autoconf.in
index 0b5be0c..0238b10 100644
--- a/configs/autoconf.in
+++ b/configs/autoconf.in
@@ -180,8 +180,10 @@ EGL_PC_REQ_PRIV = @GL_PC_REQ_PRIV@
 EGL_PC_LIB_PRIV = @GL_PC_LIB_PRIV@
 EGL_PC_CFLAGS = @GL_PC_CFLAGS@
 
-EGL_DRI2_CFLAGS = @EGL_DRI2_CFLAGS@
-EGL_DRI2_LIBS = @EGL_DRI2_LIBS@
+XCB_DRI2_CFLAGS = @XCB_DRI2_CFLAGS@
+XCB_DRI2_LIBS = @XCB_DRI2_LIBS@
+LIBUDEV_CFLAGS = @LIBUDEV_CFLAGS@
+LIBUDEV_LIBS = @LIBUDEV_LIBS@
 
 MESA_LLVM = @MESA_LLVM@
 
diff --git a/configure.ac b/configure.ac
index 3d8da6c..04e1166 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1013,11 +1013,22 @@ if test "x$enable_egl" = xyes; then
         fi
 
         # build egl_dri2 when xcb-dri2 is available
-        PKG_CHECK_MODULES([EGL_DRI2], [x11-xcb xcb-dri2 xcb-xfixes libdrm],
+        PKG_CHECK_MODULES([XCB_DRI2], [x11-xcb xcb-dri2 xcb-xfixes],
 			  [have_xcb_dri2=yes],[have_xcb_dri2=no])
+	PKG_CHECK_MODULES([LIBUDEV], [libudev > 150],
+			  [have_libudev=yes],[have_libudev=no])
+
         if test "$have_xcb_dri2" = yes; then
-            EGL_DRIVERS_DIRS="$EGL_DRIVERS_DIRS dri2"
+	    EGL_DRIVER_DRI2=dri2
+            DEFINES="$DEFINES -DHAVE_XCB_DRI2"
+        fi
+
+        if test "$have_libudev" = yes; then
+	    EGL_DRIVER_DRI2=dri2
+            DEFINES="$DEFINES -DHAVE_LIBUDEV"
         fi
+
+        EGL_DRIVERS_DIRS="$EGL_DRIVERS_DIRS $EGL_DRIVER_DRI2"
     fi
 
     if test "$with_demos" = yes; then
diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
index e9f5a49..664fe55 100644
--- a/include/EGL/eglext.h
+++ b/include/EGL/eglext.h
@@ -246,6 +246,21 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOK) (EGLDisplay dpy, EG
 #endif /* EGL_NOK_texture_from_pixmap */
 
 
+#ifndef EGL_MESA_get_display
+#define EGL_MESA_get_display 1
+
+#define EGL_DISPLAY_TYPE_NATIVE_MESA	0
+#define EGL_DISPLAY_TYPE_DRM_MESA	1
+#define EGL_DISPLAY_TYPE_XCB_MESA	2
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplayMESA(EGLint type, void *display);
+#endif
+
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYMESA) (EGLint type, void *display);
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/egl/drivers/dri2/Makefile b/src/egl/drivers/dri2/Makefile
index 4e760ae..8a3c9b6 100644
--- a/src/egl/drivers/dri2/Makefile
+++ b/src/egl/drivers/dri2/Makefile
@@ -11,8 +11,10 @@ EGL_INCLUDES = \
 	-I$(TOP)/src/egl/main \
 	-I$(TOP)/src/mapi \
 	-DDEFAULT_DRIVER_DIR=\"$(DRI_DRIVER_SEARCH_DIR)\" \
-	$(EGL_DRI2_CFLAGS)
+	$(XCB_DRI2_CFLAGS) \
+	$(LIBUDEV_CFLAGS) \
+	$(LIBDRM_CFLAGS)
 
-EGL_LIBS = $(EGL_DRI2_LIBS)
+EGL_LIBS = $(XCB_DRI2_LIBS) $(LIBUDEV_LIBS) $(LIBDRM_LIBS)
 
 include ../Makefile.template
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index eb9a651..81e1de4 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -40,6 +40,12 @@
 #include <xcb/dri2.h>
 #include <xcb/xfixes.h>
 #include <X11/Xlib-xcb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#endif
 
 #include <glapi/glapi.h>
 #include "eglconfig.h"
@@ -500,7 +506,6 @@ dri2_connect(struct dri2_egl_display *dri2_dpy)
 
    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
-
    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
 						  XCB_XFIXES_MAJOR_VERSION,
 						  XCB_XFIXES_MINOR_VERSION);
@@ -628,6 +633,106 @@ dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
    return EGL_TRUE;
 }
 
+#ifdef HAVE_LIBUDEV
+
+struct dri2_driver_map {
+   int vendor_id;
+   const char *driver;
+   const int *chip_ids;
+   int num_chips_ids;
+};
+
+const int i915_chip_ids[] = {
+   0x3577, /* PCI_CHIP_I830_M */
+   0x2562, /* PCI_CHIP_845_G */
+   0x3582, /* PCI_CHIP_I855_GM */
+   0x2572, /* PCI_CHIP_I865_G */
+   0x2582, /* PCI_CHIP_I915_G */
+   0x258a, /* PCI_CHIP_E7221_G */
+   0x2592, /* PCI_CHIP_I915_GM */
+   0x2772, /* PCI_CHIP_I945_G */
+   0x27a2, /* PCI_CHIP_I945_GM */
+   0x27ae, /* PCI_CHIP_I945_GME */
+   0x29b2, /* PCI_CHIP_Q35_G */
+   0x29c2, /* PCI_CHIP_G33_G */
+   0x29d2, /* PCI_CHIP_Q33_G */
+};
+
+const int i965_chip_ids[] = {
+   0x29a2, /* PCI_CHIP_I965_G */
+   0x2992, /* PCI_CHIP_I965_Q */
+   0x2982, /* PCI_CHIP_I965_G_1 */
+   0x2972, /* PCI_CHIP_I946_GZ */
+   0x2a02, /* PCI_CHIP_I965_GM */
+   0x2a12, /* PCI_CHIP_I965_GME */
+   0x2a42, /* PCI_CHIP_GM45_GM */
+   0x2e02, /* PCI_CHIP_IGD_E_G */
+   0x2e12, /* PCI_CHIP_Q45_G */
+   0x2e22, /* PCI_CHIP_G45_G */
+   0x2e32, /* PCI_CHIP_G41_G */
+};
+
+const struct dri2_driver_map driver_map[] = {
+   { 0x8086, "i915", i915_chip_ids, ARRAY_SIZE(i915_chip_ids) },
+   { 0x8086, "i965", i965_chip_ids, ARRAY_SIZE(i965_chip_ids) },
+};   
+
+static char *
+dri2_get_driver_for_fd(int fd)
+{
+   struct udev *udev;
+   struct udev_device *device, *parent;
+   struct stat buf;
+   const char *pci_id;
+   char *driver = NULL;
+   int vendor_id, chip_id, i, j;
+
+   udev = udev_new();
+   if (fstat(fd, &buf) < 0) {
+      _eglLog(_EGL_WARNING, "DRI2: failed to stat fd %d", fd);
+      goto out;
+   }
+
+   device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
+   if (device == NULL) {
+      _eglLog(_EGL_WARNING,
+	      "DRI2: could not create udev device for fd %d", fd);
+      goto out;
+   }
+
+   parent = udev_device_get_parent(device);
+   if (parent == NULL) {
+      _eglLog(_EGL_WARNING, "DRI2: could not get parent device");
+      goto out;
+   }
+
+   pci_id = udev_device_get_property_value(parent, "PCI_ID");
+   if (pci_id == NULL || sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
+      _eglLog(_EGL_WARNING, "DRI2: malformed or no PCI ID");
+      goto out;
+   }
+   
+   for (i = 0; i < ARRAY_SIZE(driver_map); i++) {
+      if (vendor_id != driver_map[i].vendor_id)
+	 continue;
+      for (j = 0; j < driver_map[i].num_chips_ids; j++)
+	 if (driver_map[i].chip_ids[j] == chip_id) {
+	    driver = strdup(driver_map[i].driver);
+	    _eglLog(_EGL_DEBUG, "pci id for %d: %04x:%04x, driver %s",
+		    fd, vendor_id, chip_id, driver);
+	    goto out;
+	 }
+   }
+
+ out:
+   udev_device_unref(device);
+   udev_unref(udev);
+
+   return driver;
+}
+
+#endif
+
 /**
  * Called via eglInitialize(), GLX_drv->API.Initialize().
  */
@@ -644,25 +749,59 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (!dri2_dpy)
       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
 
+   memset(dri2_dpy, 0, sizeof *dri2_dpy);
    disp->DriverData = (void *) dri2_dpy;
-   if (disp->NativeDisplay == NULL) {
-      dri2_dpy->conn = xcb_connect(0, 0);
-      if (!dri2_dpy->conn) {
-	 _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
-	 goto cleanup_dpy;
+
+   switch (disp->DisplayType) {
+   case EGL_DISPLAY_TYPE_NATIVE_MESA:
+      if (disp->NativeDisplay == NULL) {
+	 dri2_dpy->conn = xcb_connect(0, 0);
+	 if (!dri2_dpy->conn) {
+	    _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
+	    goto cleanup_dpy;
+	 }
+      } else {
+	 dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
       }
-   } else {
-      dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
-   }
+      break;
 
-   if (dri2_dpy->conn == NULL)
-      goto cleanup_conn;
+#ifdef HAVE_LIBUDEV
+   case EGL_DISPLAY_TYPE_DRM_MESA:
+      dri2_dpy->fd = (int) disp->VoidDisplay;
+      break;
+#endif
+
+   case EGL_DISPLAY_TYPE_XCB_MESA:
+      dri2_dpy->conn = disp->VoidDisplay;
+      break;
+
+   default:
+      _eglLog(_EGL_WARNING,
+	      "DRI2: unknown display type: %d", disp->DisplayType);
+      goto cleanup_dpy;
+   }
 
    if (dri2_dpy->conn) {
       if (!dri2_connect(dri2_dpy))
 	 goto cleanup_conn;
    }
 
+   if (dri2_dpy->device_name != NULL) {
+      dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
+      if (dri2_dpy->fd == -1) {
+	 _eglLog(_EGL_WARNING, "DRI2: could not open %s (%s)",
+		 dri2_dpy->device_name, strerror(errno));
+	 goto cleanup_connect;
+      }
+   }
+
+#ifdef HAVE_LIBUDEV
+   if (dri2_dpy->driver_name == NULL)
+      dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
+#endif
+   if (dri2_dpy->driver_name == NULL)
+      goto cleanup_fd;
+
    search_paths = NULL;
    if (geteuid() == getuid()) {
       /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
@@ -698,7 +837,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
       _eglLog(_EGL_WARNING,
 	      "DRI2: failed to open any driver (search paths %s)",
 	      search_paths);
-      goto cleanup_conn;
+      goto cleanup_fd;
    }
 
    _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
@@ -712,17 +851,9 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions))
       goto cleanup_driver;
 
-   dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
-   if (dri2_dpy->fd == -1) {
-      _eglLog(_EGL_WARNING,
-	      "DRI2: could not open %s (%s)", dri2_dpy->device_name,
-              strerror(errno));
-      goto cleanup_driver;
-   }
-
    if (dri2_dpy->conn) {
       if (!dri2_authenticate(dri2_dpy))
-	 goto cleanup_fd;
+	 goto cleanup_driver;
    }
 
    if (dri2_dpy->dri2_minor >= 1) {
@@ -754,7 +885,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
 
    if (dri2_dpy->dri_screen == NULL) {
       _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
-      goto cleanup_fd;
+      goto cleanup_driver;
    }
 
    extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
@@ -796,10 +927,13 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    _eglCleanupDisplay(disp);
  cleanup_dri_screen:
    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
- cleanup_fd:
-   close(dri2_dpy->fd);
  cleanup_driver:
    dlclose(dri2_dpy->driver);
+ cleanup_fd:
+   close(dri2_dpy->fd);
+ cleanup_connect:
+   free(dri2_dpy->device_name);
+   free(dri2_dpy->driver_name);
  cleanup_conn:
    if (disp->NativeDisplay == NULL)
       xcb_disconnect(dri2_dpy->conn);
diff --git a/src/egl/drivers/glx/egl_glx.c b/src/egl/drivers/glx/egl_glx.c
index e08ef5f..cd54c77 100644
--- a/src/egl/drivers/glx/egl_glx.c
+++ b/src/egl/drivers/glx/egl_glx.c
@@ -502,6 +502,11 @@ GLX_eglInitialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (!GLX_dpy)
       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
 
+   if (disp->DisplayType != EGL_DISPLAY_TYPE_NATIVE_MESA) {
+      _eglLog(_EGL_WARNING, "GLX: Unsupported display type");
+      return EGL_FALSE;
+   }
+
    GLX_dpy->dpy = (Display *) disp->NativeDisplay;
    if (!GLX_dpy->dpy) {
       GLX_dpy->dpy = XOpenDisplay(NULL);
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 1a533e0..d158714 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -248,7 +248,8 @@ _eglUnlockDisplay(_EGLDisplay *dpy)
 EGLDisplay EGLAPIENTRY
 eglGetDisplay(EGLNativeDisplayType nativeDisplay)
 {
-   _EGLDisplay *dpy = _eglFindDisplay(nativeDisplay);
+   _EGLDisplay *dpy =
+      _eglFindDisplay(EGL_DISPLAY_TYPE_NATIVE_MESA, (void *) nativeDisplay);
    return _eglGetDisplayHandle(dpy);
 }
 
@@ -811,6 +812,13 @@ eglGetError(void)
    return e;
 }
 
+EGLDisplay EGLAPIENTRY
+eglGetDisplayMESA(EGLint type, void *display)
+{
+   _EGLDisplay *dpy = _eglFindDisplay(type, display);
+
+   return _eglGetDisplayHandle(dpy);
+}
 
 __eglMustCastToProperFunctionPointerType EGLAPIENTRY
 eglGetProcAddress(const char *procname)
@@ -841,6 +849,9 @@ eglGetProcAddress(const char *procname)
 #ifdef EGL_NOK_swap_region
       { "eglSwapBuffersRegionNOK", (_EGLProc) eglSwapBuffersRegionNOK },
 #endif
+#ifdef EGL_MESA_get_display
+      { "eglGetDisplayMESA", (_EGLProc) eglGetDisplayMESA },
+#endif
       { NULL, NULL }
    };
    EGLint i;
diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c
index 5dc5fd9..bd2113b 100644
--- a/src/egl/main/egldisplay.c
+++ b/src/egl/main/egldisplay.c
@@ -49,7 +49,7 @@ _eglFiniDisplay(void)
  * new one.
  */
 _EGLDisplay *
-_eglFindDisplay(EGLNativeDisplayType nativeDisplay)
+_eglFindDisplay(EGLint type, void *nativeDisplay)
 {
    _EGLDisplay *dpy;
 
@@ -58,7 +58,7 @@ _eglFindDisplay(EGLNativeDisplayType nativeDisplay)
    /* search the display list first */
    dpy = _eglGlobal.DisplayList;
    while (dpy) {
-      if (dpy->NativeDisplay == nativeDisplay)
+      if (dpy->DisplayType == type && dpy->VoidDisplay == nativeDisplay)
          break;
       dpy = dpy->Next;
    }
@@ -68,7 +68,9 @@ _eglFindDisplay(EGLNativeDisplayType nativeDisplay)
       dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
       if (dpy) {
          _eglInitMutex(&dpy->Mutex);
-         dpy->NativeDisplay = nativeDisplay;
+         dpy->NativeDisplay = (EGLNativeDisplayType) nativeDisplay;
+	 dpy->VoidDisplay = nativeDisplay;
+	 dpy->DisplayType = type;
 
          /* add to the display list */ 
          dpy->Next = _eglGlobal.DisplayList;
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index 42e305f..fdf2686 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -61,6 +61,8 @@ struct _egl_display
    _EGLMutex Mutex;
 
    EGLNativeDisplayType NativeDisplay;
+   EGLint DisplayType;
+   void *VoidDisplay;
 
    EGLBoolean Initialized; /**< True if the display is initialized */
    _EGLDriver *Driver;
@@ -92,7 +94,7 @@ _eglFiniDisplay(void);
 
 
 extern _EGLDisplay *
-_eglFindDisplay(EGLNativeDisplayType displayName);
+_eglFindDisplay(EGLint type, void *display);
 
 
 PUBLIC void
-- 
1.7.0.1



More information about the mesa-dev mailing list