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