xref: /aosp_15_r20/external/mesa3d/src/glx/dri2_glx.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2008 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Soft-
6  * ware"), to deal in the Software without restriction, including without
7  * limitation the rights to use, copy, modify, merge, publish, distribute,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, provided that the above copyright
10  * notice(s) and this permission notice appear in all copies of the Soft-
11  * ware and that both the above copyright notice(s) and this permission
12  * notice appear in supporting documentation.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22  * MANCE OF THIS SOFTWARE.
23  *
24  * Except as contained in this notice, the name of a copyright holder shall
25  * not be used in advertising or otherwise to promote the sale, use or
26  * other dealings in this Software without prior written authorization of
27  * the copyright holder.
28  *
29  * Authors:
30  *   Kristian Høgsberg ([email protected])
31  */
32 
33 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
34 
35 #include <X11/Xlib.h>
36 #include <X11/extensions/Xfixes.h>
37 #include <X11/Xlib-xcb.h>
38 #include <xcb/xcb.h>
39 #include <xcb/dri2.h>
40 #include "glxclient.h"
41 #include <X11/extensions/dri2proto.h>
42 #include <dlfcn.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include <sys/time.h>
48 #include "dri2.h"
49 #include "dri_common.h"
50 #include "dri2_priv.h"
51 #include "loader.h"
52 #include "loader_dri_helper.h"
53 #include "dri_util.h"
54 
55 #undef DRI2_MINOR
56 #define DRI2_MINOR 1
57 
58 struct dri2_drawable
59 {
60    __GLXDRIdrawable base;
61    __DRIbuffer buffers[5];
62    int bufferCount;
63    int width, height;
64    int have_back;
65    int have_fake_front;
66    int swap_interval;
67 
68    uint64_t previous_time;
69    unsigned frames;
70 };
71 
72 static const struct glx_context_vtable dri2_context_vtable;
73 
74 /* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
75  * low halves separately.  This helps you split them.
76  */
77 static void
split_counter(uint64_t counter,uint32_t * hi,uint32_t * lo)78 split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
79 {
80    *hi = (counter >> 32);
81    *lo = counter & 0xffffffff;
82 }
83 
84 static uint64_t
merge_counter(uint32_t hi,uint32_t lo)85 merge_counter(uint32_t hi, uint32_t lo)
86 {
87    return ((uint64_t)hi << 32) | lo;
88 }
89 
90 static void
dri2DestroyDrawable(__GLXDRIdrawable * base)91 dri2DestroyDrawable(__GLXDRIdrawable *base)
92 {
93    struct dri2_screen *psc = (struct dri2_screen *) base->psc;
94    struct glx_display *dpyPriv = psc->base.display;
95 
96    __glxHashDelete(dpyPriv->dri2Hash, base->xDrawable);
97    driDestroyDrawable(base->dri_drawable);
98 
99    /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
100     * now, as the application explicitly asked to destroy the GLX
101     * drawable.  Otherwise, for legacy drawables, we let the DRI2
102     * drawable linger on the server, since there's no good way of
103     * knowing when the application is done with it.  The server will
104     * destroy the DRI2 drawable when it destroys the X drawable or the
105     * client exits anyway. */
106    if (base->xDrawable != base->drawable)
107       DRI2DestroyDrawable(psc->base.dpy, base->xDrawable);
108 
109    free(base);
110 }
111 
112 static __GLXDRIdrawable *
dri2CreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * config_base)113 dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
114                    GLXDrawable drawable, int type,
115                    struct glx_config *config_base)
116 {
117    struct dri2_drawable *pdraw;
118    struct dri2_screen *psc = (struct dri2_screen *) base;
119    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
120    struct glx_display *dpyPriv;
121 
122    dpyPriv = __glXInitialize(psc->base.dpy);
123    if (dpyPriv == NULL)
124       return NULL;
125 
126    pdraw = calloc(1, sizeof(*pdraw));
127    if (!pdraw)
128       return NULL;
129 
130    pdraw->base.destroyDrawable = dri2DestroyDrawable;
131    pdraw->base.xDrawable = xDrawable;
132    pdraw->base.drawable = drawable;
133    pdraw->base.psc = &psc->base;
134    pdraw->bufferCount = 0;
135    pdraw->swap_interval = dri_get_initial_swap_interval(psc->base.frontend_screen);
136    pdraw->have_back = 0;
137 
138    DRI2CreateDrawable(psc->base.dpy, xDrawable);
139    /* Create a new drawable */
140    pdraw->base.dri_drawable =
141       dri_create_drawable(psc->base.frontend_screen, config->driConfig, false, pdraw);
142 
143    if (!pdraw->base.dri_drawable) {
144       DRI2DestroyDrawable(psc->base.dpy, xDrawable);
145       free(pdraw);
146       return NULL;
147    }
148 
149    if (__glxHashInsert(dpyPriv->dri2Hash, xDrawable, pdraw)) {
150       driDestroyDrawable(pdraw->base.dri_drawable);
151       DRI2DestroyDrawable(psc->base.dpy, xDrawable);
152       free(pdraw);
153       return None;
154    }
155 
156    /*
157     * Make sure server has the same swap interval we do for the new
158     * drawable.
159     */
160    if (base->driScreen.setSwapInterval)
161       base->driScreen.setSwapInterval(&pdraw->base, pdraw->swap_interval);
162 
163    return &pdraw->base;
164 }
165 
166 static int
dri2DrawableGetMSC(struct glx_screen * psc,__GLXDRIdrawable * pdraw,int64_t * ust,int64_t * msc,int64_t * sbc)167 dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
168 		   int64_t *ust, int64_t *msc, int64_t *sbc)
169 {
170    xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
171    xcb_dri2_get_msc_cookie_t get_msc_cookie;
172    xcb_dri2_get_msc_reply_t *get_msc_reply;
173 
174    get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
175    get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
176 
177    if (!get_msc_reply)
178       return 0;
179 
180    *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
181    *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
182    *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
183    free(get_msc_reply);
184 
185    return 1;
186 }
187 
188 static int
dri2WaitForMSC(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,int64_t * ust,int64_t * msc,int64_t * sbc)189 dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
190 	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
191 {
192    xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
193    xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
194    xcb_dri2_wait_msc_reply_t *wait_msc_reply;
195    uint32_t target_msc_hi, target_msc_lo;
196    uint32_t divisor_hi, divisor_lo;
197    uint32_t remainder_hi, remainder_lo;
198 
199    split_counter(target_msc, &target_msc_hi, &target_msc_lo);
200    split_counter(divisor, &divisor_hi, &divisor_lo);
201    split_counter(remainder, &remainder_hi, &remainder_lo);
202 
203    wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
204                                                  target_msc_hi, target_msc_lo,
205                                                  divisor_hi, divisor_lo,
206                                                  remainder_hi, remainder_lo);
207    wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
208 
209    if (!wait_msc_reply)
210       return 0;
211 
212    *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
213    *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
214    *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
215    free(wait_msc_reply);
216 
217    return 1;
218 }
219 
220 static int
dri2WaitForSBC(__GLXDRIdrawable * pdraw,int64_t target_sbc,int64_t * ust,int64_t * msc,int64_t * sbc)221 dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
222 	       int64_t *msc, int64_t *sbc)
223 {
224    xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
225    xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
226    xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
227    uint32_t target_sbc_hi, target_sbc_lo;
228 
229    split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
230 
231    wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
232                                                  target_sbc_hi, target_sbc_lo);
233    wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
234 
235    if (!wait_sbc_reply)
236       return 0;
237 
238    *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
239    *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
240    *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
241    free(wait_sbc_reply);
242 
243    return 1;
244 }
245 
246 static __DRIcontext *
dri2GetCurrentContext()247 dri2GetCurrentContext()
248 {
249    struct glx_context *gc = __glXGetCurrentContext();
250 
251    return (gc != &dummyContext) ? gc->driContext : NULL;
252 }
253 
254 /**
255  * dri2Throttle - Request driver throttling
256  *
257  * This function uses the DRI2 throttle extension to give the
258  * driver the opportunity to throttle on flush front, copysubbuffer
259  * and swapbuffers.
260  */
261 static void
dri2Throttle(struct dri2_screen * psc,struct dri2_drawable * draw,enum __DRI2throttleReason reason)262 dri2Throttle(struct dri2_screen *psc,
263 	     struct dri2_drawable *draw,
264 	     enum __DRI2throttleReason reason)
265 {
266    __DRIcontext *ctx = dri2GetCurrentContext();
267 
268    dri_throttle(ctx, draw->base.dri_drawable, reason);
269 }
270 
271 /**
272  * Asks the driver to flush any queued work necessary for serializing with the
273  * X command stream, and optionally the slightly more strict requirement of
274  * glFlush() equivalence (which would require flushing even if nothing had
275  * been drawn to a window system framebuffer, for example).
276  */
277 static void
dri2Flush(struct dri2_screen * psc,__DRIcontext * ctx,struct dri2_drawable * draw,unsigned flags,enum __DRI2throttleReason throttle_reason)278 dri2Flush(struct dri2_screen *psc,
279           __DRIcontext *ctx,
280           struct dri2_drawable *draw,
281           unsigned flags,
282           enum __DRI2throttleReason throttle_reason)
283 {
284    if (ctx) {
285       dri_flush(ctx, draw->base.dri_drawable, flags, throttle_reason);
286    } else {
287       if (flags & __DRI2_FLUSH_CONTEXT)
288          glFlush();
289 
290       dri_flush_drawable(draw->base.dri_drawable);
291 
292       dri2Throttle(psc, draw, throttle_reason);
293    }
294 }
295 
296 static void
__dri2CopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,enum __DRI2throttleReason reason,Bool flush)297 __dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
298 		    int width, int height,
299 		    enum __DRI2throttleReason reason, Bool flush)
300 {
301    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
302    struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
303    XRectangle xrect;
304    XserverRegion region;
305    __DRIcontext *ctx = dri2GetCurrentContext();
306    unsigned flags;
307 
308    /* Check we have the right attachments */
309    if (!priv->have_back)
310       return;
311 
312    xrect.x = x;
313    xrect.y = priv->height - y - height;
314    xrect.width = width;
315    xrect.height = height;
316 
317    flags = __DRI2_FLUSH_DRAWABLE;
318    if (flush)
319       flags |= __DRI2_FLUSH_CONTEXT;
320    dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_COPYSUBBUFFER);
321 
322    region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
323    DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
324                   DRI2BufferFrontLeft, DRI2BufferBackLeft);
325 
326    /* Refresh the fake front (if present) after we just damaged the real
327     * front.
328     */
329    if (priv->have_fake_front)
330       DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
331 		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
332 
333    XFixesDestroyRegion(psc->base.dpy, region);
334 }
335 
336 static void
dri2CopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)337 dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
338 		  int width, int height, Bool flush)
339 {
340    __dri2CopySubBuffer(pdraw, x, y, width, height,
341 		       __DRI2_THROTTLE_COPYSUBBUFFER, flush);
342 }
343 
344 
345 static void
dri2_copy_drawable(struct dri2_drawable * priv,int dest,int src)346 dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
347 {
348    XRectangle xrect;
349    XserverRegion region;
350    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
351 
352    xrect.x = 0;
353    xrect.y = 0;
354    xrect.width = priv->width;
355    xrect.height = priv->height;
356 
357    dri_flush_drawable(priv->base.dri_drawable);
358 
359    region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
360    DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
361    XFixesDestroyRegion(psc->base.dpy, region);
362 
363 }
364 
365 static void
dri2_wait_x(struct glx_context * gc)366 dri2_wait_x(struct glx_context *gc)
367 {
368    struct dri2_drawable *priv = (struct dri2_drawable *)
369       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
370 
371    if (priv == NULL || !priv->have_fake_front)
372       return;
373 
374    dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
375 }
376 
377 static void
dri2_wait_gl(struct glx_context * gc)378 dri2_wait_gl(struct glx_context *gc)
379 {
380    struct dri2_drawable *priv = (struct dri2_drawable *)
381       GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
382 
383    if (priv == NULL || !priv->have_fake_front)
384       return;
385 
386    dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
387 }
388 
389 /**
390  * Called by the driver when it needs to update the real front buffer with the
391  * contents of its fake front buffer.
392  */
393 static void
dri2FlushFrontBuffer(__DRIdrawable * driDrawable,void * loaderPrivate)394 dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
395 {
396    struct glx_display *priv;
397    struct glx_context *gc;
398    struct dri2_drawable *pdraw = loaderPrivate;
399    struct dri2_screen *psc;
400 
401    if (!pdraw)
402       return;
403 
404    if (!pdraw->base.psc)
405       return;
406 
407    psc = (struct dri2_screen *) pdraw->base.psc;
408 
409    priv = __glXInitialize(psc->base.dpy);
410 
411    if (priv == NULL)
412        return;
413 
414    gc = __glXGetCurrentContext();
415 
416    dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
417 
418    dri2_wait_gl(gc);
419 }
420 
421 
422 static void
dri2DeinitScreen(struct glx_screen * base)423 dri2DeinitScreen(struct glx_screen *base)
424 {
425    struct dri2_screen *psc = (struct dri2_screen *) base;
426 
427    close(psc->fd);
428 }
429 
430 /**
431  * Process list of buffer received from the server
432  *
433  * Processes the list of buffers received in a reply from the server to either
434  * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
435  */
436 static void
process_buffers(struct dri2_drawable * pdraw,DRI2Buffer * buffers,unsigned count)437 process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
438                 unsigned count)
439 {
440    int i;
441 
442    pdraw->bufferCount = count;
443    pdraw->have_fake_front = 0;
444    pdraw->have_back = 0;
445 
446    /* This assumes the DRI2 buffer attachment tokens matches the
447     * __DRIbuffer tokens. */
448    for (i = 0; i < count; i++) {
449       pdraw->buffers[i].attachment = buffers[i].attachment;
450       pdraw->buffers[i].name = buffers[i].name;
451       pdraw->buffers[i].pitch = buffers[i].pitch;
452       pdraw->buffers[i].cpp = buffers[i].cpp;
453       pdraw->buffers[i].flags = buffers[i].flags;
454       if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
455          pdraw->have_fake_front = 1;
456       if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
457          pdraw->have_back = 1;
458    }
459 
460 }
461 
dri2GetSwapEventType(Display * dpy,XID drawable)462 unsigned dri2GetSwapEventType(Display* dpy, XID drawable)
463 {
464       struct glx_display *glx_dpy = __glXInitialize(dpy);
465       __GLXDRIdrawable *pdraw;
466       pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
467       if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
468          return 0;
469       return glx_dpy->codes.first_event + GLX_BufferSwapComplete;
470 }
471 
472 static int64_t
dri2XcbSwapBuffers(Display * dpy,__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder)473 dri2XcbSwapBuffers(Display *dpy,
474                   __GLXDRIdrawable *pdraw,
475                   int64_t target_msc,
476                   int64_t divisor,
477                   int64_t remainder)
478 {
479    xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
480    xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
481    uint32_t target_msc_hi, target_msc_lo;
482    uint32_t divisor_hi, divisor_lo;
483    uint32_t remainder_hi, remainder_lo;
484    int64_t ret = 0;
485    xcb_connection_t *c = XGetXCBConnection(dpy);
486 
487    split_counter(target_msc, &target_msc_hi, &target_msc_lo);
488    split_counter(divisor, &divisor_hi, &divisor_lo);
489    split_counter(remainder, &remainder_hi, &remainder_lo);
490 
491    swap_buffers_cookie =
492       xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
493                                       target_msc_hi, target_msc_lo,
494                                       divisor_hi, divisor_lo,
495                                       remainder_hi, remainder_lo);
496 
497    /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
498     * to do so some time before reusing a (non-pageflipped) backbuffer.
499     * Otherwise, the new rendering could get ahead of the X Server's
500     * dispatch of the swapbuffer and you'd display garbage.
501     *
502     * We use XSync() first to reap the invalidate events through the event
503     * filter, to ensure that the next drawing doesn't use an invalidated
504     * buffer.
505     */
506    XSync(dpy, False);
507 
508    swap_buffers_reply =
509       xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
510    if (swap_buffers_reply) {
511       ret = merge_counter(swap_buffers_reply->swap_hi,
512                           swap_buffers_reply->swap_lo);
513       free(swap_buffers_reply);
514    }
515    return ret;
516 }
517 
518 static int64_t
dri2SwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)519 dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
520 		int64_t remainder, Bool flush)
521 {
522     struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
523     struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
524     int64_t ret = 0;
525 
526     /* Check we have the right attachments */
527     if (!priv->have_back)
528 	return ret;
529 
530     __DRIcontext *ctx = dri2GetCurrentContext();
531     unsigned flags = __DRI2_FLUSH_DRAWABLE;
532     if (flush)
533        flags |= __DRI2_FLUSH_CONTEXT;
534     dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
535 
536     ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
537                              target_msc, divisor, remainder);
538 
539     return ret;
540 }
541 
542 static __DRIbuffer *
dri2GetBuffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)543 dri2GetBuffers(__DRIdrawable * driDrawable,
544                int *width, int *height,
545                unsigned int *attachments, int count,
546                int *out_count, void *loaderPrivate)
547 {
548    struct dri2_drawable *pdraw = loaderPrivate;
549    DRI2Buffer *buffers;
550 
551    buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
552                             width, height, attachments, count, out_count);
553    if (buffers == NULL)
554       return NULL;
555 
556    pdraw->width = *width;
557    pdraw->height = *height;
558    process_buffers(pdraw, buffers, *out_count);
559 
560    free(buffers);
561 
562    return pdraw->buffers;
563 }
564 
565 static __DRIbuffer *
dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)566 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
567                          int *width, int *height,
568                          unsigned int *attachments, int count,
569                          int *out_count, void *loaderPrivate)
570 {
571    struct dri2_drawable *pdraw = loaderPrivate;
572    DRI2Buffer *buffers;
573 
574    buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
575                                       pdraw->base.xDrawable,
576                                       width, height, attachments,
577                                       count, out_count);
578    if (buffers == NULL)
579       return NULL;
580 
581    pdraw->width = *width;
582    pdraw->height = *height;
583    process_buffers(pdraw, buffers, *out_count);
584 
585    free(buffers);
586 
587    return pdraw->buffers;
588 }
589 
590 static int
dri2SetSwapInterval(__GLXDRIdrawable * pdraw,int interval)591 dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
592 {
593    xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
594    struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
595    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
596 
597    if (!dri_valid_swap_interval(psc->base.frontend_screen, interval))
598       return GLX_BAD_VALUE;
599 
600    xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
601    priv->swap_interval = interval;
602 
603    return 0;
604 }
605 
606 static int
dri2GetSwapInterval(__GLXDRIdrawable * pdraw)607 dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
608 {
609    struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
610 
611   return priv->swap_interval;
612 }
613 
614 static const __DRIdri2LoaderExtension dri2LoaderExtension = {
615    .base = { __DRI_DRI2_LOADER, 3 },
616 
617    .getBuffers              = dri2GetBuffers,
618    .flushFrontBuffer        = dri2FlushFrontBuffer,
619    .getBuffersWithFormat    = dri2GetBuffersWithFormat,
620 };
621 
622 _X_HIDDEN void
dri2InvalidateBuffers(Display * dpy,XID drawable)623 dri2InvalidateBuffers(Display *dpy, XID drawable)
624 {
625    __GLXDRIdrawable *pdraw =
626       dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
627 
628    if (!pdraw)
629       return;
630 
631    dri_invalidate_drawable(pdraw->dri_drawable);
632 }
633 
634 static const struct glx_context_vtable dri2_context_vtable = {
635    .destroy             = dri_destroy_context,
636    .bind                = dri_bind_context,
637    .unbind              = dri_unbind_context,
638    .wait_gl             = dri2_wait_gl,
639    .wait_x              = dri2_wait_x,
640 };
641 
642 static const __DRIextension *loader_extensions[] = {
643    &dri2LoaderExtension.base,
644    &dri2UseInvalidate.base,
645    &driBackgroundCallable.base,
646    NULL
647 };
648 
649 struct glx_screen *
dri2CreateScreen(int screen,struct glx_display * priv,bool driver_name_is_inferred)650 dri2CreateScreen(int screen, struct glx_display * priv, bool driver_name_is_inferred)
651 {
652    struct dri2_screen *psc;
653    __GLXDRIscreen *psp;
654    char *driverName = NULL, *loader_driverName, *deviceName, *tmp;
655    drm_magic_t magic;
656 
657    psc = calloc(1, sizeof *psc);
658    if (psc == NULL)
659       return NULL;
660 
661    psc->fd = -1;
662 
663 
664    if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
665 		    &driverName, &deviceName)) {
666       glx_screen_cleanup(&psc->base);
667       free(psc);
668       InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
669       return NULL;
670    }
671 
672    psc->fd = loader_open_device(deviceName);
673    if (psc->fd < 0) {
674       ErrorMessageF("failed to open %s: %s\n", deviceName, strerror(errno));
675       goto handle_error;
676    }
677 
678    if (drmGetMagic(psc->fd, &magic)) {
679       ErrorMessageF("failed to get magic\n");
680       goto handle_error;
681    }
682 
683    if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
684       ErrorMessageF("failed to authenticate magic %d\n", magic);
685       goto handle_error;
686    }
687 
688    /* If Mesa knows about the appropriate driver for this fd, then trust it.
689     * Otherwise, default to the server's value.
690     */
691    loader_driverName = loader_get_driver_for_fd(psc->fd);
692    if (loader_driverName) {
693       free(driverName);
694       driverName = loader_driverName;
695    }
696    psc->base.driverName = driverName;
697    priv->driver = GLX_DRIVER_DRI2;
698 
699    if (!dri_screen_init(&psc->base, priv, screen, psc->fd, loader_extensions, driver_name_is_inferred)) {
700       ErrorMessageF("glx: failed to create dri2 screen\n");
701       goto handle_error;
702    }
703 
704    psc->base.context_vtable = &dri2_context_vtable;
705    psp = &psc->base.driScreen;
706    psp->deinitScreen = dri2DeinitScreen;
707    psp->createDrawable = dri2CreateDrawable;
708    psp->swapBuffers = dri2SwapBuffers;
709    psp->getDrawableMSC = NULL;
710    psp->waitForMSC = NULL;
711    psp->waitForSBC = NULL;
712    psp->setSwapInterval = NULL;
713    psp->getSwapInterval = NULL;
714 
715    psp->getDrawableMSC = dri2DrawableGetMSC;
716    psp->waitForMSC = dri2WaitForMSC;
717    psp->waitForSBC = dri2WaitForSBC;
718    psp->setSwapInterval = dri2SetSwapInterval;
719    psp->getSwapInterval = dri2GetSwapInterval;
720    psp->maxSwapInterval = INT_MAX;
721 
722    psc->base.can_EXT_texture_from_pixmap = true;
723 
724    /* DRI2 supports SubBuffer through DRI2CopyRegion, so it's always
725     * available.*/
726    psp->copySubBuffer = dri2CopySubBuffer;
727 
728    free(deviceName);
729 
730    tmp = getenv("LIBGL_SHOW_FPS");
731    psc->show_fps_interval = (tmp) ? atoi(tmp) : 0;
732    if (psc->show_fps_interval < 0)
733       psc->show_fps_interval = 0;
734 
735 
736    InfoMessageF("Using DRI2 for screen %d\n", screen);
737 
738    return &psc->base;
739 
740 handle_error:
741    CriticalErrorMessageF("failed to load driver: %s\n", driverName);
742 
743    if (psc->fd >= 0)
744       close(psc->fd);
745 
746    free(deviceName);
747    glx_screen_cleanup(&psc->base);
748    free(psc);
749 
750    return NULL;
751 }
752 
753 _X_HIDDEN __GLXDRIdrawable *
dri2GetGlxDrawableFromXDrawableId(Display * dpy,XID id)754 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
755 {
756    struct glx_display *d = __glXInitialize(dpy);
757    __GLXDRIdrawable *pdraw;
758 
759    if (__glxHashLookup(d->dri2Hash, id, (void *) &pdraw) == 0)
760       return pdraw;
761 
762    return NULL;
763 }
764 
765 bool
dri2CheckSupport(Display * dpy)766 dri2CheckSupport(Display *dpy)
767 {
768    int eventBase, errorBase;
769    int driMajor, driMinor;
770 
771    if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
772       return false;
773    if (!DRI2QueryVersion(dpy, &driMajor, &driMinor) ||
774        driMinor < 3) {
775       return false;
776    }
777    return true;
778 }
779 
780 #endif /* GLX_DIRECT_RENDERING */
781