xref: /aosp_15_r20/external/libva/va/x11/va_nvctrl.c (revision 54e60f844a168e9a219354de272cd517ee8cd4b7)
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