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