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>
35 #include <sys/types.h>
41 #include <GL/gl.h> /* dri_interface needs GL types */
42 #include <GL/internal/dri_interface.h>
44 #include "gbm_driint.h"
48 /* For importing wl_buffer */
49 #if HAVE_WAYLAND_PLATFORM
50 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
54 dri_lookup_egl_image(__DRIscreen
*screen
, void *image
, void *data
)
56 struct gbm_dri_device
*dri
= data
;
58 if (dri
->lookup_image
== NULL
)
61 return dri
->lookup_image(screen
, image
, dri
->lookup_user_data
);
65 dri_get_buffers(__DRIdrawable
* driDrawable
,
66 int *width
, int *height
,
67 unsigned int *attachments
, int count
,
68 int *out_count
, void *data
)
70 struct gbm_dri_surface
*surf
= data
;
71 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
73 if (dri
->get_buffers
== NULL
)
76 return dri
->get_buffers(driDrawable
, width
, height
, attachments
,
77 count
, out_count
, surf
->dri_private
);
81 dri_flush_front_buffer(__DRIdrawable
* driDrawable
, void *data
)
83 struct gbm_dri_surface
*surf
= data
;
84 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
86 if (dri
->flush_front_buffer
!= NULL
)
87 dri
->flush_front_buffer(driDrawable
, surf
->dri_private
);
91 dri_get_buffers_with_format(__DRIdrawable
* driDrawable
,
92 int *width
, int *height
,
93 unsigned int *attachments
, int count
,
94 int *out_count
, void *data
)
96 struct gbm_dri_surface
*surf
= data
;
97 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
99 if (dri
->get_buffers_with_format
== NULL
)
103 dri
->get_buffers_with_format(driDrawable
, width
, height
, attachments
,
104 count
, out_count
, surf
->dri_private
);
107 static const __DRIuseInvalidateExtension use_invalidate
= {
108 { __DRI_USE_INVALIDATE
, 1 }
111 static const __DRIimageLookupExtension image_lookup_extension
= {
112 { __DRI_IMAGE_LOOKUP
, 1 },
116 const __DRIdri2LoaderExtension dri2_loader_extension
= {
117 { __DRI_DRI2_LOADER
, 3 },
119 dri_flush_front_buffer
,
120 dri_get_buffers_with_format
,
123 struct dri_extension_match
{
129 static struct dri_extension_match dri_core_extensions
[] = {
130 { __DRI2_FLUSH
, 1, offsetof(struct gbm_dri_device
, flush
) },
131 { __DRI_IMAGE
, 1, offsetof(struct gbm_dri_device
, image
) },
135 static struct dri_extension_match gbm_dri_device_extensions
[] = {
136 { __DRI_CORE
, 1, offsetof(struct gbm_dri_device
, core
) },
137 { __DRI_DRI2
, 1, offsetof(struct gbm_dri_device
, dri2
) },
142 dri_bind_extensions(struct gbm_dri_device
*dri
,
143 struct dri_extension_match
*matches
,
144 const __DRIextension
**extensions
)
149 for (i
= 0; extensions
[i
]; i
++) {
150 for (j
= 0; matches
[j
].name
; j
++) {
151 if (strcmp(extensions
[i
]->name
, matches
[j
].name
) == 0 &&
152 extensions
[i
]->version
>= matches
[j
].version
) {
153 field
= ((char *) dri
+ matches
[j
].offset
);
154 *(const __DRIextension
**) field
= extensions
[i
];
159 for (j
= 0; matches
[j
].name
; j
++) {
160 field
= ((char *) dri
+ matches
[j
].offset
);
161 if (*(const __DRIextension
**) field
== NULL
) {
170 dri_load_driver(struct gbm_dri_device
*dri
)
172 const __DRIextension
**extensions
= NULL
;
173 char path
[PATH_MAX
], *search_paths
, *p
, *next
, *end
;
174 char *get_extensions_name
;
177 if (geteuid() == getuid()) {
178 /* don't allow setuid apps to use GBM_DRIVERS_PATH */
179 search_paths
= getenv("GBM_DRIVERS_PATH");
181 if (search_paths
== NULL
)
182 search_paths
= DEFAULT_DRIVER_DIR
;
185 end
= search_paths
+ strlen(search_paths
);
186 for (p
= search_paths
; p
< end
&& dri
->driver
== NULL
; p
= next
+ 1) {
188 next
= strchr(p
, ':');
194 snprintf(path
, sizeof path
,
195 "%.*s/tls/%s_dri.so", len
, p
, dri
->base
.driver_name
);
196 dri
->driver
= dlopen(path
, RTLD_NOW
| RTLD_GLOBAL
);
198 if (dri
->driver
== NULL
) {
199 snprintf(path
, sizeof path
,
200 "%.*s/%s_dri.so", len
, p
, dri
->base
.driver_name
);
201 dri
->driver
= dlopen(path
, RTLD_NOW
| RTLD_GLOBAL
);
202 if (dri
->driver
== NULL
)
203 fprintf(stderr
, "failed to open %s: %s\n", path
, dlerror());
207 if (dri
->driver
== NULL
) {
208 fprintf(stderr
, "gbm: failed to open any driver (search paths %s)",
213 if (asprintf(&get_extensions_name
, "%s_%s",
214 __DRI_DRIVER_GET_EXTENSIONS
, dri
->base
.driver_name
) != -1) {
215 const __DRIextension
**(*get_extensions
)(void);
217 get_extensions
= dlsym(dri
->driver
, get_extensions_name
);
218 free(get_extensions_name
);
221 extensions
= get_extensions();
225 extensions
= dlsym(dri
->driver
, __DRI_DRIVER_EXTENSIONS
);
226 if (extensions
== NULL
) {
227 fprintf(stderr
, "gbm: driver exports no extensions (%s)", dlerror());
228 dlclose(dri
->driver
);
233 if (dri_bind_extensions(dri
, gbm_dri_device_extensions
, extensions
) < 0) {
234 dlclose(dri
->driver
);
235 fprintf(stderr
, "failed to bind extensions\n");
243 dri_screen_create(struct gbm_dri_device
*dri
)
245 const __DRIextension
**extensions
;
248 dri
->base
.driver_name
= dri_fd_get_driver_name(dri
->base
.base
.fd
);
249 if (dri
->base
.driver_name
== NULL
)
252 ret
= dri_load_driver(dri
);
254 fprintf(stderr
, "failed to load driver: %s\n", dri
->base
.driver_name
);
258 dri
->extensions
[0] = &image_lookup_extension
.base
;
259 dri
->extensions
[1] = &use_invalidate
.base
;
260 dri
->extensions
[2] = &dri2_loader_extension
.base
;
261 dri
->extensions
[3] = NULL
;
263 if (dri
->dri2
== NULL
)
266 dri
->screen
= dri
->dri2
->createNewScreen(0, dri
->base
.base
.fd
,
268 &dri
->driver_configs
, dri
);
269 if (dri
->screen
== NULL
)
272 extensions
= dri
->core
->getExtensions(dri
->screen
);
273 if (dri_bind_extensions(dri
, dri_core_extensions
, extensions
) < 0) {
278 dri
->lookup_image
= NULL
;
279 dri
->lookup_user_data
= NULL
;
284 dri
->core
->destroyScreen(dri
->screen
);
290 gbm_dri_is_format_supported(struct gbm_device
*gbm
,
295 case GBM_BO_FORMAT_XRGB8888
:
296 case GBM_FORMAT_XRGB8888
:
298 case GBM_BO_FORMAT_ARGB8888
:
299 case GBM_FORMAT_ARGB8888
:
300 if (usage
& GBM_BO_USE_SCANOUT
)
307 if (usage
& GBM_BO_USE_CURSOR_64X64
&&
308 usage
& GBM_BO_USE_RENDERING
)
315 gbm_dri_bo_write(struct gbm_bo
*_bo
, const void *buf
, size_t count
)
317 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
319 if (bo
->image
!= NULL
)
322 memcpy(bo
->map
, buf
, count
);
328 gbm_dri_bo_destroy(struct gbm_bo
*_bo
)
330 struct gbm_dri_device
*dri
= gbm_dri_device(_bo
->gbm
);
331 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
332 struct drm_mode_destroy_dumb arg
;
334 if (bo
->image
!= NULL
) {
335 dri
->image
->destroyImage(bo
->image
);
337 munmap(bo
->map
, bo
->size
);
338 memset(&arg
, 0, sizeof(arg
));
339 arg
.handle
= bo
->handle
;
340 drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &arg
);
347 gbm_dri_to_gbm_format(uint32_t dri_format
)
351 switch (dri_format
) {
352 case __DRI_IMAGE_FORMAT_RGB565
:
353 ret
= GBM_FORMAT_RGB565
;
355 case __DRI_IMAGE_FORMAT_XRGB8888
:
356 ret
= GBM_FORMAT_XRGB8888
;
358 case __DRI_IMAGE_FORMAT_ARGB8888
:
359 ret
= GBM_FORMAT_ARGB8888
;
361 case __DRI_IMAGE_FORMAT_ABGR8888
:
362 ret
= GBM_FORMAT_ABGR8888
;
372 static struct gbm_bo
*
373 gbm_dri_bo_import(struct gbm_device
*gbm
,
374 uint32_t type
, void *buffer
, uint32_t usage
)
376 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
377 struct gbm_dri_bo
*bo
;
379 unsigned dri_use
= 0;
382 /* Required for query image WIDTH & HEIGHT */
383 if (dri
->image
->base
.version
< 4)
387 #if HAVE_WAYLAND_PLATFORM
388 case GBM_BO_IMPORT_WL_BUFFER
:
390 struct wl_drm_buffer
*wb
;
395 wb
= wayland_drm_buffer_get(dri
->wl_drm
, (struct wl_resource
*) buffer
);
399 image
= wb
->driver_buffer
;
401 switch (wb
->format
) {
402 case WL_DRM_FORMAT_XRGB8888
:
403 gbm_format
= GBM_FORMAT_XRGB8888
;
405 case WL_DRM_FORMAT_ARGB8888
:
406 gbm_format
= GBM_FORMAT_ARGB8888
;
408 case WL_DRM_FORMAT_RGB565
:
409 gbm_format
= GBM_FORMAT_RGB565
;
411 case WL_DRM_FORMAT_YUYV
:
412 gbm_format
= GBM_FORMAT_YUYV
;
421 case GBM_BO_IMPORT_EGL_IMAGE
:
424 if (dri
->lookup_image
== NULL
)
427 image
= dri
->lookup_image(dri
->screen
, buffer
, dri
->lookup_user_data
);
428 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_FORMAT
, &dri_format
);
429 gbm_format
= gbm_dri_to_gbm_format(dri_format
);
440 bo
= calloc(1, sizeof *bo
);
444 bo
->image
= dri
->image
->dupImage(image
, NULL
);
446 if (usage
& GBM_BO_USE_SCANOUT
)
447 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
448 if (usage
& GBM_BO_USE_CURSOR_64X64
)
449 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
450 if (dri
->image
->base
.version
>= 2 &&
451 !dri
->image
->validateUsage(bo
->image
, dri_use
)) {
456 bo
->base
.base
.gbm
= gbm
;
457 bo
->base
.base
.format
= gbm_format
;
459 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_WIDTH
,
460 (int*)&bo
->base
.base
.width
);
461 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HEIGHT
,
462 (int*)&bo
->base
.base
.height
);
463 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_STRIDE
,
464 (int*)&bo
->base
.base
.stride
);
465 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
466 &bo
->base
.base
.handle
.s32
);
468 return &bo
->base
.base
;
471 static struct gbm_bo
*
472 create_dumb(struct gbm_device
*gbm
,
473 uint32_t width
, uint32_t height
,
474 uint32_t format
, uint32_t usage
)
476 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
477 struct drm_mode_create_dumb create_arg
;
478 struct drm_mode_map_dumb map_arg
;
479 struct gbm_dri_bo
*bo
;
480 struct drm_mode_destroy_dumb destroy_arg
;
483 if (!(usage
& GBM_BO_USE_CURSOR_64X64
))
485 if (format
!= GBM_FORMAT_ARGB8888
)
488 bo
= calloc(1, sizeof *bo
);
493 create_arg
.width
= width
;
494 create_arg
.height
= height
;
496 ret
= drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_CREATE_DUMB
, &create_arg
);
500 bo
->base
.base
.gbm
= gbm
;
501 bo
->base
.base
.width
= width
;
502 bo
->base
.base
.height
= height
;
503 bo
->base
.base
.stride
= create_arg
.pitch
;
504 bo
->base
.base
.format
= format
;
505 bo
->base
.base
.handle
.u32
= create_arg
.handle
;
506 bo
->handle
= create_arg
.handle
;
507 bo
->size
= create_arg
.size
;
509 memset(&map_arg
, 0, sizeof(map_arg
));
510 map_arg
.handle
= bo
->handle
;
512 ret
= drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_MAP_DUMB
, &map_arg
);
516 bo
->map
= mmap(0, bo
->size
, PROT_WRITE
,
517 MAP_SHARED
, dri
->base
.base
.fd
, map_arg
.offset
);
518 if (bo
->map
== MAP_FAILED
)
521 return &bo
->base
.base
;
524 memset(&destroy_arg
, 0, sizeof destroy_arg
);
525 destroy_arg
.handle
= create_arg
.handle
;
526 drmIoctl(dri
->base
.base
.fd
, DRM_IOCTL_MODE_DESTROY_DUMB
, &destroy_arg
);
533 static struct gbm_bo
*
534 gbm_dri_bo_create(struct gbm_device
*gbm
,
535 uint32_t width
, uint32_t height
,
536 uint32_t format
, uint32_t usage
)
538 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
539 struct gbm_dri_bo
*bo
;
541 unsigned dri_use
= 0;
543 if (usage
& GBM_BO_USE_WRITE
)
544 return create_dumb(gbm
, width
, height
, format
, usage
);
546 bo
= calloc(1, sizeof *bo
);
550 bo
->base
.base
.gbm
= gbm
;
551 bo
->base
.base
.width
= width
;
552 bo
->base
.base
.height
= height
;
553 bo
->base
.base
.format
= format
;
556 case GBM_FORMAT_RGB565
:
557 dri_format
=__DRI_IMAGE_FORMAT_RGB565
;
559 case GBM_FORMAT_XRGB8888
:
560 case GBM_BO_FORMAT_XRGB8888
:
561 dri_format
= __DRI_IMAGE_FORMAT_XRGB8888
;
563 case GBM_FORMAT_ARGB8888
:
564 case GBM_BO_FORMAT_ARGB8888
:
565 dri_format
= __DRI_IMAGE_FORMAT_ARGB8888
;
567 case GBM_FORMAT_ABGR8888
:
568 dri_format
= __DRI_IMAGE_FORMAT_ABGR8888
;
570 case GBM_FORMAT_ARGB2101010
:
571 dri_format
= __DRI_IMAGE_FORMAT_ARGB2101010
;
573 case GBM_FORMAT_XRGB2101010
:
574 dri_format
= __DRI_IMAGE_FORMAT_XRGB2101010
;
580 if (usage
& GBM_BO_USE_SCANOUT
)
581 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
582 if (usage
& GBM_BO_USE_CURSOR_64X64
)
583 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
585 /* Gallium drivers requires shared in order to get the handle/stride */
586 dri_use
|= __DRI_IMAGE_USE_SHARE
;
589 dri
->image
->createImage(dri
->screen
,
593 if (bo
->image
== NULL
)
596 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
597 &bo
->base
.base
.handle
.s32
);
598 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_STRIDE
,
599 (int *) &bo
->base
.base
.stride
);
601 return &bo
->base
.base
;
604 static struct gbm_surface
*
605 gbm_dri_surface_create(struct gbm_device
*gbm
,
606 uint32_t width
, uint32_t height
,
607 uint32_t format
, uint32_t flags
)
609 struct gbm_dri_surface
*surf
;
611 surf
= calloc(1, sizeof *surf
);
615 surf
->base
.gbm
= gbm
;
616 surf
->base
.width
= width
;
617 surf
->base
.height
= height
;
618 surf
->base
.format
= format
;
619 surf
->base
.flags
= flags
;
625 gbm_dri_surface_destroy(struct gbm_surface
*_surf
)
627 struct gbm_dri_surface
*surf
= gbm_dri_surface(_surf
);
633 dri_destroy(struct gbm_device
*gbm
)
635 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
637 dri
->core
->destroyScreen(dri
->screen
);
638 free(dri
->driver_configs
);
639 dlclose(dri
->driver
);
640 free(dri
->base
.driver_name
);
645 static struct gbm_device
*
646 dri_device_create(int fd
)
648 struct gbm_dri_device
*dri
;
651 dri
= calloc(1, sizeof *dri
);
653 dri
->base
.base
.fd
= fd
;
654 dri
->base
.base
.bo_create
= gbm_dri_bo_create
;
655 dri
->base
.base
.bo_import
= gbm_dri_bo_import
;
656 dri
->base
.base
.is_format_supported
= gbm_dri_is_format_supported
;
657 dri
->base
.base
.bo_write
= gbm_dri_bo_write
;
658 dri
->base
.base
.bo_destroy
= gbm_dri_bo_destroy
;
659 dri
->base
.base
.destroy
= dri_destroy
;
660 dri
->base
.base
.surface_create
= gbm_dri_surface_create
;
661 dri
->base
.base
.surface_destroy
= gbm_dri_surface_destroy
;
663 dri
->base
.type
= GBM_DRM_DRIVER_TYPE_DRI
;
664 dri
->base
.base
.name
= "drm";
666 ret
= dri_screen_create(dri
);
670 return &dri
->base
.base
;
678 struct gbm_backend gbm_dri_backend
= {
679 .backend_name
= "dri",
680 .create_device
= dri_device_create
,