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