• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (krh@redhat.com)
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_dri_helper.h"
80 #include "dri2.h"
81 
82 static struct dri3_drawable *
loader_drawable_to_dri3_drawable(struct loader_dri3_drawable * draw)83 loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) {
84    size_t offset = offsetof(struct dri3_drawable, loader_drawable);
85    if (!draw)
86       return NULL;
87    return (struct dri3_drawable *)(((void*) draw) - offset);
88 }
89 
90 static void
glx_dri3_set_drawable_size(struct loader_dri3_drawable * draw,int width,int height)91 glx_dri3_set_drawable_size(struct loader_dri3_drawable *draw,
92                            int width, int height)
93 {
94    /* Nothing to do */
95 }
96 
97 static bool
glx_dri3_in_current_context(struct loader_dri3_drawable * draw)98 glx_dri3_in_current_context(struct loader_dri3_drawable *draw)
99 {
100    struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw);
101 
102    if (!priv)
103       return false;
104 
105    struct glx_context *pcp = __glXGetCurrentContext();
106    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
107 
108    return (pcp != &dummyContext) && pcp->psc == &psc->base;
109 }
110 
111 static __DRIcontext *
glx_dri3_get_dri_context(struct loader_dri3_drawable * draw)112 glx_dri3_get_dri_context(struct loader_dri3_drawable *draw)
113 {
114    struct glx_context *gc = __glXGetCurrentContext();
115 
116    return (gc != &dummyContext) ? gc->driContext : NULL;
117 }
118 
119 static __DRIscreen *
glx_dri3_get_dri_screen(void)120 glx_dri3_get_dri_screen(void)
121 {
122    struct glx_context *gc = __glXGetCurrentContext();
123    struct dri3_screen *psc = (struct dri3_screen *) gc->psc;
124 
125    return (gc != &dummyContext && psc) ? psc->driScreenRenderGPU : NULL;
126 }
127 
128 static void
glx_dri3_flush_drawable(struct loader_dri3_drawable * draw,unsigned flags)129 glx_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)
130 {
131    loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER);
132 }
133 
134 static const struct loader_dri3_vtable glx_dri3_vtable = {
135    .set_drawable_size = glx_dri3_set_drawable_size,
136    .in_current_context = glx_dri3_in_current_context,
137    .get_dri_context = glx_dri3_get_dri_context,
138    .get_dri_screen = glx_dri3_get_dri_screen,
139    .flush_drawable = glx_dri3_flush_drawable,
140 };
141 
142 
143 static const struct glx_context_vtable dri3_context_vtable;
144 
145 static void
dri3_destroy_context(struct glx_context * context)146 dri3_destroy_context(struct glx_context *context)
147 {
148    struct dri3_screen *psc = (struct dri3_screen *) context->psc;
149 
150    driReleaseDrawables(context);
151 
152    free((char *) context->extensions);
153 
154    psc->core->destroyContext(context->driContext);
155 
156    free(context);
157 }
158 
159 static Bool
dri3_bind_context(struct glx_context * context,GLXDrawable draw,GLXDrawable read)160 dri3_bind_context(struct glx_context *context, GLXDrawable draw, GLXDrawable read)
161 {
162    struct dri3_screen *psc = (struct dri3_screen *) context->psc;
163    struct dri3_drawable *pdraw, *pread;
164    __DRIdrawable *dri_draw = NULL, *dri_read = NULL;
165 
166    pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw);
167    pread = (struct dri3_drawable *) driFetchDrawable(context, read);
168 
169    driReleaseDrawables(context);
170 
171    if (pdraw)
172       dri_draw = pdraw->loader_drawable.dri_drawable;
173    else if (draw != None)
174       return GLXBadDrawable;
175 
176    if (pread)
177       dri_read = pread->loader_drawable.dri_drawable;
178    else if (read != None)
179       return GLXBadDrawable;
180 
181    if (!psc->core->bindContext(context->driContext, dri_draw, dri_read))
182       return GLXBadContext;
183 
184    if (dri_draw)
185       psc->f->invalidate(dri_draw);
186    if (dri_read && dri_read != dri_draw)
187       psc->f->invalidate(dri_read);
188 
189    return Success;
190 }
191 
192 static void
dri3_unbind_context(struct glx_context * context)193 dri3_unbind_context(struct glx_context *context)
194 {
195    struct dri3_screen *psc = (struct dri3_screen *) context->psc;
196 
197    psc->core->unbindContext(context->driContext);
198 }
199 
200 static struct glx_context *
dri3_create_context_attribs(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)201 dri3_create_context_attribs(struct glx_screen *base,
202                             struct glx_config *config_base,
203                             struct glx_context *shareList,
204                             unsigned num_attribs,
205                             const uint32_t *attribs,
206                             unsigned *error)
207 {
208    struct glx_context *pcp = NULL;
209    struct dri3_screen *psc = (struct dri3_screen *) base;
210    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
211    __DRIcontext *shared = NULL;
212 
213    struct dri_ctx_attribs dca;
214    uint32_t ctx_attribs[2 * 6];
215    unsigned num_ctx_attribs = 0;
216 
217    *error = dri_convert_glx_attribs(num_attribs, attribs, &dca);
218    if (*error != __DRI_CTX_ERROR_SUCCESS)
219       goto error_exit;
220 
221    /* Check the renderType value */
222    if (!validate_renderType_against_config(config_base, dca.render_type)) {
223       *error = BadValue;
224       goto error_exit;
225    }
226 
227    if (shareList) {
228       /* We can't share with an indirect context */
229       if (!shareList->isDirect)
230          return NULL;
231 
232       /* The GLX_ARB_create_context_no_error specs say:
233        *
234        *    BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB
235        *    used to create <share_context> does not match the value of
236        *    GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created.
237        */
238       if (!!shareList->noError != !!dca.no_error) {
239          *error = BadMatch;
240          return NULL;
241       }
242 
243       shared = shareList->driContext;
244    }
245 
246    pcp = calloc(1, sizeof *pcp);
247    if (pcp == NULL) {
248       *error = BadAlloc;
249       goto error_exit;
250    }
251 
252    if (!glx_context_init(pcp, &psc->base, config_base))
253       goto error_exit;
254 
255    ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
256    ctx_attribs[num_ctx_attribs++] = dca.major_ver;
257    ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
258    ctx_attribs[num_ctx_attribs++] = dca.minor_ver;
259 
260    /* Only send a value when the non-default value is requested.  By doing
261     * this we don't have to check the driver's DRI3 version before sending the
262     * default value.
263     */
264    if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
265       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
266       ctx_attribs[num_ctx_attribs++] = dca.reset;
267    }
268 
269    if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
270       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
271       ctx_attribs[num_ctx_attribs++] = dca.release;
272    }
273 
274    if (dca.no_error) {
275       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_NO_ERROR;
276       ctx_attribs[num_ctx_attribs++] = dca.no_error;
277       pcp->noError = GL_TRUE;
278    }
279 
280    if (dca.flags != 0) {
281       ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
282       ctx_attribs[num_ctx_attribs++] = dca.flags;
283    }
284 
285    pcp->renderType = dca.render_type;
286 
287    pcp->driContext =
288       psc->image_driver->createContextAttribs(psc->driScreenRenderGPU,
289                                               dca.api,
290                                               config ? config->driConfig
291                                               : NULL,
292                                               shared,
293                                               num_ctx_attribs / 2,
294                                               ctx_attribs,
295                                               error,
296                                               pcp);
297 
298    *error = dri_context_error_to_glx_error(*error);
299 
300    if (pcp->driContext == NULL)
301       goto error_exit;
302 
303    pcp->vtable = base->context_vtable;
304 
305    return pcp;
306 
307 error_exit:
308    free(pcp);
309 
310    return NULL;
311 }
312 
313 static void
dri3_destroy_drawable(__GLXDRIdrawable * base)314 dri3_destroy_drawable(__GLXDRIdrawable *base)
315 {
316    struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
317 
318    loader_dri3_drawable_fini(&pdraw->loader_drawable);
319 
320    free(pdraw);
321 }
322 
323 static enum loader_dri3_drawable_type
glx_to_loader_dri3_drawable_type(int type)324 glx_to_loader_dri3_drawable_type(int type)
325 {
326    switch (type) {
327    case GLX_WINDOW_BIT:
328       return LOADER_DRI3_DRAWABLE_WINDOW;
329    case GLX_PIXMAP_BIT:
330       return LOADER_DRI3_DRAWABLE_PIXMAP;
331    case GLX_PBUFFER_BIT:
332       return LOADER_DRI3_DRAWABLE_PBUFFER;
333    default:
334       return LOADER_DRI3_DRAWABLE_UNKNOWN;
335    }
336 }
337 
338 static __GLXDRIdrawable *
dri3_create_drawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * config_base)339 dri3_create_drawable(struct glx_screen *base, XID xDrawable,
340                      GLXDrawable drawable, int type,
341                      struct glx_config *config_base)
342 {
343    struct dri3_drawable *pdraw;
344    struct dri3_screen *psc = (struct dri3_screen *) base;
345    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
346    bool has_multibuffer = false;
347 #ifdef HAVE_DRI3_MODIFIERS
348    const struct dri3_display *const pdp = (struct dri3_display *)
349       base->display->dri3Display;
350 #endif
351 
352    pdraw = calloc(1, sizeof(*pdraw));
353    if (!pdraw)
354       return NULL;
355 
356    pdraw->base.destroyDrawable = dri3_destroy_drawable;
357    pdraw->base.xDrawable = xDrawable;
358    pdraw->base.drawable = drawable;
359    pdraw->base.psc = &psc->base;
360 
361 #ifdef HAVE_DRI3_MODIFIERS
362    if (pdp->has_multibuffer && psc->image && psc->image->base.version >= 15)
363       has_multibuffer = true;
364 #endif
365 
366    (void) __glXInitialize(psc->base.dpy);
367 
368    if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy),
369                                  xDrawable,
370                                  glx_to_loader_dri3_drawable_type(type),
371                                  psc->driScreenRenderGPU, psc->driScreenDisplayGPU,
372                                  has_multibuffer,
373                                  psc->prefer_back_buffer_reuse,
374                                  config->driConfig,
375                                  &psc->loader_dri3_ext, &glx_dri3_vtable,
376                                  &pdraw->loader_drawable)) {
377       free(pdraw);
378       return NULL;
379    }
380 
381    return &pdraw->base;
382 }
383 
384 /** dri3_wait_for_msc
385  *
386  * Get the X server to send an event when the target msc/divisor/remainder is
387  * reached.
388  */
389 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)390 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
391                   int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
392 {
393    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
394 
395    loader_dri3_wait_for_msc(&priv->loader_drawable, target_msc, divisor,
396                             remainder, ust, msc, sbc);
397 
398    return 1;
399 }
400 
401 /** dri3_drawable_get_msc
402  *
403  * Return the current UST/MSC/SBC triplet by asking the server
404  * for an event
405  */
406 static int
dri3_drawable_get_msc(struct glx_screen * psc,__GLXDRIdrawable * pdraw,int64_t * ust,int64_t * msc,int64_t * sbc)407 dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
408                       int64_t *ust, int64_t *msc, int64_t *sbc)
409 {
410    return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
411 }
412 
413 /** dri3_wait_for_sbc
414  *
415  * Wait for the completed swap buffer count to reach the specified
416  * target. Presumably the application knows that this will be reached with
417  * outstanding complete events, or we're going to be here awhile.
418  */
419 static int
dri3_wait_for_sbc(__GLXDRIdrawable * pdraw,int64_t target_sbc,int64_t * ust,int64_t * msc,int64_t * sbc)420 dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
421                   int64_t *msc, int64_t *sbc)
422 {
423    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
424 
425    return loader_dri3_wait_for_sbc(&priv->loader_drawable, target_sbc,
426                                    ust, msc, sbc);
427 }
428 
429 static void
dri3_copy_sub_buffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)430 dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
431                      int width, int height,
432                      Bool flush)
433 {
434    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
435 
436    loader_dri3_copy_sub_buffer(&priv->loader_drawable, x, y,
437                                width, height, flush);
438 }
439 
440 static void
dri3_wait_x(struct glx_context * gc)441 dri3_wait_x(struct glx_context *gc)
442 {
443    struct dri3_drawable *priv = (struct dri3_drawable *)
444       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
445 
446    if (priv)
447       loader_dri3_wait_x(&priv->loader_drawable);
448 }
449 
450 static void
dri3_wait_gl(struct glx_context * gc)451 dri3_wait_gl(struct glx_context *gc)
452 {
453    struct dri3_drawable *priv = (struct dri3_drawable *)
454       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
455 
456    if (priv)
457       loader_dri3_wait_gl(&priv->loader_drawable);
458 }
459 
460 /**
461  * Called by the driver when it needs to update the real front buffer with the
462  * contents of its fake front buffer.
463  */
464 static void
dri3_flush_front_buffer(__DRIdrawable * driDrawable,void * loaderPrivate)465 dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
466 {
467    struct loader_dri3_drawable *draw = loaderPrivate;
468    struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw);
469    struct dri3_screen *psc;
470 
471    if (!pdraw)
472       return;
473 
474    if (!pdraw->base.psc)
475       return;
476 
477    psc = (struct dri3_screen *) pdraw->base.psc;
478 
479    (void) __glXInitialize(psc->base.dpy);
480 
481    loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
482 
483    psc->f->invalidate(driDrawable);
484    loader_dri3_wait_gl(draw);
485 }
486 
487 /**
488  * Make sure all pending swapbuffers have been submitted to hardware
489  *
490  * \param driDrawable[in]  Pointer to the dri drawable whose swaps we are
491  * flushing.
492  * \param loaderPrivate[in]  Pointer to the corresponding struct
493  * loader_dri_drawable.
494  */
495 static void
dri3_flush_swap_buffers(__DRIdrawable * driDrawable,void * loaderPrivate)496 dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate)
497 {
498    struct loader_dri3_drawable *draw = loaderPrivate;
499    struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw);
500    struct dri3_screen *psc;
501 
502    if (!pdraw)
503       return;
504 
505    if (!pdraw->base.psc)
506       return;
507 
508    psc = (struct dri3_screen *) pdraw->base.psc;
509 
510    (void) __glXInitialize(psc->base.dpy);
511    loader_dri3_swapbuffer_barrier(draw);
512 }
513 
514 static void
dri_set_background_context(void * loaderPrivate)515 dri_set_background_context(void *loaderPrivate)
516 {
517    __glXSetCurrentContext(loaderPrivate);
518 }
519 
520 static GLboolean
dri_is_thread_safe(void * loaderPrivate)521 dri_is_thread_safe(void *loaderPrivate)
522 {
523    /* Unlike DRI2, DRI3 doesn't call GetBuffers/GetBuffersWithFormat
524     * during draw so we're safe here.
525     */
526    return true;
527 }
528 
529 /* The image loader extension record for DRI3
530  */
531 static const __DRIimageLoaderExtension imageLoaderExtension = {
532    .base = { __DRI_IMAGE_LOADER, 3 },
533 
534    .getBuffers          = loader_dri3_get_buffers,
535    .flushFrontBuffer    = dri3_flush_front_buffer,
536    .flushSwapBuffers    = dri3_flush_swap_buffers,
537 };
538 
539 const __DRIuseInvalidateExtension dri3UseInvalidate = {
540    .base = { __DRI_USE_INVALIDATE, 1 }
541 };
542 
543 static const __DRIbackgroundCallableExtension driBackgroundCallable = {
544    .base = { __DRI_BACKGROUND_CALLABLE, 2 },
545 
546    .setBackgroundContext = dri_set_background_context,
547    .isThreadSafe         = dri_is_thread_safe,
548 };
549 
550 static const __DRIextension *loader_extensions[] = {
551    &imageLoaderExtension.base,
552    &dri3UseInvalidate.base,
553    &driBackgroundCallable.base,
554    NULL
555 };
556 
557 /** dri3_swap_buffers
558  *
559  * Make the current back buffer visible using the present extension
560  */
561 static int64_t
dri3_swap_buffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)562 dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
563                   int64_t remainder, Bool flush)
564 {
565    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
566    unsigned flags = __DRI2_FLUSH_DRAWABLE;
567 
568    if (flush)
569       flags |= __DRI2_FLUSH_CONTEXT;
570 
571    return loader_dri3_swap_buffers_msc(&priv->loader_drawable,
572                                        target_msc, divisor, remainder,
573                                        flags, NULL, 0, false);
574 }
575 
576 static int
dri3_get_buffer_age(__GLXDRIdrawable * pdraw)577 dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
578 {
579    struct dri3_drawable *priv = (struct dri3_drawable *)pdraw;
580 
581    return loader_dri3_query_buffer_age(&priv->loader_drawable);
582 }
583 
584 /** dri3_destroy_screen
585  */
586 static void
dri3_destroy_screen(struct glx_screen * base)587 dri3_destroy_screen(struct glx_screen *base)
588 {
589    struct dri3_screen *psc = (struct dri3_screen *) base;
590 
591    /* Free the direct rendering per screen data */
592    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->driScreenDisplayGPU) {
593       loader_dri3_close_screen(psc->driScreenDisplayGPU);
594       psc->core->destroyScreen(psc->driScreenDisplayGPU);
595    }
596    if (psc->fd_render_gpu != psc->fd_display_gpu)
597       close(psc->fd_display_gpu);
598    loader_dri3_close_screen(psc->driScreenRenderGPU);
599    psc->core->destroyScreen(psc->driScreenRenderGPU);
600    driDestroyConfigs(psc->driver_configs);
601    close(psc->fd_render_gpu);
602    free(psc);
603 }
604 
605 /** dri3_set_swap_interval
606  *
607  * Record the application swap interval specification,
608  */
609 static int
dri3_set_swap_interval(__GLXDRIdrawable * pdraw,int interval)610 dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
611 {
612    assert(pdraw != NULL);
613 
614    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
615    struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
616 
617    if (!dri_valid_swap_interval(psc->driScreenRenderGPU, psc->config, interval))
618       return GLX_BAD_VALUE;
619 
620    loader_dri3_set_swap_interval(&priv->loader_drawable, interval);
621 
622    return 0;
623 }
624 
625 /** dri3_get_swap_interval
626  *
627  * Return the stored swap interval
628  */
629 static int
dri3_get_swap_interval(__GLXDRIdrawable * pdraw)630 dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
631 {
632    assert(pdraw != NULL);
633 
634    struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
635 
636   return priv->loader_drawable.swap_interval;
637 }
638 
639 static void
dri3_bind_tex_image(__GLXDRIdrawable * base,int buffer,const int * attrib_list)640 dri3_bind_tex_image(__GLXDRIdrawable *base,
641                     int buffer, const int *attrib_list)
642 {
643    struct glx_context *gc = __glXGetCurrentContext();
644    struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
645    struct dri3_screen *psc;
646 
647    if (pdraw != NULL) {
648       psc = (struct dri3_screen *) base->psc;
649 
650       psc->f->invalidate(pdraw->loader_drawable.dri_drawable);
651 
652       XSync(gc->currentDpy, false);
653 
654       psc->texBuffer->setTexBuffer2(gc->driContext,
655                                         pdraw->base.textureTarget,
656                                         pdraw->base.textureFormat,
657                                         pdraw->loader_drawable.dri_drawable);
658    }
659 }
660 
661 static void
dri3_release_tex_image(__GLXDRIdrawable * base,int buffer)662 dri3_release_tex_image(__GLXDRIdrawable *base, int buffer)
663 {
664    struct glx_context *gc = __glXGetCurrentContext();
665    struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
666    struct dri3_screen *psc;
667 
668    if (pdraw != NULL) {
669       psc = (struct dri3_screen *) base->psc;
670 
671       if (psc->texBuffer->base.version >= 3 &&
672           psc->texBuffer->releaseTexBuffer != NULL)
673          psc->texBuffer->releaseTexBuffer(gc->driContext,
674                                               pdraw->base.textureTarget,
675                                               pdraw->loader_drawable.dri_drawable);
676    }
677 }
678 
679 static const struct glx_context_vtable dri3_context_vtable = {
680    .destroy             = dri3_destroy_context,
681    .bind                = dri3_bind_context,
682    .unbind              = dri3_unbind_context,
683    .wait_gl             = dri3_wait_gl,
684    .wait_x              = dri3_wait_x,
685    .interop_query_device_info = dri3_interop_query_device_info,
686    .interop_export_object = dri3_interop_export_object,
687    .interop_flush_objects = dri3_interop_flush_objects
688 };
689 
690 /** dri3_bind_extensions
691  *
692  * Enable all of the extensions supported on DRI3
693  */
694 static void
dri3_bind_extensions(struct dri3_screen * psc,struct glx_display * priv,const char * driverName)695 dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
696                      const char *driverName)
697 {
698    const __DRIextension **extensions;
699    unsigned mask;
700    int i;
701 
702    extensions = psc->core->getExtensions(psc->driScreenRenderGPU);
703 
704    __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control");
705    __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control_tear");
706    __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
707    __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
708    __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
709    __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
710 
711    mask = psc->image_driver->getAPIMask(psc->driScreenRenderGPU);
712 
713    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
714    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
715    __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_no_error");
716    __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context");
717 
718    if ((mask & ((1 << __DRI_API_GLES) |
719                 (1 << __DRI_API_GLES2) |
720                 (1 << __DRI_API_GLES3))) != 0) {
721       __glXEnableDirectExtension(&psc->base,
722                                  "GLX_EXT_create_context_es_profile");
723       __glXEnableDirectExtension(&psc->base,
724                                  "GLX_EXT_create_context_es2_profile");
725    }
726 
727    static const struct dri_extension_match exts[] = {
728        { __DRI2_RENDERER_QUERY, 1, offsetof(struct dri3_screen, rendererQuery), true },
729        { __DRI2_FLUSH, 1, offsetof(struct dri3_screen, f), true },
730        { __DRI_IMAGE, 1, offsetof(struct dri3_screen, image), true },
731        { __DRI2_INTEROP, 1, offsetof(struct dri3_screen, interop), true },
732        { __DRI2_CONFIG_QUERY, 1, offsetof(struct dri3_screen, config), true },
733    };
734    loader_bind_extensions(psc, exts, ARRAY_SIZE(exts), extensions);
735 
736    for (i = 0; extensions[i]; i++) {
737       /* when on a different gpu than the server, the server pixmaps
738        * can have a tiling mode we can't read. Thus we can't create
739        * a texture from them.
740        */
741       if (psc->fd_render_gpu == psc->fd_display_gpu &&
742          (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
743          psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
744          __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
745       }
746 
747       if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
748          __glXEnableDirectExtension(&psc->base,
749                                     "GLX_ARB_create_context_robustness");
750 
751       if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0)
752          __glXEnableDirectExtension(&psc->base,
753                                     "GLX_ARB_context_flush_control");
754    }
755 
756    if (psc->rendererQuery)
757       __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
758 
759    if (psc->interop)
760       __glXEnableDirectExtension(&psc->base, "GLX_MESA_gl_interop");
761 }
762 
763 static char *
dri3_get_driver_name(struct glx_screen * glx_screen)764 dri3_get_driver_name(struct glx_screen *glx_screen)
765 {
766     struct dri3_screen *psc = (struct dri3_screen *)glx_screen;
767 
768     return loader_get_driver_for_fd(psc->fd_render_gpu);
769 }
770 
771 static const struct glx_screen_vtable dri3_screen_vtable = {
772    .create_context         = dri_common_create_context,
773    .create_context_attribs = dri3_create_context_attribs,
774    .query_renderer_integer = dri3_query_renderer_integer,
775    .query_renderer_string  = dri3_query_renderer_string,
776    .get_driver_name        = dri3_get_driver_name,
777 };
778 
779 /** dri3_create_screen
780  *
781  * Initialize DRI3 on the specified screen.
782  *
783  * Opens the DRI device, locates the appropriate DRI driver
784  * and loads that.
785  *
786  * Checks to see if the driver supports the necessary extensions
787  *
788  * Initializes the driver for the screen and sets up our structures
789  */
790 
791 static struct glx_screen *
dri3_create_screen(int screen,struct glx_display * priv)792 dri3_create_screen(int screen, struct glx_display * priv)
793 {
794    xcb_connection_t *c = XGetXCBConnection(priv->dpy);
795    const __DRIconfig **driver_configs;
796    const __DRIextension **extensions;
797    const struct dri3_display *const pdp = (struct dri3_display *)
798       priv->dri3Display;
799    struct dri3_screen *psc;
800    __GLXDRIscreen *psp;
801    struct glx_config *configs = NULL, *visuals = NULL;
802    char *driverName, *driverNameDisplayGPU, *tmp;
803    bool return_zink = false;
804 
805    psc = calloc(1, sizeof *psc);
806    if (psc == NULL)
807       return NULL;
808 
809    psc->fd_render_gpu = -1;
810    psc->fd_display_gpu = -1;
811 
812    if (!glx_screen_init(&psc->base, screen, priv)) {
813       free(psc);
814       return NULL;
815    }
816 
817    psc->fd_render_gpu = loader_dri3_open(c, RootWindow(priv->dpy, screen), None);
818    if (psc->fd_render_gpu < 0) {
819       int conn_error = xcb_connection_has_error(c);
820 
821       glx_screen_cleanup(&psc->base);
822       free(psc);
823       InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
824 
825       if (conn_error)
826          ErrorMessageF("Connection closed during DRI3 initialization failure");
827 
828       return NULL;
829    }
830 
831    loader_get_user_preferred_fd(&psc->fd_render_gpu, &psc->fd_display_gpu);
832 
833    driverName = loader_get_driver_for_fd(psc->fd_render_gpu);
834    if (!driverName) {
835       ErrorMessageF("No driver found\n");
836       goto handle_error;
837    }
838 
839    if (!strcmp(driverName, "zink")) {
840       return_zink = true;
841       goto handle_error;
842    }
843 
844    extensions = driOpenDriver(driverName, &psc->driver);
845    if (extensions == NULL)
846       goto handle_error;
847 
848    static const struct dri_extension_match exts[] = {
849        { __DRI_CORE, 1, offsetof(struct dri3_screen, core), false },
850        { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri3_screen, image_driver), false },
851        { __DRI_MESA, 1, offsetof(struct dri3_screen, mesa), false },
852    };
853    if (!loader_bind_extensions(psc, exts, ARRAY_SIZE(exts), extensions))
854       goto handle_error;
855 
856    if (psc->fd_render_gpu != psc->fd_display_gpu) {
857       driverNameDisplayGPU = loader_get_driver_for_fd(psc->fd_display_gpu);
858       if (driverNameDisplayGPU) {
859 
860          /* check if driver name is matching so that non mesa drivers
861           * will not crash. Also need this check since image extension
862           * pointer from render gpu is shared with display gpu. Image
863           * extension pointer is shared because it keeps things simple.
864           */
865          if (strcmp(driverName, driverNameDisplayGPU) == 0) {
866             psc->driScreenDisplayGPU =
867                psc->image_driver->createNewScreen2(screen, psc->fd_display_gpu,
868                                                    pdp->loader_extensions,
869                                                    extensions,
870                                                    &driver_configs, psc);
871          }
872 
873          free(driverNameDisplayGPU);
874       }
875    }
876 
877    psc->driScreenRenderGPU =
878       psc->image_driver->createNewScreen2(screen, psc->fd_render_gpu,
879                                           pdp->loader_extensions,
880                                           extensions,
881                                           &driver_configs, psc);
882 
883    if (psc->driScreenRenderGPU == NULL) {
884       ErrorMessageF("glx: failed to create dri3 screen\n");
885       goto handle_error;
886    }
887 
888    if (psc->fd_render_gpu == psc->fd_display_gpu)
889       psc->driScreenDisplayGPU = psc->driScreenRenderGPU;
890 
891    dri3_bind_extensions(psc, priv, driverName);
892 
893    if (!psc->image || psc->image->base.version < 7 || !psc->image->createImageFromFds) {
894       ErrorMessageF("Version 7 or imageFromFds image extension not found\n");
895       goto handle_error;
896    }
897 
898    if (!psc->f || psc->f->base.version < 4) {
899       ErrorMessageF("Version 4 or later of flush extension not found\n");
900       goto handle_error;
901    }
902 
903    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->image->base.version < 9) {
904       ErrorMessageF("Different GPU, but image extension version 9 or later not found\n");
905       goto handle_error;
906    }
907 
908    if (psc->fd_render_gpu != psc->fd_display_gpu && !psc->image->blitImage) {
909       ErrorMessageF("Different GPU, but blitImage not implemented for this driver\n");
910       goto handle_error;
911    }
912 
913    if (psc->fd_render_gpu == psc->fd_display_gpu && (
914        !psc->texBuffer || psc->texBuffer->base.version < 2 ||
915        !psc->texBuffer->setTexBuffer2
916        )) {
917       ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
918       goto handle_error;
919    }
920 
921    psc->loader_dri3_ext.core = psc->core;
922    psc->loader_dri3_ext.image_driver = psc->image_driver;
923    psc->loader_dri3_ext.flush = psc->f;
924    psc->loader_dri3_ext.tex_buffer = psc->texBuffer;
925    psc->loader_dri3_ext.image = psc->image;
926    psc->loader_dri3_ext.config = psc->config;
927 
928    configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
929    visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
930 
931    if (!configs || !visuals) {
932        ErrorMessageF("No matching fbConfigs or visuals found\n");
933        goto handle_error;
934    }
935 
936    glx_config_destroy_list(psc->base.configs);
937    psc->base.configs = configs;
938    glx_config_destroy_list(psc->base.visuals);
939    psc->base.visuals = visuals;
940 
941    psc->driver_configs = driver_configs;
942 
943    psc->base.vtable = &dri3_screen_vtable;
944    psc->base.context_vtable = &dri3_context_vtable;
945    psp = &psc->vtable;
946    psc->base.driScreen = psp;
947    psp->destroyScreen = dri3_destroy_screen;
948    psp->createDrawable = dri3_create_drawable;
949    psp->swapBuffers = dri3_swap_buffers;
950 
951    psp->getDrawableMSC = dri3_drawable_get_msc;
952    psp->waitForMSC = dri3_wait_for_msc;
953    psp->waitForSBC = dri3_wait_for_sbc;
954    psp->setSwapInterval = dri3_set_swap_interval;
955    psp->getSwapInterval = dri3_get_swap_interval;
956    psp->bindTexImage = dri3_bind_tex_image;
957    psp->releaseTexImage = dri3_release_tex_image;
958    psp->maxSwapInterval = INT_MAX;
959 
960    __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
961    __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
962 
963    psp->copySubBuffer = dri3_copy_sub_buffer;
964    __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
965 
966    psp->getBufferAge = dri3_get_buffer_age;
967    __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
968 
969    if (psc->config->base.version > 1 &&
970           psc->config->configQuerys(psc->driScreenRenderGPU, "glx_extension_override",
971                                     &tmp) == 0)
972       __glXParseExtensionOverride(&psc->base, tmp);
973 
974    if (psc->config->base.version > 1 &&
975           psc->config->configQuerys(psc->driScreenRenderGPU,
976                                     "indirect_gl_extension_override",
977                                     &tmp) == 0)
978       __IndirectGlParseExtensionOverride(&psc->base, tmp);
979 
980    if (psc->config->base.version > 1) {
981       uint8_t force = false;
982       if (psc->config->configQueryb(psc->driScreenRenderGPU, "force_direct_glx_context",
983                                     &force) == 0) {
984          psc->base.force_direct_context = force;
985       }
986 
987       uint8_t invalid_glx_destroy_window = false;
988       if (psc->config->configQueryb(psc->driScreenRenderGPU,
989                                     "allow_invalid_glx_destroy_window",
990                                     &invalid_glx_destroy_window) == 0) {
991          psc->base.allow_invalid_glx_destroy_window = invalid_glx_destroy_window;
992       }
993 
994       uint8_t keep_native_window_glx_drawable = false;
995       if (psc->config->configQueryb(psc->driScreenRenderGPU,
996                                     "keep_native_window_glx_drawable",
997                                     &keep_native_window_glx_drawable) == 0) {
998          psc->base.keep_native_window_glx_drawable = keep_native_window_glx_drawable;
999       }
1000    }
1001 
1002    free(driverName);
1003 
1004    InfoMessageF("Using DRI3 for screen %d\n", screen);
1005 
1006    psc->prefer_back_buffer_reuse = 1;
1007    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->rendererQuery) {
1008       unsigned value;
1009       if (psc->rendererQuery->queryInteger(psc->driScreenRenderGPU,
1010                                            __DRI2_RENDERER_PREFER_BACK_BUFFER_REUSE,
1011                                            &value) == 0)
1012          psc->prefer_back_buffer_reuse = value;
1013    }
1014 
1015    return &psc->base;
1016 
1017 handle_error:
1018    if (!return_zink)
1019       CriticalErrorMessageF("failed to load driver: %s\n", driverName ? driverName : "(null)");
1020 
1021    if (configs)
1022        glx_config_destroy_list(configs);
1023    if (visuals)
1024        glx_config_destroy_list(visuals);
1025    if (psc->driScreenRenderGPU)
1026        psc->core->destroyScreen(psc->driScreenRenderGPU);
1027    psc->driScreenRenderGPU = NULL;
1028    if (psc->fd_render_gpu != psc->fd_display_gpu && psc->driScreenDisplayGPU)
1029        psc->core->destroyScreen(psc->driScreenDisplayGPU);
1030    psc->driScreenDisplayGPU = NULL;
1031    if (psc->fd_display_gpu >= 0 && psc->fd_render_gpu != psc->fd_display_gpu)
1032       close(psc->fd_display_gpu);
1033    if (psc->fd_render_gpu >= 0)
1034       close(psc->fd_render_gpu);
1035    if (psc->driver)
1036       dlclose(psc->driver);
1037 
1038    free(driverName);
1039    glx_screen_cleanup(&psc->base);
1040    free(psc);
1041 
1042    return return_zink ? GLX_LOADER_USE_ZINK : NULL;
1043 }
1044 
1045 /** dri_destroy_display
1046  *
1047  * Called from __glXFreeDisplayPrivate.
1048  */
1049 static void
dri3_destroy_display(__GLXDRIdisplay * dpy)1050 dri3_destroy_display(__GLXDRIdisplay * dpy)
1051 {
1052    free(dpy);
1053 }
1054 
1055 /* Only request versions of these protocols which we actually support. */
1056 #define DRI3_SUPPORTED_MAJOR 1
1057 #define PRESENT_SUPPORTED_MAJOR 1
1058 
1059 #ifdef HAVE_DRI3_MODIFIERS
1060 #define DRI3_SUPPORTED_MINOR 2
1061 #define PRESENT_SUPPORTED_MINOR 2
1062 #else
1063 #define PRESENT_SUPPORTED_MINOR 0
1064 #define DRI3_SUPPORTED_MINOR 0
1065 #endif
1066 
1067 
1068 bool
dri3_check_multibuffer(Display * dpy,bool * err)1069 dri3_check_multibuffer(Display * dpy, bool *err)
1070 {
1071    xcb_connection_t                     *c = XGetXCBConnection(dpy);
1072    xcb_dri3_query_version_cookie_t      dri3_cookie;
1073    xcb_dri3_query_version_reply_t       *dri3_reply;
1074    xcb_present_query_version_cookie_t   present_cookie;
1075    xcb_present_query_version_reply_t    *present_reply;
1076    xcb_generic_error_t                  *error;
1077    const xcb_query_extension_reply_t    *extension;
1078 
1079    xcb_prefetch_extension_data(c, &xcb_dri3_id);
1080    xcb_prefetch_extension_data(c, &xcb_present_id);
1081 
1082    extension = xcb_get_extension_data(c, &xcb_dri3_id);
1083    if (!(extension && extension->present))
1084       goto error;
1085 
1086    extension = xcb_get_extension_data(c, &xcb_present_id);
1087    if (!(extension && extension->present))
1088       goto error;
1089 
1090    dri3_cookie = xcb_dri3_query_version(c,
1091                                         DRI3_SUPPORTED_MAJOR,
1092                                         DRI3_SUPPORTED_MINOR);
1093    present_cookie = xcb_present_query_version(c,
1094                                               PRESENT_SUPPORTED_MAJOR,
1095                                               PRESENT_SUPPORTED_MINOR);
1096 
1097    dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error);
1098    if (!dri3_reply) {
1099       free(error);
1100       goto error;
1101    }
1102 
1103    int dri3Major = dri3_reply->major_version;
1104    int dri3Minor = dri3_reply->minor_version;
1105    free(dri3_reply);
1106 
1107    present_reply = xcb_present_query_version_reply(c, present_cookie, &error);
1108    if (!present_reply) {
1109       free(error);
1110       goto error;
1111    }
1112    int presentMajor = present_reply->major_version;
1113    int presentMinor = present_reply->minor_version;
1114    free(present_reply);
1115 
1116 #ifdef HAVE_DRI3_MODIFIERS
1117    if ((dri3Major > 1 || (dri3Major == 1 && dri3Minor >= 2)) &&
1118        (presentMajor > 1 || (presentMajor == 1 && presentMinor >= 2)))
1119       return true;
1120 #endif
1121    return false;
1122 error:
1123    *err = true;
1124    return false;
1125 }
1126 
1127 /** dri3_create_display
1128  *
1129  * Allocate, initialize and return a __DRIdisplayPrivate object.
1130  * This is called from __glXInitialize() when we are given a new
1131  * display pointer. This is public to that function, but hidden from
1132  * outside of libGL.
1133  */
1134 _X_HIDDEN __GLXDRIdisplay *
dri3_create_display(Display * dpy)1135 dri3_create_display(Display * dpy)
1136 {
1137    struct dri3_display                  *pdp;
1138    bool err = false;
1139    bool has_multibuffer = dri3_check_multibuffer(dpy, &err);
1140    if (err)
1141       return NULL;
1142 
1143    pdp = calloc(1, sizeof *pdp);
1144    if (pdp == NULL)
1145       return NULL;
1146    pdp->has_multibuffer = has_multibuffer;
1147 
1148    pdp->base.destroyDisplay = dri3_destroy_display;
1149    pdp->base.createScreen = dri3_create_screen;
1150 
1151    pdp->loader_extensions = loader_extensions;
1152 
1153    return &pdp->base;
1154 }
1155 
1156 #endif /* GLX_DIRECT_RENDERING */
1157