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