diff options
Diffstat (limited to 'dri.c')
-rw-r--r-- | dri.c | 319 |
1 files changed, 319 insertions, 0 deletions
@@ -0,0 +1,319 @@ +/* + * Copyright 2017 Advanced Micro Devices. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* This file implements a minigbm driver based on loading a driver .so + * that uses the DRI interface as implemented in Mesa. + * + * TODO: + * - this is currently setup as a kind of library / base class which allows + * specialization by the caller; can we get rid of that? + * - lots of TODOs throughout the code, e.g. incomplete format support + */ + +#include "dri.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include <dlfcn.h> +#include <sys/mman.h> + +#include "drv_priv.h" +#include "gbm.h" +#include "helpers.h" +#include "util.h" + +// clang-format off + +struct dri_bo_priv { + __DRIimage *image; +}; + +static bool lookup_extension(const __DRIextension * const *extensions, + const char *name, int min_version, + const __DRIextension **dst) +{ + while (*extensions) { + if ((*extensions)->name && + !strcmp((*extensions)->name, name) && + (*extensions)->version >= min_version) { + *dst = *extensions; + return true; + } + } + + return false; +} + +static const struct { + uint32_t gbm_format; + int dri_image_format; +} gbm_to_dri_image_formats[] = { + { GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8 }, + { GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88 }, + { GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565 }, + { GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888 }, + { GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888 }, + { GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888 }, + { GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888 }, + { GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010 }, + { GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010 }, +}; + +static int +gbm_format_to_dri_format(uint32_t gbm_format) +{ + for (unsigned i = 0; i < ARRAY_SIZE(gbm_to_dri_image_formats); i++) { + if (gbm_to_dri_image_formats[i].gbm_format == gbm_format) + return gbm_to_dri_image_formats[i].dri_image_format; + } + + return 0; +} + +/** + * The caller is responsible for setting drv->priv to a structure that derives + * from dri_driver_priv. + * + * TODO: + * - should this handle the drv_{add,modify}_combination calls? + */ +int dri_init(struct driver *drv, const char *dri_so_path, const char *driver_suffix) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)drv->priv; + if (!dri) + return -1; + + dri->driver_handle = dlopen(dri_so_path, RTLD_NOW | RTLD_GLOBAL); + if (!dri->driver_handle) + return -1; + + const __DRIextension **(*get_extensions)(); + char fname[128]; + + snprintf(fname, sizeof(fname), __DRI_DRIVER_GET_EXTENSIONS "_%s", driver_suffix); + + get_extensions = dlsym(dri->driver_handle, fname); + if (!get_extensions) + goto fail; + + dri->extensions = get_extensions(); + if (!dri->extensions) + goto fail; + + if (!lookup_extension(dri->extensions, __DRI_CORE, 2, + (const __DRIextension **)&dri->core_extension)) + goto fail; + + /* Version 4 for createNewScreen2 */ + if (!lookup_extension(dri->extensions, __DRI_DRI2, 4, + (const __DRIextension **)&dri->dri2_extension)) + goto fail; + + /* Version 13 for __DRI_IMAGE_ATTRIB_OFFSET */ + if (!lookup_extension(dri->extensions, __DRI_IMAGE, 12, + (const __DRIextension **)&dri->image_extension)) + goto fail; + + static const __DRIextension * empty_extensions[] = { NULL }; + + dri->device = dri->dri2_extension->createNewScreen2( + 0, /* screen -- unused X-ism */ + drv_get_fd(drv), + empty_extensions, /* loader (i.e., our) extensions */ + dri->extensions, + &dri->configs, + NULL); /* loader private */ + if (!dri->device) + goto fail; + + return 0; + +fail: + dlclose(dri->driver_handle); + dri->driver_handle = NULL; + return -1; +} + +/** + * The caller is responsible for freeing drv->priv. + */ +void dri_close(struct driver *drv) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)drv->priv; + + if (dri->context) + dri->core_extension->destroyContext(dri->context); + + dri->core_extension->destroyScreen(dri->device); + dlclose(dri->driver_handle); +} + +int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, + uint64_t use_flags) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)bo->drv->priv; + struct dri_bo_priv *bo_dri; + + assert(!bo->priv); + + bo_dri = (struct dri_bo_priv *)calloc(1, sizeof(*bo_dri)); + if (!bo_dri) + return -1; + + int dri_format = gbm_format_to_dri_format(format); + unsigned dri_use = 0; + + if (use_flags & GBM_BO_USE_SCANOUT) + dri_use |= __DRI_IMAGE_USE_SCANOUT; + if (use_flags & GBM_BO_USE_CURSOR) + dri_use |= __DRI_IMAGE_USE_CURSOR; + if (use_flags & 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; + + bo_dri->image = dri->image_extension->createImage( + dri->device, + width, height, dri_format, dri_use, + NULL); /* loaderPrivate */ + if (!bo_dri->image) + goto fail; + + assert(bo->num_planes == 1); /* TODO: implement */ + + if (!dri->image_extension->queryImage( + bo_dri->image, + __DRI_IMAGE_ATTRIB_HANDLE, + &bo->handles[0].s32)) + goto fail_free; + if (!dri->image_extension->queryImage( + bo_dri->image, + __DRI_IMAGE_ATTRIB_STRIDE, + (int *)&bo->strides[0])) + goto fail_free; + if (!dri->image_extension->queryImage( + bo_dri->image, + __DRI_IMAGE_ATTRIB_OFFSET, + (int *)&bo->offsets[0])) + goto fail_free; + + bo->sizes[0] = 42; /* TODO */ + bo->total_size = bo->sizes[0]; + + bo->priv = bo_dri; + return 0; + +fail_free: + dri->image_extension->destroyImage(bo_dri->image); +fail: + free(bo_dri); + return -1; +} + +int dri_bo_import(struct bo *bo, struct drv_import_fd_data *data) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)bo->drv->priv; + struct dri_bo_priv *bo_dri; + + assert(!bo->priv); + + bo_dri = (struct dri_bo_priv *)calloc(1, sizeof(*bo_dri)); + if (!bo_dri) + return -1; + + bo_dri->image = dri->image_extension->createImageFromFds( + dri->device, + data->width, data->height, data->format, + data->fds, bo->num_planes, + (int*)data->strides, (int*)data->offsets, + NULL); /* loaderPrivate */ + if (!bo_dri->image) + goto fail; + + assert(bo->num_planes == 1); /* TODO: implement */ + + if (!dri->image_extension->queryImage( + bo_dri->image, + __DRI_IMAGE_ATTRIB_HANDLE, + &bo->handles[0].s32)) + goto fail_free; + + bo->priv = bo_dri; + return 0; + +fail_free: + dri->image_extension->destroyImage(bo_dri->image); +fail: + free(bo_dri); + return -1; +} + +int dri_bo_destroy(struct bo *bo) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)bo->drv->priv; + struct dri_bo_priv *bo_dri = (struct dri_bo_priv *)bo->priv; + + dri->image_extension->destroyImage(bo_dri->image); + free(bo_dri); + + return 0; +} + +/** + * Map an image plane. + * + * This relies on the underlying driver to do a decompressing and/or de-tiling + * blit if necessary, + * + * This function itself is not thread-safe; we rely on the fact that the caller + * locks a per-driver mutex. + */ +void *dri_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)bo->drv->priv; + struct dri_bo_priv *bo_dri = (struct dri_bo_priv *)bo->priv; + + if (!dri->context) { + dri->context = dri->dri2_extension->createNewContext( + dri->device, + NULL, /* config */ + NULL, /* shared */ + NULL); /* loaderPrivate */ + if (!dri->context) + return MAP_FAILED; + } + + assert(plane == 0); /* TODO */ + + void *addr; + int stride; + + addr = dri->image_extension->mapImage( + dri->context, bo_dri->image, + 0, 0, bo->width, bo->height, /* rectangle to map */ + map_flags, /* GBM flags and DRI flags are the same */ + &stride, &vma->priv); + if (!addr) + return MAP_FAILED; + + assert((uint32_t)stride == bo->strides[plane]); + + return addr; +} + +int dri_bo_unmap(struct bo *bo, struct vma *vma) +{ + struct dri_driver_priv *dri = (struct dri_driver_priv *)bo->drv->priv; + struct dri_bo_priv *bo_dri = (struct dri_bo_priv *)bo->priv; + + dri->image_extension->unmapImage(dri->context, bo_dri->image, vma->priv); + + return 0; +} |