xref: /aosp_15_r20/external/libva/va/x11/va_dri3.c (revision 54e60f844a168e9a219354de272cd517ee8cd4b7)
1 /*
2  * Copyright © 2022 Collabora Ltd.
3  * Copyright (c) 2023 Emil Velikov
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  *   Emil Velikov ([email protected])
32  */
33 
34 #include "sysdeps.h"
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 
40 #include <xcb/xcb.h>
41 #include <xcb/dri3.h>
42 
43 #include <X11/Xlib-xcb.h>
44 #include <xf86drm.h>
45 
46 #include "va_backend.h"
47 #include "va_drmcommon.h"
48 #include "drm/va_drm_utils.h"
49 
50 static xcb_screen_t *
va_DRI3GetXCBScreen(xcb_connection_t * conn,int screen)51 va_DRI3GetXCBScreen(xcb_connection_t *conn, int screen)
52 {
53     xcb_screen_iterator_t iter;
54 
55     iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
56     for (; iter.rem; --screen, xcb_screen_next(&iter))
57         if (screen == 0)
58             return iter.data;
59     return NULL;
60 }
61 
62 static int
va_isDRI3Connected(VADriverContextP ctx,int * outfd)63 va_isDRI3Connected(VADriverContextP ctx, int *outfd)
64 {
65     xcb_connection_t *conn = XGetXCBConnection(ctx->native_dpy);
66     xcb_screen_t *screen;
67     xcb_window_t root;
68     const xcb_query_extension_reply_t *ext;
69     xcb_dri3_open_cookie_t cookie;
70     xcb_dri3_open_reply_t *reply;
71     int fd;
72     char *render_node;
73 
74     if (!conn)
75         return -1;
76 
77     screen = va_DRI3GetXCBScreen(conn, ctx->x11_screen);
78     if (!screen)
79         return -1;
80 
81     root = screen->root;
82 
83     xcb_prefetch_extension_data(conn, &xcb_dri3_id);
84     ext = xcb_get_extension_data(conn, &xcb_dri3_id);
85     if (!ext || !ext->present)
86         return -1;
87 
88     /* We don't require any of the ancy stuff, so there's no point in checking
89      * the version.
90      */
91 
92     cookie = xcb_dri3_open(conn, root, 0 /* provider */);
93     reply = xcb_dri3_open_reply(conn, cookie, NULL /* error */);
94 
95     if (!reply || reply->nfd != 1) {
96         free(reply);
97         return -1;
98     }
99 
100     fd = xcb_dri3_open_reply_fds(conn, reply)[0];
101     free(reply);
102 
103     /* The server can give us primary or a render node.
104      * In case of the former we need to swap it for the latter.
105      */
106     switch (drmGetNodeTypeFromFd(fd)) {
107     case DRM_NODE_PRIMARY:
108         render_node = drmGetRenderDeviceNameFromFd(fd);
109         close(fd);
110         if (!render_node)
111             return -1;
112 
113         fd = open(render_node, O_RDWR | O_CLOEXEC);
114         free(render_node);
115         if (fd == -1)
116             return -1;
117 
118         break;
119     case DRM_NODE_RENDER:
120         fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
121         break;
122     default:
123         close(fd);
124         return -1;
125     }
126 
127     *outfd = fd;
128     return 0;
129 }
130 
va_DRI3_GetDriverNames(VADisplayContextP pDisplayContext,char ** drivers,unsigned * num_drivers)131 VAStatus va_DRI3_GetDriverNames(
132     VADisplayContextP pDisplayContext,
133     char **drivers,
134     unsigned *num_drivers
135 )
136 {
137     VADriverContextP const ctx = pDisplayContext->pDriverContext;
138     struct drm_state * const drm_state = ctx->drm_state;
139     int fd = -1;
140 
141     if (va_isDRI3Connected(ctx, &fd) && fd != -1)
142         return VA_STATUS_ERROR_UNKNOWN;
143 
144     drm_state->fd = fd;
145     drm_state->auth_type = VA_DRM_AUTH_CUSTOM;
146     return VA_DRM_GetDriverNames(ctx, drivers, num_drivers);
147 }
148