1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (c) 2014 The Chromium OS Authors.
5bf215546Sopenharmony_ci * Copyright © 2011 Intel Corporation
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <stdlib.h>
27bf215546Sopenharmony_ci#include <stdio.h>
28bf215546Sopenharmony_ci#include <string.h>
29bf215546Sopenharmony_ci#include <xf86drm.h>
30bf215546Sopenharmony_ci#include <dlfcn.h>
31bf215546Sopenharmony_ci#include <sys/types.h>
32bf215546Sopenharmony_ci#include <sys/stat.h>
33bf215546Sopenharmony_ci#include <fcntl.h>
34bf215546Sopenharmony_ci#include <unistd.h>
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "egl_dri2.h"
37bf215546Sopenharmony_ci#include "loader.h"
38bf215546Sopenharmony_ci#include "kopper_interface.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cistatic __DRIimage*
41bf215546Sopenharmony_cisurfaceless_alloc_image(struct dri2_egl_display *dri2_dpy,
42bf215546Sopenharmony_ci                     struct dri2_egl_surface *dri2_surf)
43bf215546Sopenharmony_ci{
44bf215546Sopenharmony_ci   return dri2_dpy->image->createImage(
45bf215546Sopenharmony_ci            dri2_dpy->dri_screen,
46bf215546Sopenharmony_ci            dri2_surf->base.Width,
47bf215546Sopenharmony_ci            dri2_surf->base.Height,
48bf215546Sopenharmony_ci            dri2_surf->visual,
49bf215546Sopenharmony_ci            0,
50bf215546Sopenharmony_ci            NULL);
51bf215546Sopenharmony_ci}
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_cistatic void
54bf215546Sopenharmony_cisurfaceless_free_images(struct dri2_egl_surface *dri2_surf)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy =
57bf215546Sopenharmony_ci      dri2_egl_display(dri2_surf->base.Resource.Display);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   if (dri2_surf->front) {
60bf215546Sopenharmony_ci      dri2_dpy->image->destroyImage(dri2_surf->front);
61bf215546Sopenharmony_ci      dri2_surf->front = NULL;
62bf215546Sopenharmony_ci   }
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   free(dri2_surf->swrast_device_buffer);
65bf215546Sopenharmony_ci   dri2_surf->swrast_device_buffer = NULL;
66bf215546Sopenharmony_ci}
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_cistatic int
69bf215546Sopenharmony_cisurfaceless_image_get_buffers(__DRIdrawable *driDrawable,
70bf215546Sopenharmony_ci                        unsigned int format,
71bf215546Sopenharmony_ci                        uint32_t *stamp,
72bf215546Sopenharmony_ci                        void *loaderPrivate,
73bf215546Sopenharmony_ci                        uint32_t buffer_mask,
74bf215546Sopenharmony_ci                        struct __DRIimageList *buffers)
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci   struct dri2_egl_surface *dri2_surf = loaderPrivate;
77bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy =
78bf215546Sopenharmony_ci      dri2_egl_display(dri2_surf->base.Resource.Display);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   buffers->image_mask = 0;
81bf215546Sopenharmony_ci   buffers->front = NULL;
82bf215546Sopenharmony_ci   buffers->back = NULL;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
85bf215546Sopenharmony_ci    * the spec states that they have a back buffer but no front buffer, in
86bf215546Sopenharmony_ci    * contrast to pixmaps, which have a front buffer but no back buffer.
87bf215546Sopenharmony_ci    *
88bf215546Sopenharmony_ci    * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
89bf215546Sopenharmony_ci    * from the spec, following the precedent of Mesa's EGL X11 platform. The
90bf215546Sopenharmony_ci    * X11 platform correctly assigns pbuffers to single-buffered configs, but
91bf215546Sopenharmony_ci    * assigns the pbuffer a front buffer instead of a back buffer.
92bf215546Sopenharmony_ci    *
93bf215546Sopenharmony_ci    * Pbuffers in the X11 platform mostly work today, so let's just copy its
94bf215546Sopenharmony_ci    * behavior instead of trying to fix (and hence potentially breaking) the
95bf215546Sopenharmony_ci    * world.
96bf215546Sopenharmony_ci    */
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci      if (!dri2_surf->front)
101bf215546Sopenharmony_ci         dri2_surf->front =
102bf215546Sopenharmony_ci            surfaceless_alloc_image(dri2_dpy, dri2_surf);
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci      buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
105bf215546Sopenharmony_ci      buffers->front = dri2_surf->front;
106bf215546Sopenharmony_ci   }
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   return 1;
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_cistatic _EGLSurface *
112bf215546Sopenharmony_cidri2_surfaceless_create_surface(_EGLDisplay *disp, EGLint type,
113bf215546Sopenharmony_ci                                _EGLConfig *conf, const EGLint *attrib_list)
114bf215546Sopenharmony_ci{
115bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
116bf215546Sopenharmony_ci   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
117bf215546Sopenharmony_ci   struct dri2_egl_surface *dri2_surf;
118bf215546Sopenharmony_ci   const __DRIconfig *config;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   /* Make sure to calloc so all pointers
121bf215546Sopenharmony_ci    * are originally NULL.
122bf215546Sopenharmony_ci    */
123bf215546Sopenharmony_ci   dri2_surf = calloc(1, sizeof *dri2_surf);
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   if (!dri2_surf) {
126bf215546Sopenharmony_ci      _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
127bf215546Sopenharmony_ci      return NULL;
128bf215546Sopenharmony_ci   }
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
131bf215546Sopenharmony_ci                          false, NULL))
132bf215546Sopenharmony_ci      goto cleanup_surface;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   config = dri2_get_dri_config(dri2_conf, type,
135bf215546Sopenharmony_ci                                dri2_surf->base.GLColorspace);
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   if (!config) {
138bf215546Sopenharmony_ci      _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
139bf215546Sopenharmony_ci      goto cleanup_surface;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   dri2_surf->visual = dri2_image_format_for_pbuffer_config(dri2_dpy, config);
143bf215546Sopenharmony_ci   if (dri2_surf->visual == __DRI_IMAGE_FORMAT_NONE)
144bf215546Sopenharmony_ci      goto cleanup_surface;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
147bf215546Sopenharmony_ci      goto cleanup_surface;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   return &dri2_surf->base;
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   cleanup_surface:
152bf215546Sopenharmony_ci      free(dri2_surf);
153bf215546Sopenharmony_ci      return NULL;
154bf215546Sopenharmony_ci}
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_cistatic EGLBoolean
157bf215546Sopenharmony_cisurfaceless_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
160bf215546Sopenharmony_ci   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci   surfaceless_free_images(dri2_surf);
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   dri2_fini_surface(surf);
167bf215546Sopenharmony_ci   free(dri2_surf);
168bf215546Sopenharmony_ci   return EGL_TRUE;
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_cistatic _EGLSurface *
172bf215546Sopenharmony_cidri2_surfaceless_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,
173bf215546Sopenharmony_ci                                        const EGLint *attrib_list)
174bf215546Sopenharmony_ci{
175bf215546Sopenharmony_ci   return dri2_surfaceless_create_surface(disp, EGL_PBUFFER_BIT, conf,
176bf215546Sopenharmony_ci                                  attrib_list);
177bf215546Sopenharmony_ci}
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_cistatic const struct dri2_egl_display_vtbl dri2_surfaceless_display_vtbl = {
180bf215546Sopenharmony_ci   .create_pbuffer_surface = dri2_surfaceless_create_pbuffer_surface,
181bf215546Sopenharmony_ci   .destroy_surface = surfaceless_destroy_surface,
182bf215546Sopenharmony_ci   .create_image = dri2_create_image_khr,
183bf215546Sopenharmony_ci   .get_dri_drawable = dri2_surface_get_dri_drawable,
184bf215546Sopenharmony_ci};
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_cistatic void
187bf215546Sopenharmony_cisurfaceless_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
188bf215546Sopenharmony_ci{
189bf215546Sopenharmony_ci}
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_cistatic unsigned
192bf215546Sopenharmony_cisurfaceless_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
193bf215546Sopenharmony_ci{
194bf215546Sopenharmony_ci   /* Note: loaderPrivate is _EGLDisplay* */
195bf215546Sopenharmony_ci   switch (cap) {
196bf215546Sopenharmony_ci   case DRI_LOADER_CAP_FP16:
197bf215546Sopenharmony_ci      return 1;
198bf215546Sopenharmony_ci   default:
199bf215546Sopenharmony_ci      return 0;
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci}
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_cistatic const __DRIkopperLoaderExtension kopper_loader_extension = {
204bf215546Sopenharmony_ci    .base = { __DRI_KOPPER_LOADER, 1 },
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci    .SetSurfaceCreateInfo   = NULL,
207bf215546Sopenharmony_ci};
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_cistatic const __DRIimageLoaderExtension image_loader_extension = {
210bf215546Sopenharmony_ci   .base             = { __DRI_IMAGE_LOADER, 2 },
211bf215546Sopenharmony_ci   .getBuffers       = surfaceless_image_get_buffers,
212bf215546Sopenharmony_ci   .flushFrontBuffer = surfaceless_flush_front_buffer,
213bf215546Sopenharmony_ci   .getCapability    = surfaceless_get_capability,
214bf215546Sopenharmony_ci};
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_cistatic const __DRIextension *image_loader_extensions[] = {
217bf215546Sopenharmony_ci   &image_loader_extension.base,
218bf215546Sopenharmony_ci   &image_lookup_extension.base,
219bf215546Sopenharmony_ci   &use_invalidate.base,
220bf215546Sopenharmony_ci   &background_callable_extension.base,
221bf215546Sopenharmony_ci   &kopper_loader_extension.base,
222bf215546Sopenharmony_ci   NULL,
223bf215546Sopenharmony_ci};
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_cistatic const __DRIextension *swrast_loader_extensions[] = {
226bf215546Sopenharmony_ci   &swrast_pbuffer_loader_extension.base,
227bf215546Sopenharmony_ci   &image_loader_extension.base,
228bf215546Sopenharmony_ci   &image_lookup_extension.base,
229bf215546Sopenharmony_ci   &use_invalidate.base,
230bf215546Sopenharmony_ci   &kopper_loader_extension.base,
231bf215546Sopenharmony_ci   NULL,
232bf215546Sopenharmony_ci};
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_cistatic bool
235bf215546Sopenharmony_cisurfaceless_probe_device(_EGLDisplay *disp, bool swrast)
236bf215546Sopenharmony_ci{
237bf215546Sopenharmony_ci#define MAX_DRM_DEVICES 64
238bf215546Sopenharmony_ci   const unsigned node_type = swrast ? DRM_NODE_PRIMARY : DRM_NODE_RENDER;
239bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
240bf215546Sopenharmony_ci   drmDevicePtr device, devices[MAX_DRM_DEVICES] = { NULL };
241bf215546Sopenharmony_ci   int i, num_devices;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
244bf215546Sopenharmony_ci   if (num_devices < 0)
245bf215546Sopenharmony_ci      return false;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   for (i = 0; i < num_devices; ++i) {
248bf215546Sopenharmony_ci      device = devices[i];
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci      if (!(device->available_nodes & (1 << node_type)))
251bf215546Sopenharmony_ci         continue;
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci      dri2_dpy->fd = loader_open_device(device->nodes[node_type]);
254bf215546Sopenharmony_ci      if (dri2_dpy->fd < 0)
255bf215546Sopenharmony_ci         continue;
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci      disp->Device = _eglAddDevice(dri2_dpy->fd, swrast);
258bf215546Sopenharmony_ci      if (!disp->Device) {
259bf215546Sopenharmony_ci         close(dri2_dpy->fd);
260bf215546Sopenharmony_ci         dri2_dpy->fd = -1;
261bf215546Sopenharmony_ci         continue;
262bf215546Sopenharmony_ci      }
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci      char *driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
265bf215546Sopenharmony_ci      if (swrast) {
266bf215546Sopenharmony_ci         /* Use kms swrast only with vgem / virtio_gpu.
267bf215546Sopenharmony_ci          * virtio-gpu fallbacks to software rendering when 3D features
268bf215546Sopenharmony_ci          * are unavailable since 6c5ab, and kms_swrast is more
269bf215546Sopenharmony_ci          * feature complete than swrast.
270bf215546Sopenharmony_ci          */
271bf215546Sopenharmony_ci         if (driver_name &&
272bf215546Sopenharmony_ci             (strcmp(driver_name, "vgem") == 0 ||
273bf215546Sopenharmony_ci              strcmp(driver_name, "virtio_gpu") == 0))
274bf215546Sopenharmony_ci            dri2_dpy->driver_name = strdup("kms_swrast");
275bf215546Sopenharmony_ci         free(driver_name);
276bf215546Sopenharmony_ci      } else {
277bf215546Sopenharmony_ci         /* Use the given hardware driver */
278bf215546Sopenharmony_ci         dri2_dpy->driver_name = driver_name;
279bf215546Sopenharmony_ci      }
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci      if (dri2_dpy->driver_name && dri2_load_driver_dri3(disp))
282bf215546Sopenharmony_ci         break;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci      free(dri2_dpy->driver_name);
285bf215546Sopenharmony_ci      dri2_dpy->driver_name = NULL;
286bf215546Sopenharmony_ci      close(dri2_dpy->fd);
287bf215546Sopenharmony_ci      dri2_dpy->fd = -1;
288bf215546Sopenharmony_ci   }
289bf215546Sopenharmony_ci   drmFreeDevices(devices, num_devices);
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   if (i == num_devices)
292bf215546Sopenharmony_ci      return false;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   if (swrast)
295bf215546Sopenharmony_ci      dri2_dpy->loader_extensions = swrast_loader_extensions;
296bf215546Sopenharmony_ci   else
297bf215546Sopenharmony_ci      dri2_dpy->loader_extensions = image_loader_extensions;
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   return true;
300bf215546Sopenharmony_ci}
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_cistatic bool
303bf215546Sopenharmony_cisurfaceless_probe_device_sw(_EGLDisplay *disp)
304bf215546Sopenharmony_ci{
305bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   dri2_dpy->fd = -1;
308bf215546Sopenharmony_ci   disp->Device = _eglAddDevice(dri2_dpy->fd, true);
309bf215546Sopenharmony_ci   assert(disp->Device);
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   dri2_dpy->driver_name = strdup(disp->Options.Zink ? "zink" : "swrast");
312bf215546Sopenharmony_ci   if (!dri2_dpy->driver_name)
313bf215546Sopenharmony_ci      return false;
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   if (!dri2_load_driver_swrast(disp)) {
316bf215546Sopenharmony_ci      free(dri2_dpy->driver_name);
317bf215546Sopenharmony_ci      dri2_dpy->driver_name = NULL;
318bf215546Sopenharmony_ci      return false;
319bf215546Sopenharmony_ci   }
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   dri2_dpy->loader_extensions = swrast_loader_extensions;
322bf215546Sopenharmony_ci   return true;
323bf215546Sopenharmony_ci}
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ciEGLBoolean
326bf215546Sopenharmony_cidri2_initialize_surfaceless(_EGLDisplay *disp)
327bf215546Sopenharmony_ci{
328bf215546Sopenharmony_ci   struct dri2_egl_display *dri2_dpy;
329bf215546Sopenharmony_ci   const char* err;
330bf215546Sopenharmony_ci   bool driver_loaded = false;
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   dri2_dpy = calloc(1, sizeof *dri2_dpy);
333bf215546Sopenharmony_ci   if (!dri2_dpy)
334bf215546Sopenharmony_ci      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   dri2_dpy->fd = -1;
337bf215546Sopenharmony_ci   disp->DriverData = (void *) dri2_dpy;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci   /* When ForceSoftware is false, we try the HW driver.  When ForceSoftware
340bf215546Sopenharmony_ci    * is true, we try kms_swrast and swrast in order.
341bf215546Sopenharmony_ci    */
342bf215546Sopenharmony_ci   driver_loaded = surfaceless_probe_device(disp, disp->Options.ForceSoftware);
343bf215546Sopenharmony_ci   if (!driver_loaded && disp->Options.ForceSoftware) {
344bf215546Sopenharmony_ci      _eglLog(_EGL_DEBUG, "Falling back to surfaceless swrast without DRM.");
345bf215546Sopenharmony_ci      driver_loaded = surfaceless_probe_device_sw(disp);
346bf215546Sopenharmony_ci   }
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   if (!driver_loaded) {
349bf215546Sopenharmony_ci      err = "DRI2: failed to load driver";
350bf215546Sopenharmony_ci      goto cleanup;
351bf215546Sopenharmony_ci   }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   if (!dri2_create_screen(disp)) {
354bf215546Sopenharmony_ci      err = "DRI2: failed to create screen";
355bf215546Sopenharmony_ci      goto cleanup;
356bf215546Sopenharmony_ci   }
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   if (!dri2_setup_extensions(disp)) {
359bf215546Sopenharmony_ci      err = "DRI2: failed to find required DRI extensions";
360bf215546Sopenharmony_ci      goto cleanup;
361bf215546Sopenharmony_ci   }
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   dri2_setup_screen(disp);
364bf215546Sopenharmony_ci#ifdef HAVE_WAYLAND_PLATFORM
365bf215546Sopenharmony_ci   dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
366bf215546Sopenharmony_ci#endif
367bf215546Sopenharmony_ci   dri2_set_WL_bind_wayland_display(disp);
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   if (!dri2_add_pbuffer_configs_for_visuals(disp)) {
370bf215546Sopenharmony_ci      err = "DRI2: failed to add configs";
371bf215546Sopenharmony_ci      goto cleanup;
372bf215546Sopenharmony_ci   }
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   /* Fill vtbl last to prevent accidentally calling virtual function during
375bf215546Sopenharmony_ci    * initialization.
376bf215546Sopenharmony_ci    */
377bf215546Sopenharmony_ci   dri2_dpy->vtbl = &dri2_surfaceless_display_vtbl;
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   return EGL_TRUE;
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_cicleanup:
382bf215546Sopenharmony_ci   dri2_display_destroy(disp);
383bf215546Sopenharmony_ci   return _eglError(EGL_NOT_INITIALIZED, err);
384bf215546Sopenharmony_ci}
385