xref: /aosp_15_r20/external/mesa3d/src/glx/dri3_glx.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2013 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 /*
24  * Portions of this code were adapted from dri2_glx.c which carries the
25  * following copyright:
26  *
27  * Copyright © 2008 Red Hat, Inc.
28  *
29  * Permission is hereby granted, free of charge, to any person obtaining a
30  * copy of this software and associated documentation files (the "Soft-
31  * ware"), to deal in the Software without restriction, including without
32  * limitation the rights to use, copy, modify, merge, publish, distribute,
33  * and/or sell copies of the Software, and to permit persons to whom the
34  * Software is furnished to do so, provided that the above copyright
35  * notice(s) and this permission notice appear in all copies of the Soft-
36  * ware and that both the above copyright notice(s) and this permission
37  * notice appear in supporting documentation.
38  *
39  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
41  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
42  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
43  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
44  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
45  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
46  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
47  * MANCE OF THIS SOFTWARE.
48  *
49  * Except as contained in this notice, the name of a copyright holder shall
50  * not be used in advertising or otherwise to promote the sale, use or
51  * other dealings in this Software without prior written authorization of
52  * the copyright holder.
53  *
54  * Authors:
55  *   Kristian Høgsberg ([email protected])
56  */
57 
58 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
59 
60 #include <X11/Xlib.h>
61 #include <X11/extensions/Xfixes.h>
62 #include <X11/Xlib-xcb.h>
63 #include <X11/xshmfence.h>
64 #include <xcb/xcb.h>
65 #include <xcb/dri3.h>
66 #include <xcb/present.h>
67 #include <GL/gl.h>
68 #include "glxclient.h"
69 #include <dlfcn.h>
70 #include <fcntl.h>
71 #include <unistd.h>
72 #include <sys/types.h>
73 #include <sys/mman.h>
74 #include <sys/time.h>
75 
76 #include "dri_common.h"
77 #include "dri3_priv.h"
78 #include "loader.h"
79 #include "loader_x11.h"
80 #include "loader_dri_helper.h"
81 #include "dri2.h"
82 #include "util/u_debug.h"
83 #include "dri_util.h"
84 
85 static struct dri3_drawable *
loader_drawable_to_dri3_drawable(struct loader_dri3_drawable * draw)86 loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) {
87    size_t offset = offsetof(struct dri3_drawable, loader_drawable);
88    if (!draw)
89       return NULL;
90    return (struct dri3_drawable *)(((void*) draw) - offset);
91 }
92 
93 static void
glx_dri3_set_drawable_size(struct loader_dri3_drawable * draw,int width,int height)94 glx_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
95                            int width, int height)
96 {
97    /* Nothing to do */
98 }
99 
100 static bool
glx_dri3_in_current_context(struct loader_dri3_drawable * draw)101 glx_dri3_in_current_context(struct loader_dri3_drawable *draw)
102 {
103    struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw);
104 
105    if (!priv)
106       return false;
107 
108    struct glx_context *pcp = __glXGetCurrentContext();
109    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
110 
111    return (pcp != &dummyContext) && pcp->psc == &psc->base;
112 }
113 
114 static __DRIcontext *
glx_dri3_get_dri_context(struct loader_dri3_drawable * draw)115 glx_dri3_get_dri_context(struct loader_dri3_drawable *draw)
116 {
117    struct glx_context *gc = __glXGetCurrentContext();
118 
119    return (gc != &dummyContext) ? gc->driContext : NULL;
120 }
121 
122 static __DRIscreen *
glx_dri3_get_dri_screen(void)123 glx_dri3_get_dri_screen(void)
124 {
125    struct glx_context *gc = __glXGetCurrentContext();
126    struct dri3_screen *psc = (struct dri3_screen *) gc->psc;
127 
128    return (gc != &dummyContext && psc) ? psc->base.frontend_screen : NULL;
129 }
130 
131 static void
glx_dri3_flush_drawable(struct loader_dri3_drawable * draw,unsigned flags)132 glx_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
133 {
134    loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER);
135 }
136 
137 static const struct loader_dri3_vtable glx_dri3_vtable = {
138    .set_drawable_size = glx_dri3_set_drawable_size,
139    .in_current_context = glx_dri3_in_current_context,
140    .get_dri_context = glx_dri3_get_dri_context,
141    .get_dri_screen = glx_dri3_get_dri_screen,
142    .flush_drawable = glx_dri3_flush_drawable,
143 };
144 
145 
146 static const struct glx_context_vtable dri3_context_vtable;
147 
148 static void
dri3_destroy_drawable(__GLXDRIdrawable * base)149 dri3_destroy_drawable(__GLXDRIdrawable *base)
150 {
151    struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
152 
153    loader_dri3_drawable_fini(&pdraw->loader_drawable);
154 
155    free(pdraw);
156 }
157 
158 static enum loader_dri3_drawable_type
glx_to_loader_dri3_drawable_type(int type)159 glx_to_loader_dri3_drawable_type(int type)
160 {
161    switch (type) {
162    case GLX_WINDOW_BIT:
163       return LOADER_DRI3_DRAWABLE_WINDOW;
164    case GLX_PIXMAP_BIT:
165       return LOADER_DRI3_DRAWABLE_PIXMAP;
166    case GLX_PBUFFER_BIT:
167       return LOADER_DRI3_DRAWABLE_PBUFFER;
168    default:
169       return LOADER_DRI3_DRAWABLE_UNKNOWN;
170    }
171 }
172 
173 static __GLXDRIdrawable *
dri3_create_drawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * config_base)174 dri3_create_drawable(struct glx_screen *base, XID xDrawable,
175                      GLXDrawable drawable, int type,
176                      struct glx_config *config_base)
177 {
178    struct dri3_drawable *pdraw;
179    struct dri3_screen *psc = (struct dri3_screen *) base;
180    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
181    bool has_multibuffer = false;
182 
183    pdraw = calloc(1, sizeof(*pdraw));
184    if (!pdraw)
185       return NULL;
186 
187    pdraw->base.destroyDrawable = dri3_destroy_drawable;
188    pdraw->base.xDrawable = xDrawable;
189    pdraw->base.drawable = drawable;
190    pdraw->base.psc = &psc->base;
191 
192 #ifdef HAVE_X11_DRM
193    has_multibuffer = base->display->has_multibuffer;
194 #endif
195 
196    (void) __glXInitialize(psc->base.dpy);
197 
198    if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy),
199                                  xDrawable,
200                                  glx_to_loader_dri3_drawable_type(type),
201                                  psc->base.frontend_screen, psc->driScreenDisplayGPU,
202                                  has_multibuffer,
203                                  psc->prefer_back_buffer_reuse,
204                                  config->driConfig,
205                                  &glx_dri3_vtable,
206                                  &pdraw->loader_drawable)) {
207       free(pdraw);
208       return NULL;
209    }
210 
211    pdraw->base.dri_drawable = pdraw->loader_drawable.dri_drawable;
212 
213    return &pdraw->base;
214 }
215 
216 /** dri3_wait_for_msc
217  *
218  * Get the X server to send an event when the target msc/divisor/remainder is
219  * reached.
220  */
221 static int
dri3_wait_for_msc(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,int64_t * ust,int64_t * msc,int64_t * sbc)222 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
223                   int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
224 {
225    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
226 
227    loader_dri3_wait_for_msc(&priv->loader_drawable, target_msc, divisor,
228                             remainder, ust, msc, sbc);
229 
230    return 1;
231 }
232 
233 /** dri3_drawable_get_msc
234  *
235  * Return the current UST/MSC/SBC triplet by asking the server
236  * for an event
237  */
238 static int
dri3_drawable_get_msc(struct glx_screen * psc,__GLXDRIdrawable * pdraw,int64_t * ust,int64_t * msc,int64_t * sbc)239 dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
240                       int64_t *ust, int64_t *msc, int64_t *sbc)
241 {
242    return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
243 }
244 
245 /** dri3_wait_for_sbc
246  *
247  * Wait for the completed swap buffer count to reach the specified
248  * target. Presumably the application knows that this will be reached with
249  * outstanding complete events, or we're going to be here awhile.
250  */
251 static int
dri3_wait_for_sbc(__GLXDRIdrawable * pdraw,int64_t target_sbc,int64_t * ust,int64_t * msc,int64_t * sbc)252 dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
253                   int64_t *msc, int64_t *sbc)
254 {
255    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
256 
257    return loader_dri3_wait_for_sbc(&priv->loader_drawable, target_sbc,
258                                    ust, msc, sbc);
259 }
260 
261 static void
dri3_copy_sub_buffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)262 dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
263                      int width, int height,
264                      Bool flush)
265 {
266    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
267 
268    loader_dri3_copy_sub_buffer(&priv->loader_drawable, x, y,
269                                width, height, flush);
270 }
271 
272 static void
dri3_wait_x(struct glx_context * gc)273 dri3_wait_x(struct glx_context *gc)
274 {
275    struct dri3_drawable *priv = (struct dri3_drawable *)
276       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
277 
278    if (priv)
279       loader_dri3_wait_x(&priv->loader_drawable);
280 }
281 
282 static void
dri3_wait_gl(struct glx_context * gc)283 dri3_wait_gl(struct glx_context *gc)
284 {
285    struct dri3_drawable *priv = (struct dri3_drawable *)
286       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
287 
288    if (priv)
289       loader_dri3_wait_gl(&priv->loader_drawable);
290 }
291 
292 /**
293  * Called by the driver when it needs to update the real front buffer with the
294  * contents of its fake front buffer.
295  */
296 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)297 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
298 {
299    struct loader_dri3_drawable *draw = loaderPrivate;
300    struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw);
301    struct dri3_screen *psc;
302 
303    if (!pdraw)
304       return;
305 
306    if (!pdraw->base.psc)
307       return;
308 
309    psc = (struct dri3_screen *) pdraw->base.psc;
310 
311    (void) __glXInitialize(psc->base.dpy);
312 
313    loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
314 
315    dri_invalidate_drawable(driDrawable);
316    loader_dri3_wait_gl(draw);
317 }
318 
319 /**
320  * Make sure all pending swapbuffers have been submitted to hardware
321  *
322  * \param driDrawable[in]  Pointer to the dri drawable whose swaps we are
323  * flushing.
324  * \param loaderPrivate[in]  Pointer to the corresponding struct
325  * loader_dri_drawable.
326  */
327 static void
dri3_flush_swap_buffers(__DRIdrawable * driDrawable,void * loaderPrivate)328 dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate)
329 {
330    struct loader_dri3_drawable *draw = loaderPrivate;
331    struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw);
332    struct dri3_screen *psc;
333 
334    if (!pdraw)
335       return;
336 
337    if (!pdraw->base.psc)
338       return;
339 
340    psc = (struct dri3_screen *) pdraw->base.psc;
341 
342    (void) __glXInitialize(psc->base.dpy);
343    loader_dri3_swapbuffer_barrier(draw);
344 }
345 
346 static void
dri_set_background_context(void * loaderPrivate)347 dri_set_background_context(void *loaderPrivate)
348 {
349    __glXSetCurrentContext(loaderPrivate);
350 }
351 
352 static GLboolean
dri_is_thread_safe(void * loaderPrivate)353 dri_is_thread_safe(void *loaderPrivate)
354 {
355    /* Unlike DRI2, DRI3 doesn't call GetBuffers/GetBuffersWithFormat
356     * during draw so we're safe here.
357     */
358    return true;
359 }
360 
361 /* The image loader extension record for DRI3
362  */
363 static const __DRIimageLoaderExtension imageLoaderExtension = {
364    .base = { __DRI_IMAGE_LOADER, 3 },
365 
366    .getBuffers          = loader_dri3_get_buffers,
367    .flushFrontBuffer    = dri3_flush_front_buffer,
368    .flushSwapBuffers    = dri3_flush_swap_buffers,
369 };
370 
371 const __DRIuseInvalidateExtension dri3UseInvalidate = {
372    .base = { __DRI_USE_INVALIDATE, 1 }
373 };
374 
375 static const __DRIbackgroundCallableExtension dri3BackgroundCallable = {
376    .base = { __DRI_BACKGROUND_CALLABLE, 2 },
377 
378    .setBackgroundContext = dri_set_background_context,
379    .isThreadSafe         = dri_is_thread_safe,
380 };
381 
382 static const __DRIextension *loader_extensions[] = {
383    &imageLoaderExtension.base,
384    &dri3UseInvalidate.base,
385    &dri3BackgroundCallable.base,
386    NULL
387 };
388 
389 /** dri3_swap_buffers
390  *
391  * Make the current back buffer visible using the present extension
392  */
393 static int64_t
dri3_swap_buffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)394 dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
395                   int64_t remainder, Bool flush)
396 {
397    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
398    unsigned flags = __DRI2_FLUSH_DRAWABLE;
399 
400    if (flush)
401       flags |= __DRI2_FLUSH_CONTEXT;
402 
403    return loader_dri3_swap_buffers_msc(&priv->loader_drawable,
404                                        target_msc, divisor, remainder,
405                                        flags, NULL, 0, false);
406 }
407 
408 int
409 dri3_get_buffer_age(__GLXDRIdrawable *pdraw);
410 int
dri3_get_buffer_age(__GLXDRIdrawable * pdraw)411 dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
412 {
413    struct dri3_drawable *priv = (struct dri3_drawable *)pdraw;
414 
415    return loader_dri3_query_buffer_age(&priv->loader_drawable);
416 }
417 
418 /** dri3_destroy_screen
419  */
420 static void
dri3_deinit_screen(struct glx_screen * base)421 dri3_deinit_screen(struct glx_screen *base)
422 {
423    struct dri3_screen *psc = (struct dri3_screen *) base;
424 
425    /* Free the direct rendering per screen data */
426    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->driScreenDisplayGPU) {
427       loader_dri3_close_screen(psc->driScreenDisplayGPU);
428       driDestroyScreen(psc->driScreenDisplayGPU);
429    }
430    if (psc->fd_render_gpu != psc->fd_display_gpu)
431       close(psc->fd_display_gpu);
432    loader_dri3_close_screen(psc->base.frontend_screen);
433    close(psc->fd_render_gpu);
434 }
435 
436 /** dri3_set_swap_interval
437  *
438  * Record the application swap interval specification,
439  */
440 static int
dri3_set_swap_interval(__GLXDRIdrawable * pdraw,int interval)441 dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
442 {
443    assert(pdraw != NULL);
444 
445    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
446    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
447 
448    if (!dri_valid_swap_interval(psc->base.frontend_screen, interval))
449       return GLX_BAD_VALUE;
450 
451    loader_dri3_set_swap_interval(&priv->loader_drawable, interval);
452 
453    return 0;
454 }
455 
456 /** dri3_get_swap_interval
457  *
458  * Return the stored swap interval
459  */
460 static int
dri3_get_swap_interval(__GLXDRIdrawable * pdraw)461 dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
462 {
463    assert(pdraw != NULL);
464 
465    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
466 
467   return priv->loader_drawable.swap_interval;
468 }
469 
470 static const struct glx_context_vtable dri3_context_vtable = {
471    .destroy             = dri_destroy_context,
472    .bind                = dri_bind_context,
473    .unbind              = dri_unbind_context,
474    .wait_gl             = dri3_wait_gl,
475    .wait_x              = dri3_wait_x,
476 };
477 
478 /** dri3_create_screen
479  *
480  * Initialize DRI3 on the specified screen.
481  *
482  * Opens the DRI device, locates the appropriate DRI driver
483  * and loads that.
484  *
485  * Checks to see if the driver supports the necessary extensions
486  *
487  * Initializes the driver for the screen and sets up our structures
488  */
489 
490 struct glx_screen *
dri3_create_screen(int screen,struct glx_display * priv,bool driver_name_is_inferred,bool * return_zink)491 dri3_create_screen(int screen, struct glx_display * priv, bool driver_name_is_inferred, bool *return_zink)
492 {
493    xcb_connection_t *c = XGetXCBConnection(priv->dpy);
494    const __DRIconfig **driver_configs;
495    struct dri3_screen *psc;
496    __GLXDRIscreen *psp;
497    char *driverName, *driverNameDisplayGPU;
498    *return_zink = false;
499 
500    psc = calloc(1, sizeof *psc);
501    if (psc == NULL)
502       return NULL;
503 
504    psc->fd_display_gpu = -1;
505 
506    psc->fd_render_gpu = x11_dri3_open(c, RootWindow(priv->dpy, screen), None);
507    if (psc->fd_render_gpu < 0) {
508       int conn_error = xcb_connection_has_error(c);
509 
510       glx_screen_cleanup(&psc->base);
511       free(psc);
512       InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
513 
514       if (conn_error)
515          ErrorMessageF("Connection closed during DRI3 initialization failure");
516 
517       return NULL;
518    }
519 
520    loader_get_user_preferred_fd(&psc->fd_render_gpu, &psc->fd_display_gpu);
521 
522    driverName = loader_get_driver_for_fd(psc->fd_render_gpu);
523    if (!driverName) {
524       ErrorMessageF("No driver found\n");
525       goto handle_error;
526    }
527    psc->base.driverName = driverName;
528 
529    if (!strcmp(driverName, "zink") && !debug_get_bool_option("LIBGL_KOPPER_DISABLE", false)) {
530       *return_zink = true;
531       goto handle_error;
532    }
533 
534    if (psc->fd_render_gpu != psc->fd_display_gpu) {
535       driverNameDisplayGPU = loader_get_driver_for_fd(psc->fd_display_gpu);
536       if (driverNameDisplayGPU) {
537 
538          /* check if driver name is matching so that non mesa drivers
539           * will not crash. Also need this check since image extension
540           * pointer from render gpu is shared with display gpu. Image
541           * extension pointer is shared because it keeps things simple.
542           */
543          if (strcmp(driverName, driverNameDisplayGPU) == 0) {
544             psc->driScreenDisplayGPU = driCreateNewScreen3(screen, psc->fd_display_gpu,
545                                                            loader_extensions,
546                                                            DRI_SCREEN_DRI3,
547                                                            &driver_configs, driver_name_is_inferred,
548                                                            priv->has_multibuffer, psc);
549          }
550 
551          free(driverNameDisplayGPU);
552       }
553    }
554    priv->driver = GLX_DRIVER_DRI3;
555 
556    if (!dri_screen_init(&psc->base, priv, screen, psc->fd_render_gpu, loader_extensions, driver_name_is_inferred)) {
557       ErrorMessageF("glx: failed to create dri3 screen\n");
558       goto handle_error;
559    }
560 
561    if (psc->fd_render_gpu == psc->fd_display_gpu)
562       psc->driScreenDisplayGPU = psc->base.frontend_screen;
563 
564    psc->base.context_vtable = &dri3_context_vtable;
565    psp = &psc->base.driScreen;
566    psp->deinitScreen = dri3_deinit_screen;
567    psp->createDrawable = dri3_create_drawable;
568    psp->swapBuffers = dri3_swap_buffers;
569 
570    psp->getDrawableMSC = dri3_drawable_get_msc;
571    psp->waitForMSC = dri3_wait_for_msc;
572    psp->waitForSBC = dri3_wait_for_sbc;
573    psp->setSwapInterval = dri3_set_swap_interval;
574    psp->getSwapInterval = dri3_get_swap_interval;
575    psp->maxSwapInterval = INT_MAX;
576 
577    /* when on a different gpu than the server, the server pixmaps
578     * can have a tiling mode we can't read. Thus we can't create
579     * a texture from them.
580     */
581    psc->base.can_EXT_texture_from_pixmap = psc->fd_render_gpu == psc->fd_display_gpu;
582    psp->copySubBuffer = dri3_copy_sub_buffer;
583 
584    InfoMessageF("Using DRI3 for screen %d\n", screen);
585 
586    psc->prefer_back_buffer_reuse = 1;
587    if (psc->fd_render_gpu != psc->fd_display_gpu) {
588       unsigned value;
589       if (dri_query_renderer_integer(psc->base.frontend_screen,
590                                      __DRI2_RENDERER_PREFER_BACK_BUFFER_REUSE,
591                                      &value) == 0)
592          psc->prefer_back_buffer_reuse = value;
593    }
594 
595 
596    return &psc->base;
597 
598 handle_error:
599    if (!*return_zink)
600       CriticalErrorMessageF("failed to load driver: %s\n", driverName ? driverName : "(null)");
601 
602    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->driScreenDisplayGPU)
603        driDestroyScreen(psc->driScreenDisplayGPU);
604    psc->driScreenDisplayGPU = NULL;
605    if (psc->fd_display_gpu >= 0 && psc->fd_render_gpu != psc->fd_display_gpu)
606       close(psc->fd_display_gpu);
607    if (psc->fd_render_gpu >= 0)
608       close(psc->fd_render_gpu);
609 
610    glx_screen_cleanup(&psc->base);
611    free(psc);
612 
613    return NULL;
614 }
615 
616 #endif /* GLX_DIRECT_RENDERING */
617