]>
Commit | Line | Data |
---|---|---|
e16f4c87 | 1 | #include "qemu/osdep.h" |
7ced9e9f | 2 | #include <glob.h> |
1e316598 | 3 | #include <dirent.h> |
7ced9e9f | 4 | |
1e316598 | 5 | #include "config-host.h" |
7ced9e9f GH |
6 | #include "ui/egl-helpers.h" |
7 | ||
8 | EGLDisplay *qemu_egl_display; | |
9 | EGLConfig qemu_egl_config; | |
10 | ||
11 | /* ---------------------------------------------------------------------- */ | |
12 | ||
13 | static bool egl_gles; | |
14 | static int egl_debug; | |
15 | ||
16 | #define egl_dbg(_x ...) \ | |
17 | do { \ | |
18 | if (egl_debug) { \ | |
19 | fprintf(stderr, "egl: " _x); \ | |
20 | } \ | |
21 | } while (0); | |
22 | ||
23 | /* ---------------------------------------------------------------------- */ | |
24 | ||
1e316598 GH |
25 | #ifdef CONFIG_OPENGL_DMABUF |
26 | ||
27 | int qemu_egl_rn_fd; | |
28 | struct gbm_device *qemu_egl_rn_gbm_dev; | |
29 | EGLContext qemu_egl_rn_ctx; | |
30 | ||
31 | int qemu_egl_rendernode_open(void) | |
32 | { | |
33 | DIR *dir; | |
34 | struct dirent *e; | |
35 | int r, fd; | |
36 | char *p; | |
37 | ||
38 | dir = opendir("/dev/dri"); | |
39 | if (!dir) { | |
40 | return -1; | |
41 | } | |
42 | ||
43 | fd = -1; | |
44 | while ((e = readdir(dir))) { | |
45 | if (e->d_type != DT_CHR) { | |
46 | continue; | |
47 | } | |
48 | ||
49 | if (strncmp(e->d_name, "renderD", 7)) { | |
50 | continue; | |
51 | } | |
52 | ||
53 | r = asprintf(&p, "/dev/dri/%s", e->d_name); | |
54 | if (r < 0) { | |
55 | return -1; | |
56 | } | |
57 | ||
58 | r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); | |
59 | if (r < 0) { | |
60 | free(p); | |
61 | continue; | |
62 | } | |
63 | fd = r; | |
64 | free(p); | |
65 | break; | |
66 | } | |
67 | ||
68 | closedir(dir); | |
69 | if (fd < 0) { | |
70 | return -1; | |
71 | } | |
72 | return fd; | |
73 | } | |
74 | ||
75 | int egl_rendernode_init(void) | |
76 | { | |
77 | qemu_egl_rn_fd = -1; | |
78 | ||
79 | qemu_egl_rn_fd = qemu_egl_rendernode_open(); | |
80 | if (qemu_egl_rn_fd == -1) { | |
81 | fprintf(stderr, "egl: no drm render node available\n"); | |
82 | goto err; | |
83 | } | |
84 | ||
85 | qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd); | |
86 | if (!qemu_egl_rn_gbm_dev) { | |
87 | fprintf(stderr, "egl: gbm_create_device failed\n"); | |
88 | goto err; | |
89 | } | |
90 | ||
91 | qemu_egl_init_dpy((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, false, false); | |
92 | ||
93 | if (!epoxy_has_egl_extension(qemu_egl_display, | |
94 | "EGL_KHR_surfaceless_context")) { | |
95 | fprintf(stderr, "egl: EGL_KHR_surfaceless_context not supported\n"); | |
96 | goto err; | |
97 | } | |
98 | if (!epoxy_has_egl_extension(qemu_egl_display, | |
99 | "EGL_MESA_image_dma_buf_export")) { | |
100 | fprintf(stderr, "egl: EGL_MESA_image_dma_buf_export not supported\n"); | |
101 | goto err; | |
102 | } | |
103 | ||
104 | qemu_egl_rn_ctx = qemu_egl_init_ctx(); | |
105 | if (!qemu_egl_rn_ctx) { | |
106 | fprintf(stderr, "egl: egl_init_ctx failed\n"); | |
107 | goto err; | |
108 | } | |
109 | ||
110 | return 0; | |
111 | ||
112 | err: | |
113 | if (qemu_egl_rn_gbm_dev) { | |
114 | gbm_device_destroy(qemu_egl_rn_gbm_dev); | |
115 | } | |
116 | if (qemu_egl_rn_fd != -1) { | |
117 | close(qemu_egl_rn_fd); | |
118 | } | |
119 | ||
120 | return -1; | |
121 | } | |
122 | ||
123 | int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc) | |
124 | { | |
125 | EGLImageKHR image; | |
126 | EGLint num_planes, fd; | |
127 | ||
128 | image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), | |
129 | EGL_GL_TEXTURE_2D_KHR, | |
130 | (EGLClientBuffer)(unsigned long)tex_id, | |
131 | NULL); | |
132 | if (!image) { | |
133 | return -1; | |
134 | } | |
135 | ||
136 | eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, | |
137 | &num_planes, NULL); | |
138 | if (num_planes != 1) { | |
139 | eglDestroyImageKHR(qemu_egl_display, image); | |
140 | return -1; | |
141 | } | |
142 | eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); | |
143 | eglDestroyImageKHR(qemu_egl_display, image); | |
144 | ||
145 | return fd; | |
146 | } | |
147 | ||
148 | #endif /* CONFIG_OPENGL_DMABUF */ | |
149 | ||
150 | /* ---------------------------------------------------------------------- */ | |
151 | ||
7ced9e9f GH |
152 | EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win) |
153 | { | |
154 | EGLSurface esurface; | |
155 | EGLBoolean b; | |
156 | ||
157 | egl_dbg("eglCreateWindowSurface (x11 win id 0x%lx) ...\n", | |
158 | (unsigned long) win); | |
159 | esurface = eglCreateWindowSurface(qemu_egl_display, | |
160 | qemu_egl_config, | |
161 | (EGLNativeWindowType)win, NULL); | |
162 | if (esurface == EGL_NO_SURFACE) { | |
163 | fprintf(stderr, "egl: eglCreateWindowSurface failed\n"); | |
164 | return NULL; | |
165 | } | |
166 | ||
167 | b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx); | |
168 | if (b == EGL_FALSE) { | |
169 | fprintf(stderr, "egl: eglMakeCurrent failed\n"); | |
170 | return NULL; | |
171 | } | |
172 | ||
173 | return esurface; | |
174 | } | |
175 | ||
176 | /* ---------------------------------------------------------------------- */ | |
177 | ||
178 | int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug) | |
179 | { | |
180 | static const EGLint conf_att_gl[] = { | |
181 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | |
182 | EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, | |
183 | EGL_RED_SIZE, 5, | |
184 | EGL_GREEN_SIZE, 5, | |
185 | EGL_BLUE_SIZE, 5, | |
186 | EGL_ALPHA_SIZE, 0, | |
187 | EGL_NONE, | |
188 | }; | |
189 | static const EGLint conf_att_gles[] = { | |
190 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | |
191 | EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | |
192 | EGL_RED_SIZE, 5, | |
193 | EGL_GREEN_SIZE, 5, | |
194 | EGL_BLUE_SIZE, 5, | |
195 | EGL_ALPHA_SIZE, 0, | |
196 | EGL_NONE, | |
197 | }; | |
198 | EGLint major, minor; | |
199 | EGLBoolean b; | |
200 | EGLint n; | |
201 | ||
202 | if (debug) { | |
203 | egl_debug = 1; | |
204 | setenv("EGL_LOG_LEVEL", "debug", true); | |
205 | setenv("LIBGL_DEBUG", "verbose", true); | |
206 | } | |
207 | ||
208 | egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy); | |
209 | qemu_egl_display = eglGetDisplay(dpy); | |
210 | if (qemu_egl_display == EGL_NO_DISPLAY) { | |
211 | fprintf(stderr, "egl: eglGetDisplay failed\n"); | |
212 | return -1; | |
213 | } | |
214 | ||
215 | egl_dbg("eglInitialize ...\n"); | |
216 | b = eglInitialize(qemu_egl_display, &major, &minor); | |
217 | if (b == EGL_FALSE) { | |
218 | fprintf(stderr, "egl: eglInitialize failed\n"); | |
219 | return -1; | |
220 | } | |
221 | ||
222 | egl_dbg("eglBindAPI ...\n"); | |
223 | b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); | |
224 | if (b == EGL_FALSE) { | |
225 | fprintf(stderr, "egl: eglBindAPI failed\n"); | |
226 | return -1; | |
227 | } | |
228 | ||
229 | egl_dbg("eglChooseConfig ...\n"); | |
230 | b = eglChooseConfig(qemu_egl_display, | |
231 | gles ? conf_att_gles : conf_att_gl, | |
232 | &qemu_egl_config, 1, &n); | |
233 | if (b == EGL_FALSE || n != 1) { | |
234 | fprintf(stderr, "egl: eglChooseConfig failed\n"); | |
235 | return -1; | |
236 | } | |
237 | ||
238 | egl_gles = gles; | |
239 | return 0; | |
240 | } | |
241 | ||
242 | EGLContext qemu_egl_init_ctx(void) | |
243 | { | |
244 | static const EGLint ctx_att_gl[] = { | |
245 | EGL_NONE | |
246 | }; | |
247 | static const EGLint ctx_att_gles[] = { | |
248 | EGL_CONTEXT_CLIENT_VERSION, 2, | |
249 | EGL_NONE | |
250 | }; | |
251 | ||
252 | EGLContext ectx; | |
253 | EGLBoolean b; | |
254 | ||
255 | egl_dbg("eglCreateContext ...\n"); | |
256 | ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT, | |
257 | egl_gles ? ctx_att_gles : ctx_att_gl); | |
258 | if (ectx == EGL_NO_CONTEXT) { | |
259 | fprintf(stderr, "egl: eglCreateContext failed\n"); | |
260 | return NULL; | |
261 | } | |
262 | ||
263 | b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx); | |
264 | if (b == EGL_FALSE) { | |
265 | fprintf(stderr, "egl: eglMakeCurrent failed\n"); | |
266 | return NULL; | |
267 | } | |
268 | ||
269 | return ectx; | |
270 | } |