initial commit
[glsdk/libdri2.git] / src / dri2.c
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  */
33 #ifdef HAVE_CONFIG_H
34 #  include "config.h"
35 #endif
37 #define NEED_REPLIES
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <X11/Xlibint.h>
41 #include <X11/extensions/Xext.h>
42 #include <X11/extensions/extutil.h>
43 #include <X11/extensions/dri2proto.h>
44 #include <drm.h>
45 #include <xf86drm.h>
46 #include <GL/glx.h>
47 #include <GL/glxext.h>
48 #include <xorg/list.h>
49 #include "X11/extensions/dri2.h"
51 /* Allow the build to work with an older versions of dri2proto.h and
52  * dri2tokens.h.
53  */
54 #if DRI2_MINOR < 1
55 #undef DRI2_MINOR
56 #define DRI2_MINOR 1
57 #define X_DRI2GetBuffersWithFormat 7
58 #endif
61 static char dri2ExtensionName[] = DRI2_NAME;
62 static XExtensionInfo *dri2Info;
63 static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay2, dri2Info)
65 /**
66  * List of per-Display privates..
67  */
68 static struct list dpy_list = { &dpy_list, &dpy_list };
70 typedef struct {
71         struct list list;
72         Display *dpy;
73         const DRI2EventOps *ops;
74 } DRI2Display;
76 static DRI2Display * dpy2dri(Display *dpy)
77 {
78         DRI2Display *dri2dpy;
79         list_for_each_entry(dri2dpy, &dpy_list, list) {
80                 if (dri2dpy->dpy == dpy) {
81                         return dri2dpy;
82                 }
83         }
84         return NULL;
85 }
87 static int
88 DRI2CloseDisplay(Display *dpy, XExtCodes *codes)
89 {
90         DRI2Display *dri2dpy = dpy2dri(dpy);
91         if (dri2dpy) {
92                 list_del(&dri2dpy->list);
93                 free(dri2dpy);
94         }
95         return DRI2CloseDisplay2(dpy, codes);
96 }
98 Bool
99 DRI2InitDisplay(Display *dpy, const DRI2EventOps *ops)
101         DRI2Display *dri2dpy = dpy2dri(dpy);
102         if (!dri2dpy) {
103                 dri2dpy = malloc(sizeof(*dri2dpy));
104                 if (!dri2dpy) {
105                         return False;
106                 }
107                 dri2dpy->dpy = dpy;
108                 dri2dpy->ops = ops;
109                 list_add(&dri2dpy->list, &dpy_list);
110         }
111         return True;
114 static Bool
115 DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
116 static Status
117 DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
118 static int
119 DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
121 static /* const */ XExtensionHooks dri2ExtensionHooks = {
122   NULL,                   /* create_gc */
123   NULL,                   /* copy_gc */
124   NULL,                   /* flush_gc */
125   NULL,                   /* free_gc */
126   NULL,                   /* create_font */
127   NULL,                   /* free_font */
128   DRI2CloseDisplay,       /* close_display */
129   DRI2WireToEvent,        /* wire_to_event */
130   DRI2EventToWire,        /* event_to_wire */
131   DRI2Error,              /* error */
132   NULL,                   /* error_string */
133 };
135 static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
136                                    dri2Info,
137                                    dri2ExtensionName,
138                                    &dri2ExtensionHooks,
139                                    0, NULL)
141 #include <GL/glx.h>
143 static Bool
144 DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
146    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
147    DRI2Display *dri2dpy = dpy2dri(dpy);
149    XextCheckExtension(dpy, info, dri2ExtensionName, False);
151    if (dri2dpy && dri2dpy->ops && dri2dpy->ops->WireToEvent) {
152            return dri2dpy->ops->WireToEvent(dpy, info, event, wire);
153    }
155    return False;
158 /* We don't actually support this.  It doesn't make sense for clients to
159  * send each other DRI2 events.
160  */
161 static Status
162 DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
164    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
165    DRI2Display *dri2dpy = dpy2dri(dpy);
167    XextCheckExtension(dpy, info, dri2ExtensionName, False);
169    if (dri2dpy && dri2dpy->ops && dri2dpy->ops->EventToWire) {
170            return dri2dpy->ops->EventToWire(dpy, info, event, wire);
171    }
173    return Success;
176 static int
177 DRI2Error(Display *dpy, xError *err, XExtCodes *codes, int *ret_code)
179         DRI2Display *dri2dpy = dpy2dri(dpy);
181         if (dri2dpy && dri2dpy->ops && dri2dpy->ops->Error) {
182                 return dri2dpy->ops->Error(dpy, err, codes, ret_code);
183         }
185     return False;
188 Bool
189 DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
191    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
193    if (XextHasExtension(info)) {
194       *eventBase = info->codes->first_event;
195       *errorBase = info->codes->first_error;
196       return True;
197    }
199    return False;
202 Bool
203 DRI2QueryVersion(Display * dpy, int *major, int *minor)
205    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
206    xDRI2QueryVersionReply rep;
207    xDRI2QueryVersionReq *req;
208    int i, nevents;
210    XextCheckExtension(dpy, info, dri2ExtensionName, False);
212    LockDisplay(dpy);
213    GetReq(DRI2QueryVersion, req);
214    req->reqType = info->codes->major_opcode;
215    req->dri2ReqType = X_DRI2QueryVersion;
216    req->majorVersion = DRI2_MAJOR;
217    req->minorVersion = DRI2_MINOR;
218    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
219       UnlockDisplay(dpy);
220       SyncHandle();
221       return False;
222    }
223    *major = rep.majorVersion;
224    *minor = rep.minorVersion;
225    UnlockDisplay(dpy);
226    SyncHandle();
228    switch (rep.minorVersion) {
229    case 1:
230            nevents = 0;
231            break;
232    case 2:
233            nevents = 1;
234            break;
235    case 3:
236    default:
237            nevents = 2;
238            break;
239    }
240         
241    for (i = 0; i < nevents; i++) {
242        XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
243        XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
244    }
246    return True;
249 Bool
250 DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
252    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
253    xDRI2ConnectReply rep;
254    xDRI2ConnectReq *req;
256    XextCheckExtension(dpy, info, dri2ExtensionName, False);
258    LockDisplay(dpy);
259    GetReq(DRI2Connect, req);
260    req->reqType = info->codes->major_opcode;
261    req->dri2ReqType = X_DRI2Connect;
262    req->window = window;
263    req->driverType = DRI2DriverDRI;
264    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
265       UnlockDisplay(dpy);
266       SyncHandle();
267       return False;
268    }
270    if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
271       UnlockDisplay(dpy);
272       SyncHandle();
273       return False;
274    }
276    *driverName = Xmalloc(rep.driverNameLength + 1);
277    if (*driverName == NULL) {
278       _XEatData(dpy,
279                 ((rep.driverNameLength + 3) & ~3) +
280                 ((rep.deviceNameLength + 3) & ~3));
281       UnlockDisplay(dpy);
282       SyncHandle();
283       return False;
284    }
285    _XReadPad(dpy, *driverName, rep.driverNameLength);
286    (*driverName)[rep.driverNameLength] = '\0';
288    *deviceName = Xmalloc(rep.deviceNameLength + 1);
289    if (*deviceName == NULL) {
290       Xfree(*driverName);
291       _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
292       UnlockDisplay(dpy);
293       SyncHandle();
294       return False;
295    }
296    _XReadPad(dpy, *deviceName, rep.deviceNameLength);
297    (*deviceName)[rep.deviceNameLength] = '\0';
299    UnlockDisplay(dpy);
300    SyncHandle();
302    return True;
305 Bool
306 DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
308    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
309    xDRI2AuthenticateReq *req;
310    xDRI2AuthenticateReply rep;
312    XextCheckExtension(dpy, info, dri2ExtensionName, False);
314    LockDisplay(dpy);
315    GetReq(DRI2Authenticate, req);
316    req->reqType = info->codes->major_opcode;
317    req->dri2ReqType = X_DRI2Authenticate;
318    req->window = window;
319    req->magic = magic;
321    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
322       UnlockDisplay(dpy);
323       SyncHandle();
324       return False;
325    }
327    UnlockDisplay(dpy);
328    SyncHandle();
330    return rep.authenticated;
333 void
334 DRI2CreateDrawable(Display * dpy, XID drawable)
336    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
337    xDRI2CreateDrawableReq *req;
339    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
341    LockDisplay(dpy);
342    GetReq(DRI2CreateDrawable, req);
343    req->reqType = info->codes->major_opcode;
344    req->dri2ReqType = X_DRI2CreateDrawable;
345    req->drawable = drawable;
346    UnlockDisplay(dpy);
347    SyncHandle();
350 void
351 DRI2DestroyDrawable(Display * dpy, XID drawable)
353    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
354    xDRI2DestroyDrawableReq *req;
356    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
358    XSync(dpy, False);
360    LockDisplay(dpy);
361    GetReq(DRI2DestroyDrawable, req);
362    req->reqType = info->codes->major_opcode;
363    req->dri2ReqType = X_DRI2DestroyDrawable;
364    req->drawable = drawable;
365    UnlockDisplay(dpy);
366    SyncHandle();
369 DRI2Buffer *
370 DRI2GetBuffers(Display * dpy, XID drawable,
371                int *width, int *height,
372                unsigned int *attachments, int count, int *outCount)
374    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
375    xDRI2GetBuffersReply rep;
376    xDRI2GetBuffersReq *req;
377    DRI2Buffer *buffers;
378    xDRI2Buffer repBuffer;
379    CARD32 *p;
380    int i;
382    XextCheckExtension(dpy, info, dri2ExtensionName, False);
384    LockDisplay(dpy);
385    GetReqExtra(DRI2GetBuffers, count * 4, req);
386    req->reqType = info->codes->major_opcode;
387    req->dri2ReqType = X_DRI2GetBuffers;
388    req->drawable = drawable;
389    req->count = count;
390    p = (CARD32 *) & req[1];
391    for (i = 0; i < count; i++)
392       p[i] = attachments[i];
394    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
395       UnlockDisplay(dpy);
396       SyncHandle();
397       return NULL;
398    }
400    *width = rep.width;
401    *height = rep.height;
402    *outCount = rep.count;
404    buffers = Xmalloc(rep.count * sizeof buffers[0]);
405    if (buffers == NULL) {
406       _XEatData(dpy, rep.count * sizeof repBuffer);
407       UnlockDisplay(dpy);
408       SyncHandle();
409       return NULL;
410    }
412    for (i = 0; i < rep.count; i++) {
413       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
414       buffers[i].attachment = repBuffer.attachment;
415       buffers[i].name = repBuffer.name;
416       buffers[i].pitch = repBuffer.pitch;
417       buffers[i].cpp = repBuffer.cpp;
418       buffers[i].flags = repBuffer.flags;
419    }
421    UnlockDisplay(dpy);
422    SyncHandle();
424    return buffers;
428 DRI2Buffer *
429 DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
430                          int *width, int *height,
431                          unsigned int *attachments, int count, int *outCount)
433    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
434    xDRI2GetBuffersReply rep;
435    xDRI2GetBuffersReq *req;
436    DRI2Buffer *buffers;
437    xDRI2Buffer repBuffer;
438    CARD32 *p;
439    int i;
441    XextCheckExtension(dpy, info, dri2ExtensionName, False);
443    LockDisplay(dpy);
444    GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
445    req->reqType = info->codes->major_opcode;
446    req->dri2ReqType = X_DRI2GetBuffersWithFormat;
447    req->drawable = drawable;
448    req->count = count;
449    p = (CARD32 *) & req[1];
450    for (i = 0; i < (count * 2); i++)
451       p[i] = attachments[i];
453    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
454       UnlockDisplay(dpy);
455       SyncHandle();
456       return NULL;
457    }
459    *width = rep.width;
460    *height = rep.height;
461    *outCount = rep.count;
463    buffers = Xmalloc(rep.count * sizeof buffers[0]);
464    if (buffers == NULL) {
465       _XEatData(dpy, rep.count * sizeof repBuffer);
466       UnlockDisplay(dpy);
467       SyncHandle();
468       return NULL;
469    }
471    for (i = 0; i < rep.count; i++) {
472       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
473       buffers[i].attachment = repBuffer.attachment;
474       buffers[i].name = repBuffer.name;
475       buffers[i].pitch = repBuffer.pitch;
476       buffers[i].cpp = repBuffer.cpp;
477       buffers[i].flags = repBuffer.flags;
478    }
480    UnlockDisplay(dpy);
481    SyncHandle();
483    return buffers;
487 void
488 DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
489                CARD32 dest, CARD32 src)
491    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
492    xDRI2CopyRegionReq *req;
493    xDRI2CopyRegionReply rep;
495    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
497    LockDisplay(dpy);
498    GetReq(DRI2CopyRegion, req);
499    req->reqType = info->codes->major_opcode;
500    req->dri2ReqType = X_DRI2CopyRegion;
501    req->drawable = drawable;
502    req->region = region;
503    req->dest = dest;
504    req->src = src;
506    _XReply(dpy, (xReply *) & rep, 0, xFalse);
508    UnlockDisplay(dpy);
509    SyncHandle();
512 #ifdef X_DRI2SwapBuffers
513 static void
514 load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
515              CARD64 remainder)
517     req->target_msc_hi = target >> 32;
518     req->target_msc_lo = target & 0xffffffff;
519     req->divisor_hi = divisor >> 32;
520     req->divisor_lo = divisor & 0xffffffff;
521     req->remainder_hi = remainder >> 32;
522     req->remainder_lo = remainder & 0xffffffff;
525 static CARD64
526 vals_to_card64(CARD32 lo, CARD32 hi)
528     return (CARD64)hi << 32 | lo;
531 void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
532                      CARD64 divisor, CARD64 remainder, CARD64 *count)
534     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
535     xDRI2SwapBuffersReq *req;
536     xDRI2SwapBuffersReply rep;
538     XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
540     LockDisplay(dpy);
541     GetReq(DRI2SwapBuffers, req);
542     req->reqType = info->codes->major_opcode;
543     req->dri2ReqType = X_DRI2SwapBuffers;
544     req->drawable = drawable;
545     load_swap_req(req, target_msc, divisor, remainder);
547     _XReply(dpy, (xReply *)&rep, 0, xFalse);
549     *count = vals_to_card64(rep.swap_lo, rep.swap_hi);
551     UnlockDisplay(dpy);
552     SyncHandle();
554 #endif
556 #ifdef X_DRI2GetMSC
557 Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
558                 CARD64 *sbc)
560     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
561     xDRI2GetMSCReq *req;
562     xDRI2MSCReply rep;
564     XextCheckExtension (dpy, info, dri2ExtensionName, False);
566     LockDisplay(dpy);
567     GetReq(DRI2GetMSC, req);
568     req->reqType = info->codes->major_opcode;
569     req->dri2ReqType = X_DRI2GetMSC;
570     req->drawable = drawable;
572     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
573         UnlockDisplay(dpy);
574         SyncHandle();
575         return False;
576     }
578     *ust = vals_to_card64(rep.ust_lo, rep.ust_hi);
579     *msc = vals_to_card64(rep.msc_lo, rep.msc_hi);
580     *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi);
582     UnlockDisplay(dpy);
583     SyncHandle();
585     return True;
587 #endif
589 #ifdef X_DRI2WaitMSC
590 static void
591 load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
592              CARD64 remainder)
594     req->target_msc_hi = target >> 32;
595     req->target_msc_lo = target & 0xffffffff;
596     req->divisor_hi = divisor >> 32;
597     req->divisor_lo = divisor & 0xffffffff;
598     req->remainder_hi = remainder >> 32;
599     req->remainder_lo = remainder & 0xffffffff;
602 Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
603                  CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
605     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
606     xDRI2WaitMSCReq *req;
607     xDRI2MSCReply rep;
609     XextCheckExtension (dpy, info, dri2ExtensionName, False);
611     LockDisplay(dpy);
612     GetReq(DRI2WaitMSC, req);
613     req->reqType = info->codes->major_opcode;
614     req->dri2ReqType = X_DRI2WaitMSC;
615     req->drawable = drawable;
616     load_msc_req(req, target_msc, divisor, remainder);
618     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
619         UnlockDisplay(dpy);
620         SyncHandle();
621         return False;
622     }
624     *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo;
625     *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo;
626     *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo;
628     UnlockDisplay(dpy);
629     SyncHandle();
631     return True;
633 #endif
635 #ifdef X_DRI2WaitSBC
636 static void
637 load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
639     req->target_sbc_hi = target >> 32;
640     req->target_sbc_lo = target & 0xffffffff;
643 Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
644                  CARD64 *msc, CARD64 *sbc)
646     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
647     xDRI2WaitSBCReq *req;
648     xDRI2MSCReply rep;
650     XextCheckExtension (dpy, info, dri2ExtensionName, False);
652     LockDisplay(dpy);
653     GetReq(DRI2WaitSBC, req);
654     req->reqType = info->codes->major_opcode;
655     req->dri2ReqType = X_DRI2WaitSBC;
656     req->drawable = drawable;
657     load_sbc_req(req, target_sbc);
659     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
660         UnlockDisplay(dpy);
661         SyncHandle();
662         return False;
663     }
665     *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo;
666     *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo;
667     *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo;
669     UnlockDisplay(dpy);
670     SyncHandle();
672     return True;
674 #endif
676 #ifdef X_DRI2SwapInterval
677 void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
679     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
680     xDRI2SwapIntervalReq *req;
682     XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
684     LockDisplay(dpy);
685     GetReq(DRI2SwapInterval, req);
686     req->reqType = info->codes->major_opcode;
687     req->dri2ReqType = X_DRI2SwapInterval;
688     req->drawable = drawable;
689     req->interval = interval;
690     UnlockDisplay(dpy);
691     SyncHandle();
693 #endif