gbm: Add gbm_bo_write 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 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 int
295 gbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
296 {
297 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
298 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
299
300 if (dri->image->base.version < 4)
301 return -1;
302
303 return dri->image->write(bo->image, buf, count);
304 }
305
306 static void
307 gbm_dri_bo_destroy(struct gbm_bo *_bo)
308 {
309 struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
310 struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
311
312 dri->image->destroyImage(bo->image);
313 free(bo);
314 }
315
316 static uint32_t
317 gbm_dri_to_gbm_format(uint32_t dri_format)
318 {
319 uint32_t ret = 0;
320
321 switch (dri_format) {
322 case __DRI_IMAGE_FORMAT_RGB565:
323 ret = GBM_FORMAT_RGB565;
324 break;
325 case __DRI_IMAGE_FORMAT_XRGB8888:
326 ret = GBM_FORMAT_XRGB8888;
327 break;
328 case __DRI_IMAGE_FORMAT_ARGB8888:
329 ret = GBM_FORMAT_ARGB8888;
330 break;
331 case __DRI_IMAGE_FORMAT_ABGR8888:
332 ret = GBM_FORMAT_ABGR8888;
333 break;
334 default:
335 ret = 0;
336 break;
337 }
338
339 return ret;
340 }
341
342 static struct gbm_bo *
343 gbm_dri_bo_create_from_egl_image(struct gbm_device *gbm,
344 void *egl_dpy, void *egl_img,
345 uint32_t width, uint32_t height,
346 uint32_t usage)
347 {
348 struct gbm_dri_device *dri = gbm_dri_device(gbm);
349 struct gbm_dri_bo *bo;
350 int dri_format;
351 unsigned dri_use = 0;
352
353 (void) egl_dpy;
354
355 if (dri->lookup_image == NULL)
356 return NULL;
357
358 bo = calloc(1, sizeof *bo);
359 if (bo == NULL)
360 return NULL;
361
362 bo->base.base.gbm = gbm;
363 bo->base.base.width = width;
364 bo->base.base.height = height;
365
366 __DRIimage *tmp = dri->lookup_image(dri->screen, egl_img,
367 dri->lookup_user_data);
368
369 bo->image = dri->image->dupImage(tmp, bo);
370 if (bo->image == NULL)
371 return NULL;
372
373 if (usage & GBM_BO_USE_SCANOUT)
374 dri_use |= __DRI_IMAGE_USE_SCANOUT;
375 if (usage & GBM_BO_USE_CURSOR_64X64)
376 dri_use |= __DRI_IMAGE_USE_CURSOR;
377 if (dri->image->base.version >= 2 &&
378 !dri->image->validateUsage(bo->image, dri_use)) {
379 free(bo);
380 return NULL;
381 }
382
383 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
384 &bo->base.base.handle.s32);
385 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
386 (int *) &bo->base.base.pitch);
387 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FORMAT,
388 &dri_format);
389
390 bo->base.base.format = gbm_dri_to_gbm_format(dri_format);
391
392 return &bo->base.base;
393 }
394
395 static struct gbm_bo *
396 gbm_dri_bo_create(struct gbm_device *gbm,
397 uint32_t width, uint32_t height,
398 uint32_t format, uint32_t usage)
399 {
400 struct gbm_dri_device *dri = gbm_dri_device(gbm);
401 struct gbm_dri_bo *bo;
402 int dri_format;
403 unsigned dri_use = 0;
404
405 if (dri->image->base.version < 4 && (usage & GBM_BO_USE_WRITE))
406 return NULL;
407
408 bo = calloc(1, sizeof *bo);
409 if (bo == NULL)
410 return NULL;
411
412 bo->base.base.gbm = gbm;
413 bo->base.base.width = width;
414 bo->base.base.height = height;
415
416 switch (format) {
417 case GBM_FORMAT_RGB565:
418 dri_format =__DRI_IMAGE_FORMAT_RGB565;
419 break;
420 case GBM_FORMAT_XRGB8888:
421 case GBM_BO_FORMAT_XRGB8888:
422 dri_format = __DRI_IMAGE_FORMAT_XRGB8888;
423 break;
424 case GBM_FORMAT_ARGB8888:
425 case GBM_BO_FORMAT_ARGB8888:
426 dri_format = __DRI_IMAGE_FORMAT_ARGB8888;
427 break;
428 case GBM_FORMAT_ABGR8888:
429 dri_format = __DRI_IMAGE_FORMAT_ABGR8888;
430 break;
431 default:
432 return NULL;
433 }
434
435 if (usage & GBM_BO_USE_SCANOUT)
436 dri_use |= __DRI_IMAGE_USE_SCANOUT;
437 if (usage & GBM_BO_USE_CURSOR_64X64)
438 dri_use |= __DRI_IMAGE_USE_CURSOR;
439 if (usage & GBM_BO_USE_WRITE)
440 dri_use |= __DRI_IMAGE_USE_WRITE;
441
442 bo->image =
443 dri->image->createImage(dri->screen,
444 width, height,
445 dri_format, dri_use,
446 bo);
447 if (bo->image == NULL)
448 return NULL;
449
450 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE,
451 &bo->base.base.handle.s32);
452 dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE,
453 (int *) &bo->base.base.pitch);
454
455 return &bo->base.base;
456 }
457
458 static struct gbm_surface *
459 gbm_dri_surface_create(struct gbm_device *gbm,
460 uint32_t width, uint32_t height,
461 uint32_t format, uint32_t flags)
462 {
463 struct gbm_dri_surface *surf;
464
465 surf = calloc(1, sizeof *surf);
466 if (surf == NULL)
467 return NULL;
468
469 surf->base.gbm = gbm;
470 surf->base.width = width;
471 surf->base.height = height;
472 surf->base.format = format;
473 surf->base.flags = flags;
474
475 return &surf->base;
476 }
477
478 static void
479 gbm_dri_surface_destroy(struct gbm_surface *_surf)
480 {
481 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
482
483 free(surf);
484 }
485
486 static void
487 dri_destroy(struct gbm_device *gbm)
488 {
489 struct gbm_dri_device *dri = gbm_dri_device(gbm);
490
491 dri->core->destroyScreen(dri->screen);
492 free(dri->driver_configs);
493 dlclose(dri->driver);
494 free(dri->base.driver_name);
495
496 free(dri);
497 }
498
499 static struct gbm_device *
500 dri_device_create(int fd)
501 {
502 struct gbm_dri_device *dri;
503 int ret;
504
505 dri = calloc(1, sizeof *dri);
506
507 dri->base.base.fd = fd;
508 dri->base.base.bo_create = gbm_dri_bo_create;
509 dri->base.base.bo_create_from_egl_image = gbm_dri_bo_create_from_egl_image;
510 dri->base.base.is_format_supported = gbm_dri_is_format_supported;
511 dri->base.base.bo_write = gbm_dri_bo_write;
512 dri->base.base.bo_destroy = gbm_dri_bo_destroy;
513 dri->base.base.destroy = dri_destroy;
514 dri->base.base.surface_create = gbm_dri_surface_create;
515 dri->base.base.surface_destroy = gbm_dri_surface_destroy;
516
517 dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
518 dri->base.base.name = "drm";
519
520 ret = dri_screen_create(dri);
521 if (ret) {
522 free(dri);
523 return NULL;
524 }
525
526 return &dri->base.base;
527 }
528
529 struct gbm_backend gbm_dri_backend = {
530 .backend_name = "dri",
531 .create_device = dri_device_create,
532 };