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