dri2_glx.c revision eeaab2047cfce8a7445fd9f835e737682eb503ac
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
427   /* Old servers don't send invalidate events */
428   if (!pdp->invalidateAvailable)
429       dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
430
431   dri2_copy_drawable(pdraw, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
432}
433
434
435static void
436dri2DestroyScreen(__GLXscreenConfigs *base)
437{
438   struct dri2_screen *psc = (struct dri2_screen *) base;
439
440   /* Free the direct rendering per screen data */
441   (*psc->core->destroyScreen) (psc->driScreen);
442   driDestroyConfigs(psc->driver_configs);
443   close(psc->fd);
444   Xfree(psc);
445}
446
447/**
448 * Process list of buffer received from the server
449 *
450 * Processes the list of buffers received in a reply from the server to either
451 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
452 */
453static void
454process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
455                unsigned count)
456{
457   int i;
458
459   pdraw->bufferCount = count;
460   pdraw->have_fake_front = 0;
461   pdraw->have_back = 0;
462
463   /* This assumes the DRI2 buffer attachment tokens matches the
464    * __DRIbuffer tokens. */
465   for (i = 0; i < count; i++) {
466      pdraw->buffers[i].attachment = buffers[i].attachment;
467      pdraw->buffers[i].name = buffers[i].name;
468      pdraw->buffers[i].pitch = buffers[i].pitch;
469      pdraw->buffers[i].cpp = buffers[i].cpp;
470      pdraw->buffers[i].flags = buffers[i].flags;
471      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
472         pdraw->have_fake_front = 1;
473      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
474         pdraw->have_back = 1;
475   }
476
477}
478
479static int64_t
480dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
481		int64_t remainder)
482{
483    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
484    __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy);
485    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
486    struct dri2_display *pdp =
487	(struct dri2_display *)dpyPriv->dri2Display;
488    CARD64 ret;
489
490#ifdef __DRI2_FLUSH
491    if (psc->f)
492    	(*psc->f->flush)(priv->driDrawable);
493#endif
494
495    /* Old servers don't send invalidate events */
496    if (!pdp->invalidateAvailable)
497       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
498
499    /* Old servers can't handle swapbuffers */
500    if (!pdp->swapAvailable) {
501       dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
502       return 0;
503    }
504
505#ifdef X_DRI2SwapBuffers
506    DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor,
507		    remainder, &ret);
508#endif
509
510    return ret;
511}
512
513static __DRIbuffer *
514dri2GetBuffers(__DRIdrawable * driDrawable,
515               int *width, int *height,
516               unsigned int *attachments, int count,
517               int *out_count, void *loaderPrivate)
518{
519   struct dri2_drawable *pdraw = loaderPrivate;
520   DRI2Buffer *buffers;
521
522   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
523                            width, height, attachments, count, out_count);
524   if (buffers == NULL)
525      return NULL;
526
527   pdraw->width = *width;
528   pdraw->height = *height;
529   process_buffers(pdraw, buffers, *out_count);
530
531   Xfree(buffers);
532
533   return pdraw->buffers;
534}
535
536static __DRIbuffer *
537dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
538                         int *width, int *height,
539                         unsigned int *attachments, int count,
540                         int *out_count, void *loaderPrivate)
541{
542   struct dri2_drawable *pdraw = loaderPrivate;
543   DRI2Buffer *buffers;
544
545   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
546                                      pdraw->base.xDrawable,
547                                      width, height, attachments,
548                                      count, out_count);
549   if (buffers == NULL)
550      return NULL;
551
552   pdraw->width = *width;
553   pdraw->height = *height;
554   process_buffers(pdraw, buffers, *out_count);
555
556   Xfree(buffers);
557
558   return pdraw->buffers;
559}
560
561#ifdef X_DRI2SwapInterval
562
563static int
564dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
565{
566   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
567   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
568   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
569
570   if (psc->config)
571      psc->config->configQueryi(psc->driScreen,
572				"vblank_mode", &vblank_mode);
573
574   switch (vblank_mode) {
575   case DRI_CONF_VBLANK_NEVER:
576      return GLX_BAD_VALUE;
577   case DRI_CONF_VBLANK_ALWAYS_SYNC:
578      if (interval <= 0)
579	 return GLX_BAD_VALUE;
580      break;
581   default:
582      break;
583   }
584
585   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
586   priv->swap_interval = interval;
587
588   return 0;
589}
590
591static int
592dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
593{
594   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
595
596  return priv->swap_interval;
597}
598
599#endif /* X_DRI2SwapInterval */
600
601static const __DRIdri2LoaderExtension dri2LoaderExtension = {
602   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
603   dri2GetBuffers,
604   dri2FlushFrontBuffer,
605   dri2GetBuffersWithFormat,
606};
607
608static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
609   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
610   dri2GetBuffers,
611   dri2FlushFrontBuffer,
612   NULL,
613};
614
615#ifdef __DRI_USE_INVALIDATE
616static const __DRIuseInvalidateExtension dri2UseInvalidate = {
617   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
618};
619#endif
620
621_X_HIDDEN void
622dri2InvalidateBuffers(Display *dpy, XID drawable)
623{
624   __GLXDRIdrawable *pdraw =
625      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
626   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
627   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
628
629#if __DRI2_FLUSH_VERSION >= 3
630   if (pdraw && psc->f)
631       psc->f->invalidate(pdp->driDrawable);
632#endif
633}
634
635static void
636dri2_bind_tex_image(Display * dpy,
637		    GLXDrawable drawable,
638		    int buffer, const int *attrib_list)
639{
640   GLXContext gc = __glXGetCurrentContext();
641   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
642   __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
643   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
644   struct dri2_display *pdp =
645      (struct dri2_display *) dpyPriv->dri2Display;
646   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
647   struct dri2_context *pcp = (struct dri2_context *) gc->driContext;
648
649   if (pdraw != NULL) {
650
651#if __DRI2_FLUSH_VERSION >= 3
652      if (!pdp->invalidateAvailable && psc->f)
653	 psc->f->invalidate(pdraw->driDrawable);
654#endif
655
656      if (psc->texBuffer->base.version >= 2 &&
657	  psc->texBuffer->setTexBuffer2 != NULL) {
658	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
659					   pdraw->base.textureTarget,
660					   pdraw->base.textureFormat,
661					   pdraw->driDrawable);
662      }
663      else {
664	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
665					  pdraw->base.textureTarget,
666					  pdraw->driDrawable);
667      }
668   }
669}
670
671static void
672dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
673{
674}
675
676static const struct glx_context_vtable dri2_context_vtable = {
677   dri2_wait_gl,
678   dri2_wait_x,
679   DRI_glXUseXFont,
680   dri2_bind_tex_image,
681   dri2_release_tex_image,
682};
683
684static void
685dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
686{
687   int i;
688
689   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
690   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
691   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
692   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
693
694   /* FIXME: if DRI2 version supports it... */
695   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
696
697   for (i = 0; extensions[i]; i++) {
698      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
699	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
700	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
701      }
702
703      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
704	 psc->f = (__DRI2flushExtension *) extensions[i];
705	 /* internal driver extension, no GL extension exposed */
706      }
707
708      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
709	 psc->config = (__DRI2configQueryExtension *) extensions[i];
710   }
711}
712
713
714static __GLXscreenConfigs *
715dri2CreateScreen(int screen, __GLXdisplayPrivate * priv)
716{
717   const __DRIconfig **driver_configs;
718   const __DRIextension **extensions;
719   const struct dri2_display *const pdp = (struct dri2_display *)
720      priv->dri2Display;
721   struct dri2_screen *psc;
722   __GLXDRIscreen *psp;
723   char *driverName, *deviceName;
724   drm_magic_t magic;
725   int i;
726
727   psc = Xmalloc(sizeof *psc);
728   if (psc == NULL)
729      return NULL;
730
731   memset(psc, 0, sizeof *psc);
732   if (!glx_screen_init(&psc->base, screen, priv))
733       return NULL;
734
735   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
736		    &driverName, &deviceName)) {
737      XFree(psc);
738      return NULL;
739   }
740
741   psc->driver = driOpenDriver(driverName);
742   if (psc->driver == NULL) {
743      ErrorMessageF("driver pointer missing\n");
744      goto handle_error;
745   }
746
747   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
748   if (extensions == NULL) {
749      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
750      goto handle_error;
751   }
752
753   for (i = 0; extensions[i]; i++) {
754      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
755	 psc->core = (__DRIcoreExtension *) extensions[i];
756      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
757	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
758   }
759
760   if (psc->core == NULL || psc->dri2 == NULL) {
761      ErrorMessageF("core dri or dri2 extension not found\n");
762      goto handle_error;
763   }
764
765   psc->fd = open(deviceName, O_RDWR);
766   if (psc->fd < 0) {
767      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
768      goto handle_error;
769   }
770
771   if (drmGetMagic(psc->fd, &magic)) {
772      ErrorMessageF("failed to get magic\n");
773      goto handle_error;
774   }
775
776   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
777      ErrorMessageF("failed to authenticate magic %d\n", magic);
778      goto handle_error;
779   }
780
781
782   /* If the server does not support the protocol for
783    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
784    */
785   psc->driScreen =
786      psc->dri2->createNewScreen(screen, psc->fd,
787				 (const __DRIextension **)
788				 &pdp->loader_extensions[0],
789				 &driver_configs, psc);
790
791   if (psc->driScreen == NULL) {
792      ErrorMessageF("failed to create dri screen\n");
793      goto handle_error;
794   }
795
796   extensions = psc->core->getExtensions(psc->driScreen);
797   dri2BindExtensions(psc, extensions);
798
799   psc->base.configs =
800      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
801   psc->base.visuals =
802      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
803
804   psc->driver_configs = driver_configs;
805
806   psp = &psc->vtable;
807   psc->base.driScreen = psp;
808   psp->destroyScreen = dri2DestroyScreen;
809   psp->createContext = dri2CreateContext;
810   psp->createDrawable = dri2CreateDrawable;
811   psp->swapBuffers = dri2SwapBuffers;
812   psp->getDrawableMSC = NULL;
813   psp->waitForMSC = NULL;
814   psp->waitForSBC = NULL;
815   psp->setSwapInterval = NULL;
816   psp->getSwapInterval = NULL;
817
818   if (pdp->driMinor >= 2) {
819#ifdef X_DRI2GetMSC
820      psp->getDrawableMSC = dri2DrawableGetMSC;
821#endif
822#ifdef X_DRI2WaitMSC
823      psp->waitForMSC = dri2WaitForMSC;
824      psp->waitForSBC = dri2WaitForSBC;
825#endif
826#ifdef X_DRI2SwapInterval
827      psp->setSwapInterval = dri2SetSwapInterval;
828      psp->getSwapInterval = dri2GetSwapInterval;
829#endif
830#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
831      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
832#endif
833   }
834
835   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
836    * available.*/
837   psp->copySubBuffer = dri2CopySubBuffer;
838   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
839
840   Xfree(driverName);
841   Xfree(deviceName);
842
843   return &psc->base;
844
845handle_error:
846   Xfree(driverName);
847   Xfree(deviceName);
848   XFree(psc);
849
850   /* FIXME: clean up here */
851
852   return NULL;
853}
854
855/* Called from __glXFreeDisplayPrivate.
856 */
857static void
858dri2DestroyDisplay(__GLXDRIdisplay * dpy)
859{
860   Xfree(dpy);
861}
862
863_X_HIDDEN __GLXDRIdrawable *
864dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
865{
866   __GLXdisplayPrivate *d = __glXInitialize(dpy);
867   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
868   __GLXDRIdrawable *pdraw;
869
870   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
871      return pdraw;
872
873   return NULL;
874}
875
876/*
877 * Allocate, initialize and return a __DRIdisplayPrivate object.
878 * This is called from __glXInitialize() when we are given a new
879 * display pointer.
880 */
881_X_HIDDEN __GLXDRIdisplay *
882dri2CreateDisplay(Display * dpy)
883{
884   struct dri2_display *pdp;
885   int eventBase, errorBase, i;
886
887   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
888      return NULL;
889
890   pdp = Xmalloc(sizeof *pdp);
891   if (pdp == NULL)
892      return NULL;
893
894   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
895      Xfree(pdp);
896      return NULL;
897   }
898
899   pdp->driPatch = 0;
900   pdp->swapAvailable = (pdp->driMinor >= 2);
901   pdp->invalidateAvailable = (pdp->driMinor >= 3);
902
903   pdp->base.destroyDisplay = dri2DestroyDisplay;
904   pdp->base.createScreen = dri2CreateScreen;
905
906   i = 0;
907   if (pdp->driMinor < 1)
908      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
909   else
910      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
911
912   pdp->loader_extensions[i++] = &systemTimeExtension.base;
913
914#ifdef __DRI_USE_INVALIDATE
915   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
916#endif
917   pdp->loader_extensions[i++] = NULL;
918
919   pdp->dri2Hash = __glxHashCreate();
920   if (pdp->dri2Hash == NULL) {
921      Xfree(pdp);
922      return NULL;
923   }
924
925   return &pdp->base;
926}
927
928#endif /* GLX_DIRECT_RENDERING */
929