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