dri2_glx.c revision 48ffc6a1553083280c217640629cc6ebed1bf982
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 (krh@redhat.com)
31 */
32
33#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
34
35#include <X11/Xlib.h>
36#include <X11/extensions/Xfixes.h>
37#include "glapi.h"
38#include "glxclient.h"
39#include <X11/extensions/dri2proto.h>
40#include "xf86dri.h"
41#include <dlfcn.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <sys/types.h>
45#include <sys/mman.h>
46#include "xf86drm.h"
47#include "dri2.h"
48#include "dri_common.h"
49
50/* From xmlpool/options.h, user exposed so should be stable */
51#define DRI_CONF_VBLANK_NEVER 0
52#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
53#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
54#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
55
56#undef DRI2_MINOR
57#define DRI2_MINOR 1
58
59struct dri2_display
60{
61   __GLXDRIdisplay base;
62
63   /*
64    ** XFree86-DRI version information
65    */
66   int driMajor;
67   int driMinor;
68   int driPatch;
69   int swapAvailable;
70   int invalidateAvailable;
71
72   __glxHashTable *dri2Hash;
73
74   const __DRIextension *loader_extensions[4];
75};
76
77struct dri2_screen {
78   struct glx_screen base;
79
80   __DRIscreen *driScreen;
81   __GLXDRIscreen vtable;
82   const __DRIdri2Extension *dri2;
83   const __DRIcoreExtension *core;
84
85   const __DRI2flushExtension *f;
86   const __DRI2configQueryExtension *config;
87   const __DRItexBufferExtension *texBuffer;
88   const __DRI2throttleExtension *throttle;
89   const __DRIconfig **driver_configs;
90
91   void *driver;
92   int fd;
93};
94
95struct dri2_context
96{
97   struct glx_context base;
98   __DRIcontext *driContext;
99};
100
101struct dri2_drawable
102{
103   __GLXDRIdrawable base;
104   __DRIdrawable *driDrawable;
105   __DRIbuffer buffers[5];
106   int bufferCount;
107   int width, height;
108   int have_back;
109   int have_fake_front;
110   int swap_interval;
111};
112
113static const struct glx_context_vtable dri2_context_vtable;
114
115static void
116dri2_destroy_context(struct glx_context *context)
117{
118   struct dri2_context *pcp = (struct dri2_context *) context;
119   struct dri2_screen *psc = (struct dri2_screen *) context->psc;
120
121   driReleaseDrawables(&pcp->base);
122
123   if (context->extensions)
124      XFree((char *) context->extensions);
125
126   (*psc->core->destroyContext) (pcp->driContext);
127
128   Xfree(pcp);
129}
130
131static Bool
132dri2_bind_context(struct glx_context *context, struct glx_context *old,
133		  GLXDrawable draw, GLXDrawable read)
134{
135   struct dri2_context *pcp = (struct dri2_context *) context;
136   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
137   struct dri2_drawable *pdraw, *pread;
138   struct dri2_display *pdp;
139
140   pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
141   pread = (struct dri2_drawable *) driFetchDrawable(context, read);
142
143   driReleaseDrawables(&pcp->base);
144
145   if (pdraw == NULL || pread == NULL)
146      return GLXBadDrawable;
147
148   if (!(*psc->core->bindContext) (pcp->driContext,
149				   pdraw->driDrawable, pread->driDrawable))
150      return GLXBadContext;
151
152   /* If the server doesn't send invalidate events, we may miss a
153    * resize before the rendering starts.  Invalidate the buffers now
154    * so the driver will recheck before rendering starts. */
155   pdp = (struct dri2_display *) psc->base.display;
156   if (!pdp->invalidateAvailable) {
157      dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable);
158      if (pread != pdraw)
159	 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable);
160   }
161
162   return Success;
163}
164
165static void
166dri2_unbind_context(struct glx_context *context, struct glx_context *new)
167{
168   struct dri2_context *pcp = (struct dri2_context *) context;
169   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
170
171   (*psc->core->unbindContext) (pcp->driContext);
172}
173
174static struct glx_context *
175dri2_create_context(struct glx_screen *base,
176		    struct glx_config *config_base,
177		    struct glx_context *shareList, int renderType)
178{
179   struct dri2_context *pcp, *pcp_shared;
180   struct dri2_screen *psc = (struct dri2_screen *) base;
181   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
182   __DRIcontext *shared = NULL;
183
184   if (shareList) {
185      /* If the shareList context is not a DRI2 context, we cannot possibly
186       * create a DRI2 context that shares it.
187       */
188      if (shareList->vtable->destroy != dri2_destroy_context) {
189	 return NULL;
190      }
191
192      pcp_shared = (struct dri2_context *) shareList;
193      shared = pcp_shared->driContext;
194   }
195
196   pcp = Xmalloc(sizeof *pcp);
197   if (pcp == NULL)
198      return NULL;
199
200   memset(pcp, 0, sizeof *pcp);
201   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
202      Xfree(pcp);
203      return NULL;
204   }
205
206   pcp->driContext =
207      (*psc->dri2->createNewContext) (psc->driScreen,
208                                      config->driConfig, shared, pcp);
209
210   if (pcp->driContext == NULL) {
211      Xfree(pcp);
212      return NULL;
213   }
214
215   pcp->base.vtable = &dri2_context_vtable;
216
217   return &pcp->base;
218}
219
220static struct glx_context *
221dri2_create_context_attribs(struct glx_screen *base,
222			    struct glx_config *config_base,
223			    struct glx_context *shareList,
224			    unsigned num_attribs,
225			    const uint32_t *attribs,
226			    unsigned *error)
227{
228   struct dri2_context *pcp = NULL;
229   struct dri2_context *pcp_shared = NULL;
230   struct dri2_screen *psc = (struct dri2_screen *) base;
231   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
232   __DRIcontext *shared = NULL;
233
234   uint32_t minor_ver = 1;
235   uint32_t major_ver = 2;
236   uint32_t flags = 0;
237   unsigned api;
238   uint32_t ctx_attribs[2 * 4];
239   unsigned num_ctx_attribs = 0;
240
241   if (psc->dri2->base.version < 3) {
242      *error = __DRI_CTX_ERROR_NO_MEMORY;
243      goto error_exit;
244   }
245
246   /* Remap the GLX tokens to DRI2 tokens.
247    */
248   if (!dri2_convert_glx_attribs(num_attribs, attribs,
249				 &major_ver, &minor_ver, &flags, &api, error))
250      goto error_exit;
251
252   if (shareList) {
253      pcp_shared = (struct dri2_context *) shareList;
254      shared = pcp_shared->driContext;
255   }
256
257   pcp = Xmalloc(sizeof *pcp);
258   if (pcp == NULL) {
259      *error = __DRI_CTX_ERROR_NO_MEMORY;
260      goto error_exit;
261   }
262
263   memset(pcp, 0, sizeof *pcp);
264   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
265      goto error_exit;
266
267   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
268   ctx_attribs[num_ctx_attribs++] = major_ver;
269   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
270   ctx_attribs[num_ctx_attribs++] = minor_ver;
271
272   if (flags != 0) {
273      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
274
275      /* The current __DRI_CTX_FLAG_* values are identical to the
276       * GLX_CONTEXT_*_BIT values.
277       */
278      ctx_attribs[num_ctx_attribs++] = flags;
279   }
280
281   pcp->driContext =
282      (*psc->dri2->createContextAttribs) (psc->driScreen,
283					  api,
284					  config->driConfig,
285					  shared,
286					  num_ctx_attribs / 2,
287					  ctx_attribs,
288					  error,
289					  pcp);
290
291   if (pcp->driContext == NULL)
292      goto error_exit;
293
294   pcp->base.vtable = &dri2_context_vtable;
295
296   return &pcp->base;
297
298error_exit:
299   if (pcp != NULL)
300      Xfree(pcp);
301
302   return NULL;
303}
304
305static void
306dri2DestroyDrawable(__GLXDRIdrawable *base)
307{
308   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
309   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
310   struct glx_display *dpyPriv = psc->base.display;
311   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
312
313   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
314   (*psc->core->destroyDrawable) (pdraw->driDrawable);
315
316   /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
317    * now, as the application explicitly asked to destroy the GLX
318    * drawable.  Otherwise, for legacy drawables, we let the DRI2
319    * drawable linger on the server, since there's no good way of
320    * knowing when the application is done with it.  The server will
321    * destroy the DRI2 drawable when it destroys the X drawable or the
322    * client exits anyway. */
323   if (pdraw->base.xDrawable != pdraw->base.drawable)
324      DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
325
326   Xfree(pdraw);
327}
328
329static __GLXDRIdrawable *
330dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
331		   GLXDrawable drawable, struct glx_config *config_base)
332{
333   struct dri2_drawable *pdraw;
334   struct dri2_screen *psc = (struct dri2_screen *) base;
335   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
336   struct glx_display *dpyPriv;
337   struct dri2_display *pdp;
338   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
339
340   pdraw = Xmalloc(sizeof(*pdraw));
341   if (!pdraw)
342      return NULL;
343
344   memset(pdraw, 0, sizeof *pdraw);
345   pdraw->base.destroyDrawable = dri2DestroyDrawable;
346   pdraw->base.xDrawable = xDrawable;
347   pdraw->base.drawable = drawable;
348   pdraw->base.psc = &psc->base;
349   pdraw->bufferCount = 0;
350   pdraw->swap_interval = 1; /* default may be overridden below */
351   pdraw->have_back = 0;
352
353   if (psc->config)
354      psc->config->configQueryi(psc->driScreen,
355				"vblank_mode", &vblank_mode);
356
357   switch (vblank_mode) {
358   case DRI_CONF_VBLANK_NEVER:
359   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
360      pdraw->swap_interval = 0;
361      break;
362   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
363   case DRI_CONF_VBLANK_ALWAYS_SYNC:
364   default:
365      pdraw->swap_interval = 1;
366      break;
367   }
368
369   DRI2CreateDrawable(psc->base.dpy, xDrawable);
370
371   dpyPriv = __glXInitialize(psc->base.dpy);
372   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
373   /* Create a new drawable */
374   pdraw->driDrawable =
375      (*psc->dri2->createNewDrawable) (psc->driScreen,
376                                       config->driConfig, pdraw);
377
378   if (!pdraw->driDrawable) {
379      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
380      Xfree(pdraw);
381      return NULL;
382   }
383
384   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
385      (*psc->core->destroyDrawable) (pdraw->driDrawable);
386      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
387      Xfree(pdraw);
388      return None;
389   }
390
391
392#ifdef X_DRI2SwapInterval
393   /*
394    * Make sure server has the same swap interval we do for the new
395    * drawable.
396    */
397   if (pdp->swapAvailable)
398      DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
399#endif
400
401   return &pdraw->base;
402}
403
404#ifdef X_DRI2GetMSC
405
406static int
407dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
408		   int64_t *ust, int64_t *msc, int64_t *sbc)
409{
410   CARD64 dri2_ust, dri2_msc, dri2_sbc;
411   int ret;
412
413   ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
414		    &dri2_ust, &dri2_msc, &dri2_sbc);
415   *ust = dri2_ust;
416   *msc = dri2_msc;
417   *sbc = dri2_sbc;
418
419   return ret;
420}
421
422#endif
423
424
425#ifdef X_DRI2WaitMSC
426
427static int
428dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
429	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
430{
431   CARD64 dri2_ust, dri2_msc, dri2_sbc;
432   int ret;
433
434   ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
435		     remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
436   *ust = dri2_ust;
437   *msc = dri2_msc;
438   *sbc = dri2_sbc;
439
440   return ret;
441}
442
443static int
444dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
445	       int64_t *msc, int64_t *sbc)
446{
447   CARD64 dri2_ust, dri2_msc, dri2_sbc;
448   int ret;
449
450   ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
451		     target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
452   *ust = dri2_ust;
453   *msc = dri2_msc;
454   *sbc = dri2_sbc;
455
456   return ret;
457}
458
459#endif /* X_DRI2WaitMSC */
460
461/**
462 * dri2Throttle - Request driver throttling
463 *
464 * This function uses the DRI2 throttle extension to give the
465 * driver the opportunity to throttle on flush front, copysubbuffer
466 * and swapbuffers.
467 */
468static void
469dri2Throttle(struct dri2_screen *psc,
470	     struct dri2_drawable *draw,
471	     enum __DRI2throttleReason reason)
472{
473   if (psc->throttle) {
474      struct glx_context *gc = __glXGetCurrentContext();
475      struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
476      __DRIcontext *ctx =
477	 (dri2Ctx) ? dri2Ctx->driContext : NULL;
478
479      psc->throttle->throttle(ctx, draw->driDrawable, reason);
480   }
481}
482
483static void
484__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
485		    int width, int height,
486		    enum __DRI2throttleReason reason)
487{
488   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
489   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
490   XRectangle xrect;
491   XserverRegion region;
492
493   /* Check we have the right attachments */
494   if (!priv->have_back)
495      return;
496
497   xrect.x = x;
498   xrect.y = priv->height - y - height;
499   xrect.width = width;
500   xrect.height = height;
501
502#ifdef __DRI2_FLUSH
503   if (psc->f)
504      (*psc->f->flush) (priv->driDrawable);
505#endif
506
507   dri2Throttle(psc, priv, reason);
508
509   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
510   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
511                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
512
513   /* Refresh the fake front (if present) after we just damaged the real
514    * front.
515    */
516   if (priv->have_fake_front)
517      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
518		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
519
520   XFixesDestroyRegion(psc->base.dpy, region);
521}
522
523static void
524dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
525		  int width, int height)
526{
527   __dri2CopySubBuffer(pdraw, x, y, width, height,
528		       __DRI2_THROTTLE_COPYSUBBUFFER);
529}
530
531
532static void
533dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
534{
535   XRectangle xrect;
536   XserverRegion region;
537   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
538
539   xrect.x = 0;
540   xrect.y = 0;
541   xrect.width = priv->width;
542   xrect.height = priv->height;
543
544#ifdef __DRI2_FLUSH
545   if (psc->f)
546      (*psc->f->flush) (priv->driDrawable);
547#endif
548
549   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
550   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
551   XFixesDestroyRegion(psc->base.dpy, region);
552
553}
554
555static void
556dri2_wait_x(struct glx_context *gc)
557{
558   struct dri2_drawable *priv = (struct dri2_drawable *)
559      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
560
561   if (priv == NULL || !priv->have_fake_front)
562      return;
563
564   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
565}
566
567static void
568dri2_wait_gl(struct glx_context *gc)
569{
570   struct dri2_drawable *priv = (struct dri2_drawable *)
571      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
572
573   if (priv == NULL || !priv->have_fake_front)
574      return;
575
576   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
577}
578
579static void
580dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
581{
582   struct glx_display *priv;
583   struct dri2_display *pdp;
584   struct glx_context *gc;
585   struct dri2_drawable *pdraw = loaderPrivate;
586   struct dri2_screen *psc;
587
588   if (!pdraw)
589      return;
590
591   if (!pdraw->base.psc)
592      return;
593
594   psc = (struct dri2_screen *) pdraw->base.psc;
595
596   priv = __glXInitialize(psc->base.dpy);
597   pdp = (struct dri2_display *) priv->dri2Display;
598   gc = __glXGetCurrentContext();
599
600   dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
601
602   /* Old servers don't send invalidate events */
603   if (!pdp->invalidateAvailable)
604       dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
605
606   dri2_wait_gl(gc);
607}
608
609
610static void
611dri2DestroyScreen(struct glx_screen *base)
612{
613   struct dri2_screen *psc = (struct dri2_screen *) base;
614
615   /* Free the direct rendering per screen data */
616   (*psc->core->destroyScreen) (psc->driScreen);
617   driDestroyConfigs(psc->driver_configs);
618   close(psc->fd);
619   Xfree(psc);
620}
621
622/**
623 * Process list of buffer received from the server
624 *
625 * Processes the list of buffers received in a reply from the server to either
626 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
627 */
628static void
629process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
630                unsigned count)
631{
632   int i;
633
634   pdraw->bufferCount = count;
635   pdraw->have_fake_front = 0;
636   pdraw->have_back = 0;
637
638   /* This assumes the DRI2 buffer attachment tokens matches the
639    * __DRIbuffer tokens. */
640   for (i = 0; i < count; i++) {
641      pdraw->buffers[i].attachment = buffers[i].attachment;
642      pdraw->buffers[i].name = buffers[i].name;
643      pdraw->buffers[i].pitch = buffers[i].pitch;
644      pdraw->buffers[i].cpp = buffers[i].cpp;
645      pdraw->buffers[i].flags = buffers[i].flags;
646      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
647         pdraw->have_fake_front = 1;
648      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
649         pdraw->have_back = 1;
650   }
651
652}
653
654unsigned dri2GetSwapEventType(Display* dpy, XID drawable)
655{
656      struct glx_display *glx_dpy = __glXInitialize(dpy);
657      __GLXDRIdrawable *pdraw;
658      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
659      if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
660         return 0;
661      return glx_dpy->codes->first_event + GLX_BufferSwapComplete;
662}
663
664static int64_t
665dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
666		int64_t remainder)
667{
668    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
669    struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
670    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
671    struct dri2_display *pdp =
672	(struct dri2_display *)dpyPriv->dri2Display;
673    CARD64 ret = 0;
674
675    /* Check we have the right attachments */
676    if (!priv->have_back)
677	return ret;
678
679    /* Old servers can't handle swapbuffers */
680    if (!pdp->swapAvailable) {
681       __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
682			   __DRI2_THROTTLE_SWAPBUFFER);
683    } else {
684#ifdef X_DRI2SwapBuffers
685#ifdef __DRI2_FLUSH
686    if (psc->f) {
687       struct glx_context *gc = __glXGetCurrentContext();
688
689       if (gc) {
690	  (*psc->f->flush)(priv->driDrawable);
691       }
692    }
693#endif
694
695       dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER);
696
697       DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable,
698		       target_msc, divisor, remainder, &ret);
699#endif
700    }
701
702    /* Old servers don't send invalidate events */
703    if (!pdp->invalidateAvailable)
704       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
705
706    return ret;
707}
708
709static __DRIbuffer *
710dri2GetBuffers(__DRIdrawable * driDrawable,
711               int *width, int *height,
712               unsigned int *attachments, int count,
713               int *out_count, void *loaderPrivate)
714{
715   struct dri2_drawable *pdraw = loaderPrivate;
716   DRI2Buffer *buffers;
717
718   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
719                            width, height, attachments, count, out_count);
720   if (buffers == NULL)
721      return NULL;
722
723   pdraw->width = *width;
724   pdraw->height = *height;
725   process_buffers(pdraw, buffers, *out_count);
726
727   Xfree(buffers);
728
729   return pdraw->buffers;
730}
731
732static __DRIbuffer *
733dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
734                         int *width, int *height,
735                         unsigned int *attachments, int count,
736                         int *out_count, void *loaderPrivate)
737{
738   struct dri2_drawable *pdraw = loaderPrivate;
739   DRI2Buffer *buffers;
740
741   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
742                                      pdraw->base.xDrawable,
743                                      width, height, attachments,
744                                      count, out_count);
745   if (buffers == NULL)
746      return NULL;
747
748   pdraw->width = *width;
749   pdraw->height = *height;
750   process_buffers(pdraw, buffers, *out_count);
751
752   Xfree(buffers);
753
754   return pdraw->buffers;
755}
756
757#ifdef X_DRI2SwapInterval
758
759static int
760dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
761{
762   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
763   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
764   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
765
766   if (psc->config)
767      psc->config->configQueryi(psc->driScreen,
768				"vblank_mode", &vblank_mode);
769
770   switch (vblank_mode) {
771   case DRI_CONF_VBLANK_NEVER:
772      return GLX_BAD_VALUE;
773   case DRI_CONF_VBLANK_ALWAYS_SYNC:
774      if (interval <= 0)
775	 return GLX_BAD_VALUE;
776      break;
777   default:
778      break;
779   }
780
781   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
782   priv->swap_interval = interval;
783
784   return 0;
785}
786
787static int
788dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
789{
790   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
791
792  return priv->swap_interval;
793}
794
795#endif /* X_DRI2SwapInterval */
796
797static const __DRIdri2LoaderExtension dri2LoaderExtension = {
798   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
799   dri2GetBuffers,
800   dri2FlushFrontBuffer,
801   dri2GetBuffersWithFormat,
802};
803
804static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
805   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
806   dri2GetBuffers,
807   dri2FlushFrontBuffer,
808   NULL,
809};
810
811#ifdef __DRI_USE_INVALIDATE
812static const __DRIuseInvalidateExtension dri2UseInvalidate = {
813   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
814};
815#endif
816
817_X_HIDDEN void
818dri2InvalidateBuffers(Display *dpy, XID drawable)
819{
820   __GLXDRIdrawable *pdraw =
821      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
822   struct dri2_screen *psc;
823   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
824
825   if (!pdraw)
826      return;
827
828   psc = (struct dri2_screen *) pdraw->psc;
829
830#if __DRI2_FLUSH_VERSION >= 3
831   if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
832       psc->f->invalidate(pdp->driDrawable);
833#endif
834}
835
836static void
837dri2_bind_tex_image(Display * dpy,
838		    GLXDrawable drawable,
839		    int buffer, const int *attrib_list)
840{
841   struct glx_context *gc = __glXGetCurrentContext();
842   struct dri2_context *pcp = (struct dri2_context *) gc;
843   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
844   struct glx_display *dpyPriv = __glXInitialize(dpy);
845   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
846   struct dri2_display *pdp =
847      (struct dri2_display *) dpyPriv->dri2Display;
848   struct dri2_screen *psc;
849
850   if (pdraw != NULL) {
851      psc = (struct dri2_screen *) base->psc;
852
853#if __DRI2_FLUSH_VERSION >= 3
854      if (!pdp->invalidateAvailable && psc->f &&
855           psc->f->base.version >= 3 && psc->f->invalidate)
856	 psc->f->invalidate(pdraw->driDrawable);
857#endif
858
859      if (psc->texBuffer->base.version >= 2 &&
860	  psc->texBuffer->setTexBuffer2 != NULL) {
861	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
862					   pdraw->base.textureTarget,
863					   pdraw->base.textureFormat,
864					   pdraw->driDrawable);
865      }
866      else {
867	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
868					  pdraw->base.textureTarget,
869					  pdraw->driDrawable);
870      }
871   }
872}
873
874static void
875dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
876{
877#if __DRI_TEX_BUFFER_VERSION >= 3
878   struct glx_context *gc = __glXGetCurrentContext();
879   struct dri2_context *pcp = (struct dri2_context *) gc;
880   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
881   struct glx_display *dpyPriv = __glXInitialize(dpy);
882   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
883   struct dri2_display *pdp =
884      (struct dri2_display *) dpyPriv->dri2Display;
885   struct dri2_screen *psc;
886
887   if (pdraw != NULL) {
888      psc = (struct dri2_screen *) base->psc;
889
890      if (psc->texBuffer->base.version >= 3 &&
891          psc->texBuffer->releaseTexBuffer != NULL) {
892         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
893                                           pdraw->base.textureTarget,
894                                           pdraw->driDrawable);
895      }
896   }
897#endif
898}
899
900static const struct glx_context_vtable dri2_context_vtable = {
901   dri2_destroy_context,
902   dri2_bind_context,
903   dri2_unbind_context,
904   dri2_wait_gl,
905   dri2_wait_x,
906   DRI_glXUseXFont,
907   dri2_bind_tex_image,
908   dri2_release_tex_image,
909   NULL, /* get_proc_address */
910};
911
912static void
913dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
914{
915   int i;
916
917   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
918   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
919   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
920   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
921
922   /* FIXME: if DRI2 version supports it... */
923   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
924
925   if (psc->dri2->base.version >= 3) {
926      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
927      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
928   }
929
930   for (i = 0; extensions[i]; i++) {
931      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
932	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
933	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
934      }
935
936      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
937	 psc->f = (__DRI2flushExtension *) extensions[i];
938	 /* internal driver extension, no GL extension exposed */
939      }
940
941      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
942	 psc->config = (__DRI2configQueryExtension *) extensions[i];
943
944      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
945	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
946   }
947}
948
949static const struct glx_screen_vtable dri2_screen_vtable = {
950   dri2_create_context,
951   dri2_create_context_attribs
952};
953
954static struct glx_screen *
955dri2CreateScreen(int screen, struct glx_display * priv)
956{
957   const __DRIconfig **driver_configs;
958   const __DRIextension **extensions;
959   const struct dri2_display *const pdp = (struct dri2_display *)
960      priv->dri2Display;
961   struct dri2_screen *psc;
962   __GLXDRIscreen *psp;
963   struct glx_config *configs = NULL, *visuals = NULL;
964   char *driverName, *deviceName;
965   drm_magic_t magic;
966   int i;
967
968   psc = Xmalloc(sizeof *psc);
969   if (psc == NULL)
970      return NULL;
971
972   memset(psc, 0, sizeof *psc);
973   psc->fd = -1;
974
975   if (!glx_screen_init(&psc->base, screen, priv)) {
976      Xfree(psc);
977      return NULL;
978   }
979
980   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
981		    &driverName, &deviceName)) {
982      glx_screen_cleanup(&psc->base);
983      XFree(psc);
984      InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
985      return NULL;
986   }
987
988   psc->driver = driOpenDriver(driverName);
989   if (psc->driver == NULL) {
990      ErrorMessageF("driver pointer missing\n");
991      goto handle_error;
992   }
993
994   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
995   if (extensions == NULL) {
996      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
997      goto handle_error;
998   }
999
1000   for (i = 0; extensions[i]; i++) {
1001      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1002	 psc->core = (__DRIcoreExtension *) extensions[i];
1003      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
1004	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
1005   }
1006
1007   if (psc->core == NULL || psc->dri2 == NULL) {
1008      ErrorMessageF("core dri or dri2 extension not found\n");
1009      goto handle_error;
1010   }
1011
1012   psc->fd = open(deviceName, O_RDWR);
1013   if (psc->fd < 0) {
1014      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
1015      goto handle_error;
1016   }
1017
1018   if (drmGetMagic(psc->fd, &magic)) {
1019      ErrorMessageF("failed to get magic\n");
1020      goto handle_error;
1021   }
1022
1023   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
1024      ErrorMessageF("failed to authenticate magic %d\n", magic);
1025      goto handle_error;
1026   }
1027
1028
1029   /* If the server does not support the protocol for
1030    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
1031    */
1032   psc->driScreen =
1033      psc->dri2->createNewScreen(screen, psc->fd,
1034				 (const __DRIextension **)
1035				 &pdp->loader_extensions[0],
1036				 &driver_configs, psc);
1037
1038   if (psc->driScreen == NULL) {
1039      ErrorMessageF("failed to create dri screen\n");
1040      goto handle_error;
1041   }
1042
1043   extensions = psc->core->getExtensions(psc->driScreen);
1044   dri2BindExtensions(psc, extensions);
1045
1046   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1047   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1048
1049   if (!configs || !visuals)
1050       goto handle_error;
1051
1052   glx_config_destroy_list(psc->base.configs);
1053   psc->base.configs = configs;
1054   glx_config_destroy_list(psc->base.visuals);
1055   psc->base.visuals = visuals;
1056
1057   psc->driver_configs = driver_configs;
1058
1059   psc->base.vtable = &dri2_screen_vtable;
1060   psp = &psc->vtable;
1061   psc->base.driScreen = psp;
1062   psp->destroyScreen = dri2DestroyScreen;
1063   psp->createDrawable = dri2CreateDrawable;
1064   psp->swapBuffers = dri2SwapBuffers;
1065   psp->getDrawableMSC = NULL;
1066   psp->waitForMSC = NULL;
1067   psp->waitForSBC = NULL;
1068   psp->setSwapInterval = NULL;
1069   psp->getSwapInterval = NULL;
1070
1071   if (pdp->driMinor >= 2) {
1072#ifdef X_DRI2GetMSC
1073      psp->getDrawableMSC = dri2DrawableGetMSC;
1074#endif
1075#ifdef X_DRI2WaitMSC
1076      psp->waitForMSC = dri2WaitForMSC;
1077      psp->waitForSBC = dri2WaitForSBC;
1078#endif
1079#ifdef X_DRI2SwapInterval
1080      psp->setSwapInterval = dri2SetSwapInterval;
1081      psp->getSwapInterval = dri2GetSwapInterval;
1082#endif
1083#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
1084      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1085#endif
1086   }
1087
1088   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
1089    * available.*/
1090   psp->copySubBuffer = dri2CopySubBuffer;
1091   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1092
1093   Xfree(driverName);
1094   Xfree(deviceName);
1095
1096   return &psc->base;
1097
1098handle_error:
1099   if (configs)
1100       glx_config_destroy_list(configs);
1101   if (visuals)
1102       glx_config_destroy_list(visuals);
1103   if (psc->driScreen)
1104       psc->core->destroyScreen(psc->driScreen);
1105   psc->driScreen = NULL;
1106   if (psc->fd >= 0)
1107      close(psc->fd);
1108   if (psc->driver)
1109      dlclose(psc->driver);
1110
1111   Xfree(driverName);
1112   Xfree(deviceName);
1113   glx_screen_cleanup(&psc->base);
1114   XFree(psc);
1115
1116   return NULL;
1117}
1118
1119/* Called from __glXFreeDisplayPrivate.
1120 */
1121static void
1122dri2DestroyDisplay(__GLXDRIdisplay * dpy)
1123{
1124   struct dri2_display *pdp = (struct dri2_display *) dpy;
1125
1126   __glxHashDestroy(pdp->dri2Hash);
1127   Xfree(dpy);
1128}
1129
1130_X_HIDDEN __GLXDRIdrawable *
1131dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
1132{
1133   struct glx_display *d = __glXInitialize(dpy);
1134   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
1135   __GLXDRIdrawable *pdraw;
1136
1137   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
1138      return pdraw;
1139
1140   return NULL;
1141}
1142
1143/*
1144 * Allocate, initialize and return a __DRIdisplayPrivate object.
1145 * This is called from __glXInitialize() when we are given a new
1146 * display pointer.
1147 */
1148_X_HIDDEN __GLXDRIdisplay *
1149dri2CreateDisplay(Display * dpy)
1150{
1151   struct dri2_display *pdp;
1152   int eventBase, errorBase, i;
1153
1154   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1155      return NULL;
1156
1157   pdp = Xmalloc(sizeof *pdp);
1158   if (pdp == NULL)
1159      return NULL;
1160
1161   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1162      Xfree(pdp);
1163      return NULL;
1164   }
1165
1166   pdp->driPatch = 0;
1167   pdp->swapAvailable = (pdp->driMinor >= 2);
1168   pdp->invalidateAvailable = (pdp->driMinor >= 3);
1169
1170   pdp->base.destroyDisplay = dri2DestroyDisplay;
1171   pdp->base.createScreen = dri2CreateScreen;
1172
1173   i = 0;
1174   if (pdp->driMinor < 1)
1175      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
1176   else
1177      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
1178
1179   pdp->loader_extensions[i++] = &systemTimeExtension.base;
1180
1181#ifdef __DRI_USE_INVALIDATE
1182   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1183#endif
1184   pdp->loader_extensions[i++] = NULL;
1185
1186   pdp->dri2Hash = __glxHashCreate();
1187   if (pdp->dri2Hash == NULL) {
1188      Xfree(pdp);
1189      return NULL;
1190   }
1191
1192   return &pdp->base;
1193}
1194
1195#endif /* GLX_DIRECT_RENDERING */
1196