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;
368 /* Required for query image WIDTH & HEIGHT */
369 if (dri->image->base.version < 4)
373 #if HAVE_WAYLAND_PLATFORM
374 case GBM_BO_IMPORT_WL_BUFFER:
376 struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
378 image = wb->driver_buffer;
379 stride = wb->stride[0];
380 offset = wb->offset[0];
382 switch (wb->format) {
383 case WL_DRM_FORMAT_XRGB8888:
384 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
385 gbm_format = GBM_FORMAT_XRGB8888;
387 case WL_DRM_FORMAT_ARGB8888:
388 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
389 gbm_format = GBM_FORMAT_ARGB8888;
391 case WL_DRM_FORMAT_YUYV:
392 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
393 gbm_format = GBM_FORMAT_YUYV;
402 case GBM_BO_IMPORT_EGL_IMAGE:
404 if (dri->lookup_image == NULL)
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);
421 bo = calloc(1, sizeof *bo);
425 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
426 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
428 bo->image = dri->image->createSubImage(image,
429 width, height, dri_format,
430 offset, stride / cpp, NULL);
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)) {
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);
451 return &bo->base.base;
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)
459 struct gbm_dri_device *dri = gbm_dri_device(gbm);
460 struct gbm_dri_bo *bo;
462 unsigned dri_use = 0;
464 bo = calloc(1, sizeof *bo);
468 bo->base.base.gbm = gbm;
469 bo->base.base.width = width;
470 bo->base.base.height = height;
472 if (usage & GBM_BO_USE_WRITE) {
474 unsigned attrs[7] = {
477 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
478 KMS_TERMINATE_PROP_LIST,
481 if (!(usage & GBM_BO_USE_CURSOR_64X64))
484 if (dri->kms == NULL)
487 ret = kms_bo_create(dri->kms, attrs, &bo->bo);
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);
496 return &bo->base.base;
500 case GBM_FORMAT_RGB565:
501 dri_format =__DRI_IMAGE_FORMAT_RGB565;
503 case GBM_FORMAT_XRGB8888:
504 case GBM_BO_FORMAT_XRGB8888:
505 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
507 case GBM_FORMAT_ARGB8888:
508 case GBM_BO_FORMAT_ARGB8888:
509 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
511 case GBM_FORMAT_ABGR8888:
512 dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
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;
523 /* Gallium drivers requires shared in order to get the handle/stride */
524 dri_use |= __DRI_IMAGE_USE_SHARE;
527 dri->image->createImage(dri->screen,
531 if (bo->image == NULL)
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);
539 return &bo->base.base;
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)
547 struct gbm_dri_surface *surf;
549 surf = calloc(1, sizeof *surf);
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;
563 gbm_dri_surface_destroy(struct gbm_surface *_surf)
565 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
571 dri_destroy(struct gbm_device *gbm)
573 struct gbm_dri_device *dri = gbm_dri_device(gbm);
575 dri->core->destroyScreen(dri->screen);
576 free(dri->driver_configs);
577 dlclose(dri->driver);
578 free(dri->base.driver_name);
583 static struct gbm_device *
584 dri_device_create(int fd)
586 struct gbm_dri_device *dri;
589 dri = calloc(1, sizeof *dri);
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;
601 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
602 dri->base.base.name = "drm";
604 kms_create(fd, &dri->kms);
605 if (dri->kms == NULL)
608 ret = dri_screen_create(dri);
612 return &dri->base.base;
615 kms_destroy(&dri->kms);
621 struct gbm_backend gbm_dri_backend = {
622 .backend_name = "dri",
623 .create_device = dri_device_create,