2 * Copyright © 2011 Intel Corporation
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:
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
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.
25 * Benjamin Franzke <benjaminfranzke@googlemail.com>
36 #include <sys/types.h>
42 #include <GL/gl.h> /* dri_interface needs GL types */
43 #include <GL/internal/dri_interface.h>
45 #include "gbm_driint.h"
50 /* For importing wl_buffer */
51 #if HAVE_WAYLAND_PLATFORM
52 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
56 dri_lookup_egl_image(__DRIscreen
*screen
, void *image
, void *data
)
58 struct gbm_dri_device
*dri
= data
;
60 if (dri
->lookup_image
== NULL
)
63 return dri
->lookup_image(screen
, image
, dri
->lookup_user_data
);
67 dri_get_buffers(__DRIdrawable
* driDrawable
,
68 int *width
, int *height
,
69 unsigned int *attachments
, int count
,
70 int *out_count
, void *data
)
72 struct gbm_dri_surface
*surf
= data
;
73 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
75 if (dri
->get_buffers
== NULL
)
78 return dri
->get_buffers(driDrawable
, width
, height
, attachments
,
79 count
, out_count
, surf
->dri_private
);
83 dri_flush_front_buffer(__DRIdrawable
* driDrawable
, void *data
)
85 struct gbm_dri_surface
*surf
= data
;
86 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
88 if (dri
->flush_front_buffer
!= NULL
)
89 dri
->flush_front_buffer(driDrawable
, surf
->dri_private
);
93 dri_get_buffers_with_format(__DRIdrawable
* driDrawable
,
94 int *width
, int *height
,
95 unsigned int *attachments
, int count
,
96 int *out_count
, void *data
)
98 struct gbm_dri_surface
*surf
= data
;
99 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
101 if (dri
->get_buffers_with_format
== NULL
)
105 dri
->get_buffers_with_format(driDrawable
, width
, height
, attachments
,
106 count
, out_count
, surf
->dri_private
);
110 image_get_buffers(__DRIdrawable
*driDrawable
,
114 uint32_t buffer_mask
,
115 struct __DRIimageList
*buffers
)
117 struct gbm_dri_surface
*surf
= loaderPrivate
;
118 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
120 if (dri
->image_get_buffers
== NULL
)
123 return dri
->image_get_buffers(driDrawable
, format
, stamp
,
124 surf
->dri_private
, buffer_mask
, buffers
);
127 static const __DRIuseInvalidateExtension use_invalidate
= {
128 .base
= { __DRI_USE_INVALIDATE
, 1 }
131 static const __DRIimageLookupExtension image_lookup_extension
= {
132 .base
= { __DRI_IMAGE_LOOKUP
, 1 },
134 .lookupEGLImage
= dri_lookup_egl_image
137 static const __DRIdri2LoaderExtension dri2_loader_extension
= {
138 .base
= { __DRI_DRI2_LOADER
, 3 },
140 .getBuffers
= dri_get_buffers
,
141 .flushFrontBuffer
= dri_flush_front_buffer
,
142 .getBuffersWithFormat
= dri_get_buffers_with_format
,
145 static const __DRIimageLoaderExtension image_loader_extension
= {
146 .base
= { __DRI_IMAGE_LOADER
, 1 },
148 .getBuffers
= image_get_buffers
,
149 .flushFrontBuffer
= dri_flush_front_buffer
,
152 static const __DRIextension
*gbm_dri_screen_extensions
[] = {
153 &image_lookup_extension
.base
,
154 &use_invalidate
.base
,
155 &dri2_loader_extension
.base
,
156 &image_loader_extension
.base
,
160 struct dri_extension_match
{
166 static struct dri_extension_match dri_core_extensions
[] = {
167 { __DRI2_FLUSH
, 1, offsetof(struct gbm_dri_device
, flush
) },
168 { __DRI_IMAGE
, 1, offsetof(struct gbm_dri_device
, image
) },
172 static struct dri_extension_match gbm_dri_device_extensions
[] = {
173 { __DRI_CORE
, 1, offsetof(struct gbm_dri_device
, core
) },
174 { __DRI_DRI2
, 1, offsetof(struct gbm_dri_device
, dri2
) },
179 dri_bind_extensions(struct gbm_dri_device
*dri
,
180 struct dri_extension_match
*matches
,
181 const __DRIextension
**extensions
)
186 for (i
= 0; extensions
[i
]; i
++) {
187 for (j
= 0; matches
[j
].name
; j
++) {
188 if (strcmp(extensions
[i
]->name
, matches
[j
].name
) == 0 &&
189 extensions
[i
]->version
>= matches
[j
].version
) {
190 field
= ((char *) dri
+ matches
[j
].offset
);
191 *(const __DRIextension
**) field
= extensions
[i
];
196 for (j
= 0; matches
[j
].name
; j
++) {
197 field
= ((char *) dri
+ matches
[j
].offset
);
198 if (*(const __DRIextension
**) field
== NULL
) {
207 dri_load_driver(struct gbm_dri_device
*dri
)
209 const __DRIextension
**extensions
= NULL
;
210 char path
[PATH_MAX
], *search_paths
, *p
, *next
, *end
;
211 char *get_extensions_name
;
214 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH or GBM_DRIVERS_PATH */
215 if (geteuid() == getuid()) {
216 /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH
217 * is recommended over GBM_DRIVERS_PATH.
219 search_paths
= getenv("GBM_DRIVERS_PATH");
221 /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set.
222 * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH.
224 if (search_paths
== NULL
) {
225 search_paths
= getenv("LIBGL_DRIVERS_PATH");
228 if (search_paths
== NULL
)
229 search_paths
= DEFAULT_DRIVER_DIR
;
232 end
= search_paths
+ strlen(search_paths
);
233 for (p
= search_paths
; p
< end
&& dri
->driver
== NULL
; p
= next
+ 1) {
235 next
= strchr(p
, ':');
241 snprintf(path
, sizeof path
,
242 "%.*s/tls/%s_dri.so", len
, p
, dri
->base
.driver_name
);
243 dri
->driver
= dlopen(path
, RTLD_NOW
| RTLD_GLOBAL
);
245 if (dri
->driver
== NULL
) {
246 snprintf(path
, sizeof path
,
247 "%.*s/%s_dri.so", len
, p
, dri
->base
.driver_name
);
248 dri
->driver
= dlopen(path
, RTLD_NOW
| RTLD_GLOBAL
);
250 /* not need continue to loop all paths once the driver is found */
251 if (dri
->driver
!= NULL
)
255 if (dri
->driver
== NULL
) {
256 fprintf(stderr
, "gbm: failed to open any driver (search paths %s)",
261 if (asprintf(&get_extensions_name
, "%s_%s",
262 __DRI_DRIVER_GET_EXTENSIONS
, dri
->base
.driver_name
) != -1) {
263 const __DRIextension
**(*get_extensions
)(void);
265 get_extensions
= dlsym(dri
->driver
, get_extensions_name
);
266 free(get_extensions_name
);
269 extensions
= get_extensions();
273 extensions
= dlsym(dri
->driver
, __DRI_DRIVER_EXTENSIONS
);
274 if (extensions
== NULL
) {
275 fprintf(stderr
, "gbm: driver exports no extensions (%s)", dlerror());
276 dlclose(dri
->driver
);
279 dri
->driver_extensions
= extensions
;
281 if (dri_bind_extensions(dri
, gbm_dri_device_extensions
, extensions
) < 0) {
282 dlclose(dri
->driver
);
283 fprintf(stderr
, "failed to bind extensions\n");
291 dri_screen_create(struct gbm_dri_device
*dri
)
293 const __DRIextension
**extensions
;
296 dri
->base
.driver_name
= loader_get_driver_for_fd(dri
->base
.base
.fd
, 0);
297 if (dri
->base
.driver_name
== NULL
)
300 ret
= dri_load_driver(dri
);
302 fprintf(stderr
, "failed to load driver: %s\n", dri
->base
.driver_name
);
306 dri
->extensions
= gbm_dri_screen_extensions
;
308 if (dri
->dri2
== NULL
)
311 if (dri
->dri2
->base
.version
>= 4) {
312 dri
->screen
= dri
->dri2
->createNewScreen2(0, dri
->base
.base
.fd
,
314 dri
->driver_extensions
,
315 &dri
->driver_configs
, dri
);
317 dri
->screen
= dri
->dri2
->createNewScreen(0, dri
->base
.base
.fd
,
319 &dri
->driver_configs
, dri
);
321 if (dri
->screen
== NULL
)
324 extensions
= dri
->core
->getExtensions(dri
->screen
);
325 if (dri_bind_extensions(dri
, dri_core_extensions
, extensions
) < 0) {
330 dri
->lookup_image
= NULL
;
331 dri
->lookup_user_data
= NULL
;
336 dri
->core
->destroyScreen(dri
->screen
);
342 gbm_dri_is_format_supported(struct gbm_device
*gbm
,
347 case GBM_BO_FORMAT_XRGB8888
:
348 case GBM_FORMAT_XRGB8888
:
350 case GBM_BO_FORMAT_ARGB8888
:
351 case GBM_FORMAT_ARGB8888
:
352 if (usage
& GBM_BO_USE_SCANOUT
)
359 if (usage
& GBM_BO_USE_CURSOR
&&
360 usage
& GBM_BO_USE_RENDERING
)
367 gbm_dri_bo_write(struct gbm_bo
*_bo
, const void *buf
, size_t count
)
369 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
371 if (bo
->image
!= NULL
) {
376 memcpy(bo
->map
, buf
, count
);
382 gbm_dri_bo_get_fd(struct gbm_bo
*_bo
)
384 struct gbm_dri_device
*dri
= gbm_dri_device(_bo
->gbm
);
385 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
388 if (bo
->image
== NULL
)
391 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_FD
, &fd
);
397 gbm_dri_bo_destroy(struct gbm_bo
*_bo
)
399 struct gbm_dri_device
*dri
= gbm_dri_device(_bo
->gbm
);
400 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
401 struct drm_mode_destroy_dumb arg
;
403 if (bo
->image
!= NULL
) {
404 dri
->image
->destroyImage(bo
->image
);
406 munmap(bo
->map
, bo
->size
);
407 memset(&arg
, 0, sizeof(arg
));
408 arg
.handle
= bo
->handle
;
409 drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &arg
);
416 gbm_dri_to_gbm_format(uint32_t dri_format
)
420 switch (dri_format
) {
421 case __DRI_IMAGE_FORMAT_RGB565
:
422 ret
= GBM_FORMAT_RGB565
;
424 case __DRI_IMAGE_FORMAT_XRGB8888
:
425 ret
= GBM_FORMAT_XRGB8888
;
427 case __DRI_IMAGE_FORMAT_ARGB8888
:
428 ret
= GBM_FORMAT_ARGB8888
;
430 case __DRI_IMAGE_FORMAT_ABGR8888
:
431 ret
= GBM_FORMAT_ABGR8888
;
441 static struct gbm_bo
*
442 gbm_dri_bo_import(struct gbm_device
*gbm
,
443 uint32_t type
, void *buffer
, uint32_t usage
)
445 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
446 struct gbm_dri_bo
*bo
;
448 unsigned dri_use
= 0;
451 /* Required for query image WIDTH & HEIGHT */
452 if (dri
->image
->base
.version
< 4) {
458 #if HAVE_WAYLAND_PLATFORM
459 case GBM_BO_IMPORT_WL_BUFFER
:
461 struct wl_drm_buffer
*wb
;
468 wb
= wayland_drm_buffer_get(dri
->wl_drm
, (struct wl_resource
*) buffer
);
474 image
= dri
->image
->dupImage(wb
->driver_buffer
, NULL
);
476 switch (wb
->format
) {
477 case WL_DRM_FORMAT_XRGB8888
:
478 gbm_format
= GBM_FORMAT_XRGB8888
;
480 case WL_DRM_FORMAT_ARGB8888
:
481 gbm_format
= GBM_FORMAT_ARGB8888
;
483 case WL_DRM_FORMAT_RGB565
:
484 gbm_format
= GBM_FORMAT_RGB565
;
486 case WL_DRM_FORMAT_YUYV
:
487 gbm_format
= GBM_FORMAT_YUYV
;
496 case GBM_BO_IMPORT_EGL_IMAGE
:
499 if (dri
->lookup_image
== NULL
) {
504 image
= dri
->lookup_image(dri
->screen
, buffer
, dri
->lookup_user_data
);
505 image
= dri
->image
->dupImage(image
, NULL
);
506 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_FORMAT
, &dri_format
);
507 gbm_format
= gbm_dri_to_gbm_format(dri_format
);
508 if (gbm_format
== 0) {
515 case GBM_BO_IMPORT_FD
:
517 struct gbm_import_fd_data
*fd_data
= buffer
;
518 int stride
= fd_data
->stride
, offset
= 0;
520 image
= dri
->image
->createImageFromFds(dri
->screen
,
527 gbm_format
= fd_data
->format
;
537 bo
= calloc(1, sizeof *bo
);
543 if (usage
& GBM_BO_USE_SCANOUT
)
544 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
545 if (usage
& GBM_BO_USE_CURSOR
)
546 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
547 if (dri
->image
->base
.version
>= 2 &&
548 !dri
->image
->validateUsage(bo
->image
, dri_use
)) {
554 bo
->base
.base
.gbm
= gbm
;
555 bo
->base
.base
.format
= gbm_format
;
557 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_WIDTH
,
558 (int*)&bo
->base
.base
.width
);
559 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HEIGHT
,
560 (int*)&bo
->base
.base
.height
);
561 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_STRIDE
,
562 (int*)&bo
->base
.base
.stride
);
563 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
564 &bo
->base
.base
.handle
.s32
);
566 return &bo
->base
.base
;
569 static struct gbm_bo
*
570 create_dumb(struct gbm_device
*gbm
,
571 uint32_t width
, uint32_t height
,
572 uint32_t format
, uint32_t usage
)
574 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
575 struct drm_mode_create_dumb create_arg
;
576 struct drm_mode_map_dumb map_arg
;
577 struct gbm_dri_bo
*bo
;
578 struct drm_mode_destroy_dumb destroy_arg
;
581 if (!(usage
& GBM_BO_USE_CURSOR
)) {
585 if (format
!= GBM_FORMAT_ARGB8888
) {
590 bo
= calloc(1, sizeof *bo
);
595 create_arg
.width
= width
;
596 create_arg
.height
= height
;
598 ret
= drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_CREATE_DUMB
, &create_arg
);
602 bo
->base
.base
.gbm
= gbm
;
603 bo
->base
.base
.width
= width
;
604 bo
->base
.base
.height
= height
;
605 bo
->base
.base
.stride
= create_arg
.pitch
;
606 bo
->base
.base
.format
= format
;
607 bo
->base
.base
.handle
.u32
= create_arg
.handle
;
608 bo
->handle
= create_arg
.handle
;
609 bo
->size
= create_arg
.size
;
611 memset(&map_arg
, 0, sizeof(map_arg
));
612 map_arg
.handle
= bo
->handle
;
614 ret
= drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_MAP_DUMB
, &map_arg
);
618 bo
->map
= mmap(0, bo
->size
, PROT_WRITE
,
619 MAP_SHARED
, dri
->base
.base
.fd
, map_arg
.offset
);
620 if (bo
->map
== MAP_FAILED
)
623 return &bo
->base
.base
;
626 memset(&destroy_arg
, 0, sizeof destroy_arg
);
627 destroy_arg
.handle
= create_arg
.handle
;
628 drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &destroy_arg
);
635 static struct gbm_bo
*
636 gbm_dri_bo_create(struct gbm_device
*gbm
,
637 uint32_t width
, uint32_t height
,
638 uint32_t format
, uint32_t usage
)
640 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
641 struct gbm_dri_bo
*bo
;
643 unsigned dri_use
= 0;
645 if (usage
& GBM_BO_USE_WRITE
)
646 return create_dumb(gbm
, width
, height
, format
, usage
);
648 bo
= calloc(1, sizeof *bo
);
652 bo
->base
.base
.gbm
= gbm
;
653 bo
->base
.base
.width
= width
;
654 bo
->base
.base
.height
= height
;
655 bo
->base
.base
.format
= format
;
658 case GBM_FORMAT_RGB565
:
659 dri_format
=__DRI_IMAGE_FORMAT_RGB565
;
661 case GBM_FORMAT_XRGB8888
:
662 case GBM_BO_FORMAT_XRGB8888
:
663 dri_format
= __DRI_IMAGE_FORMAT_XRGB8888
;
665 case GBM_FORMAT_ARGB8888
:
666 case GBM_BO_FORMAT_ARGB8888
:
667 dri_format
= __DRI_IMAGE_FORMAT_ARGB8888
;
669 case GBM_FORMAT_ABGR8888
:
670 dri_format
= __DRI_IMAGE_FORMAT_ABGR8888
;
672 case GBM_FORMAT_ARGB2101010
:
673 dri_format
= __DRI_IMAGE_FORMAT_ARGB2101010
;
675 case GBM_FORMAT_XRGB2101010
:
676 dri_format
= __DRI_IMAGE_FORMAT_XRGB2101010
;
683 if (usage
& GBM_BO_USE_SCANOUT
)
684 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
685 if (usage
& GBM_BO_USE_CURSOR
)
686 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
688 /* Gallium drivers requires shared in order to get the handle/stride */
689 dri_use
|= __DRI_IMAGE_USE_SHARE
;
692 dri
->image
->createImage(dri
->screen
,
696 if (bo
->image
== NULL
)
699 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
700 &bo
->base
.base
.handle
.s32
);
701 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_STRIDE
,
702 (int *) &bo
->base
.base
.stride
);
704 return &bo
->base
.base
;
711 static struct gbm_surface
*
712 gbm_dri_surface_create(struct gbm_device
*gbm
,
713 uint32_t width
, uint32_t height
,
714 uint32_t format
, uint32_t flags
)
716 struct gbm_dri_surface
*surf
;
718 surf
= calloc(1, sizeof *surf
);
722 surf
->base
.gbm
= gbm
;
723 surf
->base
.width
= width
;
724 surf
->base
.height
= height
;
725 surf
->base
.format
= format
;
726 surf
->base
.flags
= flags
;
732 gbm_dri_surface_destroy(struct gbm_surface
*_surf
)
734 struct gbm_dri_surface
*surf
= gbm_dri_surface(_surf
);
740 dri_destroy(struct gbm_device
*gbm
)
742 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
744 dri
->core
->destroyScreen(dri
->screen
);
745 free(dri
->driver_configs
);
746 dlclose(dri
->driver
);
747 free(dri
->base
.driver_name
);
752 static struct gbm_device
*
753 dri_device_create(int fd
)
755 struct gbm_dri_device
*dri
;
758 dri
= calloc(1, sizeof *dri
);
762 dri
->base
.base
.fd
= fd
;
763 dri
->base
.base
.bo_create
= gbm_dri_bo_create
;
764 dri
->base
.base
.bo_import
= gbm_dri_bo_import
;
765 dri
->base
.base
.is_format_supported
= gbm_dri_is_format_supported
;
766 dri
->base
.base
.bo_write
= gbm_dri_bo_write
;
767 dri
->base
.base
.bo_get_fd
= gbm_dri_bo_get_fd
;
768 dri
->base
.base
.bo_destroy
= gbm_dri_bo_destroy
;
769 dri
->base
.base
.destroy
= dri_destroy
;
770 dri
->base
.base
.surface_create
= gbm_dri_surface_create
;
771 dri
->base
.base
.surface_destroy
= gbm_dri_surface_destroy
;
773 dri
->base
.type
= GBM_DRM_DRIVER_TYPE_DRI
;
774 dri
->base
.base
.name
= "drm";
776 ret
= dri_screen_create(dri
);
780 return &dri
->base
.base
;
788 struct gbm_backend gbm_dri_backend
= {
789 .backend_name
= "dri",
790 .create_device
= dri_device_create
,