dri2_glx.c revision af69d88d
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
773464ebd5Sriastradh   const __DRIextension *loader_extensions[4];
78cdc920a0Smrg};
79cdc920a0Smrg
803464ebd5Sriastradhstruct dri2_context
81cdc920a0Smrg{
823464ebd5Sriastradh   struct glx_context base;
83cdc920a0Smrg   __DRIcontext *driContext;
84cdc920a0Smrg};
85cdc920a0Smrg
863464ebd5Sriastradhstruct dri2_drawable
87cdc920a0Smrg{
88cdc920a0Smrg   __GLXDRIdrawable base;
893464ebd5Sriastradh   __DRIdrawable *driDrawable;
90cdc920a0Smrg   __DRIbuffer buffers[5];
91cdc920a0Smrg   int bufferCount;
92cdc920a0Smrg   int width, height;
93cdc920a0Smrg   int have_back;
94cdc920a0Smrg   int have_fake_front;
95cdc920a0Smrg   int swap_interval;
96af69d88dSmrg
97af69d88dSmrg   uint64_t previous_time;
98af69d88dSmrg   unsigned frames;
99cdc920a0Smrg};
100cdc920a0Smrg
1013464ebd5Sriastradhstatic const struct glx_context_vtable dri2_context_vtable;
102cdc920a0Smrg
103af69d88dSmrg/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and
104af69d88dSmrg * low halves separately.  This helps you split them.
105af69d88dSmrg */
106af69d88dSmrgstatic void
107af69d88dSmrgsplit_counter(uint64_t counter, uint32_t *hi, uint32_t *lo)
108af69d88dSmrg{
109af69d88dSmrg   *hi = (counter >> 32);
110af69d88dSmrg   *lo = counter & 0xffffffff;
111af69d88dSmrg}
112af69d88dSmrg
113af69d88dSmrgstatic uint64_t
114af69d88dSmrgmerge_counter(uint32_t hi, uint32_t lo)
115af69d88dSmrg{
116af69d88dSmrg   return ((uint64_t)hi << 32) | lo;
117af69d88dSmrg}
118af69d88dSmrg
119cdc920a0Smrgstatic void
1203464ebd5Sriastradhdri2_destroy_context(struct glx_context *context)
121cdc920a0Smrg{
1223464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1233464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) context->psc;
1243464ebd5Sriastradh
1253464ebd5Sriastradh   driReleaseDrawables(&pcp->base);
1263464ebd5Sriastradh
127af69d88dSmrg   free((char *) context->extensions);
128cdc920a0Smrg
1293464ebd5Sriastradh   (*psc->core->destroyContext) (pcp->driContext);
130cdc920a0Smrg
131af69d88dSmrg   free(pcp);
132cdc920a0Smrg}
133cdc920a0Smrg
134cdc920a0Smrgstatic Bool
1353464ebd5Sriastradhdri2_bind_context(struct glx_context *context, struct glx_context *old,
1363464ebd5Sriastradh		  GLXDrawable draw, GLXDrawable read)
137cdc920a0Smrg{
1383464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1393464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
1403464ebd5Sriastradh   struct dri2_drawable *pdraw, *pread;
141af69d88dSmrg   __DRIdrawable *dri_draw = NULL, *dri_read = NULL;
142af69d88dSmrg   struct glx_display *dpyPriv = psc->base.display;
1433464ebd5Sriastradh   struct dri2_display *pdp;
1443464ebd5Sriastradh
1453464ebd5Sriastradh   pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw);
1463464ebd5Sriastradh   pread = (struct dri2_drawable *) driFetchDrawable(context, read);
1473464ebd5Sriastradh
1483464ebd5Sriastradh   driReleaseDrawables(&pcp->base);
1493464ebd5Sriastradh
150af69d88dSmrg   if (pdraw)
151af69d88dSmrg      dri_draw = pdraw->driDrawable;
152af69d88dSmrg   else if (draw != None)
1533464ebd5Sriastradh      return GLXBadDrawable;
1543464ebd5Sriastradh
155af69d88dSmrg   if (pread)
156af69d88dSmrg      dri_read = pread->driDrawable;
157af69d88dSmrg   else if (read != None)
158af69d88dSmrg      return GLXBadDrawable;
159af69d88dSmrg
160af69d88dSmrg   if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read))
1613464ebd5Sriastradh      return GLXBadContext;
1623464ebd5Sriastradh
1633464ebd5Sriastradh   /* If the server doesn't send invalidate events, we may miss a
1643464ebd5Sriastradh    * resize before the rendering starts.  Invalidate the buffers now
1653464ebd5Sriastradh    * so the driver will recheck before rendering starts. */
166af69d88dSmrg   pdp = (struct dri2_display *) dpyPriv->dri2Display;
167af69d88dSmrg   if (!pdp->invalidateAvailable && pdraw) {
1683464ebd5Sriastradh      dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable);
169af69d88dSmrg      if (pread != pdraw && pread)
1703464ebd5Sriastradh	 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable);
1713464ebd5Sriastradh   }
172cdc920a0Smrg
1733464ebd5Sriastradh   return Success;
174cdc920a0Smrg}
175cdc920a0Smrg
176cdc920a0Smrgstatic void
1773464ebd5Sriastradhdri2_unbind_context(struct glx_context *context, struct glx_context *new)
178cdc920a0Smrg{
1793464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) context;
1803464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc;
181cdc920a0Smrg
1823464ebd5Sriastradh   (*psc->core->unbindContext) (pcp->driContext);
183cdc920a0Smrg}
184cdc920a0Smrg
1853464ebd5Sriastradhstatic struct glx_context *
1863464ebd5Sriastradhdri2_create_context(struct glx_screen *base,
1873464ebd5Sriastradh		    struct glx_config *config_base,
1883464ebd5Sriastradh		    struct glx_context *shareList, int renderType)
189cdc920a0Smrg{
1903464ebd5Sriastradh   struct dri2_context *pcp, *pcp_shared;
1913464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
1923464ebd5Sriastradh   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
193cdc920a0Smrg   __DRIcontext *shared = NULL;
194cdc920a0Smrg
195af69d88dSmrg   /* Check the renderType value */
196af69d88dSmrg   if (!validate_renderType_against_config(config_base, renderType))
197af69d88dSmrg       return NULL;
198af69d88dSmrg
199cdc920a0Smrg   if (shareList) {
200af69d88dSmrg      /* If the shareList context is not a DRI2 context, we cannot possibly
201af69d88dSmrg       * create a DRI2 context that shares it.
202af69d88dSmrg       */
203af69d88dSmrg      if (shareList->vtable->destroy != dri2_destroy_context) {
204af69d88dSmrg	 return NULL;
205af69d88dSmrg      }
206af69d88dSmrg
2073464ebd5Sriastradh      pcp_shared = (struct dri2_context *) shareList;
208cdc920a0Smrg      shared = pcp_shared->driContext;
209cdc920a0Smrg   }
210cdc920a0Smrg
211af69d88dSmrg   pcp = calloc(1, sizeof *pcp);
212cdc920a0Smrg   if (pcp == NULL)
213cdc920a0Smrg      return NULL;
214cdc920a0Smrg
2153464ebd5Sriastradh   if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
216af69d88dSmrg      free(pcp);
2173464ebd5Sriastradh      return NULL;
2183464ebd5Sriastradh   }
2193464ebd5Sriastradh
220af69d88dSmrg   pcp->base.renderType = renderType;
221af69d88dSmrg
222cdc920a0Smrg   pcp->driContext =
2233464ebd5Sriastradh      (*psc->dri2->createNewContext) (psc->driScreen,
224cdc920a0Smrg                                      config->driConfig, shared, pcp);
225cdc920a0Smrg
226cdc920a0Smrg   if (pcp->driContext == NULL) {
227af69d88dSmrg      free(pcp);
228cdc920a0Smrg      return NULL;
229cdc920a0Smrg   }
230cdc920a0Smrg
2313464ebd5Sriastradh   pcp->base.vtable = &dri2_context_vtable;
232cdc920a0Smrg
233cdc920a0Smrg   return &pcp->base;
234cdc920a0Smrg}
235cdc920a0Smrg
236af69d88dSmrgstatic struct glx_context *
237af69d88dSmrgdri2_create_context_attribs(struct glx_screen *base,
238af69d88dSmrg			    struct glx_config *config_base,
239af69d88dSmrg			    struct glx_context *shareList,
240af69d88dSmrg			    unsigned num_attribs,
241af69d88dSmrg			    const uint32_t *attribs,
242af69d88dSmrg			    unsigned *error)
243af69d88dSmrg{
244af69d88dSmrg   struct dri2_context *pcp = NULL;
245af69d88dSmrg   struct dri2_context *pcp_shared = NULL;
246af69d88dSmrg   struct dri2_screen *psc = (struct dri2_screen *) base;
247af69d88dSmrg   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
248af69d88dSmrg   __DRIcontext *shared = NULL;
249af69d88dSmrg
250af69d88dSmrg   uint32_t minor_ver;
251af69d88dSmrg   uint32_t major_ver;
252af69d88dSmrg   uint32_t renderType;
253af69d88dSmrg   uint32_t flags;
254af69d88dSmrg   unsigned api;
255af69d88dSmrg   int reset;
256af69d88dSmrg   uint32_t ctx_attribs[2 * 5];
257af69d88dSmrg   unsigned num_ctx_attribs = 0;
258af69d88dSmrg
259af69d88dSmrg   if (psc->dri2->base.version < 3) {
260af69d88dSmrg      *error = __DRI_CTX_ERROR_NO_MEMORY;
261af69d88dSmrg      goto error_exit;
262af69d88dSmrg   }
263af69d88dSmrg
264af69d88dSmrg   /* Remap the GLX tokens to DRI2 tokens.
265af69d88dSmrg    */
266af69d88dSmrg   if (!dri2_convert_glx_attribs(num_attribs, attribs,
267af69d88dSmrg                                 &major_ver, &minor_ver, &renderType, &flags,
268af69d88dSmrg                                 &api, &reset, error))
269af69d88dSmrg      goto error_exit;
270af69d88dSmrg
271af69d88dSmrg   /* Check the renderType value */
272af69d88dSmrg   if (!validate_renderType_against_config(config_base, renderType))
273af69d88dSmrg       goto error_exit;
274af69d88dSmrg
275af69d88dSmrg   if (shareList) {
276af69d88dSmrg      pcp_shared = (struct dri2_context *) shareList;
277af69d88dSmrg      shared = pcp_shared->driContext;
278af69d88dSmrg   }
279af69d88dSmrg
280af69d88dSmrg   pcp = calloc(1, sizeof *pcp);
281af69d88dSmrg   if (pcp == NULL) {
282af69d88dSmrg      *error = __DRI_CTX_ERROR_NO_MEMORY;
283af69d88dSmrg      goto error_exit;
284af69d88dSmrg   }
285af69d88dSmrg
286af69d88dSmrg   if (!glx_context_init(&pcp->base, &psc->base, &config->base))
287af69d88dSmrg      goto error_exit;
288af69d88dSmrg
289af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
290af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = major_ver;
291af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
292af69d88dSmrg   ctx_attribs[num_ctx_attribs++] = minor_ver;
293af69d88dSmrg
294af69d88dSmrg   /* Only send a value when the non-default value is requested.  By doing
295af69d88dSmrg    * this we don't have to check the driver's DRI2 version before sending the
296af69d88dSmrg    * default value.
297af69d88dSmrg    */
298af69d88dSmrg   if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
299af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
300af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = reset;
301af69d88dSmrg   }
302af69d88dSmrg
303af69d88dSmrg   if (flags != 0) {
304af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
305af69d88dSmrg
306af69d88dSmrg      /* The current __DRI_CTX_FLAG_* values are identical to the
307af69d88dSmrg       * GLX_CONTEXT_*_BIT values.
308af69d88dSmrg       */
309af69d88dSmrg      ctx_attribs[num_ctx_attribs++] = flags;
310af69d88dSmrg   }
311af69d88dSmrg
312af69d88dSmrg   /* The renderType is retrieved from attribs, or set to default
313af69d88dSmrg    *  of GLX_RGBA_TYPE.
314af69d88dSmrg    */
315af69d88dSmrg   pcp->base.renderType = renderType;
316af69d88dSmrg
317af69d88dSmrg   pcp->driContext =
318af69d88dSmrg      (*psc->dri2->createContextAttribs) (psc->driScreen,
319af69d88dSmrg					  api,
320af69d88dSmrg					  config->driConfig,
321af69d88dSmrg					  shared,
322af69d88dSmrg					  num_ctx_attribs / 2,
323af69d88dSmrg					  ctx_attribs,
324af69d88dSmrg					  error,
325af69d88dSmrg					  pcp);
326af69d88dSmrg
327af69d88dSmrg   if (pcp->driContext == NULL)
328af69d88dSmrg      goto error_exit;
329af69d88dSmrg
330af69d88dSmrg   pcp->base.vtable = &dri2_context_vtable;
331af69d88dSmrg
332af69d88dSmrg   return &pcp->base;
333af69d88dSmrg
334af69d88dSmrgerror_exit:
335af69d88dSmrg   free(pcp);
336af69d88dSmrg
337af69d88dSmrg   return NULL;
338af69d88dSmrg}
339af69d88dSmrg
340cdc920a0Smrgstatic void
3413464ebd5Sriastradhdri2DestroyDrawable(__GLXDRIdrawable *base)
342cdc920a0Smrg{
3433464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base->psc;
3443464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
3453464ebd5Sriastradh   struct glx_display *dpyPriv = psc->base.display;
3463464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display;
3473464ebd5Sriastradh
3483464ebd5Sriastradh   __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable);
3493464ebd5Sriastradh   (*psc->core->destroyDrawable) (pdraw->driDrawable);
3503464ebd5Sriastradh
3513464ebd5Sriastradh   /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable
3523464ebd5Sriastradh    * now, as the application explicitly asked to destroy the GLX
3533464ebd5Sriastradh    * drawable.  Otherwise, for legacy drawables, we let the DRI2
3543464ebd5Sriastradh    * drawable linger on the server, since there's no good way of
3553464ebd5Sriastradh    * knowing when the application is done with it.  The server will
3563464ebd5Sriastradh    * destroy the DRI2 drawable when it destroys the X drawable or the
3573464ebd5Sriastradh    * client exits anyway. */
3583464ebd5Sriastradh   if (pdraw->base.xDrawable != pdraw->base.drawable)
3593464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable);
360cdc920a0Smrg
361af69d88dSmrg   free(pdraw);
362cdc920a0Smrg}
363cdc920a0Smrg
364cdc920a0Smrgstatic __GLXDRIdrawable *
3653464ebd5Sriastradhdri2CreateDrawable(struct glx_screen *base, XID xDrawable,
3663464ebd5Sriastradh		   GLXDrawable drawable, struct glx_config *config_base)
367cdc920a0Smrg{
3683464ebd5Sriastradh   struct dri2_drawable *pdraw;
3693464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
3703464ebd5Sriastradh   __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
3713464ebd5Sriastradh   struct glx_display *dpyPriv;
3723464ebd5Sriastradh   struct dri2_display *pdp;
3733464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
374cdc920a0Smrg
375af69d88dSmrg   dpyPriv = __glXInitialize(psc->base.dpy);
376af69d88dSmrg   if (dpyPriv == NULL)
377af69d88dSmrg      return NULL;
378af69d88dSmrg
379af69d88dSmrg   pdraw = calloc(1, sizeof(*pdraw));
380cdc920a0Smrg   if (!pdraw)
381cdc920a0Smrg      return NULL;
382cdc920a0Smrg
383cdc920a0Smrg   pdraw->base.destroyDrawable = dri2DestroyDrawable;
384cdc920a0Smrg   pdraw->base.xDrawable = xDrawable;
385cdc920a0Smrg   pdraw->base.drawable = drawable;
3863464ebd5Sriastradh   pdraw->base.psc = &psc->base;
387cdc920a0Smrg   pdraw->bufferCount = 0;
3883464ebd5Sriastradh   pdraw->swap_interval = 1; /* default may be overridden below */
389cdc920a0Smrg   pdraw->have_back = 0;
390cdc920a0Smrg
3913464ebd5Sriastradh   if (psc->config)
3923464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
3933464ebd5Sriastradh				"vblank_mode", &vblank_mode);
3943464ebd5Sriastradh
3953464ebd5Sriastradh   switch (vblank_mode) {
3963464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
3973464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
3983464ebd5Sriastradh      pdraw->swap_interval = 0;
3993464ebd5Sriastradh      break;
4003464ebd5Sriastradh   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
4013464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
4023464ebd5Sriastradh   default:
4033464ebd5Sriastradh      pdraw->swap_interval = 1;
4043464ebd5Sriastradh      break;
4053464ebd5Sriastradh   }
4063464ebd5Sriastradh
4073464ebd5Sriastradh   DRI2CreateDrawable(psc->base.dpy, xDrawable);
4083464ebd5Sriastradh   pdp = (struct dri2_display *)dpyPriv->dri2Display;;
409cdc920a0Smrg   /* Create a new drawable */
4103464ebd5Sriastradh   pdraw->driDrawable =
4113464ebd5Sriastradh      (*psc->dri2->createNewDrawable) (psc->driScreen,
412cdc920a0Smrg                                       config->driConfig, pdraw);
413cdc920a0Smrg
4143464ebd5Sriastradh   if (!pdraw->driDrawable) {
4153464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
416af69d88dSmrg      free(pdraw);
417cdc920a0Smrg      return NULL;
418cdc920a0Smrg   }
419cdc920a0Smrg
4203464ebd5Sriastradh   if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) {
4213464ebd5Sriastradh      (*psc->core->destroyDrawable) (pdraw->driDrawable);
4223464ebd5Sriastradh      DRI2DestroyDrawable(psc->base.dpy, xDrawable);
423af69d88dSmrg      free(pdraw);
4243464ebd5Sriastradh      return None;
4253464ebd5Sriastradh   }
4263464ebd5Sriastradh
427cdc920a0Smrg   /*
428cdc920a0Smrg    * Make sure server has the same swap interval we do for the new
429cdc920a0Smrg    * drawable.
430cdc920a0Smrg    */
431af69d88dSmrg   if (psc->vtable.setSwapInterval)
432af69d88dSmrg      psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval);
433cdc920a0Smrg
434cdc920a0Smrg   return &pdraw->base;
435cdc920a0Smrg}
436cdc920a0Smrg
437cdc920a0Smrgstatic int
4383464ebd5Sriastradhdri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
439cdc920a0Smrg		   int64_t *ust, int64_t *msc, int64_t *sbc)
440cdc920a0Smrg{
441af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
442af69d88dSmrg   xcb_dri2_get_msc_cookie_t get_msc_cookie;
443af69d88dSmrg   xcb_dri2_get_msc_reply_t *get_msc_reply;
4443464ebd5Sriastradh
445af69d88dSmrg   get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable);
446af69d88dSmrg   get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL);
4473464ebd5Sriastradh
448af69d88dSmrg   if (!get_msc_reply)
449af69d88dSmrg      return 0;
450cdc920a0Smrg
451af69d88dSmrg   *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo);
452af69d88dSmrg   *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo);
453af69d88dSmrg   *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo);
454af69d88dSmrg   free(get_msc_reply);
455cdc920a0Smrg
456af69d88dSmrg   return 1;
457af69d88dSmrg}
458cdc920a0Smrg
459cdc920a0Smrgstatic int
460cdc920a0Smrgdri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
461cdc920a0Smrg	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
462cdc920a0Smrg{
463af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
464af69d88dSmrg   xcb_dri2_wait_msc_cookie_t wait_msc_cookie;
465af69d88dSmrg   xcb_dri2_wait_msc_reply_t *wait_msc_reply;
466af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
467af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
468af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
469af69d88dSmrg
470af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
471af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
472af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
473af69d88dSmrg
474af69d88dSmrg   wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable,
475af69d88dSmrg                                                 target_msc_hi, target_msc_lo,
476af69d88dSmrg                                                 divisor_hi, divisor_lo,
477af69d88dSmrg                                                 remainder_hi, remainder_lo);
478af69d88dSmrg   wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL);
479af69d88dSmrg
480af69d88dSmrg   if (!wait_msc_reply)
481af69d88dSmrg      return 0;
482af69d88dSmrg
483af69d88dSmrg   *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo);
484af69d88dSmrg   *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo);
485af69d88dSmrg   *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo);
486af69d88dSmrg   free(wait_msc_reply);
487af69d88dSmrg
488af69d88dSmrg   return 1;
489cdc920a0Smrg}
490cdc920a0Smrg
491cdc920a0Smrgstatic int
492cdc920a0Smrgdri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
493cdc920a0Smrg	       int64_t *msc, int64_t *sbc)
494cdc920a0Smrg{
495af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
496af69d88dSmrg   xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie;
497af69d88dSmrg   xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
498af69d88dSmrg   uint32_t target_sbc_hi, target_sbc_lo;
4993464ebd5Sriastradh
500af69d88dSmrg   split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo);
5013464ebd5Sriastradh
502af69d88dSmrg   wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable,
503af69d88dSmrg                                                 target_sbc_hi, target_sbc_lo);
504af69d88dSmrg   wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL);
505af69d88dSmrg
506af69d88dSmrg   if (!wait_sbc_reply)
507af69d88dSmrg      return 0;
508af69d88dSmrg
509af69d88dSmrg   *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo);
510af69d88dSmrg   *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
511af69d88dSmrg   *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo);
512af69d88dSmrg   free(wait_sbc_reply);
513af69d88dSmrg
514af69d88dSmrg   return 1;
515cdc920a0Smrg}
516cdc920a0Smrg
517af69d88dSmrgstatic __DRIcontext *
518af69d88dSmrgdri2GetCurrentContext()
519af69d88dSmrg{
520af69d88dSmrg   struct glx_context *gc = __glXGetCurrentContext();
521af69d88dSmrg   struct dri2_context *dri2Ctx = (struct dri2_context *)gc;
522af69d88dSmrg
523af69d88dSmrg   return dri2Ctx ? dri2Ctx->driContext : NULL;
524af69d88dSmrg}
525af69d88dSmrg
526af69d88dSmrg/**
527af69d88dSmrg * dri2Throttle - Request driver throttling
528af69d88dSmrg *
529af69d88dSmrg * This function uses the DRI2 throttle extension to give the
530af69d88dSmrg * driver the opportunity to throttle on flush front, copysubbuffer
531af69d88dSmrg * and swapbuffers.
532af69d88dSmrg */
533af69d88dSmrgstatic void
534af69d88dSmrgdri2Throttle(struct dri2_screen *psc,
535af69d88dSmrg	     struct dri2_drawable *draw,
536af69d88dSmrg	     enum __DRI2throttleReason reason)
537af69d88dSmrg{
538af69d88dSmrg   if (psc->throttle) {
539af69d88dSmrg      __DRIcontext *ctx = dri2GetCurrentContext();
540af69d88dSmrg
541af69d88dSmrg      psc->throttle->throttle(ctx, draw->driDrawable, reason);
542af69d88dSmrg   }
543af69d88dSmrg}
544cdc920a0Smrg
545af69d88dSmrg/**
546af69d88dSmrg * Asks the driver to flush any queued work necessary for serializing with the
547af69d88dSmrg * X command stream, and optionally the slightly more strict requirement of
548af69d88dSmrg * glFlush() equivalence (which would require flushing even if nothing had
549af69d88dSmrg * been drawn to a window system framebuffer, for example).
550af69d88dSmrg */
551cdc920a0Smrgstatic void
552af69d88dSmrgdri2Flush(struct dri2_screen *psc,
553af69d88dSmrg          __DRIcontext *ctx,
554af69d88dSmrg          struct dri2_drawable *draw,
555af69d88dSmrg          unsigned flags,
556af69d88dSmrg          enum __DRI2throttleReason throttle_reason)
557af69d88dSmrg{
558af69d88dSmrg   if (ctx && psc->f && psc->f->base.version >= 4) {
559af69d88dSmrg      psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason);
560af69d88dSmrg   } else {
561af69d88dSmrg      if (flags & __DRI2_FLUSH_CONTEXT)
562af69d88dSmrg         glFlush();
563af69d88dSmrg
564af69d88dSmrg      if (psc->f)
565af69d88dSmrg         psc->f->flush(draw->driDrawable);
566af69d88dSmrg
567af69d88dSmrg      dri2Throttle(psc, draw, throttle_reason);
568af69d88dSmrg   }
569af69d88dSmrg}
570af69d88dSmrg
571af69d88dSmrgstatic void
572af69d88dSmrg__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
573af69d88dSmrg		    int width, int height,
574af69d88dSmrg		    enum __DRI2throttleReason reason, Bool flush)
575cdc920a0Smrg{
5763464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
5773464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc;
578cdc920a0Smrg   XRectangle xrect;
579cdc920a0Smrg   XserverRegion region;
580af69d88dSmrg   __DRIcontext *ctx = dri2GetCurrentContext();
581af69d88dSmrg   unsigned flags;
582cdc920a0Smrg
583cdc920a0Smrg   /* Check we have the right attachments */
584cdc920a0Smrg   if (!priv->have_back)
585cdc920a0Smrg      return;
586cdc920a0Smrg
587cdc920a0Smrg   xrect.x = x;
588cdc920a0Smrg   xrect.y = priv->height - y - height;
589cdc920a0Smrg   xrect.width = width;
590cdc920a0Smrg   xrect.height = height;
591cdc920a0Smrg
592af69d88dSmrg   flags = __DRI2_FLUSH_DRAWABLE;
593af69d88dSmrg   if (flush)
594af69d88dSmrg      flags |= __DRI2_FLUSH_CONTEXT;
595af69d88dSmrg   dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
596cdc920a0Smrg
5973464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
5983464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
599cdc920a0Smrg                  DRI2BufferFrontLeft, DRI2BufferBackLeft);
600cdc920a0Smrg
601cdc920a0Smrg   /* Refresh the fake front (if present) after we just damaged the real
602cdc920a0Smrg    * front.
603cdc920a0Smrg    */
6043464ebd5Sriastradh   if (priv->have_fake_front)
6053464ebd5Sriastradh      DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region,
6063464ebd5Sriastradh		     DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
6073464ebd5Sriastradh
6083464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
609cdc920a0Smrg}
610cdc920a0Smrg
611af69d88dSmrgstatic void
612af69d88dSmrgdri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y,
613af69d88dSmrg		  int width, int height, Bool flush)
614af69d88dSmrg{
615af69d88dSmrg   __dri2CopySubBuffer(pdraw, x, y, width, height,
616af69d88dSmrg		       __DRI2_THROTTLE_COPYSUBBUFFER, flush);
617af69d88dSmrg}
618af69d88dSmrg
619af69d88dSmrg
620cdc920a0Smrgstatic void
6213464ebd5Sriastradhdri2_copy_drawable(struct dri2_drawable *priv, int dest, int src)
622cdc920a0Smrg{
623cdc920a0Smrg   XRectangle xrect;
624cdc920a0Smrg   XserverRegion region;
6253464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
626cdc920a0Smrg
627cdc920a0Smrg   xrect.x = 0;
628cdc920a0Smrg   xrect.y = 0;
629cdc920a0Smrg   xrect.width = priv->width;
630cdc920a0Smrg   xrect.height = priv->height;
631cdc920a0Smrg
6323464ebd5Sriastradh   if (psc->f)
6333464ebd5Sriastradh      (*psc->f->flush) (priv->driDrawable);
634cdc920a0Smrg
6353464ebd5Sriastradh   region = XFixesCreateRegion(psc->base.dpy, &xrect, 1);
6363464ebd5Sriastradh   DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src);
6373464ebd5Sriastradh   XFixesDestroyRegion(psc->base.dpy, region);
6383464ebd5Sriastradh
639cdc920a0Smrg}
640cdc920a0Smrg
641cdc920a0Smrgstatic void
6423464ebd5Sriastradhdri2_wait_x(struct glx_context *gc)
643cdc920a0Smrg{
6443464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
6453464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
646cdc920a0Smrg
6473464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
648cdc920a0Smrg      return;
649cdc920a0Smrg
6503464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
6513464ebd5Sriastradh}
652cdc920a0Smrg
6533464ebd5Sriastradhstatic void
6543464ebd5Sriastradhdri2_wait_gl(struct glx_context *gc)
6553464ebd5Sriastradh{
6563464ebd5Sriastradh   struct dri2_drawable *priv = (struct dri2_drawable *)
6573464ebd5Sriastradh      GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable);
658cdc920a0Smrg
6593464ebd5Sriastradh   if (priv == NULL || !priv->have_fake_front)
6603464ebd5Sriastradh      return;
6613464ebd5Sriastradh
6623464ebd5Sriastradh   dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
663cdc920a0Smrg}
664cdc920a0Smrg
665af69d88dSmrg/**
666af69d88dSmrg * Called by the driver when it needs to update the real front buffer with the
667af69d88dSmrg * contents of its fake front buffer.
668af69d88dSmrg */
669cdc920a0Smrgstatic void
670cdc920a0Smrgdri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
671cdc920a0Smrg{
672af69d88dSmrg   struct glx_display *priv;
673af69d88dSmrg   struct dri2_display *pdp;
674af69d88dSmrg   struct glx_context *gc;
6753464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
676af69d88dSmrg   struct dri2_screen *psc;
677af69d88dSmrg
6783464ebd5Sriastradh   if (!pdraw)
6793464ebd5Sriastradh      return;
6803464ebd5Sriastradh
6813464ebd5Sriastradh   if (!pdraw->base.psc)
6823464ebd5Sriastradh      return;
6833464ebd5Sriastradh
684af69d88dSmrg   psc = (struct dri2_screen *) pdraw->base.psc;
685af69d88dSmrg
686af69d88dSmrg   priv = __glXInitialize(psc->base.dpy);
687af69d88dSmrg
688af69d88dSmrg   if (priv == NULL)
689af69d88dSmrg       return;
690af69d88dSmrg
691af69d88dSmrg   pdp = (struct dri2_display *) priv->dri2Display;
692af69d88dSmrg   gc = __glXGetCurrentContext();
693af69d88dSmrg
694af69d88dSmrg   dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT);
695cdc920a0Smrg
696cdc920a0Smrg   /* Old servers don't send invalidate events */
697cdc920a0Smrg   if (!pdp->invalidateAvailable)
6983464ebd5Sriastradh       dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable);
699cdc920a0Smrg
7003464ebd5Sriastradh   dri2_wait_gl(gc);
701cdc920a0Smrg}
702cdc920a0Smrg
703cdc920a0Smrg
704cdc920a0Smrgstatic void
7053464ebd5Sriastradhdri2DestroyScreen(struct glx_screen *base)
706cdc920a0Smrg{
7073464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) base;
7083464ebd5Sriastradh
709cdc920a0Smrg   /* Free the direct rendering per screen data */
7103464ebd5Sriastradh   (*psc->core->destroyScreen) (psc->driScreen);
7113464ebd5Sriastradh   driDestroyConfigs(psc->driver_configs);
712cdc920a0Smrg   close(psc->fd);
713af69d88dSmrg   free(psc);
714cdc920a0Smrg}
715cdc920a0Smrg
716cdc920a0Smrg/**
717cdc920a0Smrg * Process list of buffer received from the server
718cdc920a0Smrg *
719cdc920a0Smrg * Processes the list of buffers received in a reply from the server to either
720cdc920a0Smrg * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat.
721cdc920a0Smrg */
722cdc920a0Smrgstatic void
7233464ebd5Sriastradhprocess_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers,
724cdc920a0Smrg                unsigned count)
725cdc920a0Smrg{
726cdc920a0Smrg   int i;
727cdc920a0Smrg
728cdc920a0Smrg   pdraw->bufferCount = count;
729cdc920a0Smrg   pdraw->have_fake_front = 0;
730cdc920a0Smrg   pdraw->have_back = 0;
731cdc920a0Smrg
732cdc920a0Smrg   /* This assumes the DRI2 buffer attachment tokens matches the
733cdc920a0Smrg    * __DRIbuffer tokens. */
734cdc920a0Smrg   for (i = 0; i < count; i++) {
735cdc920a0Smrg      pdraw->buffers[i].attachment = buffers[i].attachment;
736cdc920a0Smrg      pdraw->buffers[i].name = buffers[i].name;
737cdc920a0Smrg      pdraw->buffers[i].pitch = buffers[i].pitch;
738cdc920a0Smrg      pdraw->buffers[i].cpp = buffers[i].cpp;
739cdc920a0Smrg      pdraw->buffers[i].flags = buffers[i].flags;
740cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
741cdc920a0Smrg         pdraw->have_fake_front = 1;
742cdc920a0Smrg      if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
743cdc920a0Smrg         pdraw->have_back = 1;
744cdc920a0Smrg   }
745cdc920a0Smrg
746cdc920a0Smrg}
747cdc920a0Smrg
7483464ebd5Sriastradhunsigned dri2GetSwapEventType(Display* dpy, XID drawable)
7493464ebd5Sriastradh{
7503464ebd5Sriastradh      struct glx_display *glx_dpy = __glXInitialize(dpy);
7513464ebd5Sriastradh      __GLXDRIdrawable *pdraw;
7523464ebd5Sriastradh      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
7533464ebd5Sriastradh      if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
7543464ebd5Sriastradh         return 0;
7553464ebd5Sriastradh      return glx_dpy->codes->first_event + GLX_BufferSwapComplete;
7563464ebd5Sriastradh}
7573464ebd5Sriastradh
758af69d88dSmrgstatic void show_fps(struct dri2_drawable *draw)
759af69d88dSmrg{
760af69d88dSmrg   const int interval =
761af69d88dSmrg      ((struct dri2_screen *) draw->base.psc)->show_fps_interval;
762af69d88dSmrg   struct timeval tv;
763af69d88dSmrg   uint64_t current_time;
764af69d88dSmrg
765af69d88dSmrg   gettimeofday(&tv, 0);
766af69d88dSmrg   current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec;
767af69d88dSmrg
768af69d88dSmrg   draw->frames++;
769af69d88dSmrg
770af69d88dSmrg   if (draw->previous_time + interval * 1000000 <= current_time) {
771af69d88dSmrg      if (draw->previous_time) {
772af69d88dSmrg         fprintf(stderr, "libGL: FPS = %.1f\n",
773af69d88dSmrg                 ((uint64_t)draw->frames * 1000000) /
774af69d88dSmrg                 (double)(current_time - draw->previous_time));
775af69d88dSmrg      }
776af69d88dSmrg      draw->frames = 0;
777af69d88dSmrg      draw->previous_time = current_time;
778af69d88dSmrg   }
779af69d88dSmrg}
780af69d88dSmrg
781af69d88dSmrgstatic int64_t
782af69d88dSmrgdri2XcbSwapBuffers(Display *dpy,
783af69d88dSmrg                  __GLXDRIdrawable *pdraw,
784af69d88dSmrg                  int64_t target_msc,
785af69d88dSmrg                  int64_t divisor,
786af69d88dSmrg                  int64_t remainder)
787af69d88dSmrg{
788af69d88dSmrg   xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie;
789af69d88dSmrg   xcb_dri2_swap_buffers_reply_t *swap_buffers_reply;
790af69d88dSmrg   uint32_t target_msc_hi, target_msc_lo;
791af69d88dSmrg   uint32_t divisor_hi, divisor_lo;
792af69d88dSmrg   uint32_t remainder_hi, remainder_lo;
793af69d88dSmrg   int64_t ret = 0;
794af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(dpy);
795af69d88dSmrg
796af69d88dSmrg   split_counter(target_msc, &target_msc_hi, &target_msc_lo);
797af69d88dSmrg   split_counter(divisor, &divisor_hi, &divisor_lo);
798af69d88dSmrg   split_counter(remainder, &remainder_hi, &remainder_lo);
799af69d88dSmrg
800af69d88dSmrg   swap_buffers_cookie =
801af69d88dSmrg      xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable,
802af69d88dSmrg                                      target_msc_hi, target_msc_lo,
803af69d88dSmrg                                      divisor_hi, divisor_lo,
804af69d88dSmrg                                      remainder_hi, remainder_lo);
805af69d88dSmrg
806af69d88dSmrg   /* Immediately wait on the swapbuffers reply.  If we didn't, we'd have
807af69d88dSmrg    * to do so some time before reusing a (non-pageflipped) backbuffer.
808af69d88dSmrg    * Otherwise, the new rendering could get ahead of the X Server's
809af69d88dSmrg    * dispatch of the swapbuffer and you'd display garbage.
810af69d88dSmrg    *
811af69d88dSmrg    * We use XSync() first to reap the invalidate events through the event
812af69d88dSmrg    * filter, to ensure that the next drawing doesn't use an invalidated
813af69d88dSmrg    * buffer.
814af69d88dSmrg    */
815af69d88dSmrg   XSync(dpy, False);
816af69d88dSmrg
817af69d88dSmrg   swap_buffers_reply =
818af69d88dSmrg      xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL);
819af69d88dSmrg   if (swap_buffers_reply) {
820af69d88dSmrg      ret = merge_counter(swap_buffers_reply->swap_hi,
821af69d88dSmrg                          swap_buffers_reply->swap_lo);
822af69d88dSmrg      free(swap_buffers_reply);
823af69d88dSmrg   }
824af69d88dSmrg   return ret;
825af69d88dSmrg}
826af69d88dSmrg
827cdc920a0Smrgstatic int64_t
828cdc920a0Smrgdri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
829af69d88dSmrg		int64_t remainder, Bool flush)
830cdc920a0Smrg{
8313464ebd5Sriastradh    struct dri2_drawable *priv = (struct dri2_drawable *) pdraw;
8323464ebd5Sriastradh    struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy);
8333464ebd5Sriastradh    struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
8343464ebd5Sriastradh    struct dri2_display *pdp =
8353464ebd5Sriastradh	(struct dri2_display *)dpyPriv->dri2Display;
836af69d88dSmrg    int64_t ret = 0;
837cdc920a0Smrg
8383464ebd5Sriastradh    /* Check we have the right attachments */
8393464ebd5Sriastradh    if (!priv->have_back)
8403464ebd5Sriastradh	return ret;
841cdc920a0Smrg
842cdc920a0Smrg    /* Old servers can't handle swapbuffers */
843cdc920a0Smrg    if (!pdp->swapAvailable) {
844af69d88dSmrg       __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height,
845af69d88dSmrg			   __DRI2_THROTTLE_SWAPBUFFER, flush);
8463464ebd5Sriastradh    } else {
847af69d88dSmrg       __DRIcontext *ctx = dri2GetCurrentContext();
848af69d88dSmrg       unsigned flags = __DRI2_FLUSH_DRAWABLE;
849af69d88dSmrg       if (flush)
850af69d88dSmrg          flags |= __DRI2_FLUSH_CONTEXT;
851af69d88dSmrg       dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER);
852af69d88dSmrg
853af69d88dSmrg       ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
854af69d88dSmrg                                target_msc, divisor, remainder);
855cdc920a0Smrg    }
856cdc920a0Smrg
857af69d88dSmrg    if (psc->show_fps_interval) {
858af69d88dSmrg       show_fps(priv);
8593464ebd5Sriastradh    }
8603464ebd5Sriastradh
8613464ebd5Sriastradh    /* Old servers don't send invalidate events */
8623464ebd5Sriastradh    if (!pdp->invalidateAvailable)
8633464ebd5Sriastradh       dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable);
864cdc920a0Smrg
865cdc920a0Smrg    return ret;
866cdc920a0Smrg}
867cdc920a0Smrg
868cdc920a0Smrgstatic __DRIbuffer *
869cdc920a0Smrgdri2GetBuffers(__DRIdrawable * driDrawable,
870cdc920a0Smrg               int *width, int *height,
871cdc920a0Smrg               unsigned int *attachments, int count,
872cdc920a0Smrg               int *out_count, void *loaderPrivate)
873cdc920a0Smrg{
8743464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
875cdc920a0Smrg   DRI2Buffer *buffers;
876cdc920a0Smrg
877cdc920a0Smrg   buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable,
878cdc920a0Smrg                            width, height, attachments, count, out_count);
879cdc920a0Smrg   if (buffers == NULL)
880cdc920a0Smrg      return NULL;
881cdc920a0Smrg
882cdc920a0Smrg   pdraw->width = *width;
883cdc920a0Smrg   pdraw->height = *height;
884cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
885cdc920a0Smrg
886af69d88dSmrg   free(buffers);
887cdc920a0Smrg
888cdc920a0Smrg   return pdraw->buffers;
889cdc920a0Smrg}
890cdc920a0Smrg
891cdc920a0Smrgstatic __DRIbuffer *
892cdc920a0Smrgdri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
893cdc920a0Smrg                         int *width, int *height,
894cdc920a0Smrg                         unsigned int *attachments, int count,
895cdc920a0Smrg                         int *out_count, void *loaderPrivate)
896cdc920a0Smrg{
8973464ebd5Sriastradh   struct dri2_drawable *pdraw = loaderPrivate;
898cdc920a0Smrg   DRI2Buffer *buffers;
899cdc920a0Smrg
900cdc920a0Smrg   buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy,
901cdc920a0Smrg                                      pdraw->base.xDrawable,
902cdc920a0Smrg                                      width, height, attachments,
903cdc920a0Smrg                                      count, out_count);
904cdc920a0Smrg   if (buffers == NULL)
905cdc920a0Smrg      return NULL;
906cdc920a0Smrg
907cdc920a0Smrg   pdraw->width = *width;
908cdc920a0Smrg   pdraw->height = *height;
909cdc920a0Smrg   process_buffers(pdraw, buffers, *out_count);
910cdc920a0Smrg
911af69d88dSmrg   free(buffers);
912cdc920a0Smrg
913cdc920a0Smrg   return pdraw->buffers;
914cdc920a0Smrg}
915cdc920a0Smrg
9163464ebd5Sriastradhstatic int
917cdc920a0Smrgdri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
918cdc920a0Smrg{
919af69d88dSmrg   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
9203464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
9213464ebd5Sriastradh   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
9223464ebd5Sriastradh   struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc;
9233464ebd5Sriastradh
9243464ebd5Sriastradh   if (psc->config)
9253464ebd5Sriastradh      psc->config->configQueryi(psc->driScreen,
9263464ebd5Sriastradh				"vblank_mode", &vblank_mode);
9273464ebd5Sriastradh
9283464ebd5Sriastradh   switch (vblank_mode) {
9293464ebd5Sriastradh   case DRI_CONF_VBLANK_NEVER:
930af69d88dSmrg      if (interval != 0)
931af69d88dSmrg         return GLX_BAD_VALUE;
932af69d88dSmrg      break;
9333464ebd5Sriastradh   case DRI_CONF_VBLANK_ALWAYS_SYNC:
9343464ebd5Sriastradh      if (interval <= 0)
9353464ebd5Sriastradh	 return GLX_BAD_VALUE;
9363464ebd5Sriastradh      break;
9373464ebd5Sriastradh   default:
9383464ebd5Sriastradh      break;
9393464ebd5Sriastradh   }
940cdc920a0Smrg
941af69d88dSmrg   xcb_dri2_swap_interval(c, priv->base.xDrawable, interval);
942cdc920a0Smrg   priv->swap_interval = interval;
9433464ebd5Sriastradh
9443464ebd5Sriastradh   return 0;
945cdc920a0Smrg}
946cdc920a0Smrg
9473464ebd5Sriastradhstatic int
948cdc920a0Smrgdri2GetSwapInterval(__GLXDRIdrawable *pdraw)
949cdc920a0Smrg{
9503464ebd5Sriastradh   struct dri2_drawable *priv =  (struct dri2_drawable *) pdraw;
951cdc920a0Smrg
952cdc920a0Smrg  return priv->swap_interval;
953cdc920a0Smrg}
954cdc920a0Smrg
955cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension = {
956af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
957af69d88dSmrg
958af69d88dSmrg   .getBuffers              = dri2GetBuffers,
959af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
960af69d88dSmrg   .getBuffersWithFormat    = dri2GetBuffersWithFormat,
961cdc920a0Smrg};
962cdc920a0Smrg
963cdc920a0Smrgstatic const __DRIdri2LoaderExtension dri2LoaderExtension_old = {
964af69d88dSmrg   .base = { __DRI_DRI2_LOADER, 3 },
965af69d88dSmrg
966af69d88dSmrg   .getBuffers              = dri2GetBuffers,
967af69d88dSmrg   .flushFrontBuffer        = dri2FlushFrontBuffer,
968af69d88dSmrg   .getBuffersWithFormat    = NULL,
969cdc920a0Smrg};
970cdc920a0Smrg
9713464ebd5Sriastradhstatic const __DRIuseInvalidateExtension dri2UseInvalidate = {
972af69d88dSmrg   .base = { __DRI_USE_INVALIDATE, 1 }
973cdc920a0Smrg};
974cdc920a0Smrg
975cdc920a0Smrg_X_HIDDEN void
976cdc920a0Smrgdri2InvalidateBuffers(Display *dpy, XID drawable)
977cdc920a0Smrg{
9783464ebd5Sriastradh   __GLXDRIdrawable *pdraw =
9793464ebd5Sriastradh      dri2GetGlxDrawableFromXDrawableId(dpy, drawable);
9803464ebd5Sriastradh   struct dri2_screen *psc;
9813464ebd5Sriastradh   struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw;
9823464ebd5Sriastradh
9833464ebd5Sriastradh   if (!pdraw)
9843464ebd5Sriastradh      return;
9853464ebd5Sriastradh
9863464ebd5Sriastradh   psc = (struct dri2_screen *) pdraw->psc;
987cdc920a0Smrg
9883464ebd5Sriastradh   if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate)
9893464ebd5Sriastradh       psc->f->invalidate(pdp->driDrawable);
990cdc920a0Smrg}
991cdc920a0Smrg
9923464ebd5Sriastradhstatic void
9933464ebd5Sriastradhdri2_bind_tex_image(Display * dpy,
9943464ebd5Sriastradh		    GLXDrawable drawable,
9953464ebd5Sriastradh		    int buffer, const int *attrib_list)
9963464ebd5Sriastradh{
9973464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
9983464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
9993464ebd5Sriastradh   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
10003464ebd5Sriastradh   struct glx_display *dpyPriv = __glXInitialize(dpy);
10013464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
1002af69d88dSmrg   struct dri2_display *pdp;
10033464ebd5Sriastradh   struct dri2_screen *psc;
10043464ebd5Sriastradh
1005af69d88dSmrg   if (dpyPriv == NULL)
1006af69d88dSmrg       return;
1007af69d88dSmrg
1008af69d88dSmrg   pdp = (struct dri2_display *) dpyPriv->dri2Display;
1009af69d88dSmrg
10103464ebd5Sriastradh   if (pdraw != NULL) {
10113464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
10123464ebd5Sriastradh
10133464ebd5Sriastradh      if (!pdp->invalidateAvailable && psc->f &&
10143464ebd5Sriastradh           psc->f->base.version >= 3 && psc->f->invalidate)
10153464ebd5Sriastradh	 psc->f->invalidate(pdraw->driDrawable);
10163464ebd5Sriastradh
10173464ebd5Sriastradh      if (psc->texBuffer->base.version >= 2 &&
10183464ebd5Sriastradh	  psc->texBuffer->setTexBuffer2 != NULL) {
10193464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
10203464ebd5Sriastradh					   pdraw->base.textureTarget,
10213464ebd5Sriastradh					   pdraw->base.textureFormat,
10223464ebd5Sriastradh					   pdraw->driDrawable);
10233464ebd5Sriastradh      }
10243464ebd5Sriastradh      else {
10253464ebd5Sriastradh	 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
10263464ebd5Sriastradh					  pdraw->base.textureTarget,
10273464ebd5Sriastradh					  pdraw->driDrawable);
10283464ebd5Sriastradh      }
10293464ebd5Sriastradh   }
10303464ebd5Sriastradh}
10313464ebd5Sriastradh
10323464ebd5Sriastradhstatic void
10333464ebd5Sriastradhdri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
10343464ebd5Sriastradh{
10353464ebd5Sriastradh   struct glx_context *gc = __glXGetCurrentContext();
10363464ebd5Sriastradh   struct dri2_context *pcp = (struct dri2_context *) gc;
10373464ebd5Sriastradh   __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
10383464ebd5Sriastradh   struct glx_display *dpyPriv = __glXInitialize(dpy);
10393464ebd5Sriastradh   struct dri2_drawable *pdraw = (struct dri2_drawable *) base;
10403464ebd5Sriastradh   struct dri2_screen *psc;
10413464ebd5Sriastradh
1042af69d88dSmrg   if (dpyPriv != NULL && pdraw != NULL) {
10433464ebd5Sriastradh      psc = (struct dri2_screen *) base->psc;
10443464ebd5Sriastradh
10453464ebd5Sriastradh      if (psc->texBuffer->base.version >= 3 &&
10463464ebd5Sriastradh          psc->texBuffer->releaseTexBuffer != NULL) {
10473464ebd5Sriastradh         (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
10483464ebd5Sriastradh                                           pdraw->base.textureTarget,
10493464ebd5Sriastradh                                           pdraw->driDrawable);
10503464ebd5Sriastradh      }
10513464ebd5Sriastradh   }
10523464ebd5Sriastradh}
10533464ebd5Sriastradh
10543464ebd5Sriastradhstatic const struct glx_context_vtable dri2_context_vtable = {
1055af69d88dSmrg   .destroy             = dri2_destroy_context,
1056af69d88dSmrg   .bind                = dri2_bind_context,
1057af69d88dSmrg   .unbind              = dri2_unbind_context,
1058af69d88dSmrg   .wait_gl             = dri2_wait_gl,
1059af69d88dSmrg   .wait_x              = dri2_wait_x,
1060af69d88dSmrg   .use_x_font          = DRI_glXUseXFont,
1061af69d88dSmrg   .bind_tex_image      = dri2_bind_tex_image,
1062af69d88dSmrg   .release_tex_image   = dri2_release_tex_image,
1063af69d88dSmrg   .get_proc_address    = NULL,
10643464ebd5Sriastradh};
10653464ebd5Sriastradh
10663464ebd5Sriastradhstatic void
1067af69d88dSmrgdri2BindExtensions(struct dri2_screen *psc, struct glx_display * priv,
1068af69d88dSmrg                   const char *driverName)
10693464ebd5Sriastradh{
1070af69d88dSmrg   const struct dri2_display *const pdp = (struct dri2_display *)
1071af69d88dSmrg      priv->dri2Display;
1072af69d88dSmrg   const __DRIextension **extensions;
10733464ebd5Sriastradh   int i;
10743464ebd5Sriastradh
1075af69d88dSmrg   extensions = psc->core->getExtensions(psc->driScreen);
1076af69d88dSmrg
10773464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
10783464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
10793464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
10803464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
10813464ebd5Sriastradh
1082af69d88dSmrg   /*
1083af69d88dSmrg    * GLX_INTEL_swap_event is broken on the server side, where it's
1084af69d88dSmrg    * currently unconditionally enabled. This completely breaks
1085af69d88dSmrg    * systems running on drivers which don't support that extension.
1086af69d88dSmrg    * There's no way to test for its presence on this side, so instead
1087af69d88dSmrg    * of disabling it unconditionally, just disable it for drivers
1088af69d88dSmrg    * which are known to not support it, or for DDX drivers supporting
1089af69d88dSmrg    * only an older (pre-ScheduleSwap) version of DRI2.
1090af69d88dSmrg    *
1091af69d88dSmrg    * This is a hack which is required until:
1092af69d88dSmrg    * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
1093af69d88dSmrg    * is merged and updated xserver makes it's way into distros:
1094af69d88dSmrg    */
1095af69d88dSmrg   if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
1096af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
1097af69d88dSmrg   }
1098af69d88dSmrg
1099af69d88dSmrg   if (psc->dri2->base.version >= 3) {
1100af69d88dSmrg      const unsigned mask = psc->dri2->getAPIMask(psc->driScreen);
1101af69d88dSmrg
1102af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
1103af69d88dSmrg      __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
1104af69d88dSmrg
1105af69d88dSmrg      if ((mask & (1 << __DRI_API_GLES2)) != 0)
1106af69d88dSmrg	 __glXEnableDirectExtension(&psc->base,
1107af69d88dSmrg				    "GLX_EXT_create_context_es2_profile");
1108af69d88dSmrg   }
11093464ebd5Sriastradh
11103464ebd5Sriastradh   for (i = 0; extensions[i]; i++) {
11113464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
11123464ebd5Sriastradh	 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
11133464ebd5Sriastradh	 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
11143464ebd5Sriastradh      }
11153464ebd5Sriastradh
11163464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
11173464ebd5Sriastradh	 psc->f = (__DRI2flushExtension *) extensions[i];
11183464ebd5Sriastradh	 /* internal driver extension, no GL extension exposed */
11193464ebd5Sriastradh      }
11203464ebd5Sriastradh
11213464ebd5Sriastradh      if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
11223464ebd5Sriastradh	 psc->config = (__DRI2configQueryExtension *) extensions[i];
1123af69d88dSmrg
1124af69d88dSmrg      if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0)))
1125af69d88dSmrg	 psc->throttle = (__DRI2throttleExtension *) extensions[i];
1126af69d88dSmrg
1127af69d88dSmrg      /* DRI2 version 3 is also required because
1128af69d88dSmrg       * GLX_ARB_create_context_robustness requires GLX_ARB_create_context.
1129af69d88dSmrg       */
1130af69d88dSmrg      if (psc->dri2->base.version >= 3
1131af69d88dSmrg          && strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
1132af69d88dSmrg         __glXEnableDirectExtension(&psc->base,
1133af69d88dSmrg                                    "GLX_ARB_create_context_robustness");
1134af69d88dSmrg
1135af69d88dSmrg      /* DRI2 version 3 is also required because GLX_MESA_query_renderer
1136af69d88dSmrg       * requires GLX_ARB_create_context_profile.
1137af69d88dSmrg       */
1138af69d88dSmrg      if (psc->dri2->base.version >= 3
1139af69d88dSmrg          && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
1140af69d88dSmrg         psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
1141af69d88dSmrg         __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
1142af69d88dSmrg      }
11433464ebd5Sriastradh   }
11443464ebd5Sriastradh}
11453464ebd5Sriastradh
11463464ebd5Sriastradhstatic const struct glx_screen_vtable dri2_screen_vtable = {
1147af69d88dSmrg   .create_context         = dri2_create_context,
1148af69d88dSmrg   .create_context_attribs = dri2_create_context_attribs,
1149af69d88dSmrg   .query_renderer_integer = dri2_query_renderer_integer,
1150af69d88dSmrg   .query_renderer_string  = dri2_query_renderer_string,
11513464ebd5Sriastradh};
11523464ebd5Sriastradh
11533464ebd5Sriastradhstatic struct glx_screen *
11543464ebd5Sriastradhdri2CreateScreen(int screen, struct glx_display * priv)
1155cdc920a0Smrg{
1156cdc920a0Smrg   const __DRIconfig **driver_configs;
1157cdc920a0Smrg   const __DRIextension **extensions;
11583464ebd5Sriastradh   const struct dri2_display *const pdp = (struct dri2_display *)
1159cdc920a0Smrg      priv->dri2Display;
11603464ebd5Sriastradh   struct dri2_screen *psc;
1161cdc920a0Smrg   __GLXDRIscreen *psp;
1162af69d88dSmrg   struct glx_config *configs = NULL, *visuals = NULL;
1163af69d88dSmrg   char *driverName = NULL, *loader_driverName, *deviceName, *tmp;
1164cdc920a0Smrg   drm_magic_t magic;
1165cdc920a0Smrg   int i;
1166cdc920a0Smrg
1167af69d88dSmrg   psc = calloc(1, sizeof *psc);
11683464ebd5Sriastradh   if (psc == NULL)
11693464ebd5Sriastradh      return NULL;
11703464ebd5Sriastradh
11713464ebd5Sriastradh   psc->fd = -1;
11723464ebd5Sriastradh
11733464ebd5Sriastradh   if (!glx_screen_init(&psc->base, screen, priv)) {
1174af69d88dSmrg      free(psc);
1175cdc920a0Smrg      return NULL;
11763464ebd5Sriastradh   }
1177cdc920a0Smrg
11783464ebd5Sriastradh   if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen),
1179cdc920a0Smrg		    &driverName, &deviceName)) {
11803464ebd5Sriastradh      glx_screen_cleanup(&psc->base);
1181af69d88dSmrg      free(psc);
1182af69d88dSmrg      InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen);
1183cdc920a0Smrg      return NULL;
1184cdc920a0Smrg   }
1185cdc920a0Smrg
1186af69d88dSmrg#ifdef O_CLOEXEC
1187af69d88dSmrg   psc->fd = open(deviceName, O_RDWR | O_CLOEXEC);
1188af69d88dSmrg   if (psc->fd == -1 && errno == EINVAL)
1189af69d88dSmrg#endif
1190af69d88dSmrg   {
1191af69d88dSmrg      psc->fd = open(deviceName, O_RDWR);
1192af69d88dSmrg      if (psc->fd != -1)
1193af69d88dSmrg         fcntl(psc->fd, F_SETFD, fcntl(psc->fd, F_GETFD) | FD_CLOEXEC);
1194af69d88dSmrg   }
1195af69d88dSmrg   if (psc->fd < 0) {
1196af69d88dSmrg      ErrorMessageF("failed to open drm device: %s\n", strerror(errno));
1197af69d88dSmrg      goto handle_error;
1198af69d88dSmrg   }
1199af69d88dSmrg
1200af69d88dSmrg   if (drmGetMagic(psc->fd, &magic)) {
1201af69d88dSmrg      ErrorMessageF("failed to get magic\n");
1202af69d88dSmrg      goto handle_error;
1203af69d88dSmrg   }
1204af69d88dSmrg
1205af69d88dSmrg   if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) {
1206af69d88dSmrg      ErrorMessageF("failed to authenticate magic %d\n", magic);
1207af69d88dSmrg      goto handle_error;
1208af69d88dSmrg   }
1209af69d88dSmrg
1210af69d88dSmrg   /* If Mesa knows about the appropriate driver for this fd, then trust it.
1211af69d88dSmrg    * Otherwise, default to the server's value.
1212af69d88dSmrg    */
1213af69d88dSmrg   loader_driverName = loader_get_driver_for_fd(psc->fd, 0);
1214af69d88dSmrg   if (loader_driverName) {
1215af69d88dSmrg      free(driverName);
1216af69d88dSmrg      driverName = loader_driverName;
1217af69d88dSmrg   }
1218af69d88dSmrg
1219cdc920a0Smrg   psc->driver = driOpenDriver(driverName);
1220cdc920a0Smrg   if (psc->driver == NULL) {
1221cdc920a0Smrg      ErrorMessageF("driver pointer missing\n");
1222cdc920a0Smrg      goto handle_error;
1223cdc920a0Smrg   }
1224cdc920a0Smrg
1225af69d88dSmrg   extensions = driGetDriverExtensions(psc->driver, driverName);
1226af69d88dSmrg   if (extensions == NULL)
1227cdc920a0Smrg      goto handle_error;
1228cdc920a0Smrg
1229cdc920a0Smrg   for (i = 0; extensions[i]; i++) {
1230cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
1231cdc920a0Smrg	 psc->core = (__DRIcoreExtension *) extensions[i];
1232cdc920a0Smrg      if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
1233cdc920a0Smrg	 psc->dri2 = (__DRIdri2Extension *) extensions[i];
1234cdc920a0Smrg   }
1235cdc920a0Smrg
1236cdc920a0Smrg   if (psc->core == NULL || psc->dri2 == NULL) {
1237cdc920a0Smrg      ErrorMessageF("core dri or dri2 extension not found\n");
1238cdc920a0Smrg      goto handle_error;
1239cdc920a0Smrg   }
1240cdc920a0Smrg
1241af69d88dSmrg   if (psc->dri2->base.version >= 4) {
1242af69d88dSmrg      psc->driScreen =
1243af69d88dSmrg         psc->dri2->createNewScreen2(screen, psc->fd,
1244af69d88dSmrg                                     (const __DRIextension **)
1245af69d88dSmrg                                     &pdp->loader_extensions[0],
1246af69d88dSmrg                                     extensions,
1247af69d88dSmrg                                     &driver_configs, psc);
1248af69d88dSmrg   } else {
1249af69d88dSmrg      psc->driScreen =
1250af69d88dSmrg         psc->dri2->createNewScreen(screen, psc->fd,
1251af69d88dSmrg                                    (const __DRIextension **)
1252af69d88dSmrg                                    &pdp->loader_extensions[0],
1253af69d88dSmrg                                    &driver_configs, psc);
1254cdc920a0Smrg   }
1255cdc920a0Smrg
1256af69d88dSmrg   if (psc->driScreen == NULL) {
1257af69d88dSmrg      ErrorMessageF("failed to create dri screen\n");
1258cdc920a0Smrg      goto handle_error;
1259cdc920a0Smrg   }
1260cdc920a0Smrg
1261af69d88dSmrg   dri2BindExtensions(psc, priv, driverName);
1262cdc920a0Smrg
1263af69d88dSmrg   configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1264af69d88dSmrg   visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1265cdc920a0Smrg
1266af69d88dSmrg   if (!configs || !visuals) {
1267af69d88dSmrg       ErrorMessageF("No matching fbConfigs or visuals found\n");
1268af69d88dSmrg       goto handle_error;
1269cdc920a0Smrg   }
1270cdc920a0Smrg
1271af69d88dSmrg   glx_config_destroy_list(psc->base.configs);
1272af69d88dSmrg   psc->base.configs = configs;
1273af69d88dSmrg   glx_config_destroy_list(psc->base.visuals);
1274af69d88dSmrg   psc->base.visuals = visuals;
1275cdc920a0Smrg
1276cdc920a0Smrg   psc->driver_configs = driver_configs;
1277cdc920a0Smrg
12783464ebd5Sriastradh   psc->base.vtable = &dri2_screen_vtable;
12793464ebd5Sriastradh   psp = &psc->vtable;
12803464ebd5Sriastradh   psc->base.driScreen = psp;
1281cdc920a0Smrg   psp->destroyScreen = dri2DestroyScreen;
1282cdc920a0Smrg   psp->createDrawable = dri2CreateDrawable;
1283cdc920a0Smrg   psp->swapBuffers = dri2SwapBuffers;
1284cdc920a0Smrg   psp->getDrawableMSC = NULL;
1285cdc920a0Smrg   psp->waitForMSC = NULL;
1286cdc920a0Smrg   psp->waitForSBC = NULL;
1287cdc920a0Smrg   psp->setSwapInterval = NULL;
1288cdc920a0Smrg   psp->getSwapInterval = NULL;
1289af69d88dSmrg   psp->getBufferAge = NULL;
1290cdc920a0Smrg
1291cdc920a0Smrg   if (pdp->driMinor >= 2) {
1292cdc920a0Smrg      psp->getDrawableMSC = dri2DrawableGetMSC;
1293cdc920a0Smrg      psp->waitForMSC = dri2WaitForMSC;
1294cdc920a0Smrg      psp->waitForSBC = dri2WaitForSBC;
1295cdc920a0Smrg      psp->setSwapInterval = dri2SetSwapInterval;
1296cdc920a0Smrg      psp->getSwapInterval = dri2GetSwapInterval;
12973464ebd5Sriastradh      __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control");
1298cdc920a0Smrg   }
1299cdc920a0Smrg
1300cdc920a0Smrg   /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always
1301cdc920a0Smrg    * available.*/
1302cdc920a0Smrg   psp->copySubBuffer = dri2CopySubBuffer;
13033464ebd5Sriastradh   __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
1304cdc920a0Smrg
1305af69d88dSmrg   free(driverName);
1306af69d88dSmrg   free(deviceName);
1307af69d88dSmrg
1308af69d88dSmrg   tmp = getenv("LIBGL_SHOW_FPS");
1309af69d88dSmrg   psc->show_fps_interval = (tmp) ? atoi(tmp) : 0;
1310af69d88dSmrg   if (psc->show_fps_interval < 0)
1311af69d88dSmrg      psc->show_fps_interval = 0;
1312cdc920a0Smrg
13133464ebd5Sriastradh   return &psc->base;
1314cdc920a0Smrg
1315cdc920a0Smrghandle_error:
1316af69d88dSmrg   CriticalErrorMessageF("failed to load driver: %s\n", driverName);
1317af69d88dSmrg
1318af69d88dSmrg   if (configs)
1319af69d88dSmrg       glx_config_destroy_list(configs);
1320af69d88dSmrg   if (visuals)
1321af69d88dSmrg       glx_config_destroy_list(visuals);
1322af69d88dSmrg   if (psc->driScreen)
1323af69d88dSmrg       psc->core->destroyScreen(psc->driScreen);
1324af69d88dSmrg   psc->driScreen = NULL;
13253464ebd5Sriastradh   if (psc->fd >= 0)
13263464ebd5Sriastradh      close(psc->fd);
13273464ebd5Sriastradh   if (psc->driver)
13283464ebd5Sriastradh      dlclose(psc->driver);
1329af69d88dSmrg
1330af69d88dSmrg   free(driverName);
1331af69d88dSmrg   free(deviceName);
13323464ebd5Sriastradh   glx_screen_cleanup(&psc->base);
1333af69d88dSmrg   free(psc);
1334cdc920a0Smrg
1335cdc920a0Smrg   return NULL;
1336cdc920a0Smrg}
1337cdc920a0Smrg
1338cdc920a0Smrg/* Called from __glXFreeDisplayPrivate.
1339cdc920a0Smrg */
1340cdc920a0Smrgstatic void
1341cdc920a0Smrgdri2DestroyDisplay(__GLXDRIdisplay * dpy)
1342cdc920a0Smrg{
13433464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) dpy;
13443464ebd5Sriastradh
13453464ebd5Sriastradh   __glxHashDestroy(pdp->dri2Hash);
1346af69d88dSmrg   free(dpy);
1347cdc920a0Smrg}
1348cdc920a0Smrg
13493464ebd5Sriastradh_X_HIDDEN __GLXDRIdrawable *
13503464ebd5Sriastradhdri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id)
13513464ebd5Sriastradh{
13523464ebd5Sriastradh   struct glx_display *d = __glXInitialize(dpy);
13533464ebd5Sriastradh   struct dri2_display *pdp = (struct dri2_display *) d->dri2Display;
13543464ebd5Sriastradh   __GLXDRIdrawable *pdraw;
13553464ebd5Sriastradh
13563464ebd5Sriastradh   if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0)
13573464ebd5Sriastradh      return pdraw;
13583464ebd5Sriastradh
13593464ebd5Sriastradh   return NULL;
13603464ebd5Sriastradh}
13613464ebd5Sriastradh
1362cdc920a0Smrg/*
1363cdc920a0Smrg * Allocate, initialize and return a __DRIdisplayPrivate object.
1364cdc920a0Smrg * This is called from __glXInitialize() when we are given a new
1365cdc920a0Smrg * display pointer.
1366cdc920a0Smrg */
1367cdc920a0Smrg_X_HIDDEN __GLXDRIdisplay *
1368cdc920a0Smrgdri2CreateDisplay(Display * dpy)
1369cdc920a0Smrg{
13703464ebd5Sriastradh   struct dri2_display *pdp;
13713464ebd5Sriastradh   int eventBase, errorBase, i;
1372cdc920a0Smrg
1373cdc920a0Smrg   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase))
1374cdc920a0Smrg      return NULL;
1375cdc920a0Smrg
1376af69d88dSmrg   pdp = malloc(sizeof *pdp);
1377cdc920a0Smrg   if (pdp == NULL)
1378cdc920a0Smrg      return NULL;
1379cdc920a0Smrg
1380cdc920a0Smrg   if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) {
1381af69d88dSmrg      free(pdp);
1382cdc920a0Smrg      return NULL;
1383cdc920a0Smrg   }
1384cdc920a0Smrg
1385cdc920a0Smrg   pdp->driPatch = 0;
1386cdc920a0Smrg   pdp->swapAvailable = (pdp->driMinor >= 2);
1387cdc920a0Smrg   pdp->invalidateAvailable = (pdp->driMinor >= 3);
1388cdc920a0Smrg
1389cdc920a0Smrg   pdp->base.destroyDisplay = dri2DestroyDisplay;
1390cdc920a0Smrg   pdp->base.createScreen = dri2CreateScreen;
1391cdc920a0Smrg
13923464ebd5Sriastradh   i = 0;
13933464ebd5Sriastradh   if (pdp->driMinor < 1)
13943464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base;
13953464ebd5Sriastradh   else
13963464ebd5Sriastradh      pdp->loader_extensions[i++] = &dri2LoaderExtension.base;
13973464ebd5Sriastradh
13983464ebd5Sriastradh   pdp->loader_extensions[i++] = &systemTimeExtension.base;
13993464ebd5Sriastradh
14003464ebd5Sriastradh   pdp->loader_extensions[i++] = &dri2UseInvalidate.base;
1401af69d88dSmrg
14023464ebd5Sriastradh   pdp->loader_extensions[i++] = NULL;
14033464ebd5Sriastradh
14043464ebd5Sriastradh   pdp->dri2Hash = __glxHashCreate();
14053464ebd5Sriastradh   if (pdp->dri2Hash == NULL) {
1406af69d88dSmrg      free(pdp);
14073464ebd5Sriastradh      return NULL;
14083464ebd5Sriastradh   }
14093464ebd5Sriastradh
1410cdc920a0Smrg   return &pdp->base;
1411cdc920a0Smrg}
1412cdc920a0Smrg
1413cdc920a0Smrg#endif /* GLX_DIRECT_RENDERING */
1414