egl_dri2: add swrast

This enables the egl_dri2 driver to load swrast driver
for software rendering. It could be used when hardware
dri2 drivers are not available, such as in VM.

Signed-off-by: Haitao Feng <haitao.feng@intel.com>
This commit is contained in:
Haitao Feng 2011-02-16 23:05:15 -05:00 committed by Kristian Høgsberg
parent 231bf886da
commit f55d027ac2
5 changed files with 395 additions and 52 deletions

View file

@ -276,6 +276,17 @@ static struct dri2_extension_match dri2_core_extensions[] = {
{ NULL, 0, 0 }
};
static struct dri2_extension_match swrast_driver_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
{ __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
{ NULL }
};
static struct dri2_extension_match swrast_core_extensions[] = {
{ __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
{ NULL }
};
static EGLBoolean
dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
struct dri2_extension_match *matches,
@ -363,10 +374,17 @@ dri2_load_driver(_EGLDisplay *disp)
return EGL_FALSE;
}
if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) {
dlclose(dri2_dpy->driver);
return EGL_FALSE;
}
if (strcmp(dri2_dpy->driver_name, "swrast") == 0) {
if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions)) {
dlclose(dri2_dpy->driver);
return EGL_FALSE;
}
} else {
if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) {
dlclose(dri2_dpy->driver);
return EGL_FALSE;
}
}
return EGL_TRUE;
}
@ -379,9 +397,17 @@ dri2_create_screen(_EGLDisplay *disp)
unsigned int api_mask;
dri2_dpy = disp->DriverData;
dri2_dpy->dri_screen =
dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
&dri2_dpy->driver_configs, disp);
if (dri2_dpy->dri2) {
dri2_dpy->dri_screen =
dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions,
&dri2_dpy->driver_configs, disp);
} else {
assert(dri2_dpy->swrast);
dri2_dpy->dri_screen =
dri2_dpy->swrast->createNewScreen(0, dri2_dpy->extensions,
&dri2_dpy->driver_configs, disp);
}
if (dri2_dpy->dri_screen == NULL) {
_eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
@ -389,13 +415,28 @@ dri2_create_screen(_EGLDisplay *disp)
}
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) {
if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
goto cleanup_dri_screen;
} else {
assert(dri2_dpy->swrast);
if (!dri2_bind_extensions(dri2_dpy, swrast_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 = 1 << __DRI_API_OPENGL;
if (dri2_dpy->dri2) {
if (dri2_dpy->dri2->base.version >= 2)
api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
else
api_mask = 1 << __DRI_API_OPENGL;
} else {
assert(dri2_dpy->swrast);
if (dri2_dpy->swrast->base.version >= 2)
api_mask = 1 << __DRI_API_OPENGL | 1 << __DRI_API_GLES | 1 << __DRI_API_GLES2;
else
api_mask = 1 << __DRI_API_OPENGL;
}
disp->ClientAPIs = 0;
if (api_mask & (1 <<__DRI_API_OPENGL))
@ -405,10 +446,19 @@ dri2_create_screen(_EGLDisplay *disp)
if (api_mask & (1 << __DRI_API_GLES2))
disp->ClientAPIs |= EGL_OPENGL_ES2_BIT;
if (dri2_dpy->dri2->base.version >= 2) {
disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
if (dri2_dpy->dri2) {
if (dri2_dpy->dri2->base.version >= 2) {
disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
}
} else {
assert(dri2_dpy->swrast);
if (dri2_dpy->swrast->base.version >= 2) {
disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE;
disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE;
}
}
return EGL_TRUE;
@ -465,7 +515,8 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
_eglCleanupDisplay(disp);
dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
close(dri2_dpy->fd);
if (dri2_dpy->fd)
close(dri2_dpy->fd);
dlclose(dri2_dpy->driver);
if (disp->PlatformDisplay == NULL)
xcb_disconnect(dri2_dpy->conn);
@ -539,23 +590,45 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
else
dri_config = NULL;
if (dri2_dpy->dri2->base.version >= 2) {
dri2_ctx->dri_context =
dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
api,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
} else if (api == __DRI_API_OPENGL) {
dri2_ctx->dri_context =
dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
if (dri2_dpy->dri2) {
if (dri2_dpy->dri2->base.version >= 2) {
dri2_ctx->dri_context =
dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
api,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
} else if (api == __DRI_API_OPENGL) {
dri2_ctx->dri_context =
dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
} else {
/* fail */
}
} else {
/* fail */
assert(dri2_dpy->swrast);
if (dri2_dpy->swrast->base.version >= 2) {
dri2_ctx->dri_context =
dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
api,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
} else if (api == __DRI_API_OPENGL) {
dri2_ctx->dri_context =
dri2_dpy->core->createNewContext(dri2_dpy->dri_screen,
dri_config,
dri2_ctx_shared ?
dri2_ctx_shared->dri_context : NULL,
dri2_ctx);
} else {
/* fail */
}
}
if (!dri2_ctx->dri_context)

View file

@ -71,6 +71,7 @@ struct dri2_egl_display
void *driver;
__DRIcoreExtension *core;
__DRIdri2Extension *dri2;
__DRIswrastExtension *swrast;
__DRI2flushExtension *flush;
__DRItexBufferExtension *tex_buffer;
__DRIimageExtension *image;
@ -79,7 +80,8 @@ struct dri2_egl_display
char *device_name;
char *driver_name;
__DRIdri2LoaderExtension dri2_loader_extension;
__DRIdri2LoaderExtension dri2_loader_extension;
__DRIswrastLoaderExtension swrast_loader_extension;
const __DRIextension *extensions[3];
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_egl_display *wl_dpy;
@ -118,6 +120,12 @@ struct dri2_egl_surface
xcb_xfixes_region_t region;
int have_fake_front;
int swap_interval;
int depth;
int bytes_per_pixel;
xcb_gcontext_t gc;
xcb_gcontext_t swapgc;
enum dri2_surface_type type;
#ifdef HAVE_WAYLAND_PLATFORM
struct wl_egl_window *wl_win;

View file

@ -638,6 +638,8 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
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;
dri2_dpy->fd = (int) disp->PlatformDisplay;

View file

@ -599,6 +599,8 @@ dri2_initialize_wayland(_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;
dri2_dpy->wl_dpy = disp->PlatformDisplay;

View file

@ -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;
}