Subversion Repositories Kolibri OS

Rev

Rev 4401 | 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;
4548 Serge 177
   char path[64];
4358 Serge 178
 
4548 Serge 179
   snprintf(path, sizeof path,"/kolibrios/lib/%s_dri.drv", dri->base.driver_name);
4358 Serge 180
 
4548 Serge 181
   dri->driver = load_library(path);
4358 Serge 182
 
183
   if (dri->driver == NULL) {
184
      fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
4548 Serge 185
              path);
4358 Serge 186
      return -1;
187
   }
188
 
189
   extensions = get_proc_address(dri->driver, __DRI_DRIVER_EXTENSIONS);
190
   if (extensions == NULL) {
191
      fprintf(stderr, "gbm: driver exports no extensions\n");
192
//      dlclose(dri->driver);
193
      return -1;
194
   }
195
 
196
 
197
   if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
198
//      dlclose(dri->driver);
199
      fprintf(stderr, "failed to bind extensions\n");
200
      return -1;
201
   }
202
 
203
   return 0;
204
}
205
 
206
static int
207
dri_screen_create(struct gbm_dri_device *dri)
208
{
209
   const __DRIextension **extensions;
210
   int ret = 0;
211
 
4548 Serge 212
   dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd);
4358 Serge 213
   if (dri->base.driver_name == NULL)
214
      return -1;
215
 
216
   ret = dri_load_driver(dri);
217
   if (ret) {
218
      fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
219
      return ret;
220
   };
221
 
222
   dri->extensions[0] = &image_lookup_extension.base;
223
   dri->extensions[1] = &use_invalidate.base;
224
   dri->extensions[2] = &dri2_loader_extension.base;
225
   dri->extensions[3] = NULL;
226
 
227
   if (dri->dri2 == NULL)
228
      return -1;
229
 
230
   dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
231
                                            dri->extensions,
232
                                            &dri->driver_configs, dri);
233
   if (dri->screen == NULL)
234
      return -1;
235
 
236
   extensions = dri->core->getExtensions(dri->screen);
237
   if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
238
      ret = -1;
239
      goto free_screen;
240
   }
241
 
242
   dri->lookup_image = NULL;
243
   dri->lookup_user_data = NULL;
244
 
245
   return 0;
246
 
247
free_screen:
248
   dri->core->destroyScreen(dri->screen);
249
 
250
   return ret;
251
}
252
 
253
static int
254
gbm_dri_is_format_supported(struct gbm_device *gbm,
255
                            uint32_t format,
256
                            uint32_t usage)
257
{
258
   switch (format) {
259
   case GBM_BO_FORMAT_XRGB8888:
260
   case GBM_FORMAT_XRGB8888:
261
      break;
262
   case GBM_BO_FORMAT_ARGB8888:
263
   case GBM_FORMAT_ARGB8888:
264
      if (usage & GBM_BO_USE_SCANOUT)
265
         return 0;
266
      break;
267
   default:
268
      return 0;
269
   }
270
 
271
   if (usage & GBM_BO_USE_CURSOR_64X64 &&
272
       usage & GBM_BO_USE_RENDERING)
273
      return 0;
274
 
275
   return 1;
276
}
277
 
278
static int
279
gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
280
{
281
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
282
 
283
   if (bo->image != NULL)
284
      return -1;
285
 
286
   memcpy(bo->map, buf, count);
287
 
288
   return 0;
289
}
290
 
291
static void
292
gbm_dri_bo_destroy(struct gbm_bo *_bo)
293
{
294
   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
295
   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
296
//   struct drm_mode_destroy_dumb arg;
297
 
298
   if (bo->image != NULL) {
299
      dri->image->destroyImage(bo->image);
300
   } else {
301
//      munmap(bo->map, bo->size);
302
//      memset(&arg, 0, sizeof(arg));
303
//      arg.handle = bo->handle;
304
//      drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
305
   }
306
 
307
   free(bo);
308
}
309
 
310
static uint32_t
311
gbm_dri_to_gbm_format(uint32_t dri_format)
312
{
313
   uint32_t ret = 0;
314
 
315
   switch (dri_format) {
316
   case __DRI_IMAGE_FORMAT_RGB565:
317
      ret = GBM_FORMAT_RGB565;
318
      break;
319
   case __DRI_IMAGE_FORMAT_XRGB8888:
320
      ret = GBM_FORMAT_XRGB8888;
321
      break;
322
   case __DRI_IMAGE_FORMAT_ARGB8888:
323
      ret = GBM_FORMAT_ARGB8888;
324
      break;
325
   case __DRI_IMAGE_FORMAT_ABGR8888:
326
      ret = GBM_FORMAT_ABGR8888;
327
      break;
328
   default:
329
      ret = 0;
330
      break;
331
   }
332
 
333
   return ret;
334
}
335
 
336
static struct gbm_bo *
337
gbm_dri_bo_import(struct gbm_device *gbm,
338
                  uint32_t type, void *buffer, uint32_t usage)
339
{
340
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
341
   struct gbm_dri_bo *bo;
342
   __DRIimage *image;
343
   unsigned dri_use = 0;
344
   int gbm_format;
345
 
346
   /* Required for query image WIDTH & HEIGHT */
347
   if (dri->image->base.version < 4)
348
      return NULL;
349
 
350
   switch (type) {
351
#if HAVE_WAYLAND_PLATFORM
352
   case GBM_BO_IMPORT_WL_BUFFER:
353
   {
354
      struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
355
 
4401 Serge 356
      if (dri->wl_drm == NULL)
4358 Serge 357
         return NULL;
358
 
4401 Serge 359
      if (!wayland_buffer_is_drm(dri->wl_drm, buffer))
360
         return NULL;
361
 
4358 Serge 362
      image = wb->driver_buffer;
363
 
364
      switch (wb->format) {
365
      case WL_DRM_FORMAT_XRGB8888:
366
         gbm_format = GBM_FORMAT_XRGB8888;
367
         break;
368
      case WL_DRM_FORMAT_ARGB8888:
369
         gbm_format = GBM_FORMAT_ARGB8888;
370
         break;
371
      case WL_DRM_FORMAT_YUYV:
372
         gbm_format = GBM_FORMAT_YUYV;
373
         break;
374
      default:
375
         return NULL;
376
      }
377
      break;
378
   }
379
#endif
380
 
381
   case GBM_BO_IMPORT_EGL_IMAGE:
382
   {
383
      int dri_format;
384
      if (dri->lookup_image == NULL)
385
         return NULL;
386
 
387
      image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
388
      dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
389
      gbm_format = gbm_dri_to_gbm_format(dri_format);
390
      if (gbm_format == 0)
391
         return NULL;
392
      break;
393
   }
394
 
395
   default:
396
      return NULL;
397
   }
398
 
399
 
400
   bo = calloc(1, sizeof *bo);
401
   if (bo == NULL)
402
      return NULL;
403
 
404
   bo->image = dri->image->dupImage(image, NULL);
405
 
406
   if (usage & GBM_BO_USE_SCANOUT)
407
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
408
   if (usage & GBM_BO_USE_CURSOR_64X64)
409
      dri_use |= __DRI_IMAGE_USE_CURSOR;
410
   if (dri->image->base.version >= 2 &&
411
       !dri->image->validateUsage(bo->image, dri_use)) {
412
      free(bo);
413
      return NULL;
414
   }
415
 
416
   bo->base.base.gbm = gbm;
417
   bo->base.base.format = gbm_format;
418
 
419
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH,
420
                          (int*)&bo->base.base.width);
421
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT,
422
                          (int*)&bo->base.base.height);
423
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
424
                          (int*)&bo->base.base.stride);
425
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
426
                          &bo->base.base.handle.s32);
427
 
428
   return &bo->base.base;
429
}
430
 
431
#if 0
432
static struct gbm_bo *
433
create_dumb(struct gbm_device *gbm,
434
                  uint32_t width, uint32_t height,
435
                  uint32_t format, uint32_t usage)
436
{
437
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
438
   struct drm_mode_create_dumb create_arg;
439
   struct drm_mode_map_dumb map_arg;
440
   struct gbm_dri_bo *bo;
441
   struct drm_mode_destroy_dumb destroy_arg;
442
   int ret;
443
 
444
   if (!(usage & GBM_BO_USE_CURSOR_64X64))
445
      return NULL;
446
   if (format != GBM_FORMAT_ARGB8888)
447
      return NULL;
448
 
449
   bo = calloc(1, sizeof *bo);
450
   if (bo == NULL)
451
      return NULL;
452
 
453
   create_arg.bpp = 32;
454
   create_arg.width = width;
455
   create_arg.height = height;
456
 
457
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
458
   if (ret)
459
      goto free_bo;
460
 
461
   bo->base.base.gbm = gbm;
462
   bo->base.base.width = width;
463
   bo->base.base.height = height;
464
   bo->base.base.stride = create_arg.pitch;
465
   bo->base.base.format = format;
466
   bo->base.base.handle.u32 = create_arg.handle;
467
   bo->handle = create_arg.handle;
468
   bo->size = create_arg.size;
469
 
470
   memset(&map_arg, 0, sizeof(map_arg));
471
   map_arg.handle = bo->handle;
472
 
473
   ret = drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
474
   if (ret)
475
      goto destroy_dumb;
476
 
477
   bo->map = mmap(0, bo->size, PROT_WRITE,
478
                  MAP_SHARED, dri->base.base.fd, map_arg.offset);
479
   if (bo->map == MAP_FAILED)
480
      goto destroy_dumb;
481
 
482
   return &bo->base.base;
483
 
484
destroy_dumb:
485
   memset(&destroy_arg, 0, sizeof destroy_arg);
486
   destroy_arg.handle = create_arg.handle;
487
   drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
488
free_bo:
489
   free(bo);
490
 
491
   return NULL;
492
}
493
#endif
494
 
495
static struct gbm_bo *
496
gbm_dri_bo_create(struct gbm_device *gbm,
497
                  uint32_t width, uint32_t height,
498
                  uint32_t format, uint32_t usage)
499
{
500
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
501
   struct gbm_dri_bo *bo;
502
   int dri_format;
503
   unsigned dri_use = 0;
504
 
505
//   if (usage & GBM_BO_USE_WRITE)
506
//      return create_dumb(gbm, width, height, format, usage);
507
 
508
   bo = calloc(1, sizeof *bo);
509
   if (bo == NULL)
510
      return NULL;
511
 
512
   bo->base.base.gbm = gbm;
513
   bo->base.base.width = width;
514
   bo->base.base.height = height;
515
   bo->base.base.format = format;
516
 
517
   switch (format) {
518
   case GBM_FORMAT_RGB565:
519
      dri_format =__DRI_IMAGE_FORMAT_RGB565;
520
      break;
521
   case GBM_FORMAT_XRGB8888:
522
   case GBM_BO_FORMAT_XRGB8888:
523
      dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
524
      break;
525
   case GBM_FORMAT_ARGB8888:
526
   case GBM_BO_FORMAT_ARGB8888:
527
      dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
528
      break;
529
   case GBM_FORMAT_ABGR8888:
530
      dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
531
      break;
532
   default:
533
      return NULL;
534
   }
535
 
536
   if (usage & GBM_BO_USE_SCANOUT)
537
      dri_use |= __DRI_IMAGE_USE_SCANOUT;
538
   if (usage & GBM_BO_USE_CURSOR_64X64)
539
      dri_use |= __DRI_IMAGE_USE_CURSOR;
540
 
541
   /* Gallium drivers requires shared in order to get the handle/stride */
542
   dri_use |= __DRI_IMAGE_USE_SHARE;
543
 
544
   bo->image =
545
      dri->image->createImage(dri->screen,
546
                              width, height,
547
                              dri_format, dri_use,
548
                              bo);
549
   if (bo->image == NULL)
550
      return NULL;
551
 
552
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
553
                          &bo->base.base.handle.s32);
554
   dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
555
                          (int *) &bo->base.base.stride);
556
 
557
   return &bo->base.base;
558
}
559
 
560
static struct gbm_surface *
561
gbm_dri_surface_create(struct gbm_device *gbm,
562
                       uint32_t width, uint32_t height,
563
		       uint32_t format, uint32_t flags)
564
{
565
   struct gbm_dri_surface *surf;
566
 
567
   surf = calloc(1, sizeof *surf);
568
   if (surf == NULL)
569
      return NULL;
570
 
571
   surf->base.gbm = gbm;
572
   surf->base.width = width;
573
   surf->base.height = height;
574
   surf->base.format = format;
575
   surf->base.flags = flags;
576
 
577
   return &surf->base;
578
}
579
 
580
static void
581
gbm_dri_surface_destroy(struct gbm_surface *_surf)
582
{
583
   struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
584
 
585
   free(surf);
586
}
587
 
588
static void
589
dri_destroy(struct gbm_device *gbm)
590
{
591
   struct gbm_dri_device *dri = gbm_dri_device(gbm);
592
 
593
   dri->core->destroyScreen(dri->screen);
594
   free(dri->driver_configs);
595
//   dlclose(dri->driver);
596
   free(dri->base.driver_name);
597
 
598
   free(dri);
599
}
600
 
601
static struct gbm_device *
602
dri_device_create(int fd)
603
{
604
   struct gbm_dri_device *dri;
605
   int ret;
606
 
607
   dri = calloc(1, sizeof *dri);
608
 
609
   dri->base.base.fd = fd;
610
   dri->base.base.bo_create = gbm_dri_bo_create;
611
   dri->base.base.bo_import = gbm_dri_bo_import;
612
   dri->base.base.is_format_supported = gbm_dri_is_format_supported;
613
   dri->base.base.bo_write = gbm_dri_bo_write;
614
   dri->base.base.bo_destroy = gbm_dri_bo_destroy;
615
   dri->base.base.destroy = dri_destroy;
616
   dri->base.base.surface_create = gbm_dri_surface_create;
617
   dri->base.base.surface_destroy = gbm_dri_surface_destroy;
618
 
619
   dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
620
   dri->base.base.name = "drm";
621
 
622
   ret = dri_screen_create(dri);
623
   if (ret)
624
      goto err_dri;
625
 
626
   return &dri->base.base;
627
 
628
err_dri:
629
   free(dri);
630
 
631
   return NULL;
632
}
633
 
634
struct gbm_backend gbm_dri_backend = {
635
   .backend_name = "dri",
636
   .create_device = dri_device_create,
637
};