summaryrefslogtreecommitdiff
path: root/src/egl/drivers/dri2/egl_dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers/dri2/egl_dri2.c')
-rw-r--r--src/egl/drivers/dri2/egl_dri2.c434
1 files changed, 344 insertions, 90 deletions
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 5d36c49b2c..15b3529cd2 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -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
{
@@ -62,15 +62,21 @@ struct dri2_egl_display
int dri2_major;
int dri2_minor;
__DRIscreen *dri_screen;
+ const __DRIconfig **driver_configs;
void *driver;
__DRIcoreExtension *core;
__DRIdri2Extension *dri2;
__DRI2flushExtension *flush;
__DRItexBufferExtension *tex_buffer;
+ __DRIimageExtension *image;
int fd;
+ char *device_name;
+ char *driver_name;
+
__DRIdri2LoaderExtension loader_extension;
- const __DRIextension *extensions[2];
+ __DRIimageLookupExtension image_lookup_extension;
+ const __DRIextension *extensions[3];
};
struct dri2_egl_context
@@ -93,12 +99,19 @@ 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;
+};
+
/* 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 +359,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,
@@ -383,9 +415,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;
@@ -405,6 +437,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 }
};
@@ -441,45 +474,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);
@@ -504,7 +524,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);
@@ -513,7 +533,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;
@@ -523,7 +543,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;
@@ -542,11 +681,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);
}
@@ -554,7 +689,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);
@@ -568,32 +703,18 @@ 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));
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;
@@ -609,12 +730,17 @@ 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,
- &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");
@@ -625,38 +751,20 @@ 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;
/* we're supporting EGL 1.4 */
*major = 1;
*minor = 4;
- free (connect);
+
return EGL_TRUE;
cleanup_configs:
@@ -667,8 +775,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);
@@ -1064,6 +1170,152 @@ dri2_release_tex_image(_EGLDriver *drv,
return EGL_TRUE;
}
+static _EGLImage *
+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);
+ 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;
+ 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)) {
+ free(buffers_reply);
+ free(geometry_reply);
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ 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);
+
+ free(buffers_reply);
+ free(geometry_reply);
+
+ return &dri2_img->base;
+}
+
+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");
+ return EGL_NO_IMAGE_KHR;
+ }
+
+ 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)
+{
+ 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 +1346,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;