Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Copyright © 2011 Intel Corporation
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 * copy of this software and associated documentation files (the "Software"),
6
 * to deal in the Software without restriction, including without limitation
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 * and/or sell copies of the Software, and to permit persons to whom the
9
 * Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice (including the next
12
 * paragraph) shall be included in all copies or substantial portions of the
13
 * Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Benjamin Franzke 
26
 */
27
 
28
#include 
29
#include 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
 
36
#include 
37
#include 
38
#include 
39
#include 
40
 
41
#include  /* dri_interface needs GL types */
42
#include 
43
 
44
#include "gbm_driint.h"
45
 
46
#include "gbmint.h"
47
#include "loader.h"
48
 
49
/* For importing wl_buffer */
50
#if HAVE_WAYLAND_PLATFORM
51
#include "../../../egl/wayland/wayland-drm/wayland-drm.h"
52
#endif
53
 
54
static __DRIimage *
55
dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
56
{
57
   struct gbm_dri_device *dri = data;
58
 
59
   if (dri->lookup_image == NULL)
60
      return NULL;
61
 
62
   return dri->lookup_image(screen, image, dri->lookup_user_data);
63
}
64
 
65
static __DRIbuffer *
66
dri_get_buffers(__DRIdrawable * driDrawable,
67
		 int *width, int *height,
68
		 unsigned int *attachments, int count,
69
		 int *out_count, void *data)
70
{
71
   struct gbm_dri_surface *surf = data;
72
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
73
 
74
   if (dri->get_buffers == NULL)
75
      return NULL;
76
 
77
   return dri->get_buffers(driDrawable, width, height, attachments,
78
                           count, out_count, surf->dri_private);
79
}
80
 
81
static void
82
dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
83
{
84
   struct gbm_dri_surface *surf = data;
85
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
86
 
87
   if (dri->flush_front_buffer != NULL)
88
      dri->flush_front_buffer(driDrawable, surf->dri_private);
89
}
90
 
91
static __DRIbuffer *
92
dri_get_buffers_with_format(__DRIdrawable * driDrawable,
93
                            int *width, int *height,
94
                            unsigned int *attachments, int count,
95
                            int *out_count, void *data)
96
{
97
   struct gbm_dri_surface *surf = data;
98
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
99
 
100
   if (dri->get_buffers_with_format == NULL)
101
      return NULL;
102
 
103
   return
104
      dri->get_buffers_with_format(driDrawable, width, height, attachments,
105
                                   count, out_count, surf->dri_private);
106
}
107
 
108
static int
109
image_get_buffers(__DRIdrawable *driDrawable,
110
                  unsigned int format,
111
                  uint32_t *stamp,
112
                  void *loaderPrivate,
113
                  uint32_t buffer_mask,
114
                  struct __DRIimageList *buffers)
115
{
116
   struct gbm_dri_surface *surf = loaderPrivate;
117
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
118
 
119
   if (dri->image_get_buffers == NULL)
120
      return 0;
121
 
122
   return dri->image_get_buffers(driDrawable, format, stamp,
123
                                 surf->dri_private, buffer_mask, buffers);
124
}
125
 
126
static void
127
swrast_get_drawable_info(__DRIdrawable *driDrawable,
128
                         int           *x,
129
                         int           *y,
130
                         int           *width,
131
                         int           *height,
132
                         void          *loaderPrivate)
133
{
134
   struct gbm_dri_surface *surf = loaderPrivate;
135
 
136
   *x = 0;
137
   *y = 0;
138
   *width = surf->base.width;
139
   *height = surf->base.height;
140
}
141
 
142
static void
143
swrast_put_image2(__DRIdrawable *driDrawable,
144
                  int            op,
145
                  int            x,
146
                  int            y,
147
                  int            width,
148
                  int            height,
149
                  int            stride,
150
                  char          *data,
151
                  void          *loaderPrivate)
152
{
153
   struct gbm_dri_surface *surf = loaderPrivate;
154
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
155
 
156
   dri->swrast_put_image2(driDrawable,
157
                          op, x, y,
158
                          width, height, stride,
159
                          data, surf->dri_private);
160
}
161
 
162
static void
163
swrast_put_image(__DRIdrawable *driDrawable,
164
                 int            op,
165
                 int            x,
166
                 int            y,
167
                 int            width,
168
                 int            height,
169
                 char          *data,
170
                 void          *loaderPrivate)
171
{
172
   return swrast_put_image2(driDrawable, op, x, y, width, height,
173
                            width * 4, data, loaderPrivate);
174
}
175
 
176
static void
177
swrast_get_image(__DRIdrawable *driDrawable,
178
                 int            x,
179
                 int            y,
180
                 int            width,
181
                 int            height,
182
                 char          *data,
183
                 void          *loaderPrivate)
184
{
185
   struct gbm_dri_surface *surf = loaderPrivate;
186
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
187
 
188
   dri->swrast_get_image(driDrawable,
189
                         x, y,
190
                         width, height,
191
                         data, surf->dri_private);
192
}
193
 
194
static const __DRIuseInvalidateExtension use_invalidate = {
195
   .base = { __DRI_USE_INVALIDATE, 1 }
196
};
197
 
198
static const __DRIimageLookupExtension image_lookup_extension = {
199
   .base = { __DRI_IMAGE_LOOKUP, 1 },
200
 
201
   .lookupEGLImage          = dri_lookup_egl_image
202
};
203
 
204
static const __DRIdri2LoaderExtension dri2_loader_extension = {
205
   .base = { __DRI_DRI2_LOADER, 3 },
206
 
207
   .getBuffers              = dri_get_buffers,
208
   .flushFrontBuffer        = dri_flush_front_buffer,
209
   .getBuffersWithFormat    = dri_get_buffers_with_format,
210
};
211
 
212
static const __DRIimageLoaderExtension image_loader_extension = {
213
   .base = { __DRI_IMAGE_LOADER, 1 },
214
 
215
   .getBuffers          = image_get_buffers,
216
   .flushFrontBuffer    = dri_flush_front_buffer,
217
};
218
 
219
static const __DRIswrastLoaderExtension swrast_loader_extension = {
220
   .base = { __DRI_SWRAST_LOADER, 2 },
221
 
222
   .getDrawableInfo = swrast_get_drawable_info,
223
   .putImage        = swrast_put_image,
224
   .getImage        = swrast_get_image,
225
   .putImage2       = swrast_put_image2
226
};
227
 
228
static const __DRIextension *gbm_dri_screen_extensions[] = {
229
   &image_lookup_extension.base,
230
   &use_invalidate.base,
231
   &dri2_loader_extension.base,
232
   &image_loader_extension.base,
233
   &swrast_loader_extension.base,
234
   NULL,
235
};
236
 
237
struct dri_extension_match {
238
   const char *name;
239
   int version;
240
   int offset;
241
};
242
 
243
static struct dri_extension_match dri_core_extensions[] = {
244
   { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
245
   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
246
   { NULL, 0, 0 }
247
};
248
 
249
static struct dri_extension_match gbm_dri_device_extensions[] = {
250
   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
251
   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
252
   { NULL, 0, 0 }
253
};
254
 
255
static struct dri_extension_match gbm_swrast_device_extensions[] = {
256
   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), },
257
   { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast) },
258
   { NULL, 0, 0 }
259
};
260
 
261
static int
262
dri_bind_extensions(struct gbm_dri_device *dri,
263
                    struct dri_extension_match *matches,
264
                    const __DRIextension **extensions)
265
{
266
   int i, j, ret = 0;
267
   void *field;
268
 
269
   for (i = 0; extensions[i]; i++) {
270
      for (j = 0; matches[j].name; j++) {
271
         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
272
             extensions[i]->version >= matches[j].version) {
273
            field = ((char *) dri + matches[j].offset);
274
            *(const __DRIextension **) field = extensions[i];
275
         }
276
      }
277
   }
278
 
279
   for (j = 0; matches[j].name; j++) {
280
      field = ((char *) dri + matches[j].offset);
281
      if (*(const __DRIextension **) field == NULL) {
282
         ret = -1;
283
      }
284
   }
285
 
286
   return ret;
287
}
288
 
289
static const __DRIextension **
290
dri_open_driver(struct gbm_dri_device *dri)
291
{
292
   const __DRIextension **extensions = NULL;
293
   char path[PATH_MAX], *search_paths, *p, *next, *end;
294
   char *get_extensions_name;
295
 
296
   search_paths = NULL;
297
   /* don't allow setuid apps to use LIBGL_DRIVERS_PATH or GBM_DRIVERS_PATH */
298
   if (geteuid() == getuid()) {
299
      /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
300
       * is recommended over GBM_DRIVERS_PATH.
301
       */
302
      search_paths = getenv("GBM_DRIVERS_PATH");
303
 
304
      /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
305
       * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
306
       */
307
      if (search_paths == NULL) {
308
         search_paths = getenv("LIBGL_DRIVERS_PATH");
309
      }
310
   }
311
   if (search_paths == NULL)
312
      search_paths = DEFAULT_DRIVER_DIR;
313
 
314
   dri->driver = NULL;
315
   end = search_paths + strlen(search_paths);
316
   for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
317
      int len;
318
      next = strchr(p, ':');
319
      if (next == NULL)
320
         next = end;
321
 
322
      len = next - p;
323
#if GLX_USE_TLS
324
      snprintf(path, sizeof path,
325
               "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
326
      dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
327
#endif
328
      if (dri->driver == NULL) {
329
         snprintf(path, sizeof path,
330
                  "%.*s/%s_dri.so", len, p, dri->base.driver_name);
331
         dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
332
      }
333
      /* not need continue to loop all paths once the driver is found */
334
      if (dri->driver != NULL)
335
         break;
336
   }
337
 
338
   if (dri->driver == NULL) {
339
      fprintf(stderr, "gbm: failed to open any driver (search paths %s)\n",
340
              search_paths);
341
      fprintf(stderr, "gbm: Last dlopen error: %s\n", dlerror());
342
      return NULL;
343
   }
344
 
345
   if (asprintf(&get_extensions_name, "%s_%s",
346
                __DRI_DRIVER_GET_EXTENSIONS, dri->base.driver_name) != -1) {
347
      const __DRIextension **(*get_extensions)(void);
348
 
349
      get_extensions = dlsym(dri->driver, get_extensions_name);
350
      free(get_extensions_name);
351
 
352
      if (get_extensions)
353
         extensions = get_extensions();
354
   }
355
 
356
   if (!extensions)
357
      extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS);
358
   if (extensions == NULL) {
359
      fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror());
360
      dlclose(dri->driver);
361
   }
362
 
363
   return extensions;
364
}
365
 
366
static int
367
dri_load_driver(struct gbm_dri_device *dri)
368
{
369
   const __DRIextension **extensions;
370
 
371
   extensions = dri_open_driver(dri);
372
   if (!extensions)
373
      return -1;
374
 
375
   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
376
      dlclose(dri->driver);
377
      fprintf(stderr, "failed to bind extensions\n");
378
      return -1;
379
   }
380
 
381
   dri->driver_extensions = extensions;
382
 
383
   return 0;
384
}
385
 
386
static int
387
dri_load_driver_swrast(struct gbm_dri_device *dri)
388
{
389
   const __DRIextension **extensions;
390
 
391
   extensions = dri_open_driver(dri);
392
   if (!extensions)
393
      return -1;
394
 
395
   if (dri_bind_extensions(dri, gbm_swrast_device_extensions, extensions) < 0) {
396
      dlclose(dri->driver);
397
      fprintf(stderr, "failed to bind extensions\n");
398
      return -1;
399
   }
400
 
401
   dri->driver_extensions = extensions;
402
 
403
   return 0;
404
}
405
 
406
static int
407
dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name)
408
{
409
   const __DRIextension **extensions;
410
   int ret = 0;
411
 
412
   dri->base.driver_name = driver_name;
413
   if (dri->base.driver_name == NULL)
414
      return -1;
415
 
416
   ret = dri_load_driver(dri);
417
   if (ret) {
418
      fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
419
      return ret;
420
   };
421
 
422
   dri->extensions = gbm_dri_screen_extensions;
423
 
424
   if (dri->dri2 == NULL)
425
      return -1;
426
 
427
   if (dri->dri2->base.version >= 4) {
428
      dri->screen = dri->dri2->createNewScreen2(0, dri->base.base.fd,
429
                                                dri->extensions,
430
                                                dri->driver_extensions,
431
                                                &dri->driver_configs, dri);
432
   } else {
433
      dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
434
                                               dri->extensions,
435
                                               &dri->driver_configs, dri);
436
   }
437
   if (dri->screen == NULL)
438
      return -1;
439
 
440
   extensions = dri->core->getExtensions(dri->screen);
441
   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
442
      ret = -1;
443
      goto free_screen;
444
   }
445
 
446
   dri->lookup_image = NULL;
447
   dri->lookup_user_data = NULL;
448
 
449
   return 0;
450
 
451
free_screen:
452
   dri->core->destroyScreen(dri->screen);
453
 
454
   return ret;
455
}
456
 
457
static int
458
dri_screen_create_swrast(struct gbm_dri_device *dri)
459
{
460
   int ret;
461
 
462
   dri->base.driver_name = strdup("swrast");
463
   if (dri->base.driver_name == NULL)
464
      return -1;
465
 
466
   ret = dri_load_driver_swrast(dri);
467
   if (ret) {
468
      fprintf(stderr, "failed to load swrast driver\n");
469
      return ret;
470
   }
471
 
472
   dri->extensions = gbm_dri_screen_extensions;
473
 
474
   if (dri->swrast == NULL)
475
      return -1;
476
 
477
   if (dri->swrast->base.version >= 4) {
478
      dri->screen = dri->swrast->createNewScreen2(0, dri->extensions,
479
                                                  dri->driver_extensions,
480
                                                  &dri->driver_configs, dri);
481
   } else {
482
      dri->screen = dri->swrast->createNewScreen(0, dri->extensions,
483
                                                 &dri->driver_configs, dri);
484
   }
485
   if (dri->screen == NULL)
486
      return -1;
487
 
488
   dri->lookup_image = NULL;
489
   dri->lookup_user_data = NULL;
490
 
491
   return 0;
492
}
493
 
494
static int
495
dri_screen_create(struct gbm_dri_device *dri)
496
{
497
   char *driver_name;
498
 
499
   driver_name = loader_get_driver_for_fd(dri->base.base.fd, 0);
500
   if (!driver_name)
501
      return -1;
502
 
503
   return dri_screen_create_dri2(dri, driver_name);
504
}
505
 
506
static int
507
dri_screen_create_sw(struct gbm_dri_device *dri)
508
{
509
   char *driver_name;
510
   int ret;
511
 
512
   driver_name = strdup("kms_swrast");
513
   if (!driver_name)
514
      return -errno;
515
 
516
   ret = dri_screen_create_dri2(dri, driver_name);
517
   if (ret == 0)
518
      return ret;
519
 
520
   return dri_screen_create_swrast(dri);
521
}
522
 
523
static int
524
gbm_dri_is_format_supported(struct gbm_device *gbm,
525
                            uint32_t format,
526
                            uint32_t usage)
527
{
528
   switch (format) {
529
   case GBM_BO_FORMAT_XRGB8888:
530
   case GBM_FORMAT_XRGB8888:
531
      break;
532
   case GBM_BO_FORMAT_ARGB8888:
533
   case GBM_FORMAT_ARGB8888:
534
      if (usage & GBM_BO_USE_SCANOUT)
535
         return 0;
536
      break;
537
   default:
538
      return 0;
539
   }
540
 
541
   if (usage & GBM_BO_USE_CURSOR &&
542
       usage & GBM_BO_USE_RENDERING)
543
      return 0;
544
 
545
   return 1;
546
}
547
 
548
static int
549
gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
550
{
551
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
552
 
553
   if (bo->image != NULL) {
554
      errno = EINVAL;
555
      return -1;
556
   }
557
 
558
   memcpy(bo->map, buf, count);
559
 
560
   return 0;
561
}
562
 
563
static int
564
gbm_dri_bo_get_fd(struct gbm_bo *_bo)
565
{
566
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
567
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
568
   int fd;
569
 
570
   if (bo->image == NULL)
571
      return -1;
572
 
573
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd);
574
 
575
   return fd;
576
}
577
 
578
static void
579
gbm_dri_bo_destroy(struct gbm_bo *_bo)
580
{
581
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
582
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
583
   struct drm_mode_destroy_dumb arg;
584
 
585
   if (bo->image != NULL) {
586
      dri->image->destroyImage(bo->image);
587
   } else {
588
      gbm_dri_bo_unmap(bo);
589
      memset(&arg, 0, sizeof(arg));
590
      arg.handle = bo->handle;
591
      drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
592
   }
593
 
594
   free(bo);
595
}
596
 
597
static uint32_t
598
gbm_dri_to_gbm_format(uint32_t dri_format)
599
{
600
   uint32_t ret = 0;
601
 
602
   switch (dri_format) {
603
   case __DRI_IMAGE_FORMAT_RGB565:
604
      ret = GBM_FORMAT_RGB565;
605
      break;
606
   case __DRI_IMAGE_FORMAT_XRGB8888:
607
      ret = GBM_FORMAT_XRGB8888;
608
      break;
609
   case __DRI_IMAGE_FORMAT_ARGB8888:
610
      ret = GBM_FORMAT_ARGB8888;
611
      break;
612
   case __DRI_IMAGE_FORMAT_ABGR8888:
613
      ret = GBM_FORMAT_ABGR8888;
614
      break;
615
   default:
616
      ret = 0;
617
      break;
618
   }
619
 
620
   return ret;
621
}
622
 
623
static struct gbm_bo *
624
gbm_dri_bo_import(struct gbm_device *gbm,
625
                  uint32_t type, void *buffer, uint32_t usage)
626
{
627
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
628
   struct gbm_dri_bo *bo;
629
   __DRIimage *image;
630
   unsigned dri_use = 0;
631
   int gbm_format;
632
 
633
   /* Required for query image WIDTH & HEIGHT */
634
   if (dri->image == NULL || dri->image->base.version < 4) {
635
      errno = ENOSYS;
636
      return NULL;
637
   }
638
 
639
   switch (type) {
640
#if HAVE_WAYLAND_PLATFORM
641
   case GBM_BO_IMPORT_WL_BUFFER:
642
   {
643
      struct wl_drm_buffer *wb;
644
 
645
      if (!dri->wl_drm) {
646
         errno = EINVAL;
647
         return NULL;
648
      }
649
 
650
      wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer);
651
      if (!wb) {
652
         errno = EINVAL;
653
         return NULL;
654
      }
655
 
656
      image = dri->image->dupImage(wb->driver_buffer, NULL);
657
 
658
      switch (wb->format) {
659
      case WL_DRM_FORMAT_XRGB8888:
660
         gbm_format = GBM_FORMAT_XRGB8888;
661
         break;
662
      case WL_DRM_FORMAT_ARGB8888:
663
         gbm_format = GBM_FORMAT_ARGB8888;
664
         break;
665
      case WL_DRM_FORMAT_RGB565:
666
         gbm_format = GBM_FORMAT_RGB565;
667
         break;
668
      case WL_DRM_FORMAT_YUYV:
669
         gbm_format = GBM_FORMAT_YUYV;
670
         break;
671
      default:
672
         return NULL;
673
      }
674
      break;
675
   }
676
#endif
677
 
678
   case GBM_BO_IMPORT_EGL_IMAGE:
679
   {
680
      int dri_format;
681
      if (dri->lookup_image == NULL) {
682
         errno = EINVAL;
683
         return NULL;
684
      }
685
 
686
      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
687
      image = dri->image->dupImage(image, NULL);
688
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
689
      gbm_format = gbm_dri_to_gbm_format(dri_format);
690
      if (gbm_format == 0) {
691
         errno = EINVAL;
692
         return NULL;
693
      }
694
      break;
695
   }
696
 
697
   case GBM_BO_IMPORT_FD:
698
   {
699
      struct gbm_import_fd_data *fd_data = buffer;
700
      int stride = fd_data->stride, offset = 0;
701
 
702
      image = dri->image->createImageFromFds(dri->screen,
703
                                             fd_data->width,
704
                                             fd_data->height,
705
                                             fd_data->format,
706
                                             &fd_data->fd, 1,
707
                                             &stride, &offset,
708
                                             NULL);
709
      gbm_format = fd_data->format;
710
      break;
711
   }
712
 
713
   default:
714
      errno = ENOSYS;
715
      return NULL;
716
   }
717
 
718
 
719
   bo = calloc(1, sizeof *bo);
720
   if (bo == NULL)
721
      return NULL;
722
 
723
   bo->image = image;
724
 
725
   if (usage & GBM_BO_USE_SCANOUT)
726
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
727
   if (usage & GBM_BO_USE_CURSOR)
728
      dri_use |= __DRI_IMAGE_USE_CURSOR;
729
   if (dri->image->base.version >= 2 &&
730
       !dri->image->validateUsage(bo->image, dri_use)) {
731
      errno = EINVAL;
732
      free(bo);
733
      return NULL;
734
   }
735
 
736
   bo->base.base.gbm = gbm;
737
   bo->base.base.format = gbm_format;
738
 
739
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
740
                          (int*)&bo->base.base.width);
741
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
742
                          (int*)&bo->base.base.height);
743
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
744
                          (int*)&bo->base.base.stride);
745
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
746
                          &bo->base.base.handle.s32);
747
 
748
   return &bo->base.base;
749
}
750
 
751
static struct gbm_bo *
752
create_dumb(struct gbm_device *gbm,
753
                  uint32_t width, uint32_t height,
754
                  uint32_t format, uint32_t usage)
755
{
756
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
757
   struct drm_mode_create_dumb create_arg;
758
   struct gbm_dri_bo *bo;
759
   struct drm_mode_destroy_dumb destroy_arg;
760
   int ret;
761
   int is_cursor, is_scanout;
762
 
763
   is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 &&
764
      format == GBM_FORMAT_ARGB8888;
765
   is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 &&
766
      format == GBM_FORMAT_XRGB8888;
767
   if (!is_cursor && !is_scanout) {
768
      errno = EINVAL;
769
      return NULL;
770
   }
771
 
772
   bo = calloc(1, sizeof *bo);
773
   if (bo == NULL)
774
      return NULL;
775
 
776
   memset(&create_arg, 0, sizeof(create_arg));
777
   create_arg.bpp = 32;
778
   create_arg.width = width;
779
   create_arg.height = height;
780
 
781
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
782
   if (ret)
783
      goto free_bo;
784
 
785
   bo->base.base.gbm = gbm;
786
   bo->base.base.width = width;
787
   bo->base.base.height = height;
788
   bo->base.base.stride = create_arg.pitch;
789
   bo->base.base.format = format;
790
   bo->base.base.handle.u32 = create_arg.handle;
791
   bo->handle = create_arg.handle;
792
   bo->size = create_arg.size;
793
 
794
   if (gbm_dri_bo_map(bo) == NULL)
795
      goto destroy_dumb;
796
 
797
   return &bo->base.base;
798
 
799
destroy_dumb:
800
   memset(&destroy_arg, 0, sizeof destroy_arg);
801
   destroy_arg.handle = create_arg.handle;
802
   drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
803
free_bo:
804
   free(bo);
805
 
806
   return NULL;
807
}
808
 
809
static struct gbm_bo *
810
gbm_dri_bo_create(struct gbm_device *gbm,
811
                  uint32_t width, uint32_t height,
812
                  uint32_t format, uint32_t usage)
813
{
814
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
815
   struct gbm_dri_bo *bo;
816
   int dri_format;
817
   unsigned dri_use = 0;
818
 
819
   if (usage & GBM_BO_USE_WRITE || dri->image == NULL)
820
      return create_dumb(gbm, width, height, format, usage);
821
 
822
   bo = calloc(1, sizeof *bo);
823
   if (bo == NULL)
824
      return NULL;
825
 
826
   bo->base.base.gbm = gbm;
827
   bo->base.base.width = width;
828
   bo->base.base.height = height;
829
   bo->base.base.format = format;
830
 
831
   switch (format) {
832
   case GBM_FORMAT_RGB565:
833
      dri_format =__DRI_IMAGE_FORMAT_RGB565;
834
      break;
835
   case GBM_FORMAT_XRGB8888:
836
   case GBM_BO_FORMAT_XRGB8888:
837
      dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
838
      break;
839
   case GBM_FORMAT_ARGB8888:
840
   case GBM_BO_FORMAT_ARGB8888:
841
      dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
842
      break;
843
   case GBM_FORMAT_ABGR8888:
844
      dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
845
      break;
846
   case GBM_FORMAT_ARGB2101010:
847
      dri_format = __DRI_IMAGE_FORMAT_ARGB2101010;
848
      break;
849
   case GBM_FORMAT_XRGB2101010:
850
      dri_format = __DRI_IMAGE_FORMAT_XRGB2101010;
851
      break;
852
   default:
853
      errno = EINVAL;
854
      goto failed;
855
   }
856
 
857
   if (usage & GBM_BO_USE_SCANOUT)
858
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
859
   if (usage & GBM_BO_USE_CURSOR)
860
      dri_use |= __DRI_IMAGE_USE_CURSOR;
861
   if (usage & GBM_BO_USE_LINEAR)
862
      dri_use |= __DRI_IMAGE_USE_LINEAR;
863
 
864
   /* Gallium drivers requires shared in order to get the handle/stride */
865
   dri_use |= __DRI_IMAGE_USE_SHARE;
866
 
867
   bo->image =
868
      dri->image->createImage(dri->screen,
869
                              width, height,
870
                              dri_format, dri_use,
871
                              bo);
872
   if (bo->image == NULL)
873
      goto failed;
874
 
875
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
876
                          &bo->base.base.handle.s32);
877
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
878
                          (int *) &bo->base.base.stride);
879
 
880
   return &bo->base.base;
881
 
882
failed:
883
   free(bo);
884
   return NULL;
885
}
886
 
887
static struct gbm_surface *
888
gbm_dri_surface_create(struct gbm_device *gbm,
889
                       uint32_t width, uint32_t height,
890
		       uint32_t format, uint32_t flags)
891
{
892
   struct gbm_dri_surface *surf;
893
 
894
   surf = calloc(1, sizeof *surf);
895
   if (surf == NULL)
896
      return NULL;
897
 
898
   surf->base.gbm = gbm;
899
   surf->base.width = width;
900
   surf->base.height = height;
901
   surf->base.format = format;
902
   surf->base.flags = flags;
903
 
904
   return &surf->base;
905
}
906
 
907
static void
908
gbm_dri_surface_destroy(struct gbm_surface *_surf)
909
{
910
   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
911
 
912
   free(surf);
913
}
914
 
915
static void
916
dri_destroy(struct gbm_device *gbm)
917
{
918
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
919
   unsigned i;
920
 
921
   dri->core->destroyScreen(dri->screen);
922
   for (i = 0; dri->driver_configs[i]; i++)
923
      free((__DRIconfig *) dri->driver_configs[i]);
924
   free(dri->driver_configs);
925
   dlclose(dri->driver);
926
   free(dri->base.driver_name);
927
 
928
   free(dri);
929
}
930
 
931
static struct gbm_device *
932
dri_device_create(int fd)
933
{
934
   struct gbm_dri_device *dri;
935
   int ret, force_sw;
936
 
937
   dri = calloc(1, sizeof *dri);
938
   if (!dri)
939
      return NULL;
940
 
941
   dri->base.base.fd = fd;
942
   dri->base.base.bo_create = gbm_dri_bo_create;
943
   dri->base.base.bo_import = gbm_dri_bo_import;
944
   dri->base.base.is_format_supported = gbm_dri_is_format_supported;
945
   dri->base.base.bo_write = gbm_dri_bo_write;
946
   dri->base.base.bo_get_fd = gbm_dri_bo_get_fd;
947
   dri->base.base.bo_destroy = gbm_dri_bo_destroy;
948
   dri->base.base.destroy = dri_destroy;
949
   dri->base.base.surface_create = gbm_dri_surface_create;
950
   dri->base.base.surface_destroy = gbm_dri_surface_destroy;
951
 
952
   dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
953
   dri->base.base.name = "drm";
954
 
955
   force_sw = getenv("GBM_ALWAYS_SOFTWARE") != NULL;
956
   if (!force_sw) {
957
      ret = dri_screen_create(dri);
958
      if (ret)
959
         ret = dri_screen_create_sw(dri);
960
   } else {
961
      ret = dri_screen_create_sw(dri);
962
   }
963
 
964
   if (ret)
965
      goto err_dri;
966
 
967
   return &dri->base.base;
968
 
969
err_dri:
970
   free(dri);
971
 
972
   return NULL;
973
}
974
 
975
struct gbm_backend gbm_dri_backend = {
976
   .backend_name = "dri",
977
   .create_device = dri_device_create,
978
};