summaryrefslogtreecommitdiff
path: root/dri.c
diff options
context:
space:
mode:
Diffstat (limited to 'dri.c')
-rw-r--r--dri.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/dri.c b/dri.c
new file mode 100644
index 0000000..48bab92
--- /dev/null
+++ b/dri.c
@@ -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;
+}