dri2_glx.c revision a7292f2920a28a190ca39ce530454a852ec36d59
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   gc->__driContext = pcp->driContext;
172
173   if (pcp->driContext == NULL) {
174      Xfree(pcp);
175      return NULL;
176   }
177
178   pcp->base.destroyContext = dri2DestroyContext;
179   pcp->base.bindContext = dri2BindContext;
180   pcp->base.unbindContext = dri2UnbindContext;
181
182   return &pcp->base;
183}
184
185static void
186dri2DestroyDrawable(__GLXDRIdrawable *base)
187{
188   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
189   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
190   __GLXdisplayPrivate *dpyPriv = psc->base.display;
191   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
192
193   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
194   (*psc->core->destroyDrawable) (pdraw->driDrawable);
195   DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
196   Xfree(pdraw);
197}
198
199static __GLXDRIdrawable *
200dri2CreateDrawable(__GLXscreenConfigs *base, XID xDrawable,
201		   GLXDrawable drawable, const __GLcontextModes * modes)
202{
203   struct dri2_drawable *pdraw;
204   struct dri2_screen *psc = (struct dri2_screen *) base;
205   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
206   __GLXdisplayPrivate *dpyPriv;
207   struct dri2_display *pdp;
208   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
209
210   pdraw = Xmalloc(sizeof(*pdraw));
211   if (!pdraw)
212      return NULL;
213
214   pdraw->base.destroyDrawable = dri2DestroyDrawable;
215   pdraw->base.xDrawable = xDrawable;
216   pdraw->base.drawable = drawable;
217   pdraw->base.psc = &psc->base;
218   pdraw->bufferCount = 0;
219   pdraw->swap_interval = 1; /* default may be overridden below */
220   pdraw->have_back = 0;
221
222   if (psc->config)
223      psc->config->configQueryi(psc->driScreen,
224				"vblank_mode", &vblank_mode);
225
226   switch (vblank_mode) {
227   case DRI_CONF_VBLANK_NEVER:
228   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
229      pdraw->swap_interval = 0;
230      break;
231   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
232   case DRI_CONF_VBLANK_ALWAYS_SYNC:
233   default:
234      pdraw->swap_interval = 1;
235      break;
236   }
237
238   DRI2CreateDrawable(psc->base.dpy, xDrawable);
239
240   dpyPriv = __glXInitialize(psc->base.dpy);
241   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
242   /* Create a new drawable */
243   pdraw->driDrawable =
244      (*psc->dri2->createNewDrawable) (psc->driScreen,
245                                       config->driConfig, pdraw);
246
247   if (!pdraw->driDrawable) {
248      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
249      Xfree(pdraw);
250      return NULL;
251   }
252
253   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
254      (*psc->core->destroyDrawable) (pdraw->driDrawable);
255      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
256      Xfree(pdraw);
257      return None;
258   }
259
260
261#ifdef X_DRI2SwapInterval
262   /*
263    * Make sure server has the same swap interval we do for the new
264    * drawable.
265    */
266   if (pdp->swapAvailable)
267      DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
268#endif
269
270   return &pdraw->base;
271}
272
273#ifdef X_DRI2GetMSC
274
275static int
276dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw,
277		   int64_t *ust, int64_t *msc, int64_t *sbc)
278{
279   CARD64 dri2_ust, dri2_msc, dri2_sbc;
280   int ret;
281
282   ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
283		    &dri2_ust, &dri2_msc, &dri2_sbc);
284   *ust = dri2_ust;
285   *msc = dri2_msc;
286   *sbc = dri2_sbc;
287
288   return ret;
289}
290
291#endif
292
293
294#ifdef X_DRI2WaitMSC
295
296static int
297dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
298	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
299{
300   CARD64 dri2_ust, dri2_msc, dri2_sbc;
301   int ret;
302
303   ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
304		     remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
305   *ust = dri2_ust;
306   *msc = dri2_msc;
307   *sbc = dri2_sbc;
308
309   return ret;
310}
311
312static int
313dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
314	       int64_t *msc, int64_t *sbc)
315{
316   CARD64 dri2_ust, dri2_msc, dri2_sbc;
317   int ret;
318
319   ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
320		     target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
321   *ust = dri2_ust;
322   *msc = dri2_msc;
323   *sbc = dri2_sbc;
324
325   return ret;
326}
327
328#endif /* X_DRI2WaitMSC */
329
330static void
331dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height)
332{
333   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
334   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
335   XRectangle xrect;
336   XserverRegion region;
337
338   /* Check we have the right attachments */
339   if (!priv->have_back)
340      return;
341
342   xrect.x = x;
343   xrect.y = priv->height - y - height;
344   xrect.width = width;
345   xrect.height = height;
346
347#ifdef __DRI2_FLUSH
348   if (psc->f)
349      (*psc->f->flush) (priv->driDrawable);
350#endif
351
352   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
353   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
354                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
355   XFixesDestroyRegion(psc->base.dpy, region);
356
357   /* Refresh the fake front (if present) after we just damaged the real
358    * front.
359    */
360   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
361		  DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
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
638   if (pdraw != NULL) {
639
640#if __DRI2_FLUSH_VERSION >= 3
641      if (!pdp->invalidateAvailable && psc->f)
642	 psc->f->invalidate(pdraw->driDrawable);
643#endif
644
645      if (psc->texBuffer->base.version >= 2 &&
646	  psc->texBuffer->setTexBuffer2 != NULL) {
647	 (*psc->texBuffer->setTexBuffer2) (gc->__driContext,
648					   pdraw->base.textureTarget,
649					   pdraw->base.textureFormat,
650					   pdraw->driDrawable);
651      }
652      else {
653	 (*psc->texBuffer->setTexBuffer) (gc->__driContext,
654					  pdraw->base.textureTarget,
655					  pdraw->driDrawable);
656      }
657   }
658}
659
660static void
661dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
662{
663}
664
665static const struct glx_context_vtable dri2_context_vtable = {
666   dri2_bind_tex_image,
667   dri2_release_tex_image,
668};
669
670static void
671dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
672{
673   int i;
674
675   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
676   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
677   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
678   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
679
680   /* FIXME: if DRI2 version supports it... */
681   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
682
683   for (i = 0; extensions[i]; i++) {
684      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
685	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
686	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
687      }
688
689      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
690	 psc->f = (__DRI2flushExtension *) extensions[i];
691	 /* internal driver extension, no GL extension exposed */
692      }
693
694      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
695	 psc->config = (__DRI2configQueryExtension *) extensions[i];
696   }
697}
698
699
700static __GLXscreenConfigs *
701dri2CreateScreen(int screen, __GLXdisplayPrivate * priv)
702{
703   const __DRIconfig **driver_configs;
704   const __DRIextension **extensions;
705   const struct dri2_display *const pdp = (struct dri2_display *)
706      priv->dri2Display;
707   struct dri2_screen *psc;
708   __GLXDRIscreen *psp;
709   char *driverName, *deviceName;
710   drm_magic_t magic;
711   int i;
712
713   psc = Xmalloc(sizeof *psc);
714   if (psc == NULL)
715      return NULL;
716
717   memset(psc, 0, sizeof *psc);
718   if (!glx_screen_init(&psc->base, screen, priv))
719       return NULL;
720
721   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
722		    &driverName, &deviceName)) {
723      XFree(psc);
724      return NULL;
725   }
726
727   psc->driver = driOpenDriver(driverName);
728   if (psc->driver == NULL) {
729      ErrorMessageF("driver pointer missing\n");
730      goto handle_error;
731   }
732
733   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
734   if (extensions == NULL) {
735      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
736      goto handle_error;
737   }
738
739   for (i = 0; extensions[i]; i++) {
740      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
741	 psc->core = (__DRIcoreExtension *) extensions[i];
742      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
743	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
744   }
745
746   if (psc->core == NULL || psc->dri2 == NULL) {
747      ErrorMessageF("core dri or dri2 extension not found\n");
748      goto handle_error;
749   }
750
751   psc->fd = open(deviceName, O_RDWR);
752   if (psc->fd < 0) {
753      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
754      goto handle_error;
755   }
756
757   if (drmGetMagic(psc->fd, &magic)) {
758      ErrorMessageF("failed to get magic\n");
759      goto handle_error;
760   }
761
762   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
763      ErrorMessageF("failed to authenticate magic %d\n", magic);
764      goto handle_error;
765   }
766
767
768   /* If the server does not support the protocol for
769    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
770    */
771   psc->driScreen =
772      psc->dri2->createNewScreen(screen, psc->fd,
773				 (const __DRIextension **)
774				 &pdp->loader_extensions[0],
775				 &driver_configs, psc);
776
777   if (psc->driScreen == NULL) {
778      ErrorMessageF("failed to create dri screen\n");
779      goto handle_error;
780   }
781
782   extensions = psc->core->getExtensions(psc->driScreen);
783   dri2BindExtensions(psc, extensions);
784
785   psc->base.configs =
786      driConvertConfigs(psc->core, psc->base.configs, driver_configs);
787   psc->base.visuals =
788      driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
789
790   psc->driver_configs = driver_configs;
791
792   psp = &psc->vtable;
793   psc->base.driScreen = psp;
794   psp->destroyScreen = dri2DestroyScreen;
795   psp->createContext = dri2CreateContext;
796   psp->createDrawable = dri2CreateDrawable;
797   psp->swapBuffers = dri2SwapBuffers;
798   psp->waitGL = dri2WaitGL;
799   psp->waitX = dri2WaitX;
800   psp->getDrawableMSC = NULL;
801   psp->waitForMSC = NULL;
802   psp->waitForSBC = NULL;
803   psp->setSwapInterval = NULL;
804   psp->getSwapInterval = NULL;
805
806   if (pdp->driMinor >= 2) {
807#ifdef X_DRI2GetMSC
808      psp->getDrawableMSC = dri2DrawableGetMSC;
809#endif
810#ifdef X_DRI2WaitMSC
811      psp->waitForMSC = dri2WaitForMSC;
812      psp->waitForSBC = dri2WaitForSBC;
813#endif
814#ifdef X_DRI2SwapInterval
815      psp->setSwapInterval = dri2SetSwapInterval;
816      psp->getSwapInterval = dri2GetSwapInterval;
817#endif
818#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
819      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
820#endif
821   }
822
823   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
824    * available.*/
825   psp->copySubBuffer = dri2CopySubBuffer;
826   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
827
828   psc->base.direct_context_vtable = &dri2_context_vtable;
829
830   Xfree(driverName);
831   Xfree(deviceName);
832
833   return &psc->base;
834
835handle_error:
836   Xfree(driverName);
837   Xfree(deviceName);
838   XFree(psc);
839
840   /* FIXME: clean up here */
841
842   return NULL;
843}
844
845/* Called from __glXFreeDisplayPrivate.
846 */
847static void
848dri2DestroyDisplay(__GLXDRIdisplay * dpy)
849{
850   Xfree(dpy);
851}
852
853_X_HIDDEN __GLXDRIdrawable *
854dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
855{
856   __GLXdisplayPrivate *d = __glXInitialize(dpy);
857   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
858   __GLXDRIdrawable *pdraw;
859
860   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
861      return pdraw;
862
863   return NULL;
864}
865
866/*
867 * Allocate, initialize and return a __DRIdisplayPrivate object.
868 * This is called from __glXInitialize() when we are given a new
869 * display pointer.
870 */
871_X_HIDDEN __GLXDRIdisplay *
872dri2CreateDisplay(Display * dpy)
873{
874   struct dri2_display *pdp;
875   int eventBase, errorBase, i;
876
877   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
878      return NULL;
879
880   pdp = Xmalloc(sizeof *pdp);
881   if (pdp == NULL)
882      return NULL;
883
884   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
885      Xfree(pdp);
886      return NULL;
887   }
888
889   pdp->driPatch = 0;
890   pdp->swapAvailable = (pdp->driMinor >= 2);
891   pdp->invalidateAvailable = (pdp->driMinor >= 3);
892
893   pdp->base.destroyDisplay = dri2DestroyDisplay;
894   pdp->base.createScreen = dri2CreateScreen;
895
896   i = 0;
897   if (pdp->driMinor < 1)
898      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
899   else
900      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
901
902   pdp->loader_extensions[i++] = &systemTimeExtension.base;
903
904#ifdef __DRI_USE_INVALIDATE
905   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
906#endif
907   pdp->loader_extensions[i++] = NULL;
908
909   pdp->dri2Hash = __glxHashCreate();
910   if (pdp->dri2Hash == NULL) {
911      Xfree(pdp);
912      return NULL;
913   }
914
915   return &pdp->base;
916}
917
918#endif /* GLX_DIRECT_RENDERING */
919