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