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