dri3_glx.c revision af69d88d
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 "dri2.h"
80
81static const struct glx_context_vtable dri3_context_vtable;
82
83static inline void
84dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer)
85{
86   xshmfence_reset(buffer->shm_fence);
87}
88
89static inline void
90dri3_fence_set(struct dri3_buffer *buffer)
91{
92   xshmfence_trigger(buffer->shm_fence);
93}
94
95static inline void
96dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer)
97{
98   xcb_sync_trigger_fence(c, buffer->sync_fence);
99}
100
101static inline void
102dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer)
103{
104   xcb_flush(c);
105   xshmfence_await(buffer->shm_fence);
106}
107
108static inline Bool
109dri3_fence_triggered(struct dri3_buffer *buffer)
110{
111   return xshmfence_query(buffer->shm_fence);
112}
113
114static void
115dri3_destroy_context(struct glx_context *context)
116{
117   struct dri3_context *pcp = (struct dri3_context *) context;
118   struct dri3_screen *psc = (struct dri3_screen *) context->psc;
119
120   driReleaseDrawables(&pcp->base);
121
122   free((char *) context->extensions);
123
124   (*psc->core->destroyContext) (pcp->driContext);
125
126   free(pcp);
127}
128
129static Bool
130dri3_bind_context(struct glx_context *context, struct glx_context *old,
131                  GLXDrawable draw, GLXDrawable read)
132{
133   struct dri3_context *pcp = (struct dri3_context *) context;
134   struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
135   struct dri3_drawable *pdraw, *pread;
136
137   pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw);
138   pread = (struct dri3_drawable *) driFetchDrawable(context, read);
139
140   driReleaseDrawables(&pcp->base);
141
142   if (pdraw == NULL || pread == NULL)
143      return GLXBadDrawable;
144
145   if (!(*psc->core->bindContext) (pcp->driContext,
146                                   pdraw->driDrawable, pread->driDrawable))
147      return GLXBadContext;
148
149   return Success;
150}
151
152static void
153dri3_unbind_context(struct glx_context *context, struct glx_context *new)
154{
155   struct dri3_context *pcp = (struct dri3_context *) context;
156   struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc;
157
158   (*psc->core->unbindContext) (pcp->driContext);
159}
160
161static struct glx_context *
162dri3_create_context_attribs(struct glx_screen *base,
163                            struct glx_config *config_base,
164                            struct glx_context *shareList,
165                            unsigned num_attribs,
166                            const uint32_t *attribs,
167                            unsigned *error)
168{
169   struct dri3_context *pcp = NULL;
170   struct dri3_context *pcp_shared = NULL;
171   struct dri3_screen *psc = (struct dri3_screen *) base;
172   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
173   __DRIcontext *shared = NULL;
174
175   uint32_t minor_ver = 1;
176   uint32_t major_ver = 2;
177   uint32_t flags = 0;
178   unsigned api;
179   int reset = __DRI_CTX_RESET_NO_NOTIFICATION;
180   uint32_t ctx_attribs[2 * 5];
181   unsigned num_ctx_attribs = 0;
182   uint32_t render_type;
183
184   /* Remap the GLX tokens to DRI2 tokens.
185    */
186   if (!dri2_convert_glx_attribs(num_attribs, attribs,
187                                 &major_ver, &minor_ver,
188                                 &render_type, &flags, &api,
189                                 &reset, error))
190      goto error_exit;
191
192   /* Check the renderType value */
193   if (!validate_renderType_against_config(config_base, render_type))
194       goto error_exit;
195
196   if (shareList) {
197      pcp_shared = (struct dri3_context *) shareList;
198      shared = pcp_shared->driContext;
199   }
200
201   pcp = calloc(1, sizeof *pcp);
202   if (pcp == NULL) {
203      *error = __DRI_CTX_ERROR_NO_MEMORY;
204      goto error_exit;
205   }
206
207   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
208      goto error_exit;
209
210   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
211   ctx_attribs[num_ctx_attribs++] = major_ver;
212   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
213   ctx_attribs[num_ctx_attribs++] = minor_ver;
214
215   /* Only send a value when the non-default value is requested.  By doing
216    * this we don't have to check the driver's DRI3 version before sending the
217    * default value.
218    */
219   if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
220      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
221      ctx_attribs[num_ctx_attribs++] = reset;
222   }
223
224   if (flags != 0) {
225      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
226
227      /* The current __DRI_CTX_FLAG_* values are identical to the
228       * GLX_CONTEXT_*_BIT values.
229       */
230      ctx_attribs[num_ctx_attribs++] = flags;
231   }
232
233   pcp->driContext =
234      (*psc->image_driver->createContextAttribs) (psc->driScreen,
235                                                  api,
236                                                  config->driConfig,
237                                                  shared,
238                                                  num_ctx_attribs / 2,
239                                                  ctx_attribs,
240                                                  error,
241                                                  pcp);
242
243   if (pcp->driContext == NULL)
244      goto error_exit;
245
246   pcp->base.vtable = &dri3_context_vtable;
247
248   return &pcp->base;
249
250error_exit:
251   free(pcp);
252
253   return NULL;
254}
255
256static struct glx_context *
257dri3_create_context(struct glx_screen *base,
258                    struct glx_config *config_base,
259                    struct glx_context *shareList, int renderType)
260{
261   unsigned int error;
262
263   return dri3_create_context_attribs(base, config_base, shareList,
264                                      0, NULL, &error);
265}
266
267static void
268dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer);
269
270static void
271dri3_update_num_back(struct dri3_drawable *priv)
272{
273   priv->num_back = 1;
274   if (priv->flipping)
275      priv->num_back++;
276   if (priv->swap_interval == 0)
277      priv->num_back++;
278}
279
280static void
281dri3_destroy_drawable(__GLXDRIdrawable *base)
282{
283   struct dri3_screen *psc = (struct dri3_screen *) base->psc;
284   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
285   xcb_connection_t     *c = XGetXCBConnection(pdraw->base.psc->dpy);
286   int i;
287
288   (*psc->core->destroyDrawable) (pdraw->driDrawable);
289
290   for (i = 0; i < DRI3_NUM_BUFFERS; i++) {
291      if (pdraw->buffers[i])
292         dri3_free_render_buffer(pdraw, pdraw->buffers[i]);
293   }
294
295   if (pdraw->special_event)
296      xcb_unregister_for_special_event(c, pdraw->special_event);
297   free(pdraw);
298}
299
300static __GLXDRIdrawable *
301dri3_create_drawable(struct glx_screen *base, XID xDrawable,
302                     GLXDrawable drawable, struct glx_config *config_base)
303{
304   struct dri3_drawable *pdraw;
305   struct dri3_screen *psc = (struct dri3_screen *) base;
306   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
307   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
308
309   pdraw = calloc(1, sizeof(*pdraw));
310   if (!pdraw)
311      return NULL;
312
313   pdraw->base.destroyDrawable = dri3_destroy_drawable;
314   pdraw->base.xDrawable = xDrawable;
315   pdraw->base.drawable = drawable;
316   pdraw->base.psc = &psc->base;
317   pdraw->swap_interval = 1; /* default may be overridden below */
318   pdraw->have_back = 0;
319   pdraw->have_fake_front = 0;
320
321   if (psc->config)
322      psc->config->configQueryi(psc->driScreen,
323                                "vblank_mode", &vblank_mode);
324
325   switch (vblank_mode) {
326   case DRI_CONF_VBLANK_NEVER:
327   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
328      pdraw->swap_interval = 0;
329      break;
330   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
331   case DRI_CONF_VBLANK_ALWAYS_SYNC:
332   default:
333      pdraw->swap_interval = 1;
334      break;
335   }
336
337   dri3_update_num_back(pdraw);
338
339   (void) __glXInitialize(psc->base.dpy);
340
341   /* Create a new drawable */
342   pdraw->driDrawable =
343      (*psc->image_driver->createNewDrawable) (psc->driScreen,
344                                               config->driConfig, pdraw);
345
346   if (!pdraw->driDrawable) {
347      free(pdraw);
348      return NULL;
349   }
350
351   /*
352    * Make sure server has the same swap interval we do for the new
353    * drawable.
354    */
355   if (psc->vtable.setSwapInterval)
356      psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
357
358   return &pdraw->base;
359}
360
361/*
362 * Process one Present event
363 */
364static void
365dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_t *ge)
366{
367   switch (ge->evtype) {
368   case XCB_PRESENT_CONFIGURE_NOTIFY: {
369      xcb_present_configure_notify_event_t *ce = (void *) ge;
370
371      priv->width = ce->width;
372      priv->height = ce->height;
373      break;
374   }
375   case XCB_PRESENT_COMPLETE_NOTIFY: {
376      xcb_present_complete_notify_event_t *ce = (void *) ge;
377
378      /* Compute the processed SBC number from the received 32-bit serial number merged
379       * with the upper 32-bits of the sent 64-bit serial number while checking for
380       * wrap
381       */
382      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
383         priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial;
384         if (priv->recv_sbc > priv->send_sbc)
385            priv->recv_sbc -= 0x100000000;
386         switch (ce->mode) {
387         case XCB_PRESENT_COMPLETE_MODE_FLIP:
388            priv->flipping = true;
389            break;
390         case XCB_PRESENT_COMPLETE_MODE_COPY:
391            priv->flipping = false;
392            break;
393         }
394         dri3_update_num_back(priv);
395      } else {
396         priv->recv_msc_serial = ce->serial;
397      }
398      priv->ust = ce->ust;
399      priv->msc = ce->msc;
400      break;
401   }
402   case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
403      xcb_present_idle_notify_event_t *ie = (void *) ge;
404      int b;
405
406      for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) {
407         struct dri3_buffer        *buf = priv->buffers[b];
408
409         if (buf && buf->pixmap == ie->pixmap) {
410            buf->busy = 0;
411            if (priv->num_back <= b && b < DRI3_MAX_BACK) {
412               dri3_free_render_buffer(priv, buf);
413               priv->buffers[b] = NULL;
414            }
415            break;
416         }
417      }
418      break;
419   }
420   }
421   free(ge);
422}
423
424static bool
425dri3_wait_for_event(__GLXDRIdrawable *pdraw)
426{
427   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
428   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
429   xcb_generic_event_t *ev;
430   xcb_present_generic_event_t *ge;
431
432   xcb_flush(c);
433   ev = xcb_wait_for_special_event(c, priv->special_event);
434   if (!ev)
435      return false;
436   ge = (void *) ev;
437   dri3_handle_present_event(priv, ge);
438   return true;
439}
440
441/** dri3_wait_for_msc
442 *
443 * Get the X server to send an event when the target msc/divisor/remainder is
444 * reached.
445 */
446static int
447dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
448                  int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
449{
450   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
451   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
452   uint32_t msc_serial;
453
454   /* Ask for the an event for the target MSC */
455   msc_serial = ++priv->send_msc_serial;
456   xcb_present_notify_msc(c,
457                          priv->base.xDrawable,
458                          msc_serial,
459                          target_msc,
460                          divisor,
461                          remainder);
462
463   xcb_flush(c);
464
465   /* Wait for the event */
466   if (priv->special_event) {
467      while ((int32_t) (msc_serial - priv->recv_msc_serial) > 0) {
468         if (!dri3_wait_for_event(pdraw))
469            return 0;
470      }
471   }
472
473   *ust = priv->ust;
474   *msc = priv->msc;
475   *sbc = priv->recv_sbc;
476
477   return 1;
478}
479
480/** dri3_drawable_get_msc
481 *
482 * Return the current UST/MSC/SBC triplet by asking the server
483 * for an event
484 */
485static int
486dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
487                      int64_t *ust, int64_t *msc, int64_t *sbc)
488{
489   return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc);
490}
491
492/** dri3_wait_for_sbc
493 *
494 * Wait for the completed swap buffer count to reach the specified
495 * target. Presumably the application knows that this will be reached with
496 * outstanding complete events, or we're going to be here awhile.
497 */
498static int
499dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
500                  int64_t *msc, int64_t *sbc)
501{
502   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
503
504   while (priv->recv_sbc < target_sbc) {
505      if (!dri3_wait_for_event(pdraw))
506         return 0;
507   }
508
509   *ust = priv->ust;
510   *msc = priv->msc;
511   *sbc = priv->recv_sbc;
512   return 1;
513}
514
515/**
516 * Asks the driver to flush any queued work necessary for serializing with the
517 * X command stream, and optionally the slightly more strict requirement of
518 * glFlush() equivalence (which would require flushing even if nothing had
519 * been drawn to a window system framebuffer, for example).
520 */
521static void
522dri3_flush(struct dri3_screen *psc,
523           struct dri3_drawable *draw,
524           unsigned flags,
525           enum __DRI2throttleReason throttle_reason)
526{
527   struct glx_context *gc = __glXGetCurrentContext();
528
529   if (gc) {
530      struct dri3_context *dri3Ctx = (struct dri3_context *)gc;
531
532      (*psc->f->flush_with_flags)(dri3Ctx->driContext, draw->driDrawable, flags, throttle_reason);
533   }
534}
535
536static xcb_gcontext_t
537dri3_drawable_gc(struct dri3_drawable *priv)
538{
539   if (!priv->gc) {
540      uint32_t v;
541      xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy);
542
543      v = 0;
544      xcb_create_gc(c,
545                    (priv->gc = xcb_generate_id(c)),
546                    priv->base.xDrawable,
547                    XCB_GC_GRAPHICS_EXPOSURES,
548                    &v);
549   }
550   return priv->gc;
551}
552
553static struct dri3_buffer *
554dri3_back_buffer(struct dri3_drawable *priv)
555{
556   return priv->buffers[DRI3_BACK_ID(priv->cur_back)];
557}
558
559static struct dri3_buffer *
560dri3_fake_front_buffer(struct dri3_drawable *priv)
561{
562   return priv->buffers[DRI3_FRONT_ID];
563}
564
565static void
566dri3_copy_area (xcb_connection_t *c  /**< */,
567                xcb_drawable_t    src_drawable  /**< */,
568                xcb_drawable_t    dst_drawable  /**< */,
569                xcb_gcontext_t    gc  /**< */,
570                int16_t           src_x  /**< */,
571                int16_t           src_y  /**< */,
572                int16_t           dst_x  /**< */,
573                int16_t           dst_y  /**< */,
574                uint16_t          width  /**< */,
575                uint16_t          height  /**< */)
576{
577   xcb_void_cookie_t cookie;
578
579   cookie = xcb_copy_area_checked(c,
580                                  src_drawable,
581                                  dst_drawable,
582                                  gc,
583                                  src_x,
584                                  src_y,
585                                  dst_x,
586                                  dst_y,
587                                  width,
588                                  height);
589   xcb_discard_reply(c, cookie.sequence);
590}
591
592static void
593dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y,
594                     int width, int height,
595                     Bool flush)
596{
597   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
598   struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc;
599   struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
600   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
601   struct dri3_buffer *back;
602
603   unsigned flags = __DRI2_FLUSH_DRAWABLE;
604
605   /* Check we have the right attachments */
606   if (!priv->have_back || priv->is_pixmap)
607      return;
608
609   if (flush)
610      flags |= __DRI2_FLUSH_CONTEXT;
611   dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
612
613   back = dri3_back_buffer(priv);
614   y = priv->height - y - height;
615
616   if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) {
617      /* Update the linear buffer part of the back buffer
618       * for the dri3_copy_area operation
619       */
620      psc->image->blitImage(pcp->driContext,
621                            back->linear_buffer,
622                            back->image,
623                            0, 0, back->width,
624                            back->height,
625                            0, 0, back->width,
626                            back->height, __BLIT_FLAG_FLUSH);
627      /* We use blitImage to update our fake front,
628       */
629      if (priv->have_fake_front)
630         psc->image->blitImage(pcp->driContext,
631                               dri3_fake_front_buffer(priv)->image,
632                               back->image,
633                               x, y, width, height,
634                               x, y, width, height, __BLIT_FLAG_FLUSH);
635   }
636
637   dri3_fence_reset(c, back);
638   dri3_copy_area(c,
639                  dri3_back_buffer(priv)->pixmap,
640                  priv->base.xDrawable,
641                  dri3_drawable_gc(priv),
642                  x, y, x, y, width, height);
643   dri3_fence_trigger(c, back);
644   /* Refresh the fake front (if present) after we just damaged the real
645    * front.
646    */
647   if (priv->have_fake_front && !psc->is_different_gpu) {
648      dri3_fence_reset(c, dri3_fake_front_buffer(priv));
649      dri3_copy_area(c,
650                     dri3_back_buffer(priv)->pixmap,
651                     dri3_fake_front_buffer(priv)->pixmap,
652                     dri3_drawable_gc(priv),
653                     x, y, x, y, width, height);
654      dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
655      dri3_fence_await(c, dri3_fake_front_buffer(priv));
656   }
657   dri3_fence_await(c, back);
658}
659
660static void
661dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src)
662{
663   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
664   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
665
666   dri3_flush(psc, priv, __DRI2_FLUSH_DRAWABLE, 0);
667
668   dri3_fence_reset(c, dri3_fake_front_buffer(priv));
669   dri3_copy_area(c,
670                  src, dest,
671                  dri3_drawable_gc(priv),
672                  0, 0, 0, 0, priv->width, priv->height);
673   dri3_fence_trigger(c, dri3_fake_front_buffer(priv));
674   dri3_fence_await(c, dri3_fake_front_buffer(priv));
675}
676
677static void
678dri3_wait_x(struct glx_context *gc)
679{
680   struct dri3_context *pcp = (struct dri3_context *) gc;
681   struct dri3_drawable *priv = (struct dri3_drawable *)
682      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
683   struct dri3_screen *psc;
684   struct dri3_buffer *front;
685
686   if (priv == NULL || !priv->have_fake_front)
687      return;
688
689   psc = (struct dri3_screen *) priv->base.psc;
690   front = dri3_fake_front_buffer(priv);
691
692   dri3_copy_drawable(priv, front->pixmap, priv->base.xDrawable);
693
694   /* In the psc->is_different_gpu case, the linear buffer has been updated,
695    * but not yet the tiled buffer.
696    * Copy back to the tiled buffer we use for rendering.
697    * Note that we don't need flushing.
698    */
699   if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base)
700      psc->image->blitImage(pcp->driContext,
701                            front->image,
702                            front->linear_buffer,
703                            0, 0, front->width,
704                            front->height,
705                            0, 0, front->width,
706                            front->height, 0);
707}
708
709static void
710dri3_wait_gl(struct glx_context *gc)
711{
712   struct dri3_context *pcp = (struct dri3_context *) gc;
713   struct dri3_drawable *priv = (struct dri3_drawable *)
714      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
715   struct dri3_screen *psc;
716   struct dri3_buffer *front;
717
718   if (priv == NULL || !priv->have_fake_front)
719      return;
720
721   psc = (struct dri3_screen *) priv->base.psc;
722   front = dri3_fake_front_buffer(priv);
723
724   /* In the psc->is_different_gpu case, we update the linear_buffer
725    * before updating the real front.
726    */
727   if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base)
728      psc->image->blitImage(pcp->driContext,
729                            front->linear_buffer,
730                            front->image,
731                            0, 0, front->width,
732                            front->height,
733                            0, 0, front->width,
734                            front->height, __BLIT_FLAG_FLUSH);
735   dri3_copy_drawable(priv, priv->base.xDrawable, front->pixmap);
736}
737
738/**
739 * Called by the driver when it needs to update the real front buffer with the
740 * contents of its fake front buffer.
741 */
742static void
743dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
744{
745   struct glx_context *gc;
746   struct dri3_drawable *pdraw = loaderPrivate;
747   struct dri3_screen *psc;
748
749   if (!pdraw)
750      return;
751
752   if (!pdraw->base.psc)
753      return;
754
755   psc = (struct dri3_screen *) pdraw->base.psc;
756
757   (void) __glXInitialize(psc->base.dpy);
758
759   gc = __glXGetCurrentContext();
760
761   dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT);
762
763   dri3_wait_gl(gc);
764}
765
766static uint32_t
767dri3_cpp_for_format(uint32_t format) {
768   switch (format) {
769   case  __DRI_IMAGE_FORMAT_R8:
770      return 1;
771   case  __DRI_IMAGE_FORMAT_RGB565:
772   case  __DRI_IMAGE_FORMAT_GR88:
773      return 2;
774   case  __DRI_IMAGE_FORMAT_XRGB8888:
775   case  __DRI_IMAGE_FORMAT_ARGB8888:
776   case  __DRI_IMAGE_FORMAT_ABGR8888:
777   case  __DRI_IMAGE_FORMAT_XBGR8888:
778   case  __DRI_IMAGE_FORMAT_XRGB2101010:
779   case  __DRI_IMAGE_FORMAT_ARGB2101010:
780   case  __DRI_IMAGE_FORMAT_SARGB8:
781      return 4;
782   case  __DRI_IMAGE_FORMAT_NONE:
783   default:
784      return 0;
785   }
786}
787
788
789/** dri3_alloc_render_buffer
790 *
791 * Use the driver createImage function to construct a __DRIimage, then
792 * get a file descriptor for that and create an X pixmap from that
793 *
794 * Allocate an xshmfence for synchronization
795 */
796static struct dri3_buffer *
797dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw,
798                         unsigned int format, int width, int height, int depth)
799{
800   struct dri3_screen *psc = (struct dri3_screen *) glx_screen;
801   Display *dpy = glx_screen->dpy;
802   struct dri3_buffer *buffer;
803   __DRIimage *pixmap_buffer;
804   xcb_connection_t *c = XGetXCBConnection(dpy);
805   xcb_pixmap_t pixmap;
806   xcb_sync_fence_t sync_fence;
807   struct xshmfence *shm_fence;
808   int buffer_fd, fence_fd;
809   int stride;
810
811   /* Create an xshmfence object and
812    * prepare to send that to the X server
813    */
814
815   fence_fd = xshmfence_alloc_shm();
816   if (fence_fd < 0) {
817      ErrorMessageF("DRI3 Fence object allocation failure %s\n", strerror(errno));
818      return NULL;
819   }
820   shm_fence = xshmfence_map_shm(fence_fd);
821   if (shm_fence == NULL) {
822      ErrorMessageF("DRI3 Fence object map failure %s\n", strerror(errno));
823      goto no_shm_fence;
824   }
825
826   /* Allocate the image from the driver
827    */
828   buffer = calloc(1, sizeof (struct dri3_buffer));
829   if (!buffer)
830      goto no_buffer;
831
832   buffer->cpp = dri3_cpp_for_format(format);
833   if (!buffer->cpp) {
834      ErrorMessageF("DRI3 buffer format %d invalid\n", format);
835      goto no_image;
836   }
837
838   if (!psc->is_different_gpu) {
839      buffer->image = (*psc->image->createImage) (psc->driScreen,
840                                                  width, height,
841                                                  format,
842                                                  __DRI_IMAGE_USE_SHARE |
843                                                  __DRI_IMAGE_USE_SCANOUT,
844                                                  buffer);
845      pixmap_buffer = buffer->image;
846
847      if (!buffer->image) {
848         ErrorMessageF("DRI3 gpu image creation failure\n");
849         goto no_image;
850      }
851   } else {
852      buffer->image = (*psc->image->createImage) (psc->driScreen,
853                                                  width, height,
854                                                  format,
855                                                  0,
856                                                  buffer);
857
858      if (!buffer->image) {
859         ErrorMessageF("DRI3 other gpu image creation failure\n");
860         goto no_image;
861      }
862
863      buffer->linear_buffer = (*psc->image->createImage) (psc->driScreen,
864                                                          width, height,
865                                                          format,
866                                                          __DRI_IMAGE_USE_SHARE |
867                                                          __DRI_IMAGE_USE_LINEAR,
868                                                          buffer);
869      pixmap_buffer = buffer->linear_buffer;
870
871      if (!buffer->linear_buffer) {
872         ErrorMessageF("DRI3 gpu linear image creation failure\n");
873         goto no_linear_buffer;
874      }
875   }
876
877   /* X wants the stride, so ask the image for it
878    */
879   if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) {
880      ErrorMessageF("DRI3 get image stride failed\n");
881      goto no_buffer_attrib;
882   }
883
884   buffer->pitch = stride;
885
886   if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) {
887      ErrorMessageF("DRI3 get image FD failed\n");
888      goto no_buffer_attrib;
889   }
890
891   xcb_dri3_pixmap_from_buffer(c,
892                               (pixmap = xcb_generate_id(c)),
893                               draw,
894                               buffer->size,
895                               width, height, buffer->pitch,
896                               depth, buffer->cpp * 8,
897                               buffer_fd);
898
899   xcb_dri3_fence_from_fd(c,
900                          pixmap,
901                          (sync_fence = xcb_generate_id(c)),
902                          false,
903                          fence_fd);
904
905   buffer->pixmap = pixmap;
906   buffer->own_pixmap = true;
907   buffer->sync_fence = sync_fence;
908   buffer->shm_fence = shm_fence;
909   buffer->width = width;
910   buffer->height = height;
911
912   /* Mark the buffer as idle
913    */
914   dri3_fence_set(buffer);
915
916   return buffer;
917
918no_buffer_attrib:
919   (*psc->image->destroyImage)(pixmap_buffer);
920no_linear_buffer:
921   if (psc->is_different_gpu)
922      (*psc->image->destroyImage)(buffer->image);
923no_image:
924   free(buffer);
925no_buffer:
926   xshmfence_unmap_shm(shm_fence);
927no_shm_fence:
928   close(fence_fd);
929   ErrorMessageF("DRI3 alloc_render_buffer failed\n");
930   return NULL;
931}
932
933/** dri3_free_render_buffer
934 *
935 * Free everything associated with one render buffer including pixmap, fence
936 * stuff and the driver image
937 */
938static void
939dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer)
940{
941   struct dri3_screen   *psc = (struct dri3_screen *) pdraw->base.psc;
942   xcb_connection_t     *c = XGetXCBConnection(pdraw->base.psc->dpy);
943
944   if (buffer->own_pixmap)
945      xcb_free_pixmap(c, buffer->pixmap);
946   xcb_sync_destroy_fence(c, buffer->sync_fence);
947   xshmfence_unmap_shm(buffer->shm_fence);
948   (*psc->image->destroyImage)(buffer->image);
949   if (buffer->linear_buffer)
950      (*psc->image->destroyImage)(buffer->linear_buffer);
951   free(buffer);
952}
953
954
955/** dri3_flush_present_events
956 *
957 * Process any present events that have been received from the X server
958 */
959static void
960dri3_flush_present_events(struct dri3_drawable *priv)
961{
962   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
963
964   /* Check to see if any configuration changes have occurred
965    * since we were last invoked
966    */
967   if (priv->special_event) {
968      xcb_generic_event_t    *ev;
969
970      while ((ev = xcb_poll_for_special_event(c, priv->special_event)) != NULL) {
971         xcb_present_generic_event_t *ge = (void *) ev;
972         dri3_handle_present_event(priv, ge);
973      }
974   }
975}
976
977/** dri3_update_drawable
978 *
979 * Called the first time we use the drawable and then
980 * after we receive present configure notify events to
981 * track the geometry of the drawable
982 */
983static int
984dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate)
985{
986   struct dri3_drawable *priv = loaderPrivate;
987   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
988
989   /* First time through, go get the current drawable geometry
990    */
991   if (priv->width == 0 || priv->height == 0 || priv->depth == 0) {
992      xcb_get_geometry_cookie_t                 geom_cookie;
993      xcb_get_geometry_reply_t                  *geom_reply;
994      xcb_void_cookie_t                         cookie;
995      xcb_generic_error_t                       *error;
996
997      /* Try to select for input on the window.
998       *
999       * If the drawable is a window, this will get our events
1000       * delivered.
1001       *
1002       * Otherwise, we'll get a BadWindow error back from this request which
1003       * will let us know that the drawable is a pixmap instead.
1004       */
1005
1006
1007      cookie = xcb_present_select_input_checked(c,
1008                                                (priv->eid = xcb_generate_id(c)),
1009                                                priv->base.xDrawable,
1010                                                XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
1011                                                XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
1012                                                XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
1013
1014      /* Create an XCB event queue to hold present events outside of the usual
1015       * application event queue
1016       */
1017      priv->special_event = xcb_register_for_special_xge(c,
1018                                                         &xcb_present_id,
1019                                                         priv->eid,
1020                                                         priv->stamp);
1021
1022      geom_cookie = xcb_get_geometry(c, priv->base.xDrawable);
1023
1024      geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
1025
1026      if (!geom_reply)
1027         return false;
1028
1029      priv->width = geom_reply->width;
1030      priv->height = geom_reply->height;
1031      priv->depth = geom_reply->depth;
1032      priv->is_pixmap = false;
1033
1034      free(geom_reply);
1035
1036      /* Check to see if our select input call failed. If it failed with a
1037       * BadWindow error, then assume the drawable is a pixmap. Destroy the
1038       * special event queue created above and mark the drawable as a pixmap
1039       */
1040
1041      error = xcb_request_check(c, cookie);
1042
1043      if (error) {
1044         if (error->error_code != BadWindow) {
1045            free(error);
1046            return false;
1047         }
1048         priv->is_pixmap = true;
1049         xcb_unregister_for_special_event(c, priv->special_event);
1050         priv->special_event = NULL;
1051      }
1052   }
1053   dri3_flush_present_events(priv);
1054   return true;
1055}
1056
1057/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
1058 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
1059 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
1060 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds
1061 */
1062static int
1063image_format_to_fourcc(int format)
1064{
1065
1066   /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
1067   switch (format) {
1068   case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
1069   case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
1070   case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
1071   case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
1072   case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888;
1073   case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888;
1074   }
1075   return 0;
1076}
1077
1078/** dri3_get_pixmap_buffer
1079 *
1080 * Get the DRM object for a pixmap from the X server and
1081 * wrap that with a __DRIimage structure using createImageFromFds
1082 */
1083static struct dri3_buffer *
1084dri3_get_pixmap_buffer(__DRIdrawable *driDrawable,
1085                       unsigned int format,
1086                       enum dri3_buffer_type buffer_type,
1087                       void *loaderPrivate)
1088{
1089   struct dri3_drawable                 *pdraw = loaderPrivate;
1090   int                                  buf_id = dri3_pixmap_buf_id(buffer_type);
1091   struct dri3_buffer                   *buffer = pdraw->buffers[buf_id];
1092   Pixmap                               pixmap;
1093   xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;
1094   xcb_dri3_buffer_from_pixmap_reply_t  *bp_reply;
1095   int                                  *fds;
1096   Display                              *dpy;
1097   struct dri3_screen                   *psc;
1098   xcb_connection_t                     *c;
1099   xcb_sync_fence_t                     sync_fence;
1100   struct xshmfence                     *shm_fence;
1101   int                                  fence_fd;
1102   __DRIimage                           *image_planar;
1103   int                                  stride, offset;
1104
1105   if (buffer)
1106      return buffer;
1107
1108   pixmap = pdraw->base.xDrawable;
1109   psc = (struct dri3_screen *) pdraw->base.psc;
1110   dpy = psc->base.dpy;
1111   c = XGetXCBConnection(dpy);
1112
1113   buffer = calloc(1, sizeof (struct dri3_buffer));
1114   if (!buffer)
1115      goto no_buffer;
1116
1117   fence_fd = xshmfence_alloc_shm();
1118   if (fence_fd < 0)
1119      goto no_fence;
1120   shm_fence = xshmfence_map_shm(fence_fd);
1121   if (shm_fence == NULL) {
1122      close (fence_fd);
1123      goto no_fence;
1124   }
1125
1126   xcb_dri3_fence_from_fd(c,
1127                          pixmap,
1128                          (sync_fence = xcb_generate_id(c)),
1129                          false,
1130                          fence_fd);
1131
1132   /* Get an FD for the pixmap object
1133    */
1134   bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap);
1135   bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL);
1136   if (!bp_reply)
1137      goto no_image;
1138   fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply);
1139
1140   stride = bp_reply->stride;
1141   offset = 0;
1142
1143   /* createImageFromFds creates a wrapper __DRIimage structure which
1144    * can deal with multiple planes for things like Yuv images. So, once
1145    * we've gotten the planar wrapper, pull the single plane out of it and
1146    * discard the wrapper.
1147    */
1148   image_planar = (*psc->image->createImageFromFds) (psc->driScreen,
1149                                                     bp_reply->width,
1150                                                     bp_reply->height,
1151                                                     image_format_to_fourcc(format),
1152                                                     fds, 1,
1153                                                     &stride, &offset, buffer);
1154   close(fds[0]);
1155   if (!image_planar)
1156      goto no_image;
1157
1158   buffer->image = (*psc->image->fromPlanar)(image_planar, 0, buffer);
1159
1160   (*psc->image->destroyImage)(image_planar);
1161
1162   if (!buffer->image)
1163      goto no_image;
1164
1165   buffer->pixmap = pixmap;
1166   buffer->own_pixmap = false;
1167   buffer->width = bp_reply->width;
1168   buffer->height = bp_reply->height;
1169   buffer->buffer_type = buffer_type;
1170   buffer->shm_fence = shm_fence;
1171   buffer->sync_fence = sync_fence;
1172
1173   pdraw->buffers[buf_id] = buffer;
1174   return buffer;
1175
1176no_image:
1177   xcb_sync_destroy_fence(c, sync_fence);
1178   xshmfence_unmap_shm(shm_fence);
1179no_fence:
1180   free(buffer);
1181no_buffer:
1182   return NULL;
1183}
1184
1185/** dri3_find_back
1186 *
1187 * Find an idle back buffer. If there isn't one, then
1188 * wait for a present idle notify event from the X server
1189 */
1190static int
1191dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv)
1192{
1193   int  b;
1194   xcb_generic_event_t *ev;
1195   xcb_present_generic_event_t *ge;
1196
1197   for (;;) {
1198      for (b = 0; b < priv->num_back; b++) {
1199         int id = DRI3_BACK_ID((b + priv->cur_back) % priv->num_back);
1200         struct dri3_buffer *buffer = priv->buffers[id];
1201
1202         if (!buffer || !buffer->busy) {
1203            priv->cur_back = id;
1204            return id;
1205         }
1206      }
1207      xcb_flush(c);
1208      ev = xcb_wait_for_special_event(c, priv->special_event);
1209      if (!ev)
1210         return -1;
1211      ge = (void *) ev;
1212      dri3_handle_present_event(priv, ge);
1213   }
1214}
1215
1216/** dri3_get_buffer
1217 *
1218 * Find a front or back buffer, allocating new ones as necessary
1219 */
1220static struct dri3_buffer *
1221dri3_get_buffer(__DRIdrawable *driDrawable,
1222                unsigned int format,
1223                enum dri3_buffer_type buffer_type,
1224                void *loaderPrivate)
1225{
1226   struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
1227   struct dri3_drawable *priv = loaderPrivate;
1228   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1229   xcb_connection_t     *c = XGetXCBConnection(priv->base.psc->dpy);
1230   struct dri3_buffer      *buffer;
1231   int                  buf_id;
1232
1233   if (buffer_type == dri3_buffer_back) {
1234      buf_id = dri3_find_back(c, priv);
1235
1236      if (buf_id < 0)
1237         return NULL;
1238   } else {
1239      buf_id = DRI3_FRONT_ID;
1240   }
1241
1242   buffer = priv->buffers[buf_id];
1243
1244   /* Allocate a new buffer if there isn't an old one, or if that
1245    * old one is the wrong size
1246    */
1247   if (!buffer || buffer->width != priv->width || buffer->height != priv->height) {
1248      struct dri3_buffer   *new_buffer;
1249
1250      /* Allocate the new buffers
1251       */
1252      new_buffer = dri3_alloc_render_buffer(priv->base.psc,
1253                                            priv->base.xDrawable,
1254                                            format, priv->width, priv->height, priv->depth);
1255      if (!new_buffer)
1256         return NULL;
1257
1258      /* When resizing, copy the contents of the old buffer, waiting for that
1259       * copy to complete using our fences before proceeding
1260       */
1261      switch (buffer_type) {
1262      case dri3_buffer_back:
1263         if (buffer) {
1264            if (!buffer->linear_buffer) {
1265               dri3_fence_reset(c, new_buffer);
1266               dri3_fence_await(c, buffer);
1267               dri3_copy_area(c,
1268                              buffer->pixmap,
1269                              new_buffer->pixmap,
1270                              dri3_drawable_gc(priv),
1271                              0, 0, 0, 0, priv->width, priv->height);
1272            dri3_fence_trigger(c, new_buffer);
1273            } else if ((&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) {
1274               psc->image->blitImage(pcp->driContext,
1275                                     new_buffer->image,
1276                                     buffer->image,
1277                                     0, 0, priv->width,
1278                                     priv->height,
1279                                     0, 0, priv->width,
1280                                     priv->height, 0);
1281            }
1282            dri3_free_render_buffer(priv, buffer);
1283         }
1284         break;
1285      case dri3_buffer_front:
1286         dri3_fence_reset(c, new_buffer);
1287         dri3_copy_area(c,
1288                        priv->base.xDrawable,
1289                        new_buffer->pixmap,
1290                        dri3_drawable_gc(priv),
1291                        0, 0, 0, 0, priv->width, priv->height);
1292         dri3_fence_trigger(c, new_buffer);
1293
1294         if (new_buffer->linear_buffer && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) {
1295            dri3_fence_await(c, new_buffer);
1296            psc->image->blitImage(pcp->driContext,
1297                                  new_buffer->image,
1298                                  new_buffer->linear_buffer,
1299                                  0, 0, priv->width,
1300                                  priv->height,
1301                                  0, 0, priv->width,
1302                                  priv->height, 0);
1303         }
1304         break;
1305      }
1306      buffer = new_buffer;
1307      buffer->buffer_type = buffer_type;
1308      priv->buffers[buf_id] = buffer;
1309   }
1310   dri3_fence_await(c, buffer);
1311
1312   /* Return the requested buffer */
1313   return buffer;
1314}
1315
1316/** dri3_free_buffers
1317 *
1318 * Free the front bufffer or all of the back buffers. Used
1319 * when the application changes which buffers it needs
1320 */
1321static void
1322dri3_free_buffers(__DRIdrawable *driDrawable,
1323                 enum dri3_buffer_type buffer_type,
1324                 void *loaderPrivate)
1325{
1326   struct dri3_drawable *priv = loaderPrivate;
1327   struct dri3_buffer      *buffer;
1328   int                  first_id;
1329   int                  n_id;
1330   int                  buf_id;
1331
1332   switch (buffer_type) {
1333   case dri3_buffer_back:
1334      first_id = DRI3_BACK_ID(0);
1335      n_id = DRI3_MAX_BACK;
1336      break;
1337   case dri3_buffer_front:
1338      first_id = DRI3_FRONT_ID;
1339      n_id = 1;
1340   }
1341
1342   for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) {
1343      buffer = priv->buffers[buf_id];
1344      if (buffer) {
1345         dri3_free_render_buffer(priv, buffer);
1346         priv->buffers[buf_id] = NULL;
1347      }
1348   }
1349}
1350
1351/** dri3_get_buffers
1352 *
1353 * The published buffer allocation API.
1354 * Returns all of the necessary buffers, allocating
1355 * as needed.
1356 */
1357static int
1358dri3_get_buffers(__DRIdrawable *driDrawable,
1359                 unsigned int format,
1360                 uint32_t *stamp,
1361                 void *loaderPrivate,
1362                 uint32_t buffer_mask,
1363                 struct __DRIimageList *buffers)
1364{
1365   struct dri3_drawable *priv = loaderPrivate;
1366   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1367   struct dri3_buffer   *front, *back;
1368
1369   buffers->image_mask = 0;
1370   buffers->front = NULL;
1371   buffers->back = NULL;
1372
1373   front = NULL;
1374   back = NULL;
1375
1376   if (!dri3_update_drawable(driDrawable, loaderPrivate))
1377      return false;
1378
1379   /* pixmaps always have front buffers */
1380   if (priv->is_pixmap)
1381      buffer_mask |= __DRI_IMAGE_BUFFER_FRONT;
1382
1383   if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
1384      /* All pixmaps are owned by the server gpu.
1385       * When we use a different gpu, we can't use the pixmap
1386       * as buffer since it is potentially tiled a way
1387       * our device can't understand. In this case, use
1388       * a fake front buffer. Hopefully the pixmap
1389       * content will get synced with the fake front
1390       * buffer.
1391       */
1392      if (priv->is_pixmap && !psc->is_different_gpu)
1393         front = dri3_get_pixmap_buffer(driDrawable,
1394                                        format,
1395                                        dri3_buffer_front,
1396                                        loaderPrivate);
1397      else
1398         front = dri3_get_buffer(driDrawable,
1399                                 format,
1400                                 dri3_buffer_front,
1401                                 loaderPrivate);
1402
1403      if (!front)
1404         return false;
1405   } else {
1406      dri3_free_buffers(driDrawable, dri3_buffer_front, loaderPrivate);
1407      priv->have_fake_front = 0;
1408   }
1409
1410   if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
1411      back = dri3_get_buffer(driDrawable,
1412                             format,
1413                             dri3_buffer_back,
1414                             loaderPrivate);
1415      if (!back)
1416         return false;
1417      priv->have_back = 1;
1418   } else {
1419      dri3_free_buffers(driDrawable, dri3_buffer_back, loaderPrivate);
1420      priv->have_back = 0;
1421   }
1422
1423   if (front) {
1424      buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
1425      buffers->front = front->image;
1426      priv->have_fake_front = psc->is_different_gpu || !priv->is_pixmap;
1427   }
1428
1429   if (back) {
1430      buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK;
1431      buffers->back = back->image;
1432   }
1433
1434   priv->stamp = stamp;
1435
1436   return true;
1437}
1438
1439/* The image loader extension record for DRI3
1440 */
1441static const __DRIimageLoaderExtension imageLoaderExtension = {
1442   .base = { __DRI_IMAGE_LOADER, 1 },
1443
1444   .getBuffers          = dri3_get_buffers,
1445   .flushFrontBuffer    = dri3_flush_front_buffer,
1446};
1447
1448const __DRIuseInvalidateExtension dri3UseInvalidate = {
1449   .base = { __DRI_USE_INVALIDATE, 1 }
1450};
1451
1452static const __DRIextension *loader_extensions[] = {
1453   &imageLoaderExtension.base,
1454   &systemTimeExtension.base,
1455   &dri3UseInvalidate.base,
1456   NULL
1457};
1458
1459/** dri3_swap_buffers
1460 *
1461 * Make the current back buffer visible using the present extension
1462 */
1463static int64_t
1464dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
1465                  int64_t remainder, Bool flush)
1466{
1467   struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext();
1468   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1469   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1470   Display *dpy = priv->base.psc->dpy;
1471   xcb_connection_t *c = XGetXCBConnection(dpy);
1472   struct dri3_buffer *back;
1473   int64_t ret = 0;
1474
1475   unsigned flags = __DRI2_FLUSH_DRAWABLE;
1476   if (flush)
1477      flags |= __DRI2_FLUSH_CONTEXT;
1478   dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
1479
1480   back = priv->buffers[DRI3_BACK_ID(priv->cur_back)];
1481   if (psc->is_different_gpu && back) {
1482      /* Update the linear buffer before presenting the pixmap */
1483      psc->image->blitImage(pcp->driContext,
1484                            back->linear_buffer,
1485                            back->image,
1486                            0, 0, back->width,
1487                            back->height,
1488                            0, 0, back->width,
1489                            back->height, __BLIT_FLAG_FLUSH);
1490      /* Update the fake front */
1491      if (priv->have_fake_front)
1492         psc->image->blitImage(pcp->driContext,
1493                               priv->buffers[DRI3_FRONT_ID]->image,
1494                               back->image,
1495                               0, 0, priv->width,
1496                               priv->height,
1497                               0, 0, priv->width,
1498                               priv->height, __BLIT_FLAG_FLUSH);
1499   }
1500
1501   dri3_flush_present_events(priv);
1502
1503   if (back && !priv->is_pixmap) {
1504      dri3_fence_reset(c, back);
1505
1506      /* Compute when we want the frame shown by taking the last known successful
1507       * MSC and adding in a swap interval for each outstanding swap request
1508       */
1509      ++priv->send_sbc;
1510      if (target_msc == 0)
1511         target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc);
1512
1513      back->busy = 1;
1514      back->last_swap = priv->send_sbc;
1515      xcb_present_pixmap(c,
1516                         priv->base.xDrawable,
1517                         back->pixmap,
1518                         (uint32_t) priv->send_sbc,
1519                         0,                                    /* valid */
1520                         0,                                    /* update */
1521                         0,                                    /* x_off */
1522                         0,                                    /* y_off */
1523                         None,                                 /* target_crtc */
1524                         None,
1525                         back->sync_fence,
1526                         XCB_PRESENT_OPTION_NONE,
1527                         target_msc,
1528                         divisor,
1529                         remainder, 0, NULL);
1530      ret = (int64_t) priv->send_sbc;
1531
1532      /* If there's a fake front, then copy the source back buffer
1533       * to the fake front to keep it up to date. This needs
1534       * to reset the fence and make future users block until
1535       * the X server is done copying the bits
1536       */
1537      if (priv->have_fake_front && !psc->is_different_gpu) {
1538         dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]);
1539         dri3_copy_area(c,
1540                        back->pixmap,
1541                        priv->buffers[DRI3_FRONT_ID]->pixmap,
1542                        dri3_drawable_gc(priv),
1543                        0, 0, 0, 0, priv->width, priv->height);
1544         dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]);
1545      }
1546      xcb_flush(c);
1547      if (priv->stamp)
1548         ++(*priv->stamp);
1549   }
1550
1551   (*psc->f->invalidate)(priv->driDrawable);
1552
1553   return ret;
1554}
1555
1556static int
1557dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
1558{
1559   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
1560   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
1561   int back_id = DRI3_BACK_ID(dri3_find_back(c, priv));
1562
1563   if (back_id < 0 || !priv->buffers[back_id])
1564      return 0;
1565
1566   if (priv->buffers[back_id]->last_swap != 0)
1567      return priv->send_sbc - priv->buffers[back_id]->last_swap + 1;
1568   else
1569      return 0;
1570}
1571
1572/** dri3_open
1573 *
1574 * Wrapper around xcb_dri3_open
1575 */
1576static int
1577dri3_open(Display *dpy,
1578          Window root,
1579          CARD32 provider)
1580{
1581   xcb_dri3_open_cookie_t       cookie;
1582   xcb_dri3_open_reply_t        *reply;
1583   xcb_connection_t             *c = XGetXCBConnection(dpy);
1584   int                          fd;
1585
1586   cookie = xcb_dri3_open(c,
1587                          root,
1588                          provider);
1589
1590   reply = xcb_dri3_open_reply(c, cookie, NULL);
1591   if (!reply)
1592      return -1;
1593
1594   if (reply->nfd != 1) {
1595      free(reply);
1596      return -1;
1597   }
1598
1599   fd = xcb_dri3_open_reply_fds(c, reply)[0];
1600   fcntl(fd, F_SETFD, FD_CLOEXEC);
1601
1602   return fd;
1603}
1604
1605
1606/** dri3_destroy_screen
1607 */
1608static void
1609dri3_destroy_screen(struct glx_screen *base)
1610{
1611   struct dri3_screen *psc = (struct dri3_screen *) base;
1612
1613   /* Free the direct rendering per screen data */
1614   (*psc->core->destroyScreen) (psc->driScreen);
1615   driDestroyConfigs(psc->driver_configs);
1616   close(psc->fd);
1617   free(psc);
1618}
1619
1620/** dri3_set_swap_interval
1621 *
1622 * Record the application swap interval specification,
1623 */
1624static int
1625dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
1626{
1627   struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
1628   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
1629   struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc;
1630
1631   if (psc->config)
1632      psc->config->configQueryi(psc->driScreen,
1633                                "vblank_mode", &vblank_mode);
1634
1635   switch (vblank_mode) {
1636   case DRI_CONF_VBLANK_NEVER:
1637      if (interval != 0)
1638         return GLX_BAD_VALUE;
1639      break;
1640   case DRI_CONF_VBLANK_ALWAYS_SYNC:
1641      if (interval <= 0)
1642         return GLX_BAD_VALUE;
1643      break;
1644   default:
1645      break;
1646   }
1647
1648   priv->swap_interval = interval;
1649   dri3_update_num_back(priv);
1650
1651   return 0;
1652}
1653
1654/** dri3_get_swap_interval
1655 *
1656 * Return the stored swap interval
1657 */
1658static int
1659dri3_get_swap_interval(__GLXDRIdrawable *pdraw)
1660{
1661   struct dri3_drawable *priv =  (struct dri3_drawable *) pdraw;
1662
1663  return priv->swap_interval;
1664}
1665
1666static void
1667dri3_bind_tex_image(Display * dpy,
1668                    GLXDrawable drawable,
1669                    int buffer, const int *attrib_list)
1670{
1671   struct glx_context *gc = __glXGetCurrentContext();
1672   struct dri3_context *pcp = (struct dri3_context *) gc;
1673   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1674   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1675   struct dri3_screen *psc;
1676
1677   if (pdraw != NULL) {
1678      psc = (struct dri3_screen *) base->psc;
1679
1680      (*psc->f->invalidate)(pdraw->driDrawable);
1681
1682      XSync(dpy, false);
1683
1684      (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
1685                                        pdraw->base.textureTarget,
1686                                        pdraw->base.textureFormat,
1687                                        pdraw->driDrawable);
1688   }
1689}
1690
1691static void
1692dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
1693{
1694   struct glx_context *gc = __glXGetCurrentContext();
1695   struct dri3_context *pcp = (struct dri3_context *) gc;
1696   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
1697   struct dri3_drawable *pdraw = (struct dri3_drawable *) base;
1698   struct dri3_screen *psc;
1699
1700   if (pdraw != NULL) {
1701      psc = (struct dri3_screen *) base->psc;
1702
1703      if (psc->texBuffer->base.version >= 3 &&
1704          psc->texBuffer->releaseTexBuffer != NULL)
1705         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
1706                                              pdraw->base.textureTarget,
1707                                              pdraw->driDrawable);
1708   }
1709}
1710
1711static const struct glx_context_vtable dri3_context_vtable = {
1712   .destroy             = dri3_destroy_context,
1713   .bind                = dri3_bind_context,
1714   .unbind              = dri3_unbind_context,
1715   .wait_gl             = dri3_wait_gl,
1716   .wait_x              = dri3_wait_x,
1717   .use_x_font          = DRI_glXUseXFont,
1718   .bind_tex_image      = dri3_bind_tex_image,
1719   .release_tex_image   = dri3_release_tex_image,
1720   .get_proc_address    = NULL,
1721};
1722
1723/** dri3_bind_extensions
1724 *
1725 * Enable all of the extensions supported on DRI3
1726 */
1727static void
1728dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
1729                     const char *driverName)
1730{
1731   const __DRIextension **extensions;
1732   unsigned mask;
1733   int i;
1734
1735   extensions = psc->core->getExtensions(psc->driScreen);
1736
1737   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
1738   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
1739   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
1740   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
1741   __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1742
1743   mask = psc->image_driver->getAPIMask(psc->driScreen);
1744
1745   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
1746   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
1747
1748   if ((mask & (1 << __DRI_API_GLES2)) != 0)
1749      __glXEnableDirectExtension(&psc->base,
1750                                 "GLX_EXT_create_context_es2_profile");
1751
1752   for (i = 0; extensions[i]; i++) {
1753      /* when on a different gpu than the server, the server pixmaps
1754       * can have a tiling mode we can't read. Thus we can't create
1755       * a texture from them.
1756       */
1757      if (!psc->is_different_gpu &&
1758         (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
1759         psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
1760         __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
1761      }
1762
1763      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
1764         psc->f = (__DRI2flushExtension *) extensions[i];
1765         /* internal driver extension, no GL extension exposed */
1766      }
1767
1768      if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0)
1769         psc->image = (__DRIimageExtension *) extensions[i];
1770
1771      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
1772         psc->config = (__DRI2configQueryExtension *) extensions[i];
1773
1774      if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1775         __glXEnableDirectExtension(&psc->base,
1776                                    "GLX_ARB_create_context_robustness");
1777
1778      if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
1779         psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
1780         __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
1781      }
1782   }
1783}
1784
1785static const struct glx_screen_vtable dri3_screen_vtable = {
1786   .create_context         = dri3_create_context,
1787   .create_context_attribs = dri3_create_context_attribs,
1788   .query_renderer_integer = dri3_query_renderer_integer,
1789   .query_renderer_string  = dri3_query_renderer_string,
1790};
1791
1792/** dri3_create_screen
1793 *
1794 * Initialize DRI3 on the specified screen.
1795 *
1796 * Opens the DRI device, locates the appropriate DRI driver
1797 * and loads that.
1798 *
1799 * Checks to see if the driver supports the necessary extensions
1800 *
1801 * Initializes the driver for the screen and sets up our structures
1802 */
1803
1804static struct glx_screen *
1805dri3_create_screen(int screen, struct glx_display * priv)
1806{
1807   xcb_connection_t *c = XGetXCBConnection(priv->dpy);
1808   const __DRIconfig **driver_configs;
1809   const __DRIextension **extensions;
1810   const struct dri3_display *const pdp = (struct dri3_display *)
1811      priv->dri3Display;
1812   struct dri3_screen *psc;
1813   __GLXDRIscreen *psp;
1814   struct glx_config *configs = NULL, *visuals = NULL;
1815   char *driverName, *deviceName;
1816   int i;
1817
1818   psc = calloc(1, sizeof *psc);
1819   if (psc == NULL)
1820      return NULL;
1821
1822   psc->fd = -1;
1823
1824   if (!glx_screen_init(&psc->base, screen, priv)) {
1825      free(psc);
1826      return NULL;
1827   }
1828
1829   psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None);
1830   if (psc->fd < 0) {
1831      int conn_error = xcb_connection_has_error(c);
1832
1833      glx_screen_cleanup(&psc->base);
1834      free(psc);
1835      InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
1836
1837      if (conn_error)
1838         ErrorMessageF("Connection closed during DRI3 initialization failure");
1839
1840      return NULL;
1841   }
1842
1843   psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu);
1844   deviceName = NULL;
1845
1846   driverName = loader_get_driver_for_fd(psc->fd, 0);
1847   if (!driverName) {
1848      ErrorMessageF("No driver found\n");
1849      goto handle_error;
1850   }
1851
1852   psc->driver = driOpenDriver(driverName);
1853   if (psc->driver == NULL) {
1854      ErrorMessageF("driver pointer missing\n");
1855      goto handle_error;
1856   }
1857
1858   extensions = driGetDriverExtensions(psc->driver, driverName);
1859   if (extensions == NULL)
1860      goto handle_error;
1861
1862   for (i = 0; extensions[i]; i++) {
1863      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1864         psc->core = (__DRIcoreExtension *) extensions[i];
1865      if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0)
1866         psc->image_driver = (__DRIimageDriverExtension *) extensions[i];
1867   }
1868
1869
1870   if (psc->core == NULL) {
1871      ErrorMessageF("core dri driver extension not found\n");
1872      goto handle_error;
1873   }
1874
1875   if (psc->image_driver == NULL) {
1876      ErrorMessageF("image driver extension not found\n");
1877      goto handle_error;
1878   }
1879
1880   psc->driScreen =
1881      psc->image_driver->createNewScreen2(screen, psc->fd,
1882                                          pdp->loader_extensions,
1883                                          extensions,
1884                                          &driver_configs, psc);
1885
1886   if (psc->driScreen == NULL) {
1887      ErrorMessageF("failed to create dri screen\n");
1888      goto handle_error;
1889   }
1890
1891   dri3_bind_extensions(psc, priv, driverName);
1892
1893   if (!psc->image || psc->image->base.version < 7 || !psc->image->createImageFromFds) {
1894      ErrorMessageF("Version 7 or imageFromFds image extension not found\n");
1895      goto handle_error;
1896   }
1897
1898   if (!psc->f || psc->f->base.version < 4) {
1899      ErrorMessageF("Version 4 or later of flush extension not found\n");
1900      goto handle_error;
1901   }
1902
1903   if (psc->is_different_gpu && psc->image->base.version < 9) {
1904      ErrorMessageF("Different GPU, but image extension version 9 or later not found\n");
1905      goto handle_error;
1906   }
1907
1908   if (!psc->is_different_gpu && (
1909       !psc->texBuffer || psc->texBuffer->base.version < 2 ||
1910       !psc->texBuffer->setTexBuffer2
1911       )) {
1912      ErrorMessageF("Version 2 or later of texBuffer extension not found\n");
1913      goto handle_error;
1914   }
1915
1916   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1917   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1918
1919   if (!configs || !visuals) {
1920       ErrorMessageF("No matching fbConfigs or visuals found\n");
1921       goto handle_error;
1922   }
1923
1924   glx_config_destroy_list(psc->base.configs);
1925   psc->base.configs = configs;
1926   glx_config_destroy_list(psc->base.visuals);
1927   psc->base.visuals = visuals;
1928
1929   psc->driver_configs = driver_configs;
1930
1931   psc->base.vtable = &dri3_screen_vtable;
1932   psp = &psc->vtable;
1933   psc->base.driScreen = psp;
1934   psp->destroyScreen = dri3_destroy_screen;
1935   psp->createDrawable = dri3_create_drawable;
1936   psp->swapBuffers = dri3_swap_buffers;
1937
1938   psp->getDrawableMSC = dri3_drawable_get_msc;
1939   psp->waitForMSC = dri3_wait_for_msc;
1940   psp->waitForSBC = dri3_wait_for_sbc;
1941   psp->setSwapInterval = dri3_set_swap_interval;
1942   psp->getSwapInterval = dri3_get_swap_interval;
1943   __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1944
1945   psp->copySubBuffer = dri3_copy_sub_buffer;
1946   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1947
1948   psp->getBufferAge = dri3_get_buffer_age;
1949   __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
1950
1951   free(driverName);
1952   free(deviceName);
1953
1954   return &psc->base;
1955
1956handle_error:
1957   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1958
1959   if (configs)
1960       glx_config_destroy_list(configs);
1961   if (visuals)
1962       glx_config_destroy_list(visuals);
1963   if (psc->driScreen)
1964       psc->core->destroyScreen(psc->driScreen);
1965   psc->driScreen = NULL;
1966   if (psc->fd >= 0)
1967      close(psc->fd);
1968   if (psc->driver)
1969      dlclose(psc->driver);
1970
1971   free(driverName);
1972   free(deviceName);
1973   glx_screen_cleanup(&psc->base);
1974   free(psc);
1975
1976   return NULL;
1977}
1978
1979/** dri_destroy_display
1980 *
1981 * Called from __glXFreeDisplayPrivate.
1982 */
1983static void
1984dri3_destroy_display(__GLXDRIdisplay * dpy)
1985{
1986   free(dpy);
1987}
1988
1989/** dri3_create_display
1990 *
1991 * Allocate, initialize and return a __DRIdisplayPrivate object.
1992 * This is called from __glXInitialize() when we are given a new
1993 * display pointer. This is public to that function, but hidden from
1994 * outside of libGL.
1995 */
1996_X_HIDDEN __GLXDRIdisplay *
1997dri3_create_display(Display * dpy)
1998{
1999   struct dri3_display                  *pdp;
2000   xcb_connection_t                     *c = XGetXCBConnection(dpy);
2001   xcb_dri3_query_version_cookie_t      dri3_cookie;
2002   xcb_dri3_query_version_reply_t       *dri3_reply;
2003   xcb_present_query_version_cookie_t   present_cookie;
2004   xcb_present_query_version_reply_t    *present_reply;
2005   xcb_generic_error_t                  *error;
2006   const xcb_query_extension_reply_t    *extension;
2007
2008   xcb_prefetch_extension_data(c, &xcb_dri3_id);
2009   xcb_prefetch_extension_data(c, &xcb_present_id);
2010
2011   extension = xcb_get_extension_data(c, &xcb_dri3_id);
2012   if (!(extension && extension->present))
2013      return NULL;
2014
2015   extension = xcb_get_extension_data(c, &xcb_present_id);
2016   if (!(extension && extension->present))
2017      return NULL;
2018
2019   dri3_cookie = xcb_dri3_query_version(c,
2020                                        XCB_DRI3_MAJOR_VERSION,
2021                                        XCB_DRI3_MINOR_VERSION);
2022
2023
2024   present_cookie = xcb_present_query_version(c,
2025                                   XCB_PRESENT_MAJOR_VERSION,
2026                                   XCB_PRESENT_MINOR_VERSION);
2027
2028   pdp = malloc(sizeof *pdp);
2029   if (pdp == NULL)
2030      return NULL;
2031
2032   dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error);
2033   if (!dri3_reply) {
2034      free(error);
2035      goto no_extension;
2036   }
2037
2038   pdp->dri3Major = dri3_reply->major_version;
2039   pdp->dri3Minor = dri3_reply->minor_version;
2040   free(dri3_reply);
2041
2042   present_reply = xcb_present_query_version_reply(c, present_cookie, &error);
2043   if (!present_reply) {
2044      free(error);
2045      goto no_extension;
2046   }
2047   pdp->presentMajor = present_reply->major_version;
2048   pdp->presentMinor = present_reply->minor_version;
2049   free(present_reply);
2050
2051   pdp->base.destroyDisplay = dri3_destroy_display;
2052   pdp->base.createScreen = dri3_create_screen;
2053
2054   loader_set_logger(dri_message);
2055
2056   pdp->loader_extensions = loader_extensions;
2057
2058   return &pdp->base;
2059no_extension:
2060   free(pdp);
2061   return NULL;
2062}
2063
2064#endif /* GLX_DIRECT_RENDERING */
2065