1 /*
2 * Copyright (c) 2008 NVIDIA, Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #define _GNU_SOURCE 1
25 #include "sysdeps.h"
26
27 #ifdef HAVE_NVCTRL
28
29 #include <string.h>
30
31 #define NEED_REPLIES
32 #include <stdlib.h>
33 #include <X11/Xlibint.h>
34 #include <X11/Xutil.h>
35 #include <X11/extensions/Xext.h>
36 #include <X11/extensions/extutil.h>
37 #include "va_nvctrl.h"
38
39 #define NV_CONTROL_ERRORS 0
40 #define NV_CONTROL_EVENTS 5
41 #define NV_CONTROL_NAME "NV-CONTROL"
42
43 #define NV_CTRL_TARGET_TYPE_X_SCREEN 0
44 #define NV_CTRL_TARGET_TYPE_GPU 1
45 #define NV_CTRL_TARGET_TYPE_FRAMELOCK 2
46 #define NV_CTRL_TARGET_TYPE_VCSC 3 /* Visual Computing System */
47
48 #define NV_CTRL_STRING_NVIDIA_DRIVER_VERSION 3 /* R--G */
49
50 #define X_nvCtrlQueryExtension 0
51 #define X_nvCtrlIsNv 1
52 #define X_nvCtrlQueryStringAttribute 4
53
54 typedef struct {
55 CARD8 reqType;
56 CARD8 nvReqType;
57 CARD16 length B16;
58 } xnvCtrlQueryExtensionReq;
59 #define sz_xnvCtrlQueryExtensionReq 4
60
61 typedef struct {
62 BYTE type; /* X_Reply */
63 CARD8 padb1;
64 CARD16 sequenceNumber B16;
65 CARD32 length B32;
66 CARD16 major B16;
67 CARD16 minor B16;
68 CARD32 padl4 B32;
69 CARD32 padl5 B32;
70 CARD32 padl6 B32;
71 CARD32 padl7 B32;
72 CARD32 padl8 B32;
73 } xnvCtrlQueryExtensionReply;
74 #define sz_xnvCtrlQueryExtensionReply 32
75
76 typedef struct {
77 CARD8 reqType;
78 CARD8 nvReqType;
79 CARD16 length B16;
80 CARD32 screen B32;
81 } xnvCtrlIsNvReq;
82 #define sz_xnvCtrlIsNvReq 8
83
84 typedef struct {
85 BYTE type; /* X_Reply */
86 CARD8 padb1;
87 CARD16 sequenceNumber B16;
88 CARD32 length B32;
89 CARD32 isnv B32;
90 CARD32 padl4 B32;
91 CARD32 padl5 B32;
92 CARD32 padl6 B32;
93 CARD32 padl7 B32;
94 CARD32 padl8 B32;
95 } xnvCtrlIsNvReply;
96 #define sz_xnvCtrlIsNvReply 32
97
98 typedef struct {
99 CARD8 reqType;
100 CARD8 nvReqType;
101 CARD16 length B16;
102 CARD16 target_id B16; /* X screen number or GPU number */
103 CARD16 target_type B16; /* X screen or GPU */
104 CARD32 display_mask B32;
105 CARD32 attribute B32;
106 } xnvCtrlQueryStringAttributeReq;
107 #define sz_xnvCtrlQueryStringAttributeReq 16
108
109 typedef struct {
110 BYTE type;
111 BYTE pad0;
112 CARD16 sequenceNumber B16;
113 CARD32 length B32;
114 CARD32 flags B32;
115 CARD32 n B32; /* Length of string */
116 CARD32 pad4 B32;
117 CARD32 pad5 B32;
118 CARD32 pad6 B32;
119 CARD32 pad7 B32;
120 } xnvCtrlQueryStringAttributeReply;
121 #define sz_xnvCtrlQueryStringAttributeReply 32
122
123 #define NVCTRL_EXT_NEED_CHECK (XPointer)(~0)
124 #define NVCTRL_EXT_NEED_NOTHING (XPointer)(0)
125 #define NVCTRL_EXT_NEED_TARGET_SWAP (XPointer)(1)
126
127 static XExtensionInfo _nvctrl_ext_info_data;
128 static XExtensionInfo *nvctrl_ext_info = &_nvctrl_ext_info_data;
129 static /* const */ char *nvctrl_extension_name = NV_CONTROL_NAME;
130
131 #define XNVCTRLCheckExtension(dpy,i,val) \
132 XextCheckExtension (dpy, i, nvctrl_extension_name, val)
133 #define XNVCTRLSimpleCheckExtension(dpy,i) \
134 XextSimpleCheckExtension (dpy, i, nvctrl_extension_name)
135
136 static XEXT_GENERATE_CLOSE_DISPLAY(close_display, nvctrl_ext_info)
137
138 static /* const */ XExtensionHooks nvctrl_extension_hooks = {
139 NULL, /* create_gc */
140 NULL, /* copy_gc */
141 NULL, /* flush_gc */
142 NULL, /* free_gc */
143 NULL, /* create_font */
144 NULL, /* free_font */
145 close_display, /* close_display */
146 NULL, /* wire_to_event */
147 NULL, /* event_to_wire */
148 NULL, /* error */
149 NULL, /* error_string */
150 };
151
152 static XEXT_GENERATE_FIND_DISPLAY(find_display, nvctrl_ext_info,
153 nvctrl_extension_name,
154 &nvctrl_extension_hooks,
155 NV_CONTROL_EVENTS, NVCTRL_EXT_NEED_CHECK)
156
157 static Bool XNVCTRLQueryVersion(Display *dpy, int *major, int *minor);
158
159 /*
160 * NV-CONTROL versions 1.8 and 1.9 pack the target_type and target_id
161 * fields in reversed order. In order to talk to one of these servers,
162 * we need to swap these fields.
163 */
XNVCTRLCheckTargetData(Display * dpy,XExtDisplayInfo * info,int * target_type,int * target_id)164 static void XNVCTRLCheckTargetData(Display *dpy, XExtDisplayInfo *info,
165 int *target_type, int *target_id)
166 {
167 /* Find out what the server's NV-CONTROL version is and
168 * setup for swapping if we need to.
169 */
170 if (info->data == NVCTRL_EXT_NEED_CHECK) {
171 int major, minor;
172
173 if (XNVCTRLQueryVersion(dpy, &major, &minor)) {
174 if (major == 1 &&
175 (minor == 8 || minor == 9)) {
176 info->data = NVCTRL_EXT_NEED_TARGET_SWAP;
177 } else {
178 info->data = NVCTRL_EXT_NEED_NOTHING;
179 }
180 } else {
181 info->data = NVCTRL_EXT_NEED_NOTHING;
182 }
183 }
184
185 /* We need to swap the target_type and target_id */
186 if (info->data == NVCTRL_EXT_NEED_TARGET_SWAP) {
187 int tmp;
188 tmp = *target_type;
189 *target_type = *target_id;
190 *target_id = tmp;
191 }
192 }
193
194
XNVCTRLQueryExtension(Display * dpy,int * event_basep,int * error_basep)195 static Bool XNVCTRLQueryExtension(
196 Display *dpy,
197 int *event_basep,
198 int *error_basep
199 )
200 {
201 XExtDisplayInfo *info = find_display(dpy);
202
203 if (XextHasExtension(info)) {
204 if (event_basep) *event_basep = info->codes->first_event;
205 if (error_basep) *error_basep = info->codes->first_error;
206 return True;
207 } else {
208 return False;
209 }
210 }
211
212
XNVCTRLQueryVersion(Display * dpy,int * major,int * minor)213 static Bool XNVCTRLQueryVersion(
214 Display *dpy,
215 int *major,
216 int *minor
217 )
218 {
219 XExtDisplayInfo *info = find_display(dpy);
220 xnvCtrlQueryExtensionReply rep;
221 xnvCtrlQueryExtensionReq *req;
222
223 if (!XextHasExtension(info))
224 return False;
225
226 XNVCTRLCheckExtension(dpy, info, False);
227
228 LockDisplay(dpy);
229 GetReq(nvCtrlQueryExtension, req);
230 req->reqType = info->codes->major_opcode;
231 req->nvReqType = X_nvCtrlQueryExtension;
232 if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) {
233 UnlockDisplay(dpy);
234 SyncHandle();
235 return False;
236 }
237 if (major) *major = rep.major;
238 if (minor) *minor = rep.minor;
239 UnlockDisplay(dpy);
240 SyncHandle();
241 return True;
242 }
243
244
XNVCTRLIsNvScreen(Display * dpy,int screen)245 static Bool XNVCTRLIsNvScreen(
246 Display *dpy,
247 int screen
248 )
249 {
250 XExtDisplayInfo *info = find_display(dpy);
251 xnvCtrlIsNvReply rep;
252 xnvCtrlIsNvReq *req;
253 Bool isnv;
254
255 if (!XextHasExtension(info))
256 return False;
257
258 XNVCTRLCheckExtension(dpy, info, False);
259
260 LockDisplay(dpy);
261 GetReq(nvCtrlIsNv, req);
262 req->reqType = info->codes->major_opcode;
263 req->nvReqType = X_nvCtrlIsNv;
264 req->screen = screen;
265 if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) {
266 UnlockDisplay(dpy);
267 SyncHandle();
268 return False;
269 }
270 isnv = rep.isnv;
271 UnlockDisplay(dpy);
272 SyncHandle();
273 return isnv;
274 }
275
276
XNVCTRLQueryTargetStringAttribute(Display * dpy,int target_type,int target_id,unsigned int display_mask,unsigned int attribute,char ** ptr)277 static Bool XNVCTRLQueryTargetStringAttribute(
278 Display *dpy,
279 int target_type,
280 int target_id,
281 unsigned int display_mask,
282 unsigned int attribute,
283 char **ptr
284 )
285 {
286 XExtDisplayInfo *info = find_display(dpy);
287 xnvCtrlQueryStringAttributeReply rep;
288 xnvCtrlQueryStringAttributeReq *req;
289 Bool exists;
290 int length, numbytes, slop;
291
292 if (!ptr) return False;
293
294 if (!XextHasExtension(info))
295 return False;
296
297 XNVCTRLCheckExtension(dpy, info, False);
298 XNVCTRLCheckTargetData(dpy, info, &target_type, &target_id);
299
300 LockDisplay(dpy);
301 GetReq(nvCtrlQueryStringAttribute, req);
302 req->reqType = info->codes->major_opcode;
303 req->nvReqType = X_nvCtrlQueryStringAttribute;
304 req->target_type = target_type;
305 req->target_id = target_id;
306 req->display_mask = display_mask;
307 req->attribute = attribute;
308 if (!_XReply(dpy, (xReply *) &rep, 0, False)) {
309 UnlockDisplay(dpy);
310 SyncHandle();
311 return False;
312 }
313 length = rep.length;
314 numbytes = rep.n;
315 slop = numbytes & 3;
316 *ptr = (char *) Xmalloc(numbytes);
317 if (! *ptr) {
318 _XEatData(dpy, length);
319 UnlockDisplay(dpy);
320 SyncHandle();
321 return False;
322 } else {
323 _XRead(dpy, (char *) *ptr, numbytes);
324 if (slop) _XEatData(dpy, 4 - slop);
325 }
326 exists = rep.flags;
327 UnlockDisplay(dpy);
328 SyncHandle();
329 return exists;
330 }
331
XNVCTRLQueryStringAttribute(Display * dpy,int screen,unsigned int display_mask,unsigned int attribute,char ** ptr)332 static Bool XNVCTRLQueryStringAttribute(
333 Display *dpy,
334 int screen,
335 unsigned int display_mask,
336 unsigned int attribute,
337 char **ptr
338 )
339 {
340 return XNVCTRLQueryTargetStringAttribute(dpy, NV_CTRL_TARGET_TYPE_X_SCREEN,
341 screen, display_mask,
342 attribute, ptr);
343 }
344
345
VA_NVCTRLQueryDirectRenderingCapable(Display * dpy,int screen,Bool * isCapable)346 static Bool VA_NVCTRLQueryDirectRenderingCapable(Display *dpy, int screen,
347 Bool *isCapable)
348 {
349 int event_base;
350 int error_base;
351
352 if (isCapable)
353 *isCapable = False;
354
355 if (!XNVCTRLQueryExtension(dpy, &event_base, &error_base))
356 return False;
357
358 if (isCapable && XNVCTRLIsNvScreen(dpy, screen))
359 *isCapable = True;
360
361 return True;
362 }
363
VA_NVCTRLGetClientDriverName(Display * dpy,int screen,char ** clientDriverName)364 static Bool VA_NVCTRLGetClientDriverName(Display *dpy, int screen,
365 char **clientDriverName)
366 {
367 int ddxDriverMajorVersion, ddxDriverMinorVersion, ddxDriverPatchVersion;
368
369 char *nvidia_driver_version = NULL;
370 if (!XNVCTRLQueryStringAttribute(dpy, screen, 0, NV_CTRL_STRING_NVIDIA_DRIVER_VERSION, &nvidia_driver_version))
371 return False;
372
373 char *end, *str = nvidia_driver_version;
374 unsigned long v = strtoul(str, &end, 10);
375 if (end && end != str) {
376 ddxDriverMajorVersion = v;
377 if (*(str = end) == '.') {
378 v = strtoul(str + 1, &end, 10);
379 if (end && end != str && (*end == '.' || *end == '\0')) {
380 ddxDriverMinorVersion = v;
381 if (*(str = end) == '.') {
382 v = strtoul(str + 1, &end, 10);
383 if (end && end != str && *end == '\0') {
384 ddxDriverPatchVersion = v;
385 }
386 }
387 }
388 }
389 }
390 Xfree(nvidia_driver_version);
391 (void) ddxDriverMajorVersion;
392 (void) ddxDriverMinorVersion;
393 (void) ddxDriverPatchVersion;
394
395 *clientDriverName = strdup("nvidia");
396
397 return True;
398 }
399
va_NVCTRL_GetDriverNames(VADisplayContextP pDisplayContext,char ** drivers,unsigned * num_drivers)400 VAStatus va_NVCTRL_GetDriverNames(
401 VADisplayContextP pDisplayContext,
402 char **drivers,
403 unsigned *num_drivers
404 )
405 {
406 VADriverContextP ctx = pDisplayContext->pDriverContext;
407 int direct_capable;
408
409 if (!VA_NVCTRLQueryDirectRenderingCapable(ctx->native_dpy, ctx->x11_screen,
410 &direct_capable) || !direct_capable)
411 return VA_STATUS_ERROR_UNKNOWN;
412
413 if (!VA_NVCTRLGetClientDriverName(ctx->native_dpy, ctx->x11_screen,
414 drivers))
415 return VA_STATUS_ERROR_UNKNOWN;
416
417 *num_drivers = 1;
418 return VA_STATUS_SUCCESS;
419 }
420
421 #endif
422