Subversion Repositories Kolibri OS

Rev

Rev 4358 | Go to most recent revision | Details | Compare with Previous | 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
 
4401 Serge 390
      if (dri->wl_drm == NULL)
4358 Serge 391
         return NULL;
392
 
4401 Serge 393
      if (!wayland_buffer_is_drm(dri->wl_drm, buffer))
394
         return NULL;
395
 
4358 Serge 396
      image = wb->driver_buffer;
397
 
398
      switch (wb->format) {
399
      case WL_DRM_FORMAT_XRGB8888:
400
         gbm_format = GBM_FORMAT_XRGB8888;
401
         break;
402
      case WL_DRM_FORMAT_ARGB8888:
403
         gbm_format = GBM_FORMAT_ARGB8888;
404
         break;
405
      case WL_DRM_FORMAT_YUYV:
406
         gbm_format = GBM_FORMAT_YUYV;
407
         break;
408
      default:
409
         return NULL;
410
      }
411
      break;
412
   }
413
#endif
414
 
415
   case GBM_BO_IMPORT_EGL_IMAGE:
416
   {
417
      int dri_format;
418
      if (dri->lookup_image == NULL)
419
         return NULL;
420
 
421
      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
422
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
423
      gbm_format = gbm_dri_to_gbm_format(dri_format);
424
      if (gbm_format == 0)
425
         return NULL;
426
      break;
427
   }
428
 
429
   default:
430
      return NULL;
431
   }
432
 
433
 
434
   bo = calloc(1, sizeof *bo);
435
   if (bo == NULL)
436
      return NULL;
437
 
438
   bo->image = dri->image->dupImage(image, NULL);
439
 
440
   if (usage & GBM_BO_USE_SCANOUT)
441
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
442
   if (usage & GBM_BO_USE_CURSOR_64X64)
443
      dri_use |= __DRI_IMAGE_USE_CURSOR;
444
   if (dri->image->base.version >= 2 &&
445
       !dri->image->validateUsage(bo->image, dri_use)) {
446
      free(bo);
447
      return NULL;
448
   }
449
 
450
   bo->base.base.gbm = gbm;
451
   bo->base.base.format = gbm_format;
452
 
453
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
454
                          (int*)&bo->base.base.width);
455
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
456
                          (int*)&bo->base.base.height);
457
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
458
                          (int*)&bo->base.base.stride);
459
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
460
                          &bo->base.base.handle.s32);
461
 
462
   return &bo->base.base;
463
}
464
 
465
#if 0
466
static struct gbm_bo *
467
create_dumb(struct gbm_device *gbm,
468
                  uint32_t width, uint32_t height,
469
                  uint32_t format, uint32_t usage)
470
{
471
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
472
   struct drm_mode_create_dumb create_arg;
473
   struct drm_mode_map_dumb map_arg;
474
   struct gbm_dri_bo *bo;
475
   struct drm_mode_destroy_dumb destroy_arg;
476
   int ret;
477
 
478
   if (!(usage & GBM_BO_USE_CURSOR_64X64))
479
      return NULL;
480
   if (format != GBM_FORMAT_ARGB8888)
481
      return NULL;
482
 
483
   bo = calloc(1, sizeof *bo);
484
   if (bo == NULL)
485
      return NULL;
486
 
487
   create_arg.bpp = 32;
488
   create_arg.width = width;
489
   create_arg.height = height;
490
 
491
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
492
   if (ret)
493
      goto free_bo;
494
 
495
   bo->base.base.gbm = gbm;
496
   bo->base.base.width = width;
497
   bo->base.base.height = height;
498
   bo->base.base.stride = create_arg.pitch;
499
   bo->base.base.format = format;
500
   bo->base.base.handle.u32 = create_arg.handle;
501
   bo->handle = create_arg.handle;
502
   bo->size = create_arg.size;
503
 
504
   memset(&map_arg, 0, sizeof(map_arg));
505
   map_arg.handle = bo->handle;
506
 
507
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
508
   if (ret)
509
      goto destroy_dumb;
510
 
511
   bo->map = mmap(0, bo->size, PROT_WRITE,
512
                  MAP_SHARED, dri->base.base.fd, map_arg.offset);
513
   if (bo->map == MAP_FAILED)
514
      goto destroy_dumb;
515
 
516
   return &bo->base.base;
517
 
518
destroy_dumb:
519
   memset(&destroy_arg, 0, sizeof destroy_arg);
520
   destroy_arg.handle = create_arg.handle;
521
   drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
522
free_bo:
523
   free(bo);
524
 
525
   return NULL;
526
}
527
#endif
528
 
529
static struct gbm_bo *
530
gbm_dri_bo_create(struct gbm_device *gbm,
531
                  uint32_t width, uint32_t height,
532
                  uint32_t format, uint32_t usage)
533
{
534
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
535
   struct gbm_dri_bo *bo;
536
   int dri_format;
537
   unsigned dri_use = 0;
538
 
539
//   if (usage & GBM_BO_USE_WRITE)
540
//      return create_dumb(gbm, width, height, format, usage);
541
 
542
   bo = calloc(1, sizeof *bo);
543
   if (bo == NULL)
544
      return NULL;
545
 
546
   bo->base.base.gbm = gbm;
547
   bo->base.base.width = width;
548
   bo->base.base.height = height;
549
   bo->base.base.format = format;
550
 
551
   switch (format) {
552
   case GBM_FORMAT_RGB565:
553
      dri_format =__DRI_IMAGE_FORMAT_RGB565;
554
      break;
555
   case GBM_FORMAT_XRGB8888:
556
   case GBM_BO_FORMAT_XRGB8888:
557
      dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
558
      break;
559
   case GBM_FORMAT_ARGB8888:
560
   case GBM_BO_FORMAT_ARGB8888:
561
      dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
562
      break;
563
   case GBM_FORMAT_ABGR8888:
564
      dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
565
      break;
566
   default:
567
      return NULL;
568
   }
569
 
570
   if (usage & GBM_BO_USE_SCANOUT)
571
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
572
   if (usage & GBM_BO_USE_CURSOR_64X64)
573
      dri_use |= __DRI_IMAGE_USE_CURSOR;
574
 
575
   /* Gallium drivers requires shared in order to get the handle/stride */
576
   dri_use |= __DRI_IMAGE_USE_SHARE;
577
 
578
   bo->image =
579
      dri->image->createImage(dri->screen,
580
                              width, height,
581
                              dri_format, dri_use,
582
                              bo);
583
   if (bo->image == NULL)
584
      return NULL;
585
 
586
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
587
                          &bo->base.base.handle.s32);
588
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
589
                          (int *) &bo->base.base.stride);
590
 
591
   printf("%s handle %d w %d h%d\n",__FUNCTION__, bo->base.base.handle.s32,
592
            width, height);
593
 
594
   return &bo->base.base;
595
}
596
 
597
static struct gbm_surface *
598
gbm_dri_surface_create(struct gbm_device *gbm,
599
                       uint32_t width, uint32_t height,
600
		       uint32_t format, uint32_t flags)
601
{
602
   struct gbm_dri_surface *surf;
603
 
604
   surf = calloc(1, sizeof *surf);
605
   if (surf == NULL)
606
      return NULL;
607
 
608
   surf->base.gbm = gbm;
609
   surf->base.width = width;
610
   surf->base.height = height;
611
   surf->base.format = format;
612
   surf->base.flags = flags;
613
 
614
   return &surf->base;
615
}
616
 
617
static void
618
gbm_dri_surface_destroy(struct gbm_surface *_surf)
619
{
620
   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
621
 
622
   free(surf);
623
}
624
 
625
static void
626
dri_destroy(struct gbm_device *gbm)
627
{
628
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
629
 
630
   dri->core->destroyScreen(dri->screen);
631
   free(dri->driver_configs);
632
//   dlclose(dri->driver);
633
   free(dri->base.driver_name);
634
 
635
   free(dri);
636
}
637
 
638
static struct gbm_device *
639
dri_device_create(int fd)
640
{
641
   struct gbm_dri_device *dri;
642
   int ret;
643
 
644
   dri = calloc(1, sizeof *dri);
645
 
646
   dri->base.base.fd = fd;
647
   dri->base.base.bo_create = gbm_dri_bo_create;
648
   dri->base.base.bo_import = gbm_dri_bo_import;
649
   dri->base.base.is_format_supported = gbm_dri_is_format_supported;
650
   dri->base.base.bo_write = gbm_dri_bo_write;
651
   dri->base.base.bo_destroy = gbm_dri_bo_destroy;
652
   dri->base.base.destroy = dri_destroy;
653
   dri->base.base.surface_create = gbm_dri_surface_create;
654
   dri->base.base.surface_destroy = gbm_dri_surface_destroy;
655
 
656
   dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
657
   dri->base.base.name = "drm";
658
 
659
   ret = dri_screen_create(dri);
660
   if (ret)
661
      goto err_dri;
662
 
663
   return &dri->base.base;
664
 
665
err_dri:
666
   free(dri);
667
 
668
   return NULL;
669
}
670
 
671
struct gbm_backend gbm_dri_backend = {
672
   .backend_name = "dri",
673
   .create_device = dri_device_create,
674
};