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 <dlfcn.h>
29 #include <fcntl.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <xf86drm.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38
39 #include "util/os_file.h"
40
41 #include "main/glconfig.h"
42
43 #include "egl_dri2.h"
44 #include "egldevice.h"
45 #include "loader.h"
46
47 static struct gbm_bo *
lock_front_buffer(struct gbm_surface * _surf)48 lock_front_buffer(struct gbm_surface *_surf)
49 {
50 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
51 struct dri2_egl_surface *dri2_surf = surf->dri_private;
52 struct gbm_dri_device *device = gbm_dri_device(_surf->gbm);
53 struct gbm_bo *bo;
54
55 if (dri2_surf->current == NULL) {
56 _eglError(EGL_BAD_SURFACE, "no front buffer");
57 return NULL;
58 }
59
60 bo = dri2_surf->current->bo;
61
62 if (!device->swrast) {
63 dri2_surf->current->locked = true;
64 dri2_surf->current = NULL;
65 }
66
67 return bo;
68 }
69
70 static void
release_buffer(struct gbm_surface * _surf,struct gbm_bo * bo)71 release_buffer(struct gbm_surface *_surf, struct gbm_bo *bo)
72 {
73 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
74 struct dri2_egl_surface *dri2_surf = surf->dri_private;
75
76 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
77 if (dri2_surf->color_buffers[i].bo == bo) {
78 dri2_surf->color_buffers[i].locked = false;
79 break;
80 }
81 }
82 }
83
84 static int
has_free_buffers(struct gbm_surface * _surf)85 has_free_buffers(struct gbm_surface *_surf)
86 {
87 struct gbm_dri_surface *surf = gbm_dri_surface(_surf);
88 struct dri2_egl_surface *dri2_surf = surf->dri_private;
89
90 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
91 if (!dri2_surf->color_buffers[i].locked)
92 return 1;
93
94 return 0;
95 }
96
97 static bool
dri2_drm_config_is_compatible(struct dri2_egl_display * dri2_dpy,const __DRIconfig * config,struct gbm_surface * surface)98 dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
99 const __DRIconfig *config,
100 struct gbm_surface *surface)
101 {
102 const struct gl_config *gl_config = (struct gl_config *) config;
103 const struct gbm_dri_visual *visual = NULL;
104 int i;
105
106 /* Check that the EGLConfig being used to render to the surface is
107 * compatible with the surface format. Since mixing ARGB and XRGB of
108 * otherwise-compatible formats is relatively common, explicitly allow
109 * this.
110 */
111 for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
112 visual = &dri2_dpy->gbm_dri->visual_table[i];
113 if (visual->gbm_format == surface->v0.format)
114 break;
115 }
116
117 if (i == dri2_dpy->gbm_dri->num_visuals)
118 return false;
119
120
121 const struct util_format_description *fmt_c =
122 util_format_description(gl_config->color_format);
123 const struct util_format_description *fmt_s =
124 util_format_description(visual->dri_image_format);
125
126 if (util_is_format_compatible(fmt_c, fmt_s) ||
127 util_is_format_compatible(fmt_s, fmt_c))
128 return true;
129
130 return false;
131 }
132
133 static _EGLSurface *
dri2_drm_create_window_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_surface,const EGLint * attrib_list)134 dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
135 void *native_surface, const EGLint *attrib_list)
136 {
137 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
138 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
139 struct dri2_egl_surface *dri2_surf;
140 struct gbm_surface *surface = native_surface;
141 struct gbm_dri_surface *surf;
142 const __DRIconfig *config;
143
144 dri2_surf = calloc(1, sizeof *dri2_surf);
145 if (!dri2_surf) {
146 _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
147 return NULL;
148 }
149
150 if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
151 attrib_list, false, native_surface))
152 goto cleanup_surf;
153
154 config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
155 dri2_surf->base.GLColorspace);
156
157 if (!config) {
158 _eglError(EGL_BAD_MATCH,
159 "Unsupported surfacetype/colorspace configuration");
160 goto cleanup_surf;
161 }
162
163 if (!dri2_drm_config_is_compatible(dri2_dpy, config, surface)) {
164 _eglError(EGL_BAD_MATCH, "EGL config not compatible with GBM format");
165 goto cleanup_surf;
166 }
167
168 surf = gbm_dri_surface(surface);
169 dri2_surf->gbm_surf = surf;
170 dri2_surf->base.Width = surf->base.v0.width;
171 dri2_surf->base.Height = surf->base.v0.height;
172 surf->dri_private = dri2_surf;
173
174 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf->gbm_surf))
175 goto cleanup_surf;
176
177 return &dri2_surf->base;
178
179 cleanup_surf:
180 free(dri2_surf);
181
182 return NULL;
183 }
184
185 static _EGLSurface *
dri2_drm_create_pixmap_surface(_EGLDisplay * disp,_EGLConfig * conf,void * native_window,const EGLint * attrib_list)186 dri2_drm_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
187 void *native_window, const EGLint *attrib_list)
188 {
189 /* From the EGL_MESA_platform_gbm spec, version 5:
190 *
191 * It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
192 * that belongs to the GBM platform. Any such call fails and generates
193 * EGL_BAD_PARAMETER.
194 */
195 _eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on GBM");
196 return NULL;
197 }
198
199 static EGLBoolean
dri2_drm_destroy_surface(_EGLDisplay * disp,_EGLSurface * surf)200 dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
201 {
202 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
203 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
204
205 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
206
207 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
208 if (dri2_surf->color_buffers[i].bo)
209 gbm_bo_destroy(dri2_surf->color_buffers[i].bo);
210 }
211
212 dri2_egl_surface_free_local_buffers(dri2_surf);
213
214 dri2_fini_surface(surf);
215 free(surf);
216
217 return EGL_TRUE;
218 }
219
220 static int
get_back_bo(struct dri2_egl_surface * dri2_surf)221 get_back_bo(struct dri2_egl_surface *dri2_surf)
222 {
223 struct dri2_egl_display *dri2_dpy =
224 dri2_egl_display(dri2_surf->base.Resource.Display);
225 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
226 int age = 0;
227
228 if (dri2_surf->back == NULL) {
229 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
230 if (!dri2_surf->color_buffers[i].locked &&
231 dri2_surf->color_buffers[i].age >= age) {
232 dri2_surf->back = &dri2_surf->color_buffers[i];
233 age = dri2_surf->color_buffers[i].age;
234 }
235 }
236 }
237
238 if (dri2_surf->back == NULL)
239 return -1;
240 if (dri2_surf->back->bo == NULL) {
241 if (surf->base.v0.modifiers)
242 dri2_surf->back->bo = gbm_bo_create_with_modifiers(
243 &dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
244 surf->base.v0.format, surf->base.v0.modifiers, surf->base.v0.count);
245 else {
246 unsigned flags = surf->base.v0.flags;
247 if (dri2_surf->base.ProtectedContent)
248 flags |= GBM_BO_USE_PROTECTED;
249 dri2_surf->back->bo =
250 gbm_bo_create(&dri2_dpy->gbm_dri->base, surf->base.v0.width,
251 surf->base.v0.height, surf->base.v0.format, flags);
252 }
253 }
254 if (dri2_surf->back->bo == NULL)
255 return -1;
256
257 return 0;
258 }
259
260 static int
get_swrast_front_bo(struct dri2_egl_surface * dri2_surf)261 get_swrast_front_bo(struct dri2_egl_surface *dri2_surf)
262 {
263 struct dri2_egl_display *dri2_dpy =
264 dri2_egl_display(dri2_surf->base.Resource.Display);
265 struct gbm_dri_surface *surf = dri2_surf->gbm_surf;
266
267 if (dri2_surf->current == NULL) {
268 assert(!dri2_surf->color_buffers[0].locked);
269 dri2_surf->current = &dri2_surf->color_buffers[0];
270 }
271
272 if (dri2_surf->current->bo == NULL)
273 dri2_surf->current->bo = gbm_bo_create(
274 &dri2_dpy->gbm_dri->base, surf->base.v0.width, surf->base.v0.height,
275 surf->base.v0.format, surf->base.v0.flags);
276 if (dri2_surf->current->bo == NULL)
277 return -1;
278
279 return 0;
280 }
281
282 static int
dri2_drm_image_get_buffers(__DRIdrawable * driDrawable,unsigned int format,uint32_t * stamp,void * loaderPrivate,uint32_t buffer_mask,struct __DRIimageList * buffers)283 dri2_drm_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
284 uint32_t *stamp, void *loaderPrivate,
285 uint32_t buffer_mask, struct __DRIimageList *buffers)
286 {
287 struct dri2_egl_surface *dri2_surf = loaderPrivate;
288 struct gbm_dri_bo *bo;
289
290 if (get_back_bo(dri2_surf) < 0)
291 return 0;
292
293 bo = gbm_dri_bo(dri2_surf->back->bo);
294 buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
295 buffers->back = bo->image;
296
297 return 1;
298 }
299
300 static void
dri2_drm_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)301 dri2_drm_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
302 {
303 (void)driDrawable;
304 (void)loaderPrivate;
305 }
306
307 static EGLBoolean
dri2_drm_swap_buffers(_EGLDisplay * disp,_EGLSurface * draw)308 dri2_drm_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
309 {
310 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
311 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
312
313 if (!dri2_dpy->flush) {
314 dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
315 return EGL_TRUE;
316 }
317
318 if (dri2_surf->current)
319 _eglError(EGL_BAD_SURFACE, "dri2_swap_buffers");
320 for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
321 if (dri2_surf->color_buffers[i].age > 0)
322 dri2_surf->color_buffers[i].age++;
323
324 /* Flushing must be done before get_back_bo to make sure glthread's
325 * unmarshalling thread is idle otherwise it might concurrently
326 * call get_back_bo (eg: through dri2_drm_image_get_buffers).
327 */
328 dri2_flush_drawable_for_swapbuffers(disp, draw);
329 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
330
331 /* Make sure we have a back buffer in case we're swapping without
332 * ever rendering. */
333 if (get_back_bo(dri2_surf) < 0)
334 return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
335
336 dri2_surf->current = dri2_surf->back;
337 dri2_surf->current->age = 1;
338 dri2_surf->back = NULL;
339
340 return EGL_TRUE;
341 }
342
343 static EGLint
dri2_drm_query_buffer_age(_EGLDisplay * disp,_EGLSurface * surface)344 dri2_drm_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
345 {
346 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
347
348 if (get_back_bo(dri2_surf) < 0) {
349 _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
350 return -1;
351 }
352
353 return dri2_surf->back->age;
354 }
355
356 static _EGLImage *
dri2_drm_create_image_khr_pixmap(_EGLDisplay * disp,_EGLContext * ctx,EGLClientBuffer buffer,const EGLint * attr_list)357 dri2_drm_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,
358 EGLClientBuffer buffer,
359 const EGLint *attr_list)
360 {
361 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
362 struct gbm_dri_bo *dri_bo = gbm_dri_bo((struct gbm_bo *)buffer);
363 struct dri2_egl_image *dri2_img;
364
365 dri2_img = malloc(sizeof *dri2_img);
366 if (!dri2_img) {
367 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
368 return NULL;
369 }
370
371 _eglInitImage(&dri2_img->base, disp);
372
373 dri2_img->dri_image = dri2_dpy->image->dupImage(dri_bo->image, dri2_img);
374 if (dri2_img->dri_image == NULL) {
375 free(dri2_img);
376 _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr_pixmap");
377 return NULL;
378 }
379
380 return &dri2_img->base;
381 }
382
383 static _EGLImage *
dri2_drm_create_image_khr(_EGLDisplay * disp,_EGLContext * ctx,EGLenum target,EGLClientBuffer buffer,const EGLint * attr_list)384 dri2_drm_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,
385 EGLClientBuffer buffer, const EGLint *attr_list)
386 {
387 switch (target) {
388 case EGL_NATIVE_PIXMAP_KHR:
389 return dri2_drm_create_image_khr_pixmap(disp, ctx, buffer, attr_list);
390 default:
391 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
392 }
393 }
394
395 static int
dri2_drm_authenticate(_EGLDisplay * disp,uint32_t id)396 dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id)
397 {
398 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
399
400 return drmAuthMagic(dri2_dpy->fd_render_gpu, id);
401 }
402
403 static void
swrast_put_image2(__DRIdrawable * driDrawable,int op,int x,int y,int width,int height,int stride,char * data,void * loaderPrivate)404 swrast_put_image2(__DRIdrawable *driDrawable, int op, int x, int y, int width,
405 int height, int stride, char *data, void *loaderPrivate)
406 {
407 struct dri2_egl_surface *dri2_surf = loaderPrivate;
408 int internal_stride;
409 struct gbm_dri_bo *bo;
410 uint32_t bpp;
411 int x_bytes, width_bytes;
412 char *src, *dst;
413
414 if (op != __DRI_SWRAST_IMAGE_OP_DRAW && op != __DRI_SWRAST_IMAGE_OP_SWAP)
415 return;
416
417 if (get_swrast_front_bo(dri2_surf) < 0)
418 return;
419
420 bo = gbm_dri_bo(dri2_surf->current->bo);
421
422 bpp = gbm_bo_get_bpp(&bo->base);
423 if (bpp == 0)
424 return;
425
426 x_bytes = x * (bpp >> 3);
427 width_bytes = width * (bpp >> 3);
428
429 if (gbm_dri_bo_map_dumb(bo) == NULL)
430 return;
431
432 internal_stride = bo->base.v0.stride;
433
434 dst = bo->map + x_bytes + (y * internal_stride);
435 src = data;
436
437 for (int i = 0; i < height; i++) {
438 memcpy(dst, src, width_bytes);
439 dst += internal_stride;
440 src += stride;
441 }
442
443 gbm_dri_bo_unmap_dumb(bo);
444 }
445
446 static void
swrast_get_image(__DRIdrawable * driDrawable,int x,int y,int width,int height,char * data,void * loaderPrivate)447 swrast_get_image(__DRIdrawable *driDrawable, int x, int y, int width,
448 int height, char *data, void *loaderPrivate)
449 {
450 struct dri2_egl_surface *dri2_surf = loaderPrivate;
451 int internal_stride, stride;
452 struct gbm_dri_bo *bo;
453 uint32_t bpp;
454 int x_bytes, width_bytes;
455 char *src, *dst;
456
457 if (get_swrast_front_bo(dri2_surf) < 0)
458 return;
459
460 bo = gbm_dri_bo(dri2_surf->current->bo);
461
462 bpp = gbm_bo_get_bpp(&bo->base);
463 if (bpp == 0)
464 return;
465
466 x_bytes = x * (bpp >> 3);
467 width_bytes = width * (bpp >> 3);
468
469 internal_stride = bo->base.v0.stride;
470 stride = width_bytes;
471
472 if (gbm_dri_bo_map_dumb(bo) == NULL)
473 return;
474
475 dst = data;
476 src = bo->map + x_bytes + (y * internal_stride);
477
478 for (int i = 0; i < height; i++) {
479 memcpy(dst, src, width_bytes);
480 dst += stride;
481 src += internal_stride;
482 }
483
484 gbm_dri_bo_unmap_dumb(bo);
485 }
486
487 static void
drm_add_configs_for_visuals(_EGLDisplay * disp)488 drm_add_configs_for_visuals(_EGLDisplay *disp)
489 {
490 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
491 const struct gbm_dri_visual *visuals = dri2_dpy->gbm_dri->visual_table;
492 int num_visuals = dri2_dpy->gbm_dri->num_visuals;
493 unsigned int format_count[num_visuals];
494
495 memset(format_count, 0, num_visuals * sizeof(unsigned int));
496
497 for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
498 const __DRIconfig *config = dri2_dpy->driver_configs[i];
499 struct gl_config *gl_config = (struct gl_config *) config;
500
501 for (unsigned j = 0; j < num_visuals; j++) {
502 struct dri2_egl_config *dri2_conf;
503
504 if (visuals[j].dri_image_format != gl_config->color_format)
505 continue;
506
507 const EGLint attr_list[] = {
508 EGL_NATIVE_VISUAL_ID,
509 visuals[j].gbm_format,
510 EGL_NONE,
511 };
512
513 dri2_conf =
514 dri2_add_config(disp, dri2_dpy->driver_configs[i], EGL_WINDOW_BIT,
515 attr_list);
516 if (dri2_conf)
517 format_count[j]++;
518 }
519 }
520
521 for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
522 if (!format_count[i]) {
523 struct gbm_format_name_desc desc;
524 _eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
525 gbm_format_get_name(visuals[i].gbm_format, &desc));
526 }
527 }
528 }
529
530 static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
531 .authenticate = dri2_drm_authenticate,
532 .create_window_surface = dri2_drm_create_window_surface,
533 .create_pixmap_surface = dri2_drm_create_pixmap_surface,
534 .destroy_surface = dri2_drm_destroy_surface,
535 .create_image = dri2_drm_create_image_khr,
536 .swap_buffers = dri2_drm_swap_buffers,
537 .query_buffer_age = dri2_drm_query_buffer_age,
538 .get_dri_drawable = dri2_surface_get_dri_drawable,
539 };
540
541 static int
get_fd_render_gpu_drm(struct gbm_dri_device * gbm_dri,int fd_display_gpu)542 get_fd_render_gpu_drm(struct gbm_dri_device *gbm_dri, int fd_display_gpu)
543 {
544 /* This doesn't make sense for the software case. */
545 assert(!gbm_dri->software);
546
547 /* Render-capable device, so just return the same fd. */
548 if (loader_is_device_render_capable(fd_display_gpu))
549 return fd_display_gpu;
550
551 /* Display-only device, so return a compatible render-only device. */
552 return gbm_dri->mesa->queryCompatibleRenderOnlyDeviceFd(fd_display_gpu);
553 }
554
555 EGLBoolean
dri2_initialize_drm(_EGLDisplay * disp)556 dri2_initialize_drm(_EGLDisplay *disp)
557 {
558 struct gbm_device *gbm;
559 const char *err;
560 struct dri2_egl_display *dri2_dpy = dri2_display_create();
561 if (!dri2_dpy)
562 return EGL_FALSE;
563
564 disp->DriverData = (void *)dri2_dpy;
565
566 gbm = disp->PlatformDisplay;
567 if (gbm == NULL) {
568 if (disp->Device) {
569 drmDevicePtr drm = _eglDeviceDrm(disp->Device);
570
571 if (!_eglDeviceSupports(disp->Device, _EGL_DEVICE_DRM)) {
572 err = "DRI2: Device isn't of _EGL_DEVICE_DRM type";
573 goto cleanup;
574 }
575
576 if (!(drm->available_nodes & (1 << DRM_NODE_PRIMARY))) {
577 err = "DRI2: Device does not have DRM_NODE_PRIMARY node";
578 goto cleanup;
579 }
580
581 dri2_dpy->fd_display_gpu =
582 loader_open_device(drm->nodes[DRM_NODE_PRIMARY]);
583 } else {
584 char buf[64];
585 int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0);
586 if (n != -1 && n < sizeof(buf))
587 dri2_dpy->fd_display_gpu = loader_open_device(buf);
588 }
589
590 gbm = gbm_create_device(dri2_dpy->fd_display_gpu);
591 if (gbm == NULL) {
592 err = "DRI2: failed to create gbm device";
593 goto cleanup;
594 }
595 dri2_dpy->own_device = true;
596 } else {
597 dri2_dpy->fd_display_gpu = os_dupfd_cloexec(gbm_device_get_fd(gbm));
598 if (dri2_dpy->fd_display_gpu < 0) {
599 err = "DRI2: failed to fcntl() existing gbm device";
600 goto cleanup;
601 }
602 }
603 dri2_dpy->gbm_dri = gbm_dri_device(gbm);
604 if (!dri2_dpy->gbm_dri->software) {
605 dri2_dpy->fd_render_gpu =
606 get_fd_render_gpu_drm(dri2_dpy->gbm_dri, dri2_dpy->fd_display_gpu);
607 if (dri2_dpy->fd_render_gpu < 0) {
608 err = "DRI2: failed to get compatible render device";
609 goto cleanup;
610 }
611 }
612
613 if (strcmp(gbm_device_get_backend_name(gbm), "drm") != 0) {
614 err = "DRI2: gbm device using incorrect/incompatible backend";
615 goto cleanup;
616 }
617
618 dri2_dpy->driver_name = strdup(dri2_dpy->gbm_dri->driver_name);
619
620 if (!dri2_load_driver_dri3(disp)) {
621 err = "DRI3: failed to load driver";
622 goto cleanup;
623 }
624
625 dri2_dpy->dri_screen_render_gpu = dri2_dpy->gbm_dri->screen;
626 dri2_dpy->core = dri2_dpy->gbm_dri->core;
627 dri2_dpy->image_driver = dri2_dpy->gbm_dri->image_driver;
628 dri2_dpy->swrast = dri2_dpy->gbm_dri->swrast;
629 dri2_dpy->kopper = dri2_dpy->gbm_dri->kopper;
630 dri2_dpy->driver_configs = dri2_dpy->gbm_dri->driver_configs;
631
632 dri2_dpy->gbm_dri->lookup_image = dri2_lookup_egl_image;
633 dri2_dpy->gbm_dri->validate_image = dri2_validate_egl_image;
634 dri2_dpy->gbm_dri->lookup_image_validated = dri2_lookup_egl_image_validated;
635 dri2_dpy->gbm_dri->lookup_user_data = disp;
636
637 dri2_dpy->gbm_dri->flush_front_buffer = dri2_drm_flush_front_buffer;
638 dri2_dpy->gbm_dri->image_get_buffers = dri2_drm_image_get_buffers;
639 dri2_dpy->gbm_dri->swrast_put_image2 = swrast_put_image2;
640 dri2_dpy->gbm_dri->swrast_get_image = swrast_get_image;
641
642 dri2_dpy->gbm_dri->base.v0.surface_lock_front_buffer = lock_front_buffer;
643 dri2_dpy->gbm_dri->base.v0.surface_release_buffer = release_buffer;
644 dri2_dpy->gbm_dri->base.v0.surface_has_free_buffers = has_free_buffers;
645
646 if (!dri2_setup_extensions(disp)) {
647 err = "DRI2: failed to find required DRI extensions";
648 goto cleanup;
649 }
650
651 if (!dri2_setup_device(disp, dri2_dpy->gbm_dri->software)) {
652 err = "DRI2: failed to setup EGLDevice";
653 goto cleanup;
654 }
655
656 dri2_setup_screen(disp);
657
658 drm_add_configs_for_visuals(disp);
659
660 disp->Extensions.KHR_image_pixmap = EGL_TRUE;
661 if (dri2_dpy->image_driver)
662 disp->Extensions.EXT_buffer_age = EGL_TRUE;
663
664 #ifdef HAVE_WAYLAND_PLATFORM
665 dri2_dpy->device_name =
666 loader_get_device_name_for_fd(dri2_dpy->fd_render_gpu);
667 #endif
668 dri2_set_WL_bind_wayland_display(disp);
669
670 /* Fill vtbl last to prevent accidentally calling virtual function during
671 * initialization.
672 */
673 dri2_dpy->vtbl = &dri2_drm_display_vtbl;
674
675 return EGL_TRUE;
676
677 cleanup:
678 dri2_display_destroy(disp);
679 return _eglError(EGL_NOT_INITIALIZED, err);
680 }
681
682 void
dri2_teardown_drm(struct dri2_egl_display * dri2_dpy)683 dri2_teardown_drm(struct dri2_egl_display *dri2_dpy)
684 {
685 if (dri2_dpy->own_device)
686 gbm_device_destroy(&dri2_dpy->gbm_dri->base);
687 }
688