AM_CFLAGS = \
-D_OS_UNIX=1 \
-DMODULEDIR='"$(libdir)/gbm"' \
- -I$(top_srcdir)/src
+ -I$(top_srcdir)/src
lib_LTLIBRARIES = libgbm.la
include_HEADERS = src/gbm.h
src/backend.h \
src/gbm.c \
src/gbm.h \
- src/gbmint.h
+ src/gbmint.h \
+ src/gbm_abi_check.c \
+ src/gbm_backend_abi.h
libgbm_la_LDFLAGS = \
+ $(LDFLAGS) \
-no-undefined \
-version-info 1:0
-libgbm_la_LIBADD =
+libgbm_la_LIBADD = $(LIBGBM_LIBS)
+
+AM_CFLAGS += \
+ $(LIBGBM_CFLAGS)
libgbmincludedir=$(includedir)
libgbminclude_HEADERS = \
libgbm_la_LIBADD += \
$(TBM_LIBS)
-
endif
libgbmtbmincludedir=$(includedir)/gbm
backends/tbm/gbm_tbmint.h
-CLEANFILES =
+CLEANFILES =
tbm_surface_internal_get_plane_data(tbm_surf, 0, &size, &offset, &stride);
bo->base.gbm = gbm;
- bo->base.width = tbm_surface_get_width(tbm_surf);
- bo->base.height = tbm_surface_get_height(tbm_surf);
- bo->base.format = tbm_surface_get_format(tbm_surf);
- bo->base.stride = stride;
+ bo->base.v0.width = tbm_surface_get_width(tbm_surf);
+ bo->base.v0.height = tbm_surface_get_height(tbm_surf);
+ bo->base.v0.format = tbm_surface_get_format(tbm_surf);
+ bo->base.v0.stride = stride;
bo->usage = usage;
handle = tbm_bo_get_handle(tbo, TBM_DEVICE_DEFAULT);
- bo->base.handle.u64 = handle.u64;
+ bo->base.v0.handle.u64 = handle.u64;
return &bo->base;
}
return NULL;
bo->base.gbm = gbm;
- bo->base.width = width;
- bo->base.height = height;
- bo->base.format = format;
+ bo->base.v0.width = width;
+ bo->base.v0.height = height;
+ bo->base.v0.format = format;
bo->usage = usage;
bo->tbm_surf = tbm_surf;
return NULL;
}
- bo->base.stride = pitch;
+ bo->base.v0.stride = pitch;
tbo = tbm_surface_internal_get_bo(bo->tbm_surf, 0);
handle = tbm_bo_get_handle(tbo, TBM_DEVICE_DEFAULT);
- bo->base.handle.u64 = handle.u64;
+ bo->base.v0.handle.u64 = handle.u64;
tbm_bo_add_user_data(tbo, TBM_DATA_KEY, NULL);
tbm_bo_set_user_data(tbo, TBM_DATA_KEY, &bo->base);
return NULL;
surf->base.gbm = gbm;
- surf->base.width = width;
- surf->base.height = height;
- surf->base.format = format;
- surf->base.flags = flags;
+ surf->base.v0.width = width;
+ surf->base.v0.height = height;
+ surf->base.v0.format = format;
+ surf->base.v0.flags = flags;
if ((flags & GBM_BO_USE_SCANOUT) || (flags & GBM_BO_USE_CURSOR_64X64))
{
gbo = __gbm_tbm_bo_create_by_tbm_surface(surf->base.gbm,
tbm_surf,
- surf->base.width,
- surf->base.height,
- surf->base.format,
- surf->base.flags);
+ surf->base.v0.width,
+ surf->base.v0.height,
+ surf->base.v0.format,
+ surf->base.v0.flags);
if (gbo)
{
return gbo;
}
static struct gbm_device *
-__tbm_device_create(int fd)
+__tbm_device_create(int fd, uint32_t gbm_backend_version)
{
struct gbm_tbm_device *dri;
if (dri->bufmgr == NULL)
goto fail;
- dri->base.fd = fd;
- dri->base.bo_create = __gbm_tbm_bo_create;
- dri->base.bo_import = __gbm_tbm_bo_import;
- dri->base.is_format_supported = __gbm_tbm_is_format_supported;
- dri->base.bo_write = __gbm_tbm_bo_write;
- dri->base.bo_get_fd = __gbm_tbm_bo_get_fd;
- dri->base.bo_destroy = __gbm_tbm_bo_destroy;
- dri->base.destroy = __tbm_destroy;
- dri->base.surface_create = __gbm_tbm_surface_create;
- dri->base.surface_destroy = __gbm_tbm_surface_destroy;
- dri->base.surface_lock_front_buffer = __gbm_tbm_surface_lock_front_buffer;
- dri->base.surface_release_buffer = __gbm_tbm_surface_release_buffer;
- dri->base.surface_has_free_buffers = __gbm_tbm_surface_has_free_buffers;
- dri->base.name = "gbm_tbm";
+ dri->base.v0.fd = fd;
+ dri->base.v0.bo_create = __gbm_tbm_bo_create;
+ dri->base.v0.bo_import = __gbm_tbm_bo_import;
+ dri->base.v0.is_format_supported = __gbm_tbm_is_format_supported;
+ dri->base.v0.bo_write = __gbm_tbm_bo_write;
+ dri->base.v0.bo_get_fd = __gbm_tbm_bo_get_fd;
+ dri->base.v0.bo_destroy = __gbm_tbm_bo_destroy;
+ dri->base.v0.destroy = __tbm_destroy;
+ dri->base.v0.surface_create = __gbm_tbm_surface_create;
+ dri->base.v0.surface_destroy = __gbm_tbm_surface_destroy;
+ dri->base.v0.surface_lock_front_buffer = __gbm_tbm_surface_lock_front_buffer;
+ dri->base.v0.surface_release_buffer = __gbm_tbm_surface_release_buffer;
+ dri->base.v0.surface_has_free_buffers = __gbm_tbm_surface_has_free_buffers;
+ dri->base.v0.name = "gbm_tbm";
+ dri->base.v0.backend_version = gbm_backend_version;
return &dri->base;
}
struct gbm_backend gbm_tbm_backend = {
- .backend_name = "gbm_tbm",
- .create_device = __tbm_device_create,
+ .v0.backend_version = GBM_BACKEND_ABI_VERSION,
+ .v0.backend_name = "gbm_tbm",
+ .v0.create_device = __tbm_device_create,
};
AC_PROG_CC
AC_PROG_LIBTOOL
+PKG_CHECK_MODULES([LIBDRM], [libdrm])
+
+LIBGBM_CFLAGS="$LIBGBM_CFLAGS $LIBDRM_CFLAGS"
+LIBGBM_LIBS="$LIBGBM_LIBS $LIBDRM_LIBS"
+
AC_ARG_ENABLE(tbm, AS_HELP_STRING([--disable-tbm],
[use tbm or not (default: enabled)]),
[have_tbm=$enableval], [have_tbm=yes])
fi
fi
+AC_SUBST(LIBGBM_CFLAGS)
+AC_SUBST(LIBGBM_LIBS)
+
AM_CONDITIONAL(HAVE_TBM, test "x$have_tbm" = "xyes")
AM_CONDITIONAL(USE_TBM_QUEUE, test x$enable_tbm_queue = xyes)
BuildRequires: systemd-devel
BuildRequires: pkgconfig(libtbm)
BuildRequires: pkgconfig(wayland-tbm-server)
+BuildRequires: pkgconfig(libdrm)
%description
Wayland Generic Buffer Management for TIZEN
/*
* Copyright © 2011 Intel Corporation
+ * Copyright © 2021 NVIDIA Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
*
* Authors:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
+ * James Jones <jajones@nvidia.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <xf86drm.h>
+#ifdef USE_LOADER
+#include "loader.h"
+#endif
#include "backend.h"
#include "config.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#define VER_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#if defined(HAVE_DRI) || defined(HAVE_DRI2) || defined(HAVE_DRI3)
+extern const struct gbm_backend gbm_dri_backend;
+#endif
#if HAVE_TBM
extern const struct gbm_backend gbm_tbm_backend;
#endif
-struct backend_desc {
+struct gbm_backend_desc {
const char *name;
- const struct gbm_backend *builtin;
+ const struct gbm_backend *backend;
+ void *lib;
};
-static const struct backend_desc backends[] = {
+static const struct gbm_backend_desc builtin_backends[] = {
+#if defined(HAVE_DRI) || defined(HAVE_DRI2) || defined(HAVE_DRI3)
+ { "dri", &gbm_dri_backend },
+#endif
#if HAVE_TBM
{ "gbm_tbm.so", &gbm_tbm_backend },
#endif
};
-static const void *
-load_backend(const struct backend_desc *backend)
+#define BACKEND_LIB_SUFFIX "_gbm"
+#ifdef USE_LOADER
+static const char *backend_search_path_vars[] = {
+ "GBM_BACKENDS_PATH",
+ NULL
+};
+#endif
+
+static void
+free_backend_desc(const struct gbm_backend_desc *backend_desc)
{
- const void *init = NULL;
+ assert(backend_desc->lib);
- if (backend == NULL)
+ dlclose(backend_desc->lib);
+ free((void *)backend_desc->name);
+ free((void *)backend_desc);
+}
+
+#ifdef USE_LOADER
+static struct gbm_backend_desc *
+create_backend_desc(const char *name,
+ const struct gbm_backend *backend,
+ void *lib)
+{
+ struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc));
+
+ if (!new_desc)
return NULL;
- if (backend->builtin) {
- init = backend->builtin;
+ new_desc->name = strdup(name);
+
+ if (!new_desc->name) {
+ free(new_desc);
+ return NULL;
}
- return init;
+ new_desc->backend = backend;
+ new_desc->lib = lib;
+
+ return new_desc;
}
+#endif
-static const struct backend_desc *
-find_backend(const char *name)
+static struct gbm_device *
+backend_create_device(const struct gbm_backend_desc *bd, int fd)
{
- const struct backend_desc *backend = NULL;
- int i;
+ const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION,
+ bd->backend->v0.backend_version);
+ struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver);
- for (i = 0; i < ARRAY_SIZE(backends); ++i) {
- if (strcmp(backends[i].name, name) == 0) {
- backend = &backends[i];
- break;
+ if (dev) {
+ if (abi_ver != dev->v0.backend_version) {
+ _gbm_device_destroy(dev);
+ return NULL;
}
+ dev->v0.backend_desc = bd;
}
- return backend;
+ return dev;
}
-struct gbm_device *
-_gbm_create_device(int fd)
+#ifdef USE_LOADER
+static struct gbm_device *
+load_backend(void *lib, int fd, const char *name)
+{
+ struct gbm_device *dev = NULL;
+ struct gbm_backend_desc *backend_desc;
+ const struct gbm_backend *gbm_backend;
+ GBM_GET_BACKEND_PROC_PTR get_backend;
+
+ get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME);
+
+ if (!get_backend)
+ goto fail;
+
+ gbm_backend = get_backend(&gbm_core);
+ backend_desc = create_backend_desc(name, gbm_backend, lib);
+
+ if (!backend_desc)
+ goto fail;
+
+ dev = backend_create_device(backend_desc, fd);
+
+ if (!dev)
+ free_backend_desc(backend_desc);
+
+ return dev;
+
+fail:
+ dlclose(lib);
+ return NULL;
+}
+#endif
+
+static struct gbm_device *
+find_backend(const char *name, int fd)
+{
+ struct gbm_device *dev = NULL;
+ const struct gbm_backend_desc *bd;
+#ifdef USE_LOADER
+ void *lib;
+#endif
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) {
+ bd = &builtin_backends[i];
+
+ if (name && strcmp(bd->name, name))
+ continue;
+
+ dev = backend_create_device(bd, fd);
+
+ if (dev)
+ break;
+ }
+#ifdef USE_LOADER
+ if (name && !dev) {
+ lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX,
+ backend_search_path_vars,
+ DEFAULT_BACKENDS_PATH,
+ true);
+
+ if (lib)
+ dev = load_backend(lib, fd, name);
+ }
+#endif
+ return dev;
+}
+
+static struct gbm_device *
+override_backend(int fd)
{
- const struct gbm_backend *backend = NULL;
struct gbm_device *dev = NULL;
- int i;
const char *b;
b = getenv("GBM_BACKEND");
if (b)
- backend = load_backend(find_backend(b));
+ dev = find_backend(b, fd);
- if (backend)
- dev = backend->create_device(fd);
+ return dev;
+}
- for (i = 0; i < ARRAY_SIZE(backends) && dev == NULL; ++i) {
- backend = load_backend(&backends[i]);
- if (backend == NULL)
- continue;
+static struct gbm_device *
+backend_from_driver_name(int fd)
+{
+ struct gbm_device *dev = NULL;
+ drmVersionPtr v = drmGetVersion(fd);
+#ifdef USE_LOADER
+ void *lib;
+#endif
- dev = backend->create_device(fd);
- }
+ if (!v)
+ return NULL;
+
+#ifdef USE_LOADER
+ lib = loader_open_driver_lib(v->name, BACKEND_LIB_SUFFIX,
+ backend_search_path_vars,
+ DEFAULT_BACKENDS_PATH,
+ false);
+
+ if (lib)
+ dev = load_backend(lib, fd, v->name);
+#endif
+ drmFreeVersion(v);
+
+ return dev;
+}
+
+struct gbm_device *
+_gbm_create_device(int fd)
+{
+ struct gbm_device *dev;
+
+ dev = override_backend(fd);
+
+ if (!dev)
+ dev = backend_from_driver_name(fd);
+
+ if (!dev)
+ dev = find_backend(NULL, fd);
return dev;
}
+
+void
+_gbm_device_destroy(struct gbm_device *gbm)
+{
+ const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc;
+ gbm->v0.destroy(gbm);
+
+ if (backend_desc && backend_desc->lib)
+ free_backend_desc(backend_desc);
+}
struct gbm_device *
_gbm_create_device(int fd);
+void
+_gbm_device_destroy(struct gbm_device *gbm);
+
#endif
GBM_EXPORT int
gbm_device_get_fd(struct gbm_device *gbm)
{
- return gbm->fd;
+ return gbm->v0.fd;
}
/** Get the backend name for the given gbm device
GBM_EXPORT const char *
gbm_device_get_backend_name(struct gbm_device *gbm)
{
- return gbm->name;
+ return gbm->v0.name;
}
/** Test if a format is supported for a given set of usage flags.
*
* \param gbm The created buffer manager
* \param format The format to test
- * \param usage A bitmask of the usages to test the format against
+ * \param flags A bitmask of the usages to test the format against
* \return 1 if the format is supported otherwise 0
*
* \sa enum gbm_bo_flags for the list of flags that the format can be
*/
GBM_EXPORT int
gbm_device_is_format_supported(struct gbm_device *gbm,
- uint32_t format, uint32_t usage)
+ uint32_t format, uint32_t flags)
{
- return gbm->is_format_supported(gbm, format, usage);
+ return gbm->v0.is_format_supported(gbm, format, flags);
}
/** Get the number of planes that are required for a given format+modifier
uint32_t format,
uint64_t modifier)
{
- return gbm->get_format_modifier_plane_count(gbm, format, modifier);
+ return gbm->v0.get_format_modifier_plane_count(gbm, format, modifier);
}
/** Destroy the gbm device and free all resources associated with it.
*
+ * Prior to calling this function all buffers and surfaces created with the
+ * gbm device need to be destroyed.
+ *
* \param gbm The device created using gbm_create_device()
*/
GBM_EXPORT void
gbm_device_destroy(struct gbm_device *gbm)
{
- gbm->refcount--;
- if (gbm->refcount == 0)
- gbm->destroy(gbm);
+ _gbm_device_destroy(gbm);
}
/** Create a gbm device for allocating buffers
return NULL;
gbm->dummy = gbm_create_device;
- gbm->stat = buf;
- gbm->refcount = 1;
return gbm;
}
GBM_EXPORT uint32_t
gbm_bo_get_width(struct gbm_bo *bo)
{
- return bo->width;
+ return bo->v0.width;
}
/** Get the height of the buffer object
GBM_EXPORT uint32_t
gbm_bo_get_height(struct gbm_bo *bo)
{
- return bo->height;
+ return bo->v0.height;
}
/** Get the stride of the buffer object
GBM_EXPORT uint32_t
gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane)
{
- return bo->gbm->bo_get_stride(bo, plane);
+ return bo->gbm->v0.bo_get_stride(bo, plane);
}
/** Get the format of the buffer object
GBM_EXPORT uint32_t
gbm_bo_get_format(struct gbm_bo *bo)
{
- return bo->format;
+ return bo->v0.format;
}
/** Get the bit-per-pixel of the buffer object's format
GBM_EXPORT uint32_t
gbm_bo_get_bpp(struct gbm_bo *bo)
{
- switch (bo->format) {
+ switch (bo->v0.format) {
default:
return 0;
case GBM_FORMAT_C8:
case GBM_FORMAT_RGB332:
case GBM_FORMAT_BGR233:
return 8;
+ case GBM_FORMAT_R16:
case GBM_FORMAT_GR88:
case GBM_FORMAT_XRGB4444:
case GBM_FORMAT_XBGR4444:
case GBM_FORMAT_RGB888:
case GBM_FORMAT_BGR888:
return 24;
+ case GBM_FORMAT_RG1616:
+ case GBM_FORMAT_GR1616:
case GBM_FORMAT_XRGB8888:
case GBM_FORMAT_XBGR8888:
case GBM_FORMAT_RGBX8888:
case GBM_FORMAT_RGBA1010102:
case GBM_FORMAT_BGRA1010102:
return 32;
+ case GBM_FORMAT_XBGR16161616:
+ case GBM_FORMAT_ABGR16161616:
case GBM_FORMAT_XBGR16161616F:
case GBM_FORMAT_ABGR16161616F:
return 64;
GBM_EXPORT uint32_t
gbm_bo_get_offset(struct gbm_bo *bo, int plane)
{
- return bo->gbm->bo_get_offset(bo, plane);
+ return bo->gbm->v0.bo_get_offset(bo, plane);
}
/** Get the gbm device used to create the buffer object
GBM_EXPORT union gbm_bo_handle
gbm_bo_get_handle(struct gbm_bo *bo)
{
- return bo->handle;
+ return bo->v0.handle;
}
/** Get a DMA-BUF file descriptor for the buffer object
GBM_EXPORT int
gbm_bo_get_fd(struct gbm_bo *bo)
{
- return bo->gbm->bo_get_fd(bo);
+ return bo->gbm->v0.bo_get_fd(bo);
}
/** Get the number of planes for the given bo.
GBM_EXPORT int
gbm_bo_get_plane_count(struct gbm_bo *bo)
{
- return bo->gbm->bo_get_planes(bo);
+ return bo->gbm->v0.bo_get_planes(bo);
}
/** Get the handle for the specified plane of the buffer object
GBM_EXPORT union gbm_bo_handle
gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane)
{
- return bo->gbm->bo_get_handle(bo, plane);
+ return bo->gbm->v0.bo_get_handle(bo, plane);
+}
+
+/** Get a DMA-BUF file descriptor for the specified plane of the buffer object
+ *
+ * This function creates a DMA-BUF (also known as PRIME) file descriptor
+ * handle for the specified plane of the buffer object. Each call to
+ * gbm_bo_get_fd_for_plane() returns a new file descriptor and the caller is
+ * responsible for closing the file descriptor.
+
+ * \param bo The buffer object
+ * \param plane The plane to get a DMA-BUF for
+ * \return Returns a file descriptor referring to the underlying buffer or -1
+ * if an error occurs.
+ *
+ * \sa gbm_bo_get_fd()
+ */
+GBM_EXPORT int
+gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane)
+{
+ return bo->gbm->v0.bo_get_plane_fd(bo, plane);
}
/**
GBM_EXPORT uint64_t
gbm_bo_get_modifier(struct gbm_bo *bo)
{
- return bo->gbm->bo_get_modifier(bo);
+ return bo->gbm->v0.bo_get_modifier(bo);
}
/** Write data into the buffer object
GBM_EXPORT int
gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count)
{
- return bo->gbm->bo_write(bo, buf, count);
+ return bo->gbm->v0.bo_write(bo, buf, count);
}
/** Set the user data associated with a buffer object
gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *))
{
- bo->user_data = data;
- bo->destroy_user_data = destroy_user_data;
+ bo->v0.user_data = data;
+ bo->v0.destroy_user_data = destroy_user_data;
}
/** Get the user data associated with a buffer object
GBM_EXPORT void *
gbm_bo_get_user_data(struct gbm_bo *bo)
{
- return bo->user_data;
+ return bo->v0.user_data;
}
/**
GBM_EXPORT void
gbm_bo_destroy(struct gbm_bo *bo)
{
- if (bo->destroy_user_data)
- bo->destroy_user_data(bo, bo->user_data);
+ if (bo->v0.destroy_user_data)
+ bo->v0.destroy_user_data(bo, bo->v0.user_data);
- bo->gbm->bo_destroy(bo);
+ bo->gbm->v0.bo_destroy(bo);
}
/**
* \param height The height for the buffer
* \param format The format to use for the buffer, from GBM_FORMAT_* or
* GBM_BO_FORMAT_* tokens
- * \param usage The union of the usage flags for this buffer
+ * \param flags The union of the usage flags for this buffer
*
* \return A newly allocated buffer that should be freed with gbm_bo_destroy()
* when no longer needed. If an error occurs during allocation %NULL will be
GBM_EXPORT struct gbm_bo *
gbm_bo_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
- uint32_t format, uint32_t usage)
+ uint32_t format, uint32_t flags)
{
if (width == 0 || height == 0) {
errno = EINVAL;
return NULL;
}
- return gbm->bo_create(gbm, width, height, format, usage, NULL, 0);
+ return gbm->v0.bo_create(gbm, width, height, format, flags, NULL, 0);
}
GBM_EXPORT struct gbm_bo *
const uint64_t *modifiers,
const unsigned int count)
{
+ uint32_t flags = 0;
+
+ /*
+ * ABI version 1 added the modifiers+flags capability. Backends from
+ * prior versions may fail if "unknown" flags are provided along with
+ * modifiers, but assume scanout is required when modifiers are used.
+ * Newer backends expect scanout to be explicitly requested if required,
+ * but applications using this older interface rely on the older implied
+ * requirement, so that behavior must be preserved.
+ */
+ if (gbm->v0.backend_version >= 1) {
+ flags |= GBM_BO_USE_SCANOUT;
+ }
+
+ return gbm_bo_create_with_modifiers2(gbm, width, height, format, modifiers,
+ count, flags);
+}
+
+GBM_EXPORT struct gbm_bo *
+gbm_bo_create_with_modifiers2(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ const uint64_t *modifiers,
+ const unsigned int count,
+ uint32_t flags)
+{
if (width == 0 || height == 0) {
errno = EINVAL;
return NULL;
return NULL;
}
- return gbm->bo_create(gbm, width, height, format, 0, modifiers, count);
+ if (modifiers && (flags & GBM_BO_USE_LINEAR)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return gbm->v0.bo_create(gbm, width, height, format, flags, modifiers, count);
}
/**
* \param gbm The gbm device returned from gbm_create_device()
* \param type The type of object we're importing
* \param buffer Pointer to the external object
- * \param usage The union of the usage flags for this buffer
+ * \param flags The union of the usage flags for this buffer
*
* \return A newly allocated buffer object that should be freed with
* gbm_bo_destroy() when no longer needed. On error, %NULL is returned
*/
GBM_EXPORT struct gbm_bo *
gbm_bo_import(struct gbm_device *gbm,
- uint32_t type, void *buffer, uint32_t usage)
+ uint32_t type, void *buffer, uint32_t flags)
{
- return gbm->bo_import(gbm, type, buffer, usage);
+ return gbm->v0.bo_import(gbm, type, buffer, flags);
}
/**
return NULL;
}
- return bo->gbm->bo_map(bo, x, y, width, height,
- flags, stride, map_data);
+ return bo->gbm->v0.bo_map(bo, x, y, width, height,
+ flags, stride, map_data);
}
/**
GBM_EXPORT void
gbm_bo_unmap(struct gbm_bo *bo, void *map_data)
{
- bo->gbm->bo_unmap(bo, map_data);
+ bo->gbm->v0.bo_unmap(bo, map_data);
}
/**
uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
- return gbm->surface_create(gbm, width, height, format, flags, NULL, 0);
+ return gbm->v0.surface_create(gbm, width, height, format, flags, NULL, 0);
}
GBM_EXPORT struct gbm_surface *
const uint64_t *modifiers,
const unsigned int count)
{
+ uint32_t flags = 0;
+
+ /*
+ * ABI version 1 added the modifiers+flags capability. Backends from
+ * prior versions may fail if "unknown" flags are provided along with
+ * modifiers, but assume scanout is required when modifiers are used.
+ * Newer backends expect scanout to be explicitly requested if required,
+ * but applications using this older interface rely on the older implied
+ * requirement, so that behavior must be preserved.
+ */
+ if (gbm->v0.backend_version >= 1) {
+ flags |= GBM_BO_USE_SCANOUT;
+ }
+
+ return gbm_surface_create_with_modifiers2(gbm, width, height, format,
+ modifiers, count,
+ flags);
+}
+
+GBM_EXPORT struct gbm_surface *
+gbm_surface_create_with_modifiers2(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ const uint64_t *modifiers,
+ const unsigned int count,
+ uint32_t flags)
+{
if ((count && !modifiers) || (modifiers && !count)) {
errno = EINVAL;
return NULL;
}
- return gbm->surface_create(gbm, width, height, format, 0,
- modifiers, count);
+ if (modifiers && (flags & GBM_BO_USE_LINEAR)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return gbm->v0.surface_create(gbm, width, height, format, flags,
+ modifiers, count);
}
/**
- * Destroys the given surface and frees all resources associated with
- * it.
+ * Destroys the given surface and frees all resources associated with it.
*
- * All buffers locked with gbm_surface_lock_front_buffer() should be
- * released prior to calling this function.
+ * Prior to calling this function all buffers locked with
+ * gbm_surface_lock_front_buffer() need to be released and the associated
+ * EGL surface destroyed.
*
* \param surf The surface
*/
GBM_EXPORT void
gbm_surface_destroy(struct gbm_surface *surf)
{
- surf->gbm->surface_destroy(surf);
+ surf->gbm->v0.surface_destroy(surf);
}
/**
*
* This function must be called exactly once after calling
* eglSwapBuffers. Calling it before any eglSwapBuffer has happened
- * on the surface or two or more times after eglSwapBuffers is an
- * error. A new bo representing the new front buffer is returned. On
- * multiple invocations, all the returned bos must be released in
- * order to release the actual surface buffer.
+ * on the surface or two or more times after eglSwapBuffers is an error.
*
* \param surf The surface
*
- * \return A buffer object that should be released with
- * gbm_surface_release_buffer() when no longer needed. The implementation
- * is free to reuse buffers released with gbm_surface_release_buffer() so
- * this bo should not be destroyed using gbm_bo_destroy(). If an error
- * occurs this function returns %NULL.
+ * \return A buffer object representing the front buffer that should be
+ * released with gbm_surface_release_buffer() when no longer needed and before
+ * the associated EGL surface gets destroyed. The implementation is free to
+ * reuse buffers released with gbm_surface_release_buffer() so this bo should
+ * not be destroyed using gbm_bo_destroy(). If an error occurs this function
+ * returns %NULL.
*/
GBM_EXPORT struct gbm_bo *
gbm_surface_lock_front_buffer(struct gbm_surface *surf)
{
- return surf->gbm->surface_lock_front_buffer(surf);
+ return surf->gbm->v0.surface_lock_front_buffer(surf);
}
/**
GBM_EXPORT void
gbm_surface_release_buffer(struct gbm_surface *surf, struct gbm_bo *bo)
{
- surf->gbm->surface_release_buffer(surf, bo);
+ surf->gbm->v0.surface_release_buffer(surf, bo);
}
/**
GBM_EXPORT int
gbm_surface_has_free_buffers(struct gbm_surface *surf)
{
- return surf->gbm->surface_has_free_buffers(surf);
+ return surf->gbm->v0.surface_has_free_buffers(surf);
}
/* The two GBM_BO_FORMAT_[XA]RGB8888 formats alias the GBM_FORMAT_*
* formats of the same name. We want to accept them whenever someone
* has a GBM format, but never return them to the user. */
-uint32_t
-gbm_format_canonicalize(uint32_t gbm_format)
+static uint32_t
+format_canonicalize(uint32_t gbm_format)
{
switch (gbm_format) {
case GBM_BO_FORMAT_XRGB8888:
GBM_EXPORT char *
gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc)
{
- gbm_format = gbm_format_canonicalize(gbm_format);
+ gbm_format = format_canonicalize(gbm_format);
desc->name[0] = gbm_format;
desc->name[1] = gbm_format >> 8;
return desc->name;
}
+
+/**
+ * A global table of functions and global variables defined in the core GBM
+ * code that need to be accessed directly by GBM backends.
+ */
+struct gbm_core gbm_core = {
+ .v0.core_version = GBM_BACKEND_ABI_VERSION,
+ .v0.format_canonicalize = format_canonicalize,
+};
/* 8 bpp Red */
#define GBM_FORMAT_R8 __gbm_fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+/* 16 bpp Red */
+#define GBM_FORMAT_R16 __gbm_fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
+
/* 16 bpp RG */
#define GBM_FORMAT_GR88 __gbm_fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+/* 32 bpp RG */
+#define GBM_FORMAT_RG1616 __gbm_fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
+#define GBM_FORMAT_GR1616 __gbm_fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
+
/* 8 bpp RGB */
#define GBM_FORMAT_RGB332 __gbm_fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
#define GBM_FORMAT_BGR233 __gbm_fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
#define GBM_FORMAT_RGBA1010102 __gbm_fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
#define GBM_FORMAT_BGRA1010102 __gbm_fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
+/* 64 bpp RGB */
+#define GBM_FORMAT_XBGR16161616 __gbm_fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */
+
+#define GBM_FORMAT_ABGR16161616 __gbm_fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */
+
/*
* Floating point 64bpp RGB
* IEEE 754-2008 binary16 half-precision float
* OpenCL, and Vulkan applications.
*/
GBM_BO_USE_PROTECTED = (1 << 5),
+
+ /**
+ * The buffer will be used for front buffer rendering. On some
+ * platforms this may (for example) disable framebuffer compression
+ * to avoid problems with compression flags data being out of sync
+ * with pixel data.
+ */
+ GBM_BO_USE_FRONT_RENDERING = (1 << 6),
};
int
int
gbm_device_is_format_supported(struct gbm_device *gbm,
- uint32_t format, uint32_t usage);
+ uint32_t format, uint32_t flags);
int
gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm,
uint32_t format,
const uint64_t *modifiers,
const unsigned int count);
+
+struct gbm_bo *
+gbm_bo_create_with_modifiers2(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ const uint64_t *modifiers,
+ const unsigned int count,
+ uint32_t flags);
+
#define GBM_BO_IMPORT_WL_BUFFER 0x5501
#define GBM_BO_IMPORT_EGL_IMAGE 0x5502
#define GBM_BO_IMPORT_FD 0x5503
struct gbm_bo *
gbm_bo_import(struct gbm_device *gbm, uint32_t type,
- void *buffer, uint32_t usage);
+ void *buffer, uint32_t flags);
/**
* Flags to indicate the type of mapping for the buffer - these are
gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane);
int
+gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane);
+
+int
gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count);
void
const uint64_t *modifiers,
const unsigned int count);
+struct gbm_surface *
+gbm_surface_create_with_modifiers2(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ const uint64_t *modifiers,
+ const unsigned int count,
+ uint32_t flags);
+
struct gbm_bo *
gbm_surface_lock_front_buffer(struct gbm_surface *surface);
--- /dev/null
+/*
+ * Copyright © 2021 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "gbm_backend_abi.h" /* Current GBM backend ABI implementation */
+
+#include <stddef.h> /* offsetof */
+#include <stdio.h> /* printf */
+
+/*
+ * The following are previous implementations of the structures defined in
+ * gbm_backend_abi.h, with their ABI version appended.
+ *
+ * DO NOT EVER CHANGE EXISTING DEFINITIONS HERE!
+ *
+ * Changing them implies breaking the GBM backend ABI. Instead, to extend the
+ * ABI, in gbm_backend_abi.h:
+ *
+ * -Add a new versioned struct
+ * -Append it to the associated top-level object's struct
+ * -Increment GBM_BACKEND_ABI_VERSION
+ *
+ * Then, here:
+ *
+ * -Add a new block of definitions below for the new ABI content
+ * -Add a new block of checks in main()
+ */
+
+/*
+ * From: Simon Ser - "gbm: assume USE_SCANOUT in create_with_modifiers"
+ *
+ * Note: ABI 1 is identical to ABI 0, except gbm_device_v0.bo_create can
+ * provide both modifiers and usage.
+ */
+#define GBM_BACKEND_ABI_VERSION_abi0 1
+struct gbm_device_v0_abi0 {
+ const struct gbm_backend_desc *backend_desc;
+ uint32_t backend_version;
+ int fd;
+ const char *name;
+ void (*destroy)(struct gbm_device *gbm);
+ int (*is_format_supported)(struct gbm_device *gbm,
+ uint32_t format,
+ uint32_t usage);
+ int (*get_format_modifier_plane_count)(struct gbm_device *device,
+ uint32_t format,
+ uint64_t modifier);
+ struct gbm_bo *(*bo_create)(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ uint32_t usage,
+ const uint64_t *modifiers,
+ const unsigned int count);
+ struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
+ void *buffer, uint32_t usage);
+ void *(*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);
+ void (*bo_unmap)(struct gbm_bo *bo, void *map_data);
+ int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
+ int (*bo_get_fd)(struct gbm_bo *bo);
+ int (*bo_get_planes)(struct gbm_bo *bo);
+ union gbm_bo_handle (*bo_get_handle)(struct gbm_bo *bo, int plane);
+ int (*bo_get_plane_fd)(struct gbm_bo *bo, int plane);
+ uint32_t (*bo_get_stride)(struct gbm_bo *bo, int plane);
+ uint32_t (*bo_get_offset)(struct gbm_bo *bo, int plane);
+ uint64_t (*bo_get_modifier)(struct gbm_bo *bo);
+ void (*bo_destroy)(struct gbm_bo *bo);
+ struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags,
+ const uint64_t *modifiers,
+ const unsigned count);
+ struct gbm_bo *(*surface_lock_front_buffer)(struct gbm_surface *surface);
+ void (*surface_release_buffer)(struct gbm_surface *surface,
+ struct gbm_bo *bo);
+ int (*surface_has_free_buffers)(struct gbm_surface *surface);
+ void (*surface_destroy)(struct gbm_surface *surface);
+};
+
+struct gbm_device_abi0 {
+ /* Hack to make a gbm_device detectable by its first element. */
+ struct gbm_device *(*dummy)(int);
+ struct gbm_device_v0_abi0 v0;
+};
+
+/**
+ * GBM buffer object interface corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_bo_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_bo_v1 to gbm_bo.
+ */
+struct gbm_bo_v0_abi0 {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t format;
+ union gbm_bo_handle handle;
+ void *user_data;
+ void (*destroy_user_data)(struct gbm_bo *, void *);
+};
+
+/**
+ * The allocated buffer object.
+ *
+ * The members in this structure should not be accessed directly.
+ *
+ * To modify this structure, introduce a new gbm_bo_v<N> structure, add it to
+ * the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_bo_abi0 {
+ struct gbm_device *gbm;
+ struct gbm_bo_v0_abi0 v0;
+};
+
+/**
+ * GBM surface interface corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_surface_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_surface_v1 to gbm_surface.
+ */
+struct gbm_surface_v0_abi0 {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t flags;
+ struct {
+ uint64_t *modifiers;
+ unsigned count;
+ };
+};
+
+/**
+ * An allocated GBM surface.
+ *
+ * To modify this structure, introduce a new gbm_surface_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_surface_abi0 {
+ struct gbm_device *gbm;
+ struct gbm_surface_v0_abi0 v0;
+};
+
+/**
+ * GBM backend interfaces corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_backend_v1, increment
+ * GBM_BACKEND_ABI_VERSION, append gbm_backend_v1 to gbm_backend.
+ */
+struct gbm_backend_v0_abi0 {
+ /**
+ * The version of the GBM backend interface supported by this backend. This
+ * is set by the backend itself, and may be greater or less than the version
+ * supported by the loader. It is the responsibility of the GBM loader to
+ * respect this version when accessing fields in this structure.
+ */
+ uint32_t backend_version;
+
+ const char *backend_name;
+ struct gbm_device *(*create_device)(int fd, uint32_t gbm_backend_version);
+};
+
+/**
+ * The interface exposed by an external GBM backend.
+ *
+ * To modify this structure, introduce a new gbm_backend_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_backend_abi0 {
+ struct gbm_backend_v0_abi0 v0;
+};
+
+/**
+ * GBM interfaces exposed to GBM backends at GBM_BACKEND_ABI_VERSION >= 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_core_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_core_v1 to gbm_backend.
+ */
+struct gbm_core_v0_abi0 {
+ /**
+ * The version of the GBM backend interface supported by the GBM loader. This
+ * is set by the loader, and may be greater or less than the version
+ * supported by a given backend. It is the responsibility of the backend to
+ * respect this version when accessing fields in this structure and other
+ * structures allocated or modified by the loader.
+ */
+ uint32_t core_version;
+
+ uint32_t (*format_canonicalize)(uint32_t gbm_format);
+};
+
+/**
+ * The interface exposed by the GBM core/loader code to GBM backends.
+ *
+ * To modify this structure, introduce a new gbm_core_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_core_abi0 {
+ struct gbm_core_v0_abi0 v0;
+};
+
+typedef const struct gbm_backend *(*GBM_GET_BACKEND_PROC_PTR_abi0)(const struct gbm_core *gbm_core);
+
+/*
+ * Structure/member ABI-checking helper macros
+ */
+#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
+
+#define CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member) \
+ do { \
+ if (offsetof(struct type ## a_ver, a_member) != \
+ offsetof(struct type ## b_ver, b_member)) { \
+ printf("Backards incompatible change detected!\n " \
+ "offsetof(struct " #type #a_ver "::" #a_member ") != " \
+ "offsetof(struct " #type #b_ver "::" #b_member ")\n"); \
+ return 1; \
+ } \
+ \
+ if (MEMBER_SIZE(struct type ## a_ver, a_member) != \
+ MEMBER_SIZE(struct type ## b_ver, b_member)) { \
+ printf("Backards incompatible change detected!\n " \
+ "MEMBER_SIZE(struct " #type #a_ver "::" #a_member ") != " \
+ "MEMBER_SIZE(struct " #type #b_ver "::" #b_member ")\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define CHECK_RENAMED_MEMBER_TYPE(type, a_ver, b_ver, a_member, b_member) \
+ do { \
+ /* Compile-time type compatibility check */ \
+ struct type ## a_ver a; \
+ struct type ## b_ver b = {0}; \
+ a.a_member = b.b_member; \
+ (void)a; \
+ } while (0)
+
+#define CHECK_RENAMED_MEMBER(type, a_ver, b_ver, a_member, b_member) \
+ do { \
+ CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member); \
+ CHECK_RENAMED_MEMBER_TYPE(type, a_ver, b_ver, a_member, b_member); \
+ } while (0)
+#define CHECK_RENAMED_MEMBER_NO_TYPE(type, a_ver, b_ver, a_member, b_member) \
+ CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member);
+
+#define CHECK_MEMBER(type, a_ver, b_ver, member) \
+ CHECK_RENAMED_MEMBER(type, a_ver, b_ver, member, member)
+#define CHECK_MEMBER_NO_TYPE(type, a_ver, b_ver, member) \
+ CHECK_RENAMED_MEMBER_NO_TYPE(type, a_ver, b_ver, member, member)
+#define CHECK_MEMBER_CURRENT(type, a_ver, member) \
+ CHECK_MEMBER(type, a_ver,, member)
+#define CHECK_MEMBER_CURRENT_NO_TYPE(type, a_ver, member) \
+ CHECK_MEMBER_NO_TYPE(type, a_ver,, member)
+
+#define CHECK_SIZE(type, a_ver, b_ver) \
+ do { \
+ if (sizeof(struct type ## a_ver) > \
+ sizeof(struct type ## b_ver)) { \
+ printf("Backards incompatible change detected!\n " \
+ "sizeof(struct " #type #a_ver ") > " \
+ "sizeof(struct " #type #b_ver ")\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define CHECK_SIZE_CURRENT(type, a_ver) \
+ do { \
+ if (sizeof(struct type ## a_ver) != \
+ sizeof(struct type)) { \
+ printf("Backards incompatible change detected!\n " \
+ "sizeof(struct " #type #a_ver ") != " \
+ "sizeof(struct " #type ")\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define CHECK_VERSION(a_ver, b_ver) \
+ do { \
+ if ((GBM_BACKEND_ABI_VERSION ## a_ver) >= \
+ (GBM_BACKEND_ABI_VERSION ## b_ver)) { \
+ printf("Backards incompatible change detected!\n " \
+ "GBM_BACKEND_ABI_VERSION" #a_ver " >= " \
+ "GBM_BACKEND_ABI_VERSION" #b_ver "\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define CHECK_VERSION_CURRENT(a_ver) \
+ do { \
+ if ((GBM_BACKEND_ABI_VERSION ## a_ver) != \
+ (GBM_BACKEND_ABI_VERSION)) { \
+ printf("Backards incompatible change detected!\n " \
+ "GBM_BACKEND_ABI_VERSION" #a_ver " != " \
+ "GBM_BACKEND_ABI_VERSION\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define CHECK_PROC(proc, a_ver, b_ver) \
+ do { \
+ proc ## a_ver a; \
+ proc ## b_ver b = NULL; \
+ a = b; \
+ (void)a; \
+ } while (0)
+
+#define CHECK_PROC_CURRENT(proc, a_ver) \
+ CHECK_PROC(proc, a_ver,)
+
+int main(int argc, char **argv)
+{
+ /********************************************/
+ /*** Compare Current ABI to ABI version 0 ***/
+ /********************************************/
+
+ /* Check current gbm_device ABI against gbm_device_abi0*/
+ CHECK_MEMBER_CURRENT(gbm_device, _abi0, dummy);
+ CHECK_MEMBER_CURRENT_NO_TYPE(gbm_device, _abi0, v0);
+
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, backend_desc);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, backend_version);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, fd);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, name);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, destroy);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, is_format_supported);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, get_format_modifier_plane_count);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_create);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_import);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_map);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_unmap);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_write);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_fd);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_planes);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_handle);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_plane_fd);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_stride);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_offset);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_modifier);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_destroy);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_create);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_lock_front_buffer);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_release_buffer);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_has_free_buffers);
+ CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_destroy);
+
+ /* Size of ABI-versioned substructures verified by above member checks */
+ CHECK_SIZE_CURRENT (gbm_device, _abi0);
+
+
+ /* Check current gbm_bo ABI against gbm_bo_abi0*/
+ CHECK_MEMBER_CURRENT(gbm_bo, _abi0, gbm);
+ CHECK_MEMBER_CURRENT_NO_TYPE(gbm_bo, _abi0, v0);
+
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, width);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, height);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, stride);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, format);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, handle);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, user_data);
+ CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, destroy_user_data);
+
+ /* Size of ABI-versioned substructures verified by above member checks */
+ CHECK_SIZE_CURRENT (gbm_bo, _abi0);
+
+
+ /* Check current gbm_surface ABI against gbm_surface_abi0 */
+ CHECK_MEMBER_CURRENT(gbm_surface, _abi0, gbm);
+ CHECK_MEMBER_CURRENT_NO_TYPE(gbm_surface, _abi0, v0);
+
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, width);
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, height);
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, format);
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, flags);
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, modifiers);
+ CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, count);
+
+ /* Size of ABI-versioned substructures verified by above member checks */
+ CHECK_SIZE_CURRENT (gbm_surface, _abi0);
+
+
+ /* Check current gbm_backend ABI against gbm_backend_abi0 */
+ CHECK_MEMBER_CURRENT_NO_TYPE(gbm_backend, _abi0, v0);
+
+ CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, backend_version);
+ CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, backend_name);
+ CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, create_device);
+
+ /* Size of ABI-versioned substructures verified by above member checks */
+ CHECK_SIZE_CURRENT (gbm_backend, _abi0);
+
+
+ /* Check current gbm_core ABI against gbm_core_abi0 */
+ CHECK_MEMBER_CURRENT_NO_TYPE(gbm_core, _abi0, v0);
+
+ CHECK_MEMBER_CURRENT(gbm_core_v0, _abi0, core_version);
+ CHECK_MEMBER_CURRENT(gbm_core_v0, _abi0, format_canonicalize);
+
+ /* Size of ABI-versioned substructures verified by above member checks */
+ CHECK_SIZE_CURRENT (gbm_core, _abi0);
+
+
+ CHECK_PROC_CURRENT (GBM_GET_BACKEND_PROC_PTR, _abi0);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2021 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Benjamin Franzke <benjaminfranzke@googlemail.com>
+ * James Jones <jajones@nvidia.com>
+ */
+
+#ifndef GBM_BACKEND_ABI_H_
+#define GBM_BACKEND_ABI_H_
+
+#include "gbm.h"
+
+/**
+ * \file gbm_backend_abi.h
+ * \brief ABI between the GBM loader and its backends
+ */
+
+struct gbm_backend_desc;
+
+/**
+ * The GBM backend interface version defined by this file.
+ *
+ * The GBM device interface version must be incremented whenever the structures
+ * defined in this file are modified. To preserve ABI compatibility with
+ * backends that support only older versions, modifications to this file must
+ * consist only of appending new fields to the end of the structures defined in
+ * it, defining new structures, or declaring new exported functions or global
+ * variables.
+ *
+ * Note this version applies to ALL structures in this file, not just the core,
+ * backend, and device structures which contain it explicitly. Buffer objects,
+ * surfaces, and any other new structures introduced to this file are also part
+ * of the backend ABI. The ABI version of an instance of any object in this file
+ * is defined as the minimum of the version of the backend associated with the
+ * object instance and the loader's core object version. Hence, any new objects
+ * added to this file should contain either a reference to an existing object
+ * defined here, or an explicit version field.
+ *
+ * A few examples of object versions:
+ *
+ * Backend ABI version: 0
+ * Core ABI version: 3
+ * ABI version of a device created by the backend: 0
+ *
+ * Backend ABI version: 2
+ * Core ABI version: 1
+ * ABI version of a surface created by a device from the backend: 1
+ *
+ * Backend ABI version: 4
+ * Core ABI version: 4
+ * ABI version of a buffer object created by a device from the backend: 4
+ */
+#define GBM_BACKEND_ABI_VERSION 1
+
+/**
+ * GBM device interface corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_bo_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_bo_v1 to gbm_bo.
+ */
+struct gbm_device_v0 {
+ const struct gbm_backend_desc *backend_desc;
+
+ /**
+ * The version of the GBM backend interface supported by this device and its
+ * child objects. This may be less than the maximum version supported by the
+ * GBM loader if the device was created by an older backend, or less than the
+ * maximum version supported by the backend if the device was created by an
+ * older loader. In other words, this will be:
+ *
+ * MIN(backend GBM interface version, loader GBM interface version)
+ *
+ * It is the backend's responsibility to assign this field the value passed
+ * in by the GBM loader to the backend's create_device function. The GBM
+ * loader will pre-clamp the value based on the loader version and the
+ * version reported by the backend in its gbm_backend_v0::backend_version
+ * field. It is the loader's responsibility to respect this version when
+ * directly accessing a device instance or any child objects instantiated by
+ * a device instance.
+ */
+ uint32_t backend_version;
+
+ int fd;
+ const char *name;
+
+ void (*destroy)(struct gbm_device *gbm);
+ int (*is_format_supported)(struct gbm_device *gbm,
+ uint32_t format,
+ uint32_t usage);
+ int (*get_format_modifier_plane_count)(struct gbm_device *device,
+ uint32_t format,
+ uint64_t modifier);
+
+ /**
+ * Since version 1, usage is properly populated when modifiers are
+ * supplied. Version 0 always set usage to 0 in this case.
+ */
+ struct gbm_bo *(*bo_create)(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format,
+ uint32_t usage,
+ const uint64_t *modifiers,
+ const unsigned int count);
+ struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
+ void *buffer, uint32_t usage);
+ void *(*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);
+ void (*bo_unmap)(struct gbm_bo *bo, void *map_data);
+ int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
+ int (*bo_get_fd)(struct gbm_bo *bo);
+ int (*bo_get_planes)(struct gbm_bo *bo);
+ union gbm_bo_handle (*bo_get_handle)(struct gbm_bo *bo, int plane);
+ int (*bo_get_plane_fd)(struct gbm_bo *bo, int plane);
+ uint32_t (*bo_get_stride)(struct gbm_bo *bo, int plane);
+ uint32_t (*bo_get_offset)(struct gbm_bo *bo, int plane);
+ uint64_t (*bo_get_modifier)(struct gbm_bo *bo);
+ void (*bo_destroy)(struct gbm_bo *bo);
+
+ /**
+ * Since version 1, flags are properly populated when modifiers are
+ * supplied. Version 0 always set flags to 0 in this case.
+ */
+ struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t flags,
+ const uint64_t *modifiers,
+ const unsigned count);
+ struct gbm_bo *(*surface_lock_front_buffer)(struct gbm_surface *surface);
+ void (*surface_release_buffer)(struct gbm_surface *surface,
+ struct gbm_bo *bo);
+ int (*surface_has_free_buffers)(struct gbm_surface *surface);
+ void (*surface_destroy)(struct gbm_surface *surface);
+};
+
+/**
+ * The device used for the memory allocation.
+ *
+ * The members of this structure should be not accessed directly
+ *
+ * To modify this structure, introduce a new gbm_device_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_device {
+ /* Hack to make a gbm_device detectable by its first element. */
+ struct gbm_device *(*dummy)(int);
+ struct gbm_device_v0 v0;
+};
+
+/**
+ * GBM buffer object interface corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_bo_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_bo_v1 to gbm_bo.
+ */
+struct gbm_bo_v0 {
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ uint32_t format;
+ union gbm_bo_handle handle;
+ void *user_data;
+ void (*destroy_user_data)(struct gbm_bo *, void *);
+};
+
+/**
+ * The allocated buffer object.
+ *
+ * The members in this structure should not be accessed directly.
+ *
+ * To modify this structure, introduce a new gbm_bo_v<N> structure, add it to
+ * the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_bo {
+ struct gbm_device *gbm;
+ struct gbm_bo_v0 v0;
+};
+
+/**
+ * GBM surface interface corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_surface_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_surface_v1 to gbm_surface.
+ */
+struct gbm_surface_v0 {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t flags;
+ struct {
+ uint64_t *modifiers;
+ unsigned count;
+ };
+};
+
+/**
+ * An allocated GBM surface.
+ *
+ * To modify this structure, introduce a new gbm_surface_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_surface {
+ struct gbm_device *gbm;
+ struct gbm_surface_v0 v0;
+};
+
+/**
+ * GBM backend interfaces corresponding to GBM_BACKEND_ABI_VERSION = 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_backend_v1, increment
+ * GBM_BACKEND_ABI_VERSION, append gbm_backend_v1 to gbm_backend.
+ */
+struct gbm_backend_v0 {
+ /**
+ * The version of the GBM backend interface supported by this backend. This
+ * is set by the backend itself, and may be greater or less than the version
+ * supported by the loader. It is the responsibility of the GBM loader to
+ * respect this version when accessing fields in this structure.
+ */
+ uint32_t backend_version;
+
+ const char *backend_name;
+ struct gbm_device *(*create_device)(int fd, uint32_t gbm_backend_version);
+};
+
+/**
+ * The interface exposed by an external GBM backend.
+ *
+ * To modify this structure, introduce a new gbm_backend_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_backend {
+ struct gbm_backend_v0 v0;
+};
+
+/**
+ * GBM interfaces exposed to GBM backends at GBM_BACKEND_ABI_VERSION >= 0
+ *
+ * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_core_v1, increment
+ * GBM_BACKEND_ABI_VERSION, and append gbm_core_v1 to gbm_backend.
+ */
+struct gbm_core_v0 {
+ /**
+ * The version of the GBM backend interface supported by the GBM loader. This
+ * is set by the loader, and may be greater or less than the version
+ * supported by a given backend. It is the responsibility of the backend to
+ * respect this version when accessing fields in this structure and other
+ * structures allocated or modified by the loader.
+ */
+ uint32_t core_version;
+
+ uint32_t (*format_canonicalize)(uint32_t gbm_format);
+};
+
+/**
+ * The interface exposed by the GBM core/loader code to GBM backends.
+ *
+ * To modify this structure, introduce a new gbm_core_v<N> structure, add it
+ * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
+ */
+struct gbm_core {
+ struct gbm_core_v0 v0;
+};
+
+/**
+ * The entrypoint an external GBM backend exports.
+ *
+ * Prior to creating any devices using the backend, GBM will look up and call
+ * this function to request the backend's interface and convey the loader's
+ * version and exported interface to the backend.
+ *
+ * DO NOT MODIFY THIS FUNCTION NAME OR PROTOTYPE. It must remain unchanged to
+ * preserve backwards compatibility with existing GBM backends.
+ */
+#define GBM_GET_BACKEND_PROC gbmint_get_backend
+#define _GBM_MKSTRX(s) _GBM_MKSTR(s)
+#define _GBM_MKSTR(s) #s
+#define GBM_GET_BACKEND_PROC_NAME _GBM_MKSTRX(GBM_GET_BACKEND_PROC)
+typedef const struct gbm_backend *(*GBM_GET_BACKEND_PROC_PTR)(const struct gbm_core *gbm_core);
+
+#endif
/*
* Copyright © 2011 Intel Corporation
+ * Copyright © 2021 NVIDIA Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
*
* Authors:
* Benjamin Franzke <benjaminfranzke@googlemail.com>
+ * James Jones <jajones@nvidia.com>
*/
#ifndef INTERNAL_H_
#define INTERNAL_H_
-#include "gbm.h"
-#include <sys/stat.h>
+#include "gbm_backend_abi.h"
/* GCC visibility */
#if defined(__GNUC__)
* \brief Internal implementation details of gbm
*/
-/**
- * The device used for the memory allocation.
- *
- * The members of this structure should be not accessed directly
- */
-struct gbm_device {
- /* Hack to make a gbm_device detectable by its first element. */
- struct gbm_device *(*dummy)(int);
-
- int fd;
- const char *name;
- unsigned int refcount;
- struct stat stat;
-
- void (*destroy)(struct gbm_device *gbm);
- int (*is_format_supported)(struct gbm_device *gbm,
- uint32_t format,
- uint32_t usage);
- int (*get_format_modifier_plane_count)(struct gbm_device *device,
- uint32_t format,
- uint64_t modifier);
-
- struct gbm_bo *(*bo_create)(struct gbm_device *gbm,
- uint32_t width, uint32_t height,
- uint32_t format,
- uint32_t usage,
- const uint64_t *modifiers,
- const unsigned int count);
- struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
- void *buffer, uint32_t usage);
- void *(*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);
- void (*bo_unmap)(struct gbm_bo *bo, void *map_data);
- int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
- int (*bo_get_fd)(struct gbm_bo *bo);
- int (*bo_get_planes)(struct gbm_bo *bo);
- union gbm_bo_handle (*bo_get_handle)(struct gbm_bo *bo, int plane);
- uint32_t (*bo_get_stride)(struct gbm_bo *bo, int plane);
- uint32_t (*bo_get_offset)(struct gbm_bo *bo, int plane);
- uint64_t (*bo_get_modifier)(struct gbm_bo *bo);
- void (*bo_destroy)(struct gbm_bo *bo);
-
- struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
- uint32_t width, uint32_t height,
- uint32_t format, uint32_t flags,
- const uint64_t *modifiers,
- const unsigned count);
- struct gbm_bo *(*surface_lock_front_buffer)(struct gbm_surface *surface);
- void (*surface_release_buffer)(struct gbm_surface *surface,
- struct gbm_bo *bo);
- int (*surface_has_free_buffers)(struct gbm_surface *surface);
- void (*surface_destroy)(struct gbm_surface *surface);
-};
-
-/**
- * The allocated buffer object.
- *
- * The members in this structure should not be accessed directly.
- */
-struct gbm_bo {
- struct gbm_device *gbm;
- uint32_t width;
- uint32_t height;
- uint32_t stride;
- uint32_t format;
- union gbm_bo_handle handle;
- void *user_data;
- void (*destroy_user_data)(struct gbm_bo *, void *);
-};
-
-struct gbm_surface {
- struct gbm_device *gbm;
- uint32_t width;
- uint32_t height;
- uint32_t format;
- uint32_t flags;
- struct {
- uint64_t *modifiers;
- unsigned count;
- };
-};
-
-struct gbm_backend {
- const char *backend_name;
- struct gbm_device *(*create_device)(int fd);
-};
-
-uint32_t
-gbm_format_canonicalize(uint32_t gbm_format);
+extern struct gbm_core gbm_core;
#endif