1/*
2 * Copyright © 2008 Red Hat, Inc.
3 * Copyright © 2010-2015 NVIDIA Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Soft-
7 * ware"), to deal in the Software without restriction, including without
8 * limitation the rights to use, copy, modify, merge, publish, distribute,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, provided that the above copyright
11 * notice(s) and this permission notice appear in all copies of the Soft-
12 * ware and that both the above copyright notice(s) and this permission
13 * notice appear in supporting documentation.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
18 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
19 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
20 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
23 * MANCE OF THIS SOFTWARE.
24 *
25 * Except as contained in this notice, the name of a copyright holder shall
26 * not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization of
28 * the copyright holder.
29 *
30 * Authors:
31 *   Kristian Høgsberg (krh@redhat.com)
32 *   Modified for VDPAU by Aaron Plattner (aplattner@nvidia.com)
33 *   and José Hiram Soltren (jsoltren@nvidia.com)
34 */
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#define NEED_REPLIES
41#include <X11/Xlibint.h>
42#include <X11/extensions/Xext.h>
43#include <X11/extensions/extutil.h>
44#include <X11/extensions/dri2proto.h>
45#include "mesa_dri2.h"
46#include "util.h"
47
48static char dri2ExtensionName[] = DRI2_NAME;
49static XExtensionInfo *dri2Info;
50
51static /* const */ XExtensionHooks dri2ExtensionHooks = {
52  NULL,                   /* create_gc */
53  NULL,                   /* copy_gc */
54  NULL,                   /* flush_gc */
55  NULL,                   /* free_gc */
56  NULL,                   /* create_font */
57  NULL,                   /* free_font */
58  NULL,                   /* close_display */
59  NULL,                   /* wire_to_event */
60  NULL,                   /* event_to_wire */
61  NULL,                   /* error */
62  NULL,                   /* error_string */
63};
64
65static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
66                                   dri2Info,
67                                   dri2ExtensionName,
68                                   &dri2ExtensionHooks,
69                                   0, NULL)
70
71Bool
72_vdp_DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
73{
74   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
75
76   if (XextHasExtension(info)) {
77      *eventBase = info->codes->first_event;
78      *errorBase = info->codes->first_error;
79      return True;
80   }
81
82   if (dri2Info) {
83      if (info) {
84         XextRemoveDisplay(dri2Info, dpy);
85      }
86      XextDestroyExtension(dri2Info);
87      dri2Info = NULL;
88   }
89
90   return False;
91}
92
93Bool
94_vdp_DRI2QueryVersion(Display * dpy, int *major, int *minor)
95{
96   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
97   xDRI2QueryVersionReply rep;
98   xDRI2QueryVersionReq *req;
99
100   XextCheckExtension(dpy, info, dri2ExtensionName, False);
101
102   LockDisplay(dpy);
103   GetReq(DRI2QueryVersion, req);
104   req->reqType = info->codes->major_opcode;
105   req->dri2ReqType = X_DRI2QueryVersion;
106   req->majorVersion = DRI2_MAJOR;
107   req->minorVersion = DRI2_MINOR;
108   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
109      UnlockDisplay(dpy);
110      SyncHandle();
111      return False;
112   }
113   *major = rep.majorVersion;
114   *minor = rep.minorVersion;
115   UnlockDisplay(dpy);
116   SyncHandle();
117
118   return True;
119}
120
121Bool
122_vdp_DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
123{
124   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
125   xDRI2ConnectReply rep;
126   xDRI2ConnectReq *req;
127
128   XextCheckExtension(dpy, info, dri2ExtensionName, False);
129
130   LockDisplay(dpy);
131   GetReq(DRI2Connect, req);
132   req->reqType = info->codes->major_opcode;
133   req->dri2ReqType = X_DRI2Connect;
134   req->window = window;
135   req->driverType = DRI2DriverVDPAU;
136#ifdef DRI2DriverPrimeShift
137   {
138      char *prime = getenv_wrapper("DRI_PRIME");
139      if (prime) {
140         unsigned int primeid;
141         errno = 0;
142         primeid = strtoul(prime, NULL, 0);
143         if (errno == 0)
144            req->driverType |=
145               ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift);
146      }
147   }
148#endif
149
150   if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
151      UnlockDisplay(dpy);
152      SyncHandle();
153      return False;
154   }
155
156   if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
157      UnlockDisplay(dpy);
158      SyncHandle();
159      return False;
160   }
161
162   *driverName = Xmalloc(rep.driverNameLength + 1);
163   if (*driverName == NULL) {
164      _XEatData(dpy,
165                ((rep.driverNameLength + 3) & ~3) +
166                ((rep.deviceNameLength + 3) & ~3));
167      UnlockDisplay(dpy);
168      SyncHandle();
169      return False;
170   }
171   _XReadPad(dpy, *driverName, rep.driverNameLength);
172   (*driverName)[rep.driverNameLength] = '\0';
173
174   *deviceName = Xmalloc(rep.deviceNameLength + 1);
175   if (*deviceName == NULL) {
176      Xfree(*driverName);
177      _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
178      UnlockDisplay(dpy);
179      SyncHandle();
180      return False;
181   }
182   _XReadPad(dpy, *deviceName, rep.deviceNameLength);
183   (*deviceName)[rep.deviceNameLength] = '\0';
184
185   UnlockDisplay(dpy);
186   SyncHandle();
187
188   return True;
189}
190
191void
192_vdp_DRI2RemoveExtension(Display * dpy)
193{
194   XextRemoveDisplay(dri2Info, dpy);
195   XextDestroyExtension(dri2Info);
196   dri2Info = NULL;
197}
198