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>
39 #include <GL/gl.h> /* dri_interface needs GL types */
40 #include <GL/internal/dri_interface.h>
42 #include "gbm_driint.h"
46 /* For importing wl_buffer */
47 #if HAVE_WAYLAND_PLATFORM
48 #include "../../../egl/wayland/wayland-drm/wayland-drm.h"
52 dri_lookup_egl_image(__DRIscreen
*screen
, void *image
, void *data
)
54 struct gbm_dri_device
*dri
= data
;
56 if (dri
->lookup_image
== NULL
)
59 return dri
->lookup_image(screen
, image
, dri
->lookup_user_data
);
63 dri_get_buffers(__DRIdrawable
* driDrawable
,
64 int *width
, int *height
,
65 unsigned int *attachments
, int count
,
66 int *out_count
, void *data
)
68 struct gbm_dri_surface
*surf
= data
;
69 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
71 if (dri
->get_buffers
== NULL
)
74 return dri
->get_buffers(driDrawable
, width
, height
, attachments
,
75 count
, out_count
, surf
->dri_private
);
79 dri_flush_front_buffer(__DRIdrawable
* driDrawable
, void *data
)
81 struct gbm_dri_surface
*surf
= data
;
82 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
84 if (dri
->flush_front_buffer
!= NULL
)
85 dri
->flush_front_buffer(driDrawable
, surf
->dri_private
);
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
)
94 struct gbm_dri_surface
*surf
= data
;
95 struct gbm_dri_device
*dri
= gbm_dri_device(surf
->base
.gbm
);
97 if (dri
->get_buffers_with_format
== NULL
)
101 dri
->get_buffers_with_format(driDrawable
, width
, height
, attachments
,
102 count
, out_count
, surf
->dri_private
);
105 static const __DRIuseInvalidateExtension use_invalidate
= {
106 { __DRI_USE_INVALIDATE
, 1 }
109 static const __DRIimageLookupExtension image_lookup_extension
= {
110 { __DRI_IMAGE_LOOKUP
, 1 },
114 const __DRIdri2LoaderExtension dri2_loader_extension
= {
115 { __DRI_DRI2_LOADER
, 3 },
117 dri_flush_front_buffer
,
118 dri_get_buffers_with_format
,
121 struct dri_extension_match
{
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
) },
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
) },
140 dri_bind_extensions(struct gbm_dri_device
*dri
,
141 struct dri_extension_match
*matches
,
142 const __DRIextension
**extensions
)
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
];
157 for (j
= 0; matches
[j
].name
; j
++) {
158 field
= ((char *) dri
+ matches
[j
].offset
);
159 if (*(const __DRIextension
**) field
== NULL
) {
168 dri_load_driver(struct gbm_dri_device
*dri
)
170 const __DRIextension
**extensions
;
171 char path
[PATH_MAX
], *search_paths
, *p
, *next
, *end
;
174 if (geteuid() == getuid()) {
175 /* don't allow setuid apps to use GBM_DRIVERS_PATH */
176 search_paths
= getenv("GBM_DRIVERS_PATH");
178 if (search_paths
== NULL
)
179 search_paths
= DEFAULT_DRIVER_DIR
;
182 end
= search_paths
+ strlen(search_paths
);
183 for (p
= search_paths
; p
< end
&& dri
->driver
== NULL
; p
= next
+ 1) {
185 next
= strchr(p
, ':');
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
);
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());
204 if (dri
->driver
== NULL
) {
205 fprintf(stderr
, "gbm: failed to open any driver (search paths %s)",
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
);
218 if (dri_bind_extensions(dri
, gbm_dri_device_extensions
, extensions
) < 0) {
219 dlclose(dri
->driver
);
220 fprintf(stderr
, "failed to bind extensions\n");
228 dri_screen_create(struct gbm_dri_device
*dri
)
230 const __DRIextension
**extensions
;
233 dri
->base
.driver_name
= dri_fd_get_driver_name(dri
->base
.base
.fd
);
234 if (dri
->base
.driver_name
== NULL
)
237 ret
= dri_load_driver(dri
);
239 fprintf(stderr
, "failed to load driver: %s\n", dri
->base
.driver_name
);
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
;
248 if (dri
->dri2
== NULL
)
251 dri
->screen
= dri
->dri2
->createNewScreen(0, dri
->base
.base
.fd
,
253 &dri
->driver_configs
, dri
);
254 if (dri
->screen
== NULL
)
257 extensions
= dri
->core
->getExtensions(dri
->screen
);
258 if (dri_bind_extensions(dri
, dri_core_extensions
, extensions
) < 0) {
263 dri
->lookup_image
= NULL
;
264 dri
->lookup_user_data
= NULL
;
269 dri
->core
->destroyScreen(dri
->screen
);
275 gbm_dri_is_format_supported(struct gbm_device
*gbm
,
280 case GBM_BO_FORMAT_XRGB8888
:
281 case GBM_FORMAT_XRGB8888
:
283 case GBM_BO_FORMAT_ARGB8888
:
284 case GBM_FORMAT_ARGB8888
:
285 if (usage
& GBM_BO_USE_SCANOUT
)
292 if (usage
& GBM_BO_USE_CURSOR_64X64
&&
293 usage
& GBM_BO_USE_RENDERING
)
300 gbm_dri_bo_write(struct gbm_bo
*_bo
, const void *buf
, size_t count
)
302 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
309 ret
= kms_bo_map(bo
->bo
, &ptr
);
313 memcpy(ptr
, buf
, count
);
315 kms_bo_unmap(bo
->bo
);
320 gbm_dri_bo_destroy(struct gbm_bo
*_bo
)
322 struct gbm_dri_device
*dri
= gbm_dri_device(_bo
->gbm
);
323 struct gbm_dri_bo
*bo
= gbm_dri_bo(_bo
);
325 if (bo
->image
!= NULL
)
326 dri
->image
->destroyImage(bo
->image
);
328 kms_bo_destroy(&bo
->bo
);
333 gbm_dri_to_gbm_format(uint32_t dri_format
)
337 switch (dri_format
) {
338 case __DRI_IMAGE_FORMAT_RGB565
:
339 ret
= GBM_FORMAT_RGB565
;
341 case __DRI_IMAGE_FORMAT_XRGB8888
:
342 ret
= GBM_FORMAT_XRGB8888
;
344 case __DRI_IMAGE_FORMAT_ARGB8888
:
345 ret
= GBM_FORMAT_ARGB8888
;
347 case __DRI_IMAGE_FORMAT_ABGR8888
:
348 ret
= GBM_FORMAT_ABGR8888
;
358 static struct gbm_bo
*
359 gbm_dri_bo_import(struct gbm_device
*gbm
,
360 uint32_t type
, void *buffer
, uint32_t usage
)
362 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
363 struct gbm_dri_bo
*bo
;
365 unsigned dri_use
= 0;
366 int dri_format
, width
, height
, gbm_format
, stride
, cpp
, offset
;
369 #if HAVE_WAYLAND_PLATFORM
370 case GBM_BO_IMPORT_WL_BUFFER
:
372 struct wl_drm_buffer
*wb
= (struct wl_drm_buffer
*) buffer
;
374 image
= wb
->driver_buffer
;
375 stride
= wb
->stride
[0];
376 offset
= wb
->offset
[0];
378 switch (wb
->format
) {
379 case WL_DRM_FORMAT_XRGB8888
:
380 dri_format
= __DRI_IMAGE_FORMAT_XRGB8888
;
381 gbm_format
= GBM_FORMAT_XRGB8888
;
383 case WL_DRM_FORMAT_ARGB8888
:
384 dri_format
= __DRI_IMAGE_FORMAT_ARGB8888
;
385 gbm_format
= GBM_FORMAT_ARGB8888
;
387 case WL_DRM_FORMAT_YUYV
:
388 dri_format
= __DRI_IMAGE_FORMAT_ARGB8888
;
389 gbm_format
= GBM_FORMAT_YUYV
;
398 case GBM_BO_IMPORT_EGL_IMAGE
:
400 if (dri
->lookup_image
== NULL
)
403 image
= dri
->lookup_image(dri
->screen
, buffer
, dri
->lookup_user_data
);
404 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_FORMAT
, &dri_format
);
405 gbm_format
= gbm_dri_to_gbm_format(dri_format
);
406 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_STRIDE
, &stride
);
417 bo
= calloc(1, sizeof *bo
);
421 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_WIDTH
, &width
);
422 dri
->image
->queryImage(image
, __DRI_IMAGE_ATTRIB_HEIGHT
, &height
);
424 bo
->image
= dri
->image
->createSubImage(image
,
425 width
, height
, dri_format
,
426 offset
, stride
/ cpp
, NULL
);
429 if (usage
& GBM_BO_USE_SCANOUT
)
430 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
431 if (usage
& GBM_BO_USE_CURSOR_64X64
)
432 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
433 if (dri
->image
->base
.version
>= 2 &&
434 !dri
->image
->validateUsage(bo
->image
, dri_use
)) {
439 bo
->base
.base
.gbm
= gbm
;
440 bo
->base
.base
.width
= width
;
441 bo
->base
.base
.height
= height
;
442 bo
->base
.base
.stride
= stride
;
443 bo
->base
.base
.format
= gbm_format
;
444 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
445 &bo
->base
.base
.handle
.s32
);
447 return &bo
->base
.base
;
450 static struct gbm_bo
*
451 gbm_dri_bo_create(struct gbm_device
*gbm
,
452 uint32_t width
, uint32_t height
,
453 uint32_t format
, uint32_t usage
)
455 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
456 struct gbm_dri_bo
*bo
;
458 unsigned dri_use
= 0;
460 bo
= calloc(1, sizeof *bo
);
464 bo
->base
.base
.gbm
= gbm
;
465 bo
->base
.base
.width
= width
;
466 bo
->base
.base
.height
= height
;
468 if (usage
& GBM_BO_USE_WRITE
) {
470 unsigned attrs
[7] = {
473 KMS_BO_TYPE
, KMS_BO_TYPE_SCANOUT_X8R8G8B8
,
474 KMS_TERMINATE_PROP_LIST
,
477 if (!(usage
& GBM_BO_USE_CURSOR_64X64
))
480 if (dri
->kms
== NULL
)
483 ret
= kms_bo_create(dri
->kms
, attrs
, &bo
->bo
);
489 kms_bo_get_prop(bo
->bo
, KMS_PITCH
, &bo
->base
.base
.stride
);
490 kms_bo_get_prop(bo
->bo
, KMS_HANDLE
, (unsigned*)&bo
->base
.base
.handle
);
492 return &bo
->base
.base
;
496 case GBM_FORMAT_RGB565
:
497 dri_format
=__DRI_IMAGE_FORMAT_RGB565
;
499 case GBM_FORMAT_XRGB8888
:
500 case GBM_BO_FORMAT_XRGB8888
:
501 dri_format
= __DRI_IMAGE_FORMAT_XRGB8888
;
503 case GBM_FORMAT_ARGB8888
:
504 case GBM_BO_FORMAT_ARGB8888
:
505 dri_format
= __DRI_IMAGE_FORMAT_ARGB8888
;
507 case GBM_FORMAT_ABGR8888
:
508 dri_format
= __DRI_IMAGE_FORMAT_ABGR8888
;
514 if (usage
& GBM_BO_USE_SCANOUT
)
515 dri_use
|= __DRI_IMAGE_USE_SCANOUT
;
516 if (usage
& GBM_BO_USE_CURSOR_64X64
)
517 dri_use
|= __DRI_IMAGE_USE_CURSOR
;
518 if (usage
& GBM_BO_USE_WRITE
)
519 dri_use
|= __DRI_IMAGE_USE_WRITE
;
521 /* Gallium drivers requires shared in order to get the handle/stride */
522 dri_use
|= __DRI_IMAGE_USE_SHARE
;
525 dri
->image
->createImage(dri
->screen
,
529 if (bo
->image
== NULL
)
532 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_HANDLE
,
533 &bo
->base
.base
.handle
.s32
);
534 dri
->image
->queryImage(bo
->image
, __DRI_IMAGE_ATTRIB_STRIDE
,
535 (int *) &bo
->base
.base
.stride
);
537 return &bo
->base
.base
;
540 static struct gbm_surface
*
541 gbm_dri_surface_create(struct gbm_device
*gbm
,
542 uint32_t width
, uint32_t height
,
543 uint32_t format
, uint32_t flags
)
545 struct gbm_dri_surface
*surf
;
547 surf
= calloc(1, sizeof *surf
);
551 surf
->base
.gbm
= gbm
;
552 surf
->base
.width
= width
;
553 surf
->base
.height
= height
;
554 surf
->base
.format
= format
;
555 surf
->base
.flags
= flags
;
561 gbm_dri_surface_destroy(struct gbm_surface
*_surf
)
563 struct gbm_dri_surface
*surf
= gbm_dri_surface(_surf
);
569 dri_destroy(struct gbm_device
*gbm
)
571 struct gbm_dri_device
*dri
= gbm_dri_device(gbm
);
573 dri
->core
->destroyScreen(dri
->screen
);
574 free(dri
->driver_configs
);
575 dlclose(dri
->driver
);
576 free(dri
->base
.driver_name
);
581 static struct gbm_device
*
582 dri_device_create(int fd
)
584 struct gbm_dri_device
*dri
;
587 dri
= calloc(1, sizeof *dri
);
589 dri
->base
.base
.fd
= fd
;
590 dri
->base
.base
.bo_create
= gbm_dri_bo_create
;
591 dri
->base
.base
.bo_import
= gbm_dri_bo_import
;
592 dri
->base
.base
.is_format_supported
= gbm_dri_is_format_supported
;
593 dri
->base
.base
.bo_write
= gbm_dri_bo_write
;
594 dri
->base
.base
.bo_destroy
= gbm_dri_bo_destroy
;
595 dri
->base
.base
.destroy
= dri_destroy
;
596 dri
->base
.base
.surface_create
= gbm_dri_surface_create
;
597 dri
->base
.base
.surface_destroy
= gbm_dri_surface_destroy
;
599 dri
->base
.type
= GBM_DRM_DRIVER_TYPE_DRI
;
600 dri
->base
.base
.name
= "drm";
602 kms_create(fd
, &dri
->kms
);
603 if (dri
->kms
== NULL
)
606 ret
= dri_screen_create(dri
);
610 return &dri
->base
.base
;
613 kms_destroy(&dri
->kms
);
619 struct gbm_backend gbm_dri_backend
= {
620 .backend_name
= "dri",
621 .create_device
= dri_device_create
,