gbm: Add new gbm_bo_import entry point
[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_device *dri = gbm_dri_device(_bo->gbm);
303 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
304
305 if (dri->image->base.version < 4)
306 return -1;
307
308 return dri->image->write(bo->image, buf, count);
309 }
310
311 static void
312 gbm_dri_bo_destroy(struct gbm_bo *_bo)
313 {
314 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
315 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
316
317 dri->image->destroyImage(bo->image);
318 free(bo);
319 }
320
321 static uint32_t
322 gbm_dri_to_gbm_format(uint32_t dri_format)
323 {
324 uint32_t ret = 0;
325
326 switch (dri_format) {
327 case __DRI_IMAGE_FORMAT_RGB565:
328 ret = GBM_FORMAT_RGB565;
329 break;
330 case __DRI_IMAGE_FORMAT_XRGB8888:
331 ret = GBM_FORMAT_XRGB8888;
332 break;
333 case __DRI_IMAGE_FORMAT_ARGB8888:
334 ret = GBM_FORMAT_ARGB8888;
335 break;
336 case __DRI_IMAGE_FORMAT_ABGR8888:
337 ret = GBM_FORMAT_ABGR8888;
338 break;
339 default:
340 ret = 0;
341 break;
342 }
343
344 return ret;
345 }
346
347 static struct gbm_bo *
348 gbm_dri_bo_import(struct gbm_device *gbm,
349 uint32_t type, void *buffer, uint32_t usage)
350 {
351 struct gbm_dri_device *dri = gbm_dri_device(gbm);
352 struct gbm_dri_bo *bo;
353 __DRIimage *image;
354 unsigned dri_use = 0;
355 int dri_format, width, height, gbm_format, stride, cpp, offset;
356
357 switch (type) {
358 #if HAVE_WAYLAND_PLATFORM
359 case GBM_BO_IMPORT_WL_BUFFER:
360 {
361 struct wl_drm_buffer *wb = (struct wl_drm_buffer *) buffer;
362
363 image = wb->driver_buffer;
364 stride = wb->stride[0];
365 offset = wb->offset[0];
366 cpp = 4;
367 switch (wb->format) {
368 case WL_DRM_FORMAT_XRGB8888:
369 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
370 gbm_format = GBM_FORMAT_XRGB8888;
371 break;
372 case WL_DRM_FORMAT_ARGB8888:
373 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
374 gbm_format = GBM_FORMAT_ARGB8888;
375 break;
376 case WL_DRM_FORMAT_YUYV:
377 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
378 gbm_format = GBM_FORMAT_YUYV;
379 break;
380 default:
381 return NULL;
382 }
383 break;
384 }
385 #endif
386
387 case GBM_BO_IMPORT_EGL_IMAGE:
388 {
389 if (dri->lookup_image == NULL)
390 return NULL;
391
392 image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data);
393 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format);
394 gbm_format = gbm_dri_to_gbm_format(dri_format);
395 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
396 offset = 0;
397 cpp = 4;
398 break;
399 }
400
401 default:
402 return NULL;
403 }
404
405
406 bo = calloc(1, sizeof *bo);
407 if (bo == NULL)
408 return NULL;
409
410 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
411 dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
412
413 bo->image = dri->image->createSubImage(image,
414 width, height, dri_format,
415 offset, stride / cpp, NULL);
416
417
418 if (usage & GBM_BO_USE_SCANOUT)
419 dri_use |= __DRI_IMAGE_USE_SCANOUT;
420 if (usage & GBM_BO_USE_CURSOR_64X64)
421 dri_use |= __DRI_IMAGE_USE_CURSOR;
422 if (dri->image->base.version >= 2 &&
423 !dri->image->validateUsage(bo->image, dri_use)) {
424 free(bo);
425 return NULL;
426 }
427
428 bo->base.base.gbm = gbm;
429 bo->base.base.width = width;
430 bo->base.base.height = height;
431 bo->base.base.pitch = stride;
432 bo->base.base.format = gbm_format;
433 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
434 &bo->base.base.handle.s32);
435
436 return &bo->base.base;
437 }
438
439 static struct gbm_bo *
440 gbm_dri_bo_create(struct gbm_device *gbm,
441 uint32_t width, uint32_t height,
442 uint32_t format, uint32_t usage)
443 {
444 struct gbm_dri_device *dri = gbm_dri_device(gbm);
445 struct gbm_dri_bo *bo;
446 int dri_format;
447 unsigned dri_use = 0;
448
449 if (dri->image->base.version < 4 && (usage & GBM_BO_USE_WRITE))
450 return NULL;
451
452 bo = calloc(1, sizeof *bo);
453 if (bo == NULL)
454 return NULL;
455
456 bo->base.base.gbm = gbm;
457 bo->base.base.width = width;
458 bo->base.base.height = height;
459
460 switch (format) {
461 case GBM_FORMAT_RGB565:
462 dri_format =__DRI_IMAGE_FORMAT_RGB565;
463 break;
464 case GBM_FORMAT_XRGB8888:
465 case GBM_BO_FORMAT_XRGB8888:
466 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
467 break;
468 case GBM_FORMAT_ARGB8888:
469 case GBM_BO_FORMAT_ARGB8888:
470 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
471 break;
472 case GBM_FORMAT_ABGR8888:
473 dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
474 break;
475 default:
476 return NULL;
477 }
478
479 if (usage & GBM_BO_USE_SCANOUT)
480 dri_use |= __DRI_IMAGE_USE_SCANOUT;
481 if (usage & GBM_BO_USE_CURSOR_64X64)
482 dri_use |= __DRI_IMAGE_USE_CURSOR;
483 if (usage & GBM_BO_USE_WRITE)
484 dri_use |= __DRI_IMAGE_USE_WRITE;
485
486 bo->image =
487 dri->image->createImage(dri->screen,
488 width, height,
489 dri_format, dri_use,
490 bo);
491 if (bo->image == NULL)
492 return NULL;
493
494 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
495 &bo->base.base.handle.s32);
496 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
497 (int *) &bo->base.base.pitch);
498
499 return &bo->base.base;
500 }
501
502 static struct gbm_surface *
503 gbm_dri_surface_create(struct gbm_device *gbm,
504 uint32_t width, uint32_t height,
505 uint32_t format, uint32_t flags)
506 {
507 struct gbm_dri_surface *surf;
508
509 surf = calloc(1, sizeof *surf);
510 if (surf == NULL)
511 return NULL;
512
513 surf->base.gbm = gbm;
514 surf->base.width = width;
515 surf->base.height = height;
516 surf->base.format = format;
517 surf->base.flags = flags;
518
519 return &surf->base;
520 }
521
522 static void
523 gbm_dri_surface_destroy(struct gbm_surface *_surf)
524 {
525 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
526
527 free(surf);
528 }
529
530 static void
531 dri_destroy(struct gbm_device *gbm)
532 {
533 struct gbm_dri_device *dri = gbm_dri_device(gbm);
534
535 dri->core->destroyScreen(dri->screen);
536 free(dri->driver_configs);
537 dlclose(dri->driver);
538 free(dri->base.driver_name);
539
540 free(dri);
541 }
542
543 static struct gbm_device *
544 dri_device_create(int fd)
545 {
546 struct gbm_dri_device *dri;
547 int ret;
548
549 dri = calloc(1, sizeof *dri);
550
551 dri->base.base.fd = fd;
552 dri->base.base.bo_create = gbm_dri_bo_create;
553 dri->base.base.bo_import = gbm_dri_bo_import;
554 dri->base.base.is_format_supported = gbm_dri_is_format_supported;
555 dri->base.base.bo_write = gbm_dri_bo_write;
556 dri->base.base.bo_destroy = gbm_dri_bo_destroy;
557 dri->base.base.destroy = dri_destroy;
558 dri->base.base.surface_create = gbm_dri_surface_create;
559 dri->base.base.surface_destroy = gbm_dri_surface_destroy;
560
561 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
562 dri->base.base.name = "drm";
563
564 ret = dri_screen_create(dri);
565 if (ret) {
566 free(dri);
567 return NULL;
568 }
569
570 return &dri->base.base;
571 }
572
573 struct gbm_backend gbm_dri_backend = {
574 .backend_name = "dri",
575 .create_device = dri_device_create,
576 };