1848b8605Smrg/*
2848b8605Smrg * Copyright © 2011 Intel Corporation
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice (including the next
12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
13848b8605Smrg * Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16848b8605Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18848b8605Smrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19848b8605Smrg * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22848b8605Smrg * DEALINGS IN THE SOFTWARE.
23848b8605Smrg *
24848b8605Smrg * Authors:
25848b8605Smrg *    Benjamin Franzke <benjaminfranzke@googlemail.com>
26848b8605Smrg */
27848b8605Smrg
28848b8605Smrg#include <stdio.h>
29848b8605Smrg#include <stdlib.h>
30848b8605Smrg#include <stddef.h>
31848b8605Smrg#include <stdint.h>
32b8e80941Smrg#include <stdbool.h>
33848b8605Smrg#include <string.h>
34848b8605Smrg#include <errno.h>
35848b8605Smrg#include <limits.h>
36b8e80941Smrg#include <assert.h>
37848b8605Smrg
38848b8605Smrg#include <sys/types.h>
39848b8605Smrg#include <unistd.h>
40848b8605Smrg#include <dlfcn.h>
41848b8605Smrg#include <xf86drm.h>
42b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
43848b8605Smrg
44848b8605Smrg#include <GL/gl.h> /* dri_interface needs GL types */
45848b8605Smrg#include <GL/internal/dri_interface.h>
46848b8605Smrg
47848b8605Smrg#include "gbm_driint.h"
48848b8605Smrg
49848b8605Smrg#include "gbmint.h"
50848b8605Smrg#include "loader.h"
51b8e80941Smrg#include "util/debug.h"
52b8e80941Smrg#include "util/macros.h"
53848b8605Smrg
54848b8605Smrg/* For importing wl_buffer */
55848b8605Smrg#if HAVE_WAYLAND_PLATFORM
56b8e80941Smrg#include "wayland-drm.h"
57848b8605Smrg#endif
58848b8605Smrg
59848b8605Smrgstatic __DRIimage *
60848b8605Smrgdri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
61848b8605Smrg{
62848b8605Smrg   struct gbm_dri_device *dri = data;
63848b8605Smrg
64848b8605Smrg   if (dri->lookup_image == NULL)
65848b8605Smrg      return NULL;
66848b8605Smrg
67848b8605Smrg   return dri->lookup_image(screen, image, dri->lookup_user_data);
68848b8605Smrg}
69848b8605Smrg
70848b8605Smrgstatic __DRIbuffer *
71848b8605Smrgdri_get_buffers(__DRIdrawable * driDrawable,
72848b8605Smrg		 int *width, int *height,
73848b8605Smrg		 unsigned int *attachments, int count,
74848b8605Smrg		 int *out_count, void *data)
75848b8605Smrg{
76848b8605Smrg   struct gbm_dri_surface *surf = data;
77848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
78848b8605Smrg
79848b8605Smrg   if (dri->get_buffers == NULL)
80848b8605Smrg      return NULL;
81848b8605Smrg
82848b8605Smrg   return dri->get_buffers(driDrawable, width, height, attachments,
83848b8605Smrg                           count, out_count, surf->dri_private);
84848b8605Smrg}
85848b8605Smrg
86848b8605Smrgstatic void
87848b8605Smrgdri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
88848b8605Smrg{
89848b8605Smrg   struct gbm_dri_surface *surf = data;
90848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
91848b8605Smrg
92848b8605Smrg   if (dri->flush_front_buffer != NULL)
93848b8605Smrg      dri->flush_front_buffer(driDrawable, surf->dri_private);
94848b8605Smrg}
95848b8605Smrg
96848b8605Smrgstatic __DRIbuffer *
97848b8605Smrgdri_get_buffers_with_format(__DRIdrawable * driDrawable,
98848b8605Smrg                            int *width, int *height,
99848b8605Smrg                            unsigned int *attachments, int count,
100848b8605Smrg                            int *out_count, void *data)
101848b8605Smrg{
102848b8605Smrg   struct gbm_dri_surface *surf = data;
103848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
104848b8605Smrg
105848b8605Smrg   if (dri->get_buffers_with_format == NULL)
106848b8605Smrg      return NULL;
107848b8605Smrg
108848b8605Smrg   return
109848b8605Smrg      dri->get_buffers_with_format(driDrawable, width, height, attachments,
110848b8605Smrg                                   count, out_count, surf->dri_private);
111848b8605Smrg}
112848b8605Smrg
113848b8605Smrgstatic int
114848b8605Smrgimage_get_buffers(__DRIdrawable *driDrawable,
115848b8605Smrg                  unsigned int format,
116848b8605Smrg                  uint32_t *stamp,
117848b8605Smrg                  void *loaderPrivate,
118848b8605Smrg                  uint32_t buffer_mask,
119848b8605Smrg                  struct __DRIimageList *buffers)
120848b8605Smrg{
121848b8605Smrg   struct gbm_dri_surface *surf = loaderPrivate;
122848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
123848b8605Smrg
124848b8605Smrg   if (dri->image_get_buffers == NULL)
125848b8605Smrg      return 0;
126848b8605Smrg
127848b8605Smrg   return dri->image_get_buffers(driDrawable, format, stamp,
128848b8605Smrg                                 surf->dri_private, buffer_mask, buffers);
129848b8605Smrg}
130848b8605Smrg
131848b8605Smrgstatic void
132848b8605Smrgswrast_get_drawable_info(__DRIdrawable *driDrawable,
133848b8605Smrg                         int           *x,
134848b8605Smrg                         int           *y,
135848b8605Smrg                         int           *width,
136848b8605Smrg                         int           *height,
137848b8605Smrg                         void          *loaderPrivate)
138848b8605Smrg{
139848b8605Smrg   struct gbm_dri_surface *surf = loaderPrivate;
140848b8605Smrg
141848b8605Smrg   *x = 0;
142848b8605Smrg   *y = 0;
143848b8605Smrg   *width = surf->base.width;
144848b8605Smrg   *height = surf->base.height;
145848b8605Smrg}
146848b8605Smrg
147848b8605Smrgstatic void
148848b8605Smrgswrast_put_image2(__DRIdrawable *driDrawable,
149848b8605Smrg                  int            op,
150848b8605Smrg                  int            x,
151848b8605Smrg                  int            y,
152848b8605Smrg                  int            width,
153848b8605Smrg                  int            height,
154848b8605Smrg                  int            stride,
155848b8605Smrg                  char          *data,
156848b8605Smrg                  void          *loaderPrivate)
157848b8605Smrg{
158848b8605Smrg   struct gbm_dri_surface *surf = loaderPrivate;
159848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
160848b8605Smrg
161848b8605Smrg   dri->swrast_put_image2(driDrawable,
162848b8605Smrg                          op, x, y,
163848b8605Smrg                          width, height, stride,
164848b8605Smrg                          data, surf->dri_private);
165848b8605Smrg}
166848b8605Smrg
167848b8605Smrgstatic void
168848b8605Smrgswrast_put_image(__DRIdrawable *driDrawable,
169848b8605Smrg                 int            op,
170848b8605Smrg                 int            x,
171848b8605Smrg                 int            y,
172848b8605Smrg                 int            width,
173848b8605Smrg                 int            height,
174848b8605Smrg                 char          *data,
175848b8605Smrg                 void          *loaderPrivate)
176848b8605Smrg{
177848b8605Smrg   swrast_put_image2(driDrawable, op, x, y, width, height,
178b8e80941Smrg                            width * 4, data, loaderPrivate);
179848b8605Smrg}
180848b8605Smrg
181848b8605Smrgstatic void
182848b8605Smrgswrast_get_image(__DRIdrawable *driDrawable,
183848b8605Smrg                 int            x,
184848b8605Smrg                 int            y,
185848b8605Smrg                 int            width,
186848b8605Smrg                 int            height,
187848b8605Smrg                 char          *data,
188848b8605Smrg                 void          *loaderPrivate)
189848b8605Smrg{
190848b8605Smrg   struct gbm_dri_surface *surf = loaderPrivate;
191848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
192848b8605Smrg
193848b8605Smrg   dri->swrast_get_image(driDrawable,
194848b8605Smrg                         x, y,
195848b8605Smrg                         width, height,
196848b8605Smrg                         data, surf->dri_private);
197848b8605Smrg}
198848b8605Smrg
199848b8605Smrgstatic const __DRIuseInvalidateExtension use_invalidate = {
200848b8605Smrg   .base = { __DRI_USE_INVALIDATE, 1 }
201848b8605Smrg};
202848b8605Smrg
203848b8605Smrgstatic const __DRIimageLookupExtension image_lookup_extension = {
204848b8605Smrg   .base = { __DRI_IMAGE_LOOKUP, 1 },
205848b8605Smrg
206848b8605Smrg   .lookupEGLImage          = dri_lookup_egl_image
207848b8605Smrg};
208848b8605Smrg
209848b8605Smrgstatic const __DRIdri2LoaderExtension dri2_loader_extension = {
210848b8605Smrg   .base = { __DRI_DRI2_LOADER, 3 },
211848b8605Smrg
212848b8605Smrg   .getBuffers              = dri_get_buffers,
213848b8605Smrg   .flushFrontBuffer        = dri_flush_front_buffer,
214848b8605Smrg   .getBuffersWithFormat    = dri_get_buffers_with_format,
215848b8605Smrg};
216848b8605Smrg
217848b8605Smrgstatic const __DRIimageLoaderExtension image_loader_extension = {
218848b8605Smrg   .base = { __DRI_IMAGE_LOADER, 1 },
219848b8605Smrg
220848b8605Smrg   .getBuffers          = image_get_buffers,
221848b8605Smrg   .flushFrontBuffer    = dri_flush_front_buffer,
222848b8605Smrg};
223848b8605Smrg
224848b8605Smrgstatic const __DRIswrastLoaderExtension swrast_loader_extension = {
225848b8605Smrg   .base = { __DRI_SWRAST_LOADER, 2 },
226848b8605Smrg
227848b8605Smrg   .getDrawableInfo = swrast_get_drawable_info,
228848b8605Smrg   .putImage        = swrast_put_image,
229848b8605Smrg   .getImage        = swrast_get_image,
230848b8605Smrg   .putImage2       = swrast_put_image2
231848b8605Smrg};
232848b8605Smrg
233848b8605Smrgstatic const __DRIextension *gbm_dri_screen_extensions[] = {
234848b8605Smrg   &image_lookup_extension.base,
235848b8605Smrg   &use_invalidate.base,
236848b8605Smrg   &dri2_loader_extension.base,
237848b8605Smrg   &image_loader_extension.base,
238848b8605Smrg   &swrast_loader_extension.base,
239848b8605Smrg   NULL,
240848b8605Smrg};
241848b8605Smrg
242848b8605Smrgstruct dri_extension_match {
243848b8605Smrg   const char *name;
244848b8605Smrg   int version;
245848b8605Smrg   int offset;
246b8e80941Smrg   int optional;
247848b8605Smrg};
248848b8605Smrg
249848b8605Smrgstatic struct dri_extension_match dri_core_extensions[] = {
250848b8605Smrg   { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
251848b8605Smrg   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
252b8e80941Smrg   { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), 1 },
253848b8605Smrg   { NULL, 0, 0 }
254848b8605Smrg};
255848b8605Smrg
256848b8605Smrgstatic struct dri_extension_match gbm_dri_device_extensions[] = {
257848b8605Smrg   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
258848b8605Smrg   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
259848b8605Smrg   { NULL, 0, 0 }
260848b8605Smrg};
261848b8605Smrg
262848b8605Smrgstatic struct dri_extension_match gbm_swrast_device_extensions[] = {
263848b8605Smrg   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), },
264848b8605Smrg   { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast) },
265848b8605Smrg   { NULL, 0, 0 }
266848b8605Smrg};
267848b8605Smrg
268848b8605Smrgstatic int
269848b8605Smrgdri_bind_extensions(struct gbm_dri_device *dri,
270848b8605Smrg                    struct dri_extension_match *matches,
271848b8605Smrg                    const __DRIextension **extensions)
272848b8605Smrg{
273848b8605Smrg   int i, j, ret = 0;
274848b8605Smrg   void *field;
275848b8605Smrg
276848b8605Smrg   for (i = 0; extensions[i]; i++) {
277848b8605Smrg      for (j = 0; matches[j].name; j++) {
278848b8605Smrg         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
279848b8605Smrg             extensions[i]->version >= matches[j].version) {
280848b8605Smrg            field = ((char *) dri + matches[j].offset);
281848b8605Smrg            *(const __DRIextension **) field = extensions[i];
282848b8605Smrg         }
283848b8605Smrg      }
284848b8605Smrg   }
285848b8605Smrg
286848b8605Smrg   for (j = 0; matches[j].name; j++) {
287848b8605Smrg      field = ((char *) dri + matches[j].offset);
288b8e80941Smrg      if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) {
289848b8605Smrg         ret = -1;
290848b8605Smrg      }
291848b8605Smrg   }
292848b8605Smrg
293848b8605Smrg   return ret;
294848b8605Smrg}
295848b8605Smrg
296848b8605Smrgstatic const __DRIextension **
297848b8605Smrgdri_open_driver(struct gbm_dri_device *dri)
298848b8605Smrg{
299b8e80941Smrg   /* Temporarily work around dri driver libs that need symbols in libglapi
300b8e80941Smrg    * but don't automatically link it in.
301b8e80941Smrg    */
302b8e80941Smrg   /* XXX: Library name differs on per platforms basis. Update this as
303b8e80941Smrg    * osx/cygwin/windows/bsd gets support for GBM..
304b8e80941Smrg    */
305b8e80941Smrg   dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
306b8e80941Smrg
307b8e80941Smrg   static const char *search_path_vars[] = {
308848b8605Smrg      /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
309848b8605Smrg       * is recommended over GBM_DRIVERS_PATH.
310848b8605Smrg       */
311b8e80941Smrg      "GBM_DRIVERS_PATH",
312848b8605Smrg      /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
313848b8605Smrg       * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
314848b8605Smrg       */
315b8e80941Smrg      "LIBGL_DRIVERS_PATH",
316b8e80941Smrg      NULL
317b8e80941Smrg   };
318b8e80941Smrg   return loader_open_driver(dri->driver_name, &dri->driver, search_path_vars);
319848b8605Smrg}
320848b8605Smrg
321848b8605Smrgstatic int
322848b8605Smrgdri_load_driver(struct gbm_dri_device *dri)
323848b8605Smrg{
324848b8605Smrg   const __DRIextension **extensions;
325848b8605Smrg
326848b8605Smrg   extensions = dri_open_driver(dri);
327848b8605Smrg   if (!extensions)
328848b8605Smrg      return -1;
329848b8605Smrg
330848b8605Smrg   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
331848b8605Smrg      dlclose(dri->driver);
332848b8605Smrg      fprintf(stderr, "failed to bind extensions\n");
333848b8605Smrg      return -1;
334848b8605Smrg   }
335848b8605Smrg
336848b8605Smrg   dri->driver_extensions = extensions;
337848b8605Smrg
338848b8605Smrg   return 0;
339848b8605Smrg}
340848b8605Smrg
341848b8605Smrgstatic int
342848b8605Smrgdri_load_driver_swrast(struct gbm_dri_device *dri)
343848b8605Smrg{
344848b8605Smrg   const __DRIextension **extensions;
345848b8605Smrg
346848b8605Smrg   extensions = dri_open_driver(dri);
347848b8605Smrg   if (!extensions)
348848b8605Smrg      return -1;
349848b8605Smrg
350848b8605Smrg   if (dri_bind_extensions(dri, gbm_swrast_device_extensions, extensions) < 0) {
351848b8605Smrg      dlclose(dri->driver);
352848b8605Smrg      fprintf(stderr, "failed to bind extensions\n");
353848b8605Smrg      return -1;
354848b8605Smrg   }
355848b8605Smrg
356848b8605Smrg   dri->driver_extensions = extensions;
357848b8605Smrg
358848b8605Smrg   return 0;
359848b8605Smrg}
360848b8605Smrg
361848b8605Smrgstatic int
362b8e80941Smrgdri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
363848b8605Smrg{
364848b8605Smrg   const __DRIextension **extensions;
365848b8605Smrg   int ret = 0;
366848b8605Smrg
367b8e80941Smrg   dri->driver_name = driver_name;
368b8e80941Smrg   if (dri->driver_name == NULL)
369848b8605Smrg      return -1;
370848b8605Smrg
371848b8605Smrg   ret = dri_load_driver(dri);
372848b8605Smrg   if (ret) {
373b8e80941Smrg      fprintf(stderr, "failed to load driver: %s\n", dri->driver_name);
374848b8605Smrg      return ret;
375b8e80941Smrg   }
376848b8605Smrg
377b8e80941Smrg   dri->loader_extensions = gbm_dri_screen_extensions;
378848b8605Smrg
379848b8605Smrg   if (dri->dri2 == NULL)
380848b8605Smrg      return -1;
381848b8605Smrg
382848b8605Smrg   if (dri->dri2->base.version >= 4) {
383b8e80941Smrg      dri->screen = dri->dri2->createNewScreen2(0, dri->base.fd,
384b8e80941Smrg                                                dri->loader_extensions,
385848b8605Smrg                                                dri->driver_extensions,
386848b8605Smrg                                                &dri->driver_configs, dri);
387848b8605Smrg   } else {
388b8e80941Smrg      dri->screen = dri->dri2->createNewScreen(0, dri->base.fd,
389b8e80941Smrg                                               dri->loader_extensions,
390848b8605Smrg                                               &dri->driver_configs, dri);
391848b8605Smrg   }
392848b8605Smrg   if (dri->screen == NULL)
393848b8605Smrg      return -1;
394848b8605Smrg
395848b8605Smrg   extensions = dri->core->getExtensions(dri->screen);
396848b8605Smrg   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
397848b8605Smrg      ret = -1;
398848b8605Smrg      goto free_screen;
399848b8605Smrg   }
400848b8605Smrg
401848b8605Smrg   dri->lookup_image = NULL;
402848b8605Smrg   dri->lookup_user_data = NULL;
403848b8605Smrg
404848b8605Smrg   return 0;
405848b8605Smrg
406848b8605Smrgfree_screen:
407848b8605Smrg   dri->core->destroyScreen(dri->screen);
408848b8605Smrg
409848b8605Smrg   return ret;
410848b8605Smrg}
411848b8605Smrg
412848b8605Smrgstatic int
413848b8605Smrgdri_screen_create_swrast(struct gbm_dri_device *dri)
414848b8605Smrg{
415848b8605Smrg   int ret;
416848b8605Smrg
417b8e80941Smrg   dri->driver_name = strdup("swrast");
418b8e80941Smrg   if (dri->driver_name == NULL)
419848b8605Smrg      return -1;
420848b8605Smrg
421848b8605Smrg   ret = dri_load_driver_swrast(dri);
422848b8605Smrg   if (ret) {
423848b8605Smrg      fprintf(stderr, "failed to load swrast driver\n");
424848b8605Smrg      return ret;
425848b8605Smrg   }
426848b8605Smrg
427b8e80941Smrg   dri->loader_extensions = gbm_dri_screen_extensions;
428848b8605Smrg
429848b8605Smrg   if (dri->swrast == NULL)
430848b8605Smrg      return -1;
431848b8605Smrg
432848b8605Smrg   if (dri->swrast->base.version >= 4) {
433b8e80941Smrg      dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions,
434848b8605Smrg                                                  dri->driver_extensions,
435848b8605Smrg                                                  &dri->driver_configs, dri);
436848b8605Smrg   } else {
437b8e80941Smrg      dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions,
438848b8605Smrg                                                 &dri->driver_configs, dri);
439848b8605Smrg   }
440848b8605Smrg   if (dri->screen == NULL)
441848b8605Smrg      return -1;
442848b8605Smrg
443848b8605Smrg   dri->lookup_image = NULL;
444848b8605Smrg   dri->lookup_user_data = NULL;
445848b8605Smrg
446848b8605Smrg   return 0;
447848b8605Smrg}
448848b8605Smrg
449848b8605Smrgstatic int
450848b8605Smrgdri_screen_create(struct gbm_dri_device *dri)
451848b8605Smrg{
452b8e80941Smrg   char *driver_name;
453848b8605Smrg
454b8e80941Smrg   driver_name = loader_get_driver_for_fd(dri->base.fd);
455848b8605Smrg   if (!driver_name)
456848b8605Smrg      return -1;
457848b8605Smrg
458848b8605Smrg   return dri_screen_create_dri2(dri, driver_name);
459848b8605Smrg}
460848b8605Smrg
461848b8605Smrgstatic int
462848b8605Smrgdri_screen_create_sw(struct gbm_dri_device *dri)
463848b8605Smrg{
464b8e80941Smrg   char *driver_name;
465848b8605Smrg   int ret;
466848b8605Smrg
467848b8605Smrg   driver_name = strdup("kms_swrast");
468848b8605Smrg   if (!driver_name)
469848b8605Smrg      return -errno;
470848b8605Smrg
471848b8605Smrg   ret = dri_screen_create_dri2(dri, driver_name);
472848b8605Smrg   if (ret == 0)
473848b8605Smrg      return ret;
474848b8605Smrg
475848b8605Smrg   return dri_screen_create_swrast(dri);
476848b8605Smrg}
477848b8605Smrg
478b8e80941Smrgstatic const struct gbm_dri_visual gbm_dri_visuals_table[] = {
479b8e80941Smrg   {
480b8e80941Smrg     GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8,
481b8e80941Smrg     { 0x000000ff, 0x00000000, 0x00000000, 0x00000000 },
482b8e80941Smrg   },
483b8e80941Smrg   {
484b8e80941Smrg     GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88,
485b8e80941Smrg     { 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 },
486b8e80941Smrg   },
487b8e80941Smrg   {
488b8e80941Smrg     GBM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555,
489b8e80941Smrg     { 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 },
490b8e80941Smrg   },
491b8e80941Smrg   {
492b8e80941Smrg     GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565,
493b8e80941Smrg     { 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 },
494b8e80941Smrg   },
495b8e80941Smrg   {
496b8e80941Smrg     GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888,
497b8e80941Smrg     { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
498b8e80941Smrg   },
499b8e80941Smrg   {
500b8e80941Smrg     GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888,
501b8e80941Smrg     { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
502b8e80941Smrg   },
503b8e80941Smrg   {
504b8e80941Smrg     GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888,
505b8e80941Smrg     { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
506b8e80941Smrg   },
507b8e80941Smrg   {
508b8e80941Smrg     GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888,
509b8e80941Smrg     { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
510b8e80941Smrg   },
511b8e80941Smrg   {
512b8e80941Smrg     GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010,
513b8e80941Smrg     { 0x3ff00000, 0x000ffc00, 0x000003ff, 0x00000000 },
514b8e80941Smrg   },
515b8e80941Smrg   {
516b8e80941Smrg     GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010,
517b8e80941Smrg     { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 },
518b8e80941Smrg   },
519b8e80941Smrg   {
520b8e80941Smrg     GBM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010,
521b8e80941Smrg     { 0x000003ff, 0x000ffc00, 0x3ff00000, 0x00000000 },
522b8e80941Smrg   },
523b8e80941Smrg   {
524b8e80941Smrg     GBM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010,
525b8e80941Smrg     { 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 },
526b8e80941Smrg   },
527b8e80941Smrg};
528b8e80941Smrg
529b8e80941Smrgstatic int
530b8e80941Smrggbm_format_to_dri_format(uint32_t gbm_format)
531b8e80941Smrg{
532b8e80941Smrg   int i;
533b8e80941Smrg
534b8e80941Smrg   gbm_format = gbm_format_canonicalize(gbm_format);
535b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
536b8e80941Smrg      if (gbm_dri_visuals_table[i].gbm_format == gbm_format)
537b8e80941Smrg         return gbm_dri_visuals_table[i].dri_image_format;
538b8e80941Smrg   }
539b8e80941Smrg
540b8e80941Smrg   return 0;
541b8e80941Smrg}
542b8e80941Smrg
543b8e80941Smrgstatic uint32_t
544b8e80941Smrggbm_dri_to_gbm_format(int dri_format)
545b8e80941Smrg{
546b8e80941Smrg   int i;
547b8e80941Smrg
548b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
549b8e80941Smrg      if (gbm_dri_visuals_table[i].dri_image_format == dri_format)
550b8e80941Smrg         return gbm_dri_visuals_table[i].gbm_format;
551b8e80941Smrg   }
552b8e80941Smrg
553b8e80941Smrg   return 0;
554b8e80941Smrg}
555b8e80941Smrg
556848b8605Smrgstatic int
557848b8605Smrggbm_dri_is_format_supported(struct gbm_device *gbm,
558848b8605Smrg                            uint32_t format,
559848b8605Smrg                            uint32_t usage)
560848b8605Smrg{
561b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
562b8e80941Smrg   int count;
563b8e80941Smrg
564b8e80941Smrg   if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING))
565848b8605Smrg      return 0;
566b8e80941Smrg
567b8e80941Smrg   format = gbm_format_canonicalize(format);
568b8e80941Smrg   if (gbm_format_to_dri_format(format) == 0)
569b8e80941Smrg      return 0;
570b8e80941Smrg
571b8e80941Smrg   /* If there is no query, fall back to the small table which was originally
572b8e80941Smrg    * here. */
573b8e80941Smrg   if (dri->image->base.version <= 15 || !dri->image->queryDmaBufModifiers) {
574b8e80941Smrg      switch (format) {
575b8e80941Smrg      case GBM_FORMAT_XRGB8888:
576b8e80941Smrg      case GBM_FORMAT_ARGB8888:
577b8e80941Smrg      case GBM_FORMAT_XBGR8888:
578b8e80941Smrg         return 1;
579b8e80941Smrg      default:
580b8e80941Smrg         return 0;
581b8e80941Smrg      }
582848b8605Smrg   }
583848b8605Smrg
584b8e80941Smrg   /* Check if the driver returns any modifiers for this format; since linear
585b8e80941Smrg    * is counted as a modifier, we will have at least one modifier for any
586b8e80941Smrg    * supported format. */
587b8e80941Smrg   if (!dri->image->queryDmaBufModifiers(dri->screen, format, 0, NULL, NULL,
588b8e80941Smrg                                         &count))
589848b8605Smrg      return 0;
590848b8605Smrg
591b8e80941Smrg   return (count > 0);
592b8e80941Smrg}
593b8e80941Smrg
594b8e80941Smrgstatic int
595b8e80941Smrggbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm,
596b8e80941Smrg                                        uint32_t format,
597b8e80941Smrg                                        uint64_t modifier)
598b8e80941Smrg{
599b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
600b8e80941Smrg   uint64_t plane_count;
601b8e80941Smrg
602b8e80941Smrg   if (dri->image->base.version < 16 ||
603b8e80941Smrg       !dri->image->queryDmaBufFormatModifierAttribs)
604b8e80941Smrg      return -1;
605b8e80941Smrg
606b8e80941Smrg   format = gbm_format_canonicalize(format);
607b8e80941Smrg   if (gbm_format_to_dri_format(format) == 0)
608b8e80941Smrg      return -1;
609b8e80941Smrg
610b8e80941Smrg   if (!dri->image->queryDmaBufFormatModifierAttribs(
611b8e80941Smrg         dri->screen, format, modifier,
612b8e80941Smrg         __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT, &plane_count))
613b8e80941Smrg      return -1;
614b8e80941Smrg
615b8e80941Smrg   return plane_count;
616848b8605Smrg}
617848b8605Smrg
618848b8605Smrgstatic int
619848b8605Smrggbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
620848b8605Smrg{
621848b8605Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
622848b8605Smrg
623848b8605Smrg   if (bo->image != NULL) {
624848b8605Smrg      errno = EINVAL;
625848b8605Smrg      return -1;
626848b8605Smrg   }
627848b8605Smrg
628848b8605Smrg   memcpy(bo->map, buf, count);
629848b8605Smrg
630848b8605Smrg   return 0;
631848b8605Smrg}
632848b8605Smrg
633848b8605Smrgstatic int
634848b8605Smrggbm_dri_bo_get_fd(struct gbm_bo *_bo)
635848b8605Smrg{
636848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
637848b8605Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
638848b8605Smrg   int fd;
639848b8605Smrg
640848b8605Smrg   if (bo->image == NULL)
641848b8605Smrg      return -1;
642848b8605Smrg
643b8e80941Smrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
644b8e80941Smrg      return -1;
645848b8605Smrg
646848b8605Smrg   return fd;
647848b8605Smrg}
648848b8605Smrg
649b8e80941Smrgstatic int
650b8e80941Smrgget_number_planes(struct gbm_dri_device *dri, __DRIimage *image)
651b8e80941Smrg{
652b8e80941Smrg   int num_planes = 0;
653b8e80941Smrg
654b8e80941Smrg   /* Dumb buffers are single-plane only. */
655b8e80941Smrg   if (!image)
656b8e80941Smrg      return 1;
657b8e80941Smrg
658b8e80941Smrg   dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);
659b8e80941Smrg
660b8e80941Smrg   if (num_planes <= 0)
661b8e80941Smrg      num_planes = 1;
662b8e80941Smrg
663b8e80941Smrg   return num_planes;
664b8e80941Smrg}
665b8e80941Smrg
666b8e80941Smrgstatic int
667b8e80941Smrggbm_dri_bo_get_planes(struct gbm_bo *_bo)
668848b8605Smrg{
669848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
670848b8605Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
671848b8605Smrg
672b8e80941Smrg   return get_number_planes(dri, bo->image);
673b8e80941Smrg}
674b8e80941Smrg
675b8e80941Smrgstatic union gbm_bo_handle
676b8e80941Smrggbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane)
677b8e80941Smrg{
678b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
679b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
680b8e80941Smrg   union gbm_bo_handle ret;
681b8e80941Smrg   ret.s32 = -1;
682b8e80941Smrg
683b8e80941Smrg   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
684b8e80941Smrg      errno = ENOSYS;
685b8e80941Smrg      return ret;
686b8e80941Smrg   }
687b8e80941Smrg
688b8e80941Smrg   if (plane >= get_number_planes(dri, bo->image)) {
689b8e80941Smrg      errno = EINVAL;
690b8e80941Smrg      return ret;
691b8e80941Smrg   }
692b8e80941Smrg
693b8e80941Smrg   /* dumb BOs can only utilize non-planar formats */
694b8e80941Smrg   if (!bo->image) {
695b8e80941Smrg      assert(plane == 0);
696b8e80941Smrg      ret.s32 = bo->handle;
697b8e80941Smrg      return ret;
698b8e80941Smrg   }
699b8e80941Smrg
700b8e80941Smrg   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
701b8e80941Smrg   if (image) {
702b8e80941Smrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
703b8e80941Smrg      dri->image->destroyImage(image);
704848b8605Smrg   } else {
705b8e80941Smrg      assert(plane == 0);
706b8e80941Smrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
707848b8605Smrg   }
708848b8605Smrg
709b8e80941Smrg   return ret;
710848b8605Smrg}
711848b8605Smrg
712848b8605Smrgstatic uint32_t
713b8e80941Smrggbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
714848b8605Smrg{
715b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
716b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
717b8e80941Smrg   __DRIimage *image;
718b8e80941Smrg   int stride = 0;
719848b8605Smrg
720b8e80941Smrg   if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) {
721b8e80941Smrg      /* Preserve legacy behavior if plane is 0 */
722b8e80941Smrg      if (plane == 0)
723b8e80941Smrg         return _bo->stride;
724b8e80941Smrg
725b8e80941Smrg      errno = ENOSYS;
726b8e80941Smrg      return 0;
727b8e80941Smrg   }
728b8e80941Smrg
729b8e80941Smrg   if (plane >= get_number_planes(dri, bo->image)) {
730b8e80941Smrg      errno = EINVAL;
731b8e80941Smrg      return 0;
732b8e80941Smrg   }
733b8e80941Smrg
734b8e80941Smrg   if (bo->image == NULL) {
735b8e80941Smrg      assert(plane == 0);
736b8e80941Smrg      return _bo->stride;
737848b8605Smrg   }
738848b8605Smrg
739b8e80941Smrg   image = dri->image->fromPlanar(bo->image, plane, NULL);
740b8e80941Smrg   if (image) {
741b8e80941Smrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
742b8e80941Smrg      dri->image->destroyImage(image);
743b8e80941Smrg   } else {
744b8e80941Smrg      assert(plane == 0);
745b8e80941Smrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
746b8e80941Smrg   }
747b8e80941Smrg
748b8e80941Smrg   return (uint32_t)stride;
749b8e80941Smrg}
750b8e80941Smrg
751b8e80941Smrgstatic uint32_t
752b8e80941Smrggbm_dri_bo_get_offset(struct gbm_bo *_bo, int plane)
753b8e80941Smrg{
754b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
755b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
756b8e80941Smrg   int offset = 0;
757b8e80941Smrg
758b8e80941Smrg   /* These error cases do not actually return an error code, as the user
759b8e80941Smrg    * will also fail to obtain the handle/FD from the BO. In that case, the
760b8e80941Smrg    * offset is irrelevant, as they have no buffer to offset into, so
761b8e80941Smrg    * returning 0 is harmless.
762b8e80941Smrg    */
763b8e80941Smrg   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar)
764b8e80941Smrg      return 0;
765b8e80941Smrg
766b8e80941Smrg   if (plane >= get_number_planes(dri, bo->image))
767b8e80941Smrg      return 0;
768b8e80941Smrg
769b8e80941Smrg    /* Dumb images have no offset */
770b8e80941Smrg   if (bo->image == NULL) {
771b8e80941Smrg      assert(plane == 0);
772b8e80941Smrg      return 0;
773b8e80941Smrg   }
774b8e80941Smrg
775b8e80941Smrg   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
776b8e80941Smrg   if (image) {
777b8e80941Smrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
778b8e80941Smrg      dri->image->destroyImage(image);
779b8e80941Smrg   } else {
780b8e80941Smrg      assert(plane == 0);
781b8e80941Smrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
782b8e80941Smrg   }
783b8e80941Smrg
784b8e80941Smrg   return (uint32_t)offset;
785b8e80941Smrg}
786b8e80941Smrg
787b8e80941Smrgstatic uint64_t
788b8e80941Smrggbm_dri_bo_get_modifier(struct gbm_bo *_bo)
789b8e80941Smrg{
790b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
791b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
792b8e80941Smrg
793b8e80941Smrg   if (!dri->image || dri->image->base.version < 14) {
794b8e80941Smrg      errno = ENOSYS;
795b8e80941Smrg      return DRM_FORMAT_MOD_INVALID;
796b8e80941Smrg   }
797b8e80941Smrg
798b8e80941Smrg   /* Dumb buffers have no modifiers */
799b8e80941Smrg   if (!bo->image)
800b8e80941Smrg      return DRM_FORMAT_MOD_LINEAR;
801b8e80941Smrg
802b8e80941Smrg   uint64_t ret = 0;
803b8e80941Smrg   int mod;
804b8e80941Smrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
805b8e80941Smrg                               &mod))
806b8e80941Smrg      return DRM_FORMAT_MOD_INVALID;
807b8e80941Smrg
808b8e80941Smrg   ret = (uint64_t)mod << 32;
809b8e80941Smrg
810b8e80941Smrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
811b8e80941Smrg                               &mod))
812b8e80941Smrg      return DRM_FORMAT_MOD_INVALID;
813b8e80941Smrg
814b8e80941Smrg   ret |= (uint64_t)(mod & 0xffffffff);
815b8e80941Smrg
816848b8605Smrg   return ret;
817848b8605Smrg}
818848b8605Smrg
819b8e80941Smrgstatic void
820b8e80941Smrggbm_dri_bo_destroy(struct gbm_bo *_bo)
821b8e80941Smrg{
822b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
823b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
824b8e80941Smrg   struct drm_mode_destroy_dumb arg;
825b8e80941Smrg
826b8e80941Smrg   if (bo->image != NULL) {
827b8e80941Smrg      dri->image->destroyImage(bo->image);
828b8e80941Smrg   } else {
829b8e80941Smrg      gbm_dri_bo_unmap_dumb(bo);
830b8e80941Smrg      memset(&arg, 0, sizeof(arg));
831b8e80941Smrg      arg.handle = bo->handle;
832b8e80941Smrg      drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
833b8e80941Smrg   }
834b8e80941Smrg
835b8e80941Smrg   free(bo);
836b8e80941Smrg}
837b8e80941Smrg
838848b8605Smrgstatic struct gbm_bo *
839848b8605Smrggbm_dri_bo_import(struct gbm_device *gbm,
840848b8605Smrg                  uint32_t type, void *buffer, uint32_t usage)
841848b8605Smrg{
842848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
843848b8605Smrg   struct gbm_dri_bo *bo;
844848b8605Smrg   __DRIimage *image;
845848b8605Smrg   unsigned dri_use = 0;
846848b8605Smrg   int gbm_format;
847848b8605Smrg
848848b8605Smrg   /* Required for query image WIDTH & HEIGHT */
849848b8605Smrg   if (dri->image == NULL || dri->image->base.version < 4) {
850848b8605Smrg      errno = ENOSYS;
851848b8605Smrg      return NULL;
852848b8605Smrg   }
853848b8605Smrg
854848b8605Smrg   switch (type) {
855848b8605Smrg#if HAVE_WAYLAND_PLATFORM
856848b8605Smrg   case GBM_BO_IMPORT_WL_BUFFER:
857848b8605Smrg   {
858848b8605Smrg      struct wl_drm_buffer *wb;
859848b8605Smrg
860848b8605Smrg      if (!dri->wl_drm) {
861848b8605Smrg         errno = EINVAL;
862848b8605Smrg         return NULL;
863848b8605Smrg      }
864848b8605Smrg
865848b8605Smrg      wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
866848b8605Smrg      if (!wb) {
867848b8605Smrg         errno = EINVAL;
868848b8605Smrg         return NULL;
869848b8605Smrg      }
870848b8605Smrg
871848b8605Smrg      image = dri->image->dupImage(wb->driver_buffer, NULL);
872848b8605Smrg
873b8e80941Smrg      /* GBM_FORMAT_* is identical to WL_DRM_FORMAT_*, so no conversion
874b8e80941Smrg       * required. */
875b8e80941Smrg      gbm_format = wb->format;
876848b8605Smrg      break;
877848b8605Smrg   }
878848b8605Smrg#endif
879848b8605Smrg
880848b8605Smrg   case GBM_BO_IMPORT_EGL_IMAGE:
881848b8605Smrg   {
882848b8605Smrg      int dri_format;
883848b8605Smrg      if (dri->lookup_image == NULL) {
884848b8605Smrg         errno = EINVAL;
885848b8605Smrg         return NULL;
886848b8605Smrg      }
887848b8605Smrg
888848b8605Smrg      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
889848b8605Smrg      image = dri->image->dupImage(image, NULL);
890848b8605Smrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
891848b8605Smrg      gbm_format = gbm_dri_to_gbm_format(dri_format);
892848b8605Smrg      if (gbm_format == 0) {
893848b8605Smrg         errno = EINVAL;
894b8e80941Smrg         dri->image->destroyImage(image);
895848b8605Smrg         return NULL;
896848b8605Smrg      }
897848b8605Smrg      break;
898848b8605Smrg   }
899848b8605Smrg
900848b8605Smrg   case GBM_BO_IMPORT_FD:
901848b8605Smrg   {
902848b8605Smrg      struct gbm_import_fd_data *fd_data = buffer;
903848b8605Smrg      int stride = fd_data->stride, offset = 0;
904b8e80941Smrg      int fourcc;
905b8e80941Smrg
906b8e80941Smrg      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
907b8e80941Smrg       * tokens accepted by createImageFromFds, except for not supporting
908b8e80941Smrg       * the sARGB format. */
909b8e80941Smrg      fourcc = gbm_format_canonicalize(fd_data->format);
910848b8605Smrg
911848b8605Smrg      image = dri->image->createImageFromFds(dri->screen,
912848b8605Smrg                                             fd_data->width,
913848b8605Smrg                                             fd_data->height,
914b8e80941Smrg                                             fourcc,
915848b8605Smrg                                             &fd_data->fd, 1,
916848b8605Smrg                                             &stride, &offset,
917848b8605Smrg                                             NULL);
918b8e80941Smrg      if (image == NULL) {
919b8e80941Smrg         errno = EINVAL;
920b8e80941Smrg         return NULL;
921b8e80941Smrg      }
922848b8605Smrg      gbm_format = fd_data->format;
923848b8605Smrg      break;
924848b8605Smrg   }
925848b8605Smrg
926b8e80941Smrg   case GBM_BO_IMPORT_FD_MODIFIER:
927b8e80941Smrg   {
928b8e80941Smrg      struct gbm_import_fd_modifier_data *fd_data = buffer;
929b8e80941Smrg      unsigned int error;
930b8e80941Smrg      int fourcc;
931b8e80941Smrg
932b8e80941Smrg      /* Import with modifier requires createImageFromDmaBufs2 */
933b8e80941Smrg      if (dri->image == NULL || dri->image->base.version < 15 ||
934b8e80941Smrg          dri->image->createImageFromDmaBufs2 == NULL) {
935b8e80941Smrg         errno = ENOSYS;
936b8e80941Smrg         return NULL;
937b8e80941Smrg      }
938b8e80941Smrg
939b8e80941Smrg      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
940b8e80941Smrg       * tokens accepted by createImageFromDmaBufs2, except for not supporting
941b8e80941Smrg       * the sARGB format. */
942b8e80941Smrg      fourcc = gbm_format_canonicalize(fd_data->format);
943b8e80941Smrg
944b8e80941Smrg      image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width,
945b8e80941Smrg                                                  fd_data->height, fourcc,
946b8e80941Smrg                                                  fd_data->modifier,
947b8e80941Smrg                                                  fd_data->fds,
948b8e80941Smrg                                                  fd_data->num_fds,
949b8e80941Smrg                                                  fd_data->strides,
950b8e80941Smrg                                                  fd_data->offsets,
951b8e80941Smrg                                                  0, 0, 0, 0,
952b8e80941Smrg                                                  &error, NULL);
953b8e80941Smrg      if (image == NULL) {
954b8e80941Smrg         errno = ENOSYS;
955b8e80941Smrg         return NULL;
956b8e80941Smrg      }
957b8e80941Smrg
958b8e80941Smrg      gbm_format = fourcc;
959b8e80941Smrg      break;
960b8e80941Smrg   }
961b8e80941Smrg
962848b8605Smrg   default:
963848b8605Smrg      errno = ENOSYS;
964848b8605Smrg      return NULL;
965848b8605Smrg   }
966848b8605Smrg
967848b8605Smrg
968848b8605Smrg   bo = calloc(1, sizeof *bo);
969b8e80941Smrg   if (bo == NULL) {
970b8e80941Smrg      dri->image->destroyImage(image);
971848b8605Smrg      return NULL;
972b8e80941Smrg   }
973848b8605Smrg
974848b8605Smrg   bo->image = image;
975848b8605Smrg
976848b8605Smrg   if (usage & GBM_BO_USE_SCANOUT)
977848b8605Smrg      dri_use |= __DRI_IMAGE_USE_SCANOUT;
978848b8605Smrg   if (usage & GBM_BO_USE_CURSOR)
979848b8605Smrg      dri_use |= __DRI_IMAGE_USE_CURSOR;
980848b8605Smrg   if (dri->image->base.version >= 2 &&
981848b8605Smrg       !dri->image->validateUsage(bo->image, dri_use)) {
982848b8605Smrg      errno = EINVAL;
983b8e80941Smrg      dri->image->destroyImage(bo->image);
984848b8605Smrg      free(bo);
985848b8605Smrg      return NULL;
986848b8605Smrg   }
987848b8605Smrg
988b8e80941Smrg   bo->base.gbm = gbm;
989b8e80941Smrg   bo->base.format = gbm_format;
990848b8605Smrg
991848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
992b8e80941Smrg                          (int*)&bo->base.width);
993848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
994b8e80941Smrg                          (int*)&bo->base.height);
995848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
996b8e80941Smrg                          (int*)&bo->base.stride);
997848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
998b8e80941Smrg                          &bo->base.handle.s32);
999848b8605Smrg
1000b8e80941Smrg   return &bo->base;
1001848b8605Smrg}
1002848b8605Smrg
1003848b8605Smrgstatic struct gbm_bo *
1004848b8605Smrgcreate_dumb(struct gbm_device *gbm,
1005848b8605Smrg                  uint32_t width, uint32_t height,
1006848b8605Smrg                  uint32_t format, uint32_t usage)
1007848b8605Smrg{
1008848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1009848b8605Smrg   struct drm_mode_create_dumb create_arg;
1010848b8605Smrg   struct gbm_dri_bo *bo;
1011848b8605Smrg   struct drm_mode_destroy_dumb destroy_arg;
1012848b8605Smrg   int ret;
1013848b8605Smrg   int is_cursor, is_scanout;
1014848b8605Smrg
1015848b8605Smrg   is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
1016848b8605Smrg      format == GBM_FORMAT_ARGB8888;
1017848b8605Smrg   is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
1018b8e80941Smrg      (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_XBGR8888);
1019848b8605Smrg   if (!is_cursor && !is_scanout) {
1020848b8605Smrg      errno = EINVAL;
1021848b8605Smrg      return NULL;
1022848b8605Smrg   }
1023848b8605Smrg
1024848b8605Smrg   bo = calloc(1, sizeof *bo);
1025848b8605Smrg   if (bo == NULL)
1026848b8605Smrg      return NULL;
1027848b8605Smrg
1028b8e80941Smrg   memset(&create_arg, 0, sizeof(create_arg));
1029848b8605Smrg   create_arg.bpp = 32;
1030848b8605Smrg   create_arg.width = width;
1031848b8605Smrg   create_arg.height = height;
1032848b8605Smrg
1033b8e80941Smrg   ret = drmIoctl(dri->base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
1034848b8605Smrg   if (ret)
1035848b8605Smrg      goto free_bo;
1036848b8605Smrg
1037b8e80941Smrg   bo->base.gbm = gbm;
1038b8e80941Smrg   bo->base.width = width;
1039b8e80941Smrg   bo->base.height = height;
1040b8e80941Smrg   bo->base.stride = create_arg.pitch;
1041b8e80941Smrg   bo->base.format = format;
1042b8e80941Smrg   bo->base.handle.u32 = create_arg.handle;
1043848b8605Smrg   bo->handle = create_arg.handle;
1044848b8605Smrg   bo->size = create_arg.size;
1045848b8605Smrg
1046b8e80941Smrg   if (gbm_dri_bo_map_dumb(bo) == NULL)
1047848b8605Smrg      goto destroy_dumb;
1048848b8605Smrg
1049b8e80941Smrg   return &bo->base;
1050848b8605Smrg
1051848b8605Smrgdestroy_dumb:
1052848b8605Smrg   memset(&destroy_arg, 0, sizeof destroy_arg);
1053848b8605Smrg   destroy_arg.handle = create_arg.handle;
1054b8e80941Smrg   drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
1055848b8605Smrgfree_bo:
1056848b8605Smrg   free(bo);
1057848b8605Smrg
1058848b8605Smrg   return NULL;
1059848b8605Smrg}
1060848b8605Smrg
1061848b8605Smrgstatic struct gbm_bo *
1062848b8605Smrggbm_dri_bo_create(struct gbm_device *gbm,
1063848b8605Smrg                  uint32_t width, uint32_t height,
1064b8e80941Smrg                  uint32_t format, uint32_t usage,
1065b8e80941Smrg                  const uint64_t *modifiers,
1066b8e80941Smrg                  const unsigned int count)
1067848b8605Smrg{
1068848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1069848b8605Smrg   struct gbm_dri_bo *bo;
1070848b8605Smrg   int dri_format;
1071848b8605Smrg   unsigned dri_use = 0;
1072848b8605Smrg
1073b8e80941Smrg   /* Callers of this may specify a modifier, or a dri usage, but not both. The
1074b8e80941Smrg    * newer modifier interface deprecates the older usage flags.
1075b8e80941Smrg    */
1076b8e80941Smrg   assert(!(usage && count));
1077b8e80941Smrg
1078b8e80941Smrg   format = gbm_format_canonicalize(format);
1079b8e80941Smrg
1080848b8605Smrg   if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
1081848b8605Smrg      return create_dumb(gbm, width, height, format, usage);
1082848b8605Smrg
1083848b8605Smrg   bo = calloc(1, sizeof *bo);
1084848b8605Smrg   if (bo == NULL)
1085848b8605Smrg      return NULL;
1086848b8605Smrg
1087b8e80941Smrg   bo->base.gbm = gbm;
1088b8e80941Smrg   bo->base.width = width;
1089b8e80941Smrg   bo->base.height = height;
1090b8e80941Smrg   bo->base.format = format;
1091848b8605Smrg
1092b8e80941Smrg   dri_format = gbm_format_to_dri_format(format);
1093b8e80941Smrg   if (dri_format == 0) {
1094848b8605Smrg      errno = EINVAL;
1095848b8605Smrg      goto failed;
1096848b8605Smrg   }
1097848b8605Smrg
1098848b8605Smrg   if (usage & GBM_BO_USE_SCANOUT)
1099848b8605Smrg      dri_use |= __DRI_IMAGE_USE_SCANOUT;
1100848b8605Smrg   if (usage & GBM_BO_USE_CURSOR)
1101848b8605Smrg      dri_use |= __DRI_IMAGE_USE_CURSOR;
1102b8e80941Smrg   if (usage & GBM_BO_USE_LINEAR)
1103b8e80941Smrg      dri_use |= __DRI_IMAGE_USE_LINEAR;
1104848b8605Smrg
1105848b8605Smrg   /* Gallium drivers requires shared in order to get the handle/stride */
1106848b8605Smrg   dri_use |= __DRI_IMAGE_USE_SHARE;
1107848b8605Smrg
1108b8e80941Smrg   if (modifiers) {
1109b8e80941Smrg      if (!dri->image || dri->image->base.version < 14 ||
1110b8e80941Smrg          !dri->image->createImageWithModifiers) {
1111b8e80941Smrg         fprintf(stderr, "Modifiers specified, but DRI is too old\n");
1112b8e80941Smrg         errno = ENOSYS;
1113b8e80941Smrg         goto failed;
1114b8e80941Smrg      }
1115b8e80941Smrg
1116b8e80941Smrg      /* It's acceptable to create an image with INVALID modifier in the list,
1117b8e80941Smrg       * but it cannot be on the only modifier (since it will certainly fail
1118b8e80941Smrg       * later). While we could easily catch this after modifier creation, doing
1119b8e80941Smrg       * the check here is a convenient debug check likely pointing at whatever
1120b8e80941Smrg       * interface the client is using to build its modifier list.
1121b8e80941Smrg       */
1122b8e80941Smrg      if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
1123b8e80941Smrg         fprintf(stderr, "Only invalid modifier specified\n");
1124b8e80941Smrg         errno = EINVAL;
1125b8e80941Smrg         goto failed;
1126b8e80941Smrg      }
1127b8e80941Smrg
1128b8e80941Smrg      bo->image =
1129b8e80941Smrg         dri->image->createImageWithModifiers(dri->screen,
1130b8e80941Smrg                                              width, height,
1131b8e80941Smrg                                              dri_format,
1132b8e80941Smrg                                              modifiers, count,
1133b8e80941Smrg                                              bo);
1134b8e80941Smrg
1135b8e80941Smrg      if (bo->image) {
1136b8e80941Smrg         /* The client passed in a list of invalid modifiers */
1137b8e80941Smrg         assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID);
1138b8e80941Smrg      }
1139b8e80941Smrg   } else {
1140b8e80941Smrg      bo->image = dri->image->createImage(dri->screen, width, height,
1141b8e80941Smrg                                          dri_format, dri_use, bo);
1142b8e80941Smrg   }
1143b8e80941Smrg
1144848b8605Smrg   if (bo->image == NULL)
1145848b8605Smrg      goto failed;
1146848b8605Smrg
1147848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
1148b8e80941Smrg                          &bo->base.handle.s32);
1149848b8605Smrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
1150b8e80941Smrg                          (int *) &bo->base.stride);
1151848b8605Smrg
1152b8e80941Smrg   return &bo->base;
1153848b8605Smrg
1154848b8605Smrgfailed:
1155848b8605Smrg   free(bo);
1156848b8605Smrg   return NULL;
1157848b8605Smrg}
1158848b8605Smrg
1159b8e80941Smrgstatic void *
1160b8e80941Smrggbm_dri_bo_map(struct gbm_bo *_bo,
1161b8e80941Smrg              uint32_t x, uint32_t y,
1162b8e80941Smrg              uint32_t width, uint32_t height,
1163b8e80941Smrg              uint32_t flags, uint32_t *stride, void **map_data)
1164b8e80941Smrg{
1165b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
1166b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
1167b8e80941Smrg
1168b8e80941Smrg   /* If it's a dumb buffer, we already have a mapping */
1169b8e80941Smrg   if (bo->map) {
1170b8e80941Smrg      *map_data = (char *)bo->map + (bo->base.stride * y) + (x * 4);
1171b8e80941Smrg      *stride = bo->base.stride;
1172b8e80941Smrg      return *map_data;
1173b8e80941Smrg   }
1174b8e80941Smrg
1175b8e80941Smrg   if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) {
1176b8e80941Smrg      errno = ENOSYS;
1177b8e80941Smrg      return NULL;
1178b8e80941Smrg   }
1179b8e80941Smrg
1180b8e80941Smrg   mtx_lock(&dri->mutex);
1181b8e80941Smrg   if (!dri->context)
1182b8e80941Smrg      dri->context = dri->dri2->createNewContext(dri->screen, NULL,
1183b8e80941Smrg                                                 NULL, NULL);
1184b8e80941Smrg   assert(dri->context);
1185b8e80941Smrg   mtx_unlock(&dri->mutex);
1186b8e80941Smrg
1187b8e80941Smrg   /* GBM flags and DRI flags are the same, so just pass them on */
1188b8e80941Smrg   return dri->image->mapImage(dri->context, bo->image, x, y,
1189b8e80941Smrg                               width, height, flags, (int *)stride,
1190b8e80941Smrg                               map_data);
1191b8e80941Smrg}
1192b8e80941Smrg
1193b8e80941Smrgstatic void
1194b8e80941Smrggbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
1195b8e80941Smrg{
1196b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
1197b8e80941Smrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
1198b8e80941Smrg
1199b8e80941Smrg   /* Check if it's a dumb buffer and check the pointer is in range */
1200b8e80941Smrg   if (bo->map) {
1201b8e80941Smrg      assert(map_data >= bo->map);
1202b8e80941Smrg      assert(map_data < (bo->map + bo->size));
1203b8e80941Smrg      return;
1204b8e80941Smrg   }
1205b8e80941Smrg
1206b8e80941Smrg   if (!dri->context || !dri->image ||
1207b8e80941Smrg       dri->image->base.version < 12 || !dri->image->unmapImage)
1208b8e80941Smrg      return;
1209b8e80941Smrg
1210b8e80941Smrg   dri->image->unmapImage(dri->context, bo->image, map_data);
1211b8e80941Smrg
1212b8e80941Smrg   /*
1213b8e80941Smrg    * Not all DRI drivers use direct maps. They may queue up DMA operations
1214b8e80941Smrg    * on the mapping context. Since there is no explicit gbm flush
1215b8e80941Smrg    * mechanism, we need to flush here.
1216b8e80941Smrg    */
1217b8e80941Smrg   if (dri->flush->base.version >= 4)
1218b8e80941Smrg      dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
1219b8e80941Smrg}
1220b8e80941Smrg
1221b8e80941Smrg
1222848b8605Smrgstatic struct gbm_surface *
1223848b8605Smrggbm_dri_surface_create(struct gbm_device *gbm,
1224848b8605Smrg                       uint32_t width, uint32_t height,
1225b8e80941Smrg		       uint32_t format, uint32_t flags,
1226b8e80941Smrg                       const uint64_t *modifiers, const unsigned count)
1227848b8605Smrg{
1228b8e80941Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1229848b8605Smrg   struct gbm_dri_surface *surf;
1230848b8605Smrg
1231b8e80941Smrg   if (modifiers &&
1232b8e80941Smrg       (!dri->image || dri->image->base.version < 14 ||
1233b8e80941Smrg        !dri->image->createImageWithModifiers)) {
1234b8e80941Smrg      errno = ENOSYS;
1235b8e80941Smrg      return NULL;
1236b8e80941Smrg   }
1237b8e80941Smrg
1238b8e80941Smrg   if (count)
1239b8e80941Smrg      assert(modifiers);
1240b8e80941Smrg
1241b8e80941Smrg   /* It's acceptable to create an image with INVALID modifier in the list,
1242b8e80941Smrg    * but it cannot be on the only modifier (since it will certainly fail
1243b8e80941Smrg    * later). While we could easily catch this after modifier creation, doing
1244b8e80941Smrg    * the check here is a convenient debug check likely pointing at whatever
1245b8e80941Smrg    * interface the client is using to build its modifier list.
1246b8e80941Smrg    */
1247b8e80941Smrg   if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
1248b8e80941Smrg      fprintf(stderr, "Only invalid modifier specified\n");
1249b8e80941Smrg      errno = EINVAL;
1250b8e80941Smrg   }
1251b8e80941Smrg
1252848b8605Smrg   surf = calloc(1, sizeof *surf);
1253b8e80941Smrg   if (surf == NULL) {
1254b8e80941Smrg      errno = ENOMEM;
1255848b8605Smrg      return NULL;
1256b8e80941Smrg   }
1257848b8605Smrg
1258848b8605Smrg   surf->base.gbm = gbm;
1259848b8605Smrg   surf->base.width = width;
1260848b8605Smrg   surf->base.height = height;
1261b8e80941Smrg   surf->base.format = gbm_format_canonicalize(format);
1262848b8605Smrg   surf->base.flags = flags;
1263b8e80941Smrg   if (!modifiers) {
1264b8e80941Smrg      assert(!count);
1265b8e80941Smrg      return &surf->base;
1266b8e80941Smrg   }
1267b8e80941Smrg
1268b8e80941Smrg   surf->base.modifiers = calloc(count, sizeof(*modifiers));
1269b8e80941Smrg   if (count && !surf->base.modifiers) {
1270b8e80941Smrg      errno = ENOMEM;
1271b8e80941Smrg      free(surf);
1272b8e80941Smrg      return NULL;
1273b8e80941Smrg   }
1274b8e80941Smrg
1275b8e80941Smrg   /* TODO: We are deferring validation of modifiers until the image is actually
1276b8e80941Smrg    * created. This deferred creation can fail due to a modifier-format
1277b8e80941Smrg    * mismatch. The result is the client has a surface but no object to back it.
1278b8e80941Smrg    */
1279b8e80941Smrg   surf->base.count = count;
1280b8e80941Smrg   memcpy(surf->base.modifiers, modifiers, count * sizeof(*modifiers));
1281848b8605Smrg
1282848b8605Smrg   return &surf->base;
1283848b8605Smrg}
1284848b8605Smrg
1285848b8605Smrgstatic void
1286848b8605Smrggbm_dri_surface_destroy(struct gbm_surface *_surf)
1287848b8605Smrg{
1288848b8605Smrg   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
1289848b8605Smrg
1290b8e80941Smrg   free(surf->base.modifiers);
1291848b8605Smrg   free(surf);
1292848b8605Smrg}
1293848b8605Smrg
1294848b8605Smrgstatic void
1295848b8605Smrgdri_destroy(struct gbm_device *gbm)
1296848b8605Smrg{
1297848b8605Smrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1298b8e80941Smrg   unsigned i;
1299b8e80941Smrg
1300b8e80941Smrg   if (dri->context)
1301b8e80941Smrg      dri->core->destroyContext(dri->context);
1302848b8605Smrg
1303848b8605Smrg   dri->core->destroyScreen(dri->screen);
1304b8e80941Smrg   for (i = 0; dri->driver_configs[i]; i++)
1305b8e80941Smrg      free((__DRIconfig *) dri->driver_configs[i]);
1306848b8605Smrg   free(dri->driver_configs);
1307848b8605Smrg   dlclose(dri->driver);
1308b8e80941Smrg   free(dri->driver_name);
1309848b8605Smrg
1310848b8605Smrg   free(dri);
1311848b8605Smrg}
1312848b8605Smrg
1313848b8605Smrgstatic struct gbm_device *
1314848b8605Smrgdri_device_create(int fd)
1315848b8605Smrg{
1316848b8605Smrg   struct gbm_dri_device *dri;
1317b8e80941Smrg   int ret;
1318b8e80941Smrg   bool force_sw;
1319848b8605Smrg
1320848b8605Smrg   dri = calloc(1, sizeof *dri);
1321848b8605Smrg   if (!dri)
1322848b8605Smrg      return NULL;
1323848b8605Smrg
1324b8e80941Smrg   dri->base.fd = fd;
1325b8e80941Smrg   dri->base.bo_create = gbm_dri_bo_create;
1326b8e80941Smrg   dri->base.bo_import = gbm_dri_bo_import;
1327b8e80941Smrg   dri->base.bo_map = gbm_dri_bo_map;
1328b8e80941Smrg   dri->base.bo_unmap = gbm_dri_bo_unmap;
1329b8e80941Smrg   dri->base.is_format_supported = gbm_dri_is_format_supported;
1330b8e80941Smrg   dri->base.get_format_modifier_plane_count =
1331b8e80941Smrg      gbm_dri_get_format_modifier_plane_count;
1332b8e80941Smrg   dri->base.bo_write = gbm_dri_bo_write;
1333b8e80941Smrg   dri->base.bo_get_fd = gbm_dri_bo_get_fd;
1334b8e80941Smrg   dri->base.bo_get_planes = gbm_dri_bo_get_planes;
1335b8e80941Smrg   dri->base.bo_get_handle = gbm_dri_bo_get_handle_for_plane;
1336b8e80941Smrg   dri->base.bo_get_stride = gbm_dri_bo_get_stride;
1337b8e80941Smrg   dri->base.bo_get_offset = gbm_dri_bo_get_offset;
1338b8e80941Smrg   dri->base.bo_get_modifier = gbm_dri_bo_get_modifier;
1339b8e80941Smrg   dri->base.bo_destroy = gbm_dri_bo_destroy;
1340b8e80941Smrg   dri->base.destroy = dri_destroy;
1341b8e80941Smrg   dri->base.surface_create = gbm_dri_surface_create;
1342b8e80941Smrg   dri->base.surface_destroy = gbm_dri_surface_destroy;
1343b8e80941Smrg
1344b8e80941Smrg   dri->base.name = "drm";
1345b8e80941Smrg
1346b8e80941Smrg   dri->visual_table = gbm_dri_visuals_table;
1347b8e80941Smrg   dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table);
1348b8e80941Smrg
1349b8e80941Smrg   mtx_init(&dri->mutex, mtx_plain);
1350b8e80941Smrg
1351b8e80941Smrg   force_sw = env_var_as_boolean("GBM_ALWAYS_SOFTWARE", false);
1352848b8605Smrg   if (!force_sw) {
1353848b8605Smrg      ret = dri_screen_create(dri);
1354848b8605Smrg      if (ret)
1355848b8605Smrg         ret = dri_screen_create_sw(dri);
1356848b8605Smrg   } else {
1357848b8605Smrg      ret = dri_screen_create_sw(dri);
1358848b8605Smrg   }
1359848b8605Smrg
1360848b8605Smrg   if (ret)
1361848b8605Smrg      goto err_dri;
1362848b8605Smrg
1363b8e80941Smrg   return &dri->base;
1364848b8605Smrg
1365848b8605Smrgerr_dri:
1366848b8605Smrg   free(dri);
1367848b8605Smrg
1368848b8605Smrg   return NULL;
1369848b8605Smrg}
1370848b8605Smrg
1371848b8605Smrgstruct gbm_backend gbm_dri_backend = {
1372848b8605Smrg   .backend_name = "dri",
1373848b8605Smrg   .create_device = dri_device_create,
1374848b8605Smrg};
1375