summaryrefslogtreecommitdiff
path: root/src/egl/drivers/dri2/platform_x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers/dri2/platform_x11.c')
-rw-r--r--src/egl/drivers/dri2/platform_x11.c292
1 files changed, 275 insertions, 17 deletions
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
index 4d72335552b..1c7c8410c0c 100644
--- a/src/egl/drivers/dri2/platform_x11.c
+++ b/src/egl/drivers/dri2/platform_x11.c
@@ -39,6 +39,137 @@
#include "egl_dri2.h"
+static void
+swrastCreateDrawable(struct dri2_egl_display * dri2_dpy,
+ struct dri2_egl_surface * dri2_surf,
+ int depth)
+{
+ uint32_t mask;
+ const uint32_t function = GXcopy;
+ uint32_t valgc[2];
+
+ /* create GC's */
+ dri2_surf->gc = xcb_generate_id(dri2_dpy->conn);
+ mask = XCB_GC_FUNCTION;
+ xcb_create_gc(dri2_dpy->conn, dri2_surf->gc, dri2_surf->drawable, mask, &function);
+
+ dri2_surf->swapgc = xcb_generate_id(dri2_dpy->conn);
+ mask = XCB_GC_FUNCTION | XCB_GC_GRAPHICS_EXPOSURES;
+ valgc[0] = function;
+ valgc[1] = False;
+ xcb_create_gc(dri2_dpy->conn, dri2_surf->swapgc, dri2_surf->drawable, mask, valgc);
+ dri2_surf->depth = depth;
+ switch (depth) {
+ case 32:
+ case 24:
+ dri2_surf->bytes_per_pixel = 4;
+ break;
+ case 16:
+ dri2_surf->bytes_per_pixel = 2;
+ break;
+ case 8:
+ dri2_surf->bytes_per_pixel = 1;
+ break;
+ case 0:
+ dri2_surf->bytes_per_pixel = 0;
+ break;
+ default:
+ _eglLog(_EGL_WARNING, "unsupported depth %d", depth);
+ }
+}
+
+static void
+swrastDestroyDrawable(struct dri2_egl_display * dri2_dpy,
+ struct dri2_egl_surface * dri2_surf)
+{
+ xcb_free_gc(dri2_dpy->conn, dri2_surf->gc);
+ xcb_free_gc(dri2_dpy->conn, dri2_surf->swapgc);
+}
+
+static void
+swrastGetDrawableInfo(__DRIdrawable * draw,
+ int *x, int *y, int *w, int *h,
+ void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
+
+ xcb_get_geometry_cookie_t cookie;
+ xcb_get_geometry_reply_t *reply;
+ xcb_generic_error_t *error;
+
+ *w = *h = 0;
+ cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
+ reply = xcb_get_geometry_reply (dri2_dpy->conn, cookie, &error);
+ if (reply == NULL)
+ return;
+
+ if (error != NULL) {
+ _eglLog(_EGL_WARNING, "error in xcb_get_geometry");
+ free(error);
+ } else {
+ *w = reply->width;
+ *h = reply->height;
+ }
+ free(reply);
+}
+
+static void
+swrastPutImage(__DRIdrawable * draw, int op,
+ int x, int y, int w, int h,
+ char *data, void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
+
+ xcb_gcontext_t gc;
+
+ switch (op) {
+ case __DRI_SWRAST_IMAGE_OP_DRAW:
+ gc = dri2_surf->gc;
+ break;
+ case __DRI_SWRAST_IMAGE_OP_SWAP:
+ gc = dri2_surf->swapgc;
+ break;
+ default:
+ return;
+ }
+
+ xcb_put_image(dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, dri2_surf->drawable,
+ gc, w, h, x, y, 0, dri2_surf->depth,
+ w*h*dri2_surf->bytes_per_pixel, (const uint8_t *)data);
+}
+
+static void
+swrastGetImage(__DRIdrawable * read,
+ int x, int y, int w, int h,
+ char *data, void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
+
+ xcb_get_image_cookie_t cookie;
+ xcb_get_image_reply_t *reply;
+ xcb_generic_error_t *error;
+
+ cookie = xcb_get_image (dri2_dpy->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ dri2_surf->drawable, x, y, w, h, ~0);
+ reply = xcb_get_image_reply (dri2_dpy->conn, cookie, &error);
+ if (reply == NULL)
+ return;
+
+ if (error != NULL) {
+ _eglLog(_EGL_WARNING, "error in xcb_get_image");
+ free(error);
+ } else {
+ uint32_t bytes = xcb_get_image_data_length(reply);
+ uint8_t *idata = xcb_get_image_data(reply);
+ memcpy(data, idata, bytes);
+ }
+ free(reply);
+}
+
+
/**
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
*/
@@ -77,18 +208,31 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
dri2_surf->drawable = window;
}
- dri2_surf->dri_drawable =
- (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
- type == EGL_WINDOW_BIT ?
- dri2_conf->dri_double_config :
- dri2_conf->dri_single_config,
- dri2_surf);
+ if (dri2_dpy->dri2) {
+ dri2_surf->dri_drawable =
+ (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
+ type == EGL_WINDOW_BIT ?
+ dri2_conf->dri_double_config :
+ dri2_conf->dri_single_config,
+ dri2_surf);
+ } else {
+ assert(dri2_dpy->swrast);
+ dri2_surf->dri_drawable =
+ (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen,
+ dri2_conf->dri_double_config,
+ dri2_surf);
+ }
+
if (dri2_surf->dri_drawable == NULL) {
_eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
goto cleanup_pixmap;
}
-
- xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
+
+ if (dri2_dpy->dri2) {
+ xcb_dri2_create_drawable (dri2_dpy->conn, dri2_surf->drawable);
+ } else {
+ swrastCreateDrawable(dri2_dpy, dri2_surf, _eglGetConfigKey(conf, EGL_DEPTH_SIZE));
+ }
if (type != EGL_PBUFFER_BIT) {
cookie = xcb_get_geometry (dri2_dpy->conn, dri2_surf->drawable);
@@ -159,7 +303,12 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
- xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
+ if (dri2_dpy->dri2) {
+ xcb_dri2_destroy_drawable (dri2_dpy->conn, dri2_surf->drawable);
+ } else {
+ assert(dri2_dpy->swrast);
+ swrastDestroyDrawable(dri2_dpy, dri2_surf);
+ }
if (surf->Type == EGL_PBUFFER_BIT)
xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
@@ -351,7 +500,7 @@ dri2_connect(struct dri2_egl_display *dri2_dpy)
xfixes_query_cookie, &error);
if (xfixes_query == NULL ||
error != NULL || xfixes_query->major_version < 2) {
- _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version");
+ _eglLog(_EGL_WARNING, "DRI2: failed to query xfixes version");
free(error);
return EGL_FALSE;
}
@@ -360,7 +509,7 @@ dri2_connect(struct dri2_egl_display *dri2_dpy)
dri2_query =
xcb_dri2_query_version_reply (dri2_dpy->conn, dri2_query_cookie, &error);
if (dri2_query == NULL || error != NULL) {
- _eglLog(_EGL_FATAL, "DRI2: failed to query version");
+ _eglLog(_EGL_WARNING, "DRI2: failed to query version");
free(error);
return EGL_FALSE;
}
@@ -371,7 +520,7 @@ dri2_connect(struct dri2_egl_display *dri2_dpy)
connect = xcb_dri2_connect_reply (dri2_dpy->conn, connect_cookie, NULL);
if (connect == NULL ||
connect->driver_name_length + connect->device_name_length == 0) {
- _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
+ _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
return EGL_FALSE;
}
@@ -403,7 +552,7 @@ dri2_authenticate(struct dri2_egl_display *dri2_dpy)
drm_magic_t magic;
if (drmGetMagic(dri2_dpy->fd, &magic)) {
- _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic");
+ _eglLog(_EGL_WARNING, "DRI2: failed to get drm magic");
return EGL_FALSE;
}
@@ -413,7 +562,7 @@ dri2_authenticate(struct dri2_egl_display *dri2_dpy)
authenticate =
xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL);
if (authenticate == NULL || !authenticate->authenticated) {
- _eglLog(_EGL_FATAL, "DRI2: failed to authenticate");
+ _eglLog(_EGL_WARNING, "DRI2: failed to authenticate");
free(authenticate);
return EGL_FALSE;
}
@@ -525,9 +674,17 @@ dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
static EGLBoolean
dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
- return dri2_copy_region(drv, disp, draw, dri2_surf->region);
+ if (dri2_dpy->dri2) {
+ return dri2_copy_region(drv, disp, draw, dri2_surf->region);
+ } else {
+ assert(dri2_dpy->swrast);
+
+ dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
+ return EGL_TRUE;
+ }
}
static EGLBoolean
@@ -690,8 +847,88 @@ dri2_x11_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
}
}
-EGLBoolean
-dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
+static EGLBoolean
+dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy;
+
+ drv->API.CreateWindowSurface = dri2_create_window_surface;
+ drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
+ drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface;
+ drv->API.DestroySurface = dri2_destroy_surface;
+ drv->API.SwapBuffers = dri2_swap_buffers;
+ drv->API.CopyBuffers = dri2_copy_buffers;
+
+ drv->API.SwapBuffersRegionNOK = NULL;
+ drv->API.CreateImageKHR = NULL;
+ drv->API.DestroyImageKHR = NULL;
+ drv->API.CreateDRMImageMESA = NULL;
+ drv->API.ExportDRMImageMESA = NULL;
+
+ dri2_dpy = malloc(sizeof *dri2_dpy);
+ if (!dri2_dpy)
+ return _eglError(EGL_BAD_ALLOC, "eglInitialize");
+
+ memset(dri2_dpy, 0, sizeof *dri2_dpy);
+
+ disp->DriverData = (void *) dri2_dpy;
+ if (disp->PlatformDisplay == NULL) {
+ dri2_dpy->conn = xcb_connect(0, 0);
+ } else {
+ dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay);
+ }
+
+ if (xcb_connection_has_error(dri2_dpy->conn)) {
+ _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed");
+ goto cleanup_dpy;
+ }
+
+ dri2_dpy->driver_name = dri2_strndup("swrast", strlen("swrast"));
+
+ if (!dri2_load_driver(disp))
+ goto cleanup_conn;
+
+ dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER;
+ dri2_dpy->swrast_loader_extension.base.version = __DRI_SWRAST_LOADER_VERSION;
+ dri2_dpy->swrast_loader_extension.getDrawableInfo = swrastGetDrawableInfo;
+ dri2_dpy->swrast_loader_extension.putImage = swrastPutImage;
+ dri2_dpy->swrast_loader_extension.getImage = swrastGetImage;
+
+ dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base;
+ dri2_dpy->extensions[1] = NULL;
+ dri2_dpy->extensions[2] = NULL;
+
+ if (!dri2_create_screen(disp))
+ goto cleanup_driver;
+
+ if (dri2_dpy->conn) {
+ if (!dri2_add_configs_for_visuals(dri2_dpy, disp))
+ goto cleanup_configs;
+ }
+
+ /* we're supporting EGL 1.4 */
+ disp->VersionMajor = 1;
+ disp->VersionMinor = 4;
+
+ return EGL_TRUE;
+
+ cleanup_configs:
+ _eglCleanupDisplay(disp);
+ dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
+ cleanup_driver:
+ dlclose(dri2_dpy->driver);
+ cleanup_conn:
+ if (disp->PlatformDisplay == NULL)
+ xcb_disconnect(dri2_dpy->conn);
+ cleanup_dpy:
+ free(dri2_dpy);
+
+ return EGL_FALSE;
+}
+
+
+static EGLBoolean
+dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy;
@@ -708,6 +945,8 @@ dri2_initialize_x11(_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->PlatformDisplay == NULL) {
dri2_dpy->conn = xcb_connect(0, 0);
@@ -797,3 +1036,22 @@ dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
return EGL_FALSE;
}
+
+EGLBoolean
+dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp)
+{
+ EGLBoolean initialized = EGL_TRUE;
+
+ int x11_dri2_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
+
+ if (x11_dri2_accel) {
+ if (!dri2_initialize_x11_dri2(drv, disp)) {
+ initialized = dri2_initialize_x11_swrast(drv, disp);
+ }
+ } else {
+ initialized = dri2_initialize_x11_swrast(drv, disp);
+ }
+
+ return initialized;
+}
+