X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fgbm%2Fbackends%2Fdri%2Fgbm_dri.c;h=3faa19e3f19312bb7536dd54766000c0757a3b16;hp=5a0dad0fb71534faaf7545e815c7e1743ba4b56b;hb=770b06588f79abe44d4fa1128759c45d0496362e;hpb=8b45bc0ad518114bf6d585d1a9738a7e3768d5c9 diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index 5a0dad0fb71..3faa19e3f19 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -29,11 +29,13 @@ #include #include #include +#include #include +#include #include +#include #include -#include #include #include #include @@ -123,13 +125,82 @@ image_get_buffers(__DRIdrawable *driDrawable, surf->dri_private, buffer_mask, buffers); } +static void +swrast_get_drawable_info(__DRIdrawable *driDrawable, + int *x, + int *y, + int *width, + int *height, + void *loaderPrivate) +{ + struct gbm_dri_surface *surf = loaderPrivate; + + *x = 0; + *y = 0; + *width = surf->base.width; + *height = surf->base.height; +} + +static void +swrast_put_image2(__DRIdrawable *driDrawable, + int op, + int x, + int y, + int width, + int height, + int stride, + char *data, + void *loaderPrivate) +{ + struct gbm_dri_surface *surf = loaderPrivate; + struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); + + dri->swrast_put_image2(driDrawable, + op, x, y, + width, height, stride, + data, surf->dri_private); +} + +static void +swrast_put_image(__DRIdrawable *driDrawable, + int op, + int x, + int y, + int width, + int height, + char *data, + void *loaderPrivate) +{ + return swrast_put_image2(driDrawable, op, x, y, width, height, + width * 4, data, loaderPrivate); +} + +static void +swrast_get_image(__DRIdrawable *driDrawable, + int x, + int y, + int width, + int height, + char *data, + void *loaderPrivate) +{ + struct gbm_dri_surface *surf = loaderPrivate; + struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); + + dri->swrast_get_image(driDrawable, + x, y, + width, height, + data, surf->dri_private); +} + static const __DRIuseInvalidateExtension use_invalidate = { - { __DRI_USE_INVALIDATE, 1 } + .base = { __DRI_USE_INVALIDATE, 1 } }; static const __DRIimageLookupExtension image_lookup_extension = { - { __DRI_IMAGE_LOOKUP, 1 }, - dri_lookup_egl_image + .base = { __DRI_IMAGE_LOOKUP, 1 }, + + .lookupEGLImage = dri_lookup_egl_image }; static const __DRIdri2LoaderExtension dri2_loader_extension = { @@ -141,21 +212,42 @@ static const __DRIdri2LoaderExtension dri2_loader_extension = { }; static const __DRIimageLoaderExtension image_loader_extension = { - { __DRI_IMAGE_LOADER, 1 }, - image_get_buffers, - dri_flush_front_buffer, + .base = { __DRI_IMAGE_LOADER, 1 }, + + .getBuffers = image_get_buffers, + .flushFrontBuffer = dri_flush_front_buffer, }; +static const __DRIswrastLoaderExtension swrast_loader_extension = { + .base = { __DRI_SWRAST_LOADER, 2 }, + + .getDrawableInfo = swrast_get_drawable_info, + .putImage = swrast_put_image, + .getImage = swrast_get_image, + .putImage2 = swrast_put_image2 +}; + +static const __DRIextension *gbm_dri_screen_extensions[] = { + &image_lookup_extension.base, + &use_invalidate.base, + &dri2_loader_extension.base, + &image_loader_extension.base, + &swrast_loader_extension.base, + NULL, +}; struct dri_extension_match { const char *name; int version; int offset; + int optional; }; static struct dri_extension_match dri_core_extensions[] = { { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) }, { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) }, + { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), 1 }, + { __DRI2_INTEROP, 1, offsetof(struct gbm_dri_device, interop), 1 }, { NULL, 0, 0 } }; @@ -165,6 +257,12 @@ static struct dri_extension_match gbm_dri_device_extensions[] = { { NULL, 0, 0 } }; +static struct dri_extension_match gbm_swrast_device_extensions[] = { + { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), }, + { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast) }, + { NULL, 0, 0 } +}; + static int dri_bind_extensions(struct gbm_dri_device *dri, struct dri_extension_match *matches, @@ -185,7 +283,7 @@ dri_bind_extensions(struct gbm_dri_device *dri, for (j = 0; matches[j].name; j++) { field = ((char *) dri + matches[j].offset); - if (*(const __DRIextension **) field == NULL) { + if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) { ret = -1; } } @@ -193,21 +291,39 @@ dri_bind_extensions(struct gbm_dri_device *dri, return ret; } -static int -dri_load_driver(struct gbm_dri_device *dri) +static const __DRIextension ** +dri_open_driver(struct gbm_dri_device *dri) { const __DRIextension **extensions = NULL; char path[PATH_MAX], *search_paths, *p, *next, *end; char *get_extensions_name; search_paths = NULL; + /* don't allow setuid apps to use LIBGL_DRIVERS_PATH or GBM_DRIVERS_PATH */ if (geteuid() == getuid()) { - /* don't allow setuid apps to use GBM_DRIVERS_PATH */ + /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH + * is recommended over GBM_DRIVERS_PATH. + */ search_paths = getenv("GBM_DRIVERS_PATH"); + + /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set. + * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH. + */ + if (search_paths == NULL) { + search_paths = getenv("LIBGL_DRIVERS_PATH"); + } } if (search_paths == NULL) search_paths = DEFAULT_DRIVER_DIR; + /* Temporarily work around dri driver libs that need symbols in libglapi + * but don't automatically link it in. + */ + /* XXX: Library name differs on per platforms basis. Update this as + * osx/cygwin/windows/bsd gets support for GBM.. + */ + dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL); + dri->driver = NULL; end = search_paths + strlen(search_paths); for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) { @@ -230,16 +346,26 @@ dri_load_driver(struct gbm_dri_device *dri) /* not need continue to loop all paths once the driver is found */ if (dri->driver != NULL) break; + +#ifdef ANDROID + snprintf(path, sizeof path, "%.*s/gallium_dri.so", len, p); + dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (dri->driver == NULL) + sprintf("failed to open %s: %s\n", path, dlerror()); + else + break; +#endif } if (dri->driver == NULL) { - fprintf(stderr, "gbm: failed to open any driver (search paths %s)", + fprintf(stderr, "gbm: failed to open any driver (search paths %s)\n", search_paths); - return -1; + fprintf(stderr, "gbm: Last dlopen error: %s\n", dlerror()); + return NULL; } - if (asprintf(&get_extensions_name, "%s_%s", - __DRI_DRIVER_GET_EXTENSIONS, dri->base.driver_name) != -1) { + get_extensions_name = loader_get_extensions_name(dri->base.driver_name); + if (get_extensions_name) { const __DRIextension **(*get_extensions)(void); get_extensions = dlsym(dri->driver, get_extensions_name); @@ -254,26 +380,58 @@ dri_load_driver(struct gbm_dri_device *dri) if (extensions == NULL) { fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror()); dlclose(dri->driver); + } + + return extensions; +} + +static int +dri_load_driver(struct gbm_dri_device *dri) +{ + const __DRIextension **extensions; + + extensions = dri_open_driver(dri); + if (!extensions) + 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; } + dri->driver_extensions = extensions; - if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) { + return 0; +} + +static int +dri_load_driver_swrast(struct gbm_dri_device *dri) +{ + const __DRIextension **extensions; + + extensions = dri_open_driver(dri); + if (!extensions) + return -1; + + if (dri_bind_extensions(dri, gbm_swrast_device_extensions, extensions) < 0) { dlclose(dri->driver); fprintf(stderr, "failed to bind extensions\n"); return -1; } + dri->driver_extensions = extensions; + return 0; } static int -dri_screen_create(struct gbm_dri_device *dri) +dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name) { const __DRIextension **extensions; int ret = 0; - dri->base.driver_name = loader_get_driver_for_fd(dri->base.base.fd, 0); + dri->base.driver_name = driver_name; if (dri->base.driver_name == NULL) return -1; @@ -283,23 +441,19 @@ dri_screen_create(struct gbm_dri_device *dri) return ret; }; - dri->extensions[0] = &image_lookup_extension.base; - dri->extensions[1] = &use_invalidate.base; - dri->extensions[2] = &dri2_loader_extension.base; - dri->extensions[3] = &image_loader_extension.base; - dri->extensions[4] = NULL; + dri->loader_extensions = gbm_dri_screen_extensions; if (dri->dri2 == NULL) return -1; if (dri->dri2->base.version >= 4) { dri->screen = dri->dri2->createNewScreen2(0, dri->base.base.fd, - dri->extensions, + dri->loader_extensions, dri->driver_extensions, &dri->driver_configs, dri); } else { dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd, - dri->extensions, + dri->loader_extensions, &dri->driver_configs, dri); } if (dri->screen == NULL) @@ -322,6 +476,72 @@ free_screen: return ret; } +static int +dri_screen_create_swrast(struct gbm_dri_device *dri) +{ + int ret; + + dri->base.driver_name = strdup("swrast"); + if (dri->base.driver_name == NULL) + return -1; + + ret = dri_load_driver_swrast(dri); + if (ret) { + fprintf(stderr, "failed to load swrast driver\n"); + return ret; + } + + dri->loader_extensions = gbm_dri_screen_extensions; + + if (dri->swrast == NULL) + return -1; + + if (dri->swrast->base.version >= 4) { + dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions, + dri->driver_extensions, + &dri->driver_configs, dri); + } else { + dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions, + &dri->driver_configs, dri); + } + if (dri->screen == NULL) + return -1; + + dri->lookup_image = NULL; + dri->lookup_user_data = NULL; + + return 0; +} + +static int +dri_screen_create(struct gbm_dri_device *dri) +{ + char *driver_name; + + driver_name = loader_get_driver_for_fd(dri->base.base.fd); + if (!driver_name) + return -1; + + return dri_screen_create_dri2(dri, driver_name); +} + +static int +dri_screen_create_sw(struct gbm_dri_device *dri) +{ + char *driver_name; + int ret; + + driver_name = strdup("kms_swrast"); + if (!driver_name) + return -errno; + + ret = dri_screen_create_dri2(dri, driver_name); + if (ret == 0) + return ret; + + return dri_screen_create_swrast(dri); +} + static int gbm_dri_is_format_supported(struct gbm_device *gbm, uint32_t format, @@ -329,6 +549,7 @@ gbm_dri_is_format_supported(struct gbm_device *gbm, { switch (format) { case GBM_BO_FORMAT_XRGB8888: + case GBM_FORMAT_XBGR8888: case GBM_FORMAT_XRGB8888: break; case GBM_BO_FORMAT_ARGB8888: @@ -340,7 +561,7 @@ gbm_dri_is_format_supported(struct gbm_device *gbm, return 0; } - if (usage & GBM_BO_USE_CURSOR_64X64 && + if (usage & GBM_BO_USE_CURSOR && usage & GBM_BO_USE_RENDERING) return 0; @@ -352,14 +573,32 @@ gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count) { struct gbm_dri_bo *bo = gbm_dri_bo(_bo); - if (bo->image != NULL) + if (bo->image != NULL) { + errno = EINVAL; return -1; + } memcpy(bo->map, buf, count); return 0; } +static int +gbm_dri_bo_get_fd(struct gbm_bo *_bo) +{ + struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); + struct gbm_dri_bo *bo = gbm_dri_bo(_bo); + int fd; + + if (bo->image == NULL) + return -1; + + if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd)) + return -1; + + return fd; +} + static void gbm_dri_bo_destroy(struct gbm_bo *_bo) { @@ -370,7 +609,7 @@ gbm_dri_bo_destroy(struct gbm_bo *_bo) if (bo->image != NULL) { dri->image->destroyImage(bo->image); } else { - munmap(bo->map, bo->size); + gbm_dri_bo_unmap_dumb(bo); memset(&arg, 0, sizeof(arg)); arg.handle = bo->handle; drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg); @@ -394,6 +633,9 @@ gbm_dri_to_gbm_format(uint32_t dri_format) case __DRI_IMAGE_FORMAT_ARGB8888: ret = GBM_FORMAT_ARGB8888; break; + case __DRI_IMAGE_FORMAT_XBGR8888: + ret = GBM_FORMAT_XBGR8888; + break; case __DRI_IMAGE_FORMAT_ABGR8888: ret = GBM_FORMAT_ABGR8888; break; @@ -416,8 +658,10 @@ gbm_dri_bo_import(struct gbm_device *gbm, int gbm_format; /* Required for query image WIDTH & HEIGHT */ - if (dri->image->base.version < 4) + if (dri->image == NULL || dri->image->base.version < 4) { + errno = ENOSYS; return NULL; + } switch (type) { #if HAVE_WAYLAND_PLATFORM @@ -425,14 +669,18 @@ gbm_dri_bo_import(struct gbm_device *gbm, { struct wl_drm_buffer *wb; - if (!dri->wl_drm) + if (!dri->wl_drm) { + errno = EINVAL; return NULL; + } wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer); - if (!wb) + if (!wb) { + errno = EINVAL; return NULL; + } - image = wb->driver_buffer; + image = dri->image->dupImage(wb->driver_buffer, NULL); switch (wb->format) { case WL_DRM_FORMAT_XRGB8888: @@ -448,6 +696,7 @@ gbm_dri_bo_import(struct gbm_device *gbm, gbm_format = GBM_FORMAT_YUYV; break; default: + dri->image->destroyImage(image); return NULL; } break; @@ -457,34 +706,77 @@ gbm_dri_bo_import(struct gbm_device *gbm, case GBM_BO_IMPORT_EGL_IMAGE: { int dri_format; - if (dri->lookup_image == NULL) + if (dri->lookup_image == NULL) { + errno = EINVAL; return NULL; + } image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data); + image = dri->image->dupImage(image, NULL); dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format); gbm_format = gbm_dri_to_gbm_format(dri_format); - if (gbm_format == 0) + if (gbm_format == 0) { + errno = EINVAL; + dri->image->destroyImage(image); return NULL; + } + break; + } + + case GBM_BO_IMPORT_FD: + { + struct gbm_import_fd_data *fd_data = buffer; + int stride = fd_data->stride, offset = 0; + int dri_format; + + switch (fd_data->format) { + case GBM_BO_FORMAT_XRGB8888: + dri_format = GBM_FORMAT_XRGB8888; + break; + case GBM_BO_FORMAT_ARGB8888: + dri_format = GBM_FORMAT_ARGB8888; + break; + default: + dri_format = fd_data->format; + } + + image = dri->image->createImageFromFds(dri->screen, + fd_data->width, + fd_data->height, + dri_format, + &fd_data->fd, 1, + &stride, &offset, + NULL); + if (image == NULL) { + errno = EINVAL; + return NULL; + } + gbm_format = fd_data->format; break; } default: + errno = ENOSYS; return NULL; } bo = calloc(1, sizeof *bo); - if (bo == NULL) + if (bo == NULL) { + dri->image->destroyImage(image); return NULL; + } - bo->image = dri->image->dupImage(image, NULL); + bo->image = image; if (usage & GBM_BO_USE_SCANOUT) dri_use |= __DRI_IMAGE_USE_SCANOUT; - if (usage & GBM_BO_USE_CURSOR_64X64) + if (usage & GBM_BO_USE_CURSOR) dri_use |= __DRI_IMAGE_USE_CURSOR; if (dri->image->base.version >= 2 && !dri->image->validateUsage(bo->image, dri_use)) { + errno = EINVAL; + dri->image->destroyImage(bo->image); free(bo); return NULL; } @@ -504,6 +796,31 @@ gbm_dri_bo_import(struct gbm_device *gbm, return &bo->base.base; } +static bool +is_planar_format(uint32_t format) +{ + switch (format) { + case GBM_FORMAT_NV12: + case GBM_FORMAT_NV21: + case GBM_FORMAT_NV16: + case GBM_FORMAT_NV61: + case GBM_FORMAT_YUV410: + case GBM_FORMAT_YVU410: + case GBM_FORMAT_YUV411: + case GBM_FORMAT_YVU411: + case GBM_FORMAT_YUV420: + case GBM_FORMAT_YVU420: + case GBM_FORMAT_YUV422: + case GBM_FORMAT_YVU422: + case GBM_FORMAT_YUV444: + case GBM_FORMAT_YVU444: + return true; + default: + return false; + } + +} + static struct gbm_bo * create_dumb(struct gbm_device *gbm, uint32_t width, uint32_t height, @@ -511,20 +828,30 @@ create_dumb(struct gbm_device *gbm, { struct gbm_dri_device *dri = gbm_dri_device(gbm); struct drm_mode_create_dumb create_arg; - struct drm_mode_map_dumb map_arg; struct gbm_dri_bo *bo; struct drm_mode_destroy_dumb destroy_arg; int ret; - - if (!(usage & GBM_BO_USE_CURSOR_64X64)) + int is_cursor, is_scanout; + + is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 && + format == GBM_FORMAT_ARGB8888; + is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 && + format == GBM_FORMAT_XRGB8888; + if (!is_cursor && !is_scanout) { + errno = EINVAL; return NULL; - if (format != GBM_FORMAT_ARGB8888) + } + + if (is_planar_format(format)) { + errno = EINVAL; return NULL; + } bo = calloc(1, sizeof *bo); if (bo == NULL) return NULL; + memset(&create_arg, 0, sizeof(create_arg)); create_arg.bpp = 32; create_arg.width = width; create_arg.height = height; @@ -542,16 +869,7 @@ create_dumb(struct gbm_device *gbm, bo->handle = create_arg.handle; bo->size = create_arg.size; - memset(&map_arg, 0, sizeof(map_arg)); - map_arg.handle = bo->handle; - - ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg); - if (ret) - goto destroy_dumb; - - bo->map = mmap(0, bo->size, PROT_WRITE, - MAP_SHARED, dri->base.base.fd, map_arg.offset); - if (bo->map == MAP_FAILED) + if (gbm_dri_bo_map_dumb(bo) == NULL) goto destroy_dumb; return &bo->base.base; @@ -576,7 +894,7 @@ gbm_dri_bo_create(struct gbm_device *gbm, int dri_format; unsigned dri_use = 0; - if (usage & GBM_BO_USE_WRITE) + if (usage & GBM_BO_USE_WRITE || dri->image == NULL) return create_dumb(gbm, width, height, format, usage); bo = calloc(1, sizeof *bo); @@ -589,8 +907,14 @@ gbm_dri_bo_create(struct gbm_device *gbm, bo->base.base.format = format; switch (format) { + case GBM_FORMAT_R8: + dri_format = __DRI_IMAGE_FORMAT_R8; + break; + case GBM_FORMAT_GR88: + dri_format = __DRI_IMAGE_FORMAT_GR88; + break; case GBM_FORMAT_RGB565: - dri_format =__DRI_IMAGE_FORMAT_RGB565; + dri_format = __DRI_IMAGE_FORMAT_RGB565; break; case GBM_FORMAT_XRGB8888: case GBM_BO_FORMAT_XRGB8888: @@ -603,6 +927,9 @@ gbm_dri_bo_create(struct gbm_device *gbm, case GBM_FORMAT_ABGR8888: dri_format = __DRI_IMAGE_FORMAT_ABGR8888; break; + case GBM_FORMAT_XBGR8888: + dri_format = __DRI_IMAGE_FORMAT_XBGR8888; + break; case GBM_FORMAT_ARGB2101010: dri_format = __DRI_IMAGE_FORMAT_ARGB2101010; break; @@ -610,13 +937,16 @@ gbm_dri_bo_create(struct gbm_device *gbm, dri_format = __DRI_IMAGE_FORMAT_XRGB2101010; break; default: - return NULL; + errno = EINVAL; + goto failed; } if (usage & GBM_BO_USE_SCANOUT) dri_use |= __DRI_IMAGE_USE_SCANOUT; - if (usage & GBM_BO_USE_CURSOR_64X64) + if (usage & GBM_BO_USE_CURSOR) dri_use |= __DRI_IMAGE_USE_CURSOR; + if (usage & GBM_BO_USE_LINEAR) + dri_use |= __DRI_IMAGE_USE_LINEAR; /* Gallium drivers requires shared in order to get the handle/stride */ dri_use |= __DRI_IMAGE_USE_SHARE; @@ -627,7 +957,7 @@ gbm_dri_bo_create(struct gbm_device *gbm, dri_format, dri_use, bo); if (bo->image == NULL) - return NULL; + goto failed; dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &bo->base.base.handle.s32); @@ -635,8 +965,67 @@ gbm_dri_bo_create(struct gbm_device *gbm, (int *) &bo->base.base.stride); return &bo->base.base; + +failed: + free(bo); + return NULL; } +static void * +gbm_dri_bo_map(struct gbm_bo *_bo, + uint32_t x, uint32_t y, + uint32_t width, uint32_t height, + uint32_t flags, uint32_t *stride, void **map_data) +{ + struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); + struct gbm_dri_bo *bo = gbm_dri_bo(_bo); + + /* If it's a dumb buffer, we already have a mapping */ + if (bo->map) { + *map_data = (char *)bo->map + (bo->base.base.stride * y) + (x * 4); + *stride = bo->base.base.stride; + return *map_data; + } + + if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) { + errno = ENOSYS; + return NULL; + } + + mtx_lock(&dri->mutex); + if (!dri->context) + dri->context = dri->dri2->createNewContext(dri->screen, NULL, + NULL, NULL); + assert(dri->context); + mtx_unlock(&dri->mutex); + + /* GBM flags and DRI flags are the same, so just pass them on */ + return dri->image->mapImage(dri->context, bo->image, x, y, + width, height, flags, (int *)stride, + map_data); +} + +static void +gbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data) +{ + struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); + struct gbm_dri_bo *bo = gbm_dri_bo(_bo); + + /* Check if it's a dumb buffer and check the pointer is in range */ + if (bo->map) { + assert(map_data >= bo->map); + assert(map_data < (bo->map + bo->size)); + return; + } + + if (!dri->context || !dri->image || + dri->image->base.version < 12 || !dri->image->unmapImage) + return; + + dri->image->unmapImage(dri->context, bo->image, map_data); +} + + static struct gbm_surface * gbm_dri_surface_create(struct gbm_device *gbm, uint32_t width, uint32_t height, @@ -669,8 +1058,14 @@ static void dri_destroy(struct gbm_device *gbm) { struct gbm_dri_device *dri = gbm_dri_device(gbm); + unsigned i; + + if (dri->context) + dri->core->destroyContext(dri->context); dri->core->destroyScreen(dri->screen); + for (i = 0; dri->driver_configs[i]; i++) + free((__DRIconfig *) dri->driver_configs[i]); free(dri->driver_configs); dlclose(dri->driver); free(dri->base.driver_name); @@ -682,15 +1077,20 @@ static struct gbm_device * dri_device_create(int fd) { struct gbm_dri_device *dri; - int ret; + int ret, force_sw; dri = calloc(1, sizeof *dri); + if (!dri) + return NULL; dri->base.base.fd = fd; dri->base.base.bo_create = gbm_dri_bo_create; dri->base.base.bo_import = gbm_dri_bo_import; + dri->base.base.bo_map = gbm_dri_bo_map; + dri->base.base.bo_unmap = gbm_dri_bo_unmap; dri->base.base.is_format_supported = gbm_dri_is_format_supported; dri->base.base.bo_write = gbm_dri_bo_write; + dri->base.base.bo_get_fd = gbm_dri_bo_get_fd; dri->base.base.bo_destroy = gbm_dri_bo_destroy; dri->base.base.destroy = dri_destroy; dri->base.base.surface_create = gbm_dri_surface_create; @@ -699,7 +1099,17 @@ dri_device_create(int fd) dri->base.type = GBM_DRM_DRIVER_TYPE_DRI; dri->base.base.name = "drm"; - ret = dri_screen_create(dri); + mtx_init(&dri->mutex, mtx_plain); + + force_sw = getenv("GBM_ALWAYS_SOFTWARE") != NULL; + if (!force_sw) { + ret = dri_screen_create(dri); + if (ret) + ret = dri_screen_create_sw(dri); + } else { + ret = dri_screen_create_sw(dri); + } + if (ret) goto err_dri;