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