dri2.c revision 1e39fc784bc3d0d5ad01d9c147529ac0e10f1262
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      xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire;
101
102      /* Ignore swap events if we're not looking for them */
103      aevent->type = dri2GetSwapEventType(dpy, awire->drawable);
104      if(!aevent->type)
105         return False;
106
107      aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
108      aevent->send_event = (awire->type & 0x80) != 0;
109      aevent->display = dpy;
110      aevent->drawable = awire->drawable;
111      switch (awire->event_type) {
112      case DRI2_EXCHANGE_COMPLETE:
113	 aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL;
114	 break;
115      case DRI2_BLIT_COMPLETE:
116	 aevent->event_type = GLX_COPY_COMPLETE_INTEL;
117	 break;
118      case DRI2_FLIP_COMPLETE:
119	 aevent->event_type = GLX_FLIP_COMPLETE_INTEL;
120	 break;
121      default:
122	 /* unknown swap completion type */
123	 return False;
124      }
125      aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
126      aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
127      aevent->sbc = awire->sbc;
128      return True;
129   }
130#endif
131#ifdef DRI2_InvalidateBuffers
132   case DRI2_InvalidateBuffers:
133   {
134      xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire;
135
136      dri2InvalidateBuffers(dpy, awire->drawable);
137      return False;
138   }
139#endif
140   default:
141      /* client doesn't support server event */
142      break;
143   }
144
145   return False;
146}
147
148/* We don't actually support this.  It doesn't make sense for clients to
149 * send each other DRI2 events.
150 */
151static Status
152DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
153{
154   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
155
156   XextCheckExtension(dpy, info, dri2ExtensionName, False);
157
158   switch (event->type) {
159   default:
160      /* client doesn't support server event */
161      break;
162   }
163
164   return Success;
165}
166
167static int
168DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
169{
170    if (err->majorCode == codes->major_opcode &&
171	err->errorCode == BadDrawable &&
172	err->minorCode == X_DRI2CopyRegion)
173	return True;
174
175    /* If the X drawable was destroyed before the GLX drawable, the
176     * DRI2 drawble will be gone by the time we call
177     * DRI2DestroyDrawable.  So just ignore BadDrawable here. */
178    if (err->majorCode == codes->major_opcode &&
179	err->errorCode == BadDrawable &&
180	err->minorCode == X_DRI2DestroyDrawable)
181	return True;
182
183    return False;
184}
185
186Bool
187DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
188{
189   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
190
191   if (XextHasExtension(info)) {
192      *eventBase = info->codes->first_event;
193      *errorBase = info->codes->first_error;
194      return True;
195   }
196
197   return False;
198}
199
200Bool
201DRI2QueryVersion(Display * dpy, int *major, int *minor)
202{
203   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
204   xDRI2QueryVersionReply rep;
205   xDRI2QueryVersionReq *req;
206   int i, nevents;
207
208   XextCheckExtension(dpy, info, dri2ExtensionName, False);
209
210   LockDisplay(dpy);
211   GetReq(DRI2QueryVersion, req);
212   req->reqType = info->codes->major_opcode;
213   req->dri2ReqType = X_DRI2QueryVersion;
214   req->majorVersion = DRI2_MAJOR;
215   req->minorVersion = DRI2_MINOR;
216   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
217      UnlockDisplay(dpy);
218      SyncHandle();
219      return False;
220   }
221   *major = rep.majorVersion;
222   *minor = rep.minorVersion;
223   UnlockDisplay(dpy);
224   SyncHandle();
225
226   switch (rep.minorVersion) {
227   case 1:
228	   nevents = 0;
229	   break;
230   case 2:
231	   nevents = 1;
232	   break;
233   case 3:
234   default:
235	   nevents = 2;
236	   break;
237   }
238
239   for (i = 0; i < nevents; i++) {
240       XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
241       XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
242   }
243
244   return True;
245}
246
247Bool
248DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
249{
250   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
251   xDRI2ConnectReply rep;
252   xDRI2ConnectReq *req;
253
254   XextCheckExtension(dpy, info, dri2ExtensionName, False);
255
256   LockDisplay(dpy);
257   GetReq(DRI2Connect, req);
258   req->reqType = info->codes->major_opcode;
259   req->dri2ReqType = X_DRI2Connect;
260   req->window = window;
261   req->driverType = DRI2DriverDRI;
262   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
263      UnlockDisplay(dpy);
264      SyncHandle();
265      return False;
266   }
267
268   if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
269      UnlockDisplay(dpy);
270      SyncHandle();
271      return False;
272   }
273
274   *driverName = Xmalloc(rep.driverNameLength + 1);
275   if (*driverName == NULL) {
276      _XEatData(dpy,
277                ((rep.driverNameLength + 3) & ~3) +
278                ((rep.deviceNameLength + 3) & ~3));
279      UnlockDisplay(dpy);
280      SyncHandle();
281      return False;
282   }
283   _XReadPad(dpy, *driverName, rep.driverNameLength);
284   (*driverName)[rep.driverNameLength] = '\0';
285
286   *deviceName = Xmalloc(rep.deviceNameLength + 1);
287   if (*deviceName == NULL) {
288      Xfree(*driverName);
289      _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
290      UnlockDisplay(dpy);
291      SyncHandle();
292      return False;
293   }
294   _XReadPad(dpy, *deviceName, rep.deviceNameLength);
295   (*deviceName)[rep.deviceNameLength] = '\0';
296
297   UnlockDisplay(dpy);
298   SyncHandle();
299
300   return True;
301}
302
303Bool
304DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
305{
306   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
307   xDRI2AuthenticateReq *req;
308   xDRI2AuthenticateReply rep;
309
310   XextCheckExtension(dpy, info, dri2ExtensionName, False);
311
312   LockDisplay(dpy);
313   GetReq(DRI2Authenticate, req);
314   req->reqType = info->codes->major_opcode;
315   req->dri2ReqType = X_DRI2Authenticate;
316   req->window = window;
317   req->magic = magic;
318
319   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
320      UnlockDisplay(dpy);
321      SyncHandle();
322      return False;
323   }
324
325   UnlockDisplay(dpy);
326   SyncHandle();
327
328   return rep.authenticated;
329}
330
331void
332DRI2CreateDrawable(Display * dpy, XID drawable)
333{
334   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
335   xDRI2CreateDrawableReq *req;
336
337   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
338
339   LockDisplay(dpy);
340   GetReq(DRI2CreateDrawable, req);
341   req->reqType = info->codes->major_opcode;
342   req->dri2ReqType = X_DRI2CreateDrawable;
343   req->drawable = drawable;
344   UnlockDisplay(dpy);
345   SyncHandle();
346}
347
348void
349DRI2DestroyDrawable(Display * dpy, XID drawable)
350{
351   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
352   xDRI2DestroyDrawableReq *req;
353
354   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
355
356   XSync(dpy, False);
357
358   LockDisplay(dpy);
359   GetReq(DRI2DestroyDrawable, req);
360   req->reqType = info->codes->major_opcode;
361   req->dri2ReqType = X_DRI2DestroyDrawable;
362   req->drawable = drawable;
363   UnlockDisplay(dpy);
364   SyncHandle();
365}
366
367DRI2Buffer *
368DRI2GetBuffers(Display * dpy, XID drawable,
369               int *width, int *height,
370               unsigned int *attachments, int count, int *outCount)
371{
372   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
373   xDRI2GetBuffersReply rep;
374   xDRI2GetBuffersReq *req;
375   DRI2Buffer *buffers;
376   xDRI2Buffer repBuffer;
377   CARD32 *p;
378   int i;
379
380   XextCheckExtension(dpy, info, dri2ExtensionName, False);
381
382   LockDisplay(dpy);
383   GetReqExtra(DRI2GetBuffers, count * 4, req);
384   req->reqType = info->codes->major_opcode;
385   req->dri2ReqType = X_DRI2GetBuffers;
386   req->drawable = drawable;
387   req->count = count;
388   p = (CARD32 *) & req[1];
389   for (i = 0; i < count; i++)
390      p[i] = attachments[i];
391
392   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
393      UnlockDisplay(dpy);
394      SyncHandle();
395      return NULL;
396   }
397
398   *width = rep.width;
399   *height = rep.height;
400   *outCount = rep.count;
401
402   buffers = Xmalloc(rep.count * sizeof buffers[0]);
403   if (buffers == NULL) {
404      _XEatData(dpy, rep.count * sizeof repBuffer);
405      UnlockDisplay(dpy);
406      SyncHandle();
407      return NULL;
408   }
409
410   for (i = 0; i < rep.count; i++) {
411      _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
412      buffers[i].attachment = repBuffer.attachment;
413      buffers[i].name = repBuffer.name;
414      buffers[i].pitch = repBuffer.pitch;
415      buffers[i].cpp = repBuffer.cpp;
416      buffers[i].flags = repBuffer.flags;
417   }
418
419   UnlockDisplay(dpy);
420   SyncHandle();
421
422   return buffers;
423}
424
425
426DRI2Buffer *
427DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
428                         int *width, int *height,
429                         unsigned int *attachments, int count, int *outCount)
430{
431   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
432   xDRI2GetBuffersReply rep;
433   xDRI2GetBuffersReq *req;
434   DRI2Buffer *buffers;
435   xDRI2Buffer repBuffer;
436   CARD32 *p;
437   int i;
438
439   XextCheckExtension(dpy, info, dri2ExtensionName, False);
440
441   LockDisplay(dpy);
442   GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
443   req->reqType = info->codes->major_opcode;
444   req->dri2ReqType = X_DRI2GetBuffersWithFormat;
445   req->drawable = drawable;
446   req->count = count;
447   p = (CARD32 *) & req[1];
448   for (i = 0; i < (count * 2); i++)
449      p[i] = attachments[i];
450
451   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
452      UnlockDisplay(dpy);
453      SyncHandle();
454      return NULL;
455   }
456
457   *width = rep.width;
458   *height = rep.height;
459   *outCount = rep.count;
460
461   buffers = Xmalloc(rep.count * sizeof buffers[0]);
462   if (buffers == NULL) {
463      _XEatData(dpy, rep.count * sizeof repBuffer);
464      UnlockDisplay(dpy);
465      SyncHandle();
466      return NULL;
467   }
468
469   for (i = 0; i < rep.count; i++) {
470      _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
471      buffers[i].attachment = repBuffer.attachment;
472      buffers[i].name = repBuffer.name;
473      buffers[i].pitch = repBuffer.pitch;
474      buffers[i].cpp = repBuffer.cpp;
475      buffers[i].flags = repBuffer.flags;
476   }
477
478   UnlockDisplay(dpy);
479   SyncHandle();
480
481   return buffers;
482}
483
484
485void
486DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
487               CARD32 dest, CARD32 src)
488{
489   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
490   xDRI2CopyRegionReq *req;
491   xDRI2CopyRegionReply rep;
492
493   XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
494
495   LockDisplay(dpy);
496   GetReq(DRI2CopyRegion, req);
497   req->reqType = info->codes->major_opcode;
498   req->dri2ReqType = X_DRI2CopyRegion;
499   req->drawable = drawable;
500   req->region = region;
501   req->dest = dest;
502   req->src = src;
503
504   _XReply(dpy, (xReply *) & rep, 0, xFalse);
505
506   UnlockDisplay(dpy);
507   SyncHandle();
508}
509
510#ifdef X_DRI2SwapBuffers
511static void
512load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
513	     CARD64 remainder)
514{
515    req->target_msc_hi = target >> 32;
516    req->target_msc_lo = target & 0xffffffff;
517    req->divisor_hi = divisor >> 32;
518    req->divisor_lo = divisor & 0xffffffff;
519    req->remainder_hi = remainder >> 32;
520    req->remainder_lo = remainder & 0xffffffff;
521}
522
523static CARD64
524vals_to_card64(CARD32 lo, CARD32 hi)
525{
526    return (CARD64)hi << 32 | lo;
527}
528
529void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
530		     CARD64 divisor, CARD64 remainder, CARD64 *count)
531{
532    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
533    xDRI2SwapBuffersReq *req;
534    xDRI2SwapBuffersReply rep;
535
536    XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
537
538    LockDisplay(dpy);
539    GetReq(DRI2SwapBuffers, req);
540    req->reqType = info->codes->major_opcode;
541    req->dri2ReqType = X_DRI2SwapBuffers;
542    req->drawable = drawable;
543    load_swap_req(req, target_msc, divisor, remainder);
544
545    _XReply(dpy, (xReply *)&rep, 0, xFalse);
546
547    *count = vals_to_card64(rep.swap_lo, rep.swap_hi);
548
549    UnlockDisplay(dpy);
550    SyncHandle();
551}
552#endif
553
554#ifdef X_DRI2GetMSC
555Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
556		CARD64 *sbc)
557{
558    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
559    xDRI2GetMSCReq *req;
560    xDRI2MSCReply rep;
561
562    XextCheckExtension (dpy, info, dri2ExtensionName, False);
563
564    LockDisplay(dpy);
565    GetReq(DRI2GetMSC, req);
566    req->reqType = info->codes->major_opcode;
567    req->dri2ReqType = X_DRI2GetMSC;
568    req->drawable = drawable;
569
570    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
571	UnlockDisplay(dpy);
572	SyncHandle();
573	return False;
574    }
575
576    *ust = vals_to_card64(rep.ust_lo, rep.ust_hi);
577    *msc = vals_to_card64(rep.msc_lo, rep.msc_hi);
578    *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi);
579
580    UnlockDisplay(dpy);
581    SyncHandle();
582
583    return True;
584}
585#endif
586
587#ifdef X_DRI2WaitMSC
588static void
589load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
590	     CARD64 remainder)
591{
592    req->target_msc_hi = target >> 32;
593    req->target_msc_lo = target & 0xffffffff;
594    req->divisor_hi = divisor >> 32;
595    req->divisor_lo = divisor & 0xffffffff;
596    req->remainder_hi = remainder >> 32;
597    req->remainder_lo = remainder & 0xffffffff;
598}
599
600Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
601		 CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
602{
603    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
604    xDRI2WaitMSCReq *req;
605    xDRI2MSCReply rep;
606
607    XextCheckExtension (dpy, info, dri2ExtensionName, False);
608
609    LockDisplay(dpy);
610    GetReq(DRI2WaitMSC, req);
611    req->reqType = info->codes->major_opcode;
612    req->dri2ReqType = X_DRI2WaitMSC;
613    req->drawable = drawable;
614    load_msc_req(req, target_msc, divisor, remainder);
615
616    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
617	UnlockDisplay(dpy);
618	SyncHandle();
619	return False;
620    }
621
622    *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo;
623    *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo;
624    *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo;
625
626    UnlockDisplay(dpy);
627    SyncHandle();
628
629    return True;
630}
631#endif
632
633#ifdef X_DRI2WaitSBC
634static void
635load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
636{
637    req->target_sbc_hi = target >> 32;
638    req->target_sbc_lo = target & 0xffffffff;
639}
640
641Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
642		 CARD64 *msc, CARD64 *sbc)
643{
644    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
645    xDRI2WaitSBCReq *req;
646    xDRI2MSCReply rep;
647
648    XextCheckExtension (dpy, info, dri2ExtensionName, False);
649
650    LockDisplay(dpy);
651    GetReq(DRI2WaitSBC, req);
652    req->reqType = info->codes->major_opcode;
653    req->dri2ReqType = X_DRI2WaitSBC;
654    req->drawable = drawable;
655    load_sbc_req(req, target_sbc);
656
657    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
658	UnlockDisplay(dpy);
659	SyncHandle();
660	return False;
661    }
662
663    *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo;
664    *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo;
665    *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo;
666
667    UnlockDisplay(dpy);
668    SyncHandle();
669
670    return True;
671}
672#endif
673
674#ifdef X_DRI2SwapInterval
675void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
676{
677    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
678    xDRI2SwapIntervalReq *req;
679
680    XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
681
682    LockDisplay(dpy);
683    GetReq(DRI2SwapInterval, req);
684    req->reqType = info->codes->major_opcode;
685    req->dri2ReqType = X_DRI2SwapInterval;
686    req->drawable = drawable;
687    req->interval = interval;
688    UnlockDisplay(dpy);
689    SyncHandle();
690}
691#endif
692
693#endif /* GLX_DIRECT_RENDERING */
694