9aafb525b93c5c74accb2414027bd6c8f433c6ad
[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
40 static struct gbm_bo *
41 lock_front_buffer(struct gbm_surface *_surf)
42 {
43 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
44 struct dri2_egl_surface *dri2_surf = surf->dri_private;
45 struct gbm_bo *bo;
46
47 if (dri2_surf->current == NULL) {
48 _eglError(EGL_BAD_SURFACE, "no front buffer");
49 return NULL;
50 }
51
52 bo = dri2_surf->current->bo;
53 dri2_surf->current->locked = 1;
54 dri2_surf->current = NULL;
55
56 return bo;
57 }
58
59 static void
60 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
61 {
62 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
63 struct dri2_egl_surface *dri2_surf = surf->dri_private;
64 int i;
65
66 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
67 if (dri2_surf->color_buffers[i].bo == bo) {
68 dri2_surf->color_buffers[i].locked = 0;
69 }
70 }
71 }
72
73 static int
74 has_free_buffers(struct gbm_surface *_surf)
75 {
76 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
77 struct dri2_egl_surface *dri2_surf = surf->dri_private;
78 int i;
79
80 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
81 if (!dri2_surf->color_buffers[i].locked)
82 return 1;
83
84 return 0;
85 }
86
87 static _EGLSurface *
88 dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
89 _EGLConfig *conf, EGLNativeWindowType window,
90 const EGLint *attrib_list)
91 {
92 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
93 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
94 struct dri2_egl_surface *dri2_surf;
95 struct gbm_dri_surface *surf;
96
97 (void) drv;
98
99 dri2_surf = malloc(sizeof *dri2_surf);
100 if (!dri2_surf) {
101 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
102 return NULL;
103 }
104
105 memset(dri2_surf, 0, sizeof *dri2_surf);
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, __DRIbuffer *buffer)
180 {
181 struct dri2_egl_display *dri2_dpy =
182 dri2_egl_display(dri2_surf->base.Resource.Display);
183 struct gbm_dri_bo *bo;
184 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
185 int i, name, pitch;
186
187 if (dri2_surf->back == NULL) {
188 for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
189 if (!dri2_surf->color_buffers[i].locked) {
190 dri2_surf->back = &dri2_surf->color_buffers[i];
191 break;
192 }
193 }
194 }
195
196 if (dri2_surf->back == NULL)
197 return -1;
198 if (dri2_surf->back->bo == NULL)
199 dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base.base,
200 surf->base.width, surf->base.height,
201 surf->base.format, surf->base.flags);
202 if (dri2_surf->back->bo == NULL)
203 return -1;
204
205 bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
206
207 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
208 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
209
210 buffer->attachment = __DRI_BUFFER_BACK_LEFT;
211 buffer->name = name;
212 buffer->pitch = pitch;
213 buffer->cpp = 4;
214 buffer->flags = 0;
215
216 return 0;
217 }
218
219 static int
220 get_aux_bo(struct dri2_egl_surface *dri2_surf,
221 unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
222 {
223 struct dri2_egl_display *dri2_dpy =
224 dri2_egl_display(dri2_surf->base.Resource.Display);
225 __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
226
227 if (b == NULL) {
228 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
229 attachment, format,
230 dri2_surf->base.Width,
231 dri2_surf->base.Height);
232 dri2_surf->dri_buffers[attachment] = b;
233 }
234 if (b == NULL)
235 return -1;
236
237 memcpy(buffer, b, sizeof *buffer);
238
239 return 0;
240 }
241
242 static __DRIbuffer *
243 dri2_get_buffers_with_format(__DRIdrawable *driDrawable,
244 int *width, int *height,
245 unsigned int *attachments, int count,
246 int *out_count, void *loaderPrivate)
247 {
248 struct dri2_egl_surface *dri2_surf = loaderPrivate;
249 int i, j;
250
251 dri2_surf->buffer_count = 0;
252 for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
253 assert(attachments[i] < __DRI_BUFFER_COUNT);
254 assert(dri2_surf->buffer_count < 5);
255
256 switch (attachments[i]) {
257 case __DRI_BUFFER_BACK_LEFT:
258 if (get_back_bo(dri2_surf, &dri2_surf->buffers[j]) < 0) {
259 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
260 return NULL;
261 }
262 break;
263 default:
264 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
265 &dri2_surf->buffers[j]) < 0) {
266 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
267 return NULL;
268 }
269 break;
270 }
271 }
272
273 *out_count = j;
274 if (j == 0)
275 return NULL;
276
277 *width = dri2_surf->base.Width;
278 *height = dri2_surf->base.Height;
279
280 return dri2_surf->buffers;
281 }
282
283 static __DRIbuffer *
284 dri2_get_buffers(__DRIdrawable * driDrawable,
285 int *width, int *height,
286 unsigned int *attachments, int count,
287 int *out_count, void *loaderPrivate)
288 {
289 unsigned int *attachments_with_format;
290 __DRIbuffer *buffer;
291 const unsigned int format = 32;
292 int i;
293
294 attachments_with_format = calloc(count * 2, sizeof(unsigned int));
295 if (!attachments_with_format) {
296 *out_count = 0;
297 return NULL;
298 }
299
300 for (i = 0; i < count; ++i) {
301 attachments_with_format[2*i] = attachments[i];
302 attachments_with_format[2*i + 1] = format;
303 }
304
305 buffer =
306 dri2_get_buffers_with_format(driDrawable,
307 width, height,
308 attachments_with_format, count,
309 out_count, loaderPrivate);
310
311 free(attachments_with_format);
312
313 return buffer;
314 }
315
316 static void
317 dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
318 {
319 (void) driDrawable;
320 (void) loaderPrivate;
321 }
322
323 static EGLBoolean
324 dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
325 {
326 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
327 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
328
329 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
330 if (dri2_surf->current)
331 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
332 dri2_surf->current = dri2_surf->back;
333 dri2_surf->back = NULL;
334 }
335
336 (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
337 (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
338
339 return EGL_TRUE;
340 }
341
342 static _EGLImage *
343 dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
344 EGLClientBuffer buffer, const EGLint *attr_list)
345 {
346 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
347 struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
348 struct dri2_egl_image *dri2_img;
349
350 dri2_img = malloc(sizeof *dri2_img);
351 if (!dri2_img) {
352 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
353 return NULL;
354 }
355
356 if (!_eglInitImage(&dri2_img->base, disp)) {
357 free(dri2_img);
358 return NULL;
359 }
360
361 dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
362 if (dri2_img->dri_image == NULL) {
363 free(dri2_img);
364 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
365 return NULL;
366 }
367
368 return &dri2_img->base;
369 }
370
371 static _EGLImage *
372 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
373 _EGLContext *ctx, EGLenum target,
374 EGLClientBuffer buffer, const EGLint *attr_list)
375 {
376 (void) drv;
377
378 switch (target) {
379 case EGL_NATIVE_PIXMAP_KHR:
380 return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
381 default:
382 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
383 }
384 }
385
386 static int
387 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
388 {
389 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
390
391 return drmAuthMagic(dri2_dpy->fd, id);
392 }
393
394 EGLBoolean
395 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
396 {
397 struct dri2_egl_display *dri2_dpy;
398 struct gbm_device *gbm;
399 int fd = -1;
400 int i;
401
402 dri2_dpy = malloc(sizeof *dri2_dpy);
403 if (!dri2_dpy)
404 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
405
406 memset(dri2_dpy, 0, sizeof *dri2_dpy);
407
408 disp->DriverData = (void *) dri2_dpy;
409
410 gbm = disp->PlatformDisplay;
411 if (gbm == NULL) {
412 fd = open("/dev/dri/card0", O_RDWR);
413 dri2_dpy->own_device = 1;
414 gbm = gbm_create_device(fd);
415 if (gbm == NULL)
416 return EGL_FALSE;
417 }
418
419 if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
420 free(dri2_dpy);
421 return EGL_FALSE;
422 }
423
424 dri2_dpy->gbm_dri = gbm_dri_device(gbm);
425 if (dri2_dpy->gbm_dri->base.type != GBM_DRM_DRIVER_TYPE_DRI) {
426 free(dri2_dpy);
427 return EGL_FALSE;
428 }
429
430 if (fd < 0) {
431 fd = dup(gbm_device_get_fd(gbm));
432 if (fd < 0) {
433 free(dri2_dpy);
434 return EGL_FALSE;
435 }
436 }
437
438 dri2_dpy->fd = fd;
439 dri2_dpy->device_name = dri2_get_device_name_for_fd(dri2_dpy->fd);
440 dri2_dpy->driver_name = dri2_dpy->gbm_dri->base.driver_name;
441
442 dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
443 dri2_dpy->core = dri2_dpy->gbm_dri->core;
444 dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
445 dri2_dpy->image = dri2_dpy->gbm_dri->image;
446 dri2_dpy->flush = dri2_dpy->gbm_dri->flush;
447 dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
448
449 dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
450 dri2_dpy->gbm_dri->lookup_user_data = disp;
451
452 dri2_dpy->gbm_dri->get_buffers = dri2_get_buffers;
453 dri2_dpy->gbm_dri->flush_front_buffer = dri2_flush_front_buffer;
454 dri2_dpy->gbm_dri->get_buffers_with_format = dri2_get_buffers_with_format;
455
456 dri2_dpy->gbm_dri->base.base.surface_lock_front_buffer = lock_front_buffer;
457 dri2_dpy->gbm_dri->base.base.surface_release_buffer = release_buffer;
458 dri2_dpy->gbm_dri->base.base.surface_has_free_buffers = has_free_buffers;
459
460 dri2_setup_screen(disp);
461
462 for (i = 0; dri2_dpy->driver_configs[i]; i++)
463 dri2_add_config(disp, dri2_dpy->driver_configs[i],
464 i + 1, 0, EGL_WINDOW_BIT, NULL, NULL);
465
466 drv->API.CreateWindowSurface = dri2_create_window_surface;
467 drv->API.DestroySurface = dri2_destroy_surface;
468 drv->API.SwapBuffers = dri2_swap_buffers;
469 drv->API.CreateImageKHR = dri2_drm_create_image_khr;
470
471 #ifdef HAVE_WAYLAND_PLATFORM
472 disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
473 #endif
474 dri2_dpy->authenticate = dri2_drm_authenticate;
475
476 /* we're supporting EGL 1.4 */
477 disp->VersionMajor = 1;
478 disp->VersionMinor = 4;
479
480 return EGL_TRUE;
481 }