1 /*
2 * Copyright 2022 Google LLC
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "config.h"
7
8 #include <errno.h>
9 #include <inttypes.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <unistd.h>
13
14 #include <xf86drm.h>
15
16 #include "drm_hw.h"
17 #include "drm_renderer.h"
18
19 #ifdef ENABLE_DRM_MSM
20 # include "msm/msm_renderer.h"
21 #endif
22
23 static struct virgl_renderer_capset_drm capset;
24
25 static const struct backend {
26 uint32_t context_type;
27 const char *name;
28 int (*probe)(int fd, struct virgl_renderer_capset_drm *capset);
29 struct virgl_context *(*create)(int fd);
30 } backends[] = {
31 #ifdef ENABLE_DRM_MSM
32 {
33 .context_type = VIRTGPU_DRM_CONTEXT_MSM,
34 .name = "msm",
35 .probe = msm_renderer_probe,
36 .create = msm_renderer_create,
37 },
38 #endif
39 };
40
41 int
drm_renderer_init(int drm_fd)42 drm_renderer_init(int drm_fd)
43 {
44 for (unsigned i = 0; i < ARRAY_SIZE(backends); i++) {
45 const struct backend *b = &backends[i];
46 int fd;
47
48 if (drm_fd != -1) {
49 fd = drm_fd;
50 } else {
51 fd = drmOpenWithType(b->name, NULL, DRM_NODE_RENDER);
52 if (fd < 0)
53 continue;
54 }
55
56 drmVersionPtr ver = drmGetVersion(fd);
57 if (!ver) {
58 close(fd);
59 return -ENOMEM;
60 }
61
62 if (strcmp(ver->name, b->name)) {
63 /* In the drmOpenWithType() path, we will only get back an fd
64 * for the device with matching name. But when we are using
65 * an externally provided fd, we need to go thru the backends
66 * table to see which one has the matching name.
67 */
68 assert(drm_fd != -1);
69 drmFreeVersion(ver);
70 continue;
71 }
72
73 capset.version_major = ver->version_major;
74 capset.version_minor = ver->version_minor;
75 capset.version_patchlevel = ver->version_patchlevel;
76 capset.context_type = b->context_type;
77
78 int ret = b->probe(fd, &capset);
79 if (ret)
80 memset(&capset, 0, sizeof(capset));
81
82 drmFreeVersion(ver);
83 close(fd);
84 return ret;
85 }
86
87 if (drm_fd != -1)
88 close(drm_fd);
89
90 return -ENODEV;
91 }
92
93 void
drm_renderer_fini(void)94 drm_renderer_fini(void)
95 {
96 drm_log("");
97 }
98
99 void
drm_renderer_reset(void)100 drm_renderer_reset(void)
101 {
102 drm_log("");
103 }
104
105 size_t
drm_renderer_capset(void * _c)106 drm_renderer_capset(void *_c)
107 {
108 struct virgl_renderer_capset_drm *c = _c;
109 drm_log("c=%p", c);
110
111 if (!capset.context_type)
112 return 0;
113
114 if (c)
115 *c = capset;
116
117 return sizeof(*c);
118 }
119
120 struct virgl_context *
drm_renderer_create(UNUSED size_t debug_len,UNUSED const char * debug_name)121 drm_renderer_create(UNUSED size_t debug_len, UNUSED const char *debug_name)
122 {
123 for (unsigned i = 0; i < ARRAY_SIZE(backends); i++) {
124 const struct backend *b = &backends[i];
125
126 if (b->context_type != capset.context_type)
127 continue;
128
129 int fd = drmOpenWithType(b->name, NULL, DRM_NODE_RENDER);
130 if (fd < 0)
131 return NULL;
132
133 return b->create(fd);
134 }
135
136 return NULL;
137 }
138