dri2_glx.c revision 9f464c52
1cdc920a0Smrg/*
2cdc920a0Smrg * Copyright © 2008 Red Hat, Inc.
3cdc920a0Smrg *
4cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5cdc920a0Smrg * copy of this software and associated documentation files (the "Soft-
6cdc920a0Smrg * ware"), to deal in the Software without restriction, including without
7cdc920a0Smrg * limitation the rights to use, copy, modify, merge, publish, distribute,
8cdc920a0Smrg * and/or sell copies of the Software, and to permit persons to whom the
9cdc920a0Smrg * Software is furnished to do so, provided that the above copyright
10cdc920a0Smrg * notice(s) and this permission notice appear in all copies of the Soft-
11cdc920a0Smrg * ware and that both the above copyright notice(s) and this permission
12cdc920a0Smrg * notice appear in supporting documentation.
13cdc920a0Smrg *
14cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15cdc920a0Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16cdc920a0Smrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17cdc920a0Smrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18cdc920a0Smrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19cdc920a0Smrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20cdc920a0Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21cdc920a0Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22cdc920a0Smrg * MANCE OF THIS SOFTWARE.
23cdc920a0Smrg *
24cdc920a0Smrg * Except as contained in this notice, the name of a copyright holder shall
25cdc920a0Smrg * not be used in advertising or otherwise to promote the sale, use or
26cdc920a0Smrg * other dealings in this Software without prior written authorization of
27cdc920a0Smrg * the copyright holder.
28cdc920a0Smrg *
29cdc920a0Smrg * Authors:
30cdc920a0Smrg *   Kristian Høgsberg (krh@redhat.com)
31cdc920a0Smrg */
32cdc920a0Smrg
33cdc920a0Smrg#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
34cdc920a0Smrg
35cdc920a0Smrg#include <X11/Xlib.h>
36cdc920a0Smrg#include <X11/extensions/Xfixes.h>
37af69d88dSmrg#include <X11/Xlib-xcb.h>
38af69d88dSmrg#include <xcb/xcb.h>
39af69d88dSmrg#include <xcb/dri2.h>
40cdc920a0Smrg#include "glxclient.h"
41cdc920a0Smrg#include <X11/extensions/dri2proto.h>
42cdc920a0Smrg#include <dlfcn.h>
43cdc920a0Smrg#include <fcntl.h>
44cdc920a0Smrg#include <unistd.h>
45cdc920a0Smrg#include <sys/types.h>
46cdc920a0Smrg#include <sys/mman.h>
47af69d88dSmrg#include <sys/time.h>
48cdc920a0Smrg#include "dri2.h"
49cdc920a0Smrg#include "dri_common.h"
50af69d88dSmrg#include "dri2_priv.h"
51af69d88dSmrg#include "loader.h"
523464ebd5Sriastradh
533464ebd5Sriastradh/* From xmlpool/options.h, user exposed so should be stable */
543464ebd5Sriastradh#define DRI_CONF_VBLANK_NEVER 0
553464ebd5Sriastradh#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1
563464ebd5Sriastradh#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2
573464ebd5Sriastradh#define DRI_CONF_VBLANK_ALWAYS_SYNC 3
58cdc920a0Smrg
59cdc920a0Smrg#undef DRI2_MINOR
60cdc920a0Smrg#define DRI2_MINOR 1
61cdc920a0Smrg
623464ebd5Sriastradhstruct dri2_display
63cdc920a0Smrg{
64cdc920a0Smrg   __GLXDRIdisplay base;
65cdc920a0Smrg
66cdc920a0Smrg   /*
67cdc920a0Smrg    ** XFree86-DRI version information
68cdc920a0Smrg    */
69cdc920a0Smrg   int driMajor;
70cdc920a0Smrg   int driMinor;
71cdc920a0Smrg   int driPatch;
72cdc920a0Smrg   int swapAvailable;
73cdc920a0Smrg   int invalidateAvailable;
743464ebd5Sriastradh
753464ebd5Sriastradh   __glxHashTable *dri2Hash;
763464ebd5Sriastradh
7701e04c3fSmrg   const __DRIextension *loader_extensions[5];
78cdc920a0Smrg};
79cdc920a0Smrg
803464ebd5Sriastradhstruct dri2_drawable
81cdc920a0Smrg{
82cdc920a0Smrg   __GLXDRIdrawable base;
833464ebd5Sriastradh   __DRIdrawable *driDrawable;
84cdc920a0Smrg   __DRIbuffer buffers[5];
85cdc920a0Smrg   int bufferCount;
86cdc920a0Smrg   int width, height;
87cdc920a0Smrg   int have_back;
88cdc920a0Smrg   int have_fake_front;
89cdc920a0Smrg   int swap_interval;
90af69d88dSmrg
91af69d88dSmrg   uint64_t previous_time;
92af69d88dSmrg   unsigned frames;
93cdc920a0Smrg};
94cdc920a0Smrg
953464ebd5Sriastradhstatic const struct glx_context_vtable dri2_context_vtable;
96cdc920a0Smrg
97af69d88dSmrg/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
98af69d88dSmrg * low halves separately.  This helps you split them.
99af69d88dSmrg */
100af69d88dSmrgstatic void
101af69d88dSmrgsplit_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
102af69d88dSmrg{
103af69d88dSmrg   *hi = (counter >> 32);
104af69d88dSmrg   *lo = counter & 0xffffffff;
105af69d88dSmrg}
106af69d88dSmrg
107af69d88dSmrgstatic uint64_t
108af69d88dSmrgmerge_counter(uint32_t hi, uint32_t lo)
109af69d88dSmrg{
110af69d88dSmrg   return ((uint64_t)hi << 32) | lo;
111af69d88dSmrg}
112af69d88dSmrg
113cdc920a0Smrgstatic void
1143464ebd5Sriastradhdri2_destroy_context(struct glx_context *context)
115cdc920a0Smrg{
1163464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1173464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) context->psc;
1183464ebd5Sriastradh
1193464ebd5Sriastradh   driReleaseDrawables(&pcp->base);
1203464ebd5Sriastradh
121af69d88dSmrg   free((char *) context->extensions);
122cdc920a0Smrg
1233464ebd5Sriastradh   (*psc->core->destroyContext) (pcp->driContext);
124cdc920a0Smrg
125af69d88dSmrg   free(pcp);
126cdc920a0Smrg}
127cdc920a0Smrg
128cdc920a0Smrgstatic Bool
1293464ebd5Sriastradhdri2_bind_context(struct glx_context *context, struct glx_context *old,
1303464ebd5Sriastradh		  GLXDrawable draw, GLXDrawable read)
131cdc920a0Smrg{
1323464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1333464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
1343464ebd5Sriastradh   struct dri2_drawable *pdraw, *pread;
135af69d88dSmrg   __DRIdrawable *dri_draw = NULL, *dri_read = NULL;
136af69d88dSmrg   struct glx_display *dpyPriv = psc->base.display;
1373464ebd5Sriastradh   struct dri2_display *pdp;
1383464ebd5Sriastradh
1393464ebd5Sriastradh   pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
1403464ebd5Sriastradh   pread = (struct dri2_drawable *) driFetchDrawable(context, read);
1413464ebd5Sriastradh
1423464ebd5Sriastradh   driReleaseDrawables(&pcp->base);
1433464ebd5Sriastradh
144af69d88dSmrg   if (pdraw)
145af69d88dSmrg      dri_draw = pdraw->driDrawable;
146af69d88dSmrg   else if (draw != None)
1473464ebd5Sriastradh      return GLXBadDrawable;
1483464ebd5Sriastradh
149af69d88dSmrg   if (pread)
150af69d88dSmrg      dri_read = pread->driDrawable;
151af69d88dSmrg   else if (read != None)
152af69d88dSmrg      return GLXBadDrawable;
153af69d88dSmrg
154af69d88dSmrg   if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read))
1553464ebd5Sriastradh      return GLXBadContext;
1563464ebd5Sriastradh
1573464ebd5Sriastradh   /* If the server doesn't send invalidate events, we may miss a
1583464ebd5Sriastradh    * resize before the rendering starts.  Invalidate the buffers now
1593464ebd5Sriastradh    * so the driver will recheck before rendering starts. */
160af69d88dSmrg   pdp = (struct dri2_display *) dpyPriv->dri2Display;
161af69d88dSmrg   if (!pdp->invalidateAvailable && pdraw) {
1623464ebd5Sriastradh      dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable);
163af69d88dSmrg      if (pread != pdraw && pread)
1643464ebd5Sriastradh	 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable);
1653464ebd5Sriastradh   }
166cdc920a0Smrg
1673464ebd5Sriastradh   return Success;
168cdc920a0Smrg}
169cdc920a0Smrg
170cdc920a0Smrgstatic void
1713464ebd5Sriastradhdri2_unbind_context(struct glx_context *context, struct glx_context *new)
172cdc920a0Smrg{
1733464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1743464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
175cdc920a0Smrg
1763464ebd5Sriastradh   (*psc->core->unbindContext) (pcp->driContext);
177cdc920a0Smrg}
178cdc920a0Smrg
1793464ebd5Sriastradhstatic struct glx_context *
1803464ebd5Sriastradhdri2_create_context(struct glx_screen *base,
1813464ebd5Sriastradh		    struct glx_config *config_base,
1823464ebd5Sriastradh		    struct glx_context *shareList, int renderType)
183cdc920a0Smrg{
1843464ebd5Sriastradh   struct dri2_context *pcp, *pcp_shared;
1853464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
1863464ebd5Sriastradh   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
187cdc920a0Smrg   __DRIcontext *shared = NULL;
188cdc920a0Smrg
189af69d88dSmrg   /* Check the renderType value */
190af69d88dSmrg   if (!validate_renderType_against_config(config_base, renderType))
191af69d88dSmrg       return NULL;
192af69d88dSmrg
193cdc920a0Smrg   if (shareList) {
194af69d88dSmrg      /* If the shareList context is not a DRI2 context, we cannot possibly
195af69d88dSmrg       * create a DRI2 context that shares it.
196af69d88dSmrg       */
197af69d88dSmrg      if (shareList->vtable->destroy != dri2_destroy_context) {
198af69d88dSmrg	 return NULL;
199af69d88dSmrg      }
200af69d88dSmrg
2013464ebd5Sriastradh      pcp_shared = (struct dri2_context *) shareList;
202cdc920a0Smrg      shared = pcp_shared->driContext;
203cdc920a0Smrg   }
204cdc920a0Smrg
205af69d88dSmrg   pcp = calloc(1, sizeof *pcp);
206cdc920a0Smrg   if (pcp == NULL)
207cdc920a0Smrg      return NULL;
208cdc920a0Smrg
2093464ebd5Sriastradh   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
210af69d88dSmrg      free(pcp);
2113464ebd5Sriastradh      return NULL;
2123464ebd5Sriastradh   }
2133464ebd5Sriastradh
214af69d88dSmrg   pcp->base.renderType = renderType;
215af69d88dSmrg
216cdc920a0Smrg   pcp->driContext =
2173464ebd5Sriastradh      (*psc->dri2->createNewContext) (psc->driScreen,
218cdc920a0Smrg                                      config->driConfig, shared, pcp);
219cdc920a0Smrg
220cdc920a0Smrg   if (pcp->driContext == NULL) {
221af69d88dSmrg      free(pcp);
222cdc920a0Smrg      return NULL;
223cdc920a0Smrg   }
224cdc920a0Smrg
2253464ebd5Sriastradh   pcp->base.vtable = &dri2_context_vtable;
226cdc920a0Smrg
227cdc920a0Smrg   return &pcp->base;
228cdc920a0Smrg}
229cdc920a0Smrg
230af69d88dSmrgstatic struct glx_context *
231af69d88dSmrgdri2_create_context_attribs(struct glx_screen *base,
232af69d88dSmrg			    struct glx_config *config_base,
233af69d88dSmrg			    struct glx_context *shareList,
234af69d88dSmrg			    unsigned num_attribs,
235af69d88dSmrg			    const uint32_t *attribs,
236af69d88dSmrg			    unsigned *error)
237af69d88dSmrg{
238af69d88dSmrg   struct dri2_context *pcp = NULL;
239af69d88dSmrg   struct dri2_context *pcp_shared = NULL;
240af69d88dSmrg   struct dri2_screen *psc = (struct dri2_screen *) base;
241af69d88dSmrg   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
242af69d88dSmrg   __DRIcontext *shared = NULL;
243af69d88dSmrg
244af69d88dSmrg   uint32_t minor_ver;
245af69d88dSmrg   uint32_t major_ver;
246af69d88dSmrg   uint32_t renderType;
247af69d88dSmrg   uint32_t flags;
248af69d88dSmrg   unsigned api;
249af69d88dSmrg   int reset;
25001e04c3fSmrg   int release;
25101e04c3fSmrg   uint32_t ctx_attribs[2 * 6];
252af69d88dSmrg   unsigned num_ctx_attribs = 0;
253af69d88dSmrg
254af69d88dSmrg   if (psc->dri2->base.version < 3) {
255af69d88dSmrg      *error = __DRI_CTX_ERROR_NO_MEMORY;
256af69d88dSmrg      goto error_exit;
257af69d88dSmrg   }
258af69d88dSmrg
259af69d88dSmrg   /* Remap the GLX tokens to DRI2 tokens.
260af69d88dSmrg    */
261af69d88dSmrg   if (!dri2_convert_glx_attribs(num_attribs, attribs,
262af69d88dSmrg                                 &major_ver, &minor_ver, &renderType, &flags,
26301e04c3fSmrg                                 &api, &reset, &release, error))
264af69d88dSmrg      goto error_exit;
265af69d88dSmrg
2669f464c52Smaya   if (!dri2_check_no_error(flags, shareList, major_ver, error)) {
2679f464c52Smaya      goto error_exit;
2689f464c52Smaya   }
2699f464c52Smaya
270af69d88dSmrg   /* Check the renderType value */
271af69d88dSmrg   if (!validate_renderType_against_config(config_base, renderType))
272af69d88dSmrg       goto error_exit;
273af69d88dSmrg
274af69d88dSmrg   if (shareList) {
275af69d88dSmrg      pcp_shared = (struct dri2_context *) shareList;
276af69d88dSmrg      shared = pcp_shared->driContext;
277af69d88dSmrg   }
278af69d88dSmrg
279af69d88dSmrg   pcp = calloc(1, sizeof *pcp);
280af69d88dSmrg   if (pcp == NULL) {
281af69d88dSmrg      *error = __DRI_CTX_ERROR_NO_MEMORY;
282af69d88dSmrg      goto error_exit;
283af69d88dSmrg   }
284af69d88dSmrg
28501e04c3fSmrg   if (!glx_context_init(&pcp->base, &psc->base, config_base))
286af69d88dSmrg      goto error_exit;
287af69d88dSmrg
288af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
289af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = major_ver;
290af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
291af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = minor_ver;
292af69d88dSmrg
293af69d88dSmrg   /* Only send a value when the non-default value is requested.  By doing
294af69d88dSmrg    * this we don't have to check the driver's DRI2 version before sending the
295af69d88dSmrg    * default value.
296af69d88dSmrg    */
297af69d88dSmrg   if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
298af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
299af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = reset;
300af69d88dSmrg   }
301af69d88dSmrg
30201e04c3fSmrg   if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
30301e04c3fSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
30401e04c3fSmrg      ctx_attribs[num_ctx_attribs++] = release;
30501e04c3fSmrg   }
30601e04c3fSmrg
307af69d88dSmrg   if (flags != 0) {
308af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
309af69d88dSmrg
310af69d88dSmrg      /* The current __DRI_CTX_FLAG_* values are identical to the
311af69d88dSmrg       * GLX_CONTEXT_*_BIT values.
312af69d88dSmrg       */
313af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = flags;
314af69d88dSmrg   }
315af69d88dSmrg
316af69d88dSmrg   /* The renderType is retrieved from attribs, or set to default
317af69d88dSmrg    *  of GLX_RGBA_TYPE.
318af69d88dSmrg    */
319af69d88dSmrg   pcp->base.renderType = renderType;
320af69d88dSmrg
3219f464c52Smaya   if (flags & __DRI_CTX_FLAG_NO_ERROR)
3229f464c52Smaya      pcp->base.noError = GL_TRUE;
3239f464c52Smaya
324af69d88dSmrg   pcp->driContext =
325af69d88dSmrg      (*psc->dri2->createContextAttribs) (psc->driScreen,
326af69d88dSmrg					  api,
32701e04c3fSmrg					  config ? config->driConfig : NULL,
328af69d88dSmrg					  shared,
329af69d88dSmrg					  num_ctx_attribs / 2,
330af69d88dSmrg					  ctx_attribs,
331af69d88dSmrg					  error,
332af69d88dSmrg					  pcp);
333af69d88dSmrg
334af69d88dSmrg   if (pcp->driContext == NULL)
335af69d88dSmrg      goto error_exit;
336af69d88dSmrg
337af69d88dSmrg   pcp->base.vtable = &dri2_context_vtable;
338af69d88dSmrg
339af69d88dSmrg   return &pcp->base;
340af69d88dSmrg
341af69d88dSmrgerror_exit:
342af69d88dSmrg   free(pcp);
343af69d88dSmrg
344af69d88dSmrg   return NULL;
345af69d88dSmrg}
346af69d88dSmrg
347cdc920a0Smrgstatic void
3483464ebd5Sriastradhdri2DestroyDrawable(__GLXDRIdrawable *base)
349cdc920a0Smrg{
3503464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
3513464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
3523464ebd5Sriastradh   struct glx_display *dpyPriv = psc->base.display;
3533464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
3543464ebd5Sriastradh
3553464ebd5Sriastradh   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
3563464ebd5Sriastradh   (*psc->core->destroyDrawable) (pdraw->driDrawable);
3573464ebd5Sriastradh
3583464ebd5Sriastradh   /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
3593464ebd5Sriastradh    * now, as the application explicitly asked to destroy the GLX
3603464ebd5Sriastradh    * drawable.  Otherwise, for legacy drawables, we let the DRI2
3613464ebd5Sriastradh    * drawable linger on the server, since there's no good way of
3623464ebd5Sriastradh    * knowing when the application is done with it.  The server will
3633464ebd5Sriastradh    * destroy the DRI2 drawable when it destroys the X drawable or the
3643464ebd5Sriastradh    * client exits anyway. */
3653464ebd5Sriastradh   if (pdraw->base.xDrawable != pdraw->base.drawable)
3663464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
367cdc920a0Smrg
368af69d88dSmrg   free(pdraw);
369cdc920a0Smrg}
370cdc920a0Smrg
371cdc920a0Smrgstatic __GLXDRIdrawable *
3723464ebd5Sriastradhdri2CreateDrawable(struct glx_screen *base, XID xDrawable,
3733464ebd5Sriastradh		   GLXDrawable drawable, struct glx_config *config_base)
374cdc920a0Smrg{
3753464ebd5Sriastradh   struct dri2_drawable *pdraw;
3763464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
3773464ebd5Sriastradh   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
3783464ebd5Sriastradh   struct glx_display *dpyPriv;
3793464ebd5Sriastradh   struct dri2_display *pdp;
3803464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
381cdc920a0Smrg
382af69d88dSmrg   dpyPriv = __glXInitialize(psc->base.dpy);
383af69d88dSmrg   if (dpyPriv == NULL)
384af69d88dSmrg      return NULL;
385af69d88dSmrg
386af69d88dSmrg   pdraw = calloc(1, sizeof(*pdraw));
387cdc920a0Smrg   if (!pdraw)
388cdc920a0Smrg      return NULL;
389cdc920a0Smrg
390cdc920a0Smrg   pdraw->base.destroyDrawable = dri2DestroyDrawable;
391cdc920a0Smrg   pdraw->base.xDrawable = xDrawable;
392cdc920a0Smrg   pdraw->base.drawable = drawable;
3933464ebd5Sriastradh   pdraw->base.psc = &psc->base;
394cdc920a0Smrg   pdraw->bufferCount = 0;
3953464ebd5Sriastradh   pdraw->swap_interval = 1; /* default may be overridden below */
396cdc920a0Smrg   pdraw->have_back = 0;
397cdc920a0Smrg
3983464ebd5Sriastradh   if (psc->config)
3993464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
4003464ebd5Sriastradh				"vblank_mode", &vblank_mode);
4013464ebd5Sriastradh
4023464ebd5Sriastradh   switch (vblank_mode) {
4033464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
4043464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
4053464ebd5Sriastradh      pdraw->swap_interval = 0;
4063464ebd5Sriastradh      break;
4073464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
4083464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
4093464ebd5Sriastradh   default:
4103464ebd5Sriastradh      pdraw->swap_interval = 1;
4113464ebd5Sriastradh      break;
4123464ebd5Sriastradh   }
4133464ebd5Sriastradh
4143464ebd5Sriastradh   DRI2CreateDrawable(psc->base.dpy, xDrawable);
41501e04c3fSmrg   pdp = (struct dri2_display *)dpyPriv->dri2Display;
416cdc920a0Smrg   /* Create a new drawable */
4173464ebd5Sriastradh   pdraw->driDrawable =
4183464ebd5Sriastradh      (*psc->dri2->createNewDrawable) (psc->driScreen,
419cdc920a0Smrg                                       config->driConfig, pdraw);
420cdc920a0Smrg
4213464ebd5Sriastradh   if (!pdraw->driDrawable) {
4223464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
423af69d88dSmrg      free(pdraw);
424cdc920a0Smrg      return NULL;
425cdc920a0Smrg   }
426cdc920a0Smrg
4273464ebd5Sriastradh   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
4283464ebd5Sriastradh      (*psc->core->destroyDrawable) (pdraw->driDrawable);
4293464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
430af69d88dSmrg      free(pdraw);
4313464ebd5Sriastradh      return None;
4323464ebd5Sriastradh   }
4333464ebd5Sriastradh
434cdc920a0Smrg   /*
435cdc920a0Smrg    * Make sure server has the same swap interval we do for the new
436cdc920a0Smrg    * drawable.
437cdc920a0Smrg    */
438af69d88dSmrg   if (psc->vtable.setSwapInterval)
439af69d88dSmrg      psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
440cdc920a0Smrg
441cdc920a0Smrg   return &pdraw->base;
442cdc920a0Smrg}
443cdc920a0Smrg
444cdc920a0Smrgstatic int
4453464ebd5Sriastradhdri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
446cdc920a0Smrg		   int64_t *ust, int64_t *msc, int64_t *sbc)
447cdc920a0Smrg{
448af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
449af69d88dSmrg   xcb_dri2_get_msc_cookie_t get_msc_cookie;
450af69d88dSmrg   xcb_dri2_get_msc_reply_t *get_msc_reply;
4513464ebd5Sriastradh
452af69d88dSmrg   get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
453af69d88dSmrg   get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
4543464ebd5Sriastradh
455af69d88dSmrg   if (!get_msc_reply)
456af69d88dSmrg      return 0;
457cdc920a0Smrg
458af69d88dSmrg   *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
459af69d88dSmrg   *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
460af69d88dSmrg   *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
461af69d88dSmrg   free(get_msc_reply);
462cdc920a0Smrg
463af69d88dSmrg   return 1;
464af69d88dSmrg}
465cdc920a0Smrg
466cdc920a0Smrgstatic int
467cdc920a0Smrgdri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
468cdc920a0Smrg	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
469cdc920a0Smrg{
470af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
471af69d88dSmrg   xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
472af69d88dSmrg   xcb_dri2_wait_msc_reply_t *wait_msc_reply;
473af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
474af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
475af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
476af69d88dSmrg
477af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
478af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
479af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
480af69d88dSmrg
481af69d88dSmrg   wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
482af69d88dSmrg                                                 target_msc_hi, target_msc_lo,
483af69d88dSmrg                                                 divisor_hi, divisor_lo,
484af69d88dSmrg                                                 remainder_hi, remainder_lo);
485af69d88dSmrg   wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
486af69d88dSmrg
487af69d88dSmrg   if (!wait_msc_reply)
488af69d88dSmrg      return 0;
489af69d88dSmrg
490af69d88dSmrg   *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
491af69d88dSmrg   *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
492af69d88dSmrg   *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
493af69d88dSmrg   free(wait_msc_reply);
494af69d88dSmrg
495af69d88dSmrg   return 1;
496cdc920a0Smrg}
497cdc920a0Smrg
498cdc920a0Smrgstatic int
499cdc920a0Smrgdri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
500cdc920a0Smrg	       int64_t *msc, int64_t *sbc)
501cdc920a0Smrg{
502af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
503af69d88dSmrg   xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
504af69d88dSmrg   xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
505af69d88dSmrg   uint32_t target_sbc_hi, target_sbc_lo;
5063464ebd5Sriastradh
507af69d88dSmrg   split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
5083464ebd5Sriastradh
509af69d88dSmrg   wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
510af69d88dSmrg                                                 target_sbc_hi, target_sbc_lo);
511af69d88dSmrg   wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
512af69d88dSmrg
513af69d88dSmrg   if (!wait_sbc_reply)
514af69d88dSmrg      return 0;
515af69d88dSmrg
516af69d88dSmrg   *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
517af69d88dSmrg   *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
518af69d88dSmrg   *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
519af69d88dSmrg   free(wait_sbc_reply);
520af69d88dSmrg
521af69d88dSmrg   return 1;
522cdc920a0Smrg}
523cdc920a0Smrg
524af69d88dSmrgstatic __DRIcontext *
525af69d88dSmrgdri2GetCurrentContext()
526af69d88dSmrg{
527af69d88dSmrg   struct glx_context *gc = __glXGetCurrentContext();
528af69d88dSmrg   struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
529af69d88dSmrg
53001e04c3fSmrg   return (gc != &dummyContext) ? dri2Ctx->driContext : NULL;
531af69d88dSmrg}
532af69d88dSmrg
533af69d88dSmrg/**
534af69d88dSmrg * dri2Throttle - Request driver throttling
535af69d88dSmrg *
536af69d88dSmrg * This function uses the DRI2 throttle extension to give the
537af69d88dSmrg * driver the opportunity to throttle on flush front, copysubbuffer
538af69d88dSmrg * and swapbuffers.
539af69d88dSmrg */
540af69d88dSmrgstatic void
541af69d88dSmrgdri2Throttle(struct dri2_screen *psc,
542af69d88dSmrg	     struct dri2_drawable *draw,
543af69d88dSmrg	     enum __DRI2throttleReason reason)
544af69d88dSmrg{
545af69d88dSmrg   if (psc->throttle) {
546af69d88dSmrg      __DRIcontext *ctx = dri2GetCurrentContext();
547af69d88dSmrg
548af69d88dSmrg      psc->throttle->throttle(ctx, draw->driDrawable, reason);
549af69d88dSmrg   }
550af69d88dSmrg}
551cdc920a0Smrg
552af69d88dSmrg/**
553af69d88dSmrg * Asks the driver to flush any queued work necessary for serializing with the
554af69d88dSmrg * X command stream, and optionally the slightly more strict requirement of
555af69d88dSmrg * glFlush() equivalence (which would require flushing even if nothing had
556af69d88dSmrg * been drawn to a window system framebuffer, for example).
557af69d88dSmrg */
558cdc920a0Smrgstatic void
559af69d88dSmrgdri2Flush(struct dri2_screen *psc,
560af69d88dSmrg          __DRIcontext *ctx,
561af69d88dSmrg          struct dri2_drawable *draw,
562af69d88dSmrg          unsigned flags,
563af69d88dSmrg          enum __DRI2throttleReason throttle_reason)
564af69d88dSmrg{
565af69d88dSmrg   if (ctx && psc->f && psc->f->base.version >= 4) {
566af69d88dSmrg      psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason);
567af69d88dSmrg   } else {
568af69d88dSmrg      if (flags & __DRI2_FLUSH_CONTEXT)
569af69d88dSmrg         glFlush();
570af69d88dSmrg
571af69d88dSmrg      if (psc->f)
572af69d88dSmrg         psc->f->flush(draw->driDrawable);
573af69d88dSmrg
574af69d88dSmrg      dri2Throttle(psc, draw, throttle_reason);
575af69d88dSmrg   }
576af69d88dSmrg}
577af69d88dSmrg
578af69d88dSmrgstatic void
579af69d88dSmrg__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
580af69d88dSmrg		    int width, int height,
581af69d88dSmrg		    enum __DRI2throttleReason reason, Bool flush)
582cdc920a0Smrg{
5833464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
5843464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
585cdc920a0Smrg   XRectangle xrect;
586cdc920a0Smrg   XserverRegion region;
587af69d88dSmrg   __DRIcontext *ctx = dri2GetCurrentContext();
588af69d88dSmrg   unsigned flags;
589cdc920a0Smrg
590cdc920a0Smrg   /* Check we have the right attachments */
591cdc920a0Smrg   if (!priv->have_back)
592cdc920a0Smrg      return;
593cdc920a0Smrg
594cdc920a0Smrg   xrect.x = x;
595cdc920a0Smrg   xrect.y = priv->height - y - height;
596cdc920a0Smrg   xrect.width = width;
597cdc920a0Smrg   xrect.height = height;
598cdc920a0Smrg
599af69d88dSmrg   flags = __DRI2_FLUSH_DRAWABLE;
600af69d88dSmrg   if (flush)
601af69d88dSmrg      flags |= __DRI2_FLUSH_CONTEXT;
602af69d88dSmrg   dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
603cdc920a0Smrg
6043464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
6053464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
606cdc920a0Smrg                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
607cdc920a0Smrg
608cdc920a0Smrg   /* Refresh the fake front (if present) after we just damaged the real
609cdc920a0Smrg    * front.
610cdc920a0Smrg    */
6113464ebd5Sriastradh   if (priv->have_fake_front)
6123464ebd5Sriastradh      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
6133464ebd5Sriastradh		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
6143464ebd5Sriastradh
6153464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
616cdc920a0Smrg}
617cdc920a0Smrg
618af69d88dSmrgstatic void
619af69d88dSmrgdri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
620af69d88dSmrg		  int width, int height, Bool flush)
621af69d88dSmrg{
622af69d88dSmrg   __dri2CopySubBuffer(pdraw, x, y, width, height,
623af69d88dSmrg		       __DRI2_THROTTLE_COPYSUBBUFFER, flush);
624af69d88dSmrg}
625af69d88dSmrg
626af69d88dSmrg
627cdc920a0Smrgstatic void
6283464ebd5Sriastradhdri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
629cdc920a0Smrg{
630cdc920a0Smrg   XRectangle xrect;
631cdc920a0Smrg   XserverRegion region;
6323464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
633cdc920a0Smrg
634cdc920a0Smrg   xrect.x = 0;
635cdc920a0Smrg   xrect.y = 0;
636cdc920a0Smrg   xrect.width = priv->width;
637cdc920a0Smrg   xrect.height = priv->height;
638cdc920a0Smrg
6393464ebd5Sriastradh   if (psc->f)
6403464ebd5Sriastradh      (*psc->f->flush) (priv->driDrawable);
641cdc920a0Smrg
6423464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
6433464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
6443464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
6453464ebd5Sriastradh
646cdc920a0Smrg}
647cdc920a0Smrg
648cdc920a0Smrgstatic void
6493464ebd5Sriastradhdri2_wait_x(struct glx_context *gc)
650cdc920a0Smrg{
6513464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
6523464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
653cdc920a0Smrg
6543464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
655cdc920a0Smrg      return;
656cdc920a0Smrg
6573464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
6583464ebd5Sriastradh}
659cdc920a0Smrg
6603464ebd5Sriastradhstatic void
6613464ebd5Sriastradhdri2_wait_gl(struct glx_context *gc)
6623464ebd5Sriastradh{
6633464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
6643464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
665cdc920a0Smrg
6663464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
6673464ebd5Sriastradh      return;
6683464ebd5Sriastradh
6693464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
670cdc920a0Smrg}
671cdc920a0Smrg
672af69d88dSmrg/**
673af69d88dSmrg * Called by the driver when it needs to update the real front buffer with the
674af69d88dSmrg * contents of its fake front buffer.
675af69d88dSmrg */
676cdc920a0Smrgstatic void
677cdc920a0Smrgdri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
678cdc920a0Smrg{
679af69d88dSmrg   struct glx_display *priv;
680af69d88dSmrg   struct dri2_display *pdp;
681af69d88dSmrg   struct glx_context *gc;
6823464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
683af69d88dSmrg   struct dri2_screen *psc;
684af69d88dSmrg
6853464ebd5Sriastradh   if (!pdraw)
6863464ebd5Sriastradh      return;
6873464ebd5Sriastradh
6883464ebd5Sriastradh   if (!pdraw->base.psc)
6893464ebd5Sriastradh      return;
6903464ebd5Sriastradh
691af69d88dSmrg   psc = (struct dri2_screen *) pdraw->base.psc;
692af69d88dSmrg
693af69d88dSmrg   priv = __glXInitialize(psc->base.dpy);
694af69d88dSmrg
695af69d88dSmrg   if (priv == NULL)
696af69d88dSmrg       return;
697af69d88dSmrg
698af69d88dSmrg   pdp = (struct dri2_display *) priv->dri2Display;
699af69d88dSmrg   gc = __glXGetCurrentContext();
700af69d88dSmrg
701af69d88dSmrg   dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
702cdc920a0Smrg
703cdc920a0Smrg   /* Old servers don't send invalidate events */
704cdc920a0Smrg   if (!pdp->invalidateAvailable)
7053464ebd5Sriastradh       dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
706cdc920a0Smrg
7073464ebd5Sriastradh   dri2_wait_gl(gc);
708cdc920a0Smrg}
709cdc920a0Smrg
710cdc920a0Smrg
711cdc920a0Smrgstatic void
7123464ebd5Sriastradhdri2DestroyScreen(struct glx_screen *base)
713cdc920a0Smrg{
7143464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
7153464ebd5Sriastradh
716cdc920a0Smrg   /* Free the direct rendering per screen data */
7173464ebd5Sriastradh   (*psc->core->destroyScreen) (psc->driScreen);
7183464ebd5Sriastradh   driDestroyConfigs(psc->driver_configs);
719cdc920a0Smrg   close(psc->fd);
720af69d88dSmrg   free(psc);
721cdc920a0Smrg}
722cdc920a0Smrg
723cdc920a0Smrg/**
724cdc920a0Smrg * Process list of buffer received from the server
725cdc920a0Smrg *
726cdc920a0Smrg * Processes the list of buffers received in a reply from the server to either
727cdc920a0Smrg * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
728cdc920a0Smrg */
729cdc920a0Smrgstatic void
7303464ebd5Sriastradhprocess_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
731cdc920a0Smrg                unsigned count)
732cdc920a0Smrg{
733cdc920a0Smrg   int i;
734cdc920a0Smrg
735cdc920a0Smrg   pdraw->bufferCount = count;
736cdc920a0Smrg   pdraw->have_fake_front = 0;
737cdc920a0Smrg   pdraw->have_back = 0;
738cdc920a0Smrg
739cdc920a0Smrg   /* This assumes the DRI2 buffer attachment tokens matches the
740cdc920a0Smrg    * __DRIbuffer tokens. */
741cdc920a0Smrg   for (i = 0; i < count; i++) {
742cdc920a0Smrg      pdraw->buffers[i].attachment = buffers[i].attachment;
743cdc920a0Smrg      pdraw->buffers[i].name = buffers[i].name;
744cdc920a0Smrg      pdraw->buffers[i].pitch = buffers[i].pitch;
745cdc920a0Smrg      pdraw->buffers[i].cpp = buffers[i].cpp;
746cdc920a0Smrg      pdraw->buffers[i].flags = buffers[i].flags;
747cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
748cdc920a0Smrg         pdraw->have_fake_front = 1;
749cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
750cdc920a0Smrg         pdraw->have_back = 1;
751cdc920a0Smrg   }
752cdc920a0Smrg
753cdc920a0Smrg}
754cdc920a0Smrg
7553464ebd5Sriastradhunsigned dri2GetSwapEventType(Display* dpy, XID drawable)
7563464ebd5Sriastradh{
7573464ebd5Sriastradh      struct glx_display *glx_dpy = __glXInitialize(dpy);
7583464ebd5Sriastradh      __GLXDRIdrawable *pdraw;
7593464ebd5Sriastradh      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
7603464ebd5Sriastradh      if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
7613464ebd5Sriastradh         return 0;
7623464ebd5Sriastradh      return glx_dpy->codes->first_event + GLX_BufferSwapComplete;
7633464ebd5Sriastradh}
7643464ebd5Sriastradh
765af69d88dSmrgstatic void show_fps(struct dri2_drawable *draw)
766af69d88dSmrg{
767af69d88dSmrg   const int interval =
768af69d88dSmrg      ((struct dri2_screen *) draw->base.psc)->show_fps_interval;
769af69d88dSmrg   struct timeval tv;
770af69d88dSmrg   uint64_t current_time;
771af69d88dSmrg
772af69d88dSmrg   gettimeofday(&tv, 0);
773af69d88dSmrg   current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec;
774af69d88dSmrg
775af69d88dSmrg   draw->frames++;
776af69d88dSmrg
777af69d88dSmrg   if (draw->previous_time + interval * 1000000 <= current_time) {
778af69d88dSmrg      if (draw->previous_time) {
779af69d88dSmrg         fprintf(stderr, "libGL: FPS = %.1f\n",
780af69d88dSmrg                 ((uint64_t)draw->frames * 1000000) /
781af69d88dSmrg                 (double)(current_time - draw->previous_time));
782af69d88dSmrg      }
783af69d88dSmrg      draw->frames = 0;
784af69d88dSmrg      draw->previous_time = current_time;
785af69d88dSmrg   }
786af69d88dSmrg}
787af69d88dSmrg
788af69d88dSmrgstatic int64_t
789af69d88dSmrgdri2XcbSwapBuffers(Display *dpy,
790af69d88dSmrg                  __GLXDRIdrawable *pdraw,
791af69d88dSmrg                  int64_t target_msc,
792af69d88dSmrg                  int64_t divisor,
793af69d88dSmrg                  int64_t remainder)
794af69d88dSmrg{
795af69d88dSmrg   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
796af69d88dSmrg   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
797af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
798af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
799af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
800af69d88dSmrg   int64_t ret = 0;
801af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(dpy);
802af69d88dSmrg
803af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
804af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
805af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
806af69d88dSmrg
807af69d88dSmrg   swap_buffers_cookie =
808af69d88dSmrg      xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
809af69d88dSmrg                                      target_msc_hi, target_msc_lo,
810af69d88dSmrg                                      divisor_hi, divisor_lo,
811af69d88dSmrg                                      remainder_hi, remainder_lo);
812af69d88dSmrg
813af69d88dSmrg   /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
814af69d88dSmrg    * to do so some time before reusing a (non-pageflipped) backbuffer.
815af69d88dSmrg    * Otherwise, the new rendering could get ahead of the X Server's
816af69d88dSmrg    * dispatch of the swapbuffer and you'd display garbage.
817af69d88dSmrg    *
818af69d88dSmrg    * We use XSync() first to reap the invalidate events through the event
819af69d88dSmrg    * filter, to ensure that the next drawing doesn't use an invalidated
820af69d88dSmrg    * buffer.
821af69d88dSmrg    */
822af69d88dSmrg   XSync(dpy, False);
823af69d88dSmrg
824af69d88dSmrg   swap_buffers_reply =
825af69d88dSmrg      xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
826af69d88dSmrg   if (swap_buffers_reply) {
827af69d88dSmrg      ret = merge_counter(swap_buffers_reply->swap_hi,
828af69d88dSmrg                          swap_buffers_reply->swap_lo);
829af69d88dSmrg      free(swap_buffers_reply);
830af69d88dSmrg   }
831af69d88dSmrg   return ret;
832af69d88dSmrg}
833af69d88dSmrg
834cdc920a0Smrgstatic int64_t
835cdc920a0Smrgdri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
836af69d88dSmrg		int64_t remainder, Bool flush)
837cdc920a0Smrg{
8383464ebd5Sriastradh    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
8393464ebd5Sriastradh    struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
8403464ebd5Sriastradh    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
8413464ebd5Sriastradh    struct dri2_display *pdp =
8423464ebd5Sriastradh	(struct dri2_display *)dpyPriv->dri2Display;
843af69d88dSmrg    int64_t ret = 0;
844cdc920a0Smrg
8453464ebd5Sriastradh    /* Check we have the right attachments */
8463464ebd5Sriastradh    if (!priv->have_back)
8473464ebd5Sriastradh	return ret;
848cdc920a0Smrg
849cdc920a0Smrg    /* Old servers can't handle swapbuffers */
850cdc920a0Smrg    if (!pdp->swapAvailable) {
851af69d88dSmrg       __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
852af69d88dSmrg			   __DRI2_THROTTLE_SWAPBUFFER, flush);
8533464ebd5Sriastradh    } else {
854af69d88dSmrg       __DRIcontext *ctx = dri2GetCurrentContext();
855af69d88dSmrg       unsigned flags = __DRI2_FLUSH_DRAWABLE;
856af69d88dSmrg       if (flush)
857af69d88dSmrg          flags |= __DRI2_FLUSH_CONTEXT;
858af69d88dSmrg       dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
859af69d88dSmrg
860af69d88dSmrg       ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
861af69d88dSmrg                                target_msc, divisor, remainder);
862cdc920a0Smrg    }
863cdc920a0Smrg
864af69d88dSmrg    if (psc->show_fps_interval) {
865af69d88dSmrg       show_fps(priv);
8663464ebd5Sriastradh    }
8673464ebd5Sriastradh
8683464ebd5Sriastradh    /* Old servers don't send invalidate events */
8693464ebd5Sriastradh    if (!pdp->invalidateAvailable)
8703464ebd5Sriastradh       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
871cdc920a0Smrg
872cdc920a0Smrg    return ret;
873cdc920a0Smrg}
874cdc920a0Smrg
875cdc920a0Smrgstatic __DRIbuffer *
876cdc920a0Smrgdri2GetBuffers(__DRIdrawable * driDrawable,
877cdc920a0Smrg               int *width, int *height,
878cdc920a0Smrg               unsigned int *attachments, int count,
879cdc920a0Smrg               int *out_count, void *loaderPrivate)
880cdc920a0Smrg{
8813464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
882cdc920a0Smrg   DRI2Buffer *buffers;
883cdc920a0Smrg
884cdc920a0Smrg   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
885cdc920a0Smrg                            width, height, attachments, count, out_count);
886cdc920a0Smrg   if (buffers == NULL)
887cdc920a0Smrg      return NULL;
888cdc920a0Smrg
889cdc920a0Smrg   pdraw->width = *width;
890cdc920a0Smrg   pdraw->height = *height;
891cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
892cdc920a0Smrg
893af69d88dSmrg   free(buffers);
894cdc920a0Smrg
895cdc920a0Smrg   return pdraw->buffers;
896cdc920a0Smrg}
897cdc920a0Smrg
898cdc920a0Smrgstatic __DRIbuffer *
899cdc920a0Smrgdri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
900cdc920a0Smrg                         int *width, int *height,
901cdc920a0Smrg                         unsigned int *attachments, int count,
902cdc920a0Smrg                         int *out_count, void *loaderPrivate)
903cdc920a0Smrg{
9043464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
905cdc920a0Smrg   DRI2Buffer *buffers;
906cdc920a0Smrg
907cdc920a0Smrg   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
908cdc920a0Smrg                                      pdraw->base.xDrawable,
909cdc920a0Smrg                                      width, height, attachments,
910cdc920a0Smrg                                      count, out_count);
911cdc920a0Smrg   if (buffers == NULL)
912cdc920a0Smrg      return NULL;
913cdc920a0Smrg
914cdc920a0Smrg   pdraw->width = *width;
915cdc920a0Smrg   pdraw->height = *height;
916cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
917cdc920a0Smrg
918af69d88dSmrg   free(buffers);
919cdc920a0Smrg
920cdc920a0Smrg   return pdraw->buffers;
921cdc920a0Smrg}
922cdc920a0Smrg
9233464ebd5Sriastradhstatic int
924cdc920a0Smrgdri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
925cdc920a0Smrg{
926af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
9273464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
9283464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
9293464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
9303464ebd5Sriastradh
9313464ebd5Sriastradh   if (psc->config)
9323464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
9333464ebd5Sriastradh				"vblank_mode", &vblank_mode);
9343464ebd5Sriastradh
9353464ebd5Sriastradh   switch (vblank_mode) {
9363464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
937af69d88dSmrg      if (interval != 0)
938af69d88dSmrg         return GLX_BAD_VALUE;
939af69d88dSmrg      break;
9403464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
9413464ebd5Sriastradh      if (interval <= 0)
9423464ebd5Sriastradh	 return GLX_BAD_VALUE;
9433464ebd5Sriastradh      break;
9443464ebd5Sriastradh   default:
9453464ebd5Sriastradh      break;
9463464ebd5Sriastradh   }
947cdc920a0Smrg
948af69d88dSmrg   xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
949cdc920a0Smrg   priv->swap_interval = interval;
9503464ebd5Sriastradh
9513464ebd5Sriastradh   return 0;
952cdc920a0Smrg}
953cdc920a0Smrg
9543464ebd5Sriastradhstatic int
955cdc920a0Smrgdri2GetSwapInterval(__GLXDRIdrawable *pdraw)
956cdc920a0Smrg{
9573464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
958cdc920a0Smrg
959cdc920a0Smrg  return priv->swap_interval;
960cdc920a0Smrg}
961cdc920a0Smrg
96201e04c3fSmrgstatic void
96301e04c3fSmrgdriSetBackgroundContext(void *loaderPrivate)
96401e04c3fSmrg{
96501e04c3fSmrg   struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
96601e04c3fSmrg   __glXSetCurrentContext(&pcp->base);
96701e04c3fSmrg}
96801e04c3fSmrg
96901e04c3fSmrgstatic GLboolean
97001e04c3fSmrgdriIsThreadSafe(void *loaderPrivate)
97101e04c3fSmrg{
97201e04c3fSmrg   struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
97301e04c3fSmrg   /* Check Xlib is running in thread safe mode
97401e04c3fSmrg    *
97501e04c3fSmrg    * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
97601e04c3fSmrg    * It wll be NULL if XInitThreads wasn't called.
97701e04c3fSmrg    */
97801e04c3fSmrg   return pcp->base.psc->dpy->lock_fns != NULL;
97901e04c3fSmrg}
98001e04c3fSmrg
981cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension = {
982af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
983af69d88dSmrg
984af69d88dSmrg   .getBuffers              = dri2GetBuffers,
985af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
986af69d88dSmrg   .getBuffersWithFormat    = dri2GetBuffersWithFormat,
987cdc920a0Smrg};
988cdc920a0Smrg
989cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
990af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
991af69d88dSmrg
992af69d88dSmrg   .getBuffers              = dri2GetBuffers,
993af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
994af69d88dSmrg   .getBuffersWithFormat    = NULL,
995cdc920a0Smrg};
996cdc920a0Smrg
9973464ebd5Sriastradhstatic const __DRIuseInvalidateExtension dri2UseInvalidate = {
998af69d88dSmrg   .base = { __DRI_USE_INVALIDATE, 1 }
999cdc920a0Smrg};
1000cdc920a0Smrg
100101e04c3fSmrgstatic const __DRIbackgroundCallableExtension driBackgroundCallable = {
100201e04c3fSmrg   .base = { __DRI_BACKGROUND_CALLABLE, 2 },
100301e04c3fSmrg
100401e04c3fSmrg   .setBackgroundContext    = driSetBackgroundContext,
100501e04c3fSmrg   .isThreadSafe            = driIsThreadSafe,
100601e04c3fSmrg};
100701e04c3fSmrg
1008cdc920a0Smrg_X_HIDDEN void
1009cdc920a0Smrgdri2InvalidateBuffers(Display *dpy, XID drawable)
1010cdc920a0Smrg{
10113464ebd5Sriastradh   __GLXDRIdrawable *pdraw =
10123464ebd5Sriastradh      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
10133464ebd5Sriastradh   struct dri2_screen *psc;
10143464ebd5Sriastradh   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
10153464ebd5Sriastradh
10163464ebd5Sriastradh   if (!pdraw)
10173464ebd5Sriastradh      return;
10183464ebd5Sriastradh
10193464ebd5Sriastradh   psc = (struct dri2_screen *) pdraw->psc;
1020cdc920a0Smrg
10213464ebd5Sriastradh   if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
10223464ebd5Sriastradh       psc->f->invalidate(pdp->driDrawable);
1023cdc920a0Smrg}
1024cdc920a0Smrg
10253464ebd5Sriastradhstatic void
10263464ebd5Sriastradhdri2_bind_tex_image(Display * dpy,
10273464ebd5Sriastradh		    GLXDrawable drawable,
10283464ebd5Sriastradh		    int buffer, const int *attrib_list)
10293464ebd5Sriastradh{
10303464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
10313464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
10323464ebd5Sriastradh   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
10333464ebd5Sriastradh   struct glx_display *dpyPriv = __glXInitialize(dpy);
10343464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
1035af69d88dSmrg   struct dri2_display *pdp;
10363464ebd5Sriastradh   struct dri2_screen *psc;
10373464ebd5Sriastradh
1038af69d88dSmrg   if (dpyPriv == NULL)
1039af69d88dSmrg       return;
1040af69d88dSmrg
1041af69d88dSmrg   pdp = (struct dri2_display *) dpyPriv->dri2Display;
1042af69d88dSmrg
10433464ebd5Sriastradh   if (pdraw != NULL) {
10443464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
10453464ebd5Sriastradh
10463464ebd5Sriastradh      if (!pdp->invalidateAvailable && psc->f &&
10473464ebd5Sriastradh           psc->f->base.version >= 3 && psc->f->invalidate)
10483464ebd5Sriastradh	 psc->f->invalidate(pdraw->driDrawable);
10493464ebd5Sriastradh
10503464ebd5Sriastradh      if (psc->texBuffer->base.version >= 2 &&
10513464ebd5Sriastradh	  psc->texBuffer->setTexBuffer2 != NULL) {
10523464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
10533464ebd5Sriastradh					   pdraw->base.textureTarget,
10543464ebd5Sriastradh					   pdraw->base.textureFormat,
10553464ebd5Sriastradh					   pdraw->driDrawable);
10563464ebd5Sriastradh      }
10573464ebd5Sriastradh      else {
10583464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
10593464ebd5Sriastradh					  pdraw->base.textureTarget,
10603464ebd5Sriastradh					  pdraw->driDrawable);
10613464ebd5Sriastradh      }
10623464ebd5Sriastradh   }
10633464ebd5Sriastradh}
10643464ebd5Sriastradh
10653464ebd5Sriastradhstatic void
10663464ebd5Sriastradhdri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
10673464ebd5Sriastradh{
10683464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
10693464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
10703464ebd5Sriastradh   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
10713464ebd5Sriastradh   struct glx_display *dpyPriv = __glXInitialize(dpy);
10723464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
10733464ebd5Sriastradh   struct dri2_screen *psc;
10743464ebd5Sriastradh
1075af69d88dSmrg   if (dpyPriv != NULL && pdraw != NULL) {
10763464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
10773464ebd5Sriastradh
10783464ebd5Sriastradh      if (psc->texBuffer->base.version >= 3 &&
10793464ebd5Sriastradh          psc->texBuffer->releaseTexBuffer != NULL) {
10803464ebd5Sriastradh         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
10813464ebd5Sriastradh                                           pdraw->base.textureTarget,
10823464ebd5Sriastradh                                           pdraw->driDrawable);
10833464ebd5Sriastradh      }
10843464ebd5Sriastradh   }
10853464ebd5Sriastradh}
10863464ebd5Sriastradh
10873464ebd5Sriastradhstatic const struct glx_context_vtable dri2_context_vtable = {
1088af69d88dSmrg   .destroy             = dri2_destroy_context,
1089af69d88dSmrg   .bind                = dri2_bind_context,
1090af69d88dSmrg   .unbind              = dri2_unbind_context,
1091af69d88dSmrg   .wait_gl             = dri2_wait_gl,
1092af69d88dSmrg   .wait_x              = dri2_wait_x,
1093af69d88dSmrg   .use_x_font          = DRI_glXUseXFont,
1094af69d88dSmrg   .bind_tex_image      = dri2_bind_tex_image,
1095af69d88dSmrg   .release_tex_image   = dri2_release_tex_image,
1096af69d88dSmrg   .get_proc_address    = NULL,
109701e04c3fSmrg   .interop_query_device_info = dri2_interop_query_device_info,
109801e04c3fSmrg   .interop_export_object = dri2_interop_export_object
10993464ebd5Sriastradh};
11003464ebd5Sriastradh
11013464ebd5Sriastradhstatic void
1102af69d88dSmrgdri2BindExtensions(struct dri2_screen *psc, struct glx_display * priv,
1103af69d88dSmrg                   const char *driverName)
11043464ebd5Sriastradh{
1105af69d88dSmrg   const struct dri2_display *const pdp = (struct dri2_display *)
1106af69d88dSmrg      priv->dri2Display;
1107af69d88dSmrg   const __DRIextension **extensions;
11083464ebd5Sriastradh   int i;
11093464ebd5Sriastradh
1110af69d88dSmrg   extensions = psc->core->getExtensions(psc->driScreen);
1111af69d88dSmrg
11123464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
11133464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
11143464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
11153464ebd5Sriastradh
1116af69d88dSmrg   /*
1117af69d88dSmrg    * GLX_INTEL_swap_event is broken on the server side, where it's
1118af69d88dSmrg    * currently unconditionally enabled. This completely breaks
1119af69d88dSmrg    * systems running on drivers which don't support that extension.
1120af69d88dSmrg    * There's no way to test for its presence on this side, so instead
1121af69d88dSmrg    * of disabling it unconditionally, just disable it for drivers
1122af69d88dSmrg    * which are known to not support it, or for DDX drivers supporting
1123af69d88dSmrg    * only an older (pre-ScheduleSwap) version of DRI2.
1124af69d88dSmrg    *
1125af69d88dSmrg    * This is a hack which is required until:
1126af69d88dSmrg    * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
1127af69d88dSmrg    * is merged and updated xserver makes it's way into distros:
1128af69d88dSmrg    */
1129af69d88dSmrg   if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
1130af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1131af69d88dSmrg   }
1132af69d88dSmrg
1133af69d88dSmrg   if (psc->dri2->base.version >= 3) {
1134af69d88dSmrg      const unsigned mask = psc->dri2->getAPIMask(psc->driScreen);
1135af69d88dSmrg
1136af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
1137af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
1138af69d88dSmrg
113901e04c3fSmrg      if ((mask & ((1 << __DRI_API_GLES) |
114001e04c3fSmrg                   (1 << __DRI_API_GLES2) |
114101e04c3fSmrg                   (1 << __DRI_API_GLES3))) != 0) {
114201e04c3fSmrg         __glXEnableDirectExtension(&psc->base,
114301e04c3fSmrg                                    "GLX_EXT_create_context_es_profile");
114401e04c3fSmrg         __glXEnableDirectExtension(&psc->base,
114501e04c3fSmrg                                    "GLX_EXT_create_context_es2_profile");
114601e04c3fSmrg      }
1147af69d88dSmrg   }
11483464ebd5Sriastradh
11493464ebd5Sriastradh   for (i = 0; extensions[i]; i++) {
11503464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
11513464ebd5Sriastradh	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
11523464ebd5Sriastradh	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
11533464ebd5Sriastradh      }
11543464ebd5Sriastradh
11553464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
11563464ebd5Sriastradh	 psc->f = (__DRI2flushExtension *) extensions[i];
11573464ebd5Sriastradh	 /* internal driver extension, no GL extension exposed */
11583464ebd5Sriastradh      }
11593464ebd5Sriastradh
11603464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
11613464ebd5Sriastradh	 psc->config = (__DRI2configQueryExtension *) extensions[i];
1162af69d88dSmrg
1163af69d88dSmrg      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
1164af69d88dSmrg	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
1165af69d88dSmrg
1166af69d88dSmrg      /* DRI2 version 3 is also required because
1167af69d88dSmrg       * GLX_ARB_create_context_robustness requires GLX_ARB_create_context.
1168af69d88dSmrg       */
1169af69d88dSmrg      if (psc->dri2->base.version >= 3
1170af69d88dSmrg          && strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1171af69d88dSmrg         __glXEnableDirectExtension(&psc->base,
1172af69d88dSmrg                                    "GLX_ARB_create_context_robustness");
1173af69d88dSmrg
11749f464c52Smaya      /* DRI2 version 3 is also required because
11759f464c52Smaya       * GLX_ARB_create_context_no_error requires GLX_ARB_create_context.
11769f464c52Smaya       */
11779f464c52Smaya      if (psc->dri2->base.version >= 3
11789f464c52Smaya          && strcmp(extensions[i]->name, __DRI2_NO_ERROR) == 0)
11799f464c52Smaya         __glXEnableDirectExtension(&psc->base,
11809f464c52Smaya                                    "GLX_ARB_create_context_no_error");
11819f464c52Smaya
1182af69d88dSmrg      /* DRI2 version 3 is also required because GLX_MESA_query_renderer
1183af69d88dSmrg       * requires GLX_ARB_create_context_profile.
1184af69d88dSmrg       */
1185af69d88dSmrg      if (psc->dri2->base.version >= 3
1186af69d88dSmrg          && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
1187af69d88dSmrg         psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
1188af69d88dSmrg         __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
1189af69d88dSmrg      }
119001e04c3fSmrg
119101e04c3fSmrg      if (strcmp(extensions[i]->name, __DRI2_INTEROP) == 0)
119201e04c3fSmrg	 psc->interop = (__DRI2interopExtension*)extensions[i];
119301e04c3fSmrg
119401e04c3fSmrg      /* DRI2 version 3 is also required because
119501e04c3fSmrg       * GLX_ARB_control_flush_control requires GLX_ARB_create_context.
119601e04c3fSmrg       */
119701e04c3fSmrg      if (psc->dri2->base.version >= 3
119801e04c3fSmrg          && strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0)
119901e04c3fSmrg         __glXEnableDirectExtension(&psc->base,
120001e04c3fSmrg                                    "GLX_ARB_context_flush_control");
12013464ebd5Sriastradh   }
12023464ebd5Sriastradh}
12033464ebd5Sriastradh
12043464ebd5Sriastradhstatic const struct glx_screen_vtable dri2_screen_vtable = {
1205af69d88dSmrg   .create_context         = dri2_create_context,
1206af69d88dSmrg   .create_context_attribs = dri2_create_context_attribs,
1207af69d88dSmrg   .query_renderer_integer = dri2_query_renderer_integer,
1208af69d88dSmrg   .query_renderer_string  = dri2_query_renderer_string,
12093464ebd5Sriastradh};
12103464ebd5Sriastradh
12113464ebd5Sriastradhstatic struct glx_screen *
12123464ebd5Sriastradhdri2CreateScreen(int screen, struct glx_display * priv)
1213cdc920a0Smrg{
1214cdc920a0Smrg   const __DRIconfig **driver_configs;
1215cdc920a0Smrg   const __DRIextension **extensions;
12163464ebd5Sriastradh   const struct dri2_display *const pdp = (struct dri2_display *)
1217cdc920a0Smrg      priv->dri2Display;
12183464ebd5Sriastradh   struct dri2_screen *psc;
1219cdc920a0Smrg   __GLXDRIscreen *psp;
1220af69d88dSmrg   struct glx_config *configs = NULL, *visuals = NULL;
1221af69d88dSmrg   char *driverName = NULL, *loader_driverName, *deviceName, *tmp;
1222cdc920a0Smrg   drm_magic_t magic;
1223cdc920a0Smrg   int i;
122401e04c3fSmrg   unsigned char disable;
1225cdc920a0Smrg
1226af69d88dSmrg   psc = calloc(1, sizeof *psc);
12273464ebd5Sriastradh   if (psc == NULL)
12283464ebd5Sriastradh      return NULL;
12293464ebd5Sriastradh
12303464ebd5Sriastradh   psc->fd = -1;
12313464ebd5Sriastradh
12323464ebd5Sriastradh   if (!glx_screen_init(&psc->base, screen, priv)) {
1233af69d88dSmrg      free(psc);
1234cdc920a0Smrg      return NULL;
12353464ebd5Sriastradh   }
1236cdc920a0Smrg
12373464ebd5Sriastradh   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
1238cdc920a0Smrg		    &driverName, &deviceName)) {
12393464ebd5Sriastradh      glx_screen_cleanup(&psc->base);
1240af69d88dSmrg      free(psc);
1241af69d88dSmrg      InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
1242cdc920a0Smrg      return NULL;
1243cdc920a0Smrg   }
1244cdc920a0Smrg
124501e04c3fSmrg   psc->fd = loader_open_device(deviceName);
1246af69d88dSmrg   if (psc->fd < 0) {
1247af69d88dSmrg      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
1248af69d88dSmrg      goto handle_error;
1249af69d88dSmrg   }
1250af69d88dSmrg
1251af69d88dSmrg   if (drmGetMagic(psc->fd, &magic)) {
1252af69d88dSmrg      ErrorMessageF("failed to get magic\n");
1253af69d88dSmrg      goto handle_error;
1254af69d88dSmrg   }
1255af69d88dSmrg
1256af69d88dSmrg   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
1257af69d88dSmrg      ErrorMessageF("failed to authenticate magic %d\n", magic);
1258af69d88dSmrg      goto handle_error;
1259af69d88dSmrg   }
1260af69d88dSmrg
1261af69d88dSmrg   /* If Mesa knows about the appropriate driver for this fd, then trust it.
1262af69d88dSmrg    * Otherwise, default to the server's value.
1263af69d88dSmrg    */
126401e04c3fSmrg   loader_driverName = loader_get_driver_for_fd(psc->fd);
1265af69d88dSmrg   if (loader_driverName) {
1266af69d88dSmrg      free(driverName);
1267af69d88dSmrg      driverName = loader_driverName;
1268af69d88dSmrg   }
1269af69d88dSmrg
12709f464c52Smaya   extensions = driOpenDriver(driverName, &psc->driver);
1271af69d88dSmrg   if (extensions == NULL)
1272cdc920a0Smrg      goto handle_error;
1273cdc920a0Smrg
1274cdc920a0Smrg   for (i = 0; extensions[i]; i++) {
1275cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1276cdc920a0Smrg	 psc->core = (__DRIcoreExtension *) extensions[i];
1277cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
1278cdc920a0Smrg	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
1279cdc920a0Smrg   }
1280cdc920a0Smrg
1281cdc920a0Smrg   if (psc->core == NULL || psc->dri2 == NULL) {
1282cdc920a0Smrg      ErrorMessageF("core dri or dri2 extension not found\n");
1283cdc920a0Smrg      goto handle_error;
1284cdc920a0Smrg   }
1285cdc920a0Smrg
1286af69d88dSmrg   if (psc->dri2->base.version >= 4) {
1287af69d88dSmrg      psc->driScreen =
1288af69d88dSmrg         psc->dri2->createNewScreen2(screen, psc->fd,
1289af69d88dSmrg                                     (const __DRIextension **)
1290af69d88dSmrg                                     &pdp->loader_extensions[0],
1291af69d88dSmrg                                     extensions,
1292af69d88dSmrg                                     &driver_configs, psc);
1293af69d88dSmrg   } else {
1294af69d88dSmrg      psc->driScreen =
1295af69d88dSmrg         psc->dri2->createNewScreen(screen, psc->fd,
1296af69d88dSmrg                                    (const __DRIextension **)
1297af69d88dSmrg                                    &pdp->loader_extensions[0],
1298af69d88dSmrg                                    &driver_configs, psc);
1299cdc920a0Smrg   }
1300cdc920a0Smrg
1301af69d88dSmrg   if (psc->driScreen == NULL) {
1302af69d88dSmrg      ErrorMessageF("failed to create dri screen\n");
1303cdc920a0Smrg      goto handle_error;
1304cdc920a0Smrg   }
1305cdc920a0Smrg
1306af69d88dSmrg   dri2BindExtensions(psc, priv, driverName);
1307cdc920a0Smrg
1308af69d88dSmrg   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1309af69d88dSmrg   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1310cdc920a0Smrg
1311af69d88dSmrg   if (!configs || !visuals) {
1312af69d88dSmrg       ErrorMessageF("No matching fbConfigs or visuals found\n");
1313af69d88dSmrg       goto handle_error;
1314cdc920a0Smrg   }
1315cdc920a0Smrg
1316af69d88dSmrg   glx_config_destroy_list(psc->base.configs);
1317af69d88dSmrg   psc->base.configs = configs;
1318af69d88dSmrg   glx_config_destroy_list(psc->base.visuals);
1319af69d88dSmrg   psc->base.visuals = visuals;
1320cdc920a0Smrg
1321cdc920a0Smrg   psc->driver_configs = driver_configs;
1322cdc920a0Smrg
13233464ebd5Sriastradh   psc->base.vtable = &dri2_screen_vtable;
13243464ebd5Sriastradh   psp = &psc->vtable;
13253464ebd5Sriastradh   psc->base.driScreen = psp;
1326cdc920a0Smrg   psp->destroyScreen = dri2DestroyScreen;
1327cdc920a0Smrg   psp->createDrawable = dri2CreateDrawable;
1328cdc920a0Smrg   psp->swapBuffers = dri2SwapBuffers;
1329cdc920a0Smrg   psp->getDrawableMSC = NULL;
1330cdc920a0Smrg   psp->waitForMSC = NULL;
1331cdc920a0Smrg   psp->waitForSBC = NULL;
1332cdc920a0Smrg   psp->setSwapInterval = NULL;
1333cdc920a0Smrg   psp->getSwapInterval = NULL;
1334af69d88dSmrg   psp->getBufferAge = NULL;
1335cdc920a0Smrg
1336cdc920a0Smrg   if (pdp->driMinor >= 2) {
1337cdc920a0Smrg      psp->getDrawableMSC = dri2DrawableGetMSC;
1338cdc920a0Smrg      psp->waitForMSC = dri2WaitForMSC;
1339cdc920a0Smrg      psp->waitForSBC = dri2WaitForSBC;
1340cdc920a0Smrg      psp->setSwapInterval = dri2SetSwapInterval;
1341cdc920a0Smrg      psp->getSwapInterval = dri2GetSwapInterval;
134201e04c3fSmrg      if (psc->config->configQueryb(psc->driScreen,
134301e04c3fSmrg                                    "glx_disable_oml_sync_control",
134401e04c3fSmrg                                    &disable) || !disable)
134501e04c3fSmrg         __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1346cdc920a0Smrg   }
1347cdc920a0Smrg
134801e04c3fSmrg   if (psc->config->configQueryb(psc->driScreen,
134901e04c3fSmrg                                 "glx_disable_sgi_video_sync",
135001e04c3fSmrg                                 &disable) || !disable)
135101e04c3fSmrg      __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
135201e04c3fSmrg
135301e04c3fSmrg   /* DRI2 supports SubBuffer through DRI2CopyRegion, so it's always
1354cdc920a0Smrg    * available.*/
1355cdc920a0Smrg   psp->copySubBuffer = dri2CopySubBuffer;
13563464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1357cdc920a0Smrg
1358af69d88dSmrg   free(driverName);
1359af69d88dSmrg   free(deviceName);
1360af69d88dSmrg
1361af69d88dSmrg   tmp = getenv("LIBGL_SHOW_FPS");
1362af69d88dSmrg   psc->show_fps_interval = (tmp) ? atoi(tmp) : 0;
1363af69d88dSmrg   if (psc->show_fps_interval < 0)
1364af69d88dSmrg      psc->show_fps_interval = 0;
1365cdc920a0Smrg
136601e04c3fSmrg   InfoMessageF("Using DRI2 for screen %d\n", screen);
136701e04c3fSmrg
13683464ebd5Sriastradh   return &psc->base;
1369cdc920a0Smrg
1370cdc920a0Smrghandle_error:
1371af69d88dSmrg   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1372af69d88dSmrg
1373af69d88dSmrg   if (configs)
1374af69d88dSmrg       glx_config_destroy_list(configs);
1375af69d88dSmrg   if (visuals)
1376af69d88dSmrg       glx_config_destroy_list(visuals);
1377af69d88dSmrg   if (psc->driScreen)
1378af69d88dSmrg       psc->core->destroyScreen(psc->driScreen);
1379af69d88dSmrg   psc->driScreen = NULL;
13803464ebd5Sriastradh   if (psc->fd >= 0)
13813464ebd5Sriastradh      close(psc->fd);
13823464ebd5Sriastradh   if (psc->driver)
13833464ebd5Sriastradh      dlclose(psc->driver);
1384af69d88dSmrg
1385af69d88dSmrg   free(driverName);
1386af69d88dSmrg   free(deviceName);
13873464ebd5Sriastradh   glx_screen_cleanup(&psc->base);
1388af69d88dSmrg   free(psc);
1389cdc920a0Smrg
1390cdc920a0Smrg   return NULL;
1391cdc920a0Smrg}
1392cdc920a0Smrg
1393cdc920a0Smrg/* Called from __glXFreeDisplayPrivate.
1394cdc920a0Smrg */
1395cdc920a0Smrgstatic void
1396cdc920a0Smrgdri2DestroyDisplay(__GLXDRIdisplay * dpy)
1397cdc920a0Smrg{
13983464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) dpy;
13993464ebd5Sriastradh
14003464ebd5Sriastradh   __glxHashDestroy(pdp->dri2Hash);
1401af69d88dSmrg   free(dpy);
1402cdc920a0Smrg}
1403cdc920a0Smrg
14043464ebd5Sriastradh_X_HIDDEN __GLXDRIdrawable *
14053464ebd5Sriastradhdri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
14063464ebd5Sriastradh{
14073464ebd5Sriastradh   struct glx_display *d = __glXInitialize(dpy);
14083464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
14093464ebd5Sriastradh   __GLXDRIdrawable *pdraw;
14103464ebd5Sriastradh
14113464ebd5Sriastradh   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
14123464ebd5Sriastradh      return pdraw;
14133464ebd5Sriastradh
14143464ebd5Sriastradh   return NULL;
14153464ebd5Sriastradh}
14163464ebd5Sriastradh
1417cdc920a0Smrg/*
1418cdc920a0Smrg * Allocate, initialize and return a __DRIdisplayPrivate object.
1419cdc920a0Smrg * This is called from __glXInitialize() when we are given a new
1420cdc920a0Smrg * display pointer.
1421cdc920a0Smrg */
1422cdc920a0Smrg_X_HIDDEN __GLXDRIdisplay *
1423cdc920a0Smrgdri2CreateDisplay(Display * dpy)
1424cdc920a0Smrg{
14253464ebd5Sriastradh   struct dri2_display *pdp;
14263464ebd5Sriastradh   int eventBase, errorBase, i;
1427cdc920a0Smrg
1428cdc920a0Smrg   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1429cdc920a0Smrg      return NULL;
1430cdc920a0Smrg
1431af69d88dSmrg   pdp = malloc(sizeof *pdp);
1432cdc920a0Smrg   if (pdp == NULL)
1433cdc920a0Smrg      return NULL;
1434cdc920a0Smrg
1435cdc920a0Smrg   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1436af69d88dSmrg      free(pdp);
1437cdc920a0Smrg      return NULL;
1438cdc920a0Smrg   }
1439cdc920a0Smrg
1440cdc920a0Smrg   pdp->driPatch = 0;
1441cdc920a0Smrg   pdp->swapAvailable = (pdp->driMinor >= 2);
1442cdc920a0Smrg   pdp->invalidateAvailable = (pdp->driMinor >= 3);
1443cdc920a0Smrg
1444cdc920a0Smrg   pdp->base.destroyDisplay = dri2DestroyDisplay;
1445cdc920a0Smrg   pdp->base.createScreen = dri2CreateScreen;
1446cdc920a0Smrg
14473464ebd5Sriastradh   i = 0;
14483464ebd5Sriastradh   if (pdp->driMinor < 1)
14493464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
14503464ebd5Sriastradh   else
14513464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
14523464ebd5Sriastradh
14533464ebd5Sriastradh   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1454af69d88dSmrg
145501e04c3fSmrg   pdp->loader_extensions[i++] = &driBackgroundCallable.base;
145601e04c3fSmrg
14573464ebd5Sriastradh   pdp->loader_extensions[i++] = NULL;
14583464ebd5Sriastradh
14593464ebd5Sriastradh   pdp->dri2Hash = __glxHashCreate();
14603464ebd5Sriastradh   if (pdp->dri2Hash == NULL) {
1461af69d88dSmrg      free(pdp);
14623464ebd5Sriastradh      return NULL;
14633464ebd5Sriastradh   }
14643464ebd5Sriastradh
1465cdc920a0Smrg   return &pdp->base;
1466cdc920a0Smrg}
1467cdc920a0Smrg
1468cdc920a0Smrg#endif /* GLX_DIRECT_RENDERING */
1469