egl_dri2: Support _EGL_PLATFORM_DRM
authorKristian Høgsberg <krh@bitplanet.net>
Thu, 3 Jun 2010 02:48:06 +0000 (22:48 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Fri, 9 Jul 2010 00:10:37 +0000 (20:10 -0400)
This lets the egl_dri2 driver initialize on just a DRM fd.

configs/autoconf.in
configure.ac
src/egl/drivers/dri2/Makefile
src/egl/drivers/dri2/egl_dri2.c

index 78fa0af6cc10beef89124b4f6715f4d9df2bafef..5afd5627fec5daad974a0c6a77f8b548aaa92349 100644 (file)
@@ -178,8 +178,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@
 
index f66b93c7916c4628e342ba90728abe9b9d0fafc2..7fcc9fbd921c112b51c2304ae729a31ac3bcc59d 100644 (file)
@@ -962,11 +962,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
 fi
 AC_SUBST([EGL_LIB_DEPS])
index 4e760aec4c87554603338ffeb9084bafbee4b6f2..8a3c9b6a0aa9c7409c8b65d2a117a35f622c86be 100644 (file)
@@ -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
index df79a605dfb0c8610dae8fa25f4e10b1dce7faef..c6d79a64e8aaeabcf7c732f15b09060cf8d51545 100644 (file)
 #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"
@@ -79,7 +85,6 @@ struct dri2_egl_display
    char                     *driver_name;
 
    __DRIdri2LoaderExtension  loader_extension;
-   __DRIimageLookupExtension image_lookup_extension;
    const __DRIextension     *extensions[3];
 };
 
@@ -117,6 +122,10 @@ struct dri2_egl_image
 _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
 _EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
 
+static const __DRIuseInvalidateExtension use_invalidate = {
+   { __DRI_USE_INVALIDATE, 1 }
+};
+
 EGLint dri2_to_egl_attribute_map[] = {
    0,
    EGL_BUFFER_SIZE,            /* __DRI_ATTRIB_BUFFER_SIZE */
@@ -381,6 +390,11 @@ dri2_lookup_egl_image(__DRIcontext *context, void *image, void *data)
    return dri2_img->dri_image;
 }
 
+static const __DRIimageLookupExtension image_lookup_extension = {
+   { __DRI_IMAGE_LOOKUP, 1 },
+   dri2_lookup_egl_image
+};
+
 static __DRIbuffer *
 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
                             int *width, int *height,
@@ -690,20 +704,53 @@ dri2_load_driver(_EGLDisplay *disp)
    return EGL_TRUE;
 }
 
-
-/**
- * Called via eglInitialize(), GLX_drv->API.Initialize().
- */
 static EGLBoolean
-dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
-               EGLint *major, EGLint *minor)
+dri2_create_screen(_EGLDisplay *disp)
 {
    const __DRIextension **extensions;
    struct dri2_egl_display *dri2_dpy;
    unsigned int api_mask;
 
-   if (disp->Platform != _EGL_PLATFORM_X11)
+   dri2_dpy = disp->DriverData;
+   dri2_dpy->dri_screen =
+      dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
+                                     &dri2_dpy->driver_configs, dri2_dpy);
+
+   if (dri2_dpy->dri_screen == NULL) {
+      _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
       return EGL_FALSE;
+   }
+
+   extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
+   if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
+      goto cleanup_dri_screen;
+
+   if (dri2_dpy->dri2->base.version >= 2)
+      api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
+   else
+      api_mask = __DRI_API_OPENGL;
+
+   disp->ClientAPIsMask = 0;
+   if (api_mask & (1 <<__DRI_API_OPENGL))
+      disp->ClientAPIsMask |= EGL_OPENGL_BIT;
+   if (api_mask & (1 <<__DRI_API_GLES))
+      disp->ClientAPIsMask |= EGL_OPENGL_ES_BIT;
+   if (api_mask & (1 << __DRI_API_GLES2))
+      disp->ClientAPIsMask |= EGL_OPENGL_ES2_BIT;
+
+   return EGL_TRUE;
+
+ cleanup_dri_screen:
+   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
+
+   return EGL_FALSE;
+}
+
+static EGLBoolean
+dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp,
+                   EGLint *major, EGLint *minor)
+{
+   struct dri2_egl_display *dri2_dpy;
 
    dri2_dpy = malloc(sizeof *dri2_dpy);
    if (!dri2_dpy)
@@ -757,39 +804,12 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
       dri2_dpy->loader_extension.getBuffersWithFormat = NULL;
    }
       
-   dri2_dpy->image_lookup_extension.base.name = __DRI_IMAGE_LOOKUP;
-   dri2_dpy->image_lookup_extension.base.version = 1;
-   dri2_dpy->image_lookup_extension.lookupEGLImage = dri2_lookup_egl_image;
-
    dri2_dpy->extensions[0] = &dri2_dpy->loader_extension.base;
-   dri2_dpy->extensions[1] = &dri2_dpy->image_lookup_extension.base;
+   dri2_dpy->extensions[1] = &image_lookup_extension.base;
    dri2_dpy->extensions[2] = NULL;
 
-   dri2_dpy->dri_screen =
-      dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
-                                     &dri2_dpy->driver_configs, dri2_dpy);
-
-   if (dri2_dpy->dri_screen == NULL) {
-      _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
+   if (!dri2_create_screen(disp))
       goto cleanup_fd;
-   }
-
-   extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
-   if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
-      goto cleanup_dri_screen;
-
-   if (dri2_dpy->dri2->base.version >= 2)
-      api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
-   else
-      api_mask = __DRI_API_OPENGL;
-
-   disp->ClientAPIsMask = 0;
-   if (api_mask & (1 <<__DRI_API_OPENGL))
-      disp->ClientAPIsMask |= EGL_OPENGL_BIT;
-   if (api_mask & (1 <<__DRI_API_GLES))
-      disp->ClientAPIsMask |= EGL_OPENGL_ES_BIT;
-   if (api_mask & (1 << __DRI_API_GLES2))
-      disp->ClientAPIsMask |= EGL_OPENGL_ES2_BIT;
 
    if (dri2_dpy->conn) {
       if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
@@ -811,7 +831,6 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
 
  cleanup_configs:
    _eglCleanupDisplay(disp);
- cleanup_dri_screen:
    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
  cleanup_fd:
    close(dri2_dpy->fd);
@@ -826,6 +845,168 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    return EGL_FALSE;
 }
 
+#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, "EGL-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,
+             "EGL-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, "EGL-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;
+}
+
+static EGLBoolean
+dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp,
+                   EGLint *major, EGLint *minor)
+{
+   struct dri2_egl_display *dri2_dpy;
+
+   dri2_dpy = malloc(sizeof *dri2_dpy);
+   if (!dri2_dpy)
+      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+   disp->DriverData = (void *) dri2_dpy;
+   dri2_dpy->fd = (int) disp->PlatformDisplay;
+
+   dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd);
+   if (dri2_dpy->driver_name == NULL)
+      return _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
+
+   if (!dri2_load_driver(disp))
+      goto cleanup_driver_name;
+
+   dri2_dpy->extensions[0] = &image_lookup_extension.base;
+   dri2_dpy->extensions[1] = &use_invalidate.base;
+   dri2_dpy->extensions[2] = NULL;
+
+   if (!dri2_create_screen(disp))
+      goto cleanup_driver;
+
+   disp->Extensions.KHR_image_base = EGL_TRUE;
+   disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
+   disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
+
+   return EGL_TRUE;
+
+ cleanup_driver:
+   dlclose(dri2_dpy->driver);
+ cleanup_driver_name:
+   free(dri2_dpy->driver_name);
+
+   return EGL_FALSE;
+}
+
+#endif
+
+/**
+ * Called via eglInitialize(), GLX_drv->API.Initialize().
+ */
+static EGLBoolean
+dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
+               EGLint *major, EGLint *minor)
+{
+   switch (disp->Platform) {
+   case _EGL_PLATFORM_X11:
+      return dri2_initialize_x11(drv, disp, major, minor);
+
+#ifdef HAVE_LIBUDEV
+   case _EGL_PLATFORM_DRM:
+      return dri2_initialize_drm(drv, disp, major, minor);
+#endif
+
+   default:
+      return EGL_FALSE;
+   }
+}
+
 /**
  * Called via eglTerminate(), drv->API.Terminate().
  */