gbm: Create hooks for dri2_loader_extension in dri backend
[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 static __DRIimage *
47 dri_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
48 {
49 struct gbm_dri_device *dri = data;
50
51 if (dri->lookup_image == NULL)
52 return NULL;
53
54 return dri->lookup_image(screen, image, dri->lookup_user_data);
55 }
56
57 static __DRIbuffer *
58 dri_get_buffers(__DRIdrawable * driDrawable,
59 int *width, int *height,
60 unsigned int *attachments, int count,
61 int *out_count, void *data)
62 {
63 struct gbm_dri_surface *surf = data;
64 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
65
66 if (dri->get_buffers == NULL)
67 return NULL;
68
69 return dri->get_buffers(driDrawable, width, height, attachments,
70 count, out_count, surf->dri_private);
71 }
72
73 static void
74 dri_flush_front_buffer(__DRIdrawable * driDrawable, void *data)
75 {
76 struct gbm_dri_surface *surf = data;
77 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
78
79 if (dri->flush_front_buffer != NULL)
80 dri->flush_front_buffer(driDrawable, surf->dri_private);
81 }
82
83 static __DRIbuffer *
84 dri_get_buffers_with_format(__DRIdrawable * driDrawable,
85 int *width, int *height,
86 unsigned int *attachments, int count,
87 int *out_count, void *data)
88 {
89 struct gbm_dri_surface *surf = data;
90 struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm);
91
92 if (dri->get_buffers_with_format == NULL)
93 return NULL;
94
95 return
96 dri->get_buffers_with_format(driDrawable, width, height, attachments,
97 count, out_count, surf->dri_private);
98 }
99
100 static const __DRIuseInvalidateExtension use_invalidate = {
101 { __DRI_USE_INVALIDATE, 1 }
102 };
103
104 static const __DRIimageLookupExtension image_lookup_extension = {
105 { __DRI_IMAGE_LOOKUP, 1 },
106 dri_lookup_egl_image
107 };
108
109 const __DRIdri2LoaderExtension dri2_loader_extension = {
110 { __DRI_DRI2_LOADER, 3 },
111 dri_get_buffers,
112 dri_flush_front_buffer,
113 dri_get_buffers_with_format,
114 };
115
116 struct dri_extension_match {
117 const char *name;
118 int version;
119 int offset;
120 };
121
122 static struct dri_extension_match dri_core_extensions[] = {
123 { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush) },
124 { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image) },
125 { NULL, 0, 0 }
126 };
127
128 static struct dri_extension_match gbm_dri_device_extensions[] = {
129 { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core) },
130 { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2) },
131 { NULL, 0, 0 }
132 };
133
134 static int
135 dri_bind_extensions(struct gbm_dri_device *dri,
136 struct dri_extension_match *matches,
137 const __DRIextension **extensions)
138 {
139 int i, j, ret = 0;
140 void *field;
141
142 for (i = 0; extensions[i]; i++) {
143 for (j = 0; matches[j].name; j++) {
144 if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
145 extensions[i]->version >= matches[j].version) {
146 field = ((char *) dri + matches[j].offset);
147 *(const __DRIextension **) field = extensions[i];
148 }
149 }
150 }
151
152 for (j = 0; matches[j].name; j++) {
153 field = ((char *) dri + matches[j].offset);
154 if (*(const __DRIextension **) field == NULL) {
155 ret = -1;
156 }
157 }
158
159 return ret;
160 }
161
162 static int
163 dri_load_driver(struct gbm_dri_device *dri)
164 {
165 const __DRIextension **extensions;
166 char path[PATH_MAX], *search_paths, *p, *next, *end;
167
168 search_paths = NULL;
169 if (geteuid() == getuid()) {
170 /* don't allow setuid apps to use GBM_DRIVERS_PATH */
171 search_paths = getenv("GBM_DRIVERS_PATH");
172 }
173 if (search_paths == NULL)
174 search_paths = DEFAULT_DRIVER_DIR;
175
176 dri->driver = NULL;
177 end = search_paths + strlen(search_paths);
178 for (p = search_paths; p < end && dri->driver == NULL; p = next + 1) {
179 int len;
180 next = strchr(p, ':');
181 if (next == NULL)
182 next = end;
183
184 len = next - p;
185 #if GLX_USE_TLS
186 snprintf(path, sizeof path,
187 "%.*s/tls/%s_dri.so", len, p, dri->base.driver_name);
188 dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
189 #endif
190 if (dri->driver == NULL) {
191 snprintf(path, sizeof path,
192 "%.*s/%s_dri.so", len, p, dri->base.driver_name);
193 dri->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
194 if (dri->driver == NULL)
195 fprintf(stderr, "failed to open %s: %s\n", path, dlerror());
196 }
197 }
198
199 if (dri->driver == NULL) {
200 fprintf(stderr, "gbm: failed to open any driver (search paths %s)",
201 search_paths);
202 return -1;
203 }
204
205 extensions = dlsym(dri->driver, __DRI_DRIVER_EXTENSIONS);
206 if (extensions == NULL) {
207 fprintf(stderr, "gbm: driver exports no extensions (%s)", dlerror());
208 dlclose(dri->driver);
209 return -1;
210 }
211
212
213 if (dri_bind_extensions(dri, gbm_dri_device_extensions, extensions) < 0) {
214 dlclose(dri->driver);
215 fprintf(stderr, "failed to bind extensions\n");
216 return -1;
217 }
218
219 return 0;
220 }
221
222 static int
223 dri_screen_create(struct gbm_dri_device *dri)
224 {
225 const __DRIextension **extensions;
226 int ret = 0;
227
228 dri->base.driver_name = dri_fd_get_driver_name(dri->base.base.fd);
229 if (dri->base.driver_name == NULL)
230 return -1;
231
232 ret = dri_load_driver(dri);
233 if (ret) {
234 fprintf(stderr, "failed to load driver: %s\n", dri->base.driver_name);
235 return ret;
236 };
237
238 dri->extensions[0] = &image_lookup_extension.base;
239 dri->extensions[1] = &use_invalidate.base;
240 dri->extensions[2] = &dri2_loader_extension.base;
241 dri->extensions[3] = NULL;
242
243 if (dri->dri2 == NULL)
244 return -1;
245
246 dri->screen = dri->dri2->createNewScreen(0, dri->base.base.fd,
247 dri->extensions,
248 &dri->driver_configs, dri);
249 if (dri->screen == NULL)
250 return -1;
251
252 extensions = dri->core->getExtensions(dri->screen);
253 if (dri_bind_extensions(dri, dri_core_extensions, extensions) < 0) {
254 ret = -1;
255 goto free_screen;
256 }
257
258 dri->lookup_image = NULL;
259 dri->lookup_user_data = NULL;
260
261 return 0;
262
263 free_screen:
264 dri->core->destroyScreen(dri->screen);
265
266 return ret;
267 }
268
269 static int
270 gbm_dri_is_format_supported(struct gbm_device *gbm,
271 uint32_t format,
272 uint32_t usage)
273 {
274 switch (format) {
275 case GBM_BO_FORMAT_XRGB8888:
276 case GBM_FORMAT_XRGB8888:
277 break;
278 case GBM_BO_FORMAT_ARGB8888:
279 case GBM_FORMAT_ARGB8888:
280 if (usage & GBM_BO_USE_SCANOUT)
281 return 0;
282 break;
283 default:
284 return 0;
285 }
286
287 if (usage & GBM_BO_USE_CURSOR_64X64 &&
288 usage & GBM_BO_USE_RENDERING)
289 return 0;
290
291 return 1;
292 }
293
294 static void
295 gbm_dri_bo_destroy(struct gbm_bo *_bo)
296 {
297 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
298 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
299
300 dri->image->destroyImage(bo->image);
301 free(bo);
302 }
303
304 static uint32_t
305 gbm_dri_to_gbm_format(uint32_t dri_format)
306 {
307 uint32_t ret = 0;
308
309 switch (dri_format) {
310 case __DRI_IMAGE_FORMAT_RGB565:
311 ret = GBM_FORMAT_RGB565;
312 break;
313 case __DRI_IMAGE_FORMAT_XRGB8888:
314 ret = GBM_FORMAT_XRGB8888;
315 break;
316 case __DRI_IMAGE_FORMAT_ARGB8888:
317 ret = GBM_FORMAT_ARGB8888;
318 break;
319 case __DRI_IMAGE_FORMAT_ABGR8888:
320 ret = GBM_FORMAT_ABGR8888;
321 break;
322 default:
323 ret = 0;
324 break;
325 }
326
327 return ret;
328 }
329
330 static struct gbm_bo *
331 gbm_dri_bo_create_from_egl_image(struct gbm_device *gbm,
332 void *egl_dpy, void *egl_img,
333 uint32_t width, uint32_t height,
334 uint32_t usage)
335 {
336 struct gbm_dri_device *dri = gbm_dri_device(gbm);
337 struct gbm_dri_bo *bo;
338 int dri_format;
339 unsigned dri_use = 0;
340
341 (void) egl_dpy;
342
343 if (dri->lookup_image == NULL)
344 return NULL;
345
346 bo = calloc(1, sizeof *bo);
347 if (bo == NULL)
348 return NULL;
349
350 bo->base.base.gbm = gbm;
351 bo->base.base.width = width;
352 bo->base.base.height = height;
353
354 __DRIimage *tmp = dri->lookup_image(dri->screen, egl_img,
355 dri->lookup_user_data);
356
357 bo->image = dri->image->dupImage(tmp, bo);
358 if (bo->image == NULL)
359 return NULL;
360
361 if (usage & GBM_BO_USE_SCANOUT)
362 dri_use |= __DRI_IMAGE_USE_SCANOUT;
363 if (usage & GBM_BO_USE_CURSOR_64X64)
364 dri_use |= __DRI_IMAGE_USE_CURSOR;
365 if (dri->image->base.version >= 2 &&
366 !dri->image->validateUsage(bo->image, dri_use)) {
367 free(bo);
368 return NULL;
369 }
370
371 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
372 &bo->base.base.handle.s32);
373 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
374 (int *) &bo->base.base.pitch);
375 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FORMAT,
376 &dri_format);
377
378 bo->base.base.format = gbm_dri_to_gbm_format(dri_format);
379
380 return &bo->base.base;
381 }
382
383 static struct gbm_bo *
384 gbm_dri_bo_create(struct gbm_device *gbm,
385 uint32_t width, uint32_t height,
386 uint32_t format, uint32_t usage)
387 {
388 struct gbm_dri_device *dri = gbm_dri_device(gbm);
389 struct gbm_dri_bo *bo;
390 int dri_format;
391 unsigned dri_use = 0;
392
393 bo = calloc(1, sizeof *bo);
394 if (bo == NULL)
395 return NULL;
396
397 bo->base.base.gbm = gbm;
398 bo->base.base.width = width;
399 bo->base.base.height = height;
400
401 switch (format) {
402 case GBM_FORMAT_RGB565:
403 dri_format =__DRI_IMAGE_FORMAT_RGB565;
404 break;
405 case GBM_FORMAT_XRGB8888:
406 case GBM_BO_FORMAT_XRGB8888:
407 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
408 break;
409 case GBM_FORMAT_ARGB8888:
410 case GBM_BO_FORMAT_ARGB8888:
411 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
412 break;
413 case GBM_FORMAT_ABGR8888:
414 dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
415 break;
416 default:
417 return NULL;
418 }
419
420 if (usage & GBM_BO_USE_SCANOUT)
421 dri_use |= __DRI_IMAGE_USE_SCANOUT;
422 if (usage & GBM_BO_USE_CURSOR_64X64)
423 dri_use |= __DRI_IMAGE_USE_CURSOR;
424
425 bo->image =
426 dri->image->createImage(dri->screen,
427 width, height,
428 dri_format, dri_use,
429 bo);
430 if (bo->image == NULL)
431 return NULL;
432
433 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
434 &bo->base.base.handle.s32);
435 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
436 (int *) &bo->base.base.pitch);
437
438 return &bo->base.base;
439 }
440
441 static struct gbm_surface *
442 gbm_dri_surface_create(struct gbm_device *gbm,
443 uint32_t width, uint32_t height,
444 uint32_t format, uint32_t flags)
445 {
446 struct gbm_dri_surface *surf;
447
448 surf = calloc(1, sizeof *surf);
449 if (surf == NULL)
450 return NULL;
451
452 surf->base.gbm = gbm;
453 surf->base.width = width;
454 surf->base.height = height;
455 surf->base.format = format;
456 surf->base.flags = flags;
457
458 return &surf->base;
459 }
460
461 static void
462 gbm_dri_surface_destroy(struct gbm_surface *_surf)
463 {
464 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
465
466 free(surf);
467 }
468
469 static void
470 dri_destroy(struct gbm_device *gbm)
471 {
472 struct gbm_dri_device *dri = gbm_dri_device(gbm);
473
474 dri->core->destroyScreen(dri->screen);
475 free(dri->driver_configs);
476 dlclose(dri->driver);
477 free(dri->base.driver_name);
478
479 free(dri);
480 }
481
482 static struct gbm_device *
483 dri_device_create(int fd)
484 {
485 struct gbm_dri_device *dri;
486 int ret;
487
488 dri = calloc(1, sizeof *dri);
489
490 dri->base.base.fd = fd;
491 dri->base.base.bo_create = gbm_dri_bo_create;
492 dri->base.base.bo_create_from_egl_image = gbm_dri_bo_create_from_egl_image;
493 dri->base.base.is_format_supported = gbm_dri_is_format_supported;
494 dri->base.base.bo_destroy = gbm_dri_bo_destroy;
495 dri->base.base.destroy = dri_destroy;
496 dri->base.base.surface_create = gbm_dri_surface_create;
497 dri->base.base.surface_destroy = gbm_dri_surface_destroy;
498
499 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
500 dri->base.base.name = "drm";
501
502 ret = dri_screen_create(dri);
503 if (ret) {
504 free(dri);
505 return NULL;
506 }
507
508 return &dri->base.base;
509 }
510
511 struct gbm_backend gbm_dri_backend = {
512 .backend_name = "dri",
513 .create_device = dri_device_create,
514 };