Sync with codes from mesa 23.3.3 version 31/309131/1
authorChangyeon Lee <cyeon.lee@samsung.com>
Fri, 5 Apr 2024 05:07:15 +0000 (14:07 +0900)
committerChangyeon Lee <cyeon.lee@samsung.com>
Fri, 5 Apr 2024 05:07:15 +0000 (14:07 +0900)
Change-Id: I21cce22f0d2f6b4e862c73ce829f07c06eb0b2ed

Makefile.am
backends/tbm/gbm_tbm.c
configure.ac
packaging/libgbm.spec
src/backend.c
src/backend.h
src/gbm.c
src/gbm.h
src/gbm_abi_check.c [new file with mode: 0644]
src/gbm_backend_abi.h [new file with mode: 0644]
src/gbmint.h

index 5740071..a7c673b 100644 (file)
@@ -4,7 +4,7 @@ pkgconfig_DATA = gbm.pc
 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
@@ -14,13 +14,19 @@ libgbm_la_SOURCES = \
        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 = \
@@ -37,7 +43,6 @@ AM_CFLAGS += \
 
 libgbm_la_LIBADD += \
        $(TBM_LIBS)
-
 endif
 
 libgbmtbmincludedir=$(includedir)/gbm
@@ -46,4 +51,4 @@ libgbmtbminclude_HEADERS = \
        backends/tbm/gbm_tbmint.h
 
 
-CLEANFILES = 
+CLEANFILES =
index 7d441c8..2ae5557 100644 (file)
@@ -167,14 +167,14 @@ __gbm_tbm_bo_import(struct gbm_device *gbm, uint32_t type,
 
    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;
 }
@@ -195,9 +195,9 @@ __gbm_tbm_bo_create_by_tbm_surface(struct gbm_device *gbm,
        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;
 
@@ -208,10 +208,10 @@ __gbm_tbm_bo_create_by_tbm_surface(struct gbm_device *gbm,
       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);
@@ -275,10 +275,10 @@ __gbm_tbm_surface_create(struct gbm_device *gbm,
        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))
    {
@@ -322,10 +322,10 @@ __gbm_tbm_surface_lock_front_buffer(struct gbm_surface *surface)
 
          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;
@@ -371,7 +371,7 @@ __tbm_destroy(struct gbm_device *gbm)
 }
 
 static struct gbm_device *
-__tbm_device_create(int fd)
+__tbm_device_create(int fd, uint32_t gbm_backend_version)
 {
    struct gbm_tbm_device *dri;
 
@@ -383,20 +383,21 @@ __tbm_device_create(int fd)
    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;
 
@@ -412,6 +413,7 @@ fail:
 }
 
 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,
 };
index e72c522..3cd6648 100644 (file)
@@ -10,6 +10,11 @@ AM_SILENT_RULES([yes])
 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])
@@ -25,6 +30,9 @@ if test x$have_tbm = xyes; then
    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)
 
index ef69040..2c506be 100644 (file)
@@ -14,6 +14,7 @@ BuildRequires: libtool
 BuildRequires: systemd-devel
 BuildRequires: pkgconfig(libtbm)
 BuildRequires: pkgconfig(wayland-tbm-server)
+BuildRequires: pkgconfig(libdrm)
 
 %description
 Wayland Generic Buffer Management for TIZEN
index b2b089b..93babcb 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * 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"),
@@ -23,6 +24,7 @@
  *
  * 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);
+}
index 4a64375..325c412 100644 (file)
@@ -33,4 +33,7 @@
 struct gbm_device *
 _gbm_create_device(int fd);
 
+void
+_gbm_device_destroy(struct gbm_device *gbm);
+
 #endif
index 954b3c3..599f7aa 100644 (file)
--- a/src/gbm.c
+++ b/src/gbm.c
@@ -52,7 +52,7 @@
 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
@@ -63,14 +63,14 @@ gbm_device_get_fd(struct gbm_device *gbm)
 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
@@ -80,9 +80,9 @@ gbm_device_get_backend_name(struct gbm_device *gbm)
  */
 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
@@ -96,19 +96,20 @@ gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm,
                                            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
@@ -139,8 +140,6 @@ gbm_create_device(int fd)
       return NULL;
 
    gbm->dummy = gbm_create_device;
-   gbm->stat = buf;
-   gbm->refcount = 1;
 
    return gbm;
 }
@@ -154,7 +153,7 @@ gbm_create_device(int fd)
 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
@@ -165,7 +164,7 @@ gbm_bo_get_width(struct gbm_bo *bo)
 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
@@ -192,7 +191,7 @@ gbm_bo_get_stride(struct gbm_bo *bo)
 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
@@ -205,7 +204,7 @@ gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane)
 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
@@ -223,7 +222,7 @@ gbm_bo_get_format(struct gbm_bo *bo)
 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:
@@ -231,6 +230,7 @@ gbm_bo_get_bpp(struct gbm_bo *bo)
       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:
@@ -254,6 +254,8 @@ gbm_bo_get_bpp(struct gbm_bo *bo)
       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:
@@ -271,6 +273,8 @@ gbm_bo_get_bpp(struct gbm_bo *bo)
       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;
@@ -289,7 +293,7 @@ gbm_bo_get_bpp(struct gbm_bo *bo)
 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
@@ -314,7 +318,7 @@ gbm_bo_get_device(struct gbm_bo *bo)
 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
@@ -331,7 +335,7 @@ gbm_bo_get_handle(struct gbm_bo *bo)
 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.
@@ -342,7 +346,7 @@ gbm_bo_get_fd(struct gbm_bo *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
@@ -360,7 +364,27 @@ gbm_bo_get_plane_count(struct gbm_bo *bo)
 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);
 }
 
 /**
@@ -379,7 +403,7 @@ gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int 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
@@ -398,7 +422,7 @@ gbm_bo_get_modifier(struct gbm_bo *bo)
 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
@@ -412,8 +436,8 @@ GBM_EXPORT void
 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
@@ -427,7 +451,7 @@ gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
 GBM_EXPORT void *
 gbm_bo_get_user_data(struct gbm_bo *bo)
 {
-   return bo->user_data;
+   return bo->v0.user_data;
 }
 
 /**
@@ -439,10 +463,10 @@ gbm_bo_get_user_data(struct gbm_bo *bo)
 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);
 }
 
 /**
@@ -453,7 +477,7 @@ gbm_bo_destroy(struct gbm_bo *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
@@ -464,14 +488,14 @@ gbm_bo_destroy(struct gbm_bo *bo)
 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 *
@@ -481,6 +505,32 @@ gbm_bo_create_with_modifiers(struct gbm_device *gbm,
                              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;
@@ -491,7 +541,12 @@ gbm_bo_create_with_modifiers(struct gbm_device *gbm,
       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);
 }
 
 /**
@@ -513,7 +568,7 @@ gbm_bo_create_with_modifiers(struct gbm_device *gbm,
  * \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
@@ -523,9 +578,9 @@ gbm_bo_create_with_modifiers(struct gbm_device *gbm,
  */
 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);
 }
 
 /**
@@ -567,8 +622,8 @@ gbm_bo_map(struct gbm_bo *bo,
       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);
 }
 
 /**
@@ -583,7 +638,7 @@ gbm_bo_map(struct gbm_bo *bo,
 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);
 }
 
 /**
@@ -605,7 +660,7 @@ gbm_surface_create(struct gbm_device *gbm,
                    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 *
@@ -615,28 +670,60 @@ gbm_surface_create_with_modifiers(struct gbm_device *gbm,
                                   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);
 }
 
 /**
@@ -647,23 +734,21 @@ gbm_surface_destroy(struct gbm_surface *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);
 }
 
 /**
@@ -681,7 +766,7 @@ gbm_surface_lock_front_buffer(struct gbm_surface *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);
 }
 
 /**
@@ -703,14 +788,14 @@ gbm_surface_release_buffer(struct gbm_surface *surf, struct gbm_bo *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:
@@ -731,7 +816,7 @@ gbm_format_canonicalize(uint32_t gbm_format)
 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;
@@ -741,3 +826,12 @@ gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc)
 
    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,
+};
index d5edb8a..3979232 100644 (file)
--- a/src/gbm.h
+++ b/src/gbm.h
@@ -94,9 +94,16 @@ enum gbm_bo_format {
 /* 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 */
@@ -150,6 +157,11 @@ enum gbm_bo_format {
 #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
@@ -244,6 +256,14 @@ enum gbm_bo_flags {
     * 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
@@ -254,7 +274,7 @@ gbm_device_get_backend_name(struct gbm_device *gbm);
 
 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,
@@ -278,6 +298,15 @@ gbm_bo_create_with_modifiers(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
@@ -306,7 +335,7 @@ struct gbm_import_fd_modifier_data {
 
 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
@@ -383,6 +412,9 @@ union gbm_bo_handle
 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
@@ -407,6 +439,14 @@ gbm_surface_create_with_modifiers(struct gbm_device *gbm,
                                   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);
 
diff --git a/src/gbm_abi_check.c b/src/gbm_abi_check.c
new file mode 100644 (file)
index 0000000..feca099
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * 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;
+}
diff --git a/src/gbm_backend_abi.h b/src/gbm_backend_abi.h
new file mode 100644 (file)
index 0000000..222ce34
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * 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
index 1925774..143b104 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * 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