Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 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
 
35
#include 
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
 
48
/* For importing wl_buffer */
49
#if HAVE_WAYLAND_PLATFORM
50
#include "../../../egl/wayland/wayland-drm/wayland-drm.h"
51
#endif
52
 
53
void *load_library(const char *name);
54
void *get_proc_address(void *lib, char *proc_name);
55
 
56
 
57
static __DRIimage *
58
dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
59
{
60
   struct gbm_dri_device *dri = data;
61
 
62
   if (dri->lookup_image == NULL)
63
      return NULL;
64
 
65
   return dri->lookup_image(screen, image, dri->lookup_user_data);
66
}
67
 
68
static __DRIbuffer *
69
dri_get_buffers(__DRIdrawable * driDrawable,
70
		 int *width, int *height,
71
		 unsigned int *attachments, int count,
72
		 int *out_count, void *data)
73
{
74
   struct gbm_dri_surface *surf = data;
75
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
76
 
77
   if (dri->get_buffers == NULL)
78
      return NULL;
79
 
80
   return dri->get_buffers(driDrawable, width, height, attachments,
81
                           count, out_count, surf->dri_private);
82
}
83
 
84
static void
85
dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
86
{
87
   struct gbm_dri_surface *surf = data;
88
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
89
 
90
   if (dri->flush_front_buffer != NULL)
91
      dri->flush_front_buffer(driDrawable, surf->dri_private);
92
}
93
 
94
static __DRIbuffer *
95
dri_get_buffers_with_format(__DRIdrawable * driDrawable,
96
                            int *width, int *height,
97
                            unsigned int *attachments, int count,
98
                            int *out_count, void *data)
99
{
100
   struct gbm_dri_surface *surf = data;
101
   struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
102
 
103
   if (dri->get_buffers_with_format == NULL)
104
      return NULL;
105
 
106
   return
107
      dri->get_buffers_with_format(driDrawable, width, height, attachments,
108
                                   count, out_count, surf->dri_private);
109
}
110
 
111
static const __DRIuseInvalidateExtension use_invalidate = {
112
   { __DRI_USE_INVALIDATE, 1 }
113
};
114
 
115
static const __DRIimageLookupExtension image_lookup_extension = {
116
   { __DRI_IMAGE_LOOKUP, 1 },
117
   dri_lookup_egl_image
118
};
119
 
120
const __DRIdri2LoaderExtension dri2_loader_extension = {
121
   { __DRI_DRI2_LOADER, 3 },
122
   dri_get_buffers,
123
   dri_flush_front_buffer,
124
   dri_get_buffers_with_format,
125
};
126
 
127
struct dri_extension_match {
128
   const char *name;
129
   int version;
130
   int offset;
131
};
132
 
133
static struct dri_extension_match dri_core_extensions[] = {
134
   { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
135
   { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
136
   { NULL, 0, 0 }
137
};
138
 
139
static struct dri_extension_match gbm_dri_device_extensions[] = {
140
   { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
141
   { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
142
   { NULL, 0, 0 }
143
};
144
 
145
static int
146
dri_bind_extensions(struct gbm_dri_device *dri,
147
                    struct dri_extension_match *matches,
148
                    const __DRIextension **extensions)
149
{
150
   int i, j, ret = 0;
151
   void *field;
152
 
153
   for (i = 0; extensions[i]; i++) {
154
      for (j = 0; matches[j].name; j++) {
155
         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
156
             extensions[i]->version >= matches[j].version) {
157
            field = ((char *) dri + matches[j].offset);
158
            *(const __DRIextension **) field = extensions[i];
159
         }
160
      }
161
   }
162
 
163
   for (j = 0; matches[j].name; j++) {
164
      field = ((char *) dri + matches[j].offset);
165
      if (*(const __DRIextension **) field == NULL) {
166
         ret = -1;
167
      }
168
   }
169
 
170
   return ret;
171
}
172
 
173
static int
174
dri_load_driver(struct gbm_dri_device *dri)
175
{
176
   const __DRIextension **extensions;
177
//   char path[PATH_MAX], *search_paths, *p, *next, *end;
178
   char *search_paths;
179
 
180
   search_paths = NULL;
181
 
182
#if 0
183
 
184
   if (geteuid() == getuid()) {
185
      /* don't allow setuid apps to use GBM_DRIVERS_PATH */
186
      search_paths = getenv("GBM_DRIVERS_PATH");
187
   }
188
   if (search_paths == NULL)
189
      search_paths = DEFAULT_DRIVER_DIR;
190
 
191
   dri->driver = NULL;
192
   end = search_paths + strlen(search_paths);
193
   for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
194
      int len;
195
      next = strchr(p, ':');
196
      if (next == NULL)
197
         next = end;
198
 
199
      len = next - p;
200
#if GLX_USE_TLS
201
      snprintf(path, sizeof path,
202
               "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
203
      dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
204
#endif
205
      if (dri->driver == NULL) {
206
         snprintf(path, sizeof path,
207
                  "%.*s/%s_dri.so", len, p, dri->base.driver_name);
208
         dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
209
         if (dri->driver == NULL)
210
            fprintf(stderr, "failed to open %s: %s\n", path, dlerror());
211
      }
212
   }
213
#endif
214
 
215
   dri->driver = load_library("libGL.dll");
216
 
217
   if (dri->driver == NULL) {
218
      fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
219
              search_paths);
220
      return -1;
221
   }
222
 
223
   extensions = get_proc_address(dri->driver, __DRI_DRIVER_EXTENSIONS);
224
   if (extensions == NULL) {
225
      fprintf(stderr, "gbm: driver exports no extensions\n");
226
//      dlclose(dri->driver);
227
      return -1;
228
   }
229
 
230
 
231
   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
232
//      dlclose(dri->driver);
233
      fprintf(stderr, "failed to bind extensions\n");
234
      return -1;
235
   }
236
 
237
   return 0;
238
}
239
 
240
static int
241
dri_screen_create(struct gbm_dri_device *dri)
242
{
243
   const __DRIextension **extensions;
244
   int ret = 0;
245
 
246
   dri->base.driver_name = strdup("drm"); //dri_fd_get_driver_name(dri->base.base.fd);
247
   if (dri->base.driver_name == NULL)
248
      return -1;
249
 
250
   ret = dri_load_driver(dri);
251
   if (ret) {
252
      fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
253
      return ret;
254
   };
255
 
256
   dri->extensions[0] = &image_lookup_extension.base;
257
   dri->extensions[1] = &use_invalidate.base;
258
   dri->extensions[2] = &dri2_loader_extension.base;
259
   dri->extensions[3] = NULL;
260
 
261
   if (dri->dri2 == NULL)
262
      return -1;
263
 
264
   dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
265
                                            dri->extensions,
266
                                            &dri->driver_configs, dri);
267
   if (dri->screen == NULL)
268
      return -1;
269
 
270
   extensions = dri->core->getExtensions(dri->screen);
271
   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
272
      ret = -1;
273
      goto free_screen;
274
   }
275
 
276
   dri->lookup_image = NULL;
277
   dri->lookup_user_data = NULL;
278
 
279
   return 0;
280
 
281
free_screen:
282
   dri->core->destroyScreen(dri->screen);
283
 
284
   return ret;
285
}
286
 
287
static int
288
gbm_dri_is_format_supported(struct gbm_device *gbm,
289
                            uint32_t format,
290
                            uint32_t usage)
291
{
292
   switch (format) {
293
   case GBM_BO_FORMAT_XRGB8888:
294
   case GBM_FORMAT_XRGB8888:
295
      break;
296
   case GBM_BO_FORMAT_ARGB8888:
297
   case GBM_FORMAT_ARGB8888:
298
      if (usage & GBM_BO_USE_SCANOUT)
299
         return 0;
300
      break;
301
   default:
302
      return 0;
303
   }
304
 
305
   if (usage & GBM_BO_USE_CURSOR_64X64 &&
306
       usage & GBM_BO_USE_RENDERING)
307
      return 0;
308
 
309
   return 1;
310
}
311
 
312
static int
313
gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
314
{
315
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
316
 
317
   if (bo->image != NULL)
318
      return -1;
319
 
320
   memcpy(bo->map, buf, count);
321
 
322
   return 0;
323
}
324
 
325
static void
326
gbm_dri_bo_destroy(struct gbm_bo *_bo)
327
{
328
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
329
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
330
//   struct drm_mode_destroy_dumb arg;
331
 
332
   if (bo->image != NULL) {
333
      dri->image->destroyImage(bo->image);
334
   } else {
335
//      munmap(bo->map, bo->size);
336
//      memset(&arg, 0, sizeof(arg));
337
//      arg.handle = bo->handle;
338
//      drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
339
   }
340
 
341
   free(bo);
342
}
343
 
344
static uint32_t
345
gbm_dri_to_gbm_format(uint32_t dri_format)
346
{
347
   uint32_t ret = 0;
348
 
349
   switch (dri_format) {
350
   case __DRI_IMAGE_FORMAT_RGB565:
351
      ret = GBM_FORMAT_RGB565;
352
      break;
353
   case __DRI_IMAGE_FORMAT_XRGB8888:
354
      ret = GBM_FORMAT_XRGB8888;
355
      break;
356
   case __DRI_IMAGE_FORMAT_ARGB8888:
357
      ret = GBM_FORMAT_ARGB8888;
358
      break;
359
   case __DRI_IMAGE_FORMAT_ABGR8888:
360
      ret = GBM_FORMAT_ABGR8888;
361
      break;
362
   default:
363
      ret = 0;
364
      break;
365
   }
366
 
367
   return ret;
368
}
369
 
370
static struct gbm_bo *
371
gbm_dri_bo_import(struct gbm_device *gbm,
372
                  uint32_t type, void *buffer, uint32_t usage)
373
{
374
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
375
   struct gbm_dri_bo *bo;
376
   __DRIimage *image;
377
   unsigned dri_use = 0;
378
   int gbm_format;
379
 
380
   /* Required for query image WIDTH & HEIGHT */
381
   if (dri->image->base.version < 4)
382
      return NULL;
383
 
384
   switch (type) {
385
#if HAVE_WAYLAND_PLATFORM
386
   case GBM_BO_IMPORT_WL_BUFFER:
387
   {
388
      struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
389
 
390
      if (!wayland_buffer_is_drm(buffer))
391
         return NULL;
392
 
393
      image = wb->driver_buffer;
394
 
395
      switch (wb->format) {
396
      case WL_DRM_FORMAT_XRGB8888:
397
         gbm_format = GBM_FORMAT_XRGB8888;
398
         break;
399
      case WL_DRM_FORMAT_ARGB8888:
400
         gbm_format = GBM_FORMAT_ARGB8888;
401
         break;
402
      case WL_DRM_FORMAT_YUYV:
403
         gbm_format = GBM_FORMAT_YUYV;
404
         break;
405
      default:
406
         return NULL;
407
      }
408
      break;
409
   }
410
#endif
411
 
412
   case GBM_BO_IMPORT_EGL_IMAGE:
413
   {
414
      int dri_format;
415
      if (dri->lookup_image == NULL)
416
         return NULL;
417
 
418
      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
419
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
420
      gbm_format = gbm_dri_to_gbm_format(dri_format);
421
      if (gbm_format == 0)
422
         return NULL;
423
      break;
424
   }
425
 
426
   default:
427
      return NULL;
428
   }
429
 
430
 
431
   bo = calloc(1, sizeof *bo);
432
   if (bo == NULL)
433
      return NULL;
434
 
435
   bo->image = dri->image->dupImage(image, NULL);
436
 
437
   if (usage & GBM_BO_USE_SCANOUT)
438
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
439
   if (usage & GBM_BO_USE_CURSOR_64X64)
440
      dri_use |= __DRI_IMAGE_USE_CURSOR;
441
   if (dri->image->base.version >= 2 &&
442
       !dri->image->validateUsage(bo->image, dri_use)) {
443
      free(bo);
444
      return NULL;
445
   }
446
 
447
   bo->base.base.gbm = gbm;
448
   bo->base.base.format = gbm_format;
449
 
450
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
451
                          (int*)&bo->base.base.width);
452
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
453
                          (int*)&bo->base.base.height);
454
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
455
                          (int*)&bo->base.base.stride);
456
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
457
                          &bo->base.base.handle.s32);
458
 
459
   return &bo->base.base;
460
}
461
 
462
#if 0
463
static struct gbm_bo *
464
create_dumb(struct gbm_device *gbm,
465
                  uint32_t width, uint32_t height,
466
                  uint32_t format, uint32_t usage)
467
{
468
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
469
   struct drm_mode_create_dumb create_arg;
470
   struct drm_mode_map_dumb map_arg;
471
   struct gbm_dri_bo *bo;
472
   struct drm_mode_destroy_dumb destroy_arg;
473
   int ret;
474
 
475
   if (!(usage & GBM_BO_USE_CURSOR_64X64))
476
      return NULL;
477
   if (format != GBM_FORMAT_ARGB8888)
478
      return NULL;
479
 
480
   bo = calloc(1, sizeof *bo);
481
   if (bo == NULL)
482
      return NULL;
483
 
484
   create_arg.bpp = 32;
485
   create_arg.width = width;
486
   create_arg.height = height;
487
 
488
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
489
   if (ret)
490
      goto free_bo;
491
 
492
   bo->base.base.gbm = gbm;
493
   bo->base.base.width = width;
494
   bo->base.base.height = height;
495
   bo->base.base.stride = create_arg.pitch;
496
   bo->base.base.format = format;
497
   bo->base.base.handle.u32 = create_arg.handle;
498
   bo->handle = create_arg.handle;
499
   bo->size = create_arg.size;
500
 
501
   memset(&map_arg, 0, sizeof(map_arg));
502
   map_arg.handle = bo->handle;
503
 
504
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
505
   if (ret)
506
      goto destroy_dumb;
507
 
508
   bo->map = mmap(0, bo->size, PROT_WRITE,
509
                  MAP_SHARED, dri->base.base.fd, map_arg.offset);
510
   if (bo->map == MAP_FAILED)
511
      goto destroy_dumb;
512
 
513
   return &bo->base.base;
514
 
515
destroy_dumb:
516
   memset(&destroy_arg, 0, sizeof destroy_arg);
517
   destroy_arg.handle = create_arg.handle;
518
   drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
519
free_bo:
520
   free(bo);
521
 
522
   return NULL;
523
}
524
#endif
525
 
526
static struct gbm_bo *
527
gbm_dri_bo_create(struct gbm_device *gbm,
528
                  uint32_t width, uint32_t height,
529
                  uint32_t format, uint32_t usage)
530
{
531
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
532
   struct gbm_dri_bo *bo;
533
   int dri_format;
534
   unsigned dri_use = 0;
535
 
536
//   if (usage & GBM_BO_USE_WRITE)
537
//      return create_dumb(gbm, width, height, format, usage);
538
 
539
   bo = calloc(1, sizeof *bo);
540
   if (bo == NULL)
541
      return NULL;
542
 
543
   bo->base.base.gbm = gbm;
544
   bo->base.base.width = width;
545
   bo->base.base.height = height;
546
   bo->base.base.format = format;
547
 
548
   switch (format) {
549
   case GBM_FORMAT_RGB565:
550
      dri_format =__DRI_IMAGE_FORMAT_RGB565;
551
      break;
552
   case GBM_FORMAT_XRGB8888:
553
   case GBM_BO_FORMAT_XRGB8888:
554
      dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
555
      break;
556
   case GBM_FORMAT_ARGB8888:
557
   case GBM_BO_FORMAT_ARGB8888:
558
      dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
559
      break;
560
   case GBM_FORMAT_ABGR8888:
561
      dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
562
      break;
563
   default:
564
      return NULL;
565
   }
566
 
567
   if (usage & GBM_BO_USE_SCANOUT)
568
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
569
   if (usage & GBM_BO_USE_CURSOR_64X64)
570
      dri_use |= __DRI_IMAGE_USE_CURSOR;
571
 
572
   /* Gallium drivers requires shared in order to get the handle/stride */
573
   dri_use |= __DRI_IMAGE_USE_SHARE;
574
 
575
   bo->image =
576
      dri->image->createImage(dri->screen,
577
                              width, height,
578
                              dri_format, dri_use,
579
                              bo);
580
   if (bo->image == NULL)
581
      return NULL;
582
 
583
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
584
                          &bo->base.base.handle.s32);
585
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
586
                          (int *) &bo->base.base.stride);
587
 
588
   printf("%s handle %d w %d h%d\n",__FUNCTION__, bo->base.base.handle.s32,
589
            width, height);
590
 
591
   return &bo->base.base;
592
}
593
 
594
static struct gbm_surface *
595
gbm_dri_surface_create(struct gbm_device *gbm,
596
                       uint32_t width, uint32_t height,
597
		       uint32_t format, uint32_t flags)
598
{
599
   struct gbm_dri_surface *surf;
600
 
601
   surf = calloc(1, sizeof *surf);
602
   if (surf == NULL)
603
      return NULL;
604
 
605
   surf->base.gbm = gbm;
606
   surf->base.width = width;
607
   surf->base.height = height;
608
   surf->base.format = format;
609
   surf->base.flags = flags;
610
 
611
   return &surf->base;
612
}
613
 
614
static void
615
gbm_dri_surface_destroy(struct gbm_surface *_surf)
616
{
617
   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
618
 
619
   free(surf);
620
}
621
 
622
static void
623
dri_destroy(struct gbm_device *gbm)
624
{
625
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
626
 
627
   dri->core->destroyScreen(dri->screen);
628
   free(dri->driver_configs);
629
//   dlclose(dri->driver);
630
   free(dri->base.driver_name);
631
 
632
   free(dri);
633
}
634
 
635
static struct gbm_device *
636
dri_device_create(int fd)
637
{
638
   struct gbm_dri_device *dri;
639
   int ret;
640
 
641
   dri = calloc(1, sizeof *dri);
642
 
643
   dri->base.base.fd = fd;
644
   dri->base.base.bo_create = gbm_dri_bo_create;
645
   dri->base.base.bo_import = gbm_dri_bo_import;
646
   dri->base.base.is_format_supported = gbm_dri_is_format_supported;
647
   dri->base.base.bo_write = gbm_dri_bo_write;
648
   dri->base.base.bo_destroy = gbm_dri_bo_destroy;
649
   dri->base.base.destroy = dri_destroy;
650
   dri->base.base.surface_create = gbm_dri_surface_create;
651
   dri->base.base.surface_destroy = gbm_dri_surface_destroy;
652
 
653
   dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
654
   dri->base.base.name = "drm";
655
 
656
   ret = dri_screen_create(dri);
657
   if (ret)
658
      goto err_dri;
659
 
660
   return &dri->base.base;
661
 
662
err_dri:
663
   free(dri);
664
 
665
   return NULL;
666
}
667
 
668
struct gbm_backend gbm_dri_backend = {
669
   .backend_name = "dri",
670
   .create_device = dri_device_create,
671
};