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