13464ebd5Sriastradh/*
23464ebd5Sriastradh * Copyright © 2011 Intel Corporation
33464ebd5Sriastradh *
43464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
53464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"),
63464ebd5Sriastradh * to deal in the Software without restriction, including without limitation
73464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
93464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions:
103464ebd5Sriastradh *
113464ebd5Sriastradh * The above copyright notice and this permission notice (including the next
123464ebd5Sriastradh * paragraph) shall be included in all copies or substantial portions of the
133464ebd5Sriastradh * Software.
143464ebd5Sriastradh *
153464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
163464ebd5Sriastradh * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
173464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
183464ebd5Sriastradh * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
193464ebd5Sriastradh * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
203464ebd5Sriastradh * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
213464ebd5Sriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
223464ebd5Sriastradh * DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh *
243464ebd5Sriastradh * Authors:
253464ebd5Sriastradh *    Benjamin Franzke <benjaminfranzke@googlemail.com>
263464ebd5Sriastradh */
273464ebd5Sriastradh
283464ebd5Sriastradh#include <stdio.h>
293464ebd5Sriastradh#include <stdlib.h>
303464ebd5Sriastradh#include <stddef.h>
313464ebd5Sriastradh#include <stdint.h>
327e995a2eSmrg#include <stdbool.h>
333464ebd5Sriastradh#include <string.h>
34af69d88dSmrg#include <errno.h>
353464ebd5Sriastradh#include <limits.h>
367e995a2eSmrg#include <assert.h>
373464ebd5Sriastradh
383464ebd5Sriastradh#include <sys/types.h>
393464ebd5Sriastradh#include <unistd.h>
403464ebd5Sriastradh#include <dlfcn.h>
41af69d88dSmrg#include <xf86drm.h>
42d8407755Smaya#include "drm-uapi/drm_fourcc.h"
433464ebd5Sriastradh
443464ebd5Sriastradh#include <GL/gl.h> /* dri_interface needs GL types */
453464ebd5Sriastradh#include <GL/internal/dri_interface.h>
463464ebd5Sriastradh
473464ebd5Sriastradh#include "gbm_driint.h"
483464ebd5Sriastradh
493464ebd5Sriastradh#include "gbmint.h"
501463c08dSmrg#include "loader_dri_helper.h"
51af69d88dSmrg#include "loader.h"
527e995a2eSmrg#include "util/debug.h"
537e995a2eSmrg#include "util/macros.h"
54af69d88dSmrg
55af69d88dSmrg/* For importing wl_buffer */
56af69d88dSmrg#if HAVE_WAYLAND_PLATFORM
577e995a2eSmrg#include "wayland-drm.h"
587e995a2eSmrg#endif
597e995a2eSmrg
603464ebd5Sriastradhstatic __DRIimage *
613464ebd5Sriastradhdri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
623464ebd5Sriastradh{
633464ebd5Sriastradh   struct gbm_dri_device *dri = data;
643464ebd5Sriastradh
653464ebd5Sriastradh   if (dri->lookup_image == NULL)
663464ebd5Sriastradh      return NULL;
673464ebd5Sriastradh
683464ebd5Sriastradh   return dri->lookup_image(screen, image, dri->lookup_user_data);
693464ebd5Sriastradh}
703464ebd5Sriastradh
711463c08dSmrgstatic GLboolean
721463c08dSmrgdri_validate_egl_image(void *image, void *data)
731463c08dSmrg{
741463c08dSmrg   struct gbm_dri_device *dri = data;
751463c08dSmrg
761463c08dSmrg   if (dri->validate_image == NULL)
771463c08dSmrg      return false;
781463c08dSmrg
791463c08dSmrg   return dri->validate_image(image, dri->lookup_user_data);
801463c08dSmrg}
811463c08dSmrg
821463c08dSmrgstatic __DRIimage *
831463c08dSmrgdri_lookup_egl_image_validated(void *image, void *data)
841463c08dSmrg{
851463c08dSmrg   struct gbm_dri_device *dri = data;
861463c08dSmrg
871463c08dSmrg   if (dri->lookup_image_validated == NULL)
881463c08dSmrg      return NULL;
891463c08dSmrg
901463c08dSmrg   return dri->lookup_image_validated(image, dri->lookup_user_data);
911463c08dSmrg}
921463c08dSmrg
93af69d88dSmrgstatic __DRIbuffer *
94af69d88dSmrgdri_get_buffers(__DRIdrawable * driDrawable,
95af69d88dSmrg		 int *width, int *height,
96af69d88dSmrg		 unsigned int *attachments, int count,
97af69d88dSmrg		 int *out_count, void *data)
98af69d88dSmrg{
99af69d88dSmrg   struct gbm_dri_surface *surf = data;
100af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
101af69d88dSmrg
102af69d88dSmrg   if (dri->get_buffers == NULL)
103af69d88dSmrg      return NULL;
104af69d88dSmrg
105af69d88dSmrg   return dri->get_buffers(driDrawable, width, height, attachments,
106af69d88dSmrg                           count, out_count, surf->dri_private);
107af69d88dSmrg}
108af69d88dSmrg
109af69d88dSmrgstatic void
110af69d88dSmrgdri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
111af69d88dSmrg{
112af69d88dSmrg   struct gbm_dri_surface *surf = data;
113af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
114af69d88dSmrg
115af69d88dSmrg   if (dri->flush_front_buffer != NULL)
116af69d88dSmrg      dri->flush_front_buffer(driDrawable, surf->dri_private);
117af69d88dSmrg}
118af69d88dSmrg
119af69d88dSmrgstatic __DRIbuffer *
120af69d88dSmrgdri_get_buffers_with_format(__DRIdrawable * driDrawable,
121af69d88dSmrg                            int *width, int *height,
122af69d88dSmrg                            unsigned int *attachments, int count,
123af69d88dSmrg                            int *out_count, void *data)
124af69d88dSmrg{
125af69d88dSmrg   struct gbm_dri_surface *surf = data;
126af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
127af69d88dSmrg
128af69d88dSmrg   if (dri->get_buffers_with_format == NULL)
129af69d88dSmrg      return NULL;
130af69d88dSmrg
131af69d88dSmrg   return
132af69d88dSmrg      dri->get_buffers_with_format(driDrawable, width, height, attachments,
133af69d88dSmrg                                   count, out_count, surf->dri_private);
134af69d88dSmrg}
135af69d88dSmrg
1361463c08dSmrgstatic unsigned
1371463c08dSmrgdri_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
1381463c08dSmrg{
1391463c08dSmrg   /* Note: loaderPrivate is _EGLDisplay* */
1401463c08dSmrg   switch (cap) {
1411463c08dSmrg   case DRI_LOADER_CAP_FP16:
1421463c08dSmrg      return 1;
1431463c08dSmrg   default:
1441463c08dSmrg      return 0;
1451463c08dSmrg   }
1461463c08dSmrg}
1471463c08dSmrg
148af69d88dSmrgstatic int
149af69d88dSmrgimage_get_buffers(__DRIdrawable *driDrawable,
150af69d88dSmrg                  unsigned int format,
151af69d88dSmrg                  uint32_t *stamp,
152af69d88dSmrg                  void *loaderPrivate,
153af69d88dSmrg                  uint32_t buffer_mask,
154af69d88dSmrg                  struct __DRIimageList *buffers)
155af69d88dSmrg{
156af69d88dSmrg   struct gbm_dri_surface *surf = loaderPrivate;
157af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
158af69d88dSmrg
159af69d88dSmrg   if (dri->image_get_buffers == NULL)
160af69d88dSmrg      return 0;
161af69d88dSmrg
162af69d88dSmrg   return dri->image_get_buffers(driDrawable, format, stamp,
163af69d88dSmrg                                 surf->dri_private, buffer_mask, buffers);
164af69d88dSmrg}
165af69d88dSmrg
166af69d88dSmrgstatic void
167af69d88dSmrgswrast_get_drawable_info(__DRIdrawable *driDrawable,
168af69d88dSmrg                         int           *x,
169af69d88dSmrg                         int           *y,
170af69d88dSmrg                         int           *width,
171af69d88dSmrg                         int           *height,
172af69d88dSmrg                         void          *loaderPrivate)
173af69d88dSmrg{
174af69d88dSmrg   struct gbm_dri_surface *surf = loaderPrivate;
175af69d88dSmrg
176af69d88dSmrg   *x = 0;
177af69d88dSmrg   *y = 0;
1781463c08dSmrg   *width = surf->base.v0.width;
1791463c08dSmrg   *height = surf->base.v0.height;
180af69d88dSmrg}
181af69d88dSmrg
182af69d88dSmrgstatic void
183af69d88dSmrgswrast_put_image2(__DRIdrawable *driDrawable,
184af69d88dSmrg                  int            op,
185af69d88dSmrg                  int            x,
186af69d88dSmrg                  int            y,
187af69d88dSmrg                  int            width,
188af69d88dSmrg                  int            height,
189af69d88dSmrg                  int            stride,
190af69d88dSmrg                  char          *data,
191af69d88dSmrg                  void          *loaderPrivate)
192af69d88dSmrg{
193af69d88dSmrg   struct gbm_dri_surface *surf = loaderPrivate;
194af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
195af69d88dSmrg
196af69d88dSmrg   dri->swrast_put_image2(driDrawable,
197af69d88dSmrg                          op, x, y,
198af69d88dSmrg                          width, height, stride,
199af69d88dSmrg                          data, surf->dri_private);
200af69d88dSmrg}
201af69d88dSmrg
202af69d88dSmrgstatic void
203af69d88dSmrgswrast_put_image(__DRIdrawable *driDrawable,
204af69d88dSmrg                 int            op,
205af69d88dSmrg                 int            x,
206af69d88dSmrg                 int            y,
207af69d88dSmrg                 int            width,
208af69d88dSmrg                 int            height,
209af69d88dSmrg                 char          *data,
210af69d88dSmrg                 void          *loaderPrivate)
211af69d88dSmrg{
212382a3c73Schristos   swrast_put_image2(driDrawable, op, x, y, width, height,
213d8407755Smaya                            width * 4, data, loaderPrivate);
214af69d88dSmrg}
215af69d88dSmrg
216af69d88dSmrgstatic void
217af69d88dSmrgswrast_get_image(__DRIdrawable *driDrawable,
218af69d88dSmrg                 int            x,
219af69d88dSmrg                 int            y,
220af69d88dSmrg                 int            width,
221af69d88dSmrg                 int            height,
222af69d88dSmrg                 char          *data,
223af69d88dSmrg                 void          *loaderPrivate)
224af69d88dSmrg{
225af69d88dSmrg   struct gbm_dri_surface *surf = loaderPrivate;
226af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
227af69d88dSmrg
228af69d88dSmrg   dri->swrast_get_image(driDrawable,
229af69d88dSmrg                         x, y,
230af69d88dSmrg                         width, height,
231af69d88dSmrg                         data, surf->dri_private);
232af69d88dSmrg}
233af69d88dSmrg
234af69d88dSmrgstatic const __DRIuseInvalidateExtension use_invalidate = {
235af69d88dSmrg   .base = { __DRI_USE_INVALIDATE, 1 }
236af69d88dSmrg};
237af69d88dSmrg
238af69d88dSmrgstatic const __DRIimageLookupExtension image_lookup_extension = {
2391463c08dSmrg   .base = { __DRI_IMAGE_LOOKUP, 2 },
240af69d88dSmrg
2411463c08dSmrg   .lookupEGLImage          = dri_lookup_egl_image,
2421463c08dSmrg   .validateEGLImage        = dri_validate_egl_image,
2431463c08dSmrg   .lookupEGLImageValidated = dri_lookup_egl_image_validated,
244af69d88dSmrg};
245af69d88dSmrg
246af69d88dSmrgstatic const __DRIdri2LoaderExtension dri2_loader_extension = {
2471463c08dSmrg   .base = { __DRI_DRI2_LOADER, 4 },
248af69d88dSmrg
249af69d88dSmrg   .getBuffers              = dri_get_buffers,
250af69d88dSmrg   .flushFrontBuffer        = dri_flush_front_buffer,
251af69d88dSmrg   .getBuffersWithFormat    = dri_get_buffers_with_format,
2521463c08dSmrg   .getCapability           = dri_get_capability,
2533464ebd5Sriastradh};
2543464ebd5Sriastradh
255af69d88dSmrgstatic const __DRIimageLoaderExtension image_loader_extension = {
2561463c08dSmrg   .base = { __DRI_IMAGE_LOADER, 2 },
257af69d88dSmrg
258af69d88dSmrg   .getBuffers          = image_get_buffers,
259af69d88dSmrg   .flushFrontBuffer    = dri_flush_front_buffer,
2601463c08dSmrg   .getCapability       = dri_get_capability,
261af69d88dSmrg};
262af69d88dSmrg
263af69d88dSmrgstatic const __DRIswrastLoaderExtension swrast_loader_extension = {
264af69d88dSmrg   .base = { __DRI_SWRAST_LOADER, 2 },
265af69d88dSmrg
266af69d88dSmrg   .getDrawableInfo = swrast_get_drawable_info,
267af69d88dSmrg   .putImage        = swrast_put_image,
268af69d88dSmrg   .getImage        = swrast_get_image,
269af69d88dSmrg   .putImage2       = swrast_put_image2
270af69d88dSmrg};
271af69d88dSmrg
272af69d88dSmrgstatic const __DRIextension *gbm_dri_screen_extensions[] = {
273af69d88dSmrg   &image_lookup_extension.base,
274af69d88dSmrg   &use_invalidate.base,
275af69d88dSmrg   &dri2_loader_extension.base,
276af69d88dSmrg   &image_loader_extension.base,
277af69d88dSmrg   &swrast_loader_extension.base,
278af69d88dSmrg   NULL,
2793464ebd5Sriastradh};
2803464ebd5Sriastradh
2813464ebd5Sriastradhstruct dri_extension_match {
2823464ebd5Sriastradh   const char *name;
2833464ebd5Sriastradh   int version;
2843464ebd5Sriastradh   int offset;
2851463c08dSmrg   bool optional;
2863464ebd5Sriastradh};
2873464ebd5Sriastradh
2883464ebd5Sriastradhstatic struct dri_extension_match dri_core_extensions[] = {
2891463c08dSmrg   { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush), false },
2901463c08dSmrg   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image), false },
2911463c08dSmrg   { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), true },
2923464ebd5Sriastradh};
2933464ebd5Sriastradh
2943464ebd5Sriastradhstatic struct dri_extension_match gbm_dri_device_extensions[] = {
2951463c08dSmrg   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false },
2961463c08dSmrg   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2), false },
2973464ebd5Sriastradh};
2983464ebd5Sriastradh
299af69d88dSmrgstatic struct dri_extension_match gbm_swrast_device_extensions[] = {
3001463c08dSmrg   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false },
3011463c08dSmrg   { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast), false },
302af69d88dSmrg};
303af69d88dSmrg
3041463c08dSmrgstatic bool
3053464ebd5Sriastradhdri_bind_extensions(struct gbm_dri_device *dri,
3061463c08dSmrg                    struct dri_extension_match *matches, size_t num_matches,
3073464ebd5Sriastradh                    const __DRIextension **extensions)
3083464ebd5Sriastradh{
3091463c08dSmrg   bool ret = true;
3103464ebd5Sriastradh   void *field;
3113464ebd5Sriastradh
3121463c08dSmrg   for (size_t i = 0; extensions[i]; i++) {
3131463c08dSmrg      for (size_t j = 0; j < num_matches; j++) {
3143464ebd5Sriastradh         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
3153464ebd5Sriastradh             extensions[i]->version >= matches[j].version) {
3163464ebd5Sriastradh            field = ((char *) dri + matches[j].offset);
3173464ebd5Sriastradh            *(const __DRIextension **) field = extensions[i];
3183464ebd5Sriastradh         }
3193464ebd5Sriastradh      }
3203464ebd5Sriastradh   }
3213464ebd5Sriastradh
3221463c08dSmrg   for (size_t j = 0; j < num_matches; j++) {
3233464ebd5Sriastradh      field = ((char *) dri + matches[j].offset);
3247e995a2eSmrg      if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) {
3251463c08dSmrg         fprintf(stderr, "gbm: did not find extension %s version %d\n",
3261463c08dSmrg                 matches[j].name, matches[j].version);
3271463c08dSmrg         ret = false;
3283464ebd5Sriastradh      }
3293464ebd5Sriastradh   }
3303464ebd5Sriastradh
3313464ebd5Sriastradh   return ret;
3323464ebd5Sriastradh}
3333464ebd5Sriastradh
334af69d88dSmrgstatic const __DRIextension **
335af69d88dSmrgdri_open_driver(struct gbm_dri_device *dri)
3363464ebd5Sriastradh{
3377e995a2eSmrg   /* Temporarily work around dri driver libs that need symbols in libglapi
3387e995a2eSmrg    * but don't automatically link it in.
3397e995a2eSmrg    */
3407e995a2eSmrg   /* XXX: Library name differs on per platforms basis. Update this as
3417e995a2eSmrg    * osx/cygwin/windows/bsd gets support for GBM..
3427e995a2eSmrg    */
3437e995a2eSmrg   dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
3447e995a2eSmrg
345d8407755Smaya   static const char *search_path_vars[] = {
346d8407755Smaya      /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
347d8407755Smaya       * is recommended over GBM_DRIVERS_PATH.
348d8407755Smaya       */
349d8407755Smaya      "GBM_DRIVERS_PATH",
350d8407755Smaya      /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
351d8407755Smaya       * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
352d8407755Smaya       */
353d8407755Smaya      "LIBGL_DRIVERS_PATH",
354d8407755Smaya      NULL
355d8407755Smaya   };
356d8407755Smaya   return loader_open_driver(dri->driver_name, &dri->driver, search_path_vars);
357af69d88dSmrg}
358af69d88dSmrg
359af69d88dSmrgstatic int
360af69d88dSmrgdri_load_driver(struct gbm_dri_device *dri)
361af69d88dSmrg{
362af69d88dSmrg   const __DRIextension **extensions;
363af69d88dSmrg
364af69d88dSmrg   extensions = dri_open_driver(dri);
365af69d88dSmrg   if (!extensions)
366af69d88dSmrg      return -1;
3673464ebd5Sriastradh
3681463c08dSmrg   if (!dri_bind_extensions(dri, gbm_dri_device_extensions,
3691463c08dSmrg                            ARRAY_SIZE(gbm_dri_device_extensions),
3701463c08dSmrg                            extensions)) {
3713464ebd5Sriastradh      dlclose(dri->driver);
3723464ebd5Sriastradh      fprintf(stderr, "failed to bind extensions\n");
3733464ebd5Sriastradh      return -1;
3743464ebd5Sriastradh   }
3753464ebd5Sriastradh
376af69d88dSmrg   dri->driver_extensions = extensions;
377af69d88dSmrg
3783464ebd5Sriastradh   return 0;
3793464ebd5Sriastradh}
3803464ebd5Sriastradh
3813464ebd5Sriastradhstatic int
382af69d88dSmrgdri_load_driver_swrast(struct gbm_dri_device *dri)
383af69d88dSmrg{
384af69d88dSmrg   const __DRIextension **extensions;
385af69d88dSmrg
386af69d88dSmrg   extensions = dri_open_driver(dri);
387af69d88dSmrg   if (!extensions)
388af69d88dSmrg      return -1;
389af69d88dSmrg
3901463c08dSmrg   if (!dri_bind_extensions(dri, gbm_swrast_device_extensions,
3911463c08dSmrg                            ARRAY_SIZE(gbm_swrast_device_extensions),
3921463c08dSmrg                            extensions)) {
393af69d88dSmrg      dlclose(dri->driver);
394af69d88dSmrg      fprintf(stderr, "failed to bind extensions\n");
395af69d88dSmrg      return -1;
396af69d88dSmrg   }
397af69d88dSmrg
398af69d88dSmrg   dri->driver_extensions = extensions;
399af69d88dSmrg
400af69d88dSmrg   return 0;
401af69d88dSmrg}
402af69d88dSmrg
403af69d88dSmrgstatic int
4047e995a2eSmrgdri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
4053464ebd5Sriastradh{
4063464ebd5Sriastradh   const __DRIextension **extensions;
4073464ebd5Sriastradh   int ret = 0;
4083464ebd5Sriastradh
4097e995a2eSmrg   dri->driver_name = driver_name;
4107e995a2eSmrg   if (dri->driver_name == NULL)
4113464ebd5Sriastradh      return -1;
4123464ebd5Sriastradh
4133464ebd5Sriastradh   ret = dri_load_driver(dri);
4143464ebd5Sriastradh   if (ret) {
4157e995a2eSmrg      fprintf(stderr, "failed to load driver: %s\n", dri->driver_name);
4163464ebd5Sriastradh      return ret;
4177e995a2eSmrg   }
4183464ebd5Sriastradh
4197e995a2eSmrg   dri->loader_extensions = gbm_dri_screen_extensions;
4203464ebd5Sriastradh
4213464ebd5Sriastradh   if (dri->dri2 == NULL)
4223464ebd5Sriastradh      return -1;
4233464ebd5Sriastradh
424af69d88dSmrg   if (dri->dri2->base.version >= 4) {
4251463c08dSmrg      dri->screen = dri->dri2->createNewScreen2(0, dri->base.v0.fd,
4267e995a2eSmrg                                                dri->loader_extensions,
427af69d88dSmrg                                                dri->driver_extensions,
428af69d88dSmrg                                                &dri->driver_configs, dri);
429af69d88dSmrg   } else {
4301463c08dSmrg      dri->screen = dri->dri2->createNewScreen(0, dri->base.v0.fd,
4317e995a2eSmrg                                               dri->loader_extensions,
432af69d88dSmrg                                               &dri->driver_configs, dri);
433af69d88dSmrg   }
434af69d88dSmrg   if (dri->screen == NULL)
435af69d88dSmrg      return -1;
4363464ebd5Sriastradh
4373464ebd5Sriastradh   extensions = dri->core->getExtensions(dri->screen);
4381463c08dSmrg   if (!dri_bind_extensions(dri, dri_core_extensions,
4391463c08dSmrg                            ARRAY_SIZE(dri_core_extensions),
4401463c08dSmrg                            extensions)) {
4413464ebd5Sriastradh      ret = -1;
4423464ebd5Sriastradh      goto free_screen;
4433464ebd5Sriastradh   }
4443464ebd5Sriastradh
4453464ebd5Sriastradh   dri->lookup_image = NULL;
4463464ebd5Sriastradh   dri->lookup_user_data = NULL;
4473464ebd5Sriastradh
4483464ebd5Sriastradh   return 0;
4493464ebd5Sriastradh
4503464ebd5Sriastradhfree_screen:
4513464ebd5Sriastradh   dri->core->destroyScreen(dri->screen);
4523464ebd5Sriastradh
4533464ebd5Sriastradh   return ret;
4543464ebd5Sriastradh}
4553464ebd5Sriastradh
456af69d88dSmrgstatic int
457af69d88dSmrgdri_screen_create_swrast(struct gbm_dri_device *dri)
458af69d88dSmrg{
459af69d88dSmrg   int ret;
460af69d88dSmrg
4617e995a2eSmrg   dri->driver_name = strdup("swrast");
4627e995a2eSmrg   if (dri->driver_name == NULL)
463af69d88dSmrg      return -1;
464af69d88dSmrg
465af69d88dSmrg   ret = dri_load_driver_swrast(dri);
466af69d88dSmrg   if (ret) {
467af69d88dSmrg      fprintf(stderr, "failed to load swrast driver\n");
468af69d88dSmrg      return ret;
469af69d88dSmrg   }
470af69d88dSmrg
4717e995a2eSmrg   dri->loader_extensions = gbm_dri_screen_extensions;
472af69d88dSmrg
473af69d88dSmrg   if (dri->swrast == NULL)
474af69d88dSmrg      return -1;
475af69d88dSmrg
476af69d88dSmrg   if (dri->swrast->base.version >= 4) {
4777e995a2eSmrg      dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions,
478af69d88dSmrg                                                  dri->driver_extensions,
479af69d88dSmrg                                                  &dri->driver_configs, dri);
480af69d88dSmrg   } else {
4817e995a2eSmrg      dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions,
482af69d88dSmrg                                                 &dri->driver_configs, dri);
483af69d88dSmrg   }
484af69d88dSmrg   if (dri->screen == NULL)
485af69d88dSmrg      return -1;
486af69d88dSmrg
487af69d88dSmrg   dri->lookup_image = NULL;
488af69d88dSmrg   dri->lookup_user_data = NULL;
489af69d88dSmrg
490af69d88dSmrg   return 0;
491af69d88dSmrg}
492af69d88dSmrg
493af69d88dSmrgstatic int
494af69d88dSmrgdri_screen_create(struct gbm_dri_device *dri)
495af69d88dSmrg{
4967e995a2eSmrg   char *driver_name;
497af69d88dSmrg
4981463c08dSmrg   driver_name = loader_get_driver_for_fd(dri->base.v0.fd);
499af69d88dSmrg   if (!driver_name)
500af69d88dSmrg      return -1;
501af69d88dSmrg
502af69d88dSmrg   return dri_screen_create_dri2(dri, driver_name);
503af69d88dSmrg}
504af69d88dSmrg
505af69d88dSmrgstatic int
506af69d88dSmrgdri_screen_create_sw(struct gbm_dri_device *dri)
507af69d88dSmrg{
5087e995a2eSmrg   char *driver_name;
509af69d88dSmrg   int ret;
510af69d88dSmrg
511af69d88dSmrg   driver_name = strdup("kms_swrast");
512af69d88dSmrg   if (!driver_name)
513af69d88dSmrg      return -errno;
514af69d88dSmrg
515af69d88dSmrg   ret = dri_screen_create_dri2(dri, driver_name);
5161463c08dSmrg   if (ret != 0)
5171463c08dSmrg      ret = dri_screen_create_swrast(dri);
5181463c08dSmrg   if (ret != 0)
519af69d88dSmrg      return ret;
520af69d88dSmrg
5211463c08dSmrg   dri->software = true;
5221463c08dSmrg   return 0;
523af69d88dSmrg}
524af69d88dSmrg
5257e995a2eSmrgstatic const struct gbm_dri_visual gbm_dri_visuals_table[] = {
5267e995a2eSmrg   {
5277e995a2eSmrg     GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8,
5281463c08dSmrg     { 0, -1, -1, -1 },
5291463c08dSmrg     { 8, 0, 0, 0 },
5301463c08dSmrg   },
5311463c08dSmrg   {
5321463c08dSmrg     GBM_FORMAT_R16, __DRI_IMAGE_FORMAT_R16,
5331463c08dSmrg     { 0, -1, -1, -1 },
5341463c08dSmrg     { 16, 0, 0, 0 },
5357e995a2eSmrg   },
5367e995a2eSmrg   {
5377e995a2eSmrg     GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88,
5381463c08dSmrg     { 0, 8, -1, -1 },
5391463c08dSmrg     { 8, 8, 0, 0 },
5407e995a2eSmrg   },
5417e995a2eSmrg   {
5427e995a2eSmrg     GBM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555,
5431463c08dSmrg     { 10, 5, 0, 11 },
5441463c08dSmrg     { 5, 5, 5, 1 },
5457e995a2eSmrg   },
5467e995a2eSmrg   {
5477e995a2eSmrg     GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565,
5481463c08dSmrg     { 11, 5, 0, -1 },
5491463c08dSmrg     { 5, 6, 5, 0 },
5507e995a2eSmrg   },
5517e995a2eSmrg   {
5527e995a2eSmrg     GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888,
5531463c08dSmrg     { 16, 8, 0, -1 },
5541463c08dSmrg     { 8, 8, 8, 0 },
5557e995a2eSmrg   },
5567e995a2eSmrg   {
5577e995a2eSmrg     GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888,
5581463c08dSmrg     { 16, 8, 0, 24 },
5591463c08dSmrg     { 8, 8, 8, 8 },
5607e995a2eSmrg   },
5617e995a2eSmrg   {
5627e995a2eSmrg     GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888,
5631463c08dSmrg     { 0, 8, 16, -1 },
5641463c08dSmrg     { 8, 8, 8, 0 },
5657e995a2eSmrg   },
5667e995a2eSmrg   {
5677e995a2eSmrg     GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888,
5681463c08dSmrg     { 0, 8, 16, 24 },
5691463c08dSmrg     { 8, 8, 8, 8 },
5707e995a2eSmrg   },
5717e995a2eSmrg   {
5727e995a2eSmrg     GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010,
5731463c08dSmrg     { 20, 10, 0, -1 },
5741463c08dSmrg     { 10, 10, 10, 0 },
5757e995a2eSmrg   },
5767e995a2eSmrg   {
5777e995a2eSmrg     GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010,
5781463c08dSmrg     { 20, 10, 0, 30 },
5791463c08dSmrg     { 10, 10, 10, 2 },
5807e995a2eSmrg   },
5817e995a2eSmrg   {
5827e995a2eSmrg     GBM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010,
5831463c08dSmrg     { 0, 10, 20, -1 },
5841463c08dSmrg     { 10, 10, 10, 0 },
5857e995a2eSmrg   },
5867e995a2eSmrg   {
5877e995a2eSmrg     GBM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010,
5881463c08dSmrg     { 0, 10, 20, 30 },
5891463c08dSmrg     { 10, 10, 10, 2 },
5901463c08dSmrg   },
5911463c08dSmrg   {
5921463c08dSmrg     GBM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F,
5931463c08dSmrg     { 0, 16, 32, -1 },
5941463c08dSmrg     { 16, 16, 16, 0 },
5951463c08dSmrg     true,
5961463c08dSmrg   },
5971463c08dSmrg   {
5981463c08dSmrg     GBM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F,
5991463c08dSmrg     { 0, 16, 32, 48 },
6001463c08dSmrg     { 16, 16, 16, 16 },
6011463c08dSmrg     true,
6027e995a2eSmrg   },
6037e995a2eSmrg};
6047e995a2eSmrg
6057e995a2eSmrgstatic int
6067e995a2eSmrggbm_format_to_dri_format(uint32_t gbm_format)
6077e995a2eSmrg{
6081463c08dSmrg   gbm_format = gbm_core.v0.format_canonicalize(gbm_format);
6091463c08dSmrg   for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
6107e995a2eSmrg      if (gbm_dri_visuals_table[i].gbm_format == gbm_format)
6117e995a2eSmrg         return gbm_dri_visuals_table[i].dri_image_format;
6127e995a2eSmrg   }
6137e995a2eSmrg
6147e995a2eSmrg   return 0;
6157e995a2eSmrg}
6167e995a2eSmrg
6177e995a2eSmrgstatic uint32_t
6187e995a2eSmrggbm_dri_to_gbm_format(int dri_format)
6197e995a2eSmrg{
6201463c08dSmrg   for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
6217e995a2eSmrg      if (gbm_dri_visuals_table[i].dri_image_format == dri_format)
6227e995a2eSmrg         return gbm_dri_visuals_table[i].gbm_format;
6237e995a2eSmrg   }
6247e995a2eSmrg
6257e995a2eSmrg   return 0;
6267e995a2eSmrg}
6277e995a2eSmrg
6287e995a2eSmrgstatic int
6297e995a2eSmrggbm_dri_is_format_supported(struct gbm_device *gbm,
6307e995a2eSmrg                            uint32_t format,
6317e995a2eSmrg                            uint32_t usage)
6327e995a2eSmrg{
6337e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
6347e995a2eSmrg   int count;
6357e995a2eSmrg
6367e995a2eSmrg   if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING))
6377e995a2eSmrg      return 0;
6387e995a2eSmrg
6391463c08dSmrg   format = gbm_core.v0.format_canonicalize(format);
6407e995a2eSmrg   if (gbm_format_to_dri_format(format) == 0)
6413464ebd5Sriastradh      return 0;
6427e995a2eSmrg
6437e995a2eSmrg   /* If there is no query, fall back to the small table which was originally
6447e995a2eSmrg    * here. */
6457e995a2eSmrg   if (dri->image->base.version <= 15 || !dri->image->queryDmaBufModifiers) {
6467e995a2eSmrg      switch (format) {
6477e995a2eSmrg      case GBM_FORMAT_XRGB8888:
6487e995a2eSmrg      case GBM_FORMAT_ARGB8888:
6497e995a2eSmrg      case GBM_FORMAT_XBGR8888:
6507e995a2eSmrg         return 1;
6517e995a2eSmrg      default:
6527e995a2eSmrg         return 0;
6537e995a2eSmrg      }
6543464ebd5Sriastradh   }
6553464ebd5Sriastradh
6561463c08dSmrg   /* This returns false if the format isn't supported */
6577e995a2eSmrg   if (!dri->image->queryDmaBufModifiers(dri->screen, format, 0, NULL, NULL,
6587e995a2eSmrg                                         &count))
6593464ebd5Sriastradh      return 0;
6603464ebd5Sriastradh
6611463c08dSmrg   return 1;
6627e995a2eSmrg}
6637e995a2eSmrg
6647e995a2eSmrgstatic int
6657e995a2eSmrggbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm,
6667e995a2eSmrg                                        uint32_t format,
6677e995a2eSmrg                                        uint64_t modifier)
6687e995a2eSmrg{
6697e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
6707e995a2eSmrg   uint64_t plane_count;
6717e995a2eSmrg
6727e995a2eSmrg   if (dri->image->base.version < 16 ||
6737e995a2eSmrg       !dri->image->queryDmaBufFormatModifierAttribs)
6747e995a2eSmrg      return -1;
6757e995a2eSmrg
6761463c08dSmrg   format = gbm_core.v0.format_canonicalize(format);
6777e995a2eSmrg   if (gbm_format_to_dri_format(format) == 0)
6787e995a2eSmrg      return -1;
6797e995a2eSmrg
6807e995a2eSmrg   if (!dri->image->queryDmaBufFormatModifierAttribs(
6817e995a2eSmrg         dri->screen, format, modifier,
6827e995a2eSmrg         __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT, &plane_count))
6837e995a2eSmrg      return -1;
6847e995a2eSmrg
6857e995a2eSmrg   return plane_count;
6863464ebd5Sriastradh}
6873464ebd5Sriastradh
688af69d88dSmrgstatic int
689af69d88dSmrggbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
690af69d88dSmrg{
691af69d88dSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
692af69d88dSmrg
693af69d88dSmrg   if (bo->image != NULL) {
694af69d88dSmrg      errno = EINVAL;
695af69d88dSmrg      return -1;
696af69d88dSmrg   }
697af69d88dSmrg
698af69d88dSmrg   memcpy(bo->map, buf, count);
699af69d88dSmrg
700af69d88dSmrg   return 0;
701af69d88dSmrg}
702af69d88dSmrg
703af69d88dSmrgstatic int
704af69d88dSmrggbm_dri_bo_get_fd(struct gbm_bo *_bo)
705af69d88dSmrg{
706af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
707af69d88dSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
708af69d88dSmrg   int fd;
709af69d88dSmrg
710af69d88dSmrg   if (bo->image == NULL)
711af69d88dSmrg      return -1;
712af69d88dSmrg
7137e995a2eSmrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
7147e995a2eSmrg      return -1;
715af69d88dSmrg
716af69d88dSmrg   return fd;
717af69d88dSmrg}
718af69d88dSmrg
7197e995a2eSmrgstatic int
7207e995a2eSmrgget_number_planes(struct gbm_dri_device *dri, __DRIimage *image)
7217e995a2eSmrg{
7227e995a2eSmrg   int num_planes = 0;
7237e995a2eSmrg
7247e995a2eSmrg   /* Dumb buffers are single-plane only. */
7257e995a2eSmrg   if (!image)
7267e995a2eSmrg      return 1;
7277e995a2eSmrg
7287e995a2eSmrg   dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);
7297e995a2eSmrg
7307e995a2eSmrg   if (num_planes <= 0)
7317e995a2eSmrg      num_planes = 1;
7327e995a2eSmrg
7337e995a2eSmrg   return num_planes;
7347e995a2eSmrg}
7357e995a2eSmrg
7367e995a2eSmrgstatic int
7377e995a2eSmrggbm_dri_bo_get_planes(struct gbm_bo *_bo)
7383464ebd5Sriastradh{
7393464ebd5Sriastradh   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
7403464ebd5Sriastradh   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
741af69d88dSmrg
7427e995a2eSmrg   return get_number_planes(dri, bo->image);
7437e995a2eSmrg}
7447e995a2eSmrg
7457e995a2eSmrgstatic union gbm_bo_handle
7467e995a2eSmrggbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane)
7477e995a2eSmrg{
7487e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
7497e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
7507e995a2eSmrg   union gbm_bo_handle ret;
7517e995a2eSmrg   ret.s32 = -1;
7527e995a2eSmrg
7537e995a2eSmrg   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
7541463c08dSmrg      /* Preserve legacy behavior if plane is 0 */
7551463c08dSmrg      if (plane == 0) {
7561463c08dSmrg         /* NOTE: return _bo->handle, *NOT* bo->handle which is invalid at this point */
7571463c08dSmrg         return _bo->v0.handle;
7581463c08dSmrg      }
7591463c08dSmrg
7607e995a2eSmrg      errno = ENOSYS;
7617e995a2eSmrg      return ret;
7627e995a2eSmrg   }
7637e995a2eSmrg
7647e995a2eSmrg   if (plane >= get_number_planes(dri, bo->image)) {
7657e995a2eSmrg      errno = EINVAL;
7667e995a2eSmrg      return ret;
7677e995a2eSmrg   }
7687e995a2eSmrg
7697e995a2eSmrg   /* dumb BOs can only utilize non-planar formats */
7707e995a2eSmrg   if (!bo->image) {
7717e995a2eSmrg      assert(plane == 0);
7727e995a2eSmrg      ret.s32 = bo->handle;
7737e995a2eSmrg      return ret;
7747e995a2eSmrg   }
7757e995a2eSmrg
7767e995a2eSmrg   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
7777e995a2eSmrg   if (image) {
7787e995a2eSmrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
7797e995a2eSmrg      dri->image->destroyImage(image);
780af69d88dSmrg   } else {
7817e995a2eSmrg      assert(plane == 0);
7827e995a2eSmrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
783af69d88dSmrg   }
7843464ebd5Sriastradh
7857e995a2eSmrg   return ret;
7863464ebd5Sriastradh}
7873464ebd5Sriastradh
7881463c08dSmrgstatic int
7891463c08dSmrggbm_dri_bo_get_plane_fd(struct gbm_bo *_bo, int plane)
7901463c08dSmrg{
7911463c08dSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
7921463c08dSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
7931463c08dSmrg   int fd = -1;
7941463c08dSmrg
7951463c08dSmrg   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
7961463c08dSmrg      /* Preserve legacy behavior if plane is 0 */
7971463c08dSmrg      if (plane == 0)
7981463c08dSmrg         return gbm_dri_bo_get_fd(_bo);
7991463c08dSmrg
8001463c08dSmrg      errno = ENOSYS;
8011463c08dSmrg      return -1;
8021463c08dSmrg   }
8031463c08dSmrg
8041463c08dSmrg   /* dumb BOs can only utilize non-planar formats */
8051463c08dSmrg   if (!bo->image) {
8061463c08dSmrg      errno = EINVAL;
8071463c08dSmrg      return -1;
8081463c08dSmrg   }
8091463c08dSmrg
8101463c08dSmrg   if (plane >= get_number_planes(dri, bo->image)) {
8111463c08dSmrg      errno = EINVAL;
8121463c08dSmrg      return -1;
8131463c08dSmrg   }
8141463c08dSmrg
8151463c08dSmrg   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
8161463c08dSmrg   if (image) {
8171463c08dSmrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
8181463c08dSmrg      dri->image->destroyImage(image);
8191463c08dSmrg   } else {
8201463c08dSmrg      assert(plane == 0);
8211463c08dSmrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd);
8221463c08dSmrg   }
8231463c08dSmrg
8241463c08dSmrg   return fd;
8251463c08dSmrg}
8261463c08dSmrg
827af69d88dSmrgstatic uint32_t
8287e995a2eSmrggbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
829af69d88dSmrg{
8307e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
8317e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
8327e995a2eSmrg   __DRIimage *image;
8337e995a2eSmrg   int stride = 0;
834af69d88dSmrg
8357e995a2eSmrg   if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) {
8367e995a2eSmrg      /* Preserve legacy behavior if plane is 0 */
8377e995a2eSmrg      if (plane == 0)
8381463c08dSmrg         return _bo->v0.stride;
8397e995a2eSmrg
8407e995a2eSmrg      errno = ENOSYS;
8417e995a2eSmrg      return 0;
8427e995a2eSmrg   }
8437e995a2eSmrg
8447e995a2eSmrg   if (plane >= get_number_planes(dri, bo->image)) {
8457e995a2eSmrg      errno = EINVAL;
8467e995a2eSmrg      return 0;
8477e995a2eSmrg   }
8487e995a2eSmrg
8497e995a2eSmrg   if (bo->image == NULL) {
8507e995a2eSmrg      assert(plane == 0);
8511463c08dSmrg      return _bo->v0.stride;
8527e995a2eSmrg   }
8537e995a2eSmrg
8547e995a2eSmrg   image = dri->image->fromPlanar(bo->image, plane, NULL);
8557e995a2eSmrg   if (image) {
8567e995a2eSmrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
8577e995a2eSmrg      dri->image->destroyImage(image);
8587e995a2eSmrg   } else {
8597e995a2eSmrg      assert(plane == 0);
8607e995a2eSmrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
861af69d88dSmrg   }
862af69d88dSmrg
8637e995a2eSmrg   return (uint32_t)stride;
8647e995a2eSmrg}
8657e995a2eSmrg
8667e995a2eSmrgstatic uint32_t
8677e995a2eSmrggbm_dri_bo_get_offset(struct gbm_bo *_bo, int plane)
8687e995a2eSmrg{
8697e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
8707e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
8717e995a2eSmrg   int offset = 0;
8727e995a2eSmrg
8737e995a2eSmrg   /* These error cases do not actually return an error code, as the user
8747e995a2eSmrg    * will also fail to obtain the handle/FD from the BO. In that case, the
8757e995a2eSmrg    * offset is irrelevant, as they have no buffer to offset into, so
8767e995a2eSmrg    * returning 0 is harmless.
8777e995a2eSmrg    */
8787e995a2eSmrg   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar)
8797e995a2eSmrg      return 0;
8807e995a2eSmrg
8817e995a2eSmrg   if (plane >= get_number_planes(dri, bo->image))
8827e995a2eSmrg      return 0;
8837e995a2eSmrg
8847e995a2eSmrg    /* Dumb images have no offset */
8857e995a2eSmrg   if (bo->image == NULL) {
8867e995a2eSmrg      assert(plane == 0);
8877e995a2eSmrg      return 0;
8887e995a2eSmrg   }
8897e995a2eSmrg
8907e995a2eSmrg   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
8917e995a2eSmrg   if (image) {
8927e995a2eSmrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
8937e995a2eSmrg      dri->image->destroyImage(image);
8947e995a2eSmrg   } else {
8957e995a2eSmrg      assert(plane == 0);
8967e995a2eSmrg      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
8977e995a2eSmrg   }
8987e995a2eSmrg
8997e995a2eSmrg   return (uint32_t)offset;
9007e995a2eSmrg}
9017e995a2eSmrg
9027e995a2eSmrgstatic uint64_t
9037e995a2eSmrggbm_dri_bo_get_modifier(struct gbm_bo *_bo)
9047e995a2eSmrg{
9057e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
9067e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
9077e995a2eSmrg
9087e995a2eSmrg   if (!dri->image || dri->image->base.version < 14) {
9097e995a2eSmrg      errno = ENOSYS;
9107e995a2eSmrg      return DRM_FORMAT_MOD_INVALID;
9117e995a2eSmrg   }
9127e995a2eSmrg
9137e995a2eSmrg   /* Dumb buffers have no modifiers */
9147e995a2eSmrg   if (!bo->image)
9157e995a2eSmrg      return DRM_FORMAT_MOD_LINEAR;
9167e995a2eSmrg
9177e995a2eSmrg   uint64_t ret = 0;
9187e995a2eSmrg   int mod;
9197e995a2eSmrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
9207e995a2eSmrg                               &mod))
9217e995a2eSmrg      return DRM_FORMAT_MOD_INVALID;
9227e995a2eSmrg
9237e995a2eSmrg   ret = (uint64_t)mod << 32;
9247e995a2eSmrg
9257e995a2eSmrg   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
9267e995a2eSmrg                               &mod))
9277e995a2eSmrg      return DRM_FORMAT_MOD_INVALID;
9287e995a2eSmrg
9297e995a2eSmrg   ret |= (uint64_t)(mod & 0xffffffff);
9307e995a2eSmrg
931af69d88dSmrg   return ret;
932af69d88dSmrg}
933af69d88dSmrg
9347e995a2eSmrgstatic void
9357e995a2eSmrggbm_dri_bo_destroy(struct gbm_bo *_bo)
9367e995a2eSmrg{
9377e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
9387e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
9397e995a2eSmrg   struct drm_mode_destroy_dumb arg;
9407e995a2eSmrg
9417e995a2eSmrg   if (bo->image != NULL) {
9427e995a2eSmrg      dri->image->destroyImage(bo->image);
9437e995a2eSmrg   } else {
9447e995a2eSmrg      gbm_dri_bo_unmap_dumb(bo);
9457e995a2eSmrg      memset(&arg, 0, sizeof(arg));
9467e995a2eSmrg      arg.handle = bo->handle;
9471463c08dSmrg      drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
9487e995a2eSmrg   }
9497e995a2eSmrg
9507e995a2eSmrg   free(bo);
9517e995a2eSmrg}
9527e995a2eSmrg
9533464ebd5Sriastradhstatic struct gbm_bo *
954af69d88dSmrggbm_dri_bo_import(struct gbm_device *gbm,
955af69d88dSmrg                  uint32_t type, void *buffer, uint32_t usage)
9563464ebd5Sriastradh{
9573464ebd5Sriastradh   struct gbm_dri_device *dri = gbm_dri_device(gbm);
9583464ebd5Sriastradh   struct gbm_dri_bo *bo;
959af69d88dSmrg   __DRIimage *image;
960af69d88dSmrg   unsigned dri_use = 0;
961af69d88dSmrg   int gbm_format;
9623464ebd5Sriastradh
963af69d88dSmrg   /* Required for query image WIDTH & HEIGHT */
964af69d88dSmrg   if (dri->image == NULL || dri->image->base.version < 4) {
965af69d88dSmrg      errno = ENOSYS;
966af69d88dSmrg      return NULL;
967af69d88dSmrg   }
9683464ebd5Sriastradh
969af69d88dSmrg   switch (type) {
970af69d88dSmrg#if HAVE_WAYLAND_PLATFORM
971af69d88dSmrg   case GBM_BO_IMPORT_WL_BUFFER:
972af69d88dSmrg   {
973af69d88dSmrg      struct wl_drm_buffer *wb;
974af69d88dSmrg
975af69d88dSmrg      if (!dri->wl_drm) {
976af69d88dSmrg         errno = EINVAL;
977af69d88dSmrg         return NULL;
978af69d88dSmrg      }
979af69d88dSmrg
980af69d88dSmrg      wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
981af69d88dSmrg      if (!wb) {
982af69d88dSmrg         errno = EINVAL;
983af69d88dSmrg         return NULL;
984af69d88dSmrg      }
985af69d88dSmrg
986af69d88dSmrg      image = dri->image->dupImage(wb->driver_buffer, NULL);
987af69d88dSmrg
9887e995a2eSmrg      /* GBM_FORMAT_* is identical to WL_DRM_FORMAT_*, so no conversion
9897e995a2eSmrg       * required. */
9907e995a2eSmrg      gbm_format = wb->format;
991af69d88dSmrg      break;
992af69d88dSmrg   }
993af69d88dSmrg#endif
994af69d88dSmrg
995af69d88dSmrg   case GBM_BO_IMPORT_EGL_IMAGE:
996af69d88dSmrg   {
997af69d88dSmrg      int dri_format;
998af69d88dSmrg      if (dri->lookup_image == NULL) {
999af69d88dSmrg         errno = EINVAL;
1000af69d88dSmrg         return NULL;
1001af69d88dSmrg      }
1002af69d88dSmrg
1003af69d88dSmrg      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
1004af69d88dSmrg      image = dri->image->dupImage(image, NULL);
1005af69d88dSmrg      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
1006af69d88dSmrg      gbm_format = gbm_dri_to_gbm_format(dri_format);
1007af69d88dSmrg      if (gbm_format == 0) {
1008af69d88dSmrg         errno = EINVAL;
10097e995a2eSmrg         dri->image->destroyImage(image);
1010af69d88dSmrg         return NULL;
1011af69d88dSmrg      }
1012af69d88dSmrg      break;
1013af69d88dSmrg   }
1014af69d88dSmrg
1015af69d88dSmrg   case GBM_BO_IMPORT_FD:
1016af69d88dSmrg   {
1017af69d88dSmrg      struct gbm_import_fd_data *fd_data = buffer;
1018af69d88dSmrg      int stride = fd_data->stride, offset = 0;
10197e995a2eSmrg      int fourcc;
10207e995a2eSmrg
10217e995a2eSmrg      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
10227e995a2eSmrg       * tokens accepted by createImageFromFds, except for not supporting
10237e995a2eSmrg       * the sARGB format. */
10241463c08dSmrg      fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
1025af69d88dSmrg
1026af69d88dSmrg      image = dri->image->createImageFromFds(dri->screen,
1027af69d88dSmrg                                             fd_data->width,
1028af69d88dSmrg                                             fd_data->height,
10297e995a2eSmrg                                             fourcc,
1030af69d88dSmrg                                             &fd_data->fd, 1,
1031af69d88dSmrg                                             &stride, &offset,
1032af69d88dSmrg                                             NULL);
10337e995a2eSmrg      if (image == NULL) {
10347e995a2eSmrg         errno = EINVAL;
10357e995a2eSmrg         return NULL;
10367e995a2eSmrg      }
1037af69d88dSmrg      gbm_format = fd_data->format;
1038af69d88dSmrg      break;
1039af69d88dSmrg   }
1040af69d88dSmrg
10417e995a2eSmrg   case GBM_BO_IMPORT_FD_MODIFIER:
10427e995a2eSmrg   {
10437e995a2eSmrg      struct gbm_import_fd_modifier_data *fd_data = buffer;
10447e995a2eSmrg      unsigned int error;
10457e995a2eSmrg      int fourcc;
10467e995a2eSmrg
10477e995a2eSmrg      /* Import with modifier requires createImageFromDmaBufs2 */
10487e995a2eSmrg      if (dri->image == NULL || dri->image->base.version < 15 ||
10497e995a2eSmrg          dri->image->createImageFromDmaBufs2 == NULL) {
10507e995a2eSmrg         errno = ENOSYS;
10517e995a2eSmrg         return NULL;
10527e995a2eSmrg      }
10537e995a2eSmrg
10547e995a2eSmrg      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
10557e995a2eSmrg       * tokens accepted by createImageFromDmaBufs2, except for not supporting
10567e995a2eSmrg       * the sARGB format. */
10571463c08dSmrg      fourcc = gbm_core.v0.format_canonicalize(fd_data->format);
10587e995a2eSmrg
10597e995a2eSmrg      image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width,
10607e995a2eSmrg                                                  fd_data->height, fourcc,
10617e995a2eSmrg                                                  fd_data->modifier,
10627e995a2eSmrg                                                  fd_data->fds,
10637e995a2eSmrg                                                  fd_data->num_fds,
10647e995a2eSmrg                                                  fd_data->strides,
10657e995a2eSmrg                                                  fd_data->offsets,
10667e995a2eSmrg                                                  0, 0, 0, 0,
10677e995a2eSmrg                                                  &error, NULL);
10687e995a2eSmrg      if (image == NULL) {
10697e995a2eSmrg         errno = ENOSYS;
10707e995a2eSmrg         return NULL;
10717e995a2eSmrg      }
10727e995a2eSmrg
10737e995a2eSmrg      gbm_format = fourcc;
10747e995a2eSmrg      break;
10757e995a2eSmrg   }
10767e995a2eSmrg
1077af69d88dSmrg   default:
1078af69d88dSmrg      errno = ENOSYS;
10793464ebd5Sriastradh      return NULL;
1080af69d88dSmrg   }
1081af69d88dSmrg
10823464ebd5Sriastradh
10833464ebd5Sriastradh   bo = calloc(1, sizeof *bo);
10847e995a2eSmrg   if (bo == NULL) {
10857e995a2eSmrg      dri->image->destroyImage(image);
10863464ebd5Sriastradh      return NULL;
10877e995a2eSmrg   }
10883464ebd5Sriastradh
1089af69d88dSmrg   bo->image = image;
10903464ebd5Sriastradh
1091af69d88dSmrg   if (usage & GBM_BO_USE_SCANOUT)
1092af69d88dSmrg      dri_use |= __DRI_IMAGE_USE_SCANOUT;
1093af69d88dSmrg   if (usage & GBM_BO_USE_CURSOR)
1094af69d88dSmrg      dri_use |= __DRI_IMAGE_USE_CURSOR;
1095af69d88dSmrg   if (dri->image->base.version >= 2 &&
1096af69d88dSmrg       !dri->image->validateUsage(bo->image, dri_use)) {
1097af69d88dSmrg      errno = EINVAL;
10987e995a2eSmrg      dri->image->destroyImage(bo->image);
1099af69d88dSmrg      free(bo);
11003464ebd5Sriastradh      return NULL;
1101af69d88dSmrg   }
1102af69d88dSmrg
11037e995a2eSmrg   bo->base.gbm = gbm;
11041463c08dSmrg   bo->base.v0.format = gbm_format;
1105af69d88dSmrg
1106af69d88dSmrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
11071463c08dSmrg                          (int*)&bo->base.v0.width);
1108af69d88dSmrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
11091463c08dSmrg                          (int*)&bo->base.v0.height);
1110af69d88dSmrg   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
11111463c08dSmrg                          (int*)&bo->base.v0.stride);
11123464ebd5Sriastradh   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
11131463c08dSmrg                          &bo->base.v0.handle.s32);
11143464ebd5Sriastradh
11157e995a2eSmrg   return &bo->base;
11163464ebd5Sriastradh}
11173464ebd5Sriastradh
1118af69d88dSmrgstatic struct gbm_bo *
1119af69d88dSmrgcreate_dumb(struct gbm_device *gbm,
1120af69d88dSmrg                  uint32_t width, uint32_t height,
1121af69d88dSmrg                  uint32_t format, uint32_t usage)
1122af69d88dSmrg{
1123af69d88dSmrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1124af69d88dSmrg   struct drm_mode_create_dumb create_arg;
1125af69d88dSmrg   struct gbm_dri_bo *bo;
1126af69d88dSmrg   struct drm_mode_destroy_dumb destroy_arg;
1127af69d88dSmrg   int ret;
1128af69d88dSmrg   int is_cursor, is_scanout;
1129af69d88dSmrg
1130af69d88dSmrg   is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
1131af69d88dSmrg      format == GBM_FORMAT_ARGB8888;
1132af69d88dSmrg   is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
11337e995a2eSmrg      (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_XBGR8888);
1134af69d88dSmrg   if (!is_cursor && !is_scanout) {
1135af69d88dSmrg      errno = EINVAL;
1136af69d88dSmrg      return NULL;
1137af69d88dSmrg   }
1138af69d88dSmrg
1139af69d88dSmrg   bo = calloc(1, sizeof *bo);
1140af69d88dSmrg   if (bo == NULL)
1141af69d88dSmrg      return NULL;
1142af69d88dSmrg
11437e995a2eSmrg   memset(&create_arg, 0, sizeof(create_arg));
1144af69d88dSmrg   create_arg.bpp = 32;
1145af69d88dSmrg   create_arg.width = width;
1146af69d88dSmrg   create_arg.height = height;
1147af69d88dSmrg
11481463c08dSmrg   ret = drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
1149af69d88dSmrg   if (ret)
1150af69d88dSmrg      goto free_bo;
1151af69d88dSmrg
11527e995a2eSmrg   bo->base.gbm = gbm;
11531463c08dSmrg   bo->base.v0.width = width;
11541463c08dSmrg   bo->base.v0.height = height;
11551463c08dSmrg   bo->base.v0.stride = create_arg.pitch;
11561463c08dSmrg   bo->base.v0.format = format;
11571463c08dSmrg   bo->base.v0.handle.u32 = create_arg.handle;
1158af69d88dSmrg   bo->handle = create_arg.handle;
1159af69d88dSmrg   bo->size = create_arg.size;
1160af69d88dSmrg
11617e995a2eSmrg   if (gbm_dri_bo_map_dumb(bo) == NULL)
1162af69d88dSmrg      goto destroy_dumb;
1163af69d88dSmrg
11647e995a2eSmrg   return &bo->base;
1165af69d88dSmrg
1166af69d88dSmrgdestroy_dumb:
1167af69d88dSmrg   memset(&destroy_arg, 0, sizeof destroy_arg);
1168af69d88dSmrg   destroy_arg.handle = create_arg.handle;
11691463c08dSmrg   drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
1170af69d88dSmrgfree_bo:
1171af69d88dSmrg   free(bo);
1172af69d88dSmrg
1173af69d88dSmrg   return NULL;
1174af69d88dSmrg}
1175af69d88dSmrg
11763464ebd5Sriastradhstatic struct gbm_bo *
11773464ebd5Sriastradhgbm_dri_bo_create(struct gbm_device *gbm,
11783464ebd5Sriastradh                  uint32_t width, uint32_t height,
11797e995a2eSmrg                  uint32_t format, uint32_t usage,
11807e995a2eSmrg                  const uint64_t *modifiers,
11817e995a2eSmrg                  const unsigned int count)
11823464ebd5Sriastradh{
11833464ebd5Sriastradh   struct gbm_dri_device *dri = gbm_dri_device(gbm);
11843464ebd5Sriastradh   struct gbm_dri_bo *bo;
11853464ebd5Sriastradh   int dri_format;
11863464ebd5Sriastradh   unsigned dri_use = 0;
11873464ebd5Sriastradh
11881463c08dSmrg   format = gbm_core.v0.format_canonicalize(format);
11897e995a2eSmrg
1190af69d88dSmrg   if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
1191af69d88dSmrg      return create_dumb(gbm, width, height, format, usage);
1192af69d88dSmrg
11933464ebd5Sriastradh   bo = calloc(1, sizeof *bo);
11943464ebd5Sriastradh   if (bo == NULL)
11953464ebd5Sriastradh      return NULL;
11963464ebd5Sriastradh
11977e995a2eSmrg   bo->base.gbm = gbm;
11981463c08dSmrg   bo->base.v0.width = width;
11991463c08dSmrg   bo->base.v0.height = height;
12001463c08dSmrg   bo->base.v0.format = format;
12013464ebd5Sriastradh
12027e995a2eSmrg   dri_format = gbm_format_to_dri_format(format);
12037e995a2eSmrg   if (dri_format == 0) {
1204af69d88dSmrg      errno = EINVAL;
1205af69d88dSmrg      goto failed;
12063464ebd5Sriastradh   }
12073464ebd5Sriastradh
12083464ebd5Sriastradh   if (usage & GBM_BO_USE_SCANOUT)
12093464ebd5Sriastradh      dri_use |= __DRI_IMAGE_USE_SCANOUT;
1210af69d88dSmrg   if (usage & GBM_BO_USE_CURSOR)
12113464ebd5Sriastradh      dri_use |= __DRI_IMAGE_USE_CURSOR;
12127e995a2eSmrg   if (usage & GBM_BO_USE_LINEAR)
12137e995a2eSmrg      dri_use |= __DRI_IMAGE_USE_LINEAR;
12141463c08dSmrg   if (usage & GBM_BO_USE_PROTECTED)
12151463c08dSmrg      dri_use |= __DRI_IMAGE_USE_PROTECTED;
12163464ebd5Sriastradh
1217af69d88dSmrg   /* Gallium drivers requires shared in order to get the handle/stride */
1218af69d88dSmrg   dri_use |= __DRI_IMAGE_USE_SHARE;
1219af69d88dSmrg
12201463c08dSmrg   if (modifiers && (dri->image->base.version < 14 ||
12211463c08dSmrg       !dri->image->createImageWithModifiers)) {
12221463c08dSmrg      errno = ENOSYS;
12231463c08dSmrg      goto failed;
12247e995a2eSmrg   }
12257e995a2eSmrg
12261463c08dSmrg   bo->image = loader_dri_create_image(dri->screen, dri->image, width, height,
12271463c08dSmrg                                       dri_format, dri_use, modifiers, count,
12281463c08dSmrg                                       bo);
12293464ebd5Sriastradh   if (bo->image == NULL)
1230af69d88dSmrg      goto failed;
12313464ebd5Sriastradh
12321463c08dSmrg   if (modifiers)
12331463c08dSmrg      assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID);
12341463c08dSmrg
12353464ebd5Sriastradh   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
12361463c08dSmrg                          &bo->base.v0.handle.s32);
12373464ebd5Sriastradh   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
12381463c08dSmrg                          (int *) &bo->base.v0.stride);
12393464ebd5Sriastradh
12407e995a2eSmrg   return &bo->base;
1241af69d88dSmrg
1242af69d88dSmrgfailed:
1243af69d88dSmrg   free(bo);
1244af69d88dSmrg   return NULL;
1245af69d88dSmrg}
1246af69d88dSmrg
12477e995a2eSmrgstatic void *
12487e995a2eSmrggbm_dri_bo_map(struct gbm_bo *_bo,
12497e995a2eSmrg              uint32_t x, uint32_t y,
12507e995a2eSmrg              uint32_t width, uint32_t height,
12517e995a2eSmrg              uint32_t flags, uint32_t *stride, void **map_data)
12527e995a2eSmrg{
12537e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
12547e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
12557e995a2eSmrg
12567e995a2eSmrg   /* If it's a dumb buffer, we already have a mapping */
12577e995a2eSmrg   if (bo->map) {
12581463c08dSmrg      *map_data = (char *)bo->map + (bo->base.v0.stride * y) + (x * 4);
12591463c08dSmrg      *stride = bo->base.v0.stride;
12607e995a2eSmrg      return *map_data;
12617e995a2eSmrg   }
12627e995a2eSmrg
12637e995a2eSmrg   if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) {
12647e995a2eSmrg      errno = ENOSYS;
12657e995a2eSmrg      return NULL;
12667e995a2eSmrg   }
12677e995a2eSmrg
12687e995a2eSmrg   mtx_lock(&dri->mutex);
12697e995a2eSmrg   if (!dri->context)
12707e995a2eSmrg      dri->context = dri->dri2->createNewContext(dri->screen, NULL,
12717e995a2eSmrg                                                 NULL, NULL);
12727e995a2eSmrg   assert(dri->context);
12737e995a2eSmrg   mtx_unlock(&dri->mutex);
12747e995a2eSmrg
12757e995a2eSmrg   /* GBM flags and DRI flags are the same, so just pass them on */
12767e995a2eSmrg   return dri->image->mapImage(dri->context, bo->image, x, y,
12777e995a2eSmrg                               width, height, flags, (int *)stride,
12787e995a2eSmrg                               map_data);
12797e995a2eSmrg}
12807e995a2eSmrg
12817e995a2eSmrgstatic void
12827e995a2eSmrggbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
12837e995a2eSmrg{
12847e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
12857e995a2eSmrg   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
12867e995a2eSmrg
12877e995a2eSmrg   /* Check if it's a dumb buffer and check the pointer is in range */
12887e995a2eSmrg   if (bo->map) {
12897e995a2eSmrg      assert(map_data >= bo->map);
12907e995a2eSmrg      assert(map_data < (bo->map + bo->size));
12917e995a2eSmrg      return;
12927e995a2eSmrg   }
12937e995a2eSmrg
12947e995a2eSmrg   if (!dri->context || !dri->image ||
12957e995a2eSmrg       dri->image->base.version < 12 || !dri->image->unmapImage)
12967e995a2eSmrg      return;
12977e995a2eSmrg
12987e995a2eSmrg   dri->image->unmapImage(dri->context, bo->image, map_data);
12997e995a2eSmrg
13007e995a2eSmrg   /*
13017e995a2eSmrg    * Not all DRI drivers use direct maps. They may queue up DMA operations
13027e995a2eSmrg    * on the mapping context. Since there is no explicit gbm flush
13037e995a2eSmrg    * mechanism, we need to flush here.
13047e995a2eSmrg    */
13057e995a2eSmrg   if (dri->flush->base.version >= 4)
13067e995a2eSmrg      dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
13077e995a2eSmrg}
13087e995a2eSmrg
13097e995a2eSmrg
1310af69d88dSmrgstatic struct gbm_surface *
1311af69d88dSmrggbm_dri_surface_create(struct gbm_device *gbm,
1312af69d88dSmrg                       uint32_t width, uint32_t height,
13137e995a2eSmrg		       uint32_t format, uint32_t flags,
13147e995a2eSmrg                       const uint64_t *modifiers, const unsigned count)
1315af69d88dSmrg{
13167e995a2eSmrg   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1317af69d88dSmrg   struct gbm_dri_surface *surf;
1318af69d88dSmrg
13197e995a2eSmrg   if (modifiers &&
13207e995a2eSmrg       (!dri->image || dri->image->base.version < 14 ||
13217e995a2eSmrg        !dri->image->createImageWithModifiers)) {
13227e995a2eSmrg      errno = ENOSYS;
13237e995a2eSmrg      return NULL;
13247e995a2eSmrg   }
13257e995a2eSmrg
13267e995a2eSmrg   if (count)
13277e995a2eSmrg      assert(modifiers);
13287e995a2eSmrg
13297e995a2eSmrg   /* It's acceptable to create an image with INVALID modifier in the list,
13307e995a2eSmrg    * but it cannot be on the only modifier (since it will certainly fail
13317e995a2eSmrg    * later). While we could easily catch this after modifier creation, doing
13327e995a2eSmrg    * the check here is a convenient debug check likely pointing at whatever
13337e995a2eSmrg    * interface the client is using to build its modifier list.
13347e995a2eSmrg    */
13357e995a2eSmrg   if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
13367e995a2eSmrg      fprintf(stderr, "Only invalid modifier specified\n");
13377e995a2eSmrg      errno = EINVAL;
13387e995a2eSmrg   }
13397e995a2eSmrg
1340af69d88dSmrg   surf = calloc(1, sizeof *surf);
13417e995a2eSmrg   if (surf == NULL) {
13427e995a2eSmrg      errno = ENOMEM;
1343af69d88dSmrg      return NULL;
13447e995a2eSmrg   }
1345af69d88dSmrg
1346af69d88dSmrg   surf->base.gbm = gbm;
13471463c08dSmrg   surf->base.v0.width = width;
13481463c08dSmrg   surf->base.v0.height = height;
13491463c08dSmrg   surf->base.v0.format = gbm_core.v0.format_canonicalize(format);
13501463c08dSmrg   surf->base.v0.flags = flags;
13517e995a2eSmrg   if (!modifiers) {
13527e995a2eSmrg      assert(!count);
13537e995a2eSmrg      return &surf->base;
13547e995a2eSmrg   }
13557e995a2eSmrg
13561463c08dSmrg   surf->base.v0.modifiers = calloc(count, sizeof(*modifiers));
13571463c08dSmrg   if (count && !surf->base.v0.modifiers) {
13587e995a2eSmrg      errno = ENOMEM;
13597e995a2eSmrg      free(surf);
13607e995a2eSmrg      return NULL;
13617e995a2eSmrg   }
13627e995a2eSmrg
13637e995a2eSmrg   /* TODO: We are deferring validation of modifiers until the image is actually
13647e995a2eSmrg    * created. This deferred creation can fail due to a modifier-format
13657e995a2eSmrg    * mismatch. The result is the client has a surface but no object to back it.
13667e995a2eSmrg    */
13671463c08dSmrg   surf->base.v0.count = count;
13681463c08dSmrg   memcpy(surf->base.v0.modifiers, modifiers, count * sizeof(*modifiers));
1369af69d88dSmrg
1370af69d88dSmrg   return &surf->base;
1371af69d88dSmrg}
1372af69d88dSmrg
1373af69d88dSmrgstatic void
1374af69d88dSmrggbm_dri_surface_destroy(struct gbm_surface *_surf)
1375af69d88dSmrg{
1376af69d88dSmrg   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
1377af69d88dSmrg
13781463c08dSmrg   free(surf->base.v0.modifiers);
1379af69d88dSmrg   free(surf);
13803464ebd5Sriastradh}
13813464ebd5Sriastradh
13823464ebd5Sriastradhstatic void
13833464ebd5Sriastradhdri_destroy(struct gbm_device *gbm)
13843464ebd5Sriastradh{
13853464ebd5Sriastradh   struct gbm_dri_device *dri = gbm_dri_device(gbm);
13867e995a2eSmrg   unsigned i;
13877e995a2eSmrg
13887e995a2eSmrg   if (dri->context)
13897e995a2eSmrg      dri->core->destroyContext(dri->context);
13903464ebd5Sriastradh
13913464ebd5Sriastradh   dri->core->destroyScreen(dri->screen);
13927e995a2eSmrg   for (i = 0; dri->driver_configs[i]; i++)
13937e995a2eSmrg      free((__DRIconfig *) dri->driver_configs[i]);
13943464ebd5Sriastradh   free(dri->driver_configs);
13953464ebd5Sriastradh   dlclose(dri->driver);
13967e995a2eSmrg   free(dri->driver_name);
13973464ebd5Sriastradh
13983464ebd5Sriastradh   free(dri);
13993464ebd5Sriastradh}
14003464ebd5Sriastradh
14013464ebd5Sriastradhstatic struct gbm_device *
14021463c08dSmrgdri_device_create(int fd, uint32_t gbm_backend_version)
14033464ebd5Sriastradh{
14043464ebd5Sriastradh   struct gbm_dri_device *dri;
14057e995a2eSmrg   int ret;
14067e995a2eSmrg   bool force_sw;
14073464ebd5Sriastradh
14081463c08dSmrg   /*
14091463c08dSmrg    * Since the DRI backend is built-in to the loader, the loader ABI version is
14101463c08dSmrg    * guaranteed to match this backend's ABI version
14111463c08dSmrg    */
14121463c08dSmrg   assert(gbm_core.v0.core_version == GBM_BACKEND_ABI_VERSION);
14131463c08dSmrg   assert(gbm_core.v0.core_version == gbm_backend_version);
14141463c08dSmrg
14153464ebd5Sriastradh   dri = calloc(1, sizeof *dri);
1416af69d88dSmrg   if (!dri)
1417af69d88dSmrg      return NULL;
14183464ebd5Sriastradh
14191463c08dSmrg   dri->base.v0.fd = fd;
14201463c08dSmrg   dri->base.v0.backend_version = gbm_backend_version;
14211463c08dSmrg   dri->base.v0.bo_create = gbm_dri_bo_create;
14221463c08dSmrg   dri->base.v0.bo_import = gbm_dri_bo_import;
14231463c08dSmrg   dri->base.v0.bo_map = gbm_dri_bo_map;
14241463c08dSmrg   dri->base.v0.bo_unmap = gbm_dri_bo_unmap;
14251463c08dSmrg   dri->base.v0.is_format_supported = gbm_dri_is_format_supported;
14261463c08dSmrg   dri->base.v0.get_format_modifier_plane_count =
14277e995a2eSmrg      gbm_dri_get_format_modifier_plane_count;
14281463c08dSmrg   dri->base.v0.bo_write = gbm_dri_bo_write;
14291463c08dSmrg   dri->base.v0.bo_get_fd = gbm_dri_bo_get_fd;
14301463c08dSmrg   dri->base.v0.bo_get_planes = gbm_dri_bo_get_planes;
14311463c08dSmrg   dri->base.v0.bo_get_handle = gbm_dri_bo_get_handle_for_plane;
14321463c08dSmrg   dri->base.v0.bo_get_plane_fd = gbm_dri_bo_get_plane_fd;
14331463c08dSmrg   dri->base.v0.bo_get_stride = gbm_dri_bo_get_stride;
14341463c08dSmrg   dri->base.v0.bo_get_offset = gbm_dri_bo_get_offset;
14351463c08dSmrg   dri->base.v0.bo_get_modifier = gbm_dri_bo_get_modifier;
14361463c08dSmrg   dri->base.v0.bo_destroy = gbm_dri_bo_destroy;
14371463c08dSmrg   dri->base.v0.destroy = dri_destroy;
14381463c08dSmrg   dri->base.v0.surface_create = gbm_dri_surface_create;
14391463c08dSmrg   dri->base.v0.surface_destroy = gbm_dri_surface_destroy;
14401463c08dSmrg
14411463c08dSmrg   dri->base.v0.name = "drm";
14427e995a2eSmrg
14437e995a2eSmrg   dri->visual_table = gbm_dri_visuals_table;
14447e995a2eSmrg   dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table);
14457e995a2eSmrg
14467e995a2eSmrg   mtx_init(&dri->mutex, mtx_plain);
14477e995a2eSmrg
14487e995a2eSmrg   force_sw = env_var_as_boolean("GBM_ALWAYS_SOFTWARE", false);
1449af69d88dSmrg   if (!force_sw) {
1450af69d88dSmrg      ret = dri_screen_create(dri);
1451af69d88dSmrg      if (ret)
1452af69d88dSmrg         ret = dri_screen_create_sw(dri);
1453af69d88dSmrg   } else {
1454af69d88dSmrg      ret = dri_screen_create_sw(dri);
14553464ebd5Sriastradh   }
14563464ebd5Sriastradh
1457af69d88dSmrg   if (ret)
1458af69d88dSmrg      goto err_dri;
1459af69d88dSmrg
14607e995a2eSmrg   return &dri->base;
1461af69d88dSmrg
1462af69d88dSmrgerr_dri:
1463af69d88dSmrg   free(dri);
1464af69d88dSmrg
1465af69d88dSmrg   return NULL;
14663464ebd5Sriastradh}
14673464ebd5Sriastradh
14683464ebd5Sriastradhstruct gbm_backend gbm_dri_backend = {
14691463c08dSmrg   .v0.backend_version = GBM_BACKEND_ABI_VERSION,
14701463c08dSmrg   .v0.backend_name = "dri",
14711463c08dSmrg   .v0.create_device = dri_device_create,
14723464ebd5Sriastradh};
1473