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