7b106c95721a688839e6639cfdf948d0013e0780
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)
100 {
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;
112 }
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)
145 {
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;
156 }
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)
163 {
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;
174 }
176 static int
177 DRI2Error(Display *dpy, xError *err, XExtCodes *codes, int *ret_code)
178 {
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;
186 }
188 Bool
189 DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
190 {
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;
200 }
202 Bool
203 DRI2QueryVersion(Display * dpy, int *major, int *minor)
204 {
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 }
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;
247 }
249 Bool
250 DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
251 {
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;
303 }
305 Bool
306 DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic)
307 {
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;
331 }
333 void
334 DRI2CreateDrawable(Display * dpy, XID drawable)
335 {
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();
348 }
350 void
351 DRI2DestroyDrawable(Display * dpy, XID drawable)
352 {
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();
367 }
369 DRI2Buffer *
370 DRI2GetBuffers(Display * dpy, XID drawable,
371 int *width, int *height,
372 unsigned int *attachments, int count, int *outCount)
373 {
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;
425 }
428 DRI2Buffer *
429 DRI2GetBuffersWithFormat(Display * dpy, XID drawable,
430 int *width, int *height,
431 unsigned int *attachments, int count, int *outCount)
432 {
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;
484 }
487 void
488 DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region,
489 CARD32 dest, CARD32 src)
490 {
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();
510 }
512 #ifdef X_DRI2SwapBuffers
513 static void
514 load_swap_req(xDRI2SwapBuffersReq *req, CARD64 target, CARD64 divisor,
515 CARD64 remainder)
516 {
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;
523 }
525 static CARD64
526 vals_to_card64(CARD32 lo, CARD32 hi)
527 {
528 return (CARD64)hi << 32 | lo;
529 }
531 void DRI2SwapBuffers(Display *dpy, XID drawable, CARD64 target_msc,
532 CARD64 divisor, CARD64 remainder, CARD64 *count)
533 {
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();
553 }
554 #endif
556 #ifdef X_DRI2GetMSC
557 Bool DRI2GetMSC(Display *dpy, XID drawable, CARD64 *ust, CARD64 *msc,
558 CARD64 *sbc)
559 {
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;
586 }
587 #endif
589 #ifdef X_DRI2WaitMSC
590 static void
591 load_msc_req(xDRI2WaitMSCReq *req, CARD64 target, CARD64 divisor,
592 CARD64 remainder)
593 {
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;
600 }
602 Bool DRI2WaitMSC(Display *dpy, XID drawable, CARD64 target_msc, CARD64 divisor,
603 CARD64 remainder, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
604 {
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;
632 }
633 #endif
635 #ifdef X_DRI2WaitSBC
636 static void
637 load_sbc_req(xDRI2WaitSBCReq *req, CARD64 target)
638 {
639 req->target_sbc_hi = target >> 32;
640 req->target_sbc_lo = target & 0xffffffff;
641 }
643 Bool DRI2WaitSBC(Display *dpy, XID drawable, CARD64 target_sbc, CARD64 *ust,
644 CARD64 *msc, CARD64 *sbc)
645 {
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;
673 }
674 #endif
676 #ifdef X_DRI2SwapInterval
677 void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
678 {
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();
692 }
693 #endif