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