gbm_dri.c 37.9 KB
Newer Older
Benjamin Franzke's avatar
Benjamin Franzke committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Benjamin Franzke <benjaminfranzke@googlemail.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
32
#include <stdbool.h>
Benjamin Franzke's avatar
Benjamin Franzke committed
33
#include <string.h>
34
#include <errno.h>
Benjamin Franzke's avatar
Benjamin Franzke committed
35
#include <limits.h>
Rob Herring's avatar
Rob Herring committed
36
#include <assert.h>
Benjamin Franzke's avatar
Benjamin Franzke committed
37
38
39
40

#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
41
#include <xf86drm.h>
42
#include "drm-uapi/drm_fourcc.h"
Benjamin Franzke's avatar
Benjamin Franzke committed
43
44
45
46
47
48
49

#include <GL/gl.h> /* dri_interface needs GL types */
#include <GL/internal/dri_interface.h>

#include "gbm_driint.h"

#include "gbmint.h"
Emil Velikov's avatar
Emil Velikov committed
50
#include "loader.h"
51
#include "util/debug.h"
52
#include "util/macros.h"
Benjamin Franzke's avatar
Benjamin Franzke committed
53

54
55
/* For importing wl_buffer */
#if HAVE_WAYLAND_PLATFORM
56
#include "wayland-drm.h"
57
58
#endif

Benjamin Franzke's avatar
Benjamin Franzke committed
59
60
61
62
63
64
65
66
67
68
69
static __DRIimage *
dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
{
   struct gbm_dri_device *dri = data;

   if (dri->lookup_image == NULL)
      return NULL;

   return dri->lookup_image(screen, image, dri->lookup_user_data);
}

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
static __DRIbuffer *
dri_get_buffers(__DRIdrawable * driDrawable,
		 int *width, int *height,
		 unsigned int *attachments, int count,
		 int *out_count, void *data)
{
   struct gbm_dri_surface *surf = data;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   if (dri->get_buffers == NULL)
      return NULL;

   return dri->get_buffers(driDrawable, width, height, attachments,
                           count, out_count, surf->dri_private);
}

static void
dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
{
   struct gbm_dri_surface *surf = data;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   if (dri->flush_front_buffer != NULL)
      dri->flush_front_buffer(driDrawable, surf->dri_private);
}

static __DRIbuffer *
dri_get_buffers_with_format(__DRIdrawable * driDrawable,
                            int *width, int *height,
                            unsigned int *attachments, int count,
                            int *out_count, void *data)
{
   struct gbm_dri_surface *surf = data;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   if (dri->get_buffers_with_format == NULL)
      return NULL;

   return
      dri->get_buffers_with_format(driDrawable, width, height, attachments,
                                   count, out_count, surf->dri_private);
}

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
static int
image_get_buffers(__DRIdrawable *driDrawable,
                  unsigned int format,
                  uint32_t *stamp,
                  void *loaderPrivate,
                  uint32_t buffer_mask,
                  struct __DRIimageList *buffers)
{
   struct gbm_dri_surface *surf = loaderPrivate;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   if (dri->image_get_buffers == NULL)
      return 0;

   return dri->image_get_buffers(driDrawable, format, stamp,
                                 surf->dri_private, buffer_mask, buffers);
}

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
static void
swrast_get_drawable_info(__DRIdrawable *driDrawable,
                         int           *x,
                         int           *y,
                         int           *width,
                         int           *height,
                         void          *loaderPrivate)
{
   struct gbm_dri_surface *surf = loaderPrivate;

   *x = 0;
   *y = 0;
   *width = surf->base.width;
   *height = surf->base.height;
}

static void
swrast_put_image2(__DRIdrawable *driDrawable,
                  int            op,
                  int            x,
                  int            y,
                  int            width,
                  int            height,
                  int            stride,
                  char          *data,
                  void          *loaderPrivate)
{
   struct gbm_dri_surface *surf = loaderPrivate;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   dri->swrast_put_image2(driDrawable,
                          op, x, y,
                          width, height, stride,
                          data, surf->dri_private);
}

static void
swrast_put_image(__DRIdrawable *driDrawable,
                 int            op,
                 int            x,
                 int            y,
                 int            width,
                 int            height,
                 char          *data,
                 void          *loaderPrivate)
{
coypoop's avatar
coypoop committed
177
   swrast_put_image2(driDrawable, op, x, y, width, height,
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
                            width * 4, data, loaderPrivate);
}

static void
swrast_get_image(__DRIdrawable *driDrawable,
                 int            x,
                 int            y,
                 int            width,
                 int            height,
                 char          *data,
                 void          *loaderPrivate)
{
   struct gbm_dri_surface *surf = loaderPrivate;
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);

   dri->swrast_get_image(driDrawable,
                         x, y,
                         width, height,
                         data, surf->dri_private);
}

199
static const __DRIuseInvalidateExtension use_invalidate = {
200
   .base = { __DRI_USE_INVALIDATE, 1 }
Benjamin Franzke's avatar
Benjamin Franzke committed
201
202
};

203
static const __DRIimageLookupExtension image_lookup_extension = {
204
205
206
   .base = { __DRI_IMAGE_LOOKUP, 1 },

   .lookupEGLImage          = dri_lookup_egl_image
Benjamin Franzke's avatar
Benjamin Franzke committed
207
208
};

209
static const __DRIdri2LoaderExtension dri2_loader_extension = {
210
211
212
213
214
   .base = { __DRI_DRI2_LOADER, 3 },

   .getBuffers              = dri_get_buffers,
   .flushFrontBuffer        = dri_flush_front_buffer,
   .getBuffersWithFormat    = dri_get_buffers_with_format,
215
216
};

217
static const __DRIimageLoaderExtension image_loader_extension = {
218
219
220
221
   .base = { __DRI_IMAGE_LOADER, 1 },

   .getBuffers          = image_get_buffers,
   .flushFrontBuffer    = dri_flush_front_buffer,
222
223
};

224
225
226
227
228
229
230
231
232
static const __DRIswrastLoaderExtension swrast_loader_extension = {
   .base = { __DRI_SWRAST_LOADER, 2 },

   .getDrawableInfo = swrast_get_drawable_info,
   .putImage        = swrast_put_image,
   .getImage        = swrast_get_image,
   .putImage2       = swrast_put_image2
};

233
234
235
236
237
static const __DRIextension *gbm_dri_screen_extensions[] = {
   &image_lookup_extension.base,
   &use_invalidate.base,
   &dri2_loader_extension.base,
   &image_loader_extension.base,
238
   &swrast_loader_extension.base,
239
240
   NULL,
};
241

Benjamin Franzke's avatar
Benjamin Franzke committed
242
243
244
245
struct dri_extension_match {
   const char *name;
   int version;
   int offset;
Rob Clark's avatar
Rob Clark committed
246
   int optional;
Benjamin Franzke's avatar
Benjamin Franzke committed
247
248
249
};

static struct dri_extension_match dri_core_extensions[] = {
250
   { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
Benjamin Franzke's avatar
Benjamin Franzke committed
251
   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
252
   { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), 1 },
Benjamin Franzke's avatar
Benjamin Franzke committed
253
254
255
256
257
258
259
260
261
   { NULL, 0, 0 }
};

static struct dri_extension_match gbm_dri_device_extensions[] = {
   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
   { NULL, 0, 0 }
};

262
263
264
265
266
267
static struct dri_extension_match gbm_swrast_device_extensions[] = {
   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), },
   { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast) },
   { NULL, 0, 0 }
};

Benjamin Franzke's avatar
Benjamin Franzke committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
static int
dri_bind_extensions(struct gbm_dri_device *dri,
                    struct dri_extension_match *matches,
                    const __DRIextension **extensions)
{
   int i, j, ret = 0;
   void *field;

   for (i = 0; extensions[i]; i++) {
      for (j = 0; matches[j].name; j++) {
         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
             extensions[i]->version >= matches[j].version) {
            field = ((char *) dri + matches[j].offset);
            *(const __DRIextension **) field = extensions[i];
         }
      }
   }

   for (j = 0; matches[j].name; j++) {
      field = ((char *) dri + matches[j].offset);
Rob Clark's avatar
Rob Clark committed
288
      if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) {
Benjamin Franzke's avatar
Benjamin Franzke committed
289
290
291
292
293
294
295
         ret = -1;
      }
   }

   return ret;
}

296
297
static const __DRIextension **
dri_open_driver(struct gbm_dri_device *dri)
Benjamin Franzke's avatar
Benjamin Franzke committed
298
{
299
300
301
302
303
304
305
306
   /* Temporarily work around dri driver libs that need symbols in libglapi
    * but don't automatically link it in.
    */
   /* XXX: Library name differs on per platforms basis. Update this as
    * osx/cygwin/windows/bsd gets support for GBM..
    */
   dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);

307
308
309
310
   static const char *search_path_vars[] = {
      /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
       * is recommended over GBM_DRIVERS_PATH.
       */
311
      "GBM_DRIVERS_PATH",
312
313
314
315
316
317
318
      /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
       * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
       */
      "LIBGL_DRIVERS_PATH",
      NULL
   };
   return loader_open_driver(dri->driver_name, &dri->driver, search_path_vars);
319
320
321
322
323
324
325
326
327
328
329
330
331
332
}

static int
dri_load_driver(struct gbm_dri_device *dri)
{
   const __DRIextension **extensions;

   extensions = dri_open_driver(dri);
   if (!extensions)
      return -1;

   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
      dlclose(dri->driver);
      fprintf(stderr, "failed to bind extensions\n");
Benjamin Franzke's avatar
Benjamin Franzke committed
333
334
      return -1;
   }
335

336
   dri->driver_extensions = extensions;
Benjamin Franzke's avatar
Benjamin Franzke committed
337

338
339
340
341
342
343
344
345
346
347
348
349
350
   return 0;
}

static int
dri_load_driver_swrast(struct gbm_dri_device *dri)
{
   const __DRIextension **extensions;

   extensions = dri_open_driver(dri);
   if (!extensions)
      return -1;

   if (dri_bind_extensions(dri, gbm_swrast_device_extensions, extensions) < 0) {
Benjamin Franzke's avatar
Benjamin Franzke committed
351
352
353
354
355
      dlclose(dri->driver);
      fprintf(stderr, "failed to bind extensions\n");
      return -1;
   }

356
357
   dri->driver_extensions = extensions;

Benjamin Franzke's avatar
Benjamin Franzke committed
358
359
360
361
   return 0;
}

static int
362
dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
Benjamin Franzke's avatar
Benjamin Franzke committed
363
364
365
366
{
   const __DRIextension **extensions;
   int ret = 0;

367
368
   dri->driver_name = driver_name;
   if (dri->driver_name == NULL)
Benjamin Franzke's avatar
Benjamin Franzke committed
369
370
371
372
      return -1;

   ret = dri_load_driver(dri);
   if (ret) {
373
      fprintf(stderr, "failed to load driver: %s\n", dri->driver_name);
Benjamin Franzke's avatar
Benjamin Franzke committed
374
      return ret;
375
   }
Benjamin Franzke's avatar
Benjamin Franzke committed
376

377
   dri->loader_extensions = gbm_dri_screen_extensions;
Benjamin Franzke's avatar
Benjamin Franzke committed
378
379
380
381

   if (dri->dri2 == NULL)
      return -1;

382
   if (dri->dri2->base.version >= 4) {
383
      dri->screen = dri->dri2->createNewScreen2(0, dri->base.fd,
384
                                                dri->loader_extensions,
385
386
387
                                                dri->driver_extensions,
                                                &dri->driver_configs, dri);
   } else {
388
      dri->screen = dri->dri2->createNewScreen(0, dri->base.fd,
389
                                               dri->loader_extensions,
390
391
                                               &dri->driver_configs, dri);
   }
392
393
   if (dri->screen == NULL)
      return -1;
Benjamin Franzke's avatar
Benjamin Franzke committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411

   extensions = dri->core->getExtensions(dri->screen);
   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
      ret = -1;
      goto free_screen;
   }

   dri->lookup_image = NULL;
   dri->lookup_user_data = NULL;

   return 0;

free_screen:
   dri->core->destroyScreen(dri->screen);

   return ret;
}

412
413
414
415
416
static int
dri_screen_create_swrast(struct gbm_dri_device *dri)
{
   int ret;

417
418
   dri->driver_name = strdup("swrast");
   if (dri->driver_name == NULL)
419
420
421
422
423
424
425
426
      return -1;

   ret = dri_load_driver_swrast(dri);
   if (ret) {
      fprintf(stderr, "failed to load swrast driver\n");
      return ret;
   }

427
   dri->loader_extensions = gbm_dri_screen_extensions;
428
429
430
431
432

   if (dri->swrast == NULL)
      return -1;

   if (dri->swrast->base.version >= 4) {
433
      dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions,
434
435
436
                                                  dri->driver_extensions,
                                                  &dri->driver_configs, dri);
   } else {
437
      dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions,
438
439
440
441
442
443
444
445
446
447
448
                                                 &dri->driver_configs, dri);
   }
   if (dri->screen == NULL)
      return -1;

   dri->lookup_image = NULL;
   dri->lookup_user_data = NULL;

   return 0;
}

449
450
451
static int
dri_screen_create(struct gbm_dri_device *dri)
{
452
   char *driver_name;
453

454
   driver_name = loader_get_driver_for_fd(dri->base.fd);
455
456
457
458
459
460
461
462
463
   if (!driver_name)
      return -1;

   return dri_screen_create_dri2(dri, driver_name);
}

static int
dri_screen_create_sw(struct gbm_dri_device *dri)
{
464
   char *driver_name;
465
466
467
468
469
470
471
472
473
474
475
476
477
   int ret;

   driver_name = strdup("kms_swrast");
   if (!driver_name)
      return -errno;

   ret = dri_screen_create_dri2(dri, driver_name);
   if (ret == 0)
      return ret;

   return dri_screen_create_swrast(dri);
}

478
static const struct gbm_dri_visual gbm_dri_visuals_table[] = {
479
480
481
482
483
484
485
486
   {
     GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8,
     { 0x000000ff, 0x00000000, 0x00000000, 0x00000000 },
   },
   {
     GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88,
     { 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 },
   },
487
488
489
490
   {
     GBM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555,
     { 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 },
   },
491
492
493
494
495
496
497
498
499
500
   {
     GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565,
     { 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 },
   },
   {
     GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888,
     { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
   },
   {
     GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888,
501
     { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
502
503
504
505
506
507
508
   },
   {
     GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888,
     { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
   },
   {
     GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888,
509
     { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
510
511
512
513
514
515
516
517
518
   },
   {
     GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010,
     { 0x3ff00000, 0x000ffc00, 0x000003ff, 0x00000000 },
   },
   {
     GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010,
     { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 },
   },
519
520
521
522
523
524
525
526
   {
     GBM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010,
     { 0x000003ff, 0x000ffc00, 0x3ff00000, 0x00000000 },
   },
   {
     GBM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010,
     { 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 },
   },
527
528
529
530
531
532
533
534
};

static int
gbm_format_to_dri_format(uint32_t gbm_format)
{
   int i;

   gbm_format = gbm_format_canonicalize(gbm_format);
535
536
537
   for (i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
      if (gbm_dri_visuals_table[i].gbm_format == gbm_format)
         return gbm_dri_visuals_table[i].dri_image_format;
538
539
540
541
542
543
544
545
546
547
   }

   return 0;
}

static uint32_t
gbm_dri_to_gbm_format(int dri_format)
{
   int i;

548
549
550
   for (i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) {
      if (gbm_dri_visuals_table[i].dri_image_format == dri_format)
         return gbm_dri_visuals_table[i].gbm_format;
551
552
553
554
555
   }

   return 0;
}

Benjamin Franzke's avatar
Benjamin Franzke committed
556
557
static int
gbm_dri_is_format_supported(struct gbm_device *gbm,
558
                            uint32_t format,
Benjamin Franzke's avatar
Benjamin Franzke committed
559
560
                            uint32_t usage)
{
561
562
563
564
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
   int count;

   if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING))
Benjamin Franzke's avatar
Benjamin Franzke committed
565
      return 0;
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581

   format = gbm_format_canonicalize(format);
   if (gbm_format_to_dri_format(format) == 0)
      return 0;

   /* If there is no query, fall back to the small table which was originally
    * here. */
   if (dri->image->base.version <= 15 || !dri->image->queryDmaBufModifiers) {
      switch (format) {
      case GBM_FORMAT_XRGB8888:
      case GBM_FORMAT_ARGB8888:
      case GBM_FORMAT_XBGR8888:
         return 1;
      default:
         return 0;
      }
Benjamin Franzke's avatar
Benjamin Franzke committed
582
583
   }

584
585
586
587
588
   /* Check if the driver returns any modifiers for this format; since linear
    * is counted as a modifier, we will have at least one modifier for any
    * supported format. */
   if (!dri->image->queryDmaBufModifiers(dri->screen, format, 0, NULL, NULL,
                                         &count))
Benjamin Franzke's avatar
Benjamin Franzke committed
589
590
      return 0;

591
   return (count > 0);
Benjamin Franzke's avatar
Benjamin Franzke committed
592
593
}

594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
static int
gbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm,
                                        uint32_t format,
                                        uint64_t modifier)
{
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
   uint64_t plane_count;

   if (dri->image->base.version < 16 ||
       !dri->image->queryDmaBufFormatModifierAttribs)
      return -1;

   format = gbm_format_canonicalize(format);
   if (gbm_format_to_dri_format(format) == 0)
      return -1;

   if (!dri->image->queryDmaBufFormatModifierAttribs(
         dri->screen, format, modifier,
         __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT, &plane_count))
      return -1;

   return plane_count;
}

618
619
620
621
622
static int
gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
{
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);

623
624
   if (bo->image != NULL) {
      errno = EINVAL;
625
      return -1;
626
   }
627

628
   memcpy(bo->map, buf, count);
629
630

   return 0;
631
632
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
633
634
635
636
637
638
639
640
641
642
static int
gbm_dri_bo_get_fd(struct gbm_bo *_bo)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
   int fd;

   if (bo->image == NULL)
      return -1;

643
644
   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd))
      return -1;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
645
646
647
648

   return fd;
}

649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
static int
get_number_planes(struct gbm_dri_device *dri, __DRIimage *image)
{
   int num_planes = 0;

   /* Dumb buffers are single-plane only. */
   if (!image)
      return 1;

   dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);

   if (num_planes <= 0)
      num_planes = 1;

   return num_planes;
}

static int
gbm_dri_bo_get_planes(struct gbm_bo *_bo)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);

   return get_number_planes(dri, bo->image);
}

675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
static union gbm_bo_handle
gbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
   union gbm_bo_handle ret;
   ret.s32 = -1;

   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) {
      errno = ENOSYS;
      return ret;
   }

   if (plane >= get_number_planes(dri, bo->image)) {
      errno = EINVAL;
      return ret;
   }

   /* dumb BOs can only utilize non-planar formats */
   if (!bo->image) {
      assert(plane == 0);
      ret.s32 = bo->handle;
      return ret;
   }

   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
   if (image) {
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
      dri->image->destroyImage(image);
   } else {
      assert(plane == 0);
      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32);
   }

   return ret;
}

712
713
714
static uint32_t
gbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane)
{
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
   __DRIimage *image;
   int stride = 0;

   if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) {
      /* Preserve legacy behavior if plane is 0 */
      if (plane == 0)
         return _bo->stride;

      errno = ENOSYS;
      return 0;
   }

   if (plane >= get_number_planes(dri, bo->image)) {
      errno = EINVAL;
      return 0;
   }

   if (bo->image == NULL) {
      assert(plane == 0);
      return _bo->stride;
   }

   image = dri->image->fromPlanar(bo->image, plane, NULL);
   if (image) {
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
      dri->image->destroyImage(image);
   } else {
      assert(plane == 0);
      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
   }

   return (uint32_t)stride;
749
750
}

751
static uint32_t
752
753
754
755
756
757
gbm_dri_bo_get_offset(struct gbm_bo *_bo, int plane)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
   int offset = 0;

758
759
760
761
762
763
764
   /* These error cases do not actually return an error code, as the user
    * will also fail to obtain the handle/FD from the BO. In that case, the
    * offset is irrelevant, as they have no buffer to offset into, so
    * returning 0 is harmless.
    */
   if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar)
      return 0;
765

766
767
   if (plane >= get_number_planes(dri, bo->image))
      return 0;
768
769
770
771
772
773
774
775
776
777
778
779

    /* Dumb images have no offset */
   if (bo->image == NULL) {
      assert(plane == 0);
      return 0;
   }

   __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL);
   if (image) {
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
      dri->image->destroyImage(image);
   } else {
780
      assert(plane == 0);
781
782
783
784
785
786
      dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_OFFSET, &offset);
   }

   return (uint32_t)offset;
}

Ben Widawsky's avatar
Ben Widawsky committed
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
static uint64_t
gbm_dri_bo_get_modifier(struct gbm_bo *_bo)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);

   if (!dri->image || dri->image->base.version < 14) {
      errno = ENOSYS;
      return DRM_FORMAT_MOD_INVALID;
   }

   /* Dumb buffers have no modifiers */
   if (!bo->image)
      return DRM_FORMAT_MOD_LINEAR;

   uint64_t ret = 0;
   int mod;
   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
                               &mod))
      return DRM_FORMAT_MOD_INVALID;

   ret = (uint64_t)mod << 32;

   if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
                               &mod))
      return DRM_FORMAT_MOD_INVALID;

814
   ret |= (uint64_t)(mod & 0xffffffff);
Ben Widawsky's avatar
Ben Widawsky committed
815
816
817
818

   return ret;
}

Benjamin Franzke's avatar
Benjamin Franzke committed
819
820
821
822
823
static void
gbm_dri_bo_destroy(struct gbm_bo *_bo)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
824
   struct drm_mode_destroy_dumb arg;
Benjamin Franzke's avatar
Benjamin Franzke committed
825

826
   if (bo->image != NULL) {
827
      dri->image->destroyImage(bo->image);
828
   } else {
829
      gbm_dri_bo_unmap_dumb(bo);
830
831
      memset(&arg, 0, sizeof(arg));
      arg.handle = bo->handle;
832
      drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
833
834
   }

Benjamin Franzke's avatar
Benjamin Franzke committed
835
836
837
838
   free(bo);
}

static struct gbm_bo *
839
840
gbm_dri_bo_import(struct gbm_device *gbm,
                  uint32_t type, void *buffer, uint32_t usage)
Benjamin Franzke's avatar
Benjamin Franzke committed
841
842
843
{
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
   struct gbm_dri_bo *bo;
844
   __DRIimage *image;
845
   unsigned dri_use = 0;
846
   int gbm_format;
847

848
   /* Required for query image WIDTH & HEIGHT */
849
   if (dri->image == NULL || dri->image->base.version < 4) {
850
      errno = ENOSYS;
851
      return NULL;
852
   }
853

854
855
856
857
   switch (type) {
#if HAVE_WAYLAND_PLATFORM
   case GBM_BO_IMPORT_WL_BUFFER:
   {
858
      struct wl_drm_buffer *wb;
859

860
861
      if (!dri->wl_drm) {
         errno = EINVAL;
862
         return NULL;
863
      }
864
865

      wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
866
867
      if (!wb) {
         errno = EINVAL;
868
         return NULL;
869
      }
870

Kristian Høgsberg's avatar
Kristian Høgsberg committed
871
      image = dri->image->dupImage(wb->driver_buffer, NULL);
872

873
874
875
      /* GBM_FORMAT_* is identical to WL_DRM_FORMAT_*, so no conversion
       * required. */
      gbm_format = wb->format;
876
877
878
      break;
   }
#endif
Benjamin Franzke's avatar
Benjamin Franzke committed
879

880
881
   case GBM_BO_IMPORT_EGL_IMAGE:
   {
882
      int dri_format;
883
884
      if (dri->lookup_image == NULL) {
         errno = EINVAL;
885
         return NULL;
886
      }
887
888

      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
889
      image = dri->image->dupImage(image, NULL);
890
891
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
      gbm_format = gbm_dri_to_gbm_format(dri_format);
892
893
      if (gbm_format == 0) {
         errno = EINVAL;
894
         dri->image->destroyImage(image);
895
         return NULL;
896
      }
897
898
      break;
   }
Benjamin Franzke's avatar
Benjamin Franzke committed
899

Kristian Høgsberg's avatar
Kristian Høgsberg committed
900
901
902
903
   case GBM_BO_IMPORT_FD:
   {
      struct gbm_import_fd_data *fd_data = buffer;
      int stride = fd_data->stride, offset = 0;
904
      int fourcc;
905

906
907
      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
       * tokens accepted by createImageFromFds, except for not supporting
908
909
       * the sARGB format. */
      fourcc = gbm_format_canonicalize(fd_data->format);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
910
911
912
913

      image = dri->image->createImageFromFds(dri->screen,
                                             fd_data->width,
                                             fd_data->height,
914
                                             fourcc,
Kristian Høgsberg's avatar
Kristian Høgsberg committed
915
916
917
                                             &fd_data->fd, 1,
                                             &stride, &offset,
                                             NULL);
918
919
920
921
      if (image == NULL) {
         errno = EINVAL;
         return NULL;
      }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
922
923
924
925
      gbm_format = fd_data->format;
      break;
   }

926
927
928
929
930
931
932
933
934
935
936
937
938
   case GBM_BO_IMPORT_FD_MODIFIER:
   {
      struct gbm_import_fd_modifier_data *fd_data = buffer;
      unsigned int error;
      int fourcc;

      /* Import with modifier requires createImageFromDmaBufs2 */
      if (dri->image == NULL || dri->image->base.version < 15 ||
          dri->image->createImageFromDmaBufs2 == NULL) {
         errno = ENOSYS;
         return NULL;
      }

939
940
      /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC
       * tokens accepted by createImageFromDmaBufs2, except for not supporting
941
942
       * the sARGB format. */
      fourcc = gbm_format_canonicalize(fd_data->format);
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957

      image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width,
                                                  fd_data->height, fourcc,
                                                  fd_data->modifier,
                                                  fd_data->fds,
                                                  fd_data->num_fds,
                                                  fd_data->strides,
                                                  fd_data->offsets,
                                                  0, 0, 0, 0,
                                                  &error, NULL);
      if (image == NULL) {
         errno = ENOSYS;
         return NULL;
      }

958
      gbm_format = fourcc;
959
960
961
      break;
   }

962
   default:
963
      errno = ENOSYS;
Benjamin Franzke's avatar
Benjamin Franzke committed
964
      return NULL;
965
966
   }

Benjamin Franzke's avatar
Benjamin Franzke committed
967
968

   bo = calloc(1, sizeof *bo);
969
970
   if (bo == NULL) {
      dri->image->destroyImage(image);
Benjamin Franzke's avatar
Benjamin Franzke committed
971
      return NULL;
972
   }
Benjamin Franzke's avatar
Benjamin Franzke committed
973

Kristian Høgsberg's avatar
Kristian Høgsberg committed
974
   bo->image = image;
Benjamin Franzke's avatar
Benjamin Franzke committed
975

976
977
   if (usage & GBM_BO_USE_SCANOUT)
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
978
   if (usage & GBM_BO_USE_CURSOR)
979
980
981
      dri_use |= __DRI_IMAGE_USE_CURSOR;
   if (dri->image->base.version >= 2 &&
       !dri->image->validateUsage(bo->image, dri_use)) {
982
      errno = EINVAL;
983
      dri->image->destroyImage(bo->image);
984
985
986
987
      free(bo);
      return NULL;
   }

988
989
   bo->base.gbm = gbm;
   bo->base.format = gbm_format;
990
991

   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
992
                          (int*)&bo->base.width);
993
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
994
                          (int*)&bo->base.height);
995
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
996
                          (int*)&bo->base.stride);
Benjamin Franzke's avatar
Benjamin Franzke committed
997
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
998
                          &bo->base.handle.s32);
Benjamin Franzke's avatar
Benjamin Franzke committed
999

1000
   return &bo->base;
Benjamin Franzke's avatar
Benjamin Franzke committed
1001
1002
1003
}

static struct gbm_bo *
1004
create_dumb(struct gbm_device *gbm,
Benjamin Franzke's avatar
Benjamin Franzke committed
1005
                  uint32_t width, uint32_t height,
1006
                  uint32_t format, uint32_t usage)
Benjamin Franzke's avatar
Benjamin Franzke committed
1007
1008
{
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1009
   struct drm_mode_create_dumb create_arg;
Benjamin Franzke's avatar
Benjamin Franzke committed
1010
   struct gbm_dri_bo *bo;
1011
1012
   struct drm_mode_destroy_dumb destroy_arg;
   int ret;
1013
   int is_cursor, is_scanout;
1014

1015
1016
1017
   is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
      format == GBM_FORMAT_ARGB8888;
   is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
1018
      (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_XBGR8888);
1019
   if (!is_cursor && !is_scanout) {
1020
      errno = EINVAL;
1021
      return NULL;
1022
   }
Benjamin Franzke's avatar
Benjamin Franzke committed
1023
1024
1025
1026
1027

   bo = calloc(1, sizeof *bo);
   if (bo == NULL)
      return NULL;

1028
   memset(&create_arg, 0, sizeof(create_arg));
1029
1030
1031
1032
   create_arg.bpp = 32;
   create_arg.width = width;
   create_arg.height = height;

1033
   ret = drmIoctl(dri->base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
1034
1035
1036
   if (ret)
      goto free_bo;

1037
1038
1039
1040
1041
1042
   bo->base.gbm = gbm;
   bo->base.width = width;
   bo->base.height = height;
   bo->base.stride = create_arg.pitch;
   bo->base.format = format;
   bo->base.handle.u32 = create_arg.handle;
1043
1044
   bo->handle = create_arg.handle;
   bo->size = create_arg.size;
Benjamin Franzke's avatar
Benjamin Franzke committed
1045

1046
   if (gbm_dri_bo_map_dumb(bo) == NULL)
1047
      goto destroy_dumb;
1048

1049
   return &bo->base;
1050
1051
1052
1053

destroy_dumb:
   memset(&destroy_arg, 0, sizeof destroy_arg);
   destroy_arg.handle = create_arg.handle;
1054
   drmIoctl(dri->base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
1055
1056
free_bo:
   free(bo);
1057

1058
1059
   return NULL;
}
1060

1061
1062
1063
static struct gbm_bo *
gbm_dri_bo_create(struct gbm_device *gbm,
                  uint32_t width, uint32_t height,
1064
1065
1066
                  uint32_t format, uint32_t usage,
                  const uint64_t *modifiers,
                  const unsigned int count)
1067
1068
1069
1070
1071
1072
{
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
   struct gbm_dri_bo *bo;
   int dri_format;
   unsigned dri_use = 0;

1073
1074
1075
1076
1077
   /* Callers of this may specify a modifier, or a dri usage, but not both. The
    * newer modifier interface deprecates the older usage flags.
    */
   assert(!(usage && count));

1078
1079
   format = gbm_format_canonicalize(format);

1080
   if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
1081
1082
1083
1084
1085
1086
      return create_dumb(gbm, width, height, format, usage);

   bo = calloc(1, sizeof *bo);
   if (bo == NULL)
      return NULL;

1087
1088
1089
1090
   bo->base.gbm = gbm;
   bo->base.width = width;
   bo->base.height = height;
   bo->base.format = format;
1091

1092
1093
   dri_format = gbm_format_to_dri_format(format);
   if (dri_format == 0) {
1094
      errno = EINVAL;
1095
      goto failed;
Benjamin Franzke's avatar
Benjamin Franzke committed
1096
1097
1098
1099
   }

   if (usage & GBM_BO_USE_SCANOUT)
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
1100
   if (usage & GBM_BO_USE_CURSOR)
Benjamin Franzke's avatar
Benjamin Franzke committed
1101
      dri_use |= __DRI_IMAGE_USE_CURSOR;
fcui's avatar
fcui committed
1102
1103
   if (usage & GBM_BO_USE_LINEAR)
      dri_use |= __DRI_IMAGE_USE_LINEAR;
Benjamin Franzke's avatar
Benjamin Franzke committed
1104

1105
1106
1107
   /* Gallium drivers requires shared in order to get the handle/stride */
   dri_use |= __DRI_IMAGE_USE_SHARE;

1108
1109
1110
1111
1112
1113
1114
1115
   if (modifiers) {
      if (!dri->image || dri->image->base.version < 14 ||
          !dri->image->createImageWithModifiers) {
         fprintf(stderr, "Modifiers specified, but DRI is too old\n");
         errno = ENOSYS;
         goto failed;
      }

1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
      /* It's acceptable to create an image with INVALID modifier in the list,
       * but it cannot be on the only modifier (since it will certainly fail
       * later). While we could easily catch this after modifier creation, doing
       * the check here is a convenient debug check likely pointing at whatever
       * interface the client is using to build its modifier list.
       */
      if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
         fprintf(stderr, "Only invalid modifier specified\n");
         errno = EINVAL;
         goto failed;
      }

1128
1129
1130
1131
1132
1133
      bo->image =
         dri->image->createImageWithModifiers(dri->screen,
                                              width, height,
                                              dri_format,
                                              modifiers, count,
                                              bo);
1134
1135
1136

      if (bo->image) {
         /* The client passed in a list of invalid modifiers */
1137
         assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID);
1138
      }
1139
1140
1141
1142
1143
   } else {
      bo->image = dri->image->createImage(dri->screen, width, height,
                                          dri_format, dri_use, bo);
   }

Benjamin Franzke's avatar
Benjamin Franzke committed
1144
   if (bo->image == NULL)
1145
      goto failed;
Benjamin Franzke's avatar
Benjamin Franzke committed
1146
1147

   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
1148
                          &bo->base.handle.s32);
Benjamin Franzke's avatar
Benjamin Franzke committed
1149
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
1150
                          (int *) &bo->base.stride);
Benjamin Franzke's avatar
Benjamin Franzke committed
1151

1152
   return &bo->base;
1153
1154
1155
1156

failed:
   free(bo);
   return NULL;
Benjamin Franzke's avatar
Benjamin Franzke committed
1157
1158
}

Rob Herring's avatar
Rob Herring committed
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
static void *
gbm_dri_bo_map(struct gbm_bo *_bo,
              uint32_t x, uint32_t y,
              uint32_t width, uint32_t height,
              uint32_t flags, uint32_t *stride, void **map_data)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);

   /* If it's a dumb buffer, we already have a mapping */
   if (bo->map) {
1170
1171
      *map_data = (char *)bo->map + (bo->base.stride * y) + (x * 4);
      *stride = bo->base.stride;
Rob Herring's avatar
Rob Herring committed
1172
1173
1174
      return *map_data;
   }

1175
   if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) {
Rob Herring's avatar
Rob Herring committed
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
      errno = ENOSYS;
      return NULL;
   }

   mtx_lock(&dri->mutex);
   if (!dri->context)
      dri->context = dri->dri2->createNewContext(dri->screen, NULL,
                                                 NULL, NULL);
   assert(dri->context);
   mtx_unlock(&dri->mutex);

   /* GBM flags and DRI flags are the same, so just pass them on */
   return dri->image->mapImage(dri->context, bo->image, x, y,
                               width, height, flags, (int *)stride,
                               map_data);
}

static void
gbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
{
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);

   /* Check if it's a dumb buffer and check the pointer is in range */
   if (bo->map) {
      assert(map_data >= bo->map);
      assert(map_data < (bo->map + bo->size));
      return;
   }

1206
1207
   if (!dri->context || !dri->image ||
       dri->image->base.version < 12 || !dri->image->unmapImage)
Rob Herring's avatar
Rob Herring committed
1208
1209
1210
      return;

   dri->image->unmapImage(dri->context, bo->image, map_data);
Thomas Hellstrom's avatar
Thomas Hellstrom committed
1211
1212
1213
1214
1215
1216

   /*
    * Not all DRI drivers use direct maps. They may queue up DMA operations
    * on the mapping context. Since there is no explicit gbm flush
    * mechanism, we need to flush here.
    */
1217
1218
   if (dri->flush->base.version >= 4)
      dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
Rob Herring's avatar
Rob Herring committed
1219
1220
1221
}


1222
1223
1224
static struct gbm_surface *
gbm_dri_surface_create(struct gbm_device *gbm,
                       uint32_t width, uint32_t height,
1225
1226
		       uint32_t format, uint32_t flags,
                       const uint64_t *modifiers, const unsigned count)
1227
{
1228
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1229
1230
   struct gbm_dri_surface *surf;

1231
1232
1233
1234
1235
1236
1237
   if (modifiers &&
       (!dri->image || dri->image->base.version < 14 ||
        !dri->image->createImageWithModifiers)) {
      errno = ENOSYS;
      return NULL;
   }

1238
1239
1240
   if (count)
      assert(modifiers);

1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
   /* It's acceptable to create an image with INVALID modifier in the list,
    * but it cannot be on the only modifier (since it will certainly fail
    * later). While we could easily catch this after modifier creation, doing
    * the check here is a convenient debug check likely pointing at whatever
    * interface the client is using to build its modifier list.
    */
   if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
      fprintf(stderr, "Only invalid modifier specified\n");
      errno = EINVAL;
   }

1252
   surf = calloc(1, sizeof *surf);
1253
1254
   if (surf == NULL) {
      errno = ENOMEM;
1255
      return NULL;
1256
   }
1257
1258
1259
1260

   surf->base.gbm = gbm;
   surf->base.width = width;
   surf->base.height = height;
1261
   surf->base.format = gbm_format_canonicalize(format);
1262
   surf->base.flags = flags;
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
   if (!modifiers) {
      assert(!count);
      return &surf->base;
   }

   surf->base.modifiers = calloc(count, sizeof(*modifiers));
   if (count && !surf->base.modifiers) {
      errno = ENOMEM;
      free(surf);
      return NULL;
   }

1275
1276
1277
1278
   /* TODO: We are deferring validation of modifiers until the image is actually
    * created. This deferred creation can fail due to a modifier-format
    * mismatch. The result is the client has a surface but no object to back it.
    */
1279
1280
   surf->base.count = count;
   memcpy(surf->base.modifiers, modifiers, count * sizeof(*modifiers));
1281
1282
1283
1284
1285
1286
1287
1288
1289

   return &surf->base;
}

static void
gbm_dri_surface_destroy(struct gbm_surface *_surf)
{
   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);

1290
   free(surf->base.modifiers);
1291
1292
1293
   free(surf);
}

Benjamin Franzke's avatar
Benjamin Franzke committed
1294
1295
1296
1297
static void
dri_destroy(struct gbm_device *gbm)
{
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
1298
   unsigned i;
Benjamin Franzke's avatar
Benjamin Franzke committed
1299

Rob Herring's avatar
Rob Herring committed
1300
1301
1302
   if (dri->context)
      dri->core->destroyContext(dri->context);

Benjamin Franzke's avatar
Benjamin Franzke committed
1303
   dri->core->destroyScreen(dri->screen);
1304
1305
   for (i = 0; dri->driver_configs[i]; i++)
      free((__DRIconfig *) dri->driver_configs[i]);
Benjamin Franzke's avatar
Benjamin Franzke committed
1306
1307
   free(dri->driver_configs);
   dlclose(dri->driver);
1308
   free(dri->driver_name);
Benjamin Franzke's avatar
Benjamin Franzke committed
1309
1310
1311
1312
1313
1314
1315
1316

   free(dri);
}

static struct gbm_device *
dri_device_create(int fd)
{
   struct gbm_dri_device *dri;
1317