dri2_glx.c revision 8d0228912bfef173139296a96a097f1a6348c963
1/*
2 * Copyright © 2008 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 *   Kristian Høgsberg (krh@redhat.com)
31 */
32
33#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
34
35#include <X11/Xlib.h>
36#include <X11/extensions/Xfixes.h>
37#include <X11/extensions/Xdamage.h>
38#include "glapi.h"
39#include "glxclient.h"
40#include <X11/extensions/dri2proto.h>
41#include "xf86dri.h"
42#include <dlfcn.h>
43#include <fcntl.h>
44#include <unistd.h>
45#include <sys/types.h>
46#include <sys/mman.h>
47#include "xf86drm.h"
48#include "dri2.h"
49#include "dri_common.h"
50
51/* From xmlpool/options.h, user exposed so should be stable */
52#define DRI_CONF_VBLANK_NEVER 0
53#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
54#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
55#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
56
57#undef DRI2_MINOR
58#define DRI2_MINOR 1
59
60struct dri2_display
61{
62   __GLXDRIdisplay base;
63
64   /*
65    ** XFree86-DRI version information
66    */
67   int driMajor;
68   int driMinor;
69   int driPatch;
70   int swapAvailable;
71   int invalidateAvailable;
72
73   __glxHashTable *dri2Hash;
74
75   const __DRIextension *loader_extensions[4];
76};
77
78struct dri2_screen {
79   __GLXscreenConfigs base;
80
81   __DRIscreen *driScreen;
82   __GLXDRIscreen vtable;
83   const __DRIdri2Extension *dri2;
84   const __DRIcoreExtension *core;
85
86   const __DRI2flushExtension *f;
87   const __DRI2configQueryExtension *config;
88   const __DRItexBufferExtension *texBuffer;
89
90   void *driver;
91   int fd;
92};
93
94struct dri2_context
95{
96   __GLXDRIcontext base;
97   __DRIcontext *driContext;
98   __GLXscreenConfigs *psc;
99};
100
101struct dri2_drawable
102{
103   __GLXDRIdrawable base;
104   __DRIdrawable *driDrawable;
105   __DRIbuffer buffers[5];
106   int bufferCount;
107   int width, height;
108   int have_back;
109   int have_fake_front;
110   int swap_interval;
111};
112
113static void
114dri2DestroyContext(__GLXDRIcontext *context,
115		   __GLXscreenConfigs *base, Display *dpy)
116{
117   struct dri2_context *pcp = (struct dri2_context *) context;
118   struct dri2_screen *psc = (struct dri2_screen *) base;
119
120   (*psc->core->destroyContext) (pcp->driContext);
121
122   Xfree(pcp);
123}
124
125static Bool
126dri2BindContext(__GLXDRIcontext *context,
127		__GLXDRIdrawable *draw, __GLXDRIdrawable *read)
128{
129   struct dri2_context *pcp = (struct dri2_context *) context;
130   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
131   struct dri2_drawable *pdr = (struct dri2_drawable *) draw;
132   struct dri2_drawable *prd = (struct dri2_drawable *) read;
133
134   return (*psc->core->bindContext) (pcp->driContext,
135				     pdr->driDrawable, prd->driDrawable);
136}
137
138static void
139dri2UnbindContext(__GLXDRIcontext *context)
140{
141   struct dri2_context *pcp = (struct dri2_context *) context;
142   struct dri2_screen *psc = (struct dri2_screen *) pcp->psc;
143
144   (*psc->core->unbindContext) (pcp->driContext);
145}
146
147static __GLXDRIcontext *
148dri2CreateContext(__GLXscreenConfigs *base,
149                  const __GLcontextModes * mode,
150                  GLXContext gc, GLXContext shareList, int renderType)
151{
152   struct dri2_context *pcp, *pcp_shared;
153   struct dri2_screen *psc = (struct dri2_screen *) base;
154   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode;
155   __DRIcontext *shared = NULL;
156
157   if (shareList) {
158      pcp_shared = (struct dri2_context *) shareList->driContext;
159      shared = pcp_shared->driContext;
160   }
161
162   pcp = Xmalloc(sizeof *pcp);
163   if (pcp == NULL)
164      return NULL;
165
166   pcp->psc = &psc->base;
167   pcp->driContext =
168      (*psc->dri2->createNewContext) (psc->driScreen,
169                                      config->driConfig, shared, pcp);
170   gc->__driContext = pcp->driContext;
171
172   if (pcp->driContext == NULL) {
173      Xfree(pcp);
174      return NULL;
175   }
176
177   pcp->base.destroyContext = dri2DestroyContext;
178   pcp->base.bindContext = dri2BindContext;
179   pcp->base.unbindContext = dri2UnbindContext;
180
181   return &pcp->base;
182}
183
184static void
185dri2DestroyDrawable(__GLXDRIdrawable *base)
186{
187   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
188   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
189   __GLXdisplayPrivate *dpyPriv;
190   struct dri2_display *pdp;
191
192   dpyPriv = __glXInitialize(base->psc->dpy);
193   pdp = (struct dri2_display *)dpyPriv->dri2Display;
194
195   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
196   (*psc->core->destroyDrawable) (pdraw->driDrawable);
197   DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
198   Xfree(pdraw);
199}
200
201static __GLXDRIdrawable *
202dri2CreateDrawable(__GLXscreenConfigs *base, XID xDrawable,
203		   GLXDrawable drawable, const __GLcontextModes * modes)
204{
205   struct dri2_drawable *pdraw;
206   struct dri2_screen *psc = (struct dri2_screen *) base;
207   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
208   __GLXdisplayPrivate *dpyPriv;
209   struct dri2_display *pdp;
210   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
211
212   pdraw = Xmalloc(sizeof(*pdraw));
213   if (!pdraw)
214      return NULL;
215
216   pdraw->base.destroyDrawable = dri2DestroyDrawable;
217   pdraw->base.xDrawable = xDrawable;
218   pdraw->base.drawable = drawable;
219   pdraw->base.psc = &psc->base;
220   pdraw->bufferCount = 0;
221   pdraw->swap_interval = 1; /* default may be overridden below */
222   pdraw->have_back = 0;
223
224   if (psc->config)
225      psc->config->configQueryi(psc->driScreen,
226				"vblank_mode", &vblank_mode);
227
228   switch (vblank_mode) {
229   case DRI_CONF_VBLANK_NEVER:
230   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
231      pdraw->swap_interval = 0;
232      break;
233   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
234   case DRI_CONF_VBLANK_ALWAYS_SYNC:
235   default:
236      pdraw->swap_interval = 1;
237      break;
238   }
239
240   DRI2CreateDrawable(psc->base.dpy, xDrawable);
241
242   dpyPriv = __glXInitialize(psc->base.dpy);
243   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
244   /* Create a new drawable */
245   pdraw->driDrawable =
246      (*psc->dri2->createNewDrawable) (psc->driScreen,
247                                       config->driConfig, pdraw);
248
249   if (!pdraw->driDrawable) {
250      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
251      Xfree(pdraw);
252      return NULL;
253   }
254
255   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
256      (*psc->core->destroyDrawable) (pdraw->driDrawable);
257      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
258      Xfree(pdraw);
259      return None;
260   }
261
262
263#ifdef X_DRI2SwapInterval
264   /*
265    * Make sure server has the same swap interval we do for the new
266    * drawable.
267    */
268   if (pdp->swapAvailable)
269      DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
270#endif
271
272   return &pdraw->base;
273}
274
275#ifdef X_DRI2GetMSC
276
277static int
278dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw,
279		   int64_t *ust, int64_t *msc, int64_t *sbc)
280{
281   CARD64 dri2_ust, dri2_msc, dri2_sbc;
282   int ret;
283
284   ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
285		    &dri2_ust, &dri2_msc, &dri2_sbc);
286   *ust = dri2_ust;
287   *msc = dri2_msc;
288   *sbc = dri2_sbc;
289
290   return ret;
291}
292
293#endif
294
295
296#ifdef X_DRI2WaitMSC
297
298static int
299dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
300	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
301{
302   CARD64 dri2_ust, dri2_msc, dri2_sbc;
303   int ret;
304
305   ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
306		     remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
307   *ust = dri2_ust;
308   *msc = dri2_msc;
309   *sbc = dri2_sbc;
310
311   return ret;
312}
313
314static int
315dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
316	       int64_t *msc, int64_t *sbc)
317{
318   CARD64 dri2_ust, dri2_msc, dri2_sbc;
319   int ret;
320
321   ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
322		     target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
323   *ust = dri2_ust;
324   *msc = dri2_msc;
325   *sbc = dri2_sbc;
326
327   return ret;
328}
329
330#endif /* X_DRI2WaitMSC */
331
332static void
333dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height)
334{
335   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
336   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
337   XRectangle xrect;
338   XserverRegion region;
339
340   /* Check we have the right attachments */
341   if (!priv->have_back)
342      return;
343
344   xrect.x = x;
345   xrect.y = priv->height - y - height;
346   xrect.width = width;
347   xrect.height = height;
348
349#ifdef __DRI2_FLUSH
350   if (psc->f)
351      (*psc->f->flush) (priv->driDrawable);
352#endif
353
354   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
355   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
356                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
357   XFixesDestroyRegion(psc->base.dpy, region);
358
359   /* Refresh the fake front (if present) after we just damaged the real
360    * front.
361    */
362   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
363		  DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
364   XFixesDestroyRegion(psc->base.dpy, region);
365}
366
367static void
368dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
369{
370   XRectangle xrect;
371   XserverRegion region;
372   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
373
374   xrect.x = 0;
375   xrect.y = 0;
376   xrect.width = priv->width;
377   xrect.height = priv->height;
378
379#ifdef __DRI2_FLUSH
380   if (psc->f)
381      (*psc->f->flush) (priv->driDrawable);
382#endif
383
384   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
385   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
386   XFixesDestroyRegion(psc->base.dpy, region);
387
388}
389
390static void
391dri2WaitX(__GLXDRIdrawable *pdraw)
392{
393   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
394
395   if (!priv->have_fake_front)
396      return;
397
398   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
399}
400
401static void
402dri2WaitGL(__GLXDRIdrawable * pdraw)
403{
404   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
405
406   if (!priv->have_fake_front)
407      return;
408
409   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
410}
411
412static void
413dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
414{
415   struct dri2_drawable *pdraw = loaderPrivate;
416   __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy);
417   struct dri2_display *pdp = (struct dri2_display *)priv->dri2Display;
418
419   /* Old servers don't send invalidate events */
420   if (!pdp->invalidateAvailable)
421       dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable);
422
423   dri2WaitGL(loaderPrivate);
424}
425
426
427static void
428dri2DestroyScreen(__GLXscreenConfigs *base)
429{
430   struct dri2_screen *psc = (struct dri2_screen *) base;
431
432   /* Free the direct rendering per screen data */
433   (*psc->core->destroyScreen) (psc->driScreen);
434   close(psc->fd);
435   Xfree(psc);
436}
437
438/**
439 * Process list of buffer received from the server
440 *
441 * Processes the list of buffers received in a reply from the server to either
442 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
443 */
444static void
445process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
446                unsigned count)
447{
448   int i;
449
450   pdraw->bufferCount = count;
451   pdraw->have_fake_front = 0;
452   pdraw->have_back = 0;
453
454   /* This assumes the DRI2 buffer attachment tokens matches the
455    * __DRIbuffer tokens. */
456   for (i = 0; i < count; i++) {
457      pdraw->buffers[i].attachment = buffers[i].attachment;
458      pdraw->buffers[i].name = buffers[i].name;
459      pdraw->buffers[i].pitch = buffers[i].pitch;
460      pdraw->buffers[i].cpp = buffers[i].cpp;
461      pdraw->buffers[i].flags = buffers[i].flags;
462      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
463         pdraw->have_fake_front = 1;
464      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
465         pdraw->have_back = 1;
466   }
467
468}
469
470static int64_t
471dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
472		int64_t remainder)
473{
474    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
475    __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy);
476    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
477    struct dri2_display *pdp =
478	(struct dri2_display *)dpyPriv->dri2Display;
479    CARD64 ret;
480
481#ifdef __DRI2_FLUSH
482    if (psc->f)
483    	(*psc->f->flush)(priv->driDrawable);
484#endif
485
486    /* Old servers don't send invalidate events */
487    if (!pdp->invalidateAvailable)
488       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable);
489
490    /* Old servers can't handle swapbuffers */
491    if (!pdp->swapAvailable) {
492       dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height);
493       return 0;
494    }
495
496#ifdef X_DRI2SwapBuffers
497    DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor,
498		    remainder, &ret);
499#endif
500
501    return ret;
502}
503
504static __DRIbuffer *
505dri2GetBuffers(__DRIdrawable * driDrawable,
506               int *width, int *height,
507               unsigned int *attachments, int count,
508               int *out_count, void *loaderPrivate)
509{
510   struct dri2_drawable *pdraw = loaderPrivate;
511   DRI2Buffer *buffers;
512
513   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
514                            width, height, attachments, count, out_count);
515   if (buffers == NULL)
516      return NULL;
517
518   pdraw->width = *width;
519   pdraw->height = *height;
520   process_buffers(pdraw, buffers, *out_count);
521
522   Xfree(buffers);
523
524   return pdraw->buffers;
525}
526
527static __DRIbuffer *
528dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
529                         int *width, int *height,
530                         unsigned int *attachments, int count,
531                         int *out_count, void *loaderPrivate)
532{
533   struct dri2_drawable *pdraw = loaderPrivate;
534   DRI2Buffer *buffers;
535
536   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
537                                      pdraw->base.xDrawable,
538                                      width, height, attachments,
539                                      count, out_count);
540   if (buffers == NULL)
541      return NULL;
542
543   pdraw->width = *width;
544   pdraw->height = *height;
545   process_buffers(pdraw, buffers, *out_count);
546
547   Xfree(buffers);
548
549   return pdraw->buffers;
550}
551
552#ifdef X_DRI2SwapInterval
553
554static int
555dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
556{
557   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
558   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
559   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
560
561   if (psc->config)
562      psc->config->configQueryi(psc->driScreen,
563				"vblank_mode", &vblank_mode);
564
565   switch (vblank_mode) {
566   case DRI_CONF_VBLANK_NEVER:
567      return GLX_BAD_VALUE;
568   case DRI_CONF_VBLANK_ALWAYS_SYNC:
569      if (interval <= 0)
570	 return GLX_BAD_VALUE;
571      break;
572   default:
573      break;
574   }
575
576   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
577   priv->swap_interval = interval;
578
579   return 0;
580}
581
582static int
583dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
584{
585   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
586
587  return priv->swap_interval;
588}
589
590#endif /* X_DRI2SwapInterval */
591
592static const __DRIdri2LoaderExtension dri2LoaderExtension = {
593   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
594   dri2GetBuffers,
595   dri2FlushFrontBuffer,
596   dri2GetBuffersWithFormat,
597};
598
599static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
600   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
601   dri2GetBuffers,
602   dri2FlushFrontBuffer,
603   NULL,
604};
605
606#ifdef __DRI_USE_INVALIDATE
607static const __DRIuseInvalidateExtension dri2UseInvalidate = {
608   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
609};
610#endif
611
612_X_HIDDEN void
613dri2InvalidateBuffers(Display *dpy, XID drawable)
614{
615   __GLXDRIdrawable *pdraw =
616      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
617   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
618   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
619
620#if __DRI2_FLUSH_VERSION >= 3
621   if (pdraw && psc->f)
622       psc->f->invalidate(pdp->driDrawable);
623#endif
624}
625
626static void
627dri2_bind_tex_image(Display * dpy,
628		    GLXDrawable drawable,
629		    int buffer, const int *attrib_list)
630{
631   GLXContext gc = __glXGetCurrentContext();
632   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable, NULL);
633   __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy);
634   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
635   struct dri2_display *pdp =
636      (struct dri2_display *) dpyPriv->dri2Display;
637   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
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) (gc->__driContext,
649					   pdraw->base.textureTarget,
650					   pdraw->base.textureFormat,
651					   pdraw->driDrawable);
652      }
653      else {
654	 (*psc->texBuffer->setTexBuffer) (gc->__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
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   driBindCommonExtensions(&psc->base, extensions);
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->base.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