From c9bee3f30845e97f432657af7c338f49b7cfd3e1 Mon Sep 17 00:00:00 2001 From: Changyeon Lee Date: Fri, 5 Apr 2024 14:07:15 +0900 Subject: [PATCH] Sync with codes from mesa 23.3.3 version Change-Id: I21cce22f0d2f6b4e862c73ce829f07c06eb0b2ed --- Makefile.am | 15 +- backends/tbm/gbm_tbm.c | 72 +++++---- configure.ac | 8 + packaging/libgbm.spec | 1 + src/backend.c | 218 +++++++++++++++++++++---- src/backend.h | 3 + src/gbm.c | 218 ++++++++++++++++++------- src/gbm.h | 44 ++++- src/gbm_abi_check.c | 426 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gbm_backend_abi.h | 305 +++++++++++++++++++++++++++++++++++ src/gbmint.h | 98 +----------- 11 files changed, 1178 insertions(+), 230 deletions(-) create mode 100644 src/gbm_abi_check.c create mode 100644 src/gbm_backend_abi.h diff --git a/Makefile.am b/Makefile.am index 5740071..a7c673b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 = diff --git a/backends/tbm/gbm_tbm.c b/backends/tbm/gbm_tbm.c index 7d441c8..2ae5557 100644 --- a/backends/tbm/gbm_tbm.c +++ b/backends/tbm/gbm_tbm.c @@ -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, }; diff --git a/configure.ac b/configure.ac index e72c522..3cd6648 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/packaging/libgbm.spec b/packaging/libgbm.spec index ef69040..2c506be 100644 --- a/packaging/libgbm.spec +++ b/packaging/libgbm.spec @@ -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 diff --git a/src/backend.c b/src/backend.c index b2b089b..93babcb 100644 --- a/src/backend.c +++ b/src/backend.c @@ -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 + * James Jones */ #include @@ -30,80 +32,232 @@ #include #include #include +#include +#include +#include +#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); +} diff --git a/src/backend.h b/src/backend.h index 4a64375..325c412 100644 --- a/src/backend.h +++ b/src/backend.h @@ -33,4 +33,7 @@ struct gbm_device * _gbm_create_device(int fd); +void +_gbm_device_destroy(struct gbm_device *gbm); + #endif diff --git a/src/gbm.c b/src/gbm.c index 954b3c3..599f7aa 100644 --- 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, +}; diff --git a/src/gbm.h b/src/gbm.h index d5edb8a..3979232 100644 --- 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 index 0000000..feca099 --- /dev/null +++ b/src/gbm_abi_check.c @@ -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 /* offsetof */ +#include /* 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 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 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 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 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 index 0000000..222ce34 --- /dev/null +++ b/src/gbm_backend_abi.h @@ -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 + * James Jones + */ + +#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 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 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 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 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 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 diff --git a/src/gbmint.h b/src/gbmint.h index 1925774..143b104 100644 --- a/src/gbmint.h +++ b/src/gbmint.h @@ -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,13 +24,13 @@ * * Authors: * Benjamin Franzke + * James Jones */ #ifndef INTERNAL_H_ #define INTERNAL_H_ -#include "gbm.h" -#include +#include "gbm_backend_abi.h" /* GCC visibility */ #if defined(__GNUC__) @@ -43,97 +44,6 @@ * \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 -- 2.7.4