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