egl/gbm: Emit EGL_BAD_PARAMETER for eglCreatePlatformPixmapSurface
[mesa.git] / src / egl / drivers / dri2 / platform_drm.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 * Kristian Høgsberg <krh@bitplanet.net>
26 */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <xf86drm.h>
32 #include <dlfcn.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37
38 #include "egl_dri2.h"
39 #include "egl_dri2_fallbacks.h"
40 #include "loader.h"
41
42 static struct gbm_bo *
43 lock_front_buffer(struct gbm_surface *_surf)
44 {
45 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
46 struct dri2_egl_surface *dri2_surf = surf->dri_private;
47 struct gbm_bo *bo;
48
49 if (dri2_surf->current == NULL) {
50 _eglError(EGL_BAD_SURFACE, "no front buffer");
51 return NULL;
52 }
53
54 bo = dri2_surf->current->bo;
55 dri2_surf->current->locked = 1;
56 dri2_surf->current = NULL;
57
58 return bo;
59 }
60
61 static void
62 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
63 {
64 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
65 struct dri2_egl_surface *dri2_surf = surf->dri_private;
66 int i;
67
68 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
69 if (dri2_surf->color_buffers[i].bo == bo) {
70 dri2_surf->color_buffers[i].locked = 0;
71 }
72 }
73 }
74
75 static int
76 has_free_buffers(struct gbm_surface *_surf)
77 {
78 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
79 struct dri2_egl_surface *dri2_surf = surf->dri_private;
80 int i;
81
82 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
83 if (!dri2_surf->color_buffers[i].locked)
84 return 1;
85
86 return 0;
87 }
88
89 static _EGLSurface *
90 dri2_drm_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
91 _EGLConfig *conf, void *native_window,
92 const EGLint *attrib_list)
93 {
94 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
95 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
96 struct dri2_egl_surface *dri2_surf;
97 struct gbm_surface *window = native_window;
98 struct gbm_dri_surface *surf;
99
100 (void) drv;
101
102 dri2_surf = calloc(1, sizeof *dri2_surf);
103 if (!dri2_surf) {
104 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
105 return NULL;
106 }
107
108 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
109 goto cleanup_surf;
110
111 switch (type) {
112 case EGL_WINDOW_BIT:
113 if (!window)
114 return NULL;
115 surf = gbm_dri_surface(window);
116 dri2_surf->gbm_surf = surf;
117 dri2_surf->base.Width = surf->base.width;
118 dri2_surf->base.Height = surf->base.height;
119 surf->dri_private = dri2_surf;
120 break;
121 default:
122 goto cleanup_surf;
123 }
124
125 dri2_surf->dri_drawable =
126 (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
127 dri2_conf->dri_double_config,
128 dri2_surf->gbm_surf);
129
130 if (dri2_surf->dri_drawable == NULL) {
131 _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
132 goto cleanup_surf;
133 }
134
135 return &dri2_surf->base;
136
137 cleanup_surf:
138 free(dri2_surf);
139
140 return NULL;
141 }
142
143 static _EGLSurface *
144 dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
145 _EGLConfig *conf, void *native_window,
146 const EGLint *attrib_list)
147 {
148 return dri2_drm_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
149 native_window, attrib_list);
150 }
151
152 static _EGLSurface *
153 dri2_drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
154 _EGLConfig *conf, void *native_window,
155 const EGLint *attrib_list)
156 {
157 /* From the EGL_MESA_platform_gbm spec, version 5:
158 *
159 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
160 * that belongs to the GBM platform. Any such call fails and generates
161 * EGL_BAD_PARAMETER.
162 */
163 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
164 return NULL;
165 }
166
167 static EGLBoolean
168 dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
169 {
170 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
171 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
172 int i;
173
174 if (!_eglPutSurface(surf))
175 return EGL_TRUE;
176
177 (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
178
179 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
180 if (dri2_surf->color_buffers[i].bo)
181 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
182 }
183
184 for (i = 0; i < __DRI_BUFFER_COUNT; i++) {
185 if (dri2_surf->dri_buffers[i])
186 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
187 dri2_surf->dri_buffers[i]);
188 }
189
190 free(surf);
191
192 return EGL_TRUE;
193 }
194
195 static int
196 get_back_bo(struct dri2_egl_surface *dri2_surf)
197 {
198 struct dri2_egl_display *dri2_dpy =
199 dri2_egl_display(dri2_surf->base.Resource.Display);
200 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
201 int i;
202
203 if (dri2_surf->back == NULL) {
204 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
205 if (!dri2_surf->color_buffers[i].locked) {
206 dri2_surf->back = &dri2_surf->color_buffers[i];
207 break;
208 }
209 }
210 }
211
212 if (dri2_surf->back == NULL)
213 return -1;
214 if (dri2_surf->back->bo == NULL)
215 dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base.base,
216 surf->base.width, surf->base.height,
217 surf->base.format, surf->base.flags);
218 if (dri2_surf->back->bo == NULL)
219 return -1;
220
221 return 0;
222 }
223
224 static void
225 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
226 {
227 struct dri2_egl_display *dri2_dpy =
228 dri2_egl_display(dri2_surf->base.Resource.Display);
229 struct gbm_dri_bo *bo;
230 int name, pitch;
231
232 bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
233
234 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
235 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
236
237 buffer->attachment = __DRI_BUFFER_BACK_LEFT;
238 buffer->name = name;
239 buffer->pitch = pitch;
240 buffer->cpp = 4;
241 buffer->flags = 0;
242 }
243
244 static int
245 get_aux_bo(struct dri2_egl_surface *dri2_surf,
246 unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
247 {
248 struct dri2_egl_display *dri2_dpy =
249 dri2_egl_display(dri2_surf->base.Resource.Display);
250 __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
251
252 if (b == NULL) {
253 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
254 attachment, format,
255 dri2_surf->base.Width,
256 dri2_surf->base.Height);
257 dri2_surf->dri_buffers[attachment] = b;
258 }
259 if (b == NULL)
260 return -1;
261
262 memcpy(buffer, b, sizeof *buffer);
263
264 return 0;
265 }
266
267 static __DRIbuffer *
268 dri2_drm_get_buffers_with_format(__DRIdrawable *driDrawable,
269 int *width, int *height,
270 unsigned int *attachments, int count,
271 int *out_count, void *loaderPrivate)
272 {
273 struct dri2_egl_surface *dri2_surf = loaderPrivate;
274 int i, j;
275
276 dri2_surf->buffer_count = 0;
277 for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
278 assert(attachments[i] < __DRI_BUFFER_COUNT);
279 assert(dri2_surf->buffer_count < 5);
280
281 switch (attachments[i]) {
282 case __DRI_BUFFER_BACK_LEFT:
283 if (get_back_bo(dri2_surf) < 0) {
284 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
285 return NULL;
286 }
287 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
288 break;
289 default:
290 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
291 &dri2_surf->buffers[j]) < 0) {
292 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
293 return NULL;
294 }
295 break;
296 }
297 }
298
299 *out_count = j;
300 if (j == 0)
301 return NULL;
302
303 *width = dri2_surf->base.Width;
304 *height = dri2_surf->base.Height;
305
306 return dri2_surf->buffers;
307 }
308
309 static __DRIbuffer *
310 dri2_drm_get_buffers(__DRIdrawable * driDrawable,
311 int *width, int *height,
312 unsigned int *attachments, int count,
313 int *out_count, void *loaderPrivate)
314 {
315 unsigned int *attachments_with_format;
316 __DRIbuffer *buffer;
317 const unsigned int format = 32;
318 int i;
319
320 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
321 if (!attachments_with_format) {
322 *out_count = 0;
323 return NULL;
324 }
325
326 for (i = 0; i < count; ++i) {
327 attachments_with_format[2*i] = attachments[i];
328 attachments_with_format[2*i + 1] = format;
329 }
330
331 buffer =
332 dri2_drm_get_buffers_with_format(driDrawable,
333 width, height,
334 attachments_with_format, count,
335 out_count, loaderPrivate);
336
337 free(attachments_with_format);
338
339 return buffer;
340 }
341
342 static int
343 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable,
344 unsigned int format,
345 uint32_t *stamp,
346 void *loaderPrivate,
347 uint32_t buffer_mask,
348 struct __DRIimageList *buffers)
349 {
350 struct dri2_egl_surface *dri2_surf = loaderPrivate;
351 struct gbm_dri_bo *bo;
352
353 if (get_back_bo(dri2_surf) < 0)
354 return 0;
355
356 bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
357 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
358 buffers->back = bo->image;
359
360 return 1;
361 }
362
363 static void
364 dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
365 {
366 (void) driDrawable;
367 (void) loaderPrivate;
368 }
369
370 static EGLBoolean
371 dri2_drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
372 {
373 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
374 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
375 int i;
376
377 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
378 if (dri2_surf->current)
379 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
380 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
381 if (dri2_surf->color_buffers[i].age > 0)
382 dri2_surf->color_buffers[i].age++;
383 dri2_surf->current = dri2_surf->back;
384 dri2_surf->current->age = 1;
385 dri2_surf->back = NULL;
386 }
387
388 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
389 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
390
391 return EGL_TRUE;
392 }
393
394 static EGLint
395 dri2_drm_query_buffer_age(_EGLDriver *drv,
396 _EGLDisplay *disp, _EGLSurface *surface)
397 {
398 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
399
400 if (get_back_bo(dri2_surf) < 0) {
401 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
402 return 0;
403 }
404
405 return dri2_surf->back->age;
406 }
407
408 static _EGLImage *
409 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
410 EGLClientBuffer buffer, const EGLint *attr_list)
411 {
412 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
413 struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
414 struct dri2_egl_image *dri2_img;
415
416 dri2_img = malloc(sizeof *dri2_img);
417 if (!dri2_img) {
418 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
419 return NULL;
420 }
421
422 if (!_eglInitImage(&dri2_img->base, disp)) {
423 free(dri2_img);
424 return NULL;
425 }
426
427 dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
428 if (dri2_img->dri_image == NULL) {
429 free(dri2_img);
430 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
431 return NULL;
432 }
433
434 return &dri2_img->base;
435 }
436
437 static _EGLImage *
438 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
439 _EGLContext *ctx, EGLenum target,
440 EGLClientBuffer buffer, const EGLint *attr_list)
441 {
442 (void) drv;
443
444 switch (target) {
445 case EGL_NATIVE_PIXMAP_KHR:
446 return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
447 default:
448 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
449 }
450 }
451
452 static int
453 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
454 {
455 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
456
457 return drmAuthMagic(dri2_dpy->fd, id);
458 }
459
460 static struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
461 .authenticate = dri2_drm_authenticate,
462 .create_window_surface = dri2_drm_create_window_surface,
463 .create_pixmap_surface = dri2_drm_create_pixmap_surface,
464 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
465 .destroy_surface = dri2_drm_destroy_surface,
466 .create_image = dri2_drm_create_image_khr,
467 .swap_interval = dri2_fallback_swap_interval,
468 .swap_buffers = dri2_drm_swap_buffers,
469 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
470 .swap_buffers_region = dri2_fallback_swap_buffers_region,
471 .post_sub_buffer = dri2_fallback_post_sub_buffer,
472 .copy_buffers = dri2_fallback_copy_buffers,
473 .query_buffer_age = dri2_drm_query_buffer_age,
474 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
475 };
476
477 EGLBoolean
478 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
479 {
480 struct dri2_egl_display *dri2_dpy;
481 struct gbm_device *gbm;
482 int fd = -1;
483 int i;
484
485 loader_set_logger(_eglLog);
486
487 dri2_dpy = calloc(1, sizeof *dri2_dpy);
488 if (!dri2_dpy)
489 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
490
491 disp->DriverData = (void *) dri2_dpy;
492
493 gbm = disp->PlatformDisplay;
494 if (gbm == NULL) {
495 fd = open("/dev/dri/card0", O_RDWR);
496 dri2_dpy->own_device = 1;
497 gbm = gbm_create_device(fd);
498 if (gbm == NULL)
499 return EGL_FALSE;
500 }
501
502 if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
503 free(dri2_dpy);
504 return EGL_FALSE;
505 }
506
507 dri2_dpy->gbm_dri = gbm_dri_device(gbm);
508 if (dri2_dpy->gbm_dri->base.type != GBM_DRM_DRIVER_TYPE_DRI) {
509 free(dri2_dpy);
510 return EGL_FALSE;
511 }
512
513 if (fd < 0) {
514 fd = dup(gbm_device_get_fd(gbm));
515 if (fd < 0) {
516 free(dri2_dpy);
517 return EGL_FALSE;
518 }
519 }
520
521 dri2_dpy->fd = fd;
522 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
523 dri2_dpy->driver_name = dri2_dpy->gbm_dri->base.driver_name;
524
525 dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
526 dri2_dpy->core = dri2_dpy->gbm_dri->core;
527 dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
528 dri2_dpy->image = dri2_dpy->gbm_dri->image;
529 dri2_dpy->flush = dri2_dpy->gbm_dri->flush;
530 dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
531
532 dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
533 dri2_dpy->gbm_dri->lookup_user_data = disp;
534
535 dri2_dpy->gbm_dri->get_buffers = dri2_drm_get_buffers;
536 dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
537 dri2_dpy->gbm_dri->get_buffers_with_format = dri2_drm_get_buffers_with_format;
538 dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
539
540 dri2_dpy->gbm_dri->base.base.surface_lock_front_buffer = lock_front_buffer;
541 dri2_dpy->gbm_dri->base.base.surface_release_buffer = release_buffer;
542 dri2_dpy->gbm_dri->base.base.surface_has_free_buffers = has_free_buffers;
543
544 dri2_setup_screen(disp);
545
546 for (i = 0; dri2_dpy->driver_configs[i]; i++) {
547 EGLint format, attr_list[3];
548 unsigned int mask;
549
550 dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
551 __DRI_ATTRIB_RED_MASK, &mask);
552 if (mask == 0x3ff00000)
553 format = GBM_FORMAT_XRGB2101010;
554 else if (mask == 0x00ff0000)
555 format = GBM_FORMAT_XRGB8888;
556 else if (mask == 0xf800)
557 format = GBM_FORMAT_RGB565;
558 else
559 continue;
560
561 attr_list[0] = EGL_NATIVE_VISUAL_ID;
562 attr_list[1] = format;
563 attr_list[2] = EGL_NONE;
564
565 dri2_add_config(disp, dri2_dpy->driver_configs[i],
566 i + 1, EGL_WINDOW_BIT, attr_list, NULL);
567 }
568
569 disp->Extensions.EXT_buffer_age = EGL_TRUE;
570
571 #ifdef HAVE_WAYLAND_PLATFORM
572 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
573 #endif
574
575 /* we're supporting EGL 1.4 */
576 disp->VersionMajor = 1;
577 disp->VersionMinor = 4;
578
579 /* Fill vtbl last to prevent accidentally calling virtual function during
580 * initialization.
581 */
582 dri2_dpy->vtbl = &dri2_drm_display_vtbl;
583
584 return EGL_TRUE;
585 }