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
537ec681f3Smrg/* From driconf.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
179af69d88dSmrgstatic struct glx_context *
180af69d88dSmrgdri2_create_context_attribs(struct glx_screen *base,
181af69d88dSmrg			    struct glx_config *config_base,
182af69d88dSmrg			    struct glx_context *shareList,
183af69d88dSmrg			    unsigned num_attribs,
184af69d88dSmrg			    const uint32_t *attribs,
185af69d88dSmrg			    unsigned *error)
186af69d88dSmrg{
187af69d88dSmrg   struct dri2_context *pcp = NULL;
188af69d88dSmrg   struct dri2_context *pcp_shared = NULL;
189af69d88dSmrg   struct dri2_screen *psc = (struct dri2_screen *) base;
190af69d88dSmrg   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
191af69d88dSmrg   __DRIcontext *shared = NULL;
192af69d88dSmrg
1937ec681f3Smrg   struct dri_ctx_attribs dca;
19401e04c3fSmrg   uint32_t ctx_attribs[2 * 6];
195af69d88dSmrg   unsigned num_ctx_attribs = 0;
196af69d88dSmrg
1977ec681f3Smrg   *error = dri_convert_glx_attribs(num_attribs, attribs, &dca);
1987ec681f3Smrg   if (*error != __DRI_CTX_ERROR_SUCCESS)
199af69d88dSmrg      goto error_exit;
200af69d88dSmrg
2017ec681f3Smrg   if (!dri2_check_no_error(dca.flags, shareList, dca.major_ver, error)) {
2029f464c52Smaya      goto error_exit;
2039f464c52Smaya   }
2049f464c52Smaya
205af69d88dSmrg   /* Check the renderType value */
2067ec681f3Smrg   if (!validate_renderType_against_config(config_base, dca.render_type))
207af69d88dSmrg       goto error_exit;
208af69d88dSmrg
209af69d88dSmrg   if (shareList) {
2107ec681f3Smrg      /* We can't share with an indirect context */
2117ec681f3Smrg      if (!shareList->isDirect)
2127ec681f3Smrg         return NULL;
2137ec681f3Smrg
214af69d88dSmrg      pcp_shared = (struct dri2_context *) shareList;
215af69d88dSmrg      shared = pcp_shared->driContext;
216af69d88dSmrg   }
217af69d88dSmrg
218af69d88dSmrg   pcp = calloc(1, sizeof *pcp);
219af69d88dSmrg   if (pcp == NULL) {
220af69d88dSmrg      *error = __DRI_CTX_ERROR_NO_MEMORY;
221af69d88dSmrg      goto error_exit;
222af69d88dSmrg   }
223af69d88dSmrg
22401e04c3fSmrg   if (!glx_context_init(&pcp->base, &psc->base, config_base))
225af69d88dSmrg      goto error_exit;
226af69d88dSmrg
227af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
2287ec681f3Smrg   ctx_attribs[num_ctx_attribs++] = dca.major_ver;
229af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
2307ec681f3Smrg   ctx_attribs[num_ctx_attribs++] = dca.minor_ver;
231af69d88dSmrg
232af69d88dSmrg   /* Only send a value when the non-default value is requested.  By doing
233af69d88dSmrg    * this we don't have to check the driver's DRI2 version before sending the
234af69d88dSmrg    * default value.
235af69d88dSmrg    */
2367ec681f3Smrg   if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
237af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
2387ec681f3Smrg      ctx_attribs[num_ctx_attribs++] = dca.reset;
239af69d88dSmrg   }
240af69d88dSmrg
2417ec681f3Smrg   if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
24201e04c3fSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
2437ec681f3Smrg      ctx_attribs[num_ctx_attribs++] = dca.release;
24401e04c3fSmrg   }
24501e04c3fSmrg
2467ec681f3Smrg   if (dca.flags != 0) {
247af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
248af69d88dSmrg
249af69d88dSmrg      /* The current __DRI_CTX_FLAG_* values are identical to the
250af69d88dSmrg       * GLX_CONTEXT_*_BIT values.
251af69d88dSmrg       */
2527ec681f3Smrg      ctx_attribs[num_ctx_attribs++] = dca.flags;
253af69d88dSmrg   }
254af69d88dSmrg
255af69d88dSmrg   /* The renderType is retrieved from attribs, or set to default
256af69d88dSmrg    *  of GLX_RGBA_TYPE.
257af69d88dSmrg    */
2587ec681f3Smrg   pcp->base.renderType = dca.render_type;
259af69d88dSmrg
2607ec681f3Smrg   if (dca.flags & __DRI_CTX_FLAG_NO_ERROR)
2619f464c52Smaya      pcp->base.noError = GL_TRUE;
2629f464c52Smaya
263af69d88dSmrg   pcp->driContext =
264af69d88dSmrg      (*psc->dri2->createContextAttribs) (psc->driScreen,
2657ec681f3Smrg					  dca.api,
26601e04c3fSmrg					  config ? config->driConfig : NULL,
267af69d88dSmrg					  shared,
268af69d88dSmrg					  num_ctx_attribs / 2,
269af69d88dSmrg					  ctx_attribs,
270af69d88dSmrg					  error,
271af69d88dSmrg					  pcp);
272af69d88dSmrg
273af69d88dSmrg   if (pcp->driContext == NULL)
274af69d88dSmrg      goto error_exit;
275af69d88dSmrg
2767ec681f3Smrg   pcp->base.vtable = base->context_vtable;
277af69d88dSmrg
278af69d88dSmrg   return &pcp->base;
279af69d88dSmrg
280af69d88dSmrgerror_exit:
281af69d88dSmrg   free(pcp);
282af69d88dSmrg
283af69d88dSmrg   return NULL;
284af69d88dSmrg}
285af69d88dSmrg
286cdc920a0Smrgstatic void
2873464ebd5Sriastradhdri2DestroyDrawable(__GLXDRIdrawable *base)
288cdc920a0Smrg{
2893464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
2903464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
2913464ebd5Sriastradh   struct glx_display *dpyPriv = psc->base.display;
2923464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
2933464ebd5Sriastradh
2943464ebd5Sriastradh   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
2953464ebd5Sriastradh   (*psc->core->destroyDrawable) (pdraw->driDrawable);
2963464ebd5Sriastradh
2973464ebd5Sriastradh   /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
2983464ebd5Sriastradh    * now, as the application explicitly asked to destroy the GLX
2993464ebd5Sriastradh    * drawable.  Otherwise, for legacy drawables, we let the DRI2
3003464ebd5Sriastradh    * drawable linger on the server, since there's no good way of
3013464ebd5Sriastradh    * knowing when the application is done with it.  The server will
3023464ebd5Sriastradh    * destroy the DRI2 drawable when it destroys the X drawable or the
3033464ebd5Sriastradh    * client exits anyway. */
3043464ebd5Sriastradh   if (pdraw->base.xDrawable != pdraw->base.drawable)
3053464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
306cdc920a0Smrg
307af69d88dSmrg   free(pdraw);
308cdc920a0Smrg}
309cdc920a0Smrg
310cdc920a0Smrgstatic __GLXDRIdrawable *
3113464ebd5Sriastradhdri2CreateDrawable(struct glx_screen *base, XID xDrawable,
3123464ebd5Sriastradh		   GLXDrawable drawable, struct glx_config *config_base)
313cdc920a0Smrg{
3143464ebd5Sriastradh   struct dri2_drawable *pdraw;
3153464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
3163464ebd5Sriastradh   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
3173464ebd5Sriastradh   struct glx_display *dpyPriv;
3183464ebd5Sriastradh   struct dri2_display *pdp;
3193464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
320cdc920a0Smrg
321af69d88dSmrg   dpyPriv = __glXInitialize(psc->base.dpy);
322af69d88dSmrg   if (dpyPriv == NULL)
323af69d88dSmrg      return NULL;
324af69d88dSmrg
325af69d88dSmrg   pdraw = calloc(1, sizeof(*pdraw));
326cdc920a0Smrg   if (!pdraw)
327cdc920a0Smrg      return NULL;
328cdc920a0Smrg
329cdc920a0Smrg   pdraw->base.destroyDrawable = dri2DestroyDrawable;
330cdc920a0Smrg   pdraw->base.xDrawable = xDrawable;
331cdc920a0Smrg   pdraw->base.drawable = drawable;
3323464ebd5Sriastradh   pdraw->base.psc = &psc->base;
333cdc920a0Smrg   pdraw->bufferCount = 0;
3343464ebd5Sriastradh   pdraw->swap_interval = 1; /* default may be overridden below */
335cdc920a0Smrg   pdraw->have_back = 0;
336cdc920a0Smrg
3373464ebd5Sriastradh   if (psc->config)
3383464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
3393464ebd5Sriastradh				"vblank_mode", &vblank_mode);
3403464ebd5Sriastradh
3413464ebd5Sriastradh   switch (vblank_mode) {
3423464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
3433464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
3443464ebd5Sriastradh      pdraw->swap_interval = 0;
3453464ebd5Sriastradh      break;
3463464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
3473464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
3483464ebd5Sriastradh   default:
3493464ebd5Sriastradh      pdraw->swap_interval = 1;
3503464ebd5Sriastradh      break;
3513464ebd5Sriastradh   }
3523464ebd5Sriastradh
3533464ebd5Sriastradh   DRI2CreateDrawable(psc->base.dpy, xDrawable);
35401e04c3fSmrg   pdp = (struct dri2_display *)dpyPriv->dri2Display;
355cdc920a0Smrg   /* Create a new drawable */
3563464ebd5Sriastradh   pdraw->driDrawable =
3573464ebd5Sriastradh      (*psc->dri2->createNewDrawable) (psc->driScreen,
358cdc920a0Smrg                                       config->driConfig, pdraw);
359cdc920a0Smrg
3603464ebd5Sriastradh   if (!pdraw->driDrawable) {
3613464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
362af69d88dSmrg      free(pdraw);
363cdc920a0Smrg      return NULL;
364cdc920a0Smrg   }
365cdc920a0Smrg
3663464ebd5Sriastradh   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
3673464ebd5Sriastradh      (*psc->core->destroyDrawable) (pdraw->driDrawable);
3683464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
369af69d88dSmrg      free(pdraw);
3703464ebd5Sriastradh      return None;
3713464ebd5Sriastradh   }
3723464ebd5Sriastradh
373cdc920a0Smrg   /*
374cdc920a0Smrg    * Make sure server has the same swap interval we do for the new
375cdc920a0Smrg    * drawable.
376cdc920a0Smrg    */
377af69d88dSmrg   if (psc->vtable.setSwapInterval)
378af69d88dSmrg      psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
379cdc920a0Smrg
380cdc920a0Smrg   return &pdraw->base;
381cdc920a0Smrg}
382cdc920a0Smrg
383cdc920a0Smrgstatic int
3843464ebd5Sriastradhdri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
385cdc920a0Smrg		   int64_t *ust, int64_t *msc, int64_t *sbc)
386cdc920a0Smrg{
387af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
388af69d88dSmrg   xcb_dri2_get_msc_cookie_t get_msc_cookie;
389af69d88dSmrg   xcb_dri2_get_msc_reply_t *get_msc_reply;
3903464ebd5Sriastradh
391af69d88dSmrg   get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
392af69d88dSmrg   get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
3933464ebd5Sriastradh
394af69d88dSmrg   if (!get_msc_reply)
395af69d88dSmrg      return 0;
396cdc920a0Smrg
397af69d88dSmrg   *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
398af69d88dSmrg   *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
399af69d88dSmrg   *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
400af69d88dSmrg   free(get_msc_reply);
401cdc920a0Smrg
402af69d88dSmrg   return 1;
403af69d88dSmrg}
404cdc920a0Smrg
405cdc920a0Smrgstatic int
406cdc920a0Smrgdri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
407cdc920a0Smrg	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
408cdc920a0Smrg{
409af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
410af69d88dSmrg   xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
411af69d88dSmrg   xcb_dri2_wait_msc_reply_t *wait_msc_reply;
412af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
413af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
414af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
415af69d88dSmrg
416af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
417af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
418af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
419af69d88dSmrg
420af69d88dSmrg   wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
421af69d88dSmrg                                                 target_msc_hi, target_msc_lo,
422af69d88dSmrg                                                 divisor_hi, divisor_lo,
423af69d88dSmrg                                                 remainder_hi, remainder_lo);
424af69d88dSmrg   wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
425af69d88dSmrg
426af69d88dSmrg   if (!wait_msc_reply)
427af69d88dSmrg      return 0;
428af69d88dSmrg
429af69d88dSmrg   *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
430af69d88dSmrg   *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
431af69d88dSmrg   *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
432af69d88dSmrg   free(wait_msc_reply);
433af69d88dSmrg
434af69d88dSmrg   return 1;
435cdc920a0Smrg}
436cdc920a0Smrg
437cdc920a0Smrgstatic int
438cdc920a0Smrgdri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
439cdc920a0Smrg	       int64_t *msc, int64_t *sbc)
440cdc920a0Smrg{
441af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
442af69d88dSmrg   xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
443af69d88dSmrg   xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
444af69d88dSmrg   uint32_t target_sbc_hi, target_sbc_lo;
4453464ebd5Sriastradh
446af69d88dSmrg   split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
4473464ebd5Sriastradh
448af69d88dSmrg   wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
449af69d88dSmrg                                                 target_sbc_hi, target_sbc_lo);
450af69d88dSmrg   wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
451af69d88dSmrg
452af69d88dSmrg   if (!wait_sbc_reply)
453af69d88dSmrg      return 0;
454af69d88dSmrg
455af69d88dSmrg   *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
456af69d88dSmrg   *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
457af69d88dSmrg   *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
458af69d88dSmrg   free(wait_sbc_reply);
459af69d88dSmrg
460af69d88dSmrg   return 1;
461cdc920a0Smrg}
462cdc920a0Smrg
463af69d88dSmrgstatic __DRIcontext *
464af69d88dSmrgdri2GetCurrentContext()
465af69d88dSmrg{
466af69d88dSmrg   struct glx_context *gc = __glXGetCurrentContext();
467af69d88dSmrg   struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
468af69d88dSmrg
46901e04c3fSmrg   return (gc != &dummyContext) ? dri2Ctx->driContext : NULL;
470af69d88dSmrg}
471af69d88dSmrg
472af69d88dSmrg/**
473af69d88dSmrg * dri2Throttle - Request driver throttling
474af69d88dSmrg *
475af69d88dSmrg * This function uses the DRI2 throttle extension to give the
476af69d88dSmrg * driver the opportunity to throttle on flush front, copysubbuffer
477af69d88dSmrg * and swapbuffers.
478af69d88dSmrg */
479af69d88dSmrgstatic void
480af69d88dSmrgdri2Throttle(struct dri2_screen *psc,
481af69d88dSmrg	     struct dri2_drawable *draw,
482af69d88dSmrg	     enum __DRI2throttleReason reason)
483af69d88dSmrg{
484af69d88dSmrg   if (psc->throttle) {
485af69d88dSmrg      __DRIcontext *ctx = dri2GetCurrentContext();
486af69d88dSmrg
487af69d88dSmrg      psc->throttle->throttle(ctx, draw->driDrawable, reason);
488af69d88dSmrg   }
489af69d88dSmrg}
490cdc920a0Smrg
491af69d88dSmrg/**
492af69d88dSmrg * Asks the driver to flush any queued work necessary for serializing with the
493af69d88dSmrg * X command stream, and optionally the slightly more strict requirement of
494af69d88dSmrg * glFlush() equivalence (which would require flushing even if nothing had
495af69d88dSmrg * been drawn to a window system framebuffer, for example).
496af69d88dSmrg */
497cdc920a0Smrgstatic void
498af69d88dSmrgdri2Flush(struct dri2_screen *psc,
499af69d88dSmrg          __DRIcontext *ctx,
500af69d88dSmrg          struct dri2_drawable *draw,
501af69d88dSmrg          unsigned flags,
502af69d88dSmrg          enum __DRI2throttleReason throttle_reason)
503af69d88dSmrg{
504af69d88dSmrg   if (ctx && psc->f && psc->f->base.version >= 4) {
505af69d88dSmrg      psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason);
506af69d88dSmrg   } else {
507af69d88dSmrg      if (flags & __DRI2_FLUSH_CONTEXT)
508af69d88dSmrg         glFlush();
509af69d88dSmrg
510af69d88dSmrg      if (psc->f)
511af69d88dSmrg         psc->f->flush(draw->driDrawable);
512af69d88dSmrg
513af69d88dSmrg      dri2Throttle(psc, draw, throttle_reason);
514af69d88dSmrg   }
515af69d88dSmrg}
516af69d88dSmrg
517af69d88dSmrgstatic void
518af69d88dSmrg__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
519af69d88dSmrg		    int width, int height,
520af69d88dSmrg		    enum __DRI2throttleReason reason, Bool flush)
521cdc920a0Smrg{
5223464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
5233464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
524cdc920a0Smrg   XRectangle xrect;
525cdc920a0Smrg   XserverRegion region;
526af69d88dSmrg   __DRIcontext *ctx = dri2GetCurrentContext();
527af69d88dSmrg   unsigned flags;
528cdc920a0Smrg
529cdc920a0Smrg   /* Check we have the right attachments */
530cdc920a0Smrg   if (!priv->have_back)
531cdc920a0Smrg      return;
532cdc920a0Smrg
533cdc920a0Smrg   xrect.x = x;
534cdc920a0Smrg   xrect.y = priv->height - y - height;
535cdc920a0Smrg   xrect.width = width;
536cdc920a0Smrg   xrect.height = height;
537cdc920a0Smrg
538af69d88dSmrg   flags = __DRI2_FLUSH_DRAWABLE;
539af69d88dSmrg   if (flush)
540af69d88dSmrg      flags |= __DRI2_FLUSH_CONTEXT;
5417ec681f3Smrg   dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_COPYSUBBUFFER);
542cdc920a0Smrg
5433464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
5443464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
545cdc920a0Smrg                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
546cdc920a0Smrg
547cdc920a0Smrg   /* Refresh the fake front (if present) after we just damaged the real
548cdc920a0Smrg    * front.
549cdc920a0Smrg    */
5503464ebd5Sriastradh   if (priv->have_fake_front)
5513464ebd5Sriastradh      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
5523464ebd5Sriastradh		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
5533464ebd5Sriastradh
5543464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
555cdc920a0Smrg}
556cdc920a0Smrg
557af69d88dSmrgstatic void
558af69d88dSmrgdri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
559af69d88dSmrg		  int width, int height, Bool flush)
560af69d88dSmrg{
561af69d88dSmrg   __dri2CopySubBuffer(pdraw, x, y, width, height,
562af69d88dSmrg		       __DRI2_THROTTLE_COPYSUBBUFFER, flush);
563af69d88dSmrg}
564af69d88dSmrg
565af69d88dSmrg
566cdc920a0Smrgstatic void
5673464ebd5Sriastradhdri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
568cdc920a0Smrg{
569cdc920a0Smrg   XRectangle xrect;
570cdc920a0Smrg   XserverRegion region;
5713464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
572cdc920a0Smrg
573cdc920a0Smrg   xrect.x = 0;
574cdc920a0Smrg   xrect.y = 0;
575cdc920a0Smrg   xrect.width = priv->width;
576cdc920a0Smrg   xrect.height = priv->height;
577cdc920a0Smrg
5783464ebd5Sriastradh   if (psc->f)
5793464ebd5Sriastradh      (*psc->f->flush) (priv->driDrawable);
580cdc920a0Smrg
5813464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
5823464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
5833464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
5843464ebd5Sriastradh
585cdc920a0Smrg}
586cdc920a0Smrg
587cdc920a0Smrgstatic void
5883464ebd5Sriastradhdri2_wait_x(struct glx_context *gc)
589cdc920a0Smrg{
5903464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
5913464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
592cdc920a0Smrg
5933464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
594cdc920a0Smrg      return;
595cdc920a0Smrg
5963464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
5973464ebd5Sriastradh}
598cdc920a0Smrg
5993464ebd5Sriastradhstatic void
6003464ebd5Sriastradhdri2_wait_gl(struct glx_context *gc)
6013464ebd5Sriastradh{
6023464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
6033464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
604cdc920a0Smrg
6053464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
6063464ebd5Sriastradh      return;
6073464ebd5Sriastradh
6083464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
609cdc920a0Smrg}
610cdc920a0Smrg
611af69d88dSmrg/**
612af69d88dSmrg * Called by the driver when it needs to update the real front buffer with the
613af69d88dSmrg * contents of its fake front buffer.
614af69d88dSmrg */
615cdc920a0Smrgstatic void
616cdc920a0Smrgdri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
617cdc920a0Smrg{
618af69d88dSmrg   struct glx_display *priv;
619af69d88dSmrg   struct dri2_display *pdp;
620af69d88dSmrg   struct glx_context *gc;
6213464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
622af69d88dSmrg   struct dri2_screen *psc;
623af69d88dSmrg
6243464ebd5Sriastradh   if (!pdraw)
6253464ebd5Sriastradh      return;
6263464ebd5Sriastradh
6273464ebd5Sriastradh   if (!pdraw->base.psc)
6283464ebd5Sriastradh      return;
6293464ebd5Sriastradh
630af69d88dSmrg   psc = (struct dri2_screen *) pdraw->base.psc;
631af69d88dSmrg
632af69d88dSmrg   priv = __glXInitialize(psc->base.dpy);
633af69d88dSmrg
634af69d88dSmrg   if (priv == NULL)
635af69d88dSmrg       return;
636af69d88dSmrg
637af69d88dSmrg   pdp = (struct dri2_display *) priv->dri2Display;
638af69d88dSmrg   gc = __glXGetCurrentContext();
639af69d88dSmrg
640af69d88dSmrg   dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
641cdc920a0Smrg
642cdc920a0Smrg   /* Old servers don't send invalidate events */
643cdc920a0Smrg   if (!pdp->invalidateAvailable)
6443464ebd5Sriastradh       dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
645cdc920a0Smrg
6463464ebd5Sriastradh   dri2_wait_gl(gc);
647cdc920a0Smrg}
648cdc920a0Smrg
649cdc920a0Smrg
650cdc920a0Smrgstatic void
6513464ebd5Sriastradhdri2DestroyScreen(struct glx_screen *base)
652cdc920a0Smrg{
6533464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
6543464ebd5Sriastradh
655cdc920a0Smrg   /* Free the direct rendering per screen data */
6563464ebd5Sriastradh   (*psc->core->destroyScreen) (psc->driScreen);
6573464ebd5Sriastradh   driDestroyConfigs(psc->driver_configs);
6587ec681f3Smrg   free(psc->driverName);
659cdc920a0Smrg   close(psc->fd);
660af69d88dSmrg   free(psc);
661cdc920a0Smrg}
662cdc920a0Smrg
663cdc920a0Smrg/**
664cdc920a0Smrg * Process list of buffer received from the server
665cdc920a0Smrg *
666cdc920a0Smrg * Processes the list of buffers received in a reply from the server to either
667cdc920a0Smrg * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
668cdc920a0Smrg */
669cdc920a0Smrgstatic void
6703464ebd5Sriastradhprocess_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
671cdc920a0Smrg                unsigned count)
672cdc920a0Smrg{
673cdc920a0Smrg   int i;
674cdc920a0Smrg
675cdc920a0Smrg   pdraw->bufferCount = count;
676cdc920a0Smrg   pdraw->have_fake_front = 0;
677cdc920a0Smrg   pdraw->have_back = 0;
678cdc920a0Smrg
679cdc920a0Smrg   /* This assumes the DRI2 buffer attachment tokens matches the
680cdc920a0Smrg    * __DRIbuffer tokens. */
681cdc920a0Smrg   for (i = 0; i < count; i++) {
682cdc920a0Smrg      pdraw->buffers[i].attachment = buffers[i].attachment;
683cdc920a0Smrg      pdraw->buffers[i].name = buffers[i].name;
684cdc920a0Smrg      pdraw->buffers[i].pitch = buffers[i].pitch;
685cdc920a0Smrg      pdraw->buffers[i].cpp = buffers[i].cpp;
686cdc920a0Smrg      pdraw->buffers[i].flags = buffers[i].flags;
687cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
688cdc920a0Smrg         pdraw->have_fake_front = 1;
689cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
690cdc920a0Smrg         pdraw->have_back = 1;
691cdc920a0Smrg   }
692cdc920a0Smrg
693cdc920a0Smrg}
694cdc920a0Smrg
6953464ebd5Sriastradhunsigned dri2GetSwapEventType(Display* dpy, XID drawable)
6963464ebd5Sriastradh{
6973464ebd5Sriastradh      struct glx_display *glx_dpy = __glXInitialize(dpy);
6983464ebd5Sriastradh      __GLXDRIdrawable *pdraw;
6993464ebd5Sriastradh      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
7003464ebd5Sriastradh      if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
7013464ebd5Sriastradh         return 0;
7027ec681f3Smrg      return glx_dpy->codes.first_event + GLX_BufferSwapComplete;
7033464ebd5Sriastradh}
7043464ebd5Sriastradh
705af69d88dSmrgstatic void show_fps(struct dri2_drawable *draw)
706af69d88dSmrg{
707af69d88dSmrg   const int interval =
708af69d88dSmrg      ((struct dri2_screen *) draw->base.psc)->show_fps_interval;
709af69d88dSmrg   struct timeval tv;
710af69d88dSmrg   uint64_t current_time;
711af69d88dSmrg
712af69d88dSmrg   gettimeofday(&tv, 0);
713af69d88dSmrg   current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec;
714af69d88dSmrg
715af69d88dSmrg   draw->frames++;
716af69d88dSmrg
717af69d88dSmrg   if (draw->previous_time + interval * 1000000 <= current_time) {
718af69d88dSmrg      if (draw->previous_time) {
7197ec681f3Smrg         fprintf(stderr, "libGL: FPS = %.2f\n",
720af69d88dSmrg                 ((uint64_t)draw->frames * 1000000) /
721af69d88dSmrg                 (double)(current_time - draw->previous_time));
722af69d88dSmrg      }
723af69d88dSmrg      draw->frames = 0;
724af69d88dSmrg      draw->previous_time = current_time;
725af69d88dSmrg   }
726af69d88dSmrg}
727af69d88dSmrg
728af69d88dSmrgstatic int64_t
729af69d88dSmrgdri2XcbSwapBuffers(Display *dpy,
730af69d88dSmrg                  __GLXDRIdrawable *pdraw,
731af69d88dSmrg                  int64_t target_msc,
732af69d88dSmrg                  int64_t divisor,
733af69d88dSmrg                  int64_t remainder)
734af69d88dSmrg{
735af69d88dSmrg   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
736af69d88dSmrg   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
737af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
738af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
739af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
740af69d88dSmrg   int64_t ret = 0;
741af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(dpy);
742af69d88dSmrg
743af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
744af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
745af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
746af69d88dSmrg
747af69d88dSmrg   swap_buffers_cookie =
748af69d88dSmrg      xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
749af69d88dSmrg                                      target_msc_hi, target_msc_lo,
750af69d88dSmrg                                      divisor_hi, divisor_lo,
751af69d88dSmrg                                      remainder_hi, remainder_lo);
752af69d88dSmrg
753af69d88dSmrg   /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
754af69d88dSmrg    * to do so some time before reusing a (non-pageflipped) backbuffer.
755af69d88dSmrg    * Otherwise, the new rendering could get ahead of the X Server's
756af69d88dSmrg    * dispatch of the swapbuffer and you'd display garbage.
757af69d88dSmrg    *
758af69d88dSmrg    * We use XSync() first to reap the invalidate events through the event
759af69d88dSmrg    * filter, to ensure that the next drawing doesn't use an invalidated
760af69d88dSmrg    * buffer.
761af69d88dSmrg    */
762af69d88dSmrg   XSync(dpy, False);
763af69d88dSmrg
764af69d88dSmrg   swap_buffers_reply =
765af69d88dSmrg      xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
766af69d88dSmrg   if (swap_buffers_reply) {
767af69d88dSmrg      ret = merge_counter(swap_buffers_reply->swap_hi,
768af69d88dSmrg                          swap_buffers_reply->swap_lo);
769af69d88dSmrg      free(swap_buffers_reply);
770af69d88dSmrg   }
771af69d88dSmrg   return ret;
772af69d88dSmrg}
773af69d88dSmrg
774cdc920a0Smrgstatic int64_t
775cdc920a0Smrgdri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
776af69d88dSmrg		int64_t remainder, Bool flush)
777cdc920a0Smrg{
7783464ebd5Sriastradh    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
7793464ebd5Sriastradh    struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
7803464ebd5Sriastradh    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
7813464ebd5Sriastradh    struct dri2_display *pdp =
7823464ebd5Sriastradh	(struct dri2_display *)dpyPriv->dri2Display;
783af69d88dSmrg    int64_t ret = 0;
784cdc920a0Smrg
7853464ebd5Sriastradh    /* Check we have the right attachments */
7863464ebd5Sriastradh    if (!priv->have_back)
7873464ebd5Sriastradh	return ret;
788cdc920a0Smrg
789cdc920a0Smrg    /* Old servers can't handle swapbuffers */
790cdc920a0Smrg    if (!pdp->swapAvailable) {
791af69d88dSmrg       __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
792af69d88dSmrg			   __DRI2_THROTTLE_SWAPBUFFER, flush);
7933464ebd5Sriastradh    } else {
794af69d88dSmrg       __DRIcontext *ctx = dri2GetCurrentContext();
795af69d88dSmrg       unsigned flags = __DRI2_FLUSH_DRAWABLE;
796af69d88dSmrg       if (flush)
797af69d88dSmrg          flags |= __DRI2_FLUSH_CONTEXT;
798af69d88dSmrg       dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
799af69d88dSmrg
800af69d88dSmrg       ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
801af69d88dSmrg                                target_msc, divisor, remainder);
802cdc920a0Smrg    }
803cdc920a0Smrg
804af69d88dSmrg    if (psc->show_fps_interval) {
805af69d88dSmrg       show_fps(priv);
8063464ebd5Sriastradh    }
8073464ebd5Sriastradh
8083464ebd5Sriastradh    /* Old servers don't send invalidate events */
8093464ebd5Sriastradh    if (!pdp->invalidateAvailable)
8103464ebd5Sriastradh       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
811cdc920a0Smrg
812cdc920a0Smrg    return ret;
813cdc920a0Smrg}
814cdc920a0Smrg
815cdc920a0Smrgstatic __DRIbuffer *
816cdc920a0Smrgdri2GetBuffers(__DRIdrawable * driDrawable,
817cdc920a0Smrg               int *width, int *height,
818cdc920a0Smrg               unsigned int *attachments, int count,
819cdc920a0Smrg               int *out_count, void *loaderPrivate)
820cdc920a0Smrg{
8213464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
822cdc920a0Smrg   DRI2Buffer *buffers;
823cdc920a0Smrg
824cdc920a0Smrg   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
825cdc920a0Smrg                            width, height, attachments, count, out_count);
826cdc920a0Smrg   if (buffers == NULL)
827cdc920a0Smrg      return NULL;
828cdc920a0Smrg
829cdc920a0Smrg   pdraw->width = *width;
830cdc920a0Smrg   pdraw->height = *height;
831cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
832cdc920a0Smrg
833af69d88dSmrg   free(buffers);
834cdc920a0Smrg
835cdc920a0Smrg   return pdraw->buffers;
836cdc920a0Smrg}
837cdc920a0Smrg
838cdc920a0Smrgstatic __DRIbuffer *
839cdc920a0Smrgdri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
840cdc920a0Smrg                         int *width, int *height,
841cdc920a0Smrg                         unsigned int *attachments, int count,
842cdc920a0Smrg                         int *out_count, void *loaderPrivate)
843cdc920a0Smrg{
8443464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
845cdc920a0Smrg   DRI2Buffer *buffers;
846cdc920a0Smrg
847cdc920a0Smrg   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
848cdc920a0Smrg                                      pdraw->base.xDrawable,
849cdc920a0Smrg                                      width, height, attachments,
850cdc920a0Smrg                                      count, out_count);
851cdc920a0Smrg   if (buffers == NULL)
852cdc920a0Smrg      return NULL;
853cdc920a0Smrg
854cdc920a0Smrg   pdraw->width = *width;
855cdc920a0Smrg   pdraw->height = *height;
856cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
857cdc920a0Smrg
858af69d88dSmrg   free(buffers);
859cdc920a0Smrg
860cdc920a0Smrg   return pdraw->buffers;
861cdc920a0Smrg}
862cdc920a0Smrg
8633464ebd5Sriastradhstatic int
864cdc920a0Smrgdri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
865cdc920a0Smrg{
866af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
8673464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
8683464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
8693464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
8703464ebd5Sriastradh
8713464ebd5Sriastradh   if (psc->config)
8723464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
8733464ebd5Sriastradh				"vblank_mode", &vblank_mode);
8743464ebd5Sriastradh
8753464ebd5Sriastradh   switch (vblank_mode) {
8763464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
877af69d88dSmrg      if (interval != 0)
878af69d88dSmrg         return GLX_BAD_VALUE;
879af69d88dSmrg      break;
8803464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
8813464ebd5Sriastradh      if (interval <= 0)
8823464ebd5Sriastradh	 return GLX_BAD_VALUE;
8833464ebd5Sriastradh      break;
8843464ebd5Sriastradh   default:
8853464ebd5Sriastradh      break;
8863464ebd5Sriastradh   }
887cdc920a0Smrg
888af69d88dSmrg   xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
889cdc920a0Smrg   priv->swap_interval = interval;
8903464ebd5Sriastradh
8913464ebd5Sriastradh   return 0;
892cdc920a0Smrg}
893cdc920a0Smrg
8943464ebd5Sriastradhstatic int
895cdc920a0Smrgdri2GetSwapInterval(__GLXDRIdrawable *pdraw)
896cdc920a0Smrg{
8973464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
898cdc920a0Smrg
899cdc920a0Smrg  return priv->swap_interval;
900cdc920a0Smrg}
901cdc920a0Smrg
90201e04c3fSmrgstatic void
90301e04c3fSmrgdriSetBackgroundContext(void *loaderPrivate)
90401e04c3fSmrg{
90501e04c3fSmrg   struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
90601e04c3fSmrg   __glXSetCurrentContext(&pcp->base);
90701e04c3fSmrg}
90801e04c3fSmrg
90901e04c3fSmrgstatic GLboolean
91001e04c3fSmrgdriIsThreadSafe(void *loaderPrivate)
91101e04c3fSmrg{
91201e04c3fSmrg   struct dri2_context *pcp = (struct dri2_context *) loaderPrivate;
91301e04c3fSmrg   /* Check Xlib is running in thread safe mode
91401e04c3fSmrg    *
91501e04c3fSmrg    * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
91601e04c3fSmrg    * It wll be NULL if XInitThreads wasn't called.
91701e04c3fSmrg    */
91801e04c3fSmrg   return pcp->base.psc->dpy->lock_fns != NULL;
91901e04c3fSmrg}
92001e04c3fSmrg
921cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension = {
922af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
923af69d88dSmrg
924af69d88dSmrg   .getBuffers              = dri2GetBuffers,
925af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
926af69d88dSmrg   .getBuffersWithFormat    = dri2GetBuffersWithFormat,
927cdc920a0Smrg};
928cdc920a0Smrg
929cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
930af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
931af69d88dSmrg
932af69d88dSmrg   .getBuffers              = dri2GetBuffers,
933af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
934af69d88dSmrg   .getBuffersWithFormat    = NULL,
935cdc920a0Smrg};
936cdc920a0Smrg
9373464ebd5Sriastradhstatic const __DRIuseInvalidateExtension dri2UseInvalidate = {
938af69d88dSmrg   .base = { __DRI_USE_INVALIDATE, 1 }
939cdc920a0Smrg};
940cdc920a0Smrg
94101e04c3fSmrgstatic const __DRIbackgroundCallableExtension driBackgroundCallable = {
94201e04c3fSmrg   .base = { __DRI_BACKGROUND_CALLABLE, 2 },
94301e04c3fSmrg
94401e04c3fSmrg   .setBackgroundContext    = driSetBackgroundContext,
94501e04c3fSmrg   .isThreadSafe            = driIsThreadSafe,
94601e04c3fSmrg};
94701e04c3fSmrg
948cdc920a0Smrg_X_HIDDEN void
949cdc920a0Smrgdri2InvalidateBuffers(Display *dpy, XID drawable)
950cdc920a0Smrg{
9513464ebd5Sriastradh   __GLXDRIdrawable *pdraw =
9523464ebd5Sriastradh      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
9533464ebd5Sriastradh   struct dri2_screen *psc;
9543464ebd5Sriastradh   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
9553464ebd5Sriastradh
9563464ebd5Sriastradh   if (!pdraw)
9573464ebd5Sriastradh      return;
9583464ebd5Sriastradh
9593464ebd5Sriastradh   psc = (struct dri2_screen *) pdraw->psc;
960cdc920a0Smrg
9617ec681f3Smrg   if (psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
9623464ebd5Sriastradh       psc->f->invalidate(pdp->driDrawable);
963cdc920a0Smrg}
964cdc920a0Smrg
9653464ebd5Sriastradhstatic void
9667ec681f3Smrgdri2_bind_tex_image(__GLXDRIdrawable *base,
9673464ebd5Sriastradh		    int buffer, const int *attrib_list)
9683464ebd5Sriastradh{
9693464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
9703464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
9717ec681f3Smrg   struct glx_display *dpyPriv = __glXInitialize(gc->currentDpy);
9723464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
973af69d88dSmrg   struct dri2_display *pdp;
9743464ebd5Sriastradh   struct dri2_screen *psc;
9753464ebd5Sriastradh
976af69d88dSmrg   pdp = (struct dri2_display *) dpyPriv->dri2Display;
977af69d88dSmrg
9783464ebd5Sriastradh   if (pdraw != NULL) {
9793464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
9803464ebd5Sriastradh
9813464ebd5Sriastradh      if (!pdp->invalidateAvailable && psc->f &&
9823464ebd5Sriastradh           psc->f->base.version >= 3 && psc->f->invalidate)
9833464ebd5Sriastradh	 psc->f->invalidate(pdraw->driDrawable);
9843464ebd5Sriastradh
9853464ebd5Sriastradh      if (psc->texBuffer->base.version >= 2 &&
9863464ebd5Sriastradh	  psc->texBuffer->setTexBuffer2 != NULL) {
9873464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
9883464ebd5Sriastradh					   pdraw->base.textureTarget,
9893464ebd5Sriastradh					   pdraw->base.textureFormat,
9903464ebd5Sriastradh					   pdraw->driDrawable);
9913464ebd5Sriastradh      }
9923464ebd5Sriastradh      else {
9933464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
9943464ebd5Sriastradh					  pdraw->base.textureTarget,
9953464ebd5Sriastradh					  pdraw->driDrawable);
9963464ebd5Sriastradh      }
9973464ebd5Sriastradh   }
9983464ebd5Sriastradh}
9993464ebd5Sriastradh
10003464ebd5Sriastradhstatic void
10017ec681f3Smrgdri2_release_tex_image(__GLXDRIdrawable *base, int buffer)
10023464ebd5Sriastradh{
10033464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
10043464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
10053464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
10063464ebd5Sriastradh   struct dri2_screen *psc;
10073464ebd5Sriastradh
10087ec681f3Smrg   if (pdraw != NULL) {
10093464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
10103464ebd5Sriastradh
10113464ebd5Sriastradh      if (psc->texBuffer->base.version >= 3 &&
10123464ebd5Sriastradh          psc->texBuffer->releaseTexBuffer != NULL) {
10133464ebd5Sriastradh         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
10143464ebd5Sriastradh                                           pdraw->base.textureTarget,
10153464ebd5Sriastradh                                           pdraw->driDrawable);
10163464ebd5Sriastradh      }
10173464ebd5Sriastradh   }
10183464ebd5Sriastradh}
10193464ebd5Sriastradh
10203464ebd5Sriastradhstatic const struct glx_context_vtable dri2_context_vtable = {
1021af69d88dSmrg   .destroy             = dri2_destroy_context,
1022af69d88dSmrg   .bind                = dri2_bind_context,
1023af69d88dSmrg   .unbind              = dri2_unbind_context,
1024af69d88dSmrg   .wait_gl             = dri2_wait_gl,
1025af69d88dSmrg   .wait_x              = dri2_wait_x,
102601e04c3fSmrg   .interop_query_device_info = dri2_interop_query_device_info,
102701e04c3fSmrg   .interop_export_object = dri2_interop_export_object
10283464ebd5Sriastradh};
10293464ebd5Sriastradh
10303464ebd5Sriastradhstatic void
1031af69d88dSmrgdri2BindExtensions(struct dri2_screen *psc, struct glx_display * priv,
1032af69d88dSmrg                   const char *driverName)
10333464ebd5Sriastradh{
1034af69d88dSmrg   const struct dri2_display *const pdp = (struct dri2_display *)
1035af69d88dSmrg      priv->dri2Display;
10367ec681f3Smrg   const unsigned mask = psc->dri2->getAPIMask(psc->driScreen);
1037af69d88dSmrg   const __DRIextension **extensions;
10383464ebd5Sriastradh   int i;
10393464ebd5Sriastradh
1040af69d88dSmrg   extensions = psc->core->getExtensions(psc->driScreen);
1041af69d88dSmrg
10427ec681f3Smrg   __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control");
10433464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
10443464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
10453464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
10463464ebd5Sriastradh
1047af69d88dSmrg   /*
1048af69d88dSmrg    * GLX_INTEL_swap_event is broken on the server side, where it's
1049af69d88dSmrg    * currently unconditionally enabled. This completely breaks
1050af69d88dSmrg    * systems running on drivers which don't support that extension.
1051af69d88dSmrg    * There's no way to test for its presence on this side, so instead
1052af69d88dSmrg    * of disabling it unconditionally, just disable it for drivers
1053af69d88dSmrg    * which are known to not support it, or for DDX drivers supporting
1054af69d88dSmrg    * only an older (pre-ScheduleSwap) version of DRI2.
1055af69d88dSmrg    *
1056af69d88dSmrg    * This is a hack which is required until:
1057af69d88dSmrg    * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
1058af69d88dSmrg    * is merged and updated xserver makes it's way into distros:
1059af69d88dSmrg    */
1060af69d88dSmrg   if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
1061af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1062af69d88dSmrg   }
1063af69d88dSmrg
10647ec681f3Smrg   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
10657ec681f3Smrg   __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
10667ec681f3Smrg   __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context");
10677ec681f3Smrg
10687ec681f3Smrg   if ((mask & ((1 << __DRI_API_GLES) |
10697ec681f3Smrg                (1 << __DRI_API_GLES2) |
10707ec681f3Smrg                (1 << __DRI_API_GLES3))) != 0) {
10717ec681f3Smrg      __glXEnableDirectExtension(&psc->base,
10727ec681f3Smrg                                 "GLX_EXT_create_context_es_profile");
10737ec681f3Smrg      __glXEnableDirectExtension(&psc->base,
10747ec681f3Smrg                                 "GLX_EXT_create_context_es2_profile");
1075af69d88dSmrg   }
10763464ebd5Sriastradh
10773464ebd5Sriastradh   for (i = 0; extensions[i]; i++) {
10783464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
10793464ebd5Sriastradh	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
10803464ebd5Sriastradh	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
10813464ebd5Sriastradh      }
10823464ebd5Sriastradh
10833464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
10843464ebd5Sriastradh	 psc->f = (__DRI2flushExtension *) extensions[i];
10853464ebd5Sriastradh	 /* internal driver extension, no GL extension exposed */
10863464ebd5Sriastradh      }
10873464ebd5Sriastradh
10883464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
10893464ebd5Sriastradh	 psc->config = (__DRI2configQueryExtension *) extensions[i];
1090af69d88dSmrg
1091af69d88dSmrg      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
1092af69d88dSmrg	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
1093af69d88dSmrg
10947ec681f3Smrg      if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1095af69d88dSmrg         __glXEnableDirectExtension(&psc->base,
1096af69d88dSmrg                                    "GLX_ARB_create_context_robustness");
1097af69d88dSmrg
10987ec681f3Smrg      if (strcmp(extensions[i]->name, __DRI2_NO_ERROR) == 0)
10999f464c52Smaya         __glXEnableDirectExtension(&psc->base,
11009f464c52Smaya                                    "GLX_ARB_create_context_no_error");
11019f464c52Smaya
11027ec681f3Smrg      if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
1103af69d88dSmrg         psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
1104af69d88dSmrg         __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
1105af69d88dSmrg      }
110601e04c3fSmrg
110701e04c3fSmrg      if (strcmp(extensions[i]->name, __DRI2_INTEROP) == 0)
110801e04c3fSmrg	 psc->interop = (__DRI2interopExtension*)extensions[i];
110901e04c3fSmrg
11107ec681f3Smrg      if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0)
111101e04c3fSmrg         __glXEnableDirectExtension(&psc->base,
111201e04c3fSmrg                                    "GLX_ARB_context_flush_control");
11133464ebd5Sriastradh   }
11143464ebd5Sriastradh}
11153464ebd5Sriastradh
11167ec681f3Smrgstatic char *
11177ec681f3Smrgdri2_get_driver_name(struct glx_screen *glx_screen)
11187ec681f3Smrg{
11197ec681f3Smrg    struct dri2_screen *psc = (struct dri2_screen *)glx_screen;
11207ec681f3Smrg
11217ec681f3Smrg    return psc->driverName;
11227ec681f3Smrg}
11237ec681f3Smrg
11243464ebd5Sriastradhstatic const struct glx_screen_vtable dri2_screen_vtable = {
11257ec681f3Smrg   .create_context         = dri_common_create_context,
1126af69d88dSmrg   .create_context_attribs = dri2_create_context_attribs,
1127af69d88dSmrg   .query_renderer_integer = dri2_query_renderer_integer,
1128af69d88dSmrg   .query_renderer_string  = dri2_query_renderer_string,
11297ec681f3Smrg   .get_driver_name        = dri2_get_driver_name,
11303464ebd5Sriastradh};
11313464ebd5Sriastradh
11323464ebd5Sriastradhstatic struct glx_screen *
11333464ebd5Sriastradhdri2CreateScreen(int screen, struct glx_display * priv)
1134cdc920a0Smrg{
1135cdc920a0Smrg   const __DRIconfig **driver_configs;
1136cdc920a0Smrg   const __DRIextension **extensions;
11373464ebd5Sriastradh   const struct dri2_display *const pdp = (struct dri2_display *)
1138cdc920a0Smrg      priv->dri2Display;
11393464ebd5Sriastradh   struct dri2_screen *psc;
1140cdc920a0Smrg   __GLXDRIscreen *psp;
1141af69d88dSmrg   struct glx_config *configs = NULL, *visuals = NULL;
1142af69d88dSmrg   char *driverName = NULL, *loader_driverName, *deviceName, *tmp;
1143cdc920a0Smrg   drm_magic_t magic;
1144cdc920a0Smrg   int i;
1145cdc920a0Smrg
1146af69d88dSmrg   psc = calloc(1, sizeof *psc);
11473464ebd5Sriastradh   if (psc == NULL)
11483464ebd5Sriastradh      return NULL;
11493464ebd5Sriastradh
11503464ebd5Sriastradh   psc->fd = -1;
11513464ebd5Sriastradh
11523464ebd5Sriastradh   if (!glx_screen_init(&psc->base, screen, priv)) {
1153af69d88dSmrg      free(psc);
1154cdc920a0Smrg      return NULL;
11553464ebd5Sriastradh   }
1156cdc920a0Smrg
11573464ebd5Sriastradh   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
1158cdc920a0Smrg		    &driverName, &deviceName)) {
11593464ebd5Sriastradh      glx_screen_cleanup(&psc->base);
1160af69d88dSmrg      free(psc);
1161af69d88dSmrg      InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
1162cdc920a0Smrg      return NULL;
1163cdc920a0Smrg   }
1164cdc920a0Smrg
116501e04c3fSmrg   psc->fd = loader_open_device(deviceName);
1166af69d88dSmrg   if (psc->fd < 0) {
11677ec681f3Smrg      ErrorMessageF("failed to open %s: %s\n", deviceName, strerror(errno));
1168af69d88dSmrg      goto handle_error;
1169af69d88dSmrg   }
1170af69d88dSmrg
1171af69d88dSmrg   if (drmGetMagic(psc->fd, &magic)) {
1172af69d88dSmrg      ErrorMessageF("failed to get magic\n");
1173af69d88dSmrg      goto handle_error;
1174af69d88dSmrg   }
1175af69d88dSmrg
1176af69d88dSmrg   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
1177af69d88dSmrg      ErrorMessageF("failed to authenticate magic %d\n", magic);
1178af69d88dSmrg      goto handle_error;
1179af69d88dSmrg   }
1180af69d88dSmrg
1181af69d88dSmrg   /* If Mesa knows about the appropriate driver for this fd, then trust it.
1182af69d88dSmrg    * Otherwise, default to the server's value.
1183af69d88dSmrg    */
118401e04c3fSmrg   loader_driverName = loader_get_driver_for_fd(psc->fd);
1185af69d88dSmrg   if (loader_driverName) {
1186af69d88dSmrg      free(driverName);
1187af69d88dSmrg      driverName = loader_driverName;
1188af69d88dSmrg   }
11897ec681f3Smrg   psc->driverName = driverName;
1190af69d88dSmrg
11919f464c52Smaya   extensions = driOpenDriver(driverName, &psc->driver);
1192af69d88dSmrg   if (extensions == NULL)
1193cdc920a0Smrg      goto handle_error;
1194cdc920a0Smrg
1195cdc920a0Smrg   for (i = 0; extensions[i]; i++) {
1196cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1197cdc920a0Smrg	 psc->core = (__DRIcoreExtension *) extensions[i];
1198cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
1199cdc920a0Smrg	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
1200cdc920a0Smrg   }
1201cdc920a0Smrg
12027ec681f3Smrg   if (psc->core == NULL || psc->dri2 == NULL || psc->dri2->base.version < 3) {
1203cdc920a0Smrg      ErrorMessageF("core dri or dri2 extension not found\n");
1204cdc920a0Smrg      goto handle_error;
1205cdc920a0Smrg   }
1206cdc920a0Smrg
1207af69d88dSmrg   if (psc->dri2->base.version >= 4) {
1208af69d88dSmrg      psc->driScreen =
1209af69d88dSmrg         psc->dri2->createNewScreen2(screen, psc->fd,
1210af69d88dSmrg                                     (const __DRIextension **)
1211af69d88dSmrg                                     &pdp->loader_extensions[0],
1212af69d88dSmrg                                     extensions,
1213af69d88dSmrg                                     &driver_configs, psc);
1214af69d88dSmrg   } else {
1215af69d88dSmrg      psc->driScreen =
1216af69d88dSmrg         psc->dri2->createNewScreen(screen, psc->fd,
1217af69d88dSmrg                                    (const __DRIextension **)
1218af69d88dSmrg                                    &pdp->loader_extensions[0],
1219af69d88dSmrg                                    &driver_configs, psc);
1220cdc920a0Smrg   }
1221cdc920a0Smrg
1222af69d88dSmrg   if (psc->driScreen == NULL) {
1223af69d88dSmrg      ErrorMessageF("failed to create dri screen\n");
1224cdc920a0Smrg      goto handle_error;
1225cdc920a0Smrg   }
1226cdc920a0Smrg
1227af69d88dSmrg   dri2BindExtensions(psc, priv, driverName);
1228cdc920a0Smrg
1229af69d88dSmrg   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1230af69d88dSmrg   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1231cdc920a0Smrg
1232af69d88dSmrg   if (!configs || !visuals) {
1233af69d88dSmrg       ErrorMessageF("No matching fbConfigs or visuals found\n");
1234af69d88dSmrg       goto handle_error;
1235cdc920a0Smrg   }
1236cdc920a0Smrg
1237af69d88dSmrg   glx_config_destroy_list(psc->base.configs);
1238af69d88dSmrg   psc->base.configs = configs;
1239af69d88dSmrg   glx_config_destroy_list(psc->base.visuals);
1240af69d88dSmrg   psc->base.visuals = visuals;
1241cdc920a0Smrg
1242cdc920a0Smrg   psc->driver_configs = driver_configs;
1243cdc920a0Smrg
12443464ebd5Sriastradh   psc->base.vtable = &dri2_screen_vtable;
12457ec681f3Smrg   psc->base.context_vtable = &dri2_context_vtable;
12463464ebd5Sriastradh   psp = &psc->vtable;
12473464ebd5Sriastradh   psc->base.driScreen = psp;
1248cdc920a0Smrg   psp->destroyScreen = dri2DestroyScreen;
1249cdc920a0Smrg   psp->createDrawable = dri2CreateDrawable;
1250cdc920a0Smrg   psp->swapBuffers = dri2SwapBuffers;
1251cdc920a0Smrg   psp->getDrawableMSC = NULL;
1252cdc920a0Smrg   psp->waitForMSC = NULL;
1253cdc920a0Smrg   psp->waitForSBC = NULL;
1254cdc920a0Smrg   psp->setSwapInterval = NULL;
1255cdc920a0Smrg   psp->getSwapInterval = NULL;
1256af69d88dSmrg   psp->getBufferAge = NULL;
12577ec681f3Smrg   psp->bindTexImage = dri2_bind_tex_image;
12587ec681f3Smrg   psp->releaseTexImage = dri2_release_tex_image;
1259cdc920a0Smrg
1260cdc920a0Smrg   if (pdp->driMinor >= 2) {
1261cdc920a0Smrg      psp->getDrawableMSC = dri2DrawableGetMSC;
1262cdc920a0Smrg      psp->waitForMSC = dri2WaitForMSC;
1263cdc920a0Smrg      psp->waitForSBC = dri2WaitForSBC;
1264cdc920a0Smrg      psp->setSwapInterval = dri2SetSwapInterval;
1265cdc920a0Smrg      psp->getSwapInterval = dri2GetSwapInterval;
12667ec681f3Smrg
12677ec681f3Smrg      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1268cdc920a0Smrg   }
1269cdc920a0Smrg
12707ec681f3Smrg   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
12717ec681f3Smrg
12727ec681f3Smrg   if (psc->config->base.version > 1 &&
12737ec681f3Smrg          psc->config->configQuerys(psc->driScreen, "glx_extension_override",
12747ec681f3Smrg                                    &tmp) == 0)
12757ec681f3Smrg      __glXParseExtensionOverride(&psc->base, tmp);
12767ec681f3Smrg
12777ec681f3Smrg   if (psc->config->base.version > 1 &&
12787ec681f3Smrg          psc->config->configQuerys(psc->driScreen,
12797ec681f3Smrg                                    "indirect_gl_extension_override",
12807ec681f3Smrg                                    &tmp) == 0)
12817ec681f3Smrg      __IndirectGlParseExtensionOverride(&psc->base, tmp);
128201e04c3fSmrg
128301e04c3fSmrg   /* DRI2 supports SubBuffer through DRI2CopyRegion, so it's always
1284cdc920a0Smrg    * available.*/
1285cdc920a0Smrg   psp->copySubBuffer = dri2CopySubBuffer;
12863464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1287cdc920a0Smrg
1288af69d88dSmrg   free(deviceName);
1289af69d88dSmrg
1290af69d88dSmrg   tmp = getenv("LIBGL_SHOW_FPS");
1291af69d88dSmrg   psc->show_fps_interval = (tmp) ? atoi(tmp) : 0;
1292af69d88dSmrg   if (psc->show_fps_interval < 0)
1293af69d88dSmrg      psc->show_fps_interval = 0;
1294cdc920a0Smrg
129501e04c3fSmrg   InfoMessageF("Using DRI2 for screen %d\n", screen);
129601e04c3fSmrg
12973464ebd5Sriastradh   return &psc->base;
1298cdc920a0Smrg
1299cdc920a0Smrghandle_error:
1300af69d88dSmrg   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1301af69d88dSmrg
1302af69d88dSmrg   if (configs)
1303af69d88dSmrg       glx_config_destroy_list(configs);
1304af69d88dSmrg   if (visuals)
1305af69d88dSmrg       glx_config_destroy_list(visuals);
1306af69d88dSmrg   if (psc->driScreen)
1307af69d88dSmrg       psc->core->destroyScreen(psc->driScreen);
1308af69d88dSmrg   psc->driScreen = NULL;
13093464ebd5Sriastradh   if (psc->fd >= 0)
13103464ebd5Sriastradh      close(psc->fd);
13113464ebd5Sriastradh   if (psc->driver)
13123464ebd5Sriastradh      dlclose(psc->driver);
1313af69d88dSmrg
1314af69d88dSmrg   free(deviceName);
13153464ebd5Sriastradh   glx_screen_cleanup(&psc->base);
1316af69d88dSmrg   free(psc);
1317cdc920a0Smrg
1318cdc920a0Smrg   return NULL;
1319cdc920a0Smrg}
1320cdc920a0Smrg
1321cdc920a0Smrg/* Called from __glXFreeDisplayPrivate.
1322cdc920a0Smrg */
1323cdc920a0Smrgstatic void
1324cdc920a0Smrgdri2DestroyDisplay(__GLXDRIdisplay * dpy)
1325cdc920a0Smrg{
13263464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) dpy;
13273464ebd5Sriastradh
13283464ebd5Sriastradh   __glxHashDestroy(pdp->dri2Hash);
1329af69d88dSmrg   free(dpy);
1330cdc920a0Smrg}
1331cdc920a0Smrg
13323464ebd5Sriastradh_X_HIDDEN __GLXDRIdrawable *
13333464ebd5Sriastradhdri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
13343464ebd5Sriastradh{
13353464ebd5Sriastradh   struct glx_display *d = __glXInitialize(dpy);
13363464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
13373464ebd5Sriastradh   __GLXDRIdrawable *pdraw;
13383464ebd5Sriastradh
13393464ebd5Sriastradh   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
13403464ebd5Sriastradh      return pdraw;
13413464ebd5Sriastradh
13423464ebd5Sriastradh   return NULL;
13433464ebd5Sriastradh}
13443464ebd5Sriastradh
1345cdc920a0Smrg/*
1346cdc920a0Smrg * Allocate, initialize and return a __DRIdisplayPrivate object.
1347cdc920a0Smrg * This is called from __glXInitialize() when we are given a new
1348cdc920a0Smrg * display pointer.
1349cdc920a0Smrg */
1350cdc920a0Smrg_X_HIDDEN __GLXDRIdisplay *
1351cdc920a0Smrgdri2CreateDisplay(Display * dpy)
1352cdc920a0Smrg{
13533464ebd5Sriastradh   struct dri2_display *pdp;
13543464ebd5Sriastradh   int eventBase, errorBase, i;
1355cdc920a0Smrg
1356cdc920a0Smrg   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1357cdc920a0Smrg      return NULL;
1358cdc920a0Smrg
1359af69d88dSmrg   pdp = malloc(sizeof *pdp);
1360cdc920a0Smrg   if (pdp == NULL)
1361cdc920a0Smrg      return NULL;
1362cdc920a0Smrg
1363cdc920a0Smrg   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1364af69d88dSmrg      free(pdp);
1365cdc920a0Smrg      return NULL;
1366cdc920a0Smrg   }
1367cdc920a0Smrg
1368cdc920a0Smrg   pdp->driPatch = 0;
1369cdc920a0Smrg   pdp->swapAvailable = (pdp->driMinor >= 2);
1370cdc920a0Smrg   pdp->invalidateAvailable = (pdp->driMinor >= 3);
1371cdc920a0Smrg
1372cdc920a0Smrg   pdp->base.destroyDisplay = dri2DestroyDisplay;
1373cdc920a0Smrg   pdp->base.createScreen = dri2CreateScreen;
1374cdc920a0Smrg
13753464ebd5Sriastradh   i = 0;
13763464ebd5Sriastradh   if (pdp->driMinor < 1)
13773464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
13783464ebd5Sriastradh   else
13793464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
13803464ebd5Sriastradh
13813464ebd5Sriastradh   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1382af69d88dSmrg
138301e04c3fSmrg   pdp->loader_extensions[i++] = &driBackgroundCallable.base;
138401e04c3fSmrg
13853464ebd5Sriastradh   pdp->loader_extensions[i++] = NULL;
13863464ebd5Sriastradh
13873464ebd5Sriastradh   pdp->dri2Hash = __glxHashCreate();
13883464ebd5Sriastradh   if (pdp->dri2Hash == NULL) {
1389af69d88dSmrg      free(pdp);
13903464ebd5Sriastradh      return NULL;
13913464ebd5Sriastradh   }
13923464ebd5Sriastradh
1393cdc920a0Smrg   return &pdp->base;
1394cdc920a0Smrg}
1395cdc920a0Smrg
1396cdc920a0Smrg#endif /* GLX_DIRECT_RENDERING */
1397