dri2_glx.c revision f679640868ae6ef700d8672702c31ba2515220a7
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   const __DRIconfig **driver_configs;
90
91   void *driver;
92   int fd;
93};
94
95struct dri2_context
96{
97   __GLXDRIcontext base;
98   __DRIcontext *driContext;
99   __GLXscreenConfigs *psc;
100};
101
102struct dri2_drawable
103{
104   __GLXDRIdrawable base;
105   __DRIdrawable *driDrawable;
106   __DRIbuffer buffers[5];
107   int bufferCount;
108   int width, height;
109   int have_back;
110   int have_fake_front;
111   int swap_interval;
112};
113
114static void
115dri2DestroyContext(__GLXDRIcontext *context,
116		   __GLXscreenConfigs *base, Display *dpy)
117{
118   struct dri2_context *pcp = (struct dri2_context *) context;
119   struct dri2_screen *psc = (struct dri2_screen *) base;
120
121   (*psc->core->destroyContext) (pcp->driContext);
122
123   Xfree(pcp);
124}
125
126static Bool
127dri2BindContext(__GLXDRIcontext *context,
128		__GLXDRIdrawable *draw, __GLXDRIdrawable *read)
129{
130   struct dri2_context *pcp = (struct dri2_context *) context;
131   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
132   struct dri2_drawable *pdr = (struct dri2_drawable *) draw;
133   struct dri2_drawable *prd = (struct dri2_drawable *) read;
134
135   return (*psc->core->bindContext) (pcp->driContext,
136				     pdr->driDrawable, prd->driDrawable);
137}
138
139static void
140dri2UnbindContext(__GLXDRIcontext *context)
141{
142   struct dri2_context *pcp = (struct dri2_context *) context;
143   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
144
145   (*psc->core->unbindContext) (pcp->driContext);
146}
147
148static __GLXDRIcontext *
149dri2CreateContext(__GLXscreenConfigs *base,
150                  const __GLcontextModes * mode,
151                  GLXContext gc, GLXContext shareList, int renderType)
152{
153   struct dri2_context *pcp, *pcp_shared;
154   struct dri2_screen *psc = (struct dri2_screen *) base;
155   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
156   __DRIcontext *shared = NULL;
157
158   if (shareList) {
159      pcp_shared = (struct dri2_context *) shareList->driContext;
160      shared = pcp_shared->driContext;
161   }
162
163   pcp = Xmalloc(sizeof *pcp);
164   if (pcp == NULL)
165      return NULL;
166
167   pcp->psc = &psc->base;
168   pcp->driContext =
169      (*psc->dri2->createNewContext) (psc->driScreen,
170                                      config->driConfig, shared, pcp);
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
355   /* Refresh the fake front (if present) after we just damaged the real
356    * front.
357    */
358   if (priv->have_fake_front)
359      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
360		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
361
362   XFixesDestroyRegion(psc->base.dpy, region);
363}
364
365static void
366dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
367{
368   XRectangle xrect;
369   XserverRegion region;
370   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
371
372   xrect.x = 0;
373   xrect.y = 0;
374   xrect.width = priv->width;
375   xrect.height = priv->height;
376
377#ifdef __DRI2_FLUSH
378   if (psc->f)
379      (*psc->f->flush) (priv->driDrawable);
380#endif
381
382   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
383   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
384   XFixesDestroyRegion(psc->base.dpy, region);
385
386}
387
388static void
389dri2WaitX(__GLXDRIdrawable *pdraw)
390{
391   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
392
393   if (!priv->have_fake_front)
394      return;
395
396   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
397}
398
399static void
400dri2WaitGL(__GLXDRIdrawable * pdraw)
401{
402   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
403
404   if (!priv->have_fake_front)
405      return;
406
407   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
408}
409
410static void
411dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
412{
413   struct dri2_drawable *pdraw = loaderPrivate;
414   __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy);
415   struct dri2_display *pdp = (struct dri2_display *)priv->dri2Display;
416
417   /* Old servers don't send invalidate events */
418   if (!pdp->invalidateAvailable)
419       dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
420
421   dri2WaitGL(loaderPrivate);
422}
423
424
425static void
426dri2DestroyScreen(__GLXscreenConfigs *base)
427{
428   struct dri2_screen *psc = (struct dri2_screen *) base;
429
430   /* Free the direct rendering per screen data */
431   (*psc->core->destroyScreen) (psc->driScreen);
432   driDestroyConfigs(psc->driver_configs);
433   close(psc->fd);
434   Xfree(psc);
435}
436
437/**
438 * Process list of buffer received from the server
439 *
440 * Processes the list of buffers received in a reply from the server to either
441 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
442 */
443static void
444process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
445                unsigned count)
446{
447   int i;
448
449   pdraw->bufferCount = count;
450   pdraw->have_fake_front = 0;
451   pdraw->have_back = 0;
452
453   /* This assumes the DRI2 buffer attachment tokens matches the
454    * __DRIbuffer tokens. */
455   for (i = 0; i < count; i++) {
456      pdraw->buffers[i].attachment = buffers[i].attachment;
457      pdraw->buffers[i].name = buffers[i].name;
458      pdraw->buffers[i].pitch = buffers[i].pitch;
459      pdraw->buffers[i].cpp = buffers[i].cpp;
460      pdraw->buffers[i].flags = buffers[i].flags;
461      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
462         pdraw->have_fake_front = 1;
463      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
464         pdraw->have_back = 1;
465   }
466
467}
468
469static int64_t
470dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
471		int64_t remainder)
472{
473    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
474    __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy);
475    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
476    struct dri2_display *pdp =
477	(struct dri2_display *)dpyPriv->dri2Display;
478    CARD64 ret;
479
480#ifdef __DRI2_FLUSH
481    if (psc->f)
482    	(*psc->f->flush)(priv->driDrawable);
483#endif
484
485    /* Old servers don't send invalidate events */
486    if (!pdp->invalidateAvailable)
487       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
488
489    /* Old servers can't handle swapbuffers */
490    if (!pdp->swapAvailable) {
491       dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
492       return 0;
493    }
494
495#ifdef X_DRI2SwapBuffers
496    DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor,
497		    remainder, &ret);
498#endif
499
500    return ret;
501}
502
503static __DRIbuffer *
504dri2GetBuffers(__DRIdrawable * driDrawable,
505               int *width, int *height,
506               unsigned int *attachments, int count,
507               int *out_count, void *loaderPrivate)
508{
509   struct dri2_drawable *pdraw = loaderPrivate;
510   DRI2Buffer *buffers;
511
512   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
513                            width, height, attachments, count, out_count);
514   if (buffers == NULL)
515      return NULL;
516
517   pdraw->width = *width;
518   pdraw->height = *height;
519   process_buffers(pdraw, buffers, *out_count);
520
521   Xfree(buffers);
522
523   return pdraw->buffers;
524}
525
526static __DRIbuffer *
527dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
528                         int *width, int *height,
529                         unsigned int *attachments, int count,
530                         int *out_count, void *loaderPrivate)
531{
532   struct dri2_drawable *pdraw = loaderPrivate;
533   DRI2Buffer *buffers;
534
535   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
536                                      pdraw->base.xDrawable,
537                                      width, height, attachments,
538                                      count, out_count);
539   if (buffers == NULL)
540      return NULL;
541
542   pdraw->width = *width;
543   pdraw->height = *height;
544   process_buffers(pdraw, buffers, *out_count);
545
546   Xfree(buffers);
547
548   return pdraw->buffers;
549}
550
551#ifdef X_DRI2SwapInterval
552
553static int
554dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
555{
556   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
557   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
558   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
559
560   if (psc->config)
561      psc->config->configQueryi(psc->driScreen,
562				"vblank_mode", &vblank_mode);
563
564   switch (vblank_mode) {
565   case DRI_CONF_VBLANK_NEVER:
566      return GLX_BAD_VALUE;
567   case DRI_CONF_VBLANK_ALWAYS_SYNC:
568      if (interval <= 0)
569	 return GLX_BAD_VALUE;
570      break;
571   default:
572      break;
573   }
574
575   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
576   priv->swap_interval = interval;
577
578   return 0;
579}
580
581static int
582dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
583{
584   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
585
586  return priv->swap_interval;
587}
588
589#endif /* X_DRI2SwapInterval */
590
591static const __DRIdri2LoaderExtension dri2LoaderExtension = {
592   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
593   dri2GetBuffers,
594   dri2FlushFrontBuffer,
595   dri2GetBuffersWithFormat,
596};
597
598static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
599   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
600   dri2GetBuffers,
601   dri2FlushFrontBuffer,
602   NULL,
603};
604
605#ifdef __DRI_USE_INVALIDATE
606static const __DRIuseInvalidateExtension dri2UseInvalidate = {
607   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
608};
609#endif
610
611_X_HIDDEN void
612dri2InvalidateBuffers(Display *dpy, XID drawable)
613{
614   __GLXDRIdrawable *pdraw =
615      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
616   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
617   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
618
619#if __DRI2_FLUSH_VERSION >= 3
620   if (pdraw && psc->f)
621       psc->f->invalidate(pdp->driDrawable);
622#endif
623}
624
625static void
626dri2_bind_tex_image(Display * dpy,
627		    GLXDrawable drawable,
628		    int buffer, const int *attrib_list)
629{
630   GLXContext gc = __glXGetCurrentContext();
631   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable, NULL);
632   __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
633   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
634   struct dri2_display *pdp =
635      (struct dri2_display *) dpyPriv->dri2Display;
636   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
637   struct dri2_context *pcp = (struct dri2_context *) gc->driContext;
638
639   if (pdraw != NULL) {
640
641#if __DRI2_FLUSH_VERSION >= 3
642      if (!pdp->invalidateAvailable && psc->f)
643	 psc->f->invalidate(pdraw->driDrawable);
644#endif
645
646      if (psc->texBuffer->base.version >= 2 &&
647	  psc->texBuffer->setTexBuffer2 != NULL) {
648	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
649					   pdraw->base.textureTarget,
650					   pdraw->base.textureFormat,
651					   pdraw->driDrawable);
652      }
653      else {
654	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
655					  pdraw->base.textureTarget,
656					  pdraw->driDrawable);
657      }
658   }
659}
660
661static void
662dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
663{
664}
665
666static const struct glx_context_vtable dri2_context_vtable = {
667   dri2_bind_tex_image,
668   dri2_release_tex_image,
669};
670
671static void
672dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
673{
674   int i;
675
676   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
677   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
678   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
679   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
680
681   /* FIXME: if DRI2 version supports it... */
682   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
683
684   for (i = 0; extensions[i]; i++) {
685      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
686	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
687	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
688      }
689
690      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
691	 psc->f = (__DRI2flushExtension *) extensions[i];
692	 /* internal driver extension, no GL extension exposed */
693      }
694
695      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
696	 psc->config = (__DRI2configQueryExtension *) extensions[i];
697   }
698}
699
700
701static __GLXscreenConfigs *
702dri2CreateScreen(int screen, __GLXdisplayPrivate * priv)
703{
704   const __DRIconfig **driver_configs;
705   const __DRIextension **extensions;
706   const struct dri2_display *const pdp = (struct dri2_display *)
707      priv->dri2Display;
708   struct dri2_screen *psc;
709   __GLXDRIscreen *psp;
710   char *driverName, *deviceName;
711   drm_magic_t magic;
712   int i;
713
714   psc = Xmalloc(sizeof *psc);
715   if (psc == NULL)
716      return NULL;
717
718   memset(psc, 0, sizeof *psc);
719   if (!glx_screen_init(&psc->base, screen, priv))
720       return NULL;
721
722   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
723		    &driverName, &deviceName)) {
724      XFree(psc);
725      return NULL;
726   }
727
728   psc->driver = driOpenDriver(driverName);
729   if (psc->driver == NULL) {
730      ErrorMessageF("driver pointer missing\n");
731      goto handle_error;
732   }
733
734   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
735   if (extensions == NULL) {
736      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
737      goto handle_error;
738   }
739
740   for (i = 0; extensions[i]; i++) {
741      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
742	 psc->core = (__DRIcoreExtension *) extensions[i];
743      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
744	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
745   }
746
747   if (psc->core == NULL || psc->dri2 == NULL) {
748      ErrorMessageF("core dri or dri2 extension not found\n");
749      goto handle_error;
750   }
751
752   psc->fd = open(deviceName, O_RDWR);
753   if (psc->fd < 0) {
754      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
755      goto handle_error;
756   }
757
758   if (drmGetMagic(psc->fd, &magic)) {
759      ErrorMessageF("failed to get magic\n");
760      goto handle_error;
761   }
762
763   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
764      ErrorMessageF("failed to authenticate magic %d\n", magic);
765      goto handle_error;
766   }
767
768
769   /* If the server does not support the protocol for
770    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
771    */
772   psc->driScreen =
773      psc->dri2->createNewScreen(screen, psc->fd,
774				 (const __DRIextension **)
775				 &pdp->loader_extensions[0],
776				 &driver_configs, psc);
777
778   if (psc->driScreen == NULL) {
779      ErrorMessageF("failed to create dri screen\n");
780      goto handle_error;
781   }
782
783   extensions = psc->core->getExtensions(psc->driScreen);
784   dri2BindExtensions(psc, extensions);
785
786   psc->base.configs =
787      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
788   psc->base.visuals =
789      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
790
791   psc->driver_configs = driver_configs;
792
793   psp = &psc->vtable;
794   psc->base.driScreen = psp;
795   psp->destroyScreen = dri2DestroyScreen;
796   psp->createContext = dri2CreateContext;
797   psp->createDrawable = dri2CreateDrawable;
798   psp->swapBuffers = dri2SwapBuffers;
799   psp->waitGL = dri2WaitGL;
800   psp->waitX = dri2WaitX;
801   psp->getDrawableMSC = NULL;
802   psp->waitForMSC = NULL;
803   psp->waitForSBC = NULL;
804   psp->setSwapInterval = NULL;
805   psp->getSwapInterval = NULL;
806
807   if (pdp->driMinor >= 2) {
808#ifdef X_DRI2GetMSC
809      psp->getDrawableMSC = dri2DrawableGetMSC;
810#endif
811#ifdef X_DRI2WaitMSC
812      psp->waitForMSC = dri2WaitForMSC;
813      psp->waitForSBC = dri2WaitForSBC;
814#endif
815#ifdef X_DRI2SwapInterval
816      psp->setSwapInterval = dri2SetSwapInterval;
817      psp->getSwapInterval = dri2GetSwapInterval;
818#endif
819#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
820      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
821#endif
822   }
823
824   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
825    * available.*/
826   psp->copySubBuffer = dri2CopySubBuffer;
827   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
828
829   psc->base.direct_context_vtable = &dri2_context_vtable;
830
831   Xfree(driverName);
832   Xfree(deviceName);
833
834   return &psc->base;
835
836handle_error:
837   Xfree(driverName);
838   Xfree(deviceName);
839   XFree(psc);
840
841   /* FIXME: clean up here */
842
843   return NULL;
844}
845
846/* Called from __glXFreeDisplayPrivate.
847 */
848static void
849dri2DestroyDisplay(__GLXDRIdisplay * dpy)
850{
851   Xfree(dpy);
852}
853
854_X_HIDDEN __GLXDRIdrawable *
855dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
856{
857   __GLXdisplayPrivate *d = __glXInitialize(dpy);
858   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
859   __GLXDRIdrawable *pdraw;
860
861   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
862      return pdraw;
863
864   return NULL;
865}
866
867/*
868 * Allocate, initialize and return a __DRIdisplayPrivate object.
869 * This is called from __glXInitialize() when we are given a new
870 * display pointer.
871 */
872_X_HIDDEN __GLXDRIdisplay *
873dri2CreateDisplay(Display * dpy)
874{
875   struct dri2_display *pdp;
876   int eventBase, errorBase, i;
877
878   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
879      return NULL;
880
881   pdp = Xmalloc(sizeof *pdp);
882   if (pdp == NULL)
883      return NULL;
884
885   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
886      Xfree(pdp);
887      return NULL;
888   }
889
890   pdp->driPatch = 0;
891   pdp->swapAvailable = (pdp->driMinor >= 2);
892   pdp->invalidateAvailable = (pdp->driMinor >= 3);
893
894   pdp->base.destroyDisplay = dri2DestroyDisplay;
895   pdp->base.createScreen = dri2CreateScreen;
896
897   i = 0;
898   if (pdp->driMinor < 1)
899      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
900   else
901      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
902
903   pdp->loader_extensions[i++] = &systemTimeExtension.base;
904
905#ifdef __DRI_USE_INVALIDATE
906   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
907#endif
908   pdp->loader_extensions[i++] = NULL;
909
910   pdp->dri2Hash = __glxHashCreate();
911   if (pdp->dri2Hash == NULL) {
912      Xfree(pdp);
913      return NULL;
914   }
915
916   return &pdp->base;
917}
918
919#endif /* GLX_DIRECT_RENDERING */
920