summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolai Hähnle <nicolai.haehnle@amd.com>2017-11-30 19:10:28 +0100
committerNicolai Hähnle <nicolai.haehnle@amd.com>2017-11-30 19:10:43 +0100
commit232cfb3c551ceec97f9de8e3839b9953f67c0419 (patch)
tree643558f69adb8aaa0264fb7e6eee43a7dac2a82f
parent208c948d28b51f45b31b777379dfe9d30c058a9d (diff)
Proof of concept: amdgpu backend based on dri_interface
-rw-r--r--Makefile2
-rw-r--r--amdgpu.c376
-rw-r--r--dri.c319
-rw-r--r--dri.h44
4 files changed, 381 insertions, 360 deletions
diff --git a/Makefile b/Makefile
index 9050e20..a58f63b 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ CFLAGS += -std=c99 -Wall -Wsign-compare -Wpointer-arith -Wcast-qual \
-Wcast-align -D_GNU_SOURCE=1 -D_FILE_OFFSET_BITS=64
ifdef DRV_AMDGPU
- CFLAGS += $(shell $(PKG_CONFIG) --cflags libdrm_amdgpu)
+ CFLAGS += $(shell $(PKG_CONFIG) --cflags libdrm_amdgpu) -DDRV_AMDGPU
LDLIBS += -ldrm_amdgpu -ldl
endif
ifdef DRV_EXYNOS
diff --git a/amdgpu.c b/amdgpu.c
index 35a900d..dfcad22 100644
--- a/amdgpu.c
+++ b/amdgpu.c
@@ -17,56 +17,11 @@
#include "drv_priv.h"
#include "helpers.h"
#include "util.h"
-#include "ac_surface.h"
-#include "ac_gpu_info.h"
+#include "dri.h"
// clang-format off
#define DRI_PATH "/usr/lib64/dri/radeonsi_dri.so"
-typedef void* (*addr_create)(const struct radeon_info*,
- const struct amdgpu_gpu_info*,
- uint64_t*);
-
-typedef int (*addr_destroy)(void*);
-
-typedef int (*compute_surface)(void*,
- const struct radeon_info*,
- const struct ac_surf_config*,
- enum radeon_surf_mode,
- struct radeon_surf*);
-
-typedef bool (*query_gpu_info)(int, amdgpu_device_handle,
- struct radeon_info*, struct amdgpu_gpu_info*);
-
-typedef int (*read_write_tiled)(void*, struct ac_surf_config*,
- struct radeon_surf*, void*,
- uint8_t*, int);
-
-struct dri_functors {
- void *handle;
- addr_create fptr_create;
- addr_destroy fptr_destroy;
- compute_surface fptr_compute_surface;
- query_gpu_info fptr_query_gpu_info;
- read_write_tiled fptr_read_write_tiled;
-};
-
-struct drv_priv_ptr {
- struct dri_functors *dri_handle;
- void *addrlib_handle;
- enum radeon_surf_mode surf_mode;
- struct radeon_info info;
- struct ac_surf_config surf_config;
- struct radeon_surf *surf_info;
- uint64_t base_align;
-};
-
-struct bo_priv_ptr {
- void *untiled_buf_ptr;
- uint32_t ref_count;
- int prot;
-};
-
// clang-format on
const static uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
@@ -75,142 +30,15 @@ const static uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMA
const static uint32_t texture_source_formats[] = { DRM_FORMAT_GR88, DRM_FORMAT_R8, DRM_FORMAT_NV21,
DRM_FORMAT_NV12 };
-static int amdgpu_set_metadata(int fd, uint32_t handle, struct amdgpu_bo_metadata *info)
-{
- struct drm_amdgpu_gem_metadata args = { 0 };
-
- if (!info)
- return -EINVAL;
-
- args.handle = handle;
- args.op = AMDGPU_GEM_METADATA_OP_SET_METADATA;
- args.data.flags = info->flags;
- args.data.tiling_info = info->tiling_info;
-
- if (info->size_metadata > sizeof(args.data.data))
- return -EINVAL;
-
- if (info->size_metadata) {
- args.data.data_size_bytes = info->size_metadata;
- memcpy(args.data.data, info->umd_metadata, info->size_metadata);
- }
-
- return drmCommandWriteRead(fd, DRM_AMDGPU_GEM_METADATA, &args, sizeof(args));
-}
-
-static int amdgpu_addrlib_compute(struct drv_priv_ptr *drv_priv, uint32_t width, uint32_t height,
- uint32_t format, uint64_t use_flags, uint32_t *tiling_flags)
-{
- struct radeon_surf *surf_info = drv_priv->surf_info;
- memset(surf_info, 0, sizeof(struct radeon_surf));
- struct ac_surf_config surf_config;
-
- drv_priv->surf_mode = RADEON_SURF_MODE_2D;
-
- surf_config.info.width = width;
- surf_config.info.height = height;
- surf_config.info.depth = 1;
- surf_config.info.samples = 1;
- surf_config.info.levels = 1;
- surf_config.info.array_size = 1;
- surf_config.is_3d = 0;
- surf_config.is_cube = 0;
-
- surf_info->bpe = drv_stride_from_format(format, 1, 0);
-
- if (use_flags &
- (BO_USE_CURSOR | BO_USE_LINEAR | BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN)) {
- drv_priv->surf_mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
- } else if (width <= 16 || height <= 16) {
- drv_priv->surf_mode = RADEON_SURF_MODE_1D;
- }
-
- if (use_flags & BO_USE_SCANOUT)
- surf_info->flags |= RADEON_SURF_SCANOUT;
-
- drv_priv->dri_handle->fptr_compute_surface(drv_priv->addrlib_handle, &drv_priv->info,
- &surf_config, drv_priv->surf_mode, surf_info);
- drv_priv->surf_mode = surf_info->u.legacy.level[0].mode;
-
- drv_priv->surf_config = surf_config;
- *tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, 1 << (drv_priv->surf_mode - 1));
- *tiling_flags |= AMDGPU_TILING_SET(MICRO_TILE_MODE, surf_info->micro_tile_mode);
-
- *tiling_flags |= AMDGPU_TILING_SET(BANK_WIDTH, drv_log_base2(surf_info->u.legacy.bankw));
- *tiling_flags |= AMDGPU_TILING_SET(BANK_HEIGHT, drv_log_base2(surf_info->u.legacy.bankh));
- *tiling_flags |= AMDGPU_TILING_SET(TILE_SPLIT, drv_log_base2(surf_info->u.legacy.tile_split >> 6));
- *tiling_flags |= AMDGPU_TILING_SET(MACRO_TILE_ASPECT, drv_log_base2(surf_info->u.legacy.mtilea));
- *tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, surf_info->u.legacy.pipe_config);
- *tiling_flags |= AMDGPU_TILING_SET(NUM_BANKS, drv_log_base2(surf_info->u.legacy.num_banks >> 1));
-
- return 0;
-}
-
-static void *amdgpu_addrlib_init(int fd, struct dri_functors* dri_handle, struct radeon_info* info, uint64_t *base_align)
-{
- int ret;
- struct amdgpu_gpu_info gpu_info = { 0 };
- amdgpu_device_handle dev;
- uint32_t drm_major, drm_minor;
- void *addr_handle = NULL;
-
- ret = amdgpu_device_initialize(fd, &drm_major, &drm_minor, &dev);
- if (ret) {
- return NULL;
- }
- if (!dri_handle->fptr_query_gpu_info(fd, dev, info, &gpu_info)) {
- return NULL;
- }
-
- amdgpu_device_deinitialize(dev);
- addr_handle = dri_handle->fptr_create(info, &gpu_info, base_align);
- return addr_handle;
-}
-
static int amdgpu_init(struct driver *drv)
{
- void *addrlib;
- struct format_metadata metadata;
- uint64_t use_flags = BO_USE_RENDER_MASK;
- struct drv_priv_ptr* drv_priv = (struct drv_priv_ptr*) malloc (sizeof(struct drv_priv_ptr));
- drv_priv->surf_info = (struct radeon_surf*) malloc (sizeof(struct radeon_surf));
- drv_priv->dri_handle = (struct dri_functors*) malloc (sizeof(struct dri_functors));
- drv_priv->dri_handle->handle = dlopen(DRI_PATH, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
- if (!drv_priv->dri_handle->handle)
- return -1;
-
- drv_priv->dri_handle->fptr_create =
- (addr_create)dlsym(drv_priv->dri_handle->handle, "amdgpu_addr_create");
- if (!drv_priv->dri_handle->fptr_create)
- return -1;
-
- drv_priv->dri_handle->fptr_destroy =
- (addr_destroy)dlsym(drv_priv->dri_handle->handle, "amdgpu_addr_destroy");
- if (!drv_priv->dri_handle->fptr_destroy)
- return -1;
+ drv->priv = malloc(sizeof(struct dri_driver_priv));
- drv_priv->dri_handle->fptr_compute_surface =
- (compute_surface)dlsym(drv_priv->dri_handle->handle, "ac_compute_surface");
- if (!drv_priv->dri_handle->fptr_compute_surface)
+ if (dri_init(drv, DRI_PATH, "radeonsi") < 0)
return -1;
- drv_priv->dri_handle->fptr_query_gpu_info =
- (query_gpu_info)dlsym(drv_priv->dri_handle->handle, "ac_query_gpu_info");
- if (!drv_priv->dri_handle->fptr_query_gpu_info)
- return -1;
-
- drv_priv->dri_handle->fptr_read_write_tiled =
- (read_write_tiled)dlsym(drv_priv->dri_handle->handle, "ac_read_write_tiled_data");
- if (!drv_priv->dri_handle->fptr_read_write_tiled) {
- return -1;
- }
-
- addrlib = amdgpu_addrlib_init(drv_get_fd(drv), drv_priv->dri_handle, &drv_priv->info, &drv_priv->base_align);
- if (!addrlib)
- return -1;
-
- drv_priv->addrlib_handle = addrlib;
- drv->priv = drv_priv;
+ struct format_metadata metadata;
+ uint64_t use_flags = BO_USE_RENDER_MASK;
drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
&LINEAR_METADATA, BO_USE_TEXTURE_MASK);
@@ -228,7 +56,7 @@ static int amdgpu_init(struct driver *drv)
drv_modify_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, BO_USE_SCANOUT);
- metadata.tiling = RADEON_MICRO_MODE_DISPLAY << 16 | RADEON_SURF_MODE_LINEAR_ALIGNED;
+ metadata.tiling = 0xf00f; /* TODO */
metadata.priority = 2;
metadata.modifier = DRM_FORMAT_MOD_LINEAR;
@@ -239,7 +67,7 @@ static int amdgpu_init(struct driver *drv)
drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_XBGR8888, &metadata, BO_USE_SCANOUT);
- metadata.tiling = RADEON_MICRO_MODE_THIN << 16 | RADEON_SURF_MODE_LINEAR_ALIGNED;
+ metadata.tiling = 0xf00f; /* TODO */
metadata.priority = 3;
metadata.modifier = DRM_FORMAT_MOD_LINEAR;
@@ -250,7 +78,7 @@ static int amdgpu_init(struct driver *drv)
use_flags &= ~BO_USE_SW_READ_OFTEN;
use_flags &= ~BO_USE_LINEAR;
- metadata.tiling = RADEON_MICRO_MODE_DISPLAY << 16 | RADEON_SURF_MODE_2D;
+ metadata.tiling = 0xf00f; /* TODO */
metadata.priority = 4;
drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
@@ -260,7 +88,7 @@ static int amdgpu_init(struct driver *drv)
drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_XBGR8888, &metadata, BO_USE_SCANOUT);
- metadata.tiling = RADEON_MICRO_MODE_THIN << 16 | RADEON_SURF_MODE_2D;
+ metadata.tiling = 0xf00f; /* TODO */
metadata.priority = 5;
drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
@@ -271,182 +99,12 @@ static int amdgpu_init(struct driver *drv)
static void amdgpu_close(struct driver *drv)
{
- struct drv_priv_ptr* drv_priv = (struct drv_priv_ptr*)drv->priv;
- drv_priv->dri_handle->fptr_destroy(drv_priv->addrlib_handle);
- drv_priv->addrlib_handle = NULL;
- free(drv_priv->surf_info);
- drv_priv->surf_info = NULL;
- dlclose(drv_priv->dri_handle->handle);
- free(drv_priv->dri_handle);
- drv_priv->dri_handle = NULL;
- drv->priv = NULL;
-}
-
-static int amdgpu_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
- uint64_t use_flags)
-{
- struct drv_priv_ptr *drv_priv = (struct drv_priv_ptr*)bo->drv->priv;
- struct bo_priv_ptr *bo_priv = (struct bo_priv_ptr*)bo->priv;
- union drm_amdgpu_gem_create gem_create;
- struct amdgpu_bo_metadata metadata = { 0 };
- uint32_t tiling_flags = 0;
- size_t plane;
- int ret;
- struct driver* tmp_drv = bo->drv;
-
- if (bo->priv == NULL) {
- bo_priv = (struct bo_priv_ptr*) malloc (sizeof(struct bo_priv_ptr));
- bo_priv->ref_count = 0;
- bo_priv->untiled_buf_ptr = NULL;
- bo->priv = bo_priv;
- } else {
- bo_priv = (struct bo_priv_ptr*)bo->priv;
- }
-
- if (format == DRM_FORMAT_NV12 || format == DRM_FORMAT_NV21) {
- drv_bo_from_format(bo, ALIGN(width, 64), height, format);
- } else {
- if (amdgpu_addrlib_compute(drv_priv, width, height, format, use_flags,
- &tiling_flags) < 0) {
- return -EINVAL;
- }
- bo->tiling = tiling_flags;
- /* RGB has 1 plane only */
- bo->offsets[0] = drv_priv->surf_info->u.legacy.level[0].offset;
- bo->total_size = bo->sizes[0] = drv_priv->surf_info->surf_size;
-
- bo->strides[0] = drv_stride_from_format(format,
- drv_priv->surf_info->u.legacy.level[0].nblk_x,0);
- }
+ dri_close(drv);
- //FIXME:drv pointer gets changed after amdgpu_addrlib_compute call
- //store it in temp pointer
- bo->drv = tmp_drv;
-
- memset(&gem_create, 0, sizeof(gem_create));
-
- gem_create.in.bo_size = bo->total_size;
- gem_create.in.alignment = drv_priv->surf_info->surf_alignment;
-
- /* Set the placement. */
- gem_create.in.domains = AMDGPU_GEM_DOMAIN_VRAM;
- gem_create.in.domain_flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
- /* Allocate the buffer with the preferred heap. */
-
- ret = drmCommandWriteRead(drv_get_fd(bo->drv), DRM_AMDGPU_GEM_CREATE, &gem_create,
- sizeof(gem_create));
-
- if (ret < 0) {
- fprintf(stderr, "drmCommandWriteRead failed with %d\n", ret);
- return ret;
- }
-
- metadata.tiling_info = tiling_flags;
-
- for (plane = 0; plane < bo->num_planes; plane++)
- bo->handles[plane].u32 = gem_create.out.handle;
-
- ret = amdgpu_set_metadata(drv_get_fd(bo->drv), bo->handles[0].u32, &metadata);
-
- return ret;
-}
-
-static int amdgpu_gbm_bo_import(struct bo *bo, struct drv_import_fd_data *data)
-{
- struct drv_priv_ptr *drv_priv = (struct drv_priv_ptr*)bo->drv->priv;
- struct bo_priv_ptr *bo_priv = NULL;
- uint32_t width = data->width;
- uint32_t height = data->height;
- uint32_t format = data->format;
- uint32_t usage = data->use_flags;
- uint32_t tiling_flags = 0;
-
- if (bo->priv == NULL) {
- bo_priv = (struct bo_priv_ptr*) malloc (sizeof(struct bo_priv_ptr));
- bo_priv->ref_count = 0;
- bo->priv = bo_priv;
- } else {
- bo_priv = (struct bo_priv_ptr*)bo->priv;
- }
-
- if (format == DRM_FORMAT_NV12 || format == DRM_FORMAT_NV21) {
- drv_bo_from_format(bo, ALIGN(width, 64), height, format);
- } else {
- if (amdgpu_addrlib_compute(drv_priv, width, height, format, usage,
- &tiling_flags) < 0) {
- return -EINVAL;
- }
- }
- return drv_prime_bo_import(bo, data);
-}
-
-static void *amdgpu_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
-{
- int ret;
- union drm_amdgpu_gem_mmap gem_map;
- void *addr = NULL;
- int prot = drv_get_prot(map_flags);
- struct bo_priv_ptr *bo_priv = (struct bo_priv_ptr*)bo->priv;
- struct drv_priv_ptr *drv_priv = (struct drv_priv_ptr*)bo->drv->priv;
-
- memset(&gem_map, 0, sizeof(gem_map));
- gem_map.in.handle = bo->handles[plane].u32;
-
- ret = drmIoctl(bo->drv->fd, DRM_IOCTL_AMDGPU_GEM_MMAP, &gem_map);
- if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_AMDGPU_GEM_MMAP failed\n");
- return MAP_FAILED;
- }
-
- vma->length = bo->total_size;
- addr = mmap(0, bo->total_size, prot, MAP_SHARED, bo->drv->fd, gem_map.out.addr_ptr);
- if (drv_priv->surf_mode >= RADEON_SURF_MODE_2D) {
- if (bo_priv->ref_count == 0) {
- uint32_t buf_size = drv_priv->surf_info->u.legacy.level[0].nblk_x *
- drv_priv->surf_config.info.height *
- (drv_priv->surf_info->bpe);
- bo_priv->untiled_buf_ptr = malloc(buf_size);
- if (bo_priv->untiled_buf_ptr == NULL) {
- munmap(addr, vma->length);
- return NULL;
- }
- }
- bo_priv->prot = prot;
- bo_priv->ref_count++;
- drv_priv->dri_handle->fptr_read_write_tiled(drv_priv->addrlib_handle,
- &drv_priv->surf_config,
- drv_priv->surf_info, addr,
- (uint8_t*)bo_priv->untiled_buf_ptr,
- 0);
- return bo_priv->untiled_buf_ptr;
- }
- bo_priv->ref_count++;
- return addr;
+ free(drv->priv);
+ drv->priv = NULL;
}
-static int amdgpu_bo_unmap(struct bo *bo, struct vma *vma)
-{
- struct bo_priv_ptr *bo_priv = (struct bo_priv_ptr *)bo->priv;
- struct drv_priv_ptr *drv_priv = (struct drv_priv_ptr *)bo->drv->priv;
- bo_priv->ref_count--;
- if (drv_priv->surf_mode >= RADEON_SURF_MODE_2D) {
- if (bo_priv->untiled_buf_ptr != NULL) {
- if (bo_priv->prot & PROT_WRITE)
- drv_priv->dri_handle->fptr_read_write_tiled(drv_priv->addrlib_handle,
- &drv_priv->surf_config,
- drv_priv->surf_info,
- vma->addr,
- (uint8_t*)bo_priv->untiled_buf_ptr,
- 1);
- if (bo_priv->ref_count == 0) {
- free(bo_priv->untiled_buf_ptr);
- bo_priv->untiled_buf_ptr = NULL;
- }
- }
- }
- return munmap(vma->addr, vma->length);
-}
-
static uint32_t amdgpu_resolve_format(uint32_t format, uint64_t use_flags)
{
switch (format) {
@@ -467,11 +125,11 @@ const struct backend backend_amdgpu = {
.name = "amdgpu",
.init = amdgpu_init,
.close = amdgpu_close,
- .bo_create = amdgpu_bo_create,
- .bo_destroy = drv_gem_bo_destroy,
- .bo_import = amdgpu_gbm_bo_import,
- .bo_map = amdgpu_bo_map,
- .bo_unmap = amdgpu_bo_unmap,
+ .bo_create = dri_bo_create,
+ .bo_destroy = dri_bo_destroy,
+ .bo_import = dri_bo_import,
+ .bo_map = dri_bo_map,
+ .bo_unmap = dri_bo_unmap,
.resolve_format = amdgpu_resolve_format,
};
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;
+}
diff --git a/dri.h b/dri.h
new file mode 100644
index 0000000..ffdd2e8
--- /dev/null
+++ b/dri.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef MINIGBM_DRI_H
+#define MINIGBM_DRI_H
+
+// clang-format off
+
+/* for GLboolean */
+#include "GL/gl.h"
+
+#include "GL/internal/dri_interface.h"
+
+struct bo;
+struct driver;
+struct vma;
+
+struct drv_import_fd_data;
+
+struct dri_driver_priv {
+ void *driver_handle;
+ __DRIscreen *device;
+ __DRIcontext *context; /* used for map/unmap operations */
+ const __DRIextension **extensions;
+ const __DRIcoreExtension *core_extension;
+ const __DRIdri2Extension *dri2_extension;
+ const __DRIimageExtension *image_extension;
+ const __DRIconfig **configs;
+};
+
+
+int dri_init(struct driver *drv, const char *dri_so_path, const char *driver_suffix);
+void dri_close(struct driver *drv);
+int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+ uint64_t use_flags);
+int dri_bo_import(struct bo *bo, struct drv_import_fd_data *data);
+int dri_bo_destroy(struct bo *bo);
+void *dri_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags);
+int dri_bo_unmap(struct bo *bo, struct vma *vma);
+
+#endif