Mesa (main): gbm: Version the GBM backend interface

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jul 6 17:27:20 UTC 2021


Module: Mesa
Branch: main
Commit: 5baa36f4239fb817d1cd32a95d7957f1bf526f1c
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=5baa36f4239fb817d1cd32a95d7957f1bf526f1c

Author: James Jones <jajones at nvidia.com>
Date:   Wed Oct 16 22:16:53 2019 -0700

gbm: Version the GBM backend interface

Define a version number for the interface GBM uses
to offload work to its backends/drivers. Store the
version in the backend interface structs provided
to the loader by backends, as well as in the core
interface struct provided to backends by the GBM
loader code to backends.

The backend can create structures of any version
it supports, which can be greater or less than the
interface version specified by GBM in the core
interface structure. Hence, GBM will need to take
care to check the backend version before accessing
any members added to structs defined in
gbm_backend_abi.h after this change.

Similarly, the backend may need to check the
interface version supported by the GBM library
before passing back data in any structure members
that require the GBM library to interact with
them for correct operation. For example, if for
some reason a structure defined in
gbm_backend_abi.h gained a field which was a
pointer to memory allocated by the backend and
freed by GBM, the backend should avoid allocating
this memory if the GBM library did not specify an
interface version new enough to indicate that it
was aware of the new structure member.

Signed-off-by: James Jones <jajones at nvidia.com>
Reviewed-by: Michel Dänzer <mdaenzer at redhat.com>
Reviewed-by: Emil Velikov <emil.l.velikov at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/9902>

---

 src/egl/drivers/dri2/platform_drm.c |  42 ++++-----
 src/gbm/backends/dri/gbm_dri.c      | 143 ++++++++++++++++--------------
 src/gbm/backends/dri/gbm_driint.h   |   4 +-
 src/gbm/main/backend.c              |  12 ++-
 src/gbm/main/gbm.c                  |  75 ++++++++--------
 src/gbm/main/gbm_backend_abi.h      | 172 +++++++++++++++++++++++++++++++++---
 6 files changed, 306 insertions(+), 142 deletions(-)

diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c
index 8b392f3e788..2b329437f88 100644
--- a/src/egl/drivers/dri2/platform_drm.c
+++ b/src/egl/drivers/dri2/platform_drm.c
@@ -113,7 +113,7 @@ dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
 
    for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
       visual = &dri2_dpy->gbm_dri->visual_table[i];
-      if (visual->gbm_format == surface->format)
+      if (visual->gbm_format == surface->v0.format)
          break;
    }
 
@@ -173,8 +173,8 @@ dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
 
    surf = gbm_dri_surface(surface);
    dri2_surf->gbm_surf = surf;
-   dri2_surf->base.Width =  surf->base.width;
-   dri2_surf->base.Height = surf->base.height;
+   dri2_surf->base.Width =  surf->base.v0.width;
+   dri2_surf->base.Height = surf->base.v0.height;
    surf->dri_private = dri2_surf;
 
    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf))
@@ -244,21 +244,21 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
    if (dri2_surf->back == NULL)
       return -1;
    if (dri2_surf->back->bo == NULL) {
-      if (surf->base.modifiers)
+      if (surf->base.v0.modifiers)
          dri2_surf->back->bo = gbm_bo_create_with_modifiers(&dri2_dpy->gbm_dri->base,
-                                                            surf->base.width,
-                                                            surf->base.height,
-                                                            surf->base.format,
-                                                            surf->base.modifiers,
-                                                            surf->base.count);
+                                                            surf->base.v0.width,
+                                                            surf->base.v0.height,
+                                                            surf->base.v0.format,
+                                                            surf->base.v0.modifiers,
+                                                            surf->base.v0.count);
       else {
-         unsigned flags = surf->base.flags;
+         unsigned flags = surf->base.v0.flags;
          if (dri2_surf->base.ProtectedContent)
             flags |= GBM_BO_USE_PROTECTED;
          dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
-                                             surf->base.width,
-                                             surf->base.height,
-                                             surf->base.format,
+                                             surf->base.v0.width,
+                                             surf->base.v0.height,
+                                             surf->base.v0.format,
                                              flags);
       }
 
@@ -283,8 +283,10 @@ get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
 
    if (dri2_surf->current->bo == NULL)
       dri2_surf->current->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
-                                             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 (dri2_surf->current->bo == NULL)
       return -1;
 
@@ -545,7 +547,7 @@ swrast_put_image2(__DRIdrawable *driDrawable,
    if (gbm_dri_bo_map_dumb(bo) == NULL)
       return;
 
-   internal_stride = bo->base.stride;
+   internal_stride = bo->base.v0.stride;
 
    dst = bo->map + x_bytes + (y * internal_stride);
    src = data;
@@ -587,7 +589,7 @@ swrast_get_image(__DRIdrawable *driDrawable,
    x_bytes = x * (bpp >> 3);
    width_bytes = width * (bpp >> 3);
 
-   internal_stride = bo->base.stride;
+   internal_stride = bo->base.v0.stride;
    stride = width_bytes;
 
    if (gbm_dri_bo_map_dumb(bo) == NULL)
@@ -759,9 +761,9 @@ dri2_initialize_drm(_EGLDisplay *disp)
    dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
    dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
 
-   dri2_dpy->gbm_dri->base.surface_lock_front_buffer = lock_front_buffer;
-   dri2_dpy->gbm_dri->base.surface_release_buffer = release_buffer;
-   dri2_dpy->gbm_dri->base.surface_has_free_buffers = has_free_buffers;
+   dri2_dpy->gbm_dri->base.v0.surface_lock_front_buffer = lock_front_buffer;
+   dri2_dpy->gbm_dri->base.v0.surface_release_buffer = release_buffer;
+   dri2_dpy->gbm_dri->base.v0.surface_has_free_buffers = has_free_buffers;
 
    if (!dri2_setup_extensions(disp)) {
       err = "DRI2: failed to find required DRI extensions";
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index baac0909025..53a1d5bb8ef 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -153,8 +153,8 @@ swrast_get_drawable_info(__DRIdrawable *driDrawable,
 
    *x = 0;
    *y = 0;
-   *width = surf->base.width;
-   *height = surf->base.height;
+   *width = surf->base.v0.width;
+   *height = surf->base.v0.height;
 }
 
 static void
@@ -398,12 +398,12 @@ dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
       return -1;
 
    if (dri->dri2->base.version >= 4) {
-      dri->screen = dri->dri2->createNewScreen2(0, dri->base.fd,
+      dri->screen = dri->dri2->createNewScreen2(0, dri->base.v0.fd,
                                                 dri->loader_extensions,
                                                 dri->driver_extensions,
                                                 &dri->driver_configs, dri);
    } else {
-      dri->screen = dri->dri2->createNewScreen(0, dri->base.fd,
+      dri->screen = dri->dri2->createNewScreen(0, dri->base.v0.fd,
                                                dri->loader_extensions,
                                                &dri->driver_configs, dri);
    }
@@ -471,7 +471,7 @@ dri_screen_create(struct gbm_dri_device *dri)
 {
    char *driver_name;
 
-   driver_name = loader_get_driver_for_fd(dri->base.fd);
+   driver_name = loader_get_driver_for_fd(dri->base.v0.fd);
    if (!driver_name)
       return -1;
 
@@ -576,7 +576,7 @@ static const struct gbm_dri_visual gbm_dri_visuals_table[] = {
 static int
 gbm_format_to_dri_format(uint32_t gbm_format)
 {
-   gbm_format = gbm_core.format_canonicalize(gbm_format);
+   gbm_format = gbm_core.v0.format_canonicalize(gbm_format);
    for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
       if (gbm_dri_visuals_table[i].gbm_format == gbm_format)
          return gbm_dri_visuals_table[i].dri_image_format;
@@ -607,7 +607,7 @@ gbm_dri_is_format_supported(struct gbm_device *gbm,
    if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING))
       return 0;
 
-   format = gbm_core.format_canonicalize(format);
+   format = gbm_core.v0.format_canonicalize(format);
    if (gbm_format_to_dri_format(format) == 0)
       return 0;
 
@@ -644,7 +644,7 @@ gbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm,
        !dri->image->queryDmaBufFormatModifierAttribs)
       return -1;
 
-   format = gbm_core.format_canonicalize(format);
+   format = gbm_core.v0.format_canonicalize(format);
    if (gbm_format_to_dri_format(format) == 0)
       return -1;
 
@@ -725,7 +725,7 @@ gbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane)
       /* Preserve legacy behavior if plane is 0 */
       if (plane == 0) {
          /* NOTE: return _bo->handle, *NOT* bo->handle which is invalid at this point */
-         return _bo->handle;
+         return _bo->v0.handle;
       }
 
       errno = ENOSYS;
@@ -806,7 +806,7 @@ gbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
    if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) {
       /* Preserve legacy behavior if plane is 0 */
       if (plane == 0)
-         return _bo->stride;
+         return _bo->v0.stride;
 
       errno = ENOSYS;
       return 0;
@@ -819,7 +819,7 @@ gbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
 
    if (bo->image == NULL) {
       assert(plane == 0);
-      return _bo->stride;
+      return _bo->v0.stride;
    }
 
    image = dri->image->fromPlanar(bo->image, plane, NULL);
@@ -915,7 +915,7 @@ gbm_dri_bo_destroy(struct gbm_bo *_bo)
       gbm_dri_bo_unmap_dumb(bo);
       memset(&arg, 0, sizeof(arg));
       arg.handle = bo->handle;
-      drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
+      drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
    }
 
    free(bo);
@@ -992,7 +992,7 @@ gbm_dri_bo_import(struct gbm_device *gbm,
       /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
        * tokens accepted by createImageFromFds, except for not supporting
        * the sARGB format. */
-      fourcc = gbm_core.format_canonicalize(fd_data->format);
+      fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
 
       image = dri->image->createImageFromFds(dri->screen,
                                              fd_data->width,
@@ -1025,7 +1025,7 @@ gbm_dri_bo_import(struct gbm_device *gbm,
       /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
        * tokens accepted by createImageFromDmaBufs2, except for not supporting
        * the sARGB format. */
-      fourcc = gbm_core.format_canonicalize(fd_data->format);
+      fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
 
       image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width,
                                                   fd_data->height, fourcc,
@@ -1072,16 +1072,16 @@ gbm_dri_bo_import(struct gbm_device *gbm,
    }
 
    bo->base.gbm = gbm;
-   bo->base.format = gbm_format;
+   bo->base.v0.format = gbm_format;
 
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
-                          (int*)&bo->base.width);
+                          (int*)&bo->base.v0.width);
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
-                          (int*)&bo->base.height);
+                          (int*)&bo->base.v0.height);
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
-                          (int*)&bo->base.stride);
+                          (int*)&bo->base.v0.stride);
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
-                          &bo->base.handle.s32);
+                          &bo->base.v0.handle.s32);
 
    return &bo->base;
 }
@@ -1116,16 +1116,16 @@ create_dumb(struct gbm_device *gbm,
    create_arg.width = width;
    create_arg.height = height;
 
-   ret = drmIoctl(dri->base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
+   ret = drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
    if (ret)
       goto free_bo;
 
    bo->base.gbm = gbm;
-   bo->base.width = width;
-   bo->base.height = height;
-   bo->base.stride = create_arg.pitch;
-   bo->base.format = format;
-   bo->base.handle.u32 = create_arg.handle;
+   bo->base.v0.width = width;
+   bo->base.v0.height = height;
+   bo->base.v0.stride = create_arg.pitch;
+   bo->base.v0.format = format;
+   bo->base.v0.handle.u32 = create_arg.handle;
    bo->handle = create_arg.handle;
    bo->size = create_arg.size;
 
@@ -1137,7 +1137,7 @@ create_dumb(struct gbm_device *gbm,
 destroy_dumb:
    memset(&destroy_arg, 0, sizeof destroy_arg);
    destroy_arg.handle = create_arg.handle;
-   drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+   drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
 free_bo:
    free(bo);
 
@@ -1161,7 +1161,7 @@ gbm_dri_bo_create(struct gbm_device *gbm,
     */
    assert(!(usage && count));
 
-   format = gbm_core.format_canonicalize(format);
+   format = gbm_core.v0.format_canonicalize(format);
 
    if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
       return create_dumb(gbm, width, height, format, usage);
@@ -1171,9 +1171,9 @@ gbm_dri_bo_create(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;
 
    dri_format = gbm_format_to_dri_format(format);
    if (dri_format == 0) {
@@ -1209,9 +1209,9 @@ gbm_dri_bo_create(struct gbm_device *gbm,
       assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID);
 
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
-                          &bo->base.handle.s32);
+                          &bo->base.v0.handle.s32);
    dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
-                          (int *) &bo->base.stride);
+                          (int *) &bo->base.v0.stride);
 
    return &bo->base;
 
@@ -1231,8 +1231,8 @@ gbm_dri_bo_map(struct gbm_bo *_bo,
 
    /* If it's a dumb buffer, we already have a mapping */
    if (bo->map) {
-      *map_data = (char *)bo->map + (bo->base.stride * y) + (x * 4);
-      *stride = bo->base.stride;
+      *map_data = (char *)bo->map + (bo->base.v0.stride * y) + (x * 4);
+      *stride = bo->base.v0.stride;
       return *map_data;
    }
 
@@ -1320,17 +1320,17 @@ gbm_dri_surface_create(struct gbm_device *gbm,
    }
 
    surf->base.gbm = gbm;
-   surf->base.width = width;
-   surf->base.height = height;
-   surf->base.format = gbm_core.format_canonicalize(format);
-   surf->base.flags = flags;
+   surf->base.v0.width = width;
+   surf->base.v0.height = height;
+   surf->base.v0.format = gbm_core.v0.format_canonicalize(format);
+   surf->base.v0.flags = flags;
    if (!modifiers) {
       assert(!count);
       return &surf->base;
    }
 
-   surf->base.modifiers = calloc(count, sizeof(*modifiers));
-   if (count && !surf->base.modifiers) {
+   surf->base.v0.modifiers = calloc(count, sizeof(*modifiers));
+   if (count && !surf->base.v0.modifiers) {
       errno = ENOMEM;
       free(surf);
       return NULL;
@@ -1340,8 +1340,8 @@ gbm_dri_surface_create(struct gbm_device *gbm,
     * created. This deferred creation can fail due to a modifier-format
     * mismatch. The result is the client has a surface but no object to back it.
     */
-   surf->base.count = count;
-   memcpy(surf->base.modifiers, modifiers, count * sizeof(*modifiers));
+   surf->base.v0.count = count;
+   memcpy(surf->base.v0.modifiers, modifiers, count * sizeof(*modifiers));
 
    return &surf->base;
 }
@@ -1351,7 +1351,7 @@ gbm_dri_surface_destroy(struct gbm_surface *_surf)
 {
    struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
 
-   free(surf->base.modifiers);
+   free(surf->base.v0.modifiers);
    free(surf);
 }
 
@@ -1375,38 +1375,46 @@ dri_destroy(struct gbm_device *gbm)
 }
 
 static struct gbm_device *
-dri_device_create(int fd)
+dri_device_create(int fd, uint32_t gbm_backend_version)
 {
    struct gbm_dri_device *dri;
    int ret;
    bool force_sw;
 
+   /*
+    * Since the DRI backend is built-in to the loader, the loader ABI version is
+    * guaranteed to match this backend's ABI version
+    */
+   assert(gbm_core.v0.core_version == GBM_BACKEND_ABI_VERSION);
+   assert(gbm_core.v0.core_version == gbm_backend_version);
+
    dri = calloc(1, sizeof *dri);
    if (!dri)
       return NULL;
 
-   dri->base.fd = fd;
-   dri->base.bo_create = gbm_dri_bo_create;
-   dri->base.bo_import = gbm_dri_bo_import;
-   dri->base.bo_map = gbm_dri_bo_map;
-   dri->base.bo_unmap = gbm_dri_bo_unmap;
-   dri->base.is_format_supported = gbm_dri_is_format_supported;
-   dri->base.get_format_modifier_plane_count =
+   dri->base.v0.fd = fd;
+   dri->base.v0.backend_version = gbm_backend_version;
+   dri->base.v0.bo_create = gbm_dri_bo_create;
+   dri->base.v0.bo_import = gbm_dri_bo_import;
+   dri->base.v0.bo_map = gbm_dri_bo_map;
+   dri->base.v0.bo_unmap = gbm_dri_bo_unmap;
+   dri->base.v0.is_format_supported = gbm_dri_is_format_supported;
+   dri->base.v0.get_format_modifier_plane_count =
       gbm_dri_get_format_modifier_plane_count;
-   dri->base.bo_write = gbm_dri_bo_write;
-   dri->base.bo_get_fd = gbm_dri_bo_get_fd;
-   dri->base.bo_get_planes = gbm_dri_bo_get_planes;
-   dri->base.bo_get_handle = gbm_dri_bo_get_handle_for_plane;
-   dri->base.bo_get_plane_fd = gbm_dri_bo_get_plane_fd;
-   dri->base.bo_get_stride = gbm_dri_bo_get_stride;
-   dri->base.bo_get_offset = gbm_dri_bo_get_offset;
-   dri->base.bo_get_modifier = gbm_dri_bo_get_modifier;
-   dri->base.bo_destroy = gbm_dri_bo_destroy;
-   dri->base.destroy = dri_destroy;
-   dri->base.surface_create = gbm_dri_surface_create;
-   dri->base.surface_destroy = gbm_dri_surface_destroy;
-
-   dri->base.name = "drm";
+   dri->base.v0.bo_write = gbm_dri_bo_write;
+   dri->base.v0.bo_get_fd = gbm_dri_bo_get_fd;
+   dri->base.v0.bo_get_planes = gbm_dri_bo_get_planes;
+   dri->base.v0.bo_get_handle = gbm_dri_bo_get_handle_for_plane;
+   dri->base.v0.bo_get_plane_fd = gbm_dri_bo_get_plane_fd;
+   dri->base.v0.bo_get_stride = gbm_dri_bo_get_stride;
+   dri->base.v0.bo_get_offset = gbm_dri_bo_get_offset;
+   dri->base.v0.bo_get_modifier = gbm_dri_bo_get_modifier;
+   dri->base.v0.bo_destroy = gbm_dri_bo_destroy;
+   dri->base.v0.destroy = dri_destroy;
+   dri->base.v0.surface_create = gbm_dri_surface_create;
+   dri->base.v0.surface_destroy = gbm_dri_surface_destroy;
+
+   dri->base.v0.name = "drm";
 
    dri->visual_table = gbm_dri_visuals_table;
    dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table);
@@ -1434,6 +1442,7 @@ err_dri:
 }
 
 struct gbm_backend gbm_dri_backend = {
-   .backend_name = "dri",
-   .create_device = dri_device_create,
+   .v0.backend_version = GBM_BACKEND_ABI_VERSION,
+   .v0.backend_name = "dri",
+   .v0.create_device = dri_device_create,
 };
diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h
index d321fe2be07..9e77ba5887c 100644
--- a/src/gbm/backends/dri/gbm_driint.h
+++ b/src/gbm/backends/dri/gbm_driint.h
@@ -170,12 +170,12 @@ gbm_dri_bo_map_dumb(struct gbm_dri_bo *bo)
    memset(&map_arg, 0, sizeof(map_arg));
    map_arg.handle = bo->handle;
 
-   ret = drmIoctl(bo->base.gbm->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
+   ret = drmIoctl(bo->base.gbm->v0.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
    if (ret)
       return NULL;
 
    bo->map = mmap(0, bo->size, PROT_WRITE,
-                  MAP_SHARED, bo->base.gbm->fd, map_arg.offset);
+                  MAP_SHARED, bo->base.gbm->v0.fd, map_arg.offset);
    if (bo->map == MAP_FAILED) {
       bo->map = NULL;
       return NULL;
diff --git a/src/gbm/main/backend.c b/src/gbm/main/backend.c
index f22600b9d8b..c5824a1a392 100644
--- a/src/gbm/main/backend.c
+++ b/src/gbm/main/backend.c
@@ -30,10 +30,12 @@
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#include <assert.h>
 
 #include "backend.h"
 
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#define VER_MIN(a, b) ((a) < (b) ? (a) : (b))
 
 extern const struct gbm_backend gbm_dri_backend;
 
@@ -51,15 +53,19 @@ find_backend(const char *name, int fd)
 {
    struct gbm_device *dev = NULL;
    unsigned i;
+   uint32_t abi_ver;
 
    for (i = 0; i < ARRAY_SIZE(backends); ++i) {
       if (name && strcmp(backends[i].name, name))
          continue;
 
-      dev = backends[i].backend->create_device(fd);
+      abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION,
+                        backends[i].backend->v0.backend_version);
+      dev = backends[i].backend->v0.create_device(fd, abi_ver);
 
       if (dev) {
-         dev->backend_desc = &backends[i];
+         assert(abi_ver == dev->v0.backend_version);
+         dev->v0.backend_desc = &backends[i];
          break;
       }
    }
@@ -96,5 +102,5 @@ _gbm_create_device(int fd)
 void
 _gbm_device_destroy(struct gbm_device *gbm)
 {
-   gbm->destroy(gbm);
+   gbm->v0.destroy(gbm);
 }
diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c
index 8831350257c..d81931a7483 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/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,7 +63,7 @@ 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.
@@ -82,7 +82,7 @@ GBM_EXPORT int
 gbm_device_is_format_supported(struct gbm_device *gbm,
                                uint32_t format, uint32_t usage)
 {
-   return gbm->is_format_supported(gbm, format, usage);
+   return gbm->v0.is_format_supported(gbm, format, usage);
 }
 
 /** Get the number of planes that are required for a given format+modifier
@@ -96,7 +96,7 @@ 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.
@@ -150,7 +150,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
@@ -161,7 +161,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
@@ -188,7 +188,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
@@ -201,7 +201,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
@@ -219,7 +219,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:
@@ -285,7 +285,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
@@ -310,7 +310,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
@@ -327,7 +327,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.
@@ -338,7 +338,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
@@ -356,7 +356,7 @@ 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
@@ -376,7 +376,7 @@ gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane)
 GBM_EXPORT int
 gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane)
 {
-   return bo->gbm->bo_get_plane_fd(bo, plane);
+   return bo->gbm->v0.bo_get_plane_fd(bo, plane);
 }
 
 /**
@@ -395,7 +395,7 @@ gbm_bo_get_fd_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
@@ -414,7 +414,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
@@ -428,8 +428,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
@@ -443,7 +443,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;
 }
 
 /**
@@ -455,10 +455,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);
 }
 
 /**
@@ -487,7 +487,7 @@ gbm_bo_create(struct gbm_device *gbm,
       return NULL;
    }
 
-   return gbm->bo_create(gbm, width, height, format, usage, NULL, 0);
+   return gbm->v0.bo_create(gbm, width, height, format, usage, NULL, 0);
 }
 
 GBM_EXPORT struct gbm_bo *
@@ -507,7 +507,7 @@ gbm_bo_create_with_modifiers(struct gbm_device *gbm,
       return NULL;
    }
 
-   return gbm->bo_create(gbm, width, height, format, 0, modifiers, count);
+   return gbm->v0.bo_create(gbm, width, height, format, 0, modifiers, count);
 }
 
 /**
@@ -541,7 +541,7 @@ GBM_EXPORT struct gbm_bo *
 gbm_bo_import(struct gbm_device *gbm,
               uint32_t type, void *buffer, uint32_t usage)
 {
-   return gbm->bo_import(gbm, type, buffer, usage);
+   return gbm->v0.bo_import(gbm, type, buffer, usage);
 }
 
 /**
@@ -583,8 +583,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);
 }
 
 /**
@@ -599,7 +599,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);
 }
 
 /**
@@ -621,7 +621,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 *
@@ -636,8 +636,8 @@ gbm_surface_create_with_modifiers(struct gbm_device *gbm,
       return NULL;
    }
 
-   return gbm->surface_create(gbm, width, height, format, 0,
-                              modifiers, count);
+   return gbm->v0.surface_create(gbm, width, height, format, 0,
+                                 modifiers, count);
 }
 
 /**
@@ -652,7 +652,7 @@ gbm_surface_create_with_modifiers(struct gbm_device *gbm,
 GBM_EXPORT void
 gbm_surface_destroy(struct gbm_surface *surf)
 {
-   surf->gbm->surface_destroy(surf);
+   surf->gbm->v0.surface_destroy(surf);
 }
 
 /**
@@ -679,7 +679,7 @@ gbm_surface_destroy(struct gbm_surface *surf)
 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);
 }
 
 /**
@@ -697,7 +697,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);
 }
 
 /**
@@ -719,7 +719,7 @@ 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_*
@@ -763,5 +763,6 @@ gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc)
  * code that need to be accessed directly by GBM backends.
  */
 struct gbm_core gbm_core = {
-   .format_canonicalize = format_canonicalize,
+   .v0.core_version = GBM_BACKEND_ABI_VERSION,
+   .v0.format_canonicalize = format_canonicalize,
 };
diff --git a/src/gbm/main/gbm_backend_abi.h b/src/gbm/main/gbm_backend_abi.h
index 6b802826306..1bf73b75120 100644
--- a/src/gbm/main/gbm_backend_abi.h
+++ b/src/gbm/main/gbm_backend_abi.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,6 +24,7 @@
  *
  * Authors:
  *    Benjamin Franzke <benjaminfranzke at googlemail.com>
+ *    James Jones <jajones at nvidia.com>
  */
 
 #ifndef GBM_BACKEND_ABI_H_
@@ -38,16 +40,68 @@
 struct gbm_backend_desc;
 
 /**
- * The device used for the memory allocation.
+ * The GBM backend interface version defined by this file.
  *
- * The members of this structure should be not accessed directly
+ * 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
  */
-struct gbm_device {
-   /* Hack to make a gbm_device detectable by its first element. */
-   struct gbm_device *(*dummy)(int);
+#define GBM_BACKEND_ABI_VERSION 0
 
+/**
+ * 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;
 
@@ -96,12 +150,26 @@ struct gbm_device {
 };
 
 /**
- * The allocated buffer object.
+ * The device used for the memory allocation.
  *
- * The members in this structure should not be accessed directly.
+ * 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_bo {
-   struct gbm_device *gbm;
+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;
@@ -111,8 +179,26 @@ struct gbm_bo {
    void (*destroy_user_data)(struct gbm_bo *, void *);
 };
 
-struct gbm_surface {
+/**
+ * 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;
@@ -123,13 +209,73 @@ struct gbm_surface {
    };
 };
 
-struct gbm_backend {
+/**
+ * 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);
+   struct gbm_device *(*create_device)(int fd, uint32_t gbm_backend_version);
 };
 
-struct gbm_core {
+/**
+ * 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;
+};
+
 #endif



More information about the mesa-commit mailing list