diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-05-05 18:25:19 +0200 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-05-16 10:46:52 +0200 |
commit | 8633ac0279f9272f81aa99524aa078ca14e3da1e (patch) | |
tree | 1f1e0053a0c5a4372dbfc5ff01ec8e8869e13f60 /src/gbm/backends/dri/gbm_dri.c | |
parent | cf40dc16fc449e7611d88cac18286261c50a683d (diff) |
wip
Diffstat (limited to 'src/gbm/backends/dri/gbm_dri.c')
-rw-r--r-- | src/gbm/backends/dri/gbm_dri.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c new file mode 100644 index 0000000000..a2dd28c013 --- /dev/null +++ b/src/gbm/backends/dri/gbm_dri.c @@ -0,0 +1,378 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> + +#include <sys/types.h> +#include <unistd.h> +#include <dlfcn.h> + +#include <GL/gl.h> /* dri_interface needs GL types */ +#include <GL/internal/dri_interface.h> + +#include "util/u_drm_screen.h" + +#include "dri_internal.h" + +#include "internal.h" + +static __DRIimage * +dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data) +{ + struct gbm_dri_device *dri = data; + + return dri->lookup_image(screen, image, dri->lookup_user_data); +} + +const __DRIuseInvalidateExtension use_invalidate = { + { __DRI_USE_INVALIDATE, 1 } +}; + +const __DRIimageLookupExtension image_lookup_extension = { + { __DRI_IMAGE_LOOKUP, 1 }, + dri_lookup_egl_image +}; + +struct dri_extension_match { + const char *name; + int version; + int offset; +}; + +static struct dri_extension_match dri_core_extensions[] = { + { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) }, + { NULL, 0, 0 } +}; + +static struct dri_extension_match gbm_dri_device_extensions[] = { + { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) }, + { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) }, + { NULL, 0, 0 } +}; + +static int +dri_bind_extensions(struct gbm_dri_device *dri, + struct dri_extension_match *matches, + const __DRIextension **extensions) +{ + int i, j, ret = 0; + void *field; + + for (i = 0; extensions[i]; i++) { + for (j = 0; matches[j].name; j++) { + if (strcmp(extensions[i]->name, matches[j].name) == 0 && + extensions[i]->version >= matches[j].version) { + field = ((char *) dri + matches[j].offset); + *(const __DRIextension **) field = extensions[i]; + } + } + } + + for (j = 0; matches[j].name; j++) { + field = ((char *) dri + matches[j].offset); + if (*(const __DRIextension **) field == NULL) { + ret = -1; + } + } + + return ret; +} + +static int +dri_load_driver(struct gbm_dri_device *dri) +{ + const __DRIextension **extensions; + char path[PATH_MAX], *search_paths, *p, *next, *end; + + search_paths = NULL; + if (geteuid() == getuid()) { + /* don't allow setuid apps to use GBM_DRIVERS_PATH */ + search_paths = getenv("GBM_DRIVERS_PATH"); + } + if (search_paths == NULL) + search_paths = DEFAULT_DRIVER_DIR; + + dri->driver = NULL; + end = search_paths + strlen(search_paths); + for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) { + int len; + next = strchr(p, ':'); + if (next == NULL) + next = end; + + len = next - p; +#if GLX_USE_TLS + snprintf(path, sizeof path, + "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name); + dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); +#endif + if (dri->driver == NULL) { + snprintf(path, sizeof path, + "%.*s/%s_dri.so", len, p, dri->base.driver_name); + dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (dri->driver == NULL) + fprintf(stderr, "failed to open %s: %s\n", path, dlerror()); + } + } + + if (dri->driver == NULL) { + fprintf(stderr, "gbm: failed to open any driver (search paths %s)", + search_paths); + return -1; + } + + extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS); + if (extensions == NULL) { + fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror()); + dlclose(dri->driver); + return -1; + } + + + if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) { + dlclose(dri->driver); + fprintf(stderr, "failed to bind extensions\n"); + return -1; + } + + return 0; +} + +static int +dri_screen_create(struct gbm_dri_device *dri) +{ + const __DRIextension **extensions; + int ret = 0; + + dri->base.driver_name = util_drm_fd_get_screen_name(dri->base.base.fd); + printf("driver name. %s\n", dri->base.driver_name); + + ret = dri_load_driver(dri); + if (ret) { + fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name); + return ret; + }; + + dri->extensions[0] = &image_lookup_extension.base; + dri->extensions[1] = &use_invalidate.base; + dri->extensions[2] = NULL; + + if (dri->dri2 == NULL) + return -1; + + dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd, dri->extensions, + &dri->driver_configs, dri); + + extensions = dri->core->getExtensions(dri->screen); + if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) { + ret = -1; + goto free_screen; + } + + dri->lookup_image = NULL; + dri->lookup_user_data = NULL; + + return 0; + +free_screen: + dri->core->destroyScreen(dri->screen); + + return ret; +} + +static void +gbm_dri_bo_destroy(struct gbm_bo *_bo) +{ + struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); + struct gbm_dri_bo *bo = gbm_dri_bo(_bo); + + dri->image->destroyImage(bo->image); +} + + +/* FIXME: need __DRIimage::dupImage */ +static __DRIimage * +dri_reference_image(struct gbm_dri_device *dri, __DRIimage *orig, + uint32_t width, uint32_t height, uint32_t format, + void *user_data) +{ + __DRIimage *image; + int32_t name, pitch; + + dri->image->queryImage(orig, __DRI_IMAGE_ATTRIB_NAME, &name); + dri->image->queryImage(orig, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); + + image = dri->image->createImageFromName(dri->screen, width, height, + format, name, pitch / 4, user_data); + + return image; +} + +static struct gbm_bo * +gbm_dri_bo_create_from_egl_image(struct gbm_device *gbm, + void *egl_dpy, void *egl_img, + uint32_t width, uint32_t height, + enum gbm_bo_format format) +{ + struct gbm_dri_device *dri = gbm_dri_device(gbm); + struct gbm_dri_bo *bo; + int dri_format; + + bo = calloc(1, sizeof *bo); + if (bo == NULL) + return NULL; + + bo->base.base.gbm = gbm; + bo->base.base.width = width; + bo->base.base.height = height; + + switch (format) { + case GBM_BO_FORMAT_XRGB8888: + dri_format = __DRI_IMAGE_FORMAT_XRGB8888; + break; + case GBM_BO_FORMAT_ARGB8888: + dri_format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + return NULL; + } + + if (dri->lookup_image == NULL) + return NULL; + + __DRIimage *tmp = dri->lookup_image(dri->screen, egl_img, dri->lookup_user_data); + + bo->image = dri_reference_image(dri, tmp, width, height, dri_format, bo); + if (bo->image == NULL) + return NULL; + + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, + &bo->base.base.handle.s32); + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, + (int *) &bo->base.base.pitch); + + return &bo->base.base; +} + +static struct gbm_bo * +gbm_dri_bo_create(struct gbm_device *gbm, + uint32_t width, uint32_t height, + enum gbm_bo_format format, uint32_t usage) +{ + struct gbm_dri_device *dri = gbm_dri_device(gbm); + struct gbm_dri_bo *bo; + int dri_format; + unsigned dri_use = 0; + + bo = calloc(1, sizeof *bo); + if (bo == NULL) + return NULL; + + bo->base.base.gbm = gbm; + bo->base.base.width = width; + bo->base.base.height = height; + + switch (format) { + case GBM_BO_FORMAT_XRGB8888: + dri_format = __DRI_IMAGE_FORMAT_XRGB8888; + break; + case GBM_BO_FORMAT_ARGB8888: + dri_format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + return NULL; + } + + if (usage & GBM_BO_USE_SCANOUT) + dri_use |= __DRI_IMAGE_USE_SCANOUT; +#if 0 + if (usage & GBM_BO_USE_CURSOR_64X64) + dri_use = |= __DRI_IMAGE_USE_CURSOR_64X64; +#endif + + bo->image = + dri->image->createImage(dri->screen, + width, height, + dri_format, dri_use, + bo); + if (bo->image == NULL) + return NULL; + + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, + &bo->base.base.handle.s32); + dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, + (int *) &bo->base.base.pitch); + + return &bo->base.base; +} + +static void +dri_destroy(struct gbm_device *gbm) +{ + struct gbm_dri_device *dri = gbm_dri_device(gbm); + //int i; + + dri->core->destroyScreen(dri->screen); +#if 0 + for (i = 0; dri->driver_configs[i]; ++i) + free(dri->driver_configs[i]); +#endif + free(dri->driver_configs); + dlclose(dri->driver); + free(dri->base.driver_name); + + free(dri); +} + +static struct gbm_device * +dri_device_create(int fd) +{ + struct gbm_dri_device *dri; + int ret; + + dri = calloc(1, sizeof *dri); + + dri->base.base.fd = fd; + dri->base.base.bo_create = gbm_dri_bo_create; + dri->base.base.bo_create_from_egl_image = gbm_dri_bo_create_from_egl_image; + dri->base.base.bo_destroy = gbm_dri_bo_destroy; + dri->base.base.destroy = dri_destroy; + + dri->base.type = GBM_DRM_DRIVER_TYPE_DRI; + dri->base.base.name = "drm"; + + ret = dri_screen_create(dri); + if (ret) { + free(dri); + return NULL; + } + + return &dri->base.base; +} + +static int +dri_probe(int fd) +{ + char *name; + int ret = 0; + + name = util_drm_fd_get_screen_name(fd); + if (name == NULL) { + ret = -1; + } else { + free(name); + ret = 0; + } + + return ret; +} + + +GBM_EXPORT struct gbm_backend gbm_backend = { + .class_name = "drm", + .backend_name = "dri", + .probe = dri_probe, + .create_device = dri_device_create, +}; |