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