1/*
2 * Copyright © 2021 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#include "gbm_backend_abi.h" /* Current GBM backend ABI implementation */
26
27#include <stddef.h> /* offsetof */
28#include <stdio.h> /* printf */
29
30/*
31 * The following are previous implementations of the structures defined in
32 * gbm_backend_abi.h, with their ABI version appended.
33 *
34 * DO NOT EVER CHANGE EXISTING DEFINITIONS HERE!
35 *
36 * Changing them implies breaking the GBM backend ABI. Instead, to extend the
37 * ABI, in gbm_backend_abi.h:
38 *
39 * -Add a new versioned struct
40 * -Append it to the associated top-level object's struct
41 * -Increment GBM_BACKEND_ABI_VERSION
42 *
43 * Then, here:
44 *
45 * -Add a new block of definitions below for the new ABI content
46 * -Add a new block of checks in main()
47 */
48
49/*
50 * From: Simon Ser - "gbm: assume USE_SCANOUT in create_with_modifiers"
51 *
52 * Note: ABI 1 is identical to ABI 0, except gbm_device_v0.bo_create can
53 * provide both modifiers and usage.
54 */
55#define GBM_BACKEND_ABI_VERSION_abi0 1
56struct gbm_device_v0_abi0 {
57   const struct gbm_backend_desc *backend_desc;
58   uint32_t backend_version;
59   int fd;
60   const char *name;
61   void (*destroy)(struct gbm_device *gbm);
62   int (*is_format_supported)(struct gbm_device *gbm,
63                              uint32_t format,
64                              uint32_t usage);
65   int (*get_format_modifier_plane_count)(struct gbm_device *device,
66                                          uint32_t format,
67                                          uint64_t modifier);
68   struct gbm_bo *(*bo_create)(struct gbm_device *gbm,
69                               uint32_t width, uint32_t height,
70                               uint32_t format,
71                               uint32_t usage,
72                               const uint64_t *modifiers,
73                               const unsigned int count);
74   struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
75                               void *buffer, uint32_t usage);
76   void *(*bo_map)(struct gbm_bo *bo,
77                               uint32_t x, uint32_t y,
78                               uint32_t width, uint32_t height,
79                               uint32_t flags, uint32_t *stride,
80                               void **map_data);
81   void (*bo_unmap)(struct gbm_bo *bo, void *map_data);
82   int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
83   int (*bo_get_fd)(struct gbm_bo *bo);
84   int (*bo_get_planes)(struct gbm_bo *bo);
85   union gbm_bo_handle (*bo_get_handle)(struct gbm_bo *bo, int plane);
86   int (*bo_get_plane_fd)(struct gbm_bo *bo, int plane);
87   uint32_t (*bo_get_stride)(struct gbm_bo *bo, int plane);
88   uint32_t (*bo_get_offset)(struct gbm_bo *bo, int plane);
89   uint64_t (*bo_get_modifier)(struct gbm_bo *bo);
90   void (*bo_destroy)(struct gbm_bo *bo);
91   struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
92                                         uint32_t width, uint32_t height,
93                                         uint32_t format, uint32_t flags,
94                                         const uint64_t *modifiers,
95                                         const unsigned count);
96   struct gbm_bo *(*surface_lock_front_buffer)(struct gbm_surface *surface);
97   void (*surface_release_buffer)(struct gbm_surface *surface,
98                                  struct gbm_bo *bo);
99   int (*surface_has_free_buffers)(struct gbm_surface *surface);
100   void (*surface_destroy)(struct gbm_surface *surface);
101};
102
103struct gbm_device_abi0 {
104   /* Hack to make a gbm_device detectable by its first element. */
105   struct gbm_device *(*dummy)(int);
106   struct gbm_device_v0_abi0 v0;
107};
108
109/**
110 * GBM buffer object interface corresponding to GBM_BACKEND_ABI_VERSION = 0
111 *
112 * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_bo_v1, increment
113 * GBM_BACKEND_ABI_VERSION, and append gbm_bo_v1 to gbm_bo.
114 */
115struct gbm_bo_v0_abi0 {
116   uint32_t width;
117   uint32_t height;
118   uint32_t stride;
119   uint32_t format;
120   union gbm_bo_handle  handle;
121   void *user_data;
122   void (*destroy_user_data)(struct gbm_bo *, void *);
123};
124
125/**
126 * The allocated buffer object.
127 *
128 * The members in this structure should not be accessed directly.
129 *
130 * To modify this structure, introduce a new gbm_bo_v<N> structure, add it to
131 * the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
132 */
133struct gbm_bo_abi0 {
134   struct gbm_device *gbm;
135   struct gbm_bo_v0_abi0 v0;
136};
137
138/**
139 * GBM surface interface corresponding to GBM_BACKEND_ABI_VERSION = 0
140 *
141 * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_surface_v1, increment
142 * GBM_BACKEND_ABI_VERSION, and append gbm_surface_v1 to gbm_surface.
143 */
144struct gbm_surface_v0_abi0 {
145   uint32_t width;
146   uint32_t height;
147   uint32_t format;
148   uint32_t flags;
149   struct {
150      uint64_t *modifiers;
151      unsigned count;
152   };
153};
154
155/**
156 * An allocated GBM surface.
157 *
158 * To modify this structure, introduce a new gbm_surface_v<N> structure, add it
159 * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
160 */
161struct gbm_surface_abi0 {
162   struct gbm_device *gbm;
163   struct gbm_surface_v0_abi0 v0;
164};
165
166/**
167 * GBM backend interfaces corresponding to GBM_BACKEND_ABI_VERSION = 0
168 *
169 * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_backend_v1, increment
170 * GBM_BACKEND_ABI_VERSION, append gbm_backend_v1 to gbm_backend.
171 */
172struct gbm_backend_v0_abi0 {
173   /**
174    * The version of the GBM backend interface supported by this backend. This
175    * is set by the backend itself, and may be greater or less than the version
176    * supported by the loader. It is the responsibility of the GBM loader to
177    * respect this version when accessing fields in this structure.
178    */
179   uint32_t backend_version;
180
181   const char *backend_name;
182   struct gbm_device *(*create_device)(int fd, uint32_t gbm_backend_version);
183};
184
185/**
186 * The interface exposed by an external GBM backend.
187 *
188 * To modify this structure, introduce a new gbm_backend_v<N> structure, add it
189 * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
190 */
191struct gbm_backend_abi0 {
192   struct gbm_backend_v0_abi0 v0;
193};
194
195/**
196 * GBM interfaces exposed to GBM backends at GBM_BACKEND_ABI_VERSION >= 0
197 *
198 * DO NOT MODIFY THIS STRUCT. Instead, introduce a gbm_core_v1, increment
199 * GBM_BACKEND_ABI_VERSION, and append gbm_core_v1 to gbm_backend.
200 */
201struct gbm_core_v0_abi0 {
202   /**
203    * The version of the GBM backend interface supported by the GBM loader. This
204    * is set by the loader, and may be greater or less than the version
205    * supported by a given backend. It is the responsibility of the backend to
206    * respect this version when accessing fields in this structure and other
207    * structures allocated or modified by the loader.
208    */
209   uint32_t core_version;
210
211   uint32_t (*format_canonicalize)(uint32_t gbm_format);
212};
213
214/**
215 * The interface exposed by the GBM core/loader code to GBM backends.
216 *
217 * To modify this structure, introduce a new gbm_core_v<N> structure, add it
218 * to the end of this structure, and increment GBM_BACKEND_ABI_VERSION.
219 */
220struct gbm_core_abi0 {
221   struct gbm_core_v0_abi0 v0;
222};
223
224typedef const struct gbm_backend *(*GBM_GET_BACKEND_PROC_PTR_abi0)(const struct gbm_core *gbm_core);
225
226/*
227 * Structure/member ABI-checking helper macros
228 */
229#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
230
231#define CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member)     \
232   do {                                                                       \
233      if (offsetof(struct type ## a_ver, a_member) !=                         \
234          offsetof(struct type ## b_ver, b_member)) {                         \
235         printf("Backards incompatible change detected!\n   "                 \
236                "offsetof(struct " #type #a_ver "::" #a_member ") != "        \
237                "offsetof(struct " #type #b_ver "::" #b_member ")\n");        \
238         return 1;                                                            \
239      }                                                                       \
240                                                                              \
241      if (MEMBER_SIZE(struct type ## a_ver, a_member) !=                      \
242          MEMBER_SIZE(struct type ## b_ver, b_member)) {                      \
243         printf("Backards incompatible change detected!\n   "                 \
244                "MEMBER_SIZE(struct " #type #a_ver "::" #a_member ") != "     \
245                "MEMBER_SIZE(struct " #type #b_ver "::" #b_member ")\n");     \
246         return 1;                                                            \
247      }                                                                       \
248   } while (0)
249
250#define CHECK_RENAMED_MEMBER_TYPE(type, a_ver, b_ver, a_member, b_member)     \
251   do {                                                                       \
252      /* Compile-time type compatibility check */                             \
253      struct type ## a_ver a;                                                 \
254      struct type ## b_ver b = {0};                                           \
255      a.a_member = b.b_member;                                                \
256      (void)a;                                                                \
257   } while (0)
258
259#define CHECK_RENAMED_MEMBER(type, a_ver, b_ver, a_member, b_member)          \
260   do {                                                                       \
261      CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member);      \
262      CHECK_RENAMED_MEMBER_TYPE(type, a_ver, b_ver, a_member, b_member);      \
263   } while (0)
264#define CHECK_RENAMED_MEMBER_NO_TYPE(type, a_ver, b_ver, a_member, b_member)  \
265      CHECK_RENAMED_MEMBER_BASE(type, a_ver, b_ver, a_member, b_member);
266
267#define CHECK_MEMBER(type, a_ver, b_ver, member) \
268   CHECK_RENAMED_MEMBER(type, a_ver, b_ver, member, member)
269#define CHECK_MEMBER_NO_TYPE(type, a_ver, b_ver, member) \
270   CHECK_RENAMED_MEMBER_NO_TYPE(type, a_ver, b_ver, member, member)
271#define CHECK_MEMBER_CURRENT(type, a_ver, member) \
272   CHECK_MEMBER(type, a_ver,, member)
273#define CHECK_MEMBER_CURRENT_NO_TYPE(type, a_ver, member) \
274   CHECK_MEMBER_NO_TYPE(type, a_ver,, member)
275
276#define CHECK_SIZE(type, a_ver, b_ver)                                     \
277   do {                                                                    \
278      if (sizeof(struct type ## a_ver) >                                   \
279          sizeof(struct type ## b_ver)) {                                  \
280         printf("Backards incompatible change detected!\n   "              \
281                "sizeof(struct " #type #a_ver ") > "                       \
282                "sizeof(struct " #type #b_ver ")\n");                      \
283         return 1;                                                         \
284      }                                                                    \
285   } while (0)
286
287#define CHECK_SIZE_CURRENT(type, a_ver)                                    \
288   do {                                                                    \
289      if (sizeof(struct type ## a_ver) !=                                  \
290          sizeof(struct type)) {                                           \
291         printf("Backards incompatible change detected!\n   "              \
292                "sizeof(struct " #type #a_ver ") != "                      \
293                "sizeof(struct " #type ")\n");                             \
294         return 1;                                                         \
295      }                                                                    \
296   } while (0)
297
298#define CHECK_VERSION(a_ver, b_ver)                                        \
299   do {                                                                    \
300      if ((GBM_BACKEND_ABI_VERSION ## a_ver) >=                            \
301          (GBM_BACKEND_ABI_VERSION ## b_ver)) {                            \
302         printf("Backards incompatible change detected!\n   "              \
303                "GBM_BACKEND_ABI_VERSION" #a_ver " >= "                    \
304                "GBM_BACKEND_ABI_VERSION" #b_ver "\n");                    \
305         return 1;                                                         \
306      }                                                                    \
307   } while (0)
308
309#define CHECK_VERSION_CURRENT(a_ver)                                       \
310   do {                                                                    \
311      if ((GBM_BACKEND_ABI_VERSION ## a_ver) !=                            \
312          (GBM_BACKEND_ABI_VERSION)) {                                     \
313         printf("Backards incompatible change detected!\n   "              \
314                "GBM_BACKEND_ABI_VERSION" #a_ver " != "                    \
315                "GBM_BACKEND_ABI_VERSION\n");                              \
316         return 1;                                                         \
317      }                                                                    \
318   } while (0)
319
320#define CHECK_PROC(proc, a_ver, b_ver)                                     \
321   do {                                                                    \
322      proc ## a_ver a;                                                     \
323      proc ## b_ver b = NULL;                                              \
324      a = b;                                                               \
325      (void)a;                                                             \
326   } while (0)
327
328#define CHECK_PROC_CURRENT(proc, a_ver)                                    \
329   CHECK_PROC(proc, a_ver,)
330
331int main(int argc, char **argv)
332{
333   /********************************************/
334   /*** Compare Current ABI to ABI version 0 ***/
335   /********************************************/
336
337   /* Check current gbm_device ABI against gbm_device_abi0*/
338   CHECK_MEMBER_CURRENT(gbm_device, _abi0, dummy);
339   CHECK_MEMBER_CURRENT_NO_TYPE(gbm_device, _abi0, v0);
340
341   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, backend_desc);
342   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, backend_version);
343   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, fd);
344   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, name);
345   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, destroy);
346   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, is_format_supported);
347   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, get_format_modifier_plane_count);
348   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_create);
349   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_import);
350   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_map);
351   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_unmap);
352   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_write);
353   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_fd);
354   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_planes);
355   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_handle);
356   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_plane_fd);
357   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_stride);
358   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_offset);
359   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_get_modifier);
360   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, bo_destroy);
361   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_create);
362   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_lock_front_buffer);
363   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_release_buffer);
364   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_has_free_buffers);
365   CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_destroy);
366
367   /* Size of ABI-versioned substructures verified by above member checks */
368   CHECK_SIZE_CURRENT  (gbm_device, _abi0);
369
370
371   /* Check current gbm_bo ABI against gbm_bo_abi0*/
372   CHECK_MEMBER_CURRENT(gbm_bo, _abi0, gbm);
373   CHECK_MEMBER_CURRENT_NO_TYPE(gbm_bo, _abi0, v0);
374
375   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, width);
376   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, height);
377   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, stride);
378   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, format);
379   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, handle);
380   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, user_data);
381   CHECK_MEMBER_CURRENT(gbm_bo_v0, _abi0, destroy_user_data);
382
383   /* Size of ABI-versioned substructures verified by above member checks */
384   CHECK_SIZE_CURRENT  (gbm_bo, _abi0);
385
386
387   /* Check current gbm_surface ABI against gbm_surface_abi0 */
388   CHECK_MEMBER_CURRENT(gbm_surface, _abi0, gbm);
389   CHECK_MEMBER_CURRENT_NO_TYPE(gbm_surface, _abi0, v0);
390
391   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, width);
392   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, height);
393   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, format);
394   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, flags);
395   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, modifiers);
396   CHECK_MEMBER_CURRENT(gbm_surface_v0, _abi0, count);
397
398   /* Size of ABI-versioned substructures verified by above member checks */
399   CHECK_SIZE_CURRENT  (gbm_surface, _abi0);
400
401
402   /* Check current gbm_backend ABI against gbm_backend_abi0 */
403   CHECK_MEMBER_CURRENT_NO_TYPE(gbm_backend, _abi0, v0);
404
405   CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, backend_version);
406   CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, backend_name);
407   CHECK_MEMBER_CURRENT(gbm_backend_v0, _abi0, create_device);
408
409   /* Size of ABI-versioned substructures verified by above member checks */
410   CHECK_SIZE_CURRENT  (gbm_backend, _abi0);
411
412
413   /* Check current gbm_core ABI against gbm_core_abi0 */
414   CHECK_MEMBER_CURRENT_NO_TYPE(gbm_core, _abi0, v0);
415
416   CHECK_MEMBER_CURRENT(gbm_core_v0, _abi0, core_version);
417   CHECK_MEMBER_CURRENT(gbm_core_v0, _abi0, format_canonicalize);
418
419   /* Size of ABI-versioned substructures verified by above member checks */
420   CHECK_SIZE_CURRENT  (gbm_core, _abi0);
421
422
423   CHECK_PROC_CURRENT  (GBM_GET_BACKEND_PROC_PTR, _abi0);
424
425   return 0;
426}
427