Fixes dependencies on GL/glx.h and GL/glxext.h files (v2)
[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 <xorg/list.h>
47 #include "X11/extensions/dri2.h"
49 /* Allow the build to work with an older versions of dri2proto.h and
50  * dri2tokens.h.
51  */
52 #if DRI2_MINOR < 1
53 #undef DRI2_MINOR
54 #define DRI2_MINOR 1
55 #define X_DRI2GetBuffersWithFormat 7
56 #endif
59 static char dri2ExtensionName[] = DRI2_NAME;
60 static XExtensionInfo *dri2Info;
61 static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay2, dri2Info)
63 /**
64  * List of per-Display privates..
65  */
66 static struct list dpy_list = { &dpy_list, &dpy_list };
68 typedef struct {
69         struct list list;
70         Display *dpy;
71         const DRI2EventOps *ops;
72 } DRI2Display;
74 static DRI2Display * dpy2dri(Display *dpy)
75 {
76         DRI2Display *dri2dpy;
77         list_for_each_entry(dri2dpy, &dpy_list, list) {
78                 if (dri2dpy->dpy == dpy) {
79                         return dri2dpy;
80                 }
81         }
82         return NULL;
83 }
85 static int
86 DRI2CloseDisplay(Display *dpy, XExtCodes *codes)
87 {
88         DRI2Display *dri2dpy = dpy2dri(dpy);
89         if (dri2dpy) {
90                 list_del(&dri2dpy->list);
91                 free(dri2dpy);
92         }
93         return DRI2CloseDisplay2(dpy, codes);
94 }
96 Bool
97 DRI2InitDisplay(Display *dpy, const DRI2EventOps *ops)
98 {
99         DRI2Display *dri2dpy = dpy2dri(dpy);
100         if (!dri2dpy) {
101                 dri2dpy = malloc(sizeof(*dri2dpy));
102                 if (!dri2dpy) {
103                         return False;
104                 }
105                 dri2dpy->dpy = dpy;
106                 dri2dpy->ops = ops;
107                 list_add(&dri2dpy->list, &dpy_list);
108         }
109         return True;
112 static Bool
113 DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
114 static Status
115 DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
116 static int
117 DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
119 static /* const */ XExtensionHooks dri2ExtensionHooks = {
120   NULL,                   /* create_gc */
121   NULL,                   /* copy_gc */
122   NULL,                   /* flush_gc */
123   NULL,                   /* free_gc */
124   NULL,                   /* create_font */
125   NULL,                   /* free_font */
126   DRI2CloseDisplay,       /* close_display */
127   DRI2WireToEvent,        /* wire_to_event */
128   DRI2EventToWire,        /* event_to_wire */
129   DRI2Error,              /* error */
130   NULL,                   /* error_string */
131 };
133 static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
134                                    dri2Info,
135                                    dri2ExtensionName,
136                                    &dri2ExtensionHooks,
137                                    0, NULL)
139 static Bool
140 DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
142    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
143    DRI2Display *dri2dpy = dpy2dri(dpy);
145    XextCheckExtension(dpy, info, dri2ExtensionName, False);
147    if (dri2dpy && dri2dpy->ops && dri2dpy->ops->WireToEvent) {
148            return dri2dpy->ops->WireToEvent(dpy, info, event, wire);
149    }
151    return False;
154 /* We don't actually support this.  It doesn't make sense for clients to
155  * send each other DRI2 events.
156  */
157 static Status
158 DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
160    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
161    DRI2Display *dri2dpy = dpy2dri(dpy);
163    XextCheckExtension(dpy, info, dri2ExtensionName, False);
165    if (dri2dpy && dri2dpy->ops && dri2dpy->ops->EventToWire) {
166            return dri2dpy->ops->EventToWire(dpy, info, event, wire);
167    }
169    return Success;
172 static int
173 DRI2Error(Display *dpy, xError *err, XExtCodes *codes, int *ret_code)
175         DRI2Display *dri2dpy = dpy2dri(dpy);
177         if (dri2dpy && dri2dpy->ops && dri2dpy->ops->Error) {
178                 return dri2dpy->ops->Error(dpy, err, codes, ret_code);
179         }
181     return False;
184 Bool
185 DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
187    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
189    if (XextHasExtension(info)) {
190       *eventBase = info->codes->first_event;
191       *errorBase = info->codes->first_error;
192       return True;
193    }
195    return False;
198 Bool
199 DRI2QueryVersion(Display * dpy, int *major, int *minor)
201    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
202    xDRI2QueryVersionReply rep;
203    xDRI2QueryVersionReq *req;
204    int i, nevents;
206    XextCheckExtension(dpy, info, dri2ExtensionName, False);
208    LockDisplay(dpy);
209    GetReq(DRI2QueryVersion, req);
210    req->reqType = info->codes->major_opcode;
211    req->dri2ReqType = X_DRI2QueryVersion;
212    req->majorVersion = DRI2_MAJOR;
213    req->minorVersion = DRI2_MINOR;
214    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
215       UnlockDisplay(dpy);
216       SyncHandle();
217       return False;
218    }
219    *major = rep.majorVersion;
220    *minor = rep.minorVersion;
221    UnlockDisplay(dpy);
222    SyncHandle();
224    switch (rep.minorVersion) {
225    case 1:
226            nevents = 0;
227            break;
228    case 2:
229            nevents = 1;
230            break;
231    case 3:
232    default:
233            nevents = 2;
234            break;
235    }
236         
237    for (i = 0; i < nevents; i++) {
238        XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent);
239        XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire);
240    }
242    return True;
245 Bool
246 DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
248    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
249    xDRI2ConnectReply rep;
250    xDRI2ConnectReq *req;
252    XextCheckExtension(dpy, info, dri2ExtensionName, False);
254    LockDisplay(dpy);
255    GetReq(DRI2Connect, req);
256    req->reqType = info->codes->major_opcode;
257    req->dri2ReqType = X_DRI2Connect;
258    req->window = window;
259    req->driverType = DRI2DriverDRI;
260    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
261       UnlockDisplay(dpy);
262       SyncHandle();
263       return False;
264    }
266    if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
267       UnlockDisplay(dpy);
268       SyncHandle();
269       return False;
270    }
272    *driverName = Xmalloc(rep.driverNameLength + 1);
273    if (*driverName == NULL) {
274       _XEatData(dpy,
275                 ((rep.driverNameLength + 3) & ~3) +
276                 ((rep.deviceNameLength + 3) & ~3));
277       UnlockDisplay(dpy);
278       SyncHandle();
279       return False;
280    }
281    _XReadPad(dpy, *driverName, rep.driverNameLength);
282    (*driverName)[rep.driverNameLength] = '\0';
284    *deviceName = Xmalloc(rep.deviceNameLength + 1);
285    if (*deviceName == NULL) {
286       Xfree(*driverName);
287       _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
288       UnlockDisplay(dpy);
289       SyncHandle();
290       return False;
291    }
292    _XReadPad(dpy, *deviceName, rep.deviceNameLength);
293    (*deviceName)[rep.deviceNameLength] = '\0';
295    UnlockDisplay(dpy);
296    SyncHandle();
298    return True;
301 Bool
302 DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
304    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
305    xDRI2AuthenticateReq *req;
306    xDRI2AuthenticateReply rep;
308    XextCheckExtension(dpy, info, dri2ExtensionName, False);
310    LockDisplay(dpy);
311    GetReq(DRI2Authenticate, req);
312    req->reqType = info->codes->major_opcode;
313    req->dri2ReqType = X_DRI2Authenticate;
314    req->window = window;
315    req->magic = magic;
317    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
318       UnlockDisplay(dpy);
319       SyncHandle();
320       return False;
321    }
323    UnlockDisplay(dpy);
324    SyncHandle();
326    return rep.authenticated;
329 void
330 DRI2CreateDrawable(Display * dpy, XID drawable)
332    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
333    xDRI2CreateDrawableReq *req;
335    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
337    LockDisplay(dpy);
338    GetReq(DRI2CreateDrawable, req);
339    req->reqType = info->codes->major_opcode;
340    req->dri2ReqType = X_DRI2CreateDrawable;
341    req->drawable = drawable;
342    UnlockDisplay(dpy);
343    SyncHandle();
346 void
347 DRI2DestroyDrawable(Display * dpy, XID drawable)
349    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
350    xDRI2DestroyDrawableReq *req;
352    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
354    XSync(dpy, False);
356    LockDisplay(dpy);
357    GetReq(DRI2DestroyDrawable, req);
358    req->reqType = info->codes->major_opcode;
359    req->dri2ReqType = X_DRI2DestroyDrawable;
360    req->drawable = drawable;
361    UnlockDisplay(dpy);
362    SyncHandle();
365 DRI2Buffer *
366 DRI2GetBuffers(Display * dpy, XID drawable,
367                int *width, int *height,
368                unsigned int *attachments, int count, int *outCount)
370    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
371    xDRI2GetBuffersReply rep;
372    xDRI2GetBuffersReq *req;
373    DRI2Buffer *buffers;
374    xDRI2Buffer repBuffer;
375    CARD32 *p;
376    int i;
378    XextCheckExtension(dpy, info, dri2ExtensionName, False);
380    LockDisplay(dpy);
381    GetReqExtra(DRI2GetBuffers, count * 4, req);
382    req->reqType = info->codes->major_opcode;
383    req->dri2ReqType = X_DRI2GetBuffers;
384    req->drawable = drawable;
385    req->count = count;
386    p = (CARD32 *) & req[1];
387    for (i = 0; i < count; i++)
388       p[i] = attachments[i];
390    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
391       UnlockDisplay(dpy);
392       SyncHandle();
393       return NULL;
394    }
396    *width = rep.width;
397    *height = rep.height;
398    *outCount = rep.count;
400    buffers = Xmalloc(rep.count * sizeof buffers[0]);
401    if (buffers == NULL) {
402       _XEatData(dpy, rep.count * sizeof repBuffer);
403       UnlockDisplay(dpy);
404       SyncHandle();
405       return NULL;
406    }
408    for (i = 0; i < rep.count; i++) {
409       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
410       buffers[i].attachment = repBuffer.attachment;
411       buffers[i].name = repBuffer.name;
412       buffers[i].pitch = repBuffer.pitch;
413       buffers[i].cpp = repBuffer.cpp;
414       buffers[i].flags = repBuffer.flags;
415    }
417    UnlockDisplay(dpy);
418    SyncHandle();
420    return buffers;
424 DRI2Buffer *
425 DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
426                          int *width, int *height,
427                          unsigned int *attachments, int count, int *outCount)
429    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
430    xDRI2GetBuffersReply rep;
431    xDRI2GetBuffersReq *req;
432    DRI2Buffer *buffers;
433    xDRI2Buffer repBuffer;
434    CARD32 *p;
435    int i;
437    XextCheckExtension(dpy, info, dri2ExtensionName, False);
439    LockDisplay(dpy);
440    GetReqExtra(DRI2GetBuffers, count * (4 * 2), req);
441    req->reqType = info->codes->major_opcode;
442    req->dri2ReqType = X_DRI2GetBuffersWithFormat;
443    req->drawable = drawable;
444    req->count = count;
445    p = (CARD32 *) & req[1];
446    for (i = 0; i < (count * 2); i++)
447       p[i] = attachments[i];
449    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
450       UnlockDisplay(dpy);
451       SyncHandle();
452       return NULL;
453    }
455    *width = rep.width;
456    *height = rep.height;
457    *outCount = rep.count;
459    buffers = Xmalloc(rep.count * sizeof buffers[0]);
460    if (buffers == NULL) {
461       _XEatData(dpy, rep.count * sizeof repBuffer);
462       UnlockDisplay(dpy);
463       SyncHandle();
464       return NULL;
465    }
467    for (i = 0; i < rep.count; i++) {
468       _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer);
469       buffers[i].attachment = repBuffer.attachment;
470       buffers[i].name = repBuffer.name;
471       buffers[i].pitch = repBuffer.pitch;
472       buffers[i].cpp = repBuffer.cpp;
473       buffers[i].flags = repBuffer.flags;
474    }
476    UnlockDisplay(dpy);
477    SyncHandle();
479    return buffers;
483 void
484 DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
485                CARD32 dest, CARD32 src)
487    XExtDisplayInfo *info = DRI2FindDisplay(dpy);
488    xDRI2CopyRegionReq *req;
489    xDRI2CopyRegionReply rep;
491    XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
493    LockDisplay(dpy);
494    GetReq(DRI2CopyRegion, req);
495    req->reqType = info->codes->major_opcode;
496    req->dri2ReqType = X_DRI2CopyRegion;
497    req->drawable = drawable;
498    req->region = region;
499    req->dest = dest;
500    req->src = src;
502    _XReply(dpy, (xReply *) & rep, 0, xFalse);
504    UnlockDisplay(dpy);
505    SyncHandle();
508 #ifdef X_DRI2SwapBuffers
509 static void
510 load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
511              CARD64 remainder)
513     req->target_msc_hi = target >> 32;
514     req->target_msc_lo = target & 0xffffffff;
515     req->divisor_hi = divisor >> 32;
516     req->divisor_lo = divisor & 0xffffffff;
517     req->remainder_hi = remainder >> 32;
518     req->remainder_lo = remainder & 0xffffffff;
521 static CARD64
522 vals_to_card64(CARD32 lo, CARD32 hi)
524     return (CARD64)hi << 32 | lo;
527 void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
528                      CARD64 divisor, CARD64 remainder, CARD64 *count)
530     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
531     xDRI2SwapBuffersReq *req;
532     xDRI2SwapBuffersReply rep;
534     XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
536     LockDisplay(dpy);
537     GetReq(DRI2SwapBuffers, req);
538     req->reqType = info->codes->major_opcode;
539     req->dri2ReqType = X_DRI2SwapBuffers;
540     req->drawable = drawable;
541     load_swap_req(req, target_msc, divisor, remainder);
543     _XReply(dpy, (xReply *)&rep, 0, xFalse);
545     *count = vals_to_card64(rep.swap_lo, rep.swap_hi);
547     UnlockDisplay(dpy);
548     SyncHandle();
550 #endif
552 #ifdef X_DRI2GetMSC
553 Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
554                 CARD64 *sbc)
556     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
557     xDRI2GetMSCReq *req;
558     xDRI2MSCReply rep;
560     XextCheckExtension (dpy, info, dri2ExtensionName, False);
562     LockDisplay(dpy);
563     GetReq(DRI2GetMSC, req);
564     req->reqType = info->codes->major_opcode;
565     req->dri2ReqType = X_DRI2GetMSC;
566     req->drawable = drawable;
568     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
569         UnlockDisplay(dpy);
570         SyncHandle();
571         return False;
572     }
574     *ust = vals_to_card64(rep.ust_lo, rep.ust_hi);
575     *msc = vals_to_card64(rep.msc_lo, rep.msc_hi);
576     *sbc = vals_to_card64(rep.sbc_lo, rep.sbc_hi);
578     UnlockDisplay(dpy);
579     SyncHandle();
581     return True;
583 #endif
585 #ifdef X_DRI2WaitMSC
586 static void
587 load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
588              CARD64 remainder)
590     req->target_msc_hi = target >> 32;
591     req->target_msc_lo = target & 0xffffffff;
592     req->divisor_hi = divisor >> 32;
593     req->divisor_lo = divisor & 0xffffffff;
594     req->remainder_hi = remainder >> 32;
595     req->remainder_lo = remainder & 0xffffffff;
598 Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
599                  CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
601     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
602     xDRI2WaitMSCReq *req;
603     xDRI2MSCReply rep;
605     XextCheckExtension (dpy, info, dri2ExtensionName, False);
607     LockDisplay(dpy);
608     GetReq(DRI2WaitMSC, req);
609     req->reqType = info->codes->major_opcode;
610     req->dri2ReqType = X_DRI2WaitMSC;
611     req->drawable = drawable;
612     load_msc_req(req, target_msc, divisor, remainder);
614     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
615         UnlockDisplay(dpy);
616         SyncHandle();
617         return False;
618     }
620     *ust = ((CARD64)rep.ust_hi << 32) | (CARD64)rep.ust_lo;
621     *msc = ((CARD64)rep.msc_hi << 32) | (CARD64)rep.msc_lo;
622     *sbc = ((CARD64)rep.sbc_hi << 32) | (CARD64)rep.sbc_lo;
624     UnlockDisplay(dpy);
625     SyncHandle();
627     return True;
629 #endif
631 #ifdef X_DRI2WaitSBC
632 static void
633 load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
635     req->target_sbc_hi = target >> 32;
636     req->target_sbc_lo = target & 0xffffffff;
639 Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
640                  CARD64 *msc, CARD64 *sbc)
642     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
643     xDRI2WaitSBCReq *req;
644     xDRI2MSCReply rep;
646     XextCheckExtension (dpy, info, dri2ExtensionName, False);
648     LockDisplay(dpy);
649     GetReq(DRI2WaitSBC, req);
650     req->reqType = info->codes->major_opcode;
651     req->dri2ReqType = X_DRI2WaitSBC;
652     req->drawable = drawable;
653     load_sbc_req(req, target_sbc);
655     if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
656         UnlockDisplay(dpy);
657         SyncHandle();
658         return False;
659     }
661     *ust = ((CARD64)rep.ust_hi << 32) | rep.ust_lo;
662     *msc = ((CARD64)rep.msc_hi << 32) | rep.msc_lo;
663     *sbc = ((CARD64)rep.sbc_hi << 32) | rep.sbc_lo;
665     UnlockDisplay(dpy);
666     SyncHandle();
668     return True;
670 #endif
672 #ifdef X_DRI2SwapInterval
673 void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
675     XExtDisplayInfo *info = DRI2FindDisplay(dpy);
676     xDRI2SwapIntervalReq *req;
678     XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
680     LockDisplay(dpy);
681     GetReq(DRI2SwapInterval, req);
682     req->reqType = info->codes->major_opcode;
683     req->dri2ReqType = X_DRI2SwapInterval;
684     req->drawable = drawable;
685     req->interval = interval;
686     UnlockDisplay(dpy);
687     SyncHandle();
689 #endif