egl/drm: Move loop vars inside the loop
[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 <stdint.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <xf86drm.h>
33 #include <dlfcn.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38
39 #include "egl_dri2.h"
40 #include "egl_dri2_fallbacks.h"
41 #include "loader.h"
42
43 static struct gbm_bo *
44 lock_front_buffer(struct gbm_surface *_surf)
45 {
46 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
47 struct dri2_egl_surface *dri2_surf = surf->dri_private;
48 struct gbm_dri_device *device = (struct gbm_dri_device *) _surf->gbm;
49 struct gbm_bo *bo;
50
51 if (dri2_surf->current == NULL) {
52 _eglError(EGL_BAD_SURFACE, "no front buffer");
53 return NULL;
54 }
55
56 bo = dri2_surf->current->bo;
57
58 if (device->dri2) {
59 dri2_surf->current->locked = true;
60 dri2_surf->current = NULL;
61 }
62
63 return bo;
64 }
65
66 static void
67 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
68 {
69 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
70 struct dri2_egl_surface *dri2_surf = surf->dri_private;
71
72 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
73 if (dri2_surf->color_buffers[i].bo == bo) {
74 dri2_surf->color_buffers[i].locked = false;
75 }
76 }
77 }
78
79 static int
80 has_free_buffers(struct gbm_surface *_surf)
81 {
82 struct gbm_dri_surface *surf = (struct gbm_dri_surface *) _surf;
83 struct dri2_egl_surface *dri2_surf = surf->dri_private;
84
85 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
86 if (!dri2_surf->color_buffers[i].locked)
87 return 1;
88
89 return 0;
90 }
91
92 static _EGLSurface *
93 dri2_drm_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
94 _EGLConfig *conf, void *native_window,
95 const EGLint *attrib_list)
96 {
97 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
98 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
99 struct dri2_egl_surface *dri2_surf;
100 struct gbm_surface *window = native_window;
101 struct gbm_dri_surface *surf;
102 const __DRIconfig *config;
103
104 (void) drv;
105
106 dri2_surf = calloc(1, sizeof *dri2_surf);
107 if (!dri2_surf) {
108 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
109 return NULL;
110 }
111
112 if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
113 goto cleanup_surf;
114
115 switch (type) {
116 case EGL_WINDOW_BIT:
117 if (!window) {
118 _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
119 goto cleanup_surf;
120 }
121
122 surf = gbm_dri_surface(window);
123 dri2_surf->gbm_surf = surf;
124 dri2_surf->base.Width = surf->base.width;
125 dri2_surf->base.Height = surf->base.height;
126 surf->dri_private = dri2_surf;
127 break;
128 default:
129 goto cleanup_surf;
130 }
131
132 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
133 dri2_surf->base.GLColorspace);
134
135 if (dri2_dpy->dri2) {
136 dri2_surf->dri_drawable =
137 dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config,
138 dri2_surf->gbm_surf);
139
140 } else {
141 assert(dri2_dpy->swrast != NULL);
142
143 dri2_surf->dri_drawable =
144 dri2_dpy->swrast->createNewDrawable(dri2_dpy->dri_screen, config,
145 dri2_surf->gbm_surf);
146
147 }
148 if (dri2_surf->dri_drawable == NULL) {
149 _eglError(EGL_BAD_ALLOC, "createNewDrawable()");
150 goto cleanup_surf;
151 }
152
153 return &dri2_surf->base;
154
155 cleanup_surf:
156 free(dri2_surf);
157
158 return NULL;
159 }
160
161 static _EGLSurface *
162 dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
163 _EGLConfig *conf, void *native_window,
164 const EGLint *attrib_list)
165 {
166 return dri2_drm_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
167 native_window, attrib_list);
168 }
169
170 static _EGLSurface *
171 dri2_drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
172 _EGLConfig *conf, void *native_window,
173 const EGLint *attrib_list)
174 {
175 /* From the EGL_MESA_platform_gbm spec, version 5:
176 *
177 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
178 * that belongs to the GBM platform. Any such call fails and generates
179 * EGL_BAD_PARAMETER.
180 */
181 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
182 return NULL;
183 }
184
185 static EGLBoolean
186 dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
187 {
188 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
189 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
190
191 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
192
193 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
194 if (dri2_surf->color_buffers[i].bo)
195 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
196 }
197
198 for (unsigned i = 0; i < __DRI_BUFFER_COUNT; i++) {
199 if (dri2_surf->dri_buffers[i])
200 dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
201 dri2_surf->dri_buffers[i]);
202 }
203
204 free(surf);
205
206 return EGL_TRUE;
207 }
208
209 static int
210 get_back_bo(struct dri2_egl_surface *dri2_surf)
211 {
212 struct dri2_egl_display *dri2_dpy =
213 dri2_egl_display(dri2_surf->base.Resource.Display);
214 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
215 int age = 0;
216
217 if (dri2_surf->back == NULL) {
218 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
219 if (!dri2_surf->color_buffers[i].locked &&
220 dri2_surf->color_buffers[i].age >= age) {
221 dri2_surf->back = &dri2_surf->color_buffers[i];
222 age = dri2_surf->color_buffers[i].age;
223 }
224 }
225 }
226
227 if (dri2_surf->back == NULL)
228 return -1;
229 if (dri2_surf->back->bo == NULL) {
230 if (surf->base.modifiers)
231 dri2_surf->back->bo = gbm_bo_create_with_modifiers(&dri2_dpy->gbm_dri->base,
232 surf->base.width, surf->base.height,
233 surf->base.format,
234 surf->base.modifiers,
235 surf->base.count);
236 else
237 dri2_surf->back->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
238 surf->base.width,
239 surf->base.height,
240 surf->base.format,
241 surf->base.flags);
242
243 }
244 if (dri2_surf->back->bo == NULL)
245 return -1;
246
247 return 0;
248 }
249
250 static int
251 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
252 {
253 struct dri2_egl_display *dri2_dpy =
254 dri2_egl_display(dri2_surf->base.Resource.Display);
255 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
256
257 if (dri2_surf->current == NULL) {
258 assert(!dri2_surf->color_buffers[0].locked);
259 dri2_surf->current = &dri2_surf->color_buffers[0];
260 }
261
262 if (dri2_surf->current->bo == NULL)
263 dri2_surf->current->bo = gbm_bo_create(&dri2_dpy->gbm_dri->base,
264 surf->base.width, surf->base.height,
265 surf->base.format, surf->base.flags);
266 if (dri2_surf->current->bo == NULL)
267 return -1;
268
269 return 0;
270 }
271
272 static void
273 back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
274 {
275 struct dri2_egl_display *dri2_dpy =
276 dri2_egl_display(dri2_surf->base.Resource.Display);
277 struct gbm_dri_bo *bo;
278 int name, pitch;
279
280 bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
281
282 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_NAME, &name);
283 dri2_dpy->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
284
285 buffer->attachment = __DRI_BUFFER_BACK_LEFT;
286 buffer->name = name;
287 buffer->pitch = pitch;
288 buffer->cpp = 4;
289 buffer->flags = 0;
290 }
291
292 static int
293 get_aux_bo(struct dri2_egl_surface *dri2_surf,
294 unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
295 {
296 struct dri2_egl_display *dri2_dpy =
297 dri2_egl_display(dri2_surf->base.Resource.Display);
298 __DRIbuffer *b = dri2_surf->dri_buffers[attachment];
299
300 if (b == NULL) {
301 b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
302 attachment, format,
303 dri2_surf->base.Width,
304 dri2_surf->base.Height);
305 dri2_surf->dri_buffers[attachment] = b;
306 }
307 if (b == NULL)
308 return -1;
309
310 memcpy(buffer, b, sizeof *buffer);
311
312 return 0;
313 }
314
315 static __DRIbuffer *
316 dri2_drm_get_buffers_with_format(__DRIdrawable *driDrawable,
317 int *width, int *height,
318 unsigned int *attachments, int count,
319 int *out_count, void *loaderPrivate)
320 {
321 struct dri2_egl_surface *dri2_surf = loaderPrivate;
322 int i, j;
323
324 dri2_surf->buffer_count = 0;
325 for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
326 assert(attachments[i] < __DRI_BUFFER_COUNT);
327 assert(dri2_surf->buffer_count < 5);
328
329 switch (attachments[i]) {
330 case __DRI_BUFFER_BACK_LEFT:
331 if (get_back_bo(dri2_surf) < 0) {
332 _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
333 return NULL;
334 }
335 back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
336 break;
337 default:
338 if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
339 &dri2_surf->buffers[j]) < 0) {
340 _eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
341 return NULL;
342 }
343 break;
344 }
345 }
346
347 *out_count = j;
348 if (j == 0)
349 return NULL;
350
351 *width = dri2_surf->base.Width;
352 *height = dri2_surf->base.Height;
353
354 return dri2_surf->buffers;
355 }
356
357 static __DRIbuffer *
358 dri2_drm_get_buffers(__DRIdrawable * driDrawable,
359 int *width, int *height,
360 unsigned int *attachments, int count,
361 int *out_count, void *loaderPrivate)
362 {
363 unsigned int *attachments_with_format;
364 __DRIbuffer *buffer;
365 const unsigned int format = 32;
366
367 attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
368 if (!attachments_with_format) {
369 *out_count = 0;
370 return NULL;
371 }
372
373 for (int i = 0; i < count; ++i) {
374 attachments_with_format[2*i] = attachments[i];
375 attachments_with_format[2*i + 1] = format;
376 }
377
378 buffer =
379 dri2_drm_get_buffers_with_format(driDrawable,
380 width, height,
381 attachments_with_format, count,
382 out_count, loaderPrivate);
383
384 free(attachments_with_format);
385
386 return buffer;
387 }
388
389 static int
390 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable,
391 unsigned int format,
392 uint32_t *stamp,
393 void *loaderPrivate,
394 uint32_t buffer_mask,
395 struct __DRIimageList *buffers)
396 {
397 struct dri2_egl_surface *dri2_surf = loaderPrivate;
398 struct gbm_dri_bo *bo;
399
400 if (get_back_bo(dri2_surf) < 0)
401 return 0;
402
403 bo = (struct gbm_dri_bo *) dri2_surf->back->bo;
404 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
405 buffers->back = bo->image;
406
407 return 1;
408 }
409
410 static void
411 dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
412 {
413 (void) driDrawable;
414 (void) loaderPrivate;
415 }
416
417 static EGLBoolean
418 dri2_drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
419 {
420 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
421 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
422
423 if (!dri2_dpy->flush) {
424 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
425 return EGL_TRUE;
426 }
427
428 if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
429 if (dri2_surf->current)
430 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
431 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
432 if (dri2_surf->color_buffers[i].age > 0)
433 dri2_surf->color_buffers[i].age++;
434
435 /* Make sure we have a back buffer in case we're swapping without
436 * ever rendering. */
437 if (get_back_bo(dri2_surf) < 0) {
438 _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
439 return EGL_FALSE;
440 }
441
442 dri2_surf->current = dri2_surf->back;
443 dri2_surf->current->age = 1;
444 dri2_surf->back = NULL;
445 }
446
447 dri2_flush_drawable_for_swapbuffers(disp, draw);
448 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
449
450 return EGL_TRUE;
451 }
452
453 static EGLint
454 dri2_drm_query_buffer_age(_EGLDriver *drv,
455 _EGLDisplay *disp, _EGLSurface *surface)
456 {
457 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
458
459 if (get_back_bo(dri2_surf) < 0) {
460 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
461 return -1;
462 }
463
464 return dri2_surf->back->age;
465 }
466
467 static _EGLImage *
468 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
469 EGLClientBuffer buffer, const EGLint *attr_list)
470 {
471 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
472 struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *) buffer);
473 struct dri2_egl_image *dri2_img;
474
475 dri2_img = malloc(sizeof *dri2_img);
476 if (!dri2_img) {
477 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
478 return NULL;
479 }
480
481 if (!_eglInitImage(&dri2_img->base, disp)) {
482 free(dri2_img);
483 return NULL;
484 }
485
486 dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
487 if (dri2_img->dri_image == NULL) {
488 free(dri2_img);
489 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
490 return NULL;
491 }
492
493 return &dri2_img->base;
494 }
495
496 static _EGLImage *
497 dri2_drm_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
498 _EGLContext *ctx, EGLenum target,
499 EGLClientBuffer buffer, const EGLint *attr_list)
500 {
501 (void) drv;
502
503 switch (target) {
504 case EGL_NATIVE_PIXMAP_KHR:
505 return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
506 default:
507 return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
508 }
509 }
510
511 static int
512 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
513 {
514 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
515
516 return drmAuthMagic(dri2_dpy->fd, id);
517 }
518
519 static void
520 swrast_put_image2(__DRIdrawable *driDrawable,
521 int op,
522 int x,
523 int y,
524 int width,
525 int height,
526 int stride,
527 char *data,
528 void *loaderPrivate)
529 {
530 struct dri2_egl_surface *dri2_surf = loaderPrivate;
531 int internal_stride;
532 struct gbm_dri_bo *bo;
533
534 if (op != __DRI_SWRAST_IMAGE_OP_DRAW &&
535 op != __DRI_SWRAST_IMAGE_OP_SWAP)
536 return;
537
538 if (get_swrast_front_bo(dri2_surf) < 0)
539 return;
540
541 bo = gbm_dri_bo(dri2_surf->current->bo);
542 if (gbm_dri_bo_map_dumb(bo) == NULL)
543 return;
544
545 internal_stride = bo->base.stride;
546
547 for (int i = 0; i < height; i++) {
548 memcpy(bo->map + (x + i) * internal_stride + y,
549 data + i * stride, stride);
550 }
551
552 gbm_dri_bo_unmap_dumb(bo);
553 }
554
555 static void
556 swrast_get_image(__DRIdrawable *driDrawable,
557 int x,
558 int y,
559 int width,
560 int height,
561 char *data,
562 void *loaderPrivate)
563 {
564 struct dri2_egl_surface *dri2_surf = loaderPrivate;
565 int internal_stride, stride;
566 struct gbm_dri_bo *bo;
567
568 if (get_swrast_front_bo(dri2_surf) < 0)
569 return;
570
571 bo = gbm_dri_bo(dri2_surf->current->bo);
572 if (gbm_dri_bo_map_dumb(bo) == NULL)
573 return;
574
575 internal_stride = bo->base.stride;
576 stride = width * 4;
577
578 for (int i = 0; i < height; i++) {
579 memcpy(data + i * stride,
580 bo->map + (x + i) * internal_stride + y, stride);
581 }
582
583 gbm_dri_bo_unmap_dumb(bo);
584 }
585
586 static EGLBoolean
587 drm_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
588 {
589 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
590 static const struct {
591 int format;
592 unsigned int red_mask;
593 unsigned int alpha_mask;
594 } visuals[] = {
595 { GBM_FORMAT_XRGB2101010, 0x3ff00000, 0x00000000 },
596 { GBM_FORMAT_ARGB2101010, 0x3ff00000, 0xc0000000 },
597 { GBM_FORMAT_XRGB8888, 0x00ff0000, 0x00000000 },
598 { GBM_FORMAT_ARGB8888, 0x00ff0000, 0xff000000 },
599 { GBM_FORMAT_RGB565, 0x0000f800, 0x00000000 },
600 };
601 EGLint attr_list[] = {
602 EGL_NATIVE_VISUAL_ID, 0,
603 EGL_NONE,
604 };
605 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
606 unsigned int count = 0;
607
608 for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
609 unsigned int red, alpha;
610
611 dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
612 __DRI_ATTRIB_RED_MASK, &red);
613 dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
614 __DRI_ATTRIB_ALPHA_MASK, &alpha);
615
616 for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) {
617 struct dri2_egl_config *dri2_conf;
618
619 if (visuals[j].red_mask != red || visuals[j].alpha_mask != alpha)
620 continue;
621
622 attr_list[1] = visuals[j].format;
623
624 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
625 count + 1, EGL_WINDOW_BIT, attr_list, NULL);
626 if (dri2_conf) {
627 if (dri2_conf->base.ConfigID == count + 1)
628 count++;
629 format_count[j]++;
630 }
631 }
632 }
633
634 for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
635 if (!format_count[i]) {
636 _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x",
637 visuals[i].format);
638 }
639 }
640
641 return (count != 0);
642 }
643
644 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
645 .authenticate = dri2_drm_authenticate,
646 .create_window_surface = dri2_drm_create_window_surface,
647 .create_pixmap_surface = dri2_drm_create_pixmap_surface,
648 .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
649 .destroy_surface = dri2_drm_destroy_surface,
650 .create_image = dri2_drm_create_image_khr,
651 .swap_interval = dri2_fallback_swap_interval,
652 .swap_buffers = dri2_drm_swap_buffers,
653 .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
654 .swap_buffers_region = dri2_fallback_swap_buffers_region,
655 .set_damage_region = dri2_fallback_set_damage_region,
656 .post_sub_buffer = dri2_fallback_post_sub_buffer,
657 .copy_buffers = dri2_fallback_copy_buffers,
658 .query_buffer_age = dri2_drm_query_buffer_age,
659 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
660 .get_sync_values = dri2_fallback_get_sync_values,
661 .get_dri_drawable = dri2_surface_get_dri_drawable,
662 };
663
664 EGLBoolean
665 dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
666 {
667 struct dri2_egl_display *dri2_dpy;
668 struct gbm_device *gbm;
669 const char *err;
670
671 loader_set_logger(_eglLog);
672
673 dri2_dpy = calloc(1, sizeof *dri2_dpy);
674 if (!dri2_dpy)
675 return _eglError(EGL_BAD_ALLOC, "eglInitialize");
676
677 dri2_dpy->fd = -1;
678 disp->DriverData = (void *) dri2_dpy;
679
680 gbm = disp->PlatformDisplay;
681 if (gbm == NULL) {
682 char buf[64];
683 int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0);
684 if (n != -1 && n < sizeof(buf))
685 dri2_dpy->fd = loader_open_device(buf);
686 if (dri2_dpy->fd < 0)
687 dri2_dpy->fd = loader_open_device("/dev/dri/card0");
688 gbm = gbm_create_device(dri2_dpy->fd);
689 if (gbm == NULL) {
690 err = "DRI2: failed to create gbm device";
691 goto cleanup;
692 }
693 dri2_dpy->own_device = true;
694 } else {
695 dri2_dpy->fd = fcntl(gbm_device_get_fd(gbm), F_DUPFD_CLOEXEC, 3);
696 if (dri2_dpy->fd < 0) {
697 err = "DRI2: failed to fcntl() existing gbm device";
698 goto cleanup;
699 }
700 }
701
702 if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
703 err = "DRI2: gbm device using incorrect/incompatible backend";
704 goto cleanup;
705 }
706
707 dri2_dpy->gbm_dri = gbm_dri_device(gbm);
708 dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
709
710 dri2_dpy->dri_screen = dri2_dpy->gbm_dri->screen;
711 dri2_dpy->core = dri2_dpy->gbm_dri->core;
712 dri2_dpy->dri2 = dri2_dpy->gbm_dri->dri2;
713 dri2_dpy->swrast = dri2_dpy->gbm_dri->swrast;
714 dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
715
716 dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
717 dri2_dpy->gbm_dri->lookup_user_data = disp;
718
719 dri2_dpy->gbm_dri->get_buffers = dri2_drm_get_buffers;
720 dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
721 dri2_dpy->gbm_dri->get_buffers_with_format = dri2_drm_get_buffers_with_format;
722 dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
723 dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
724 dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
725
726 dri2_dpy->gbm_dri->base.surface_lock_front_buffer = lock_front_buffer;
727 dri2_dpy->gbm_dri->base.surface_release_buffer = release_buffer;
728 dri2_dpy->gbm_dri->base.surface_has_free_buffers = has_free_buffers;
729
730 if (!dri2_setup_extensions(disp)) {
731 err = "DRI2: failed to find required DRI extensions";
732 goto cleanup;
733 }
734
735 dri2_setup_screen(disp);
736
737 if (!drm_add_configs_for_visuals(drv, disp)) {
738 err = "DRI2: failed to add configs";
739 goto cleanup;
740 }
741
742 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
743 if (dri2_dpy->dri2)
744 disp->Extensions.EXT_buffer_age = EGL_TRUE;
745
746 #ifdef HAVE_WAYLAND_PLATFORM
747 dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
748 #endif
749 dri2_set_WL_bind_wayland_display(drv, disp);
750
751 /* Fill vtbl last to prevent accidentally calling virtual function during
752 * initialization.
753 */
754 dri2_dpy->vtbl = &dri2_drm_display_vtbl;
755
756 return EGL_TRUE;
757
758 cleanup:
759 dri2_display_destroy(disp);
760 return _eglError(EGL_NOT_INITIALIZED, err);
761 }