dri2.c revision 16887d042a917fa4773e4d853f50051b54e9948c
1/*
2 * Copyright © 2008 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 *   Kristian Høgsberg (krh@redhat.com)
31 */
32
33
34#ifdef GLX_DIRECT_RENDERING
35
36#include <stdio.h>
37#include <X11/Xlibint.h>
38#include <X11/extensions/Xext.h>
39#include <X11/extensions/extutil.h>
40#include <X11/extensions/dri2proto.h>
41#include "xf86drm.h"
42#include "dri2.h"
43#include "glxclient.h"
44#include "GL/glxext.h"
45
46/* Allow the build to work with an older versions of dri2proto.h and
47 * dri2tokens.h.
48 */
49#if DRI2_MINOR < 1
50#undef DRI2_MINOR
51#define DRI2_MINOR 1
52#define X_DRI2GetBuffersWithFormat 7
53#endif
54
55
56static char dri2ExtensionName[] = DRI2_NAME;
57static XExtensionInfo *dri2Info;
58static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
59
60static Bool
61DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
62static Status
63DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
64static int
65DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
66
67static /* const */ XExtensionHooks dri2ExtensionHooks = {
68  NULL,                   /* create_gc */
69  NULL,                   /* copy_gc */
70  NULL,                   /* flush_gc */
71  NULL,                   /* free_gc */
72  NULL,                   /* create_font */
73  NULL,                   /* free_font */
74  DRI2CloseDisplay,       /* close_display */
75  DRI2WireToEvent,        /* wire_to_event */
76  DRI2EventToWire,        /* event_to_wire */
77  DRI2Error,              /* error */
78  NULL,                   /* error_string */
79};
80
81static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
82                                   dri2Info,
83                                   dri2ExtensionName,
84                                   &dri2ExtensionHooks,
85                                   0, NULL)
86
87static Bool
88DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
89{
90   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
91
92   XextCheckExtension(dpy, info, dri2ExtensionName, False);
93
94   switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
95
96#ifdef X_DRI2SwapBuffers
97   case DRI2_BufferSwapComplete:
98   {
99      GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
100      xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire;
101      __GLXDRIdrawable *pdraw;
102      struct glx_display *glx_dpy = __glXInitialize(dpy);
103
104      /* Ignore swap events if we're not looking for them */
105      pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable);
106      if (!(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
107	 return False;
108
109      aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
110      aevent->type = glx_dpy->codes->first_event + GLX_BufferSwapComplete;
111      aevent->send_event = (awire->type & 0x80) != 0;
112      aevent->display = dpy;
113      aevent->drawable = awire->drawable;
114      switch (awire->event_type) {
115      case DRI2_EXCHANGE_COMPLETE:
116	 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL;
117	 break;
118      case DRI2_BLIT_COMPLETE:
119	 aevent->event_type = GLX_COPY_COMPLETE_INTEL;
120	 break;
121      case DRI2_FLIP_COMPLETE:
122	 aevent->event_type = GLX_FLIP_COMPLETE_INTEL;
123	 break;
124      default:
125	 /* unknown swap completion type */
126	 return False;
127      }
128      aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
129      aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
130      aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo;
131      return True;
132   }
133#endif
134#ifdef DRI2_InvalidateBuffers
135   case DRI2_InvalidateBuffers:
136   {
137      xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
138
139      dri2InvalidateBuffers(dpy, awire->drawable);
140      return False;
141   }
142#endif
143   default:
144      /* client doesn't support server event */
145      break;
146   }
147
148   return False;
149}
150
151/* We don't actually support this.  It doesn't make sense for clients to
152 * send each other DRI2 events.
153 */
154static Status
155DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
156{
157   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
158
159   XextCheckExtension(dpy, info, dri2ExtensionName, False);
160
161   switch (event->type) {
162   default:
163      /* client doesn't support server event */
164      break;
165   }
166
167   return Success;
168}
169
170static int
171DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
172{
173    if (err->majorCode == codes->major_opcode &&
174	err->errorCode == BadDrawable &&
175	err->minorCode == X_DRI2CopyRegion)
176	return True;
177
178    /* If the X drawable was destroyed before the GLX drawable, the
179     * DRI2 drawble will be gone by the time we call
180     * DRI2DestroyDrawable.  So just ignore BadDrawable here. */
181    if (err->majorCode == codes->major_opcode &&
182	err->errorCode == BadDrawable &&
183	err->minorCode == X_DRI2DestroyDrawable)
184	return True;
185
186    return False;
187}
188
189Bool
190DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
191{
192   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
193
194   if (XextHasExtension(info)) {
195      *eventBase = info->codes->first_event;
196      *errorBase = info->codes->first_error;
197      return True;
198   }
199
200   return False;
201}
202
203Bool
204DRI2QueryVersion(Display * dpy, int *major, int *minor)
205{
206   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
207   xDRI2QueryVersionReply rep;
208   xDRI2QueryVersionReq *req;
209   int i, nevents;
210
211   XextCheckExtension(dpy, info, dri2ExtensionName, False);
212
213   LockDisplay(dpy);
214   GetReq(DRI2QueryVersion, req);
215   req->reqType = info->codes->major_opcode;
216   req->dri2ReqType = X_DRI2QueryVersion;
217   req->majorVersion = DRI2_MAJOR;
218   req->minorVersion = DRI2_MINOR;
219   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
220      UnlockDisplay(dpy);
221      SyncHandle();
222      return False;
223   }
224   *major = rep.majorVersion;
225   *minor = rep.minorVersion;
226   UnlockDisplay(dpy);
227   SyncHandle();
228
229   switch (rep.minorVersion) {
230   case 1:
231	   nevents = 0;
232	   break;
233   case 2:
234	   nevents = 1;
235	   break;
236   case 3:
237   default:
238	   nevents = 2;
239	   break;
240   }
241
242   for (i = 0; i < nevents; i++) {
243       XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
244       XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
245   }
246
247   return True;
248}
249
250Bool
251DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
252{
253   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
254   xDRI2ConnectReply rep;
255   xDRI2ConnectReq *req;
256
257   XextCheckExtension(dpy, info, dri2ExtensionName, False);
258
259   LockDisplay(dpy);
260   GetReq(DRI2Connect, req);
261   req->reqType = info->codes->major_opcode;
262   req->dri2ReqType = X_DRI2Connect;
263   req->window = window;
264   req->driverType = DRI2DriverDRI;
265   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
266      UnlockDisplay(dpy);
267      SyncHandle();
268      return False;
269   }
270
271   if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
272      UnlockDisplay(dpy);
273      SyncHandle();
274      return False;
275   }
276
277   *driverName = Xmalloc(rep.driverNameLength + 1);
278   if (*driverName == NULL) {
279      _XEatData(dpy,
280                ((rep.driverNameLength + 3) & ~3) +
281                ((rep.deviceNameLength + 3) & ~3));
282      UnlockDisplay(dpy);
283      SyncHandle();
284      return False;
285   }
286   _XReadPad(dpy, *driverName, rep.driverNameLength);
287   (*driverName)[rep.driverNameLength] = '\0';
288
289   *deviceName = Xmalloc(rep.deviceNameLength + 1);
290   if (*deviceName == NULL) {
291      Xfree(*driverName);
292      _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
293      UnlockDisplay(dpy);
294      SyncHandle();
295      return False;
296   }
297   _XReadPad(dpy, *deviceName, rep.deviceNameLength);
298   (*deviceName)[rep.deviceNameLength] = '\0';
299
300   UnlockDisplay(dpy);
301   SyncHandle();
302
303   return True;
304}
305
306Bool
307DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
308{
309   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
310   xDRI2AuthenticateReq *req;
311   xDRI2AuthenticateReply rep;
312
313   XextCheckExtension(dpy, info, dri2ExtensionName, False);
314
315   LockDisplay(dpy);
316   GetReq(DRI2Authenticate, req);
317   req->reqType = info->codes->major_opcode;
318   req->dri2ReqType = X_DRI2Authenticate;
319   req->window = window;
320   req->magic = magic;
321
322   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
323      UnlockDisplay(dpy);
324      SyncHandle();
325      return False;
326   }
327
328   UnlockDisplay(dpy);
329   SyncHandle();
330
331   return rep.authenticated;
332}
333
334void
335DRI2CreateDrawable(Display * dpy, XID drawable)
336{
337   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
338   xDRI2CreateDrawableReq *req;
339
340   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
341
342   LockDisplay(dpy);
343   GetReq(DRI2CreateDrawable, req);
344   req->reqType = info->codes->major_opcode;
345   req->dri2ReqType = X_DRI2CreateDrawable;
346   req->drawable = drawable;
347   UnlockDisplay(dpy);
348   SyncHandle();
349}
350
351void
352DRI2DestroyDrawable(Display * dpy, XID drawable)
353{
354   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
355   xDRI2DestroyDrawableReq *req;
356
357   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
358
359   XSync(dpy, False);
360
361   LockDisplay(dpy);
362   GetReq(DRI2DestroyDrawable, req);
363   req->reqType = info->codes->major_opcode;
364   req->dri2ReqType = X_DRI2DestroyDrawable;
365   req->drawable = drawable;
366   UnlockDisplay(dpy);
367   SyncHandle();
368}
369
370DRI2Buffer *
371DRI2GetBuffers(Display * dpy, XID drawable,
372               int *width, int *height,
373               unsigned int *attachments, int count, int *outCount)
374{
375   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
376   xDRI2GetBuffersReply rep;
377   xDRI2GetBuffersReq *req;
378   DRI2Buffer *buffers;
379   xDRI2Buffer repBuffer;
380   CARD32 *p;
381   int i;
382
383   XextCheckExtension(dpy, info, dri2ExtensionName, False);
384
385   LockDisplay(dpy);
386   GetReqExtra(DRI2GetBuffers, count * 4, req);
387   req->reqType = info->codes->major_opcode;
388   req->dri2ReqType = X_DRI2GetBuffers;
389   req->drawable = drawable;
390   req->count = count;
391   p = (CARD32 *) & req[1];
392   for (i = 0; i < count; i++)
393      p[i] = attachments[i];
394
395   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
396      UnlockDisplay(dpy);
397      SyncHandle();
398      return NULL;
399   }
400
401   *width = rep.width;
402   *height = rep.height;
403   *outCount = rep.count;
404
405   buffers = Xmalloc(rep.count * sizeof buffers[0]);
406   if (buffers == NULL) {
407      _XEatData(dpy, rep.count * sizeof repBuffer);
408      UnlockDisplay(dpy);
409      SyncHandle();
410      return NULL;
411   }
412
413   for (i = 0; i < rep.count; i++) {
414      _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
415      buffers[i].attachment = repBuffer.attachment;
416      buffers[i].name = repBuffer.name;
417      buffers[i].pitch = repBuffer.pitch;
418      buffers[i].cpp = repBuffer.cpp;
419      buffers[i].flags = repBuffer.flags;
420   }
421
422   UnlockDisplay(dpy);
423   SyncHandle();
424
425   return buffers;
426}
427
428
429DRI2Buffer *
430DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
431                         int *width, int *height,
432                         unsigned int *attachments, int count, int *outCount)
433{
434   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
435   xDRI2GetBuffersReply rep;
436   xDRI2GetBuffersReq *req;
437   DRI2Buffer *buffers;
438   xDRI2Buffer repBuffer;
439   CARD32 *p;
440   int i;
441
442   XextCheckExtension(dpy, info, dri2ExtensionName, False);
443
444   LockDisplay(dpy);
445   GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
446   req->reqType = info->codes->major_opcode;
447   req->dri2ReqType = X_DRI2GetBuffersWithFormat;
448   req->drawable = drawable;
449   req->count = count;
450   p = (CARD32 *) & req[1];
451   for (i = 0; i < (count * 2); i++)
452      p[i] = attachments[i];
453
454   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
455      UnlockDisplay(dpy);
456      SyncHandle();
457      return NULL;
458   }
459
460   *width = rep.width;
461   *height = rep.height;
462   *outCount = rep.count;
463
464   buffers = Xmalloc(rep.count * sizeof buffers[0]);
465   if (buffers == NULL) {
466      _XEatData(dpy, rep.count * sizeof repBuffer);
467      UnlockDisplay(dpy);
468      SyncHandle();
469      return NULL;
470   }
471
472   for (i = 0; i < rep.count; i++) {
473      _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
474      buffers[i].attachment = repBuffer.attachment;
475      buffers[i].name = repBuffer.name;
476      buffers[i].pitch = repBuffer.pitch;
477      buffers[i].cpp = repBuffer.cpp;
478      buffers[i].flags = repBuffer.flags;
479   }
480
481   UnlockDisplay(dpy);
482   SyncHandle();
483
484   return buffers;
485}
486
487
488void
489DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
490               CARD32 dest, CARD32 src)
491{
492   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
493   xDRI2CopyRegionReq *req;
494   xDRI2CopyRegionReply rep;
495
496   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
497
498   LockDisplay(dpy);
499   GetReq(DRI2CopyRegion, req);
500   req->reqType = info->codes->major_opcode;
501   req->dri2ReqType = X_DRI2CopyRegion;
502   req->drawable = drawable;
503   req->region = region;
504   req->dest = dest;
505   req->src = src;
506
507   _XReply(dpy, (xReply *) & rep, 0, xFalse);
508
509   UnlockDisplay(dpy);
510   SyncHandle();
511}
512
513#ifdef X_DRI2SwapBuffers
514static void
515load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
516	     CARD64 remainder)
517{
518    req->target_msc_hi = target >> 32;
519    req->target_msc_lo = target & 0xffffffff;
520    req->divisor_hi = divisor >> 32;
521    req->divisor_lo = divisor & 0xffffffff;
522    req->remainder_hi = remainder >> 32;
523    req->remainder_lo = remainder & 0xffffffff;
524}
525
526static CARD64
527vals_to_card64(CARD32 lo, CARD32 hi)
528{
529    return (CARD64)hi << 32 | lo;
530}
531
532void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
533		     CARD64 divisor, CARD64 remainder, CARD64 *count)
534{
535    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
536    xDRI2SwapBuffersReq *req;
537    xDRI2SwapBuffersReply rep;
538
539    XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
540
541    LockDisplay(dpy);
542    GetReq(DRI2SwapBuffers, req);
543    req->reqType = info->codes->major_opcode;
544    req->dri2ReqType = X_DRI2SwapBuffers;
545    req->drawable = drawable;
546    load_swap_req(req, target_msc, divisor, remainder);
547
548    _XReply(dpy, (xReply *)&rep, 0, xFalse);
549
550    *count = vals_to_card64(rep.swap_lo, rep.swap_hi);
551
552    UnlockDisplay(dpy);
553    SyncHandle();
554}
555#endif
556
557#ifdef X_DRI2GetMSC
558Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
559		CARD64 *sbc)
560{
561    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
562    xDRI2GetMSCReq *req;
563    xDRI2MSCReply rep;
564
565    XextCheckExtension (dpy, info, dri2ExtensionName, False);
566
567    LockDisplay(dpy);
568    GetReq(DRI2GetMSC, req);
569    req->reqType = info->codes->major_opcode;
570    req->dri2ReqType = X_DRI2GetMSC;
571    req->drawable = drawable;
572
573    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
574	UnlockDisplay(dpy);
575	SyncHandle();
576	return False;
577    }
578
579    *ust = vals_to_card64(rep.ust_lo, rep.ust_hi);
580    *msc = vals_to_card64(rep.msc_lo, rep.msc_hi);
581    *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi);
582
583    UnlockDisplay(dpy);
584    SyncHandle();
585
586    return True;
587}
588#endif
589
590#ifdef X_DRI2WaitMSC
591static void
592load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
593	     CARD64 remainder)
594{
595    req->target_msc_hi = target >> 32;
596    req->target_msc_lo = target & 0xffffffff;
597    req->divisor_hi = divisor >> 32;
598    req->divisor_lo = divisor & 0xffffffff;
599    req->remainder_hi = remainder >> 32;
600    req->remainder_lo = remainder & 0xffffffff;
601}
602
603Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
604		 CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
605{
606    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
607    xDRI2WaitMSCReq *req;
608    xDRI2MSCReply rep;
609
610    XextCheckExtension (dpy, info, dri2ExtensionName, False);
611
612    LockDisplay(dpy);
613    GetReq(DRI2WaitMSC, req);
614    req->reqType = info->codes->major_opcode;
615    req->dri2ReqType = X_DRI2WaitMSC;
616    req->drawable = drawable;
617    load_msc_req(req, target_msc, divisor, remainder);
618
619    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
620	UnlockDisplay(dpy);
621	SyncHandle();
622	return False;
623    }
624
625    *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo;
626    *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo;
627    *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo;
628
629    UnlockDisplay(dpy);
630    SyncHandle();
631
632    return True;
633}
634#endif
635
636#ifdef X_DRI2WaitSBC
637static void
638load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
639{
640    req->target_sbc_hi = target >> 32;
641    req->target_sbc_lo = target & 0xffffffff;
642}
643
644Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
645		 CARD64 *msc, CARD64 *sbc)
646{
647    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
648    xDRI2WaitSBCReq *req;
649    xDRI2MSCReply rep;
650
651    XextCheckExtension (dpy, info, dri2ExtensionName, False);
652
653    LockDisplay(dpy);
654    GetReq(DRI2WaitSBC, req);
655    req->reqType = info->codes->major_opcode;
656    req->dri2ReqType = X_DRI2WaitSBC;
657    req->drawable = drawable;
658    load_sbc_req(req, target_sbc);
659
660    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
661	UnlockDisplay(dpy);
662	SyncHandle();
663	return False;
664    }
665
666    *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo;
667    *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo;
668    *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo;
669
670    UnlockDisplay(dpy);
671    SyncHandle();
672
673    return True;
674}
675#endif
676
677#ifdef X_DRI2SwapInterval
678void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
679{
680    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
681    xDRI2SwapIntervalReq *req;
682
683    XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
684
685    LockDisplay(dpy);
686    GetReq(DRI2SwapInterval, req);
687    req->reqType = info->codes->major_opcode;
688    req->dri2ReqType = X_DRI2SwapInterval;
689    req->drawable = drawable;
690    req->interval = interval;
691    UnlockDisplay(dpy);
692    SyncHandle();
693}
694#endif
695
696#endif /* GLX_DIRECT_RENDERING */
697