dri2_glx.c revision 037755122e9011c768e5caa4d4cb83aba783d3e9
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 <X11/extensions/Xdamage.h>
38#include "glapi.h"
39#include "glxclient.h"
40#include <X11/extensions/dri2proto.h>
41#include "xf86dri.h"
42#include <dlfcn.h>
43#include <fcntl.h>
44#include <unistd.h>
45#include <sys/types.h>
46#include <sys/mman.h>
47#include "xf86drm.h"
48#include "dri2.h"
49#include "dri_common.h"
50
51/* From xmlpool/options.h, user exposed so should be stable */
52#define DRI_CONF_VBLANK_NEVER 0
53#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
54#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
55#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
56
57#undef DRI2_MINOR
58#define DRI2_MINOR 1
59
60struct dri2_display
61{
62   __GLXDRIdisplay base;
63
64   /*
65    ** XFree86-DRI version information
66    */
67   int driMajor;
68   int driMinor;
69   int driPatch;
70   int swapAvailable;
71   int invalidateAvailable;
72
73   __glxHashTable *dri2Hash;
74
75   const __DRIextension *loader_extensions[4];
76};
77
78struct dri2_screen {
79   __GLXscreenConfigs base;
80
81   __DRIscreen *driScreen;
82   __GLXDRIscreen vtable;
83   const __DRIdri2Extension *dri2;
84   const __DRIcoreExtension *core;
85
86   const __DRI2flushExtension *f;
87   const __DRI2configQueryExtension *config;
88   const __DRItexBufferExtension *texBuffer;
89
90   void *driver;
91   int fd;
92};
93
94struct dri2_context
95{
96   __GLXDRIcontext base;
97   __DRIcontext *driContext;
98   __GLXscreenConfigs *psc;
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 void
114dri2DestroyContext(__GLXDRIcontext *context,
115		   __GLXscreenConfigs *base, Display *dpy)
116{
117   struct dri2_context *pcp = (struct dri2_context *) context;
118   struct dri2_screen *psc = (struct dri2_screen *) base;
119
120   (*psc->core->destroyContext) (pcp->driContext);
121
122   Xfree(pcp);
123}
124
125static Bool
126dri2BindContext(__GLXDRIcontext *context,
127		__GLXDRIdrawable *draw, __GLXDRIdrawable *read)
128{
129   struct dri2_context *pcp = (struct dri2_context *) context;
130   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
131   struct dri2_drawable *pdr = (struct dri2_drawable *) draw;
132   struct dri2_drawable *prd = (struct dri2_drawable *) read;
133
134   return (*psc->core->bindContext) (pcp->driContext,
135				     pdr->driDrawable, prd->driDrawable);
136}
137
138static void
139dri2UnbindContext(__GLXDRIcontext *context)
140{
141   struct dri2_context *pcp = (struct dri2_context *) context;
142   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
143
144   (*psc->core->unbindContext) (pcp->driContext);
145}
146
147static __GLXDRIcontext *
148dri2CreateContext(__GLXscreenConfigs *base,
149                  const __GLcontextModes * mode,
150                  GLXContext gc, GLXContext shareList, int renderType)
151{
152   struct dri2_context *pcp, *pcp_shared;
153   struct dri2_screen *psc = (struct dri2_screen *) base;
154   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
155   __DRIcontext *shared = NULL;
156
157   if (shareList) {
158      pcp_shared = (struct dri2_context *) shareList->driContext;
159      shared = pcp_shared->driContext;
160   }
161
162   pcp = Xmalloc(sizeof *pcp);
163   if (pcp == NULL)
164      return NULL;
165
166   pcp->psc = &psc->base;
167   pcp->driContext =
168      (*psc->dri2->createNewContext) (psc->driScreen,
169                                      config->driConfig, shared, pcp);
170   gc->__driContext = pcp->driContext;
171
172   if (pcp->driContext == NULL) {
173      Xfree(pcp);
174      return NULL;
175   }
176
177   pcp->base.destroyContext = dri2DestroyContext;
178   pcp->base.bindContext = dri2BindContext;
179   pcp->base.unbindContext = dri2UnbindContext;
180
181   return &pcp->base;
182}
183
184static void
185dri2DestroyDrawable(__GLXDRIdrawable *base)
186{
187   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
188   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
189   __GLXdisplayPrivate *dpyPriv = psc->base.display;
190   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
191
192   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
193   (*psc->core->destroyDrawable) (pdraw->driDrawable);
194   DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
195   Xfree(pdraw);
196}
197
198static __GLXDRIdrawable *
199dri2CreateDrawable(__GLXscreenConfigs *base, XID xDrawable,
200		   GLXDrawable drawable, const __GLcontextModes * modes)
201{
202   struct dri2_drawable *pdraw;
203   struct dri2_screen *psc = (struct dri2_screen *) base;
204   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
205   __GLXdisplayPrivate *dpyPriv;
206   struct dri2_display *pdp;
207   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
208
209   pdraw = Xmalloc(sizeof(*pdraw));
210   if (!pdraw)
211      return NULL;
212
213   pdraw->base.destroyDrawable = dri2DestroyDrawable;
214   pdraw->base.xDrawable = xDrawable;
215   pdraw->base.drawable = drawable;
216   pdraw->base.psc = &psc->base;
217   pdraw->bufferCount = 0;
218   pdraw->swap_interval = 1; /* default may be overridden below */
219   pdraw->have_back = 0;
220
221   if (psc->config)
222      psc->config->configQueryi(psc->driScreen,
223				"vblank_mode", &vblank_mode);
224
225   switch (vblank_mode) {
226   case DRI_CONF_VBLANK_NEVER:
227   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
228      pdraw->swap_interval = 0;
229      break;
230   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
231   case DRI_CONF_VBLANK_ALWAYS_SYNC:
232   default:
233      pdraw->swap_interval = 1;
234      break;
235   }
236
237   DRI2CreateDrawable(psc->base.dpy, xDrawable);
238
239   dpyPriv = __glXInitialize(psc->base.dpy);
240   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
241   /* Create a new drawable */
242   pdraw->driDrawable =
243      (*psc->dri2->createNewDrawable) (psc->driScreen,
244                                       config->driConfig, pdraw);
245
246   if (!pdraw->driDrawable) {
247      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
248      Xfree(pdraw);
249      return NULL;
250   }
251
252   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
253      (*psc->core->destroyDrawable) (pdraw->driDrawable);
254      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
255      Xfree(pdraw);
256      return None;
257   }
258
259
260#ifdef X_DRI2SwapInterval
261   /*
262    * Make sure server has the same swap interval we do for the new
263    * drawable.
264    */
265   if (pdp->swapAvailable)
266      DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
267#endif
268
269   return &pdraw->base;
270}
271
272#ifdef X_DRI2GetMSC
273
274static int
275dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw,
276		   int64_t *ust, int64_t *msc, int64_t *sbc)
277{
278   CARD64 dri2_ust, dri2_msc, dri2_sbc;
279   int ret;
280
281   ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
282		    &dri2_ust, &dri2_msc, &dri2_sbc);
283   *ust = dri2_ust;
284   *msc = dri2_msc;
285   *sbc = dri2_sbc;
286
287   return ret;
288}
289
290#endif
291
292
293#ifdef X_DRI2WaitMSC
294
295static int
296dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
297	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
298{
299   CARD64 dri2_ust, dri2_msc, dri2_sbc;
300   int ret;
301
302   ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
303		     remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
304   *ust = dri2_ust;
305   *msc = dri2_msc;
306   *sbc = dri2_sbc;
307
308   return ret;
309}
310
311static int
312dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
313	       int64_t *msc, int64_t *sbc)
314{
315   CARD64 dri2_ust, dri2_msc, dri2_sbc;
316   int ret;
317
318   ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
319		     target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
320   *ust = dri2_ust;
321   *msc = dri2_msc;
322   *sbc = dri2_sbc;
323
324   return ret;
325}
326
327#endif /* X_DRI2WaitMSC */
328
329static void
330dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height)
331{
332   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
333   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
334   XRectangle xrect;
335   XserverRegion region;
336
337   /* Check we have the right attachments */
338   if (!priv->have_back)
339      return;
340
341   xrect.x = x;
342   xrect.y = priv->height - y - height;
343   xrect.width = width;
344   xrect.height = height;
345
346#ifdef __DRI2_FLUSH
347   if (psc->f)
348      (*psc->f->flush) (priv->driDrawable);
349#endif
350
351   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
352   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
353                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
354   XFixesDestroyRegion(psc->base.dpy, region);
355
356   /* Refresh the fake front (if present) after we just damaged the real
357    * front.
358    */
359   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
360		  DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
361   XFixesDestroyRegion(psc->base.dpy, region);
362}
363
364static void
365dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
366{
367   XRectangle xrect;
368   XserverRegion region;
369   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
370
371   xrect.x = 0;
372   xrect.y = 0;
373   xrect.width = priv->width;
374   xrect.height = priv->height;
375
376#ifdef __DRI2_FLUSH
377   if (psc->f)
378      (*psc->f->flush) (priv->driDrawable);
379#endif
380
381   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
382   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
383   XFixesDestroyRegion(psc->base.dpy, region);
384
385}
386
387static void
388dri2WaitX(__GLXDRIdrawable *pdraw)
389{
390   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
391
392   if (!priv->have_fake_front)
393      return;
394
395   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
396}
397
398static void
399dri2WaitGL(__GLXDRIdrawable * pdraw)
400{
401   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
402
403   if (!priv->have_fake_front)
404      return;
405
406   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
407}
408
409static void
410dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
411{
412   struct dri2_drawable *pdraw = loaderPrivate;
413   __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy);
414   struct dri2_display *pdp = (struct dri2_display *)priv->dri2Display;
415
416   /* Old servers don't send invalidate events */
417   if (!pdp->invalidateAvailable)
418       dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
419
420   dri2WaitGL(loaderPrivate);
421}
422
423
424static void
425dri2DestroyScreen(__GLXscreenConfigs *base)
426{
427   struct dri2_screen *psc = (struct dri2_screen *) base;
428
429   /* Free the direct rendering per screen data */
430   (*psc->core->destroyScreen) (psc->driScreen);
431   close(psc->fd);
432   Xfree(psc);
433}
434
435/**
436 * Process list of buffer received from the server
437 *
438 * Processes the list of buffers received in a reply from the server to either
439 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
440 */
441static void
442process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
443                unsigned count)
444{
445   int i;
446
447   pdraw->bufferCount = count;
448   pdraw->have_fake_front = 0;
449   pdraw->have_back = 0;
450
451   /* This assumes the DRI2 buffer attachment tokens matches the
452    * __DRIbuffer tokens. */
453   for (i = 0; i < count; i++) {
454      pdraw->buffers[i].attachment = buffers[i].attachment;
455      pdraw->buffers[i].name = buffers[i].name;
456      pdraw->buffers[i].pitch = buffers[i].pitch;
457      pdraw->buffers[i].cpp = buffers[i].cpp;
458      pdraw->buffers[i].flags = buffers[i].flags;
459      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
460         pdraw->have_fake_front = 1;
461      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
462         pdraw->have_back = 1;
463   }
464
465}
466
467static int64_t
468dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
469		int64_t remainder)
470{
471    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
472    __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy);
473    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
474    struct dri2_display *pdp =
475	(struct dri2_display *)dpyPriv->dri2Display;
476    CARD64 ret;
477
478#ifdef __DRI2_FLUSH
479    if (psc->f)
480    	(*psc->f->flush)(priv->driDrawable);
481#endif
482
483    /* Old servers don't send invalidate events */
484    if (!pdp->invalidateAvailable)
485       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
486
487    /* Old servers can't handle swapbuffers */
488    if (!pdp->swapAvailable) {
489       dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
490       return 0;
491    }
492
493#ifdef X_DRI2SwapBuffers
494    DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor,
495		    remainder, &ret);
496#endif
497
498    return ret;
499}
500
501static __DRIbuffer *
502dri2GetBuffers(__DRIdrawable * driDrawable,
503               int *width, int *height,
504               unsigned int *attachments, int count,
505               int *out_count, void *loaderPrivate)
506{
507   struct dri2_drawable *pdraw = loaderPrivate;
508   DRI2Buffer *buffers;
509
510   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
511                            width, height, attachments, count, out_count);
512   if (buffers == NULL)
513      return NULL;
514
515   pdraw->width = *width;
516   pdraw->height = *height;
517   process_buffers(pdraw, buffers, *out_count);
518
519   Xfree(buffers);
520
521   return pdraw->buffers;
522}
523
524static __DRIbuffer *
525dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
526                         int *width, int *height,
527                         unsigned int *attachments, int count,
528                         int *out_count, void *loaderPrivate)
529{
530   struct dri2_drawable *pdraw = loaderPrivate;
531   DRI2Buffer *buffers;
532
533   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
534                                      pdraw->base.xDrawable,
535                                      width, height, attachments,
536                                      count, out_count);
537   if (buffers == NULL)
538      return NULL;
539
540   pdraw->width = *width;
541   pdraw->height = *height;
542   process_buffers(pdraw, buffers, *out_count);
543
544   Xfree(buffers);
545
546   return pdraw->buffers;
547}
548
549#ifdef X_DRI2SwapInterval
550
551static int
552dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
553{
554   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
555   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
556   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
557
558   if (psc->config)
559      psc->config->configQueryi(psc->driScreen,
560				"vblank_mode", &vblank_mode);
561
562   switch (vblank_mode) {
563   case DRI_CONF_VBLANK_NEVER:
564      return GLX_BAD_VALUE;
565   case DRI_CONF_VBLANK_ALWAYS_SYNC:
566      if (interval <= 0)
567	 return GLX_BAD_VALUE;
568      break;
569   default:
570      break;
571   }
572
573   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
574   priv->swap_interval = interval;
575
576   return 0;
577}
578
579static int
580dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
581{
582   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
583
584  return priv->swap_interval;
585}
586
587#endif /* X_DRI2SwapInterval */
588
589static const __DRIdri2LoaderExtension dri2LoaderExtension = {
590   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
591   dri2GetBuffers,
592   dri2FlushFrontBuffer,
593   dri2GetBuffersWithFormat,
594};
595
596static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
597   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
598   dri2GetBuffers,
599   dri2FlushFrontBuffer,
600   NULL,
601};
602
603#ifdef __DRI_USE_INVALIDATE
604static const __DRIuseInvalidateExtension dri2UseInvalidate = {
605   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
606};
607#endif
608
609_X_HIDDEN void
610dri2InvalidateBuffers(Display *dpy, XID drawable)
611{
612   __GLXDRIdrawable *pdraw =
613      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
614   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
615   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
616
617#if __DRI2_FLUSH_VERSION >= 3
618   if (pdraw && psc->f)
619       psc->f->invalidate(pdp->driDrawable);
620#endif
621}
622
623static void
624dri2_bind_tex_image(Display * dpy,
625		    GLXDrawable drawable,
626		    int buffer, const int *attrib_list)
627{
628   GLXContext gc = __glXGetCurrentContext();
629   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable, NULL);
630   __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
631   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
632   struct dri2_display *pdp =
633      (struct dri2_display *) dpyPriv->dri2Display;
634   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
635
636   if (pdraw != NULL) {
637
638#if __DRI2_FLUSH_VERSION >= 3
639      if (!pdp->invalidateAvailable && psc->f)
640	 psc->f->invalidate(pdraw->driDrawable);
641#endif
642
643      if (psc->texBuffer->base.version >= 2 &&
644	  psc->texBuffer->setTexBuffer2 != NULL) {
645	 (*psc->texBuffer->setTexBuffer2) (gc->__driContext,
646					   pdraw->base.textureTarget,
647					   pdraw->base.textureFormat,
648					   pdraw->driDrawable);
649      }
650      else {
651	 (*psc->texBuffer->setTexBuffer) (gc->__driContext,
652					  pdraw->base.textureTarget,
653					  pdraw->driDrawable);
654      }
655   }
656}
657
658static void
659dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
660{
661}
662
663static const struct glx_context_vtable dri2_context_vtable = {
664   dri2_bind_tex_image,
665   dri2_release_tex_image,
666};
667
668static void
669dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
670{
671   int i;
672
673   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
674   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
675   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
676
677   /* FIXME: if DRI2 version supports it... */
678   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
679
680   for (i = 0; extensions[i]; i++) {
681      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
682	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
683	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
684      }
685
686      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
687	 psc->f = (__DRI2flushExtension *) extensions[i];
688	 /* internal driver extension, no GL extension exposed */
689      }
690
691      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
692	 psc->config = (__DRI2configQueryExtension *) extensions[i];
693   }
694}
695
696
697static __GLXscreenConfigs *
698dri2CreateScreen(int screen, __GLXdisplayPrivate * priv)
699{
700   const __DRIconfig **driver_configs;
701   const __DRIextension **extensions;
702   const struct dri2_display *const pdp = (struct dri2_display *)
703      priv->dri2Display;
704   struct dri2_screen *psc;
705   __GLXDRIscreen *psp;
706   char *driverName, *deviceName;
707   drm_magic_t magic;
708   int i;
709
710   psc = Xmalloc(sizeof *psc);
711   if (psc == NULL)
712      return NULL;
713
714   memset(psc, 0, sizeof *psc);
715   if (!glx_screen_init(&psc->base, screen, priv))
716       return NULL;
717
718   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
719		    &driverName, &deviceName)) {
720      XFree(psc);
721      return NULL;
722   }
723
724   psc->driver = driOpenDriver(driverName);
725   if (psc->driver == NULL) {
726      ErrorMessageF("driver pointer missing\n");
727      goto handle_error;
728   }
729
730   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
731   if (extensions == NULL) {
732      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
733      goto handle_error;
734   }
735
736   for (i = 0; extensions[i]; i++) {
737      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
738	 psc->core = (__DRIcoreExtension *) extensions[i];
739      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
740	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
741   }
742
743   if (psc->core == NULL || psc->dri2 == NULL) {
744      ErrorMessageF("core dri or dri2 extension not found\n");
745      goto handle_error;
746   }
747
748   psc->fd = open(deviceName, O_RDWR);
749   if (psc->fd < 0) {
750      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
751      goto handle_error;
752   }
753
754   if (drmGetMagic(psc->fd, &magic)) {
755      ErrorMessageF("failed to get magic\n");
756      goto handle_error;
757   }
758
759   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
760      ErrorMessageF("failed to authenticate magic %d\n", magic);
761      goto handle_error;
762   }
763
764
765   /* If the server does not support the protocol for
766    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
767    */
768   psc->driScreen =
769      psc->dri2->createNewScreen(screen, psc->fd,
770				 (const __DRIextension **)
771				 &pdp->loader_extensions[0],
772				 &driver_configs, psc);
773
774   if (psc->driScreen == NULL) {
775      ErrorMessageF("failed to create dri screen\n");
776      goto handle_error;
777   }
778
779   extensions = psc->core->getExtensions(psc->driScreen);
780   driBindCommonExtensions(&psc->base, extensions);
781   dri2BindExtensions(psc, extensions);
782
783   psc->base.configs =
784      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
785   psc->base.visuals =
786      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
787
788   psc->base.driver_configs = driver_configs;
789
790   psp = &psc->vtable;
791   psc->base.driScreen = psp;
792   psp->destroyScreen = dri2DestroyScreen;
793   psp->createContext = dri2CreateContext;
794   psp->createDrawable = dri2CreateDrawable;
795   psp->swapBuffers = dri2SwapBuffers;
796   psp->waitGL = dri2WaitGL;
797   psp->waitX = dri2WaitX;
798   psp->getDrawableMSC = NULL;
799   psp->waitForMSC = NULL;
800   psp->waitForSBC = NULL;
801   psp->setSwapInterval = NULL;
802   psp->getSwapInterval = NULL;
803
804   if (pdp->driMinor >= 2) {
805#ifdef X_DRI2GetMSC
806      psp->getDrawableMSC = dri2DrawableGetMSC;
807#endif
808#ifdef X_DRI2WaitMSC
809      psp->waitForMSC = dri2WaitForMSC;
810      psp->waitForSBC = dri2WaitForSBC;
811#endif
812#ifdef X_DRI2SwapInterval
813      psp->setSwapInterval = dri2SetSwapInterval;
814      psp->getSwapInterval = dri2GetSwapInterval;
815#endif
816#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
817      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
818#endif
819   }
820
821   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
822    * available.*/
823   psp->copySubBuffer = dri2CopySubBuffer;
824   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
825
826   psc->base.direct_context_vtable = &dri2_context_vtable;
827
828   Xfree(driverName);
829   Xfree(deviceName);
830
831   return &psc->base;
832
833handle_error:
834   Xfree(driverName);
835   Xfree(deviceName);
836   XFree(psc);
837
838   /* FIXME: clean up here */
839
840   return NULL;
841}
842
843/* Called from __glXFreeDisplayPrivate.
844 */
845static void
846dri2DestroyDisplay(__GLXDRIdisplay * dpy)
847{
848   Xfree(dpy);
849}
850
851_X_HIDDEN __GLXDRIdrawable *
852dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
853{
854   __GLXdisplayPrivate *d = __glXInitialize(dpy);
855   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
856   __GLXDRIdrawable *pdraw;
857
858   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
859      return pdraw;
860
861   return NULL;
862}
863
864/*
865 * Allocate, initialize and return a __DRIdisplayPrivate object.
866 * This is called from __glXInitialize() when we are given a new
867 * display pointer.
868 */
869_X_HIDDEN __GLXDRIdisplay *
870dri2CreateDisplay(Display * dpy)
871{
872   struct dri2_display *pdp;
873   int eventBase, errorBase, i;
874
875   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
876      return NULL;
877
878   pdp = Xmalloc(sizeof *pdp);
879   if (pdp == NULL)
880      return NULL;
881
882   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
883      Xfree(pdp);
884      return NULL;
885   }
886
887   pdp->driPatch = 0;
888   pdp->swapAvailable = (pdp->driMinor >= 2);
889   pdp->invalidateAvailable = (pdp->driMinor >= 3);
890
891   pdp->base.destroyDisplay = dri2DestroyDisplay;
892   pdp->base.createScreen = dri2CreateScreen;
893
894   i = 0;
895   if (pdp->driMinor < 1)
896      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
897   else
898      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
899
900   pdp->loader_extensions[i++] = &systemTimeExtension.base;
901
902#ifdef __DRI_USE_INVALIDATE
903   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
904#endif
905   pdp->loader_extensions[i++] = NULL;
906
907   pdp->dri2Hash = __glxHashCreate();
908   if (pdp->dri2Hash == NULL) {
909      Xfree(pdp);
910      return NULL;
911   }
912
913   return &pdp->base;
914}
915
916#endif /* GLX_DIRECT_RENDERING */
917