dri2_glx.c revision 6c9af977401ff986964d678f8870eee23c504077
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 "glapi.h"
38#include "glxclient.h"
39#include <X11/extensions/dri2proto.h>
40#include "xf86dri.h"
41#include <dlfcn.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <sys/types.h>
45#include <sys/mman.h>
46#include <sys/time.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   struct glx_screen 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 __DRI2throttleExtension *throttle;
90   const __DRIconfig **driver_configs;
91
92   void *driver;
93   int fd;
94
95   Bool show_fps;
96};
97
98struct dri2_context
99{
100   struct glx_context base;
101   __DRIcontext *driContext;
102};
103
104struct dri2_drawable
105{
106   __GLXDRIdrawable base;
107   __DRIdrawable *driDrawable;
108   __DRIbuffer buffers[5];
109   int bufferCount;
110   int width, height;
111   int have_back;
112   int have_fake_front;
113   int swap_interval;
114
115   double previous_time;
116   unsigned frames;
117};
118
119static const struct glx_context_vtable dri2_context_vtable;
120
121static void
122dri2_destroy_context(struct glx_context *context)
123{
124   struct dri2_context *pcp = (struct dri2_context *) context;
125   struct dri2_screen *psc = (struct dri2_screen *) context->psc;
126
127   driReleaseDrawables(&pcp->base);
128
129   if (context->extensions)
130      XFree((char *) context->extensions);
131
132   (*psc->core->destroyContext) (pcp->driContext);
133
134   Xfree(pcp);
135}
136
137static Bool
138dri2_bind_context(struct glx_context *context, struct glx_context *old,
139		  GLXDrawable draw, GLXDrawable read)
140{
141   struct dri2_context *pcp = (struct dri2_context *) context;
142   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
143   struct dri2_drawable *pdraw, *pread;
144   struct dri2_display *pdp;
145
146   pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
147   pread = (struct dri2_drawable *) driFetchDrawable(context, read);
148
149   driReleaseDrawables(&pcp->base);
150
151   if (pdraw == NULL || pread == NULL)
152      return GLXBadDrawable;
153
154   if (!(*psc->core->bindContext) (pcp->driContext,
155				   pdraw->driDrawable, pread->driDrawable))
156      return GLXBadContext;
157
158   /* If the server doesn't send invalidate events, we may miss a
159    * resize before the rendering starts.  Invalidate the buffers now
160    * so the driver will recheck before rendering starts. */
161   pdp = (struct dri2_display *) psc->base.display;
162   if (!pdp->invalidateAvailable) {
163      dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable);
164      if (pread != pdraw)
165	 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable);
166   }
167
168   return Success;
169}
170
171static void
172dri2_unbind_context(struct glx_context *context, struct glx_context *new)
173{
174   struct dri2_context *pcp = (struct dri2_context *) context;
175   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
176
177   (*psc->core->unbindContext) (pcp->driContext);
178}
179
180static struct glx_context *
181dri2_create_context(struct glx_screen *base,
182		    struct glx_config *config_base,
183		    struct glx_context *shareList, int renderType)
184{
185   struct dri2_context *pcp, *pcp_shared;
186   struct dri2_screen *psc = (struct dri2_screen *) base;
187   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
188   __DRIcontext *shared = NULL;
189
190   if (shareList) {
191      /* If the shareList context is not a DRI2 context, we cannot possibly
192       * create a DRI2 context that shares it.
193       */
194      if (shareList->vtable->destroy != dri2_destroy_context) {
195	 return NULL;
196      }
197
198      pcp_shared = (struct dri2_context *) shareList;
199      shared = pcp_shared->driContext;
200   }
201
202   pcp = Xmalloc(sizeof *pcp);
203   if (pcp == NULL)
204      return NULL;
205
206   memset(pcp, 0, sizeof *pcp);
207   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
208      Xfree(pcp);
209      return NULL;
210   }
211
212   pcp->driContext =
213      (*psc->dri2->createNewContext) (psc->driScreen,
214                                      config->driConfig, shared, pcp);
215
216   if (pcp->driContext == NULL) {
217      Xfree(pcp);
218      return NULL;
219   }
220
221   pcp->base.vtable = &dri2_context_vtable;
222
223   return &pcp->base;
224}
225
226static struct glx_context *
227dri2_create_context_attribs(struct glx_screen *base,
228			    struct glx_config *config_base,
229			    struct glx_context *shareList,
230			    unsigned num_attribs,
231			    const uint32_t *attribs,
232			    unsigned *error)
233{
234   struct dri2_context *pcp = NULL;
235   struct dri2_context *pcp_shared = NULL;
236   struct dri2_screen *psc = (struct dri2_screen *) base;
237   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
238   __DRIcontext *shared = NULL;
239
240   uint32_t minor_ver = 1;
241   uint32_t major_ver = 2;
242   uint32_t flags = 0;
243   unsigned api;
244   uint32_t ctx_attribs[2 * 4];
245   unsigned num_ctx_attribs = 0;
246
247   if (psc->dri2->base.version < 3) {
248      *error = __DRI_CTX_ERROR_NO_MEMORY;
249      goto error_exit;
250   }
251
252   /* Remap the GLX tokens to DRI2 tokens.
253    */
254   if (!dri2_convert_glx_attribs(num_attribs, attribs,
255				 &major_ver, &minor_ver, &flags, &api, error))
256      goto error_exit;
257
258   if (shareList) {
259      pcp_shared = (struct dri2_context *) shareList;
260      shared = pcp_shared->driContext;
261   }
262
263   pcp = Xmalloc(sizeof *pcp);
264   if (pcp == NULL) {
265      *error = __DRI_CTX_ERROR_NO_MEMORY;
266      goto error_exit;
267   }
268
269   memset(pcp, 0, sizeof *pcp);
270   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
271      goto error_exit;
272
273   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
274   ctx_attribs[num_ctx_attribs++] = major_ver;
275   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
276   ctx_attribs[num_ctx_attribs++] = minor_ver;
277
278   if (flags != 0) {
279      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
280
281      /* The current __DRI_CTX_FLAG_* values are identical to the
282       * GLX_CONTEXT_*_BIT values.
283       */
284      ctx_attribs[num_ctx_attribs++] = flags;
285   }
286
287   pcp->driContext =
288      (*psc->dri2->createContextAttribs) (psc->driScreen,
289					  api,
290					  config->driConfig,
291					  shared,
292					  num_ctx_attribs / 2,
293					  ctx_attribs,
294					  error,
295					  pcp);
296
297   if (pcp->driContext == NULL)
298      goto error_exit;
299
300   pcp->base.vtable = &dri2_context_vtable;
301
302   return &pcp->base;
303
304error_exit:
305   if (pcp != NULL)
306      Xfree(pcp);
307
308   return NULL;
309}
310
311static void
312dri2DestroyDrawable(__GLXDRIdrawable *base)
313{
314   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
315   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
316   struct glx_display *dpyPriv = psc->base.display;
317   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
318
319   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
320   (*psc->core->destroyDrawable) (pdraw->driDrawable);
321
322   /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
323    * now, as the application explicitly asked to destroy the GLX
324    * drawable.  Otherwise, for legacy drawables, we let the DRI2
325    * drawable linger on the server, since there's no good way of
326    * knowing when the application is done with it.  The server will
327    * destroy the DRI2 drawable when it destroys the X drawable or the
328    * client exits anyway. */
329   if (pdraw->base.xDrawable != pdraw->base.drawable)
330      DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
331
332   Xfree(pdraw);
333}
334
335static __GLXDRIdrawable *
336dri2CreateDrawable(struct glx_screen *base, XID xDrawable,
337		   GLXDrawable drawable, struct glx_config *config_base)
338{
339   struct dri2_drawable *pdraw;
340   struct dri2_screen *psc = (struct dri2_screen *) base;
341   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
342   struct glx_display *dpyPriv;
343   struct dri2_display *pdp;
344   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
345
346   pdraw = Xmalloc(sizeof(*pdraw));
347   if (!pdraw)
348      return NULL;
349
350   memset(pdraw, 0, sizeof *pdraw);
351   pdraw->base.destroyDrawable = dri2DestroyDrawable;
352   pdraw->base.xDrawable = xDrawable;
353   pdraw->base.drawable = drawable;
354   pdraw->base.psc = &psc->base;
355   pdraw->bufferCount = 0;
356   pdraw->swap_interval = 1; /* default may be overridden below */
357   pdraw->have_back = 0;
358
359   if (psc->config)
360      psc->config->configQueryi(psc->driScreen,
361				"vblank_mode", &vblank_mode);
362
363   switch (vblank_mode) {
364   case DRI_CONF_VBLANK_NEVER:
365   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
366      pdraw->swap_interval = 0;
367      break;
368   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
369   case DRI_CONF_VBLANK_ALWAYS_SYNC:
370   default:
371      pdraw->swap_interval = 1;
372      break;
373   }
374
375   DRI2CreateDrawable(psc->base.dpy, xDrawable);
376
377   dpyPriv = __glXInitialize(psc->base.dpy);
378   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
379   /* Create a new drawable */
380   pdraw->driDrawable =
381      (*psc->dri2->createNewDrawable) (psc->driScreen,
382                                       config->driConfig, pdraw);
383
384   if (!pdraw->driDrawable) {
385      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
386      Xfree(pdraw);
387      return NULL;
388   }
389
390   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
391      (*psc->core->destroyDrawable) (pdraw->driDrawable);
392      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
393      Xfree(pdraw);
394      return None;
395   }
396
397
398#ifdef X_DRI2SwapInterval
399   /*
400    * Make sure server has the same swap interval we do for the new
401    * drawable.
402    */
403   if (pdp->swapAvailable)
404      DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval);
405#endif
406
407   return &pdraw->base;
408}
409
410#ifdef X_DRI2GetMSC
411
412static int
413dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
414		   int64_t *ust, int64_t *msc, int64_t *sbc)
415{
416   CARD64 dri2_ust, dri2_msc, dri2_sbc;
417   int ret;
418
419   ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable,
420		    &dri2_ust, &dri2_msc, &dri2_sbc);
421   *ust = dri2_ust;
422   *msc = dri2_msc;
423   *sbc = dri2_sbc;
424
425   return ret;
426}
427
428#endif
429
430
431#ifdef X_DRI2WaitMSC
432
433static int
434dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
435	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
436{
437   CARD64 dri2_ust, dri2_msc, dri2_sbc;
438   int ret;
439
440   ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor,
441		     remainder, &dri2_ust, &dri2_msc, &dri2_sbc);
442   *ust = dri2_ust;
443   *msc = dri2_msc;
444   *sbc = dri2_sbc;
445
446   return ret;
447}
448
449static int
450dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
451	       int64_t *msc, int64_t *sbc)
452{
453   CARD64 dri2_ust, dri2_msc, dri2_sbc;
454   int ret;
455
456   ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable,
457		     target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc);
458   *ust = dri2_ust;
459   *msc = dri2_msc;
460   *sbc = dri2_sbc;
461
462   return ret;
463}
464
465#endif /* X_DRI2WaitMSC */
466
467/**
468 * dri2Throttle - Request driver throttling
469 *
470 * This function uses the DRI2 throttle extension to give the
471 * driver the opportunity to throttle on flush front, copysubbuffer
472 * and swapbuffers.
473 */
474static void
475dri2Throttle(struct dri2_screen *psc,
476	     struct dri2_drawable *draw,
477	     enum __DRI2throttleReason reason)
478{
479   if (psc->throttle) {
480      struct glx_context *gc = __glXGetCurrentContext();
481      struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
482      __DRIcontext *ctx =
483	 (dri2Ctx) ? dri2Ctx->driContext : NULL;
484
485      psc->throttle->throttle(ctx, draw->driDrawable, reason);
486   }
487}
488
489static void
490__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
491		    int width, int height,
492		    enum __DRI2throttleReason reason)
493{
494   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
495   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
496   XRectangle xrect;
497   XserverRegion region;
498
499   /* Check we have the right attachments */
500   if (!priv->have_back)
501      return;
502
503   xrect.x = x;
504   xrect.y = priv->height - y - height;
505   xrect.width = width;
506   xrect.height = height;
507
508#ifdef __DRI2_FLUSH
509   if (psc->f)
510      (*psc->f->flush) (priv->driDrawable);
511#endif
512
513   dri2Throttle(psc, priv, reason);
514
515   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
516   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
517                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
518
519   /* Refresh the fake front (if present) after we just damaged the real
520    * front.
521    */
522   if (priv->have_fake_front)
523      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
524		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
525
526   XFixesDestroyRegion(psc->base.dpy, region);
527}
528
529static void
530dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
531		  int width, int height)
532{
533   __dri2CopySubBuffer(pdraw, x, y, width, height,
534		       __DRI2_THROTTLE_COPYSUBBUFFER);
535}
536
537
538static void
539dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
540{
541   XRectangle xrect;
542   XserverRegion region;
543   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
544
545   xrect.x = 0;
546   xrect.y = 0;
547   xrect.width = priv->width;
548   xrect.height = priv->height;
549
550#ifdef __DRI2_FLUSH
551   if (psc->f)
552      (*psc->f->flush) (priv->driDrawable);
553#endif
554
555   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
556   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
557   XFixesDestroyRegion(psc->base.dpy, region);
558
559}
560
561static void
562dri2_wait_x(struct glx_context *gc)
563{
564   struct dri2_drawable *priv = (struct dri2_drawable *)
565      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
566
567   if (priv == NULL || !priv->have_fake_front)
568      return;
569
570   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
571}
572
573static void
574dri2_wait_gl(struct glx_context *gc)
575{
576   struct dri2_drawable *priv = (struct dri2_drawable *)
577      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
578
579   if (priv == NULL || !priv->have_fake_front)
580      return;
581
582   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
583}
584
585static void
586dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
587{
588   struct glx_display *priv;
589   struct dri2_display *pdp;
590   struct glx_context *gc;
591   struct dri2_drawable *pdraw = loaderPrivate;
592   struct dri2_screen *psc;
593
594   if (!pdraw)
595      return;
596
597   if (!pdraw->base.psc)
598      return;
599
600   psc = (struct dri2_screen *) pdraw->base.psc;
601
602   priv = __glXInitialize(psc->base.dpy);
603   pdp = (struct dri2_display *) priv->dri2Display;
604   gc = __glXGetCurrentContext();
605
606   dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
607
608   /* Old servers don't send invalidate events */
609   if (!pdp->invalidateAvailable)
610       dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
611
612   dri2_wait_gl(gc);
613}
614
615
616static void
617dri2DestroyScreen(struct glx_screen *base)
618{
619   struct dri2_screen *psc = (struct dri2_screen *) base;
620
621   /* Free the direct rendering per screen data */
622   (*psc->core->destroyScreen) (psc->driScreen);
623   driDestroyConfigs(psc->driver_configs);
624   close(psc->fd);
625   Xfree(psc);
626}
627
628/**
629 * Process list of buffer received from the server
630 *
631 * Processes the list of buffers received in a reply from the server to either
632 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
633 */
634static void
635process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
636                unsigned count)
637{
638   int i;
639
640   pdraw->bufferCount = count;
641   pdraw->have_fake_front = 0;
642   pdraw->have_back = 0;
643
644   /* This assumes the DRI2 buffer attachment tokens matches the
645    * __DRIbuffer tokens. */
646   for (i = 0; i < count; i++) {
647      pdraw->buffers[i].attachment = buffers[i].attachment;
648      pdraw->buffers[i].name = buffers[i].name;
649      pdraw->buffers[i].pitch = buffers[i].pitch;
650      pdraw->buffers[i].cpp = buffers[i].cpp;
651      pdraw->buffers[i].flags = buffers[i].flags;
652      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
653         pdraw->have_fake_front = 1;
654      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
655         pdraw->have_back = 1;
656   }
657
658}
659
660unsigned dri2GetSwapEventType(Display* dpy, XID drawable)
661{
662      struct glx_display *glx_dpy = __glXInitialize(dpy);
663      __GLXDRIdrawable *pdraw;
664      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
665      if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
666         return 0;
667      return glx_dpy->codes->first_event + GLX_BufferSwapComplete;
668}
669
670static void show_fps(struct dri2_drawable *draw)
671{
672   struct timeval tv;
673   double current_time;
674
675   gettimeofday(&tv, 0);
676   current_time = (double)tv.tv_sec + (double)tv.tv_usec * 0.000001;
677
678   draw->frames++;
679
680   if (draw->previous_time + 1 < current_time) {
681      if (draw->previous_time) {
682         fprintf(stderr, "libGL: FPS = %.1f\n",
683                 draw->frames / (current_time - draw->previous_time));
684      }
685      draw->frames = 0;
686      draw->previous_time = current_time;
687   }
688}
689
690static int64_t
691dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
692		int64_t remainder)
693{
694    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
695    struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
696    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
697    struct dri2_display *pdp =
698	(struct dri2_display *)dpyPriv->dri2Display;
699    CARD64 ret = 0;
700
701    /* Check we have the right attachments */
702    if (!priv->have_back)
703	return ret;
704
705    /* Old servers can't handle swapbuffers */
706    if (!pdp->swapAvailable) {
707       __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
708			   __DRI2_THROTTLE_SWAPBUFFER);
709    } else {
710#ifdef X_DRI2SwapBuffers
711#ifdef __DRI2_FLUSH
712    if (psc->f) {
713       struct glx_context *gc = __glXGetCurrentContext();
714
715       if (gc) {
716	  (*psc->f->flush)(priv->driDrawable);
717       }
718    }
719#endif
720
721       dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER);
722
723       DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable,
724		       target_msc, divisor, remainder, &ret);
725#endif
726    }
727
728    if (psc->show_fps) {
729       show_fps(priv);
730    }
731
732    /* Old servers don't send invalidate events */
733    if (!pdp->invalidateAvailable)
734       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
735
736    return ret;
737}
738
739static __DRIbuffer *
740dri2GetBuffers(__DRIdrawable * driDrawable,
741               int *width, int *height,
742               unsigned int *attachments, int count,
743               int *out_count, void *loaderPrivate)
744{
745   struct dri2_drawable *pdraw = loaderPrivate;
746   DRI2Buffer *buffers;
747
748   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
749                            width, height, attachments, count, out_count);
750   if (buffers == NULL)
751      return NULL;
752
753   pdraw->width = *width;
754   pdraw->height = *height;
755   process_buffers(pdraw, buffers, *out_count);
756
757   Xfree(buffers);
758
759   return pdraw->buffers;
760}
761
762static __DRIbuffer *
763dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
764                         int *width, int *height,
765                         unsigned int *attachments, int count,
766                         int *out_count, void *loaderPrivate)
767{
768   struct dri2_drawable *pdraw = loaderPrivate;
769   DRI2Buffer *buffers;
770
771   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
772                                      pdraw->base.xDrawable,
773                                      width, height, attachments,
774                                      count, out_count);
775   if (buffers == NULL)
776      return NULL;
777
778   pdraw->width = *width;
779   pdraw->height = *height;
780   process_buffers(pdraw, buffers, *out_count);
781
782   Xfree(buffers);
783
784   return pdraw->buffers;
785}
786
787#ifdef X_DRI2SwapInterval
788
789static int
790dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
791{
792   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
793   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
794   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
795
796   if (psc->config)
797      psc->config->configQueryi(psc->driScreen,
798				"vblank_mode", &vblank_mode);
799
800   switch (vblank_mode) {
801   case DRI_CONF_VBLANK_NEVER:
802      return GLX_BAD_VALUE;
803   case DRI_CONF_VBLANK_ALWAYS_SYNC:
804      if (interval <= 0)
805	 return GLX_BAD_VALUE;
806      break;
807   default:
808      break;
809   }
810
811   DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval);
812   priv->swap_interval = interval;
813
814   return 0;
815}
816
817static int
818dri2GetSwapInterval(__GLXDRIdrawable *pdraw)
819{
820   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
821
822  return priv->swap_interval;
823}
824
825#endif /* X_DRI2SwapInterval */
826
827static const __DRIdri2LoaderExtension dri2LoaderExtension = {
828   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
829   dri2GetBuffers,
830   dri2FlushFrontBuffer,
831   dri2GetBuffersWithFormat,
832};
833
834static const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
835   {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION},
836   dri2GetBuffers,
837   dri2FlushFrontBuffer,
838   NULL,
839};
840
841#ifdef __DRI_USE_INVALIDATE
842static const __DRIuseInvalidateExtension dri2UseInvalidate = {
843   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
844};
845#endif
846
847_X_HIDDEN void
848dri2InvalidateBuffers(Display *dpy, XID drawable)
849{
850   __GLXDRIdrawable *pdraw =
851      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
852   struct dri2_screen *psc;
853   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
854
855   if (!pdraw)
856      return;
857
858   psc = (struct dri2_screen *) pdraw->psc;
859
860#if __DRI2_FLUSH_VERSION >= 3
861   if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
862       psc->f->invalidate(pdp->driDrawable);
863#endif
864}
865
866static void
867dri2_bind_tex_image(Display * dpy,
868		    GLXDrawable drawable,
869		    int buffer, const int *attrib_list)
870{
871   struct glx_context *gc = __glXGetCurrentContext();
872   struct dri2_context *pcp = (struct dri2_context *) gc;
873   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
874   struct glx_display *dpyPriv = __glXInitialize(dpy);
875   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
876   struct dri2_display *pdp =
877      (struct dri2_display *) dpyPriv->dri2Display;
878   struct dri2_screen *psc;
879
880   if (pdraw != NULL) {
881      psc = (struct dri2_screen *) base->psc;
882
883#if __DRI2_FLUSH_VERSION >= 3
884      if (!pdp->invalidateAvailable && psc->f &&
885           psc->f->base.version >= 3 && psc->f->invalidate)
886	 psc->f->invalidate(pdraw->driDrawable);
887#endif
888
889      if (psc->texBuffer->base.version >= 2 &&
890	  psc->texBuffer->setTexBuffer2 != NULL) {
891	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
892					   pdraw->base.textureTarget,
893					   pdraw->base.textureFormat,
894					   pdraw->driDrawable);
895      }
896      else {
897	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
898					  pdraw->base.textureTarget,
899					  pdraw->driDrawable);
900      }
901   }
902}
903
904static void
905dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
906{
907#if __DRI_TEX_BUFFER_VERSION >= 3
908   struct glx_context *gc = __glXGetCurrentContext();
909   struct dri2_context *pcp = (struct dri2_context *) gc;
910   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
911   struct glx_display *dpyPriv = __glXInitialize(dpy);
912   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
913   struct dri2_display *pdp =
914      (struct dri2_display *) dpyPriv->dri2Display;
915   struct dri2_screen *psc;
916
917   if (pdraw != NULL) {
918      psc = (struct dri2_screen *) base->psc;
919
920      if (psc->texBuffer->base.version >= 3 &&
921          psc->texBuffer->releaseTexBuffer != NULL) {
922         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
923                                           pdraw->base.textureTarget,
924                                           pdraw->driDrawable);
925      }
926   }
927#endif
928}
929
930static const struct glx_context_vtable dri2_context_vtable = {
931   dri2_destroy_context,
932   dri2_bind_context,
933   dri2_unbind_context,
934   dri2_wait_gl,
935   dri2_wait_x,
936   DRI_glXUseXFont,
937   dri2_bind_tex_image,
938   dri2_release_tex_image,
939   NULL, /* get_proc_address */
940};
941
942static void
943dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions)
944{
945   int i;
946
947   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
948   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
949   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
950   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
951
952   /* FIXME: if DRI2 version supports it... */
953   __glXEnableDirectExtension(&psc->base, "INTEL_swap_event");
954
955   if (psc->dri2->base.version >= 3) {
956      const unsigned mask = psc->dri2->getAPIMask(psc->driScreen);
957
958      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
959      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
960
961      if ((mask & (1 << __DRI_API_GLES2)) != 0)
962	 __glXEnableDirectExtension(&psc->base,
963				    "GLX_EXT_create_context_es2_profile");
964   }
965
966   for (i = 0; extensions[i]; i++) {
967      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
968	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
969	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
970      }
971
972      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
973	 psc->f = (__DRI2flushExtension *) extensions[i];
974	 /* internal driver extension, no GL extension exposed */
975      }
976
977      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
978	 psc->config = (__DRI2configQueryExtension *) extensions[i];
979
980      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
981	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
982   }
983}
984
985static const struct glx_screen_vtable dri2_screen_vtable = {
986   dri2_create_context,
987   dri2_create_context_attribs
988};
989
990static struct glx_screen *
991dri2CreateScreen(int screen, struct glx_display * priv)
992{
993   const __DRIconfig **driver_configs;
994   const __DRIextension **extensions;
995   const struct dri2_display *const pdp = (struct dri2_display *)
996      priv->dri2Display;
997   struct dri2_screen *psc;
998   __GLXDRIscreen *psp;
999   struct glx_config *configs = NULL, *visuals = NULL;
1000   char *driverName, *deviceName, *tmp;
1001   drm_magic_t magic;
1002   int i;
1003
1004   psc = Xmalloc(sizeof *psc);
1005   if (psc == NULL)
1006      return NULL;
1007
1008   memset(psc, 0, sizeof *psc);
1009   psc->fd = -1;
1010
1011   if (!glx_screen_init(&psc->base, screen, priv)) {
1012      Xfree(psc);
1013      return NULL;
1014   }
1015
1016   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
1017		    &driverName, &deviceName)) {
1018      glx_screen_cleanup(&psc->base);
1019      XFree(psc);
1020      InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
1021      return NULL;
1022   }
1023
1024   psc->driver = driOpenDriver(driverName);
1025   if (psc->driver == NULL) {
1026      ErrorMessageF("driver pointer missing\n");
1027      goto handle_error;
1028   }
1029
1030   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
1031   if (extensions == NULL) {
1032      ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
1033      goto handle_error;
1034   }
1035
1036   for (i = 0; extensions[i]; i++) {
1037      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1038	 psc->core = (__DRIcoreExtension *) extensions[i];
1039      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
1040	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
1041   }
1042
1043   if (psc->core == NULL || psc->dri2 == NULL) {
1044      ErrorMessageF("core dri or dri2 extension not found\n");
1045      goto handle_error;
1046   }
1047
1048   psc->fd = open(deviceName, O_RDWR);
1049   if (psc->fd < 0) {
1050      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
1051      goto handle_error;
1052   }
1053
1054   if (drmGetMagic(psc->fd, &magic)) {
1055      ErrorMessageF("failed to get magic\n");
1056      goto handle_error;
1057   }
1058
1059   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
1060      ErrorMessageF("failed to authenticate magic %d\n", magic);
1061      goto handle_error;
1062   }
1063
1064
1065   /* If the server does not support the protocol for
1066    * DRI2GetBuffersWithFormat, don't supply that interface to the driver.
1067    */
1068   psc->driScreen =
1069      psc->dri2->createNewScreen(screen, psc->fd,
1070				 (const __DRIextension **)
1071				 &pdp->loader_extensions[0],
1072				 &driver_configs, psc);
1073
1074   if (psc->driScreen == NULL) {
1075      ErrorMessageF("failed to create dri screen\n");
1076      goto handle_error;
1077   }
1078
1079   extensions = psc->core->getExtensions(psc->driScreen);
1080   dri2BindExtensions(psc, extensions);
1081
1082   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1083   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1084
1085   if (!configs || !visuals)
1086       goto handle_error;
1087
1088   glx_config_destroy_list(psc->base.configs);
1089   psc->base.configs = configs;
1090   glx_config_destroy_list(psc->base.visuals);
1091   psc->base.visuals = visuals;
1092
1093   psc->driver_configs = driver_configs;
1094
1095   psc->base.vtable = &dri2_screen_vtable;
1096   psp = &psc->vtable;
1097   psc->base.driScreen = psp;
1098   psp->destroyScreen = dri2DestroyScreen;
1099   psp->createDrawable = dri2CreateDrawable;
1100   psp->swapBuffers = dri2SwapBuffers;
1101   psp->getDrawableMSC = NULL;
1102   psp->waitForMSC = NULL;
1103   psp->waitForSBC = NULL;
1104   psp->setSwapInterval = NULL;
1105   psp->getSwapInterval = NULL;
1106
1107   if (pdp->driMinor >= 2) {
1108#ifdef X_DRI2GetMSC
1109      psp->getDrawableMSC = dri2DrawableGetMSC;
1110#endif
1111#ifdef X_DRI2WaitMSC
1112      psp->waitForMSC = dri2WaitForMSC;
1113      psp->waitForSBC = dri2WaitForSBC;
1114#endif
1115#ifdef X_DRI2SwapInterval
1116      psp->setSwapInterval = dri2SetSwapInterval;
1117      psp->getSwapInterval = dri2GetSwapInterval;
1118#endif
1119#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval)
1120      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1121#endif
1122   }
1123
1124   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
1125    * available.*/
1126   psp->copySubBuffer = dri2CopySubBuffer;
1127   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1128
1129   Xfree(driverName);
1130   Xfree(deviceName);
1131
1132   tmp = getenv("LIBGL_SHOW_FPS");
1133   psc->show_fps = tmp && strcmp(tmp, "1") == 0;
1134
1135   return &psc->base;
1136
1137handle_error:
1138   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1139
1140   if (configs)
1141       glx_config_destroy_list(configs);
1142   if (visuals)
1143       glx_config_destroy_list(visuals);
1144   if (psc->driScreen)
1145       psc->core->destroyScreen(psc->driScreen);
1146   psc->driScreen = NULL;
1147   if (psc->fd >= 0)
1148      close(psc->fd);
1149   if (psc->driver)
1150      dlclose(psc->driver);
1151
1152   Xfree(driverName);
1153   Xfree(deviceName);
1154   glx_screen_cleanup(&psc->base);
1155   XFree(psc);
1156
1157   return NULL;
1158}
1159
1160/* Called from __glXFreeDisplayPrivate.
1161 */
1162static void
1163dri2DestroyDisplay(__GLXDRIdisplay * dpy)
1164{
1165   struct dri2_display *pdp = (struct dri2_display *) dpy;
1166
1167   __glxHashDestroy(pdp->dri2Hash);
1168   Xfree(dpy);
1169}
1170
1171_X_HIDDEN __GLXDRIdrawable *
1172dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
1173{
1174   struct glx_display *d = __glXInitialize(dpy);
1175   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
1176   __GLXDRIdrawable *pdraw;
1177
1178   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
1179      return pdraw;
1180
1181   return NULL;
1182}
1183
1184/*
1185 * Allocate, initialize and return a __DRIdisplayPrivate object.
1186 * This is called from __glXInitialize() when we are given a new
1187 * display pointer.
1188 */
1189_X_HIDDEN __GLXDRIdisplay *
1190dri2CreateDisplay(Display * dpy)
1191{
1192   struct dri2_display *pdp;
1193   int eventBase, errorBase, i;
1194
1195   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1196      return NULL;
1197
1198   pdp = Xmalloc(sizeof *pdp);
1199   if (pdp == NULL)
1200      return NULL;
1201
1202   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1203      Xfree(pdp);
1204      return NULL;
1205   }
1206
1207   pdp->driPatch = 0;
1208   pdp->swapAvailable = (pdp->driMinor >= 2);
1209   pdp->invalidateAvailable = (pdp->driMinor >= 3);
1210
1211   pdp->base.destroyDisplay = dri2DestroyDisplay;
1212   pdp->base.createScreen = dri2CreateScreen;
1213
1214   i = 0;
1215   if (pdp->driMinor < 1)
1216      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
1217   else
1218      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
1219
1220   pdp->loader_extensions[i++] = &systemTimeExtension.base;
1221
1222#ifdef __DRI_USE_INVALIDATE
1223   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1224#endif
1225   pdp->loader_extensions[i++] = NULL;
1226
1227   pdp->dri2Hash = __glxHashCreate();
1228   if (pdp->dri2Hash == NULL) {
1229      Xfree(pdp);
1230      return NULL;
1231   }
1232
1233   return &pdp->base;
1234}
1235
1236#endif /* GLX_DIRECT_RENDERING */
1237