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