Merge branch '7.8'
[mesa.git] / src / egl / drivers / dri2 / egl_dri2.c
index 0c2dfe6dd43ca32aaac1e9f2645afd4fbf477add..4be39627302566baca9ecd0eb1c3d6ff34fa7fb2 100644 (file)
@@ -54,6 +54,8 @@
 struct dri2_egl_driver
 {
    _EGLDriver base;
+
+   void (*glFlush)(void);
 };
 
 struct dri2_egl_display
@@ -62,6 +64,7 @@ struct dri2_egl_display
    int                       dri2_major;
    int                       dri2_minor;
    __DRIscreen              *dri_screen;
+   const __DRIconfig       **driver_configs;
    void                     *driver;
    __DRIcoreExtension       *core;
    __DRIdri2Extension       *dri2;
@@ -70,6 +73,9 @@ struct dri2_egl_display
    __DRIimageExtension      *image;
    int                       fd;
 
+   char                     *device_name;
+   char                     *driver_name;
+
    __DRIdri2LoaderExtension  loader_extension;
    __DRIimageLookupExtension image_lookup_extension;
    const __DRIextension     *extensions[3];
@@ -103,12 +109,6 @@ struct dri2_egl_image
 {
    _EGLImage   base;
    __DRIimage *dri_image;
-   int         width;
-   int         height;
-   int         name;
-   int         pitch;
-   int         cpp;
-   int         format;
 };
 
 /* standard typecasts */
@@ -417,9 +417,9 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
 }
 
 #ifdef GLX_USE_TLS
-static const char dri_driver_format[] = "%.*s/tls/%.*s_dri.so";
+static const char dri_driver_format[] = "%.*s/tls/%s_dri.so";
 #else
-static const char dri_driver_format[] = "%.*s/%.*s_dri.so";
+static const char dri_driver_format[] = "%.*s/%s_dri.so";
 #endif
 
 static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
@@ -476,45 +476,32 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
    return ret;
 }
 
-/**
- * Called via eglInitialize(), GLX_drv->API.Initialize().
- */
+static char *
+dri2_strndup(const char *s, int length)
+{
+   char *d;
+
+   d = malloc(length + 1);
+   if (d == NULL)
+      return NULL;
+
+   memcpy(d, s, length);
+   d[length] = '\0';
+
+   return d;
+}
+
 static EGLBoolean
-dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
-               EGLint *major, EGLint *minor)
+dri2_connect(struct dri2_egl_display *dri2_dpy)
 {
-   const __DRIextension **extensions;
-   const __DRIconfig **driver_configs;
-   struct dri2_egl_display *dri2_dpy;
-   char path[PATH_MAX], *search_paths, *p, *next, *end;
    xcb_xfixes_query_version_reply_t *xfixes_query;
    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
    xcb_dri2_query_version_reply_t *dri2_query;
    xcb_dri2_query_version_cookie_t dri2_query_cookie;
    xcb_dri2_connect_reply_t *connect;
    xcb_dri2_connect_cookie_t connect_cookie;
-   xcb_dri2_authenticate_reply_t *authenticate;
-   xcb_dri2_authenticate_cookie_t authenticate_cookie;
    xcb_generic_error_t *error;
-   drm_magic_t magic;
    xcb_screen_iterator_t s;
-   xcb_depth_iterator_t d;
-   xcb_visualtype_t *visuals;
-   int i, j, id;
-
-   dri2_dpy = malloc(sizeof *dri2_dpy);
-   if (!dri2_dpy)
-      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
-
-   disp->DriverData = (void *) dri2_dpy;
-   if (disp->NativeDisplay != NULL)
-      dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
-   else
-      dri2_dpy->conn = xcb_connect(0, 0);
-   if (!dri2_dpy->conn) {
-      _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
-      goto cleanup_dpy;
-   }
 
    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);
    xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id);
@@ -539,7 +526,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
        error != NULL || xfixes_query->major_version < 2) {
       _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version");
       free(error);
-      goto cleanup_conn;
+      return EGL_FALSE;
    }
    free(xfixes_query);
 
@@ -548,7 +535,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (dri2_query == NULL || error != NULL) {
       _eglLog(_EGL_FATAL, "DRI2: failed to query version");
       free(error);
-      goto cleanup_conn;
+      return EGL_FALSE;
    }
    dri2_dpy->dri2_major = dri2_query->major_version;
    dri2_dpy->dri2_minor = dri2_query->minor_version;
@@ -558,7 +545,126 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (connect == NULL ||
        connect->driver_name_length + connect->device_name_length == 0) {
       _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
-      goto cleanup_connect;
+      return EGL_FALSE;
+   }
+
+   dri2_dpy->device_name =
+      dri2_strndup(xcb_dri2_connect_device_name (connect),
+                  xcb_dri2_connect_device_name_length (connect));
+                  
+   dri2_dpy->driver_name =
+      dri2_strndup(xcb_dri2_connect_driver_name (connect),
+                  xcb_dri2_connect_driver_name_length (connect));
+
+   if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) {
+      free(dri2_dpy->device_name);
+      free(dri2_dpy->driver_name);
+      free(connect);
+      return EGL_FALSE;
+   }
+   free(connect);
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_authenticate(struct dri2_egl_display *dri2_dpy)
+{
+   xcb_dri2_authenticate_reply_t *authenticate;
+   xcb_dri2_authenticate_cookie_t authenticate_cookie;
+   xcb_screen_iterator_t s;
+   drm_magic_t magic;
+
+   if (drmGetMagic(dri2_dpy->fd, &magic)) {
+      _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
+      return EGL_FALSE;
+   }
+
+   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+   authenticate_cookie =
+      xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, magic);
+   authenticate =
+      xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
+   if (authenticate == NULL || !authenticate->authenticated) {
+      _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
+      free(authenticate);
+      return EGL_FALSE;
+   }
+
+   free(authenticate);
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
+                            _EGLDisplay *disp)
+{
+   xcb_screen_iterator_t s;
+   xcb_depth_iterator_t d;
+   xcb_visualtype_t *visuals;
+   int i, j, id;
+
+   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+   d = xcb_screen_allowed_depths_iterator(s.data);
+   id = 1;
+   while (d.rem > 0) {
+      EGLBoolean class_added[6] = { 0, };
+
+      visuals = xcb_depth_visuals(d.data);
+      for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
+        if (class_added[visuals[i]._class])
+           continue;
+
+        class_added[visuals[i]._class] = EGL_TRUE;
+        for (j = 0; dri2_dpy->driver_configs[j]; j++)
+           dri2_add_config(disp, dri2_dpy->driver_configs[j],
+                           id++, d.data->depth, &visuals[i]);
+      }
+
+      xcb_depth_next(&d);      
+   }
+
+   if (!disp->NumConfigs) {
+      _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+/**
+ * Called via eglInitialize(), GLX_drv->API.Initialize().
+ */
+static EGLBoolean
+dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
+               EGLint *major, EGLint *minor)
+{
+   const __DRIextension **extensions;
+   struct dri2_egl_display *dri2_dpy;
+   char path[PATH_MAX], *search_paths, *p, *next, *end;
+
+   dri2_dpy = malloc(sizeof *dri2_dpy);
+   if (!dri2_dpy)
+      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+   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;
+      }
+   } else {
+      dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay);
+   }
+
+   if (dri2_dpy->conn == NULL)
+      goto cleanup_conn;
+
+   if (dri2_dpy->conn) {
+      if (!dri2_connect(dri2_dpy))
+        goto cleanup_conn;
    }
 
    search_paths = NULL;
@@ -577,11 +683,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
          next = end;
 
       snprintf(path, sizeof path,
-              dri_driver_format,
-              (int) (next - p), p,
-              xcb_dri2_connect_driver_name_length (connect),
-              xcb_dri2_connect_driver_name (connect));
-
+              dri_driver_format, (int) (next - p), p, dri2_dpy->driver_name);
       dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
    }
 
@@ -589,7 +691,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
       _eglLog(_EGL_FATAL,
              "DRI2: failed to open any driver (search paths %s)",
              search_paths);
-      goto cleanup_connect;
+      goto cleanup_conn;
    }
 
    _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
@@ -603,32 +705,19 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions))
       goto cleanup_driver;
 
-   snprintf(path, sizeof path, "%.*s",
-           xcb_dri2_connect_device_name_length (connect),
-           xcb_dri2_connect_device_name (connect));
-   dri2_dpy->fd = open (path, O_RDWR);
+   dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
    if (dri2_dpy->fd == -1) {
       _eglLog(_EGL_FATAL,
-             "DRI2: could not open %s (%s)", path, strerror(errno));
+             "DRI2: could not open %s (%s)", dri2_dpy->device_name,
+              strerror(errno));
       goto cleanup_driver;
    }
 
-   if (drmGetMagic(dri2_dpy->fd, &magic)) {
-      _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
-      goto cleanup_fd;
-   }
-
-   authenticate_cookie = xcb_dri2_authenticate_unchecked (dri2_dpy->conn,
-                                                         s.data->root, magic);
-   authenticate = xcb_dri2_authenticate_reply (dri2_dpy->conn,
-                                              authenticate_cookie, NULL);
-   if (authenticate == NULL || !authenticate->authenticated) {
-      _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
-      free(authenticate);
-      goto cleanup_fd;
+   if (dri2_dpy->conn) {
+      if (!dri2_authenticate(dri2_dpy))
+        goto cleanup_fd;
    }
 
-   free(authenticate);
    if (dri2_dpy->dri2_minor >= 1) {
       dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER;
       dri2_dpy->loader_extension.base.version = 3;
@@ -654,7 +743,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
 
    dri2_dpy->dri_screen =
       dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
-                                     &driver_configs, dri2_dpy);
+                                     &dri2_dpy->driver_configs, dri2_dpy);
 
    if (dri2_dpy->dri_screen == NULL) {
       _eglLog(_EGL_FATAL, "DRI2: failed to create dri screen");
@@ -665,40 +754,21 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
       goto cleanup_dri_screen;
 
-   s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
-   d = xcb_screen_allowed_depths_iterator(s.data);
-   id = 1;
-   while (d.rem > 0) {
-      EGLBoolean class_added[6] = { 0, };
-
-      visuals = xcb_depth_visuals(d.data);
-      for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
-        if (class_added[visuals[i]._class])
-           continue;
-
-        class_added[visuals[i]._class] = EGL_TRUE;
-        for (j = 0; driver_configs[j]; j++)
-           dri2_add_config(disp, driver_configs[j],
-                           id++, d.data->depth, &visuals[i]);
-
-      }
-
-      xcb_depth_next(&d);      
-   }
-
-   if (!disp->NumConfigs) {
-      _eglLog(_EGL_WARNING, "DRI2: failed to create any config");
-      goto cleanup_configs;
+   if (dri2_dpy->conn) {
+      if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
+        goto cleanup_configs;
    }
 
    disp->ClientAPIsMask = EGL_OPENGL_BIT;
    disp->Extensions.KHR_image_base = EGL_TRUE;
    disp->Extensions.KHR_image_pixmap = EGL_TRUE;
+   disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
+   disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
 
    /* we're supporting EGL 1.4 */
    *major = 1;
    *minor = 4;
-   free (connect);
+
    return EGL_TRUE;
 
  cleanup_configs:
@@ -709,8 +779,6 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    close(dri2_dpy->fd);
  cleanup_driver:
    dlclose(dri2_dpy->driver);
- cleanup_connect:
-   free(connect);
  cleanup_conn:
    if (disp->NativeDisplay == NULL)
       xcb_disconnect(dri2_dpy->conn);
@@ -809,6 +877,7 @@ static EGLBoolean
 dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
                  _EGLSurface *rsurf, _EGLContext *ctx)
 {
+   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf);
    struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf);
@@ -820,6 +889,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
    if (!_eglBindContext(&ctx, &dsurf, &rsurf))
       return EGL_FALSE;
 
+   /* flush before context switch */
+   if (ctx && dri2_drv->glFlush)
+      dri2_drv->glFlush();
+
    ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL;
    rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL;
    cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
@@ -947,10 +1020,18 @@ dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
 static EGLBoolean
 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
 {
+   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+   _EGLContext *ctx;
    xcb_dri2_copy_region_cookie_t cookie;
 
+   if (dri2_drv->glFlush) {
+      ctx = _eglGetCurrentContext();
+      if (ctx && ctx->DrawSurface == &dri2_surf->base)
+         dri2_drv->glFlush();
+   }
+
    (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
 
 #if 0
@@ -1107,9 +1188,8 @@ dri2_release_tex_image(_EGLDriver *drv,
 }
 
 static _EGLImage *
-dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
-                     _EGLContext *ctx, EGLenum target,
-                     EGLClientBuffer buffer, const EGLint *attr_list)
+dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
+                            EGLClientBuffer buffer, const EGLint *attr_list)
 {
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
@@ -1122,80 +1202,126 @@ dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
    xcb_get_geometry_cookie_t geometry_cookie;
    xcb_get_geometry_reply_t *geometry_reply;
    xcb_generic_error_t *error;
+   int stride, format;
+
+   drawable = (xcb_drawable_t) buffer;
+   xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
+   attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
+   buffers_cookie =
+      xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
+                                     drawable, 1, 1, attachments);
+   geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
+   buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
+                                              buffers_cookie, NULL);
+   buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
+   if (buffers == NULL) {
+      return NULL;
+   }
+
+   geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
+                                           geometry_cookie, &error);
+   if (geometry_reply == NULL || error != NULL) {
+      _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
+      free(error);
+      free(buffers_reply);
+   }
+
+   switch (geometry_reply->depth) {
+   case 16:
+      format = __DRI_IMAGE_FORMAT_RGB565;
+      break;
+   case 24:
+      format = __DRI_IMAGE_FORMAT_XRGB8888;
+      break;
+   case 32:
+      format = __DRI_IMAGE_FORMAT_ARGB8888;
+      break;
+   default:
+      _eglError(EGL_BAD_PARAMETER,
+               "dri2_create_image_khr: unsupported pixmap depth");
+      free(buffers_reply);
+      free(geometry_reply);
+      return NULL;
+   }
 
    dri2_img = malloc(sizeof *dri2_img);
    if (!dri2_img) {
+      free(buffers_reply);
+      free(geometry_reply);
       _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
       return EGL_NO_IMAGE_KHR;
    }
 
-   if (!_eglInitImage(&dri2_img->base, disp, attr_list))
+   if (!_eglInitImage(&dri2_img->base, disp, attr_list)) {
+      free(buffers_reply);
+      free(geometry_reply);
       return EGL_NO_IMAGE_KHR;
+   }
 
-   switch (target) {
-   case EGL_NATIVE_PIXMAP_KHR:
-      drawable = (xcb_drawable_t) buffer;
-      xcb_dri2_create_drawable (dri2_dpy->conn, drawable);
-      attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT;
-      buffers_cookie =
-        xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
-                                        drawable, 1, 1, attachments);
-      geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable);
-      buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn,
-                                                 buffers_cookie, NULL);
-      buffers = xcb_dri2_get_buffers_buffers (buffers_reply);
-      if (buffers == NULL) {
-        free(dri2_img);
-        return NULL;
-      }
+   stride = buffers[0].pitch / buffers[0].cpp;
+   dri2_img->dri_image =
+      dri2_dpy->image->createImageFromName(dri2_ctx->dri_context,
+                                          buffers_reply->width,
+                                          buffers_reply->height,
+                                          format,
+                                          buffers[0].name,
+                                          stride,
+                                          dri2_img);
 
-      geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn,
-                                              geometry_cookie, &error);
-      if (geometry_reply == NULL || error != NULL) {
-        _eglError(EGL_BAD_ALLOC, "xcb_get_geometry");
-        free(error);
-        free(dri2_img);
-        free(buffers_reply);
-      }
+   free(buffers_reply);
+   free(geometry_reply);
 
-      dri2_img->width = buffers_reply->width;
-      dri2_img->height = buffers_reply->height;
-      dri2_img->name = buffers[0].name;
-      dri2_img->pitch = buffers[0].pitch / buffers[0].cpp;
-      dri2_img->cpp = buffers[0].cpp;
-      switch (geometry_reply->depth) {
-      case 16:
-        dri2_img->format = __DRI_IMAGE_FORMAT_RGB565;
-        break;
-      case 24:
-        dri2_img->format = __DRI_IMAGE_FORMAT_XRGB8888;
-        break;
-      case 32:
-        dri2_img->format = __DRI_IMAGE_FORMAT_ARGB8888;
-        break;
-      }
-      free(buffers_reply);
-      free(geometry_reply);
-      break;
+   return &dri2_img->base;
+}
 
-   default:
+static _EGLImage *
+dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
+                                  EGLClientBuffer buffer,
+                                  const EGLint *attr_list)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+   struct dri2_egl_image *dri2_img;
+   GLuint renderbuffer = (GLuint) buffer;
+
+   if (renderbuffer == 0) {
       _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
-      free(dri2_img);
       return EGL_NO_IMAGE_KHR;
    }
 
-   dri2_img->dri_image =
-      dri2_dpy->image->createImageFromName(dri2_ctx->dri_context,
-                                          dri2_img->width,
-                                          dri2_img->height,
-                                          dri2_img->format,
-                                          dri2_img->name,
-                                          dri2_img->pitch,
-                                          dri2_img);
+   dri2_img = malloc(sizeof *dri2_img);
+   if (!dri2_img) {
+      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
+      return EGL_NO_IMAGE_KHR;
+   }
+
+   if (!_eglInitImage(&dri2_img->base, disp, attr_list))
+      return EGL_NO_IMAGE_KHR;
+
+   dri2_img->dri_image = 
+      dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
+                                                  renderbuffer,
+                                                  dri2_img);
 
    return &dri2_img->base;
 }
 
+static _EGLImage *
+dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
+                     _EGLContext *ctx, EGLenum target,
+                     EGLClientBuffer buffer, const EGLint *attr_list)
+{
+   switch (target) {
+   case EGL_NATIVE_PIXMAP_KHR:
+      return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
+   case EGL_GL_RENDERBUFFER_KHR:
+      return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
+   default:
+      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
+      return EGL_NO_IMAGE_KHR;
+   }
+}
+
 static EGLBoolean
 dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
 {
@@ -1243,5 +1369,8 @@ _eglMain(const char *args)
    dri2_drv->base.Name = "DRI2";
    dri2_drv->base.Unload = dri2_unload;
 
+   dri2_drv->glFlush =
+      (void (*)(void)) dri2_get_proc_address(&dri2_drv->base, "glFlush");
+
    return &dri2_drv->base;
 }