egl_dri2: Implement EGL_KHR_image and EGL_KHR_image_pixmap
authorKristian Høgsberg <krh@bitplanet.net>
Fri, 12 Feb 2010 00:28:26 +0000 (19:28 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 24 Feb 2010 19:28:42 +0000 (14:28 -0500)
src/egl/drivers/dri2/egl_dri2.c

index 5d36c49b2c9ff2c910716f42e3aa79890d3624a9..0c2dfe6dd43ca32aaac1e9f2645afd4fbf477add 100644 (file)
@@ -42,7 +42,6 @@
 #include <X11/Xlib-xcb.h>
 
 #include <glapi/glapi.h>
-#include "eglconfigutil.h"
 #include "eglconfig.h"
 #include "eglcontext.h"
 #include "egldisplay.h"
@@ -50,6 +49,7 @@
 #include "eglcurrent.h"
 #include "egllog.h"
 #include "eglsurface.h"
+#include "eglimage.h"
 
 struct dri2_egl_driver
 {
@@ -67,10 +67,12 @@ struct dri2_egl_display
    __DRIdri2Extension       *dri2;
    __DRI2flushExtension     *flush;
    __DRItexBufferExtension  *tex_buffer;
+   __DRIimageExtension      *image;
    int                       fd;
 
    __DRIdri2LoaderExtension  loader_extension;
-   const __DRIextension     *extensions[2];
+   __DRIimageLookupExtension image_lookup_extension;
+   const __DRIextension     *extensions[3];
 };
 
 struct dri2_egl_context
@@ -93,12 +95,25 @@ struct dri2_egl_surface
 
 struct dri2_egl_config
 {
-   _EGLConfig base;
+   _EGLConfig         base;
    const __DRIconfig *dri_config;
 };
 
+struct dri2_egl_image
+{
+   _EGLImage   base;
+   __DRIimage *dri_image;
+   int         width;
+   int         height;
+   int         name;
+   int         pitch;
+   int         cpp;
+   int         format;
+};
+
 /* standard typecasts */
 _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl)
+_EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
 
 EGLint dri2_to_egl_attribute_map[] = {
    0,
@@ -346,6 +361,25 @@ dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
 #endif
 }
 
+static __DRIimage *
+dri2_lookup_egl_image(__DRIcontext *context, void *image, void *data)
+{
+   struct dri2_egl_context *dri2_ctx = data;
+   _EGLDisplay *disp = dri2_ctx->base.Resource.Display;
+   struct dri2_egl_image *dri2_img;
+   _EGLImage *img;
+
+   img = _eglLookupImage(image, disp);
+   if (img == NULL) {
+      _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
+      return NULL;
+   }
+
+   dri2_img = dri2_egl_image(image);
+
+   return dri2_img->dri_image;
+}
+
 static __DRIbuffer *
 dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
                             int *width, int *height,
@@ -405,6 +439,7 @@ static struct dri2_extension_match dri2_driver_extensions[] = {
 static struct dri2_extension_match dri2_core_extensions[] = {
    { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
    { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
+   { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
    { NULL }
 };
 
@@ -609,8 +644,13 @@ 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] = NULL;
+   dri2_dpy->extensions[1] = &dri2_dpy->image_lookup_extension.base;
+   dri2_dpy->extensions[2] = NULL;
 
    dri2_dpy->dri_screen =
       dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
@@ -652,6 +692,8 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
    }
 
    disp->ClientAPIsMask = EGL_OPENGL_BIT;
+   disp->Extensions.KHR_image_base = EGL_TRUE;
+   disp->Extensions.KHR_image_pixmap = EGL_TRUE;
 
    /* we're supporting EGL 1.4 */
    *major = 1;
@@ -1064,6 +1106,107 @@ dri2_release_tex_image(_EGLDriver *drv,
    return EGL_TRUE;
 }
 
+static _EGLImage *
+dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
+                     _EGLContext *ctx, EGLenum target,
+                     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;
+   unsigned int attachments[1];
+   xcb_drawable_t drawable;
+   xcb_dri2_get_buffers_cookie_t buffers_cookie;
+   xcb_dri2_get_buffers_reply_t *buffers_reply;
+   xcb_dri2_dri2_buffer_t *buffers;
+   xcb_get_geometry_cookie_t geometry_cookie;
+   xcb_get_geometry_reply_t *geometry_reply;
+   xcb_generic_error_t *error;
+
+   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;
+
+   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;
+      }
+
+      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);
+      }
+
+      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;
+
+   default:
+      _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);
+
+   return &dri2_img->base;
+}
+
+static EGLBoolean
+dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_image *dri2_img = dri2_egl_image(image);
+
+   dri2_dpy->image->destroyImage(dri2_img->dri_image);
+   free(dri2_img);
+
+   return EGL_TRUE;
+}
 
 /**
  * This is the main entrypoint into the driver, called by libEGL.
@@ -1094,6 +1237,8 @@ _eglMain(const char *args)
    dri2_drv->base.API.CopyBuffers = dri2_copy_buffers;
    dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
    dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
+   dri2_drv->base.API.CreateImageKHR = dri2_create_image_khr;
+   dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
 
    dri2_drv->base.Name = "DRI2";
    dri2_drv->base.Unload = dri2_unload;