1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "qemu/osdep.h"
18#include <glob.h>
19#include <dirent.h>
20
21#include "qemu/error-report.h"
22#include "ui/egl-helpers.h"
23
24EGLDisplay *qemu_egl_display;
25EGLConfig qemu_egl_config;
26
27
28
29void egl_fb_destroy(egl_fb *fb)
30{
31 if (!fb->framebuffer) {
32 return;
33 }
34
35 if (fb->delete_texture) {
36 glDeleteTextures(1, &fb->texture);
37 fb->delete_texture = false;
38 }
39 glDeleteFramebuffers(1, &fb->framebuffer);
40
41 fb->width = 0;
42 fb->height = 0;
43 fb->texture = 0;
44 fb->framebuffer = 0;
45}
46
47void egl_fb_setup_default(egl_fb *fb, int width, int height)
48{
49 fb->width = width;
50 fb->height = height;
51 fb->framebuffer = 0;
52}
53
54void egl_fb_create_for_tex(egl_fb *fb, int width, int height, GLuint texture)
55{
56 fb->width = width;
57 fb->height = height;
58 fb->texture = texture;
59 if (!fb->framebuffer) {
60 glGenFramebuffers(1, &fb->framebuffer);
61 }
62
63 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb->framebuffer);
64 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
65 GL_TEXTURE_2D, fb->texture, 0);
66}
67
68void egl_fb_create_new_tex(egl_fb *fb, int width, int height)
69{
70 GLuint texture;
71
72 glGenTextures(1, &texture);
73 glBindTexture(GL_TEXTURE_2D, texture);
74 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
75 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
76
77 egl_fb_create_for_tex(fb, width, height, texture);
78 fb->delete_texture = true;
79}
80
81void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip)
82{
83 GLuint y1, y2;
84
85 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
86 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer);
87 glViewport(0, 0, dst->width, dst->height);
88 y1 = flip ? src->height : 0;
89 y2 = flip ? 0 : src->height;
90 glBlitFramebuffer(0, y1, src->width, y2,
91 0, 0, dst->width, dst->height,
92 GL_COLOR_BUFFER_BIT, GL_LINEAR);
93}
94
95void egl_fb_read(void *dst, egl_fb *src)
96{
97 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
98 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
99 glReadPixels(0, 0, src->width, src->height,
100 GL_BGRA, GL_UNSIGNED_BYTE, dst);
101}
102
103
104
105#ifdef CONFIG_OPENGL_DMABUF
106
107int qemu_egl_rn_fd;
108struct gbm_device *qemu_egl_rn_gbm_dev;
109EGLContext qemu_egl_rn_ctx;
110
111static int qemu_egl_rendernode_open(const char *rendernode)
112{
113 DIR *dir;
114 struct dirent *e;
115 int r, fd;
116 char *p;
117
118 if (rendernode) {
119 return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
120 }
121
122 dir = opendir("/dev/dri");
123 if (!dir) {
124 return -1;
125 }
126
127 fd = -1;
128 while ((e = readdir(dir))) {
129 if (e->d_type != DT_CHR) {
130 continue;
131 }
132
133 if (strncmp(e->d_name, "renderD", 7)) {
134 continue;
135 }
136
137 p = g_strdup_printf("/dev/dri/%s", e->d_name);
138
139 r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
140 if (r < 0) {
141 g_free(p);
142 continue;
143 }
144 fd = r;
145 g_free(p);
146 break;
147 }
148
149 closedir(dir);
150 if (fd < 0) {
151 return -1;
152 }
153 return fd;
154}
155
156int egl_rendernode_init(const char *rendernode)
157{
158 qemu_egl_rn_fd = -1;
159 int rc;
160
161 qemu_egl_rn_fd = qemu_egl_rendernode_open(rendernode);
162 if (qemu_egl_rn_fd == -1) {
163 error_report("egl: no drm render node available");
164 goto err;
165 }
166
167 qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd);
168 if (!qemu_egl_rn_gbm_dev) {
169 error_report("egl: gbm_create_device failed");
170 goto err;
171 }
172
173 rc = qemu_egl_init_dpy_mesa((EGLNativeDisplayType)qemu_egl_rn_gbm_dev);
174 if (rc != 0) {
175
176 goto err;
177 }
178
179 if (!epoxy_has_egl_extension(qemu_egl_display,
180 "EGL_KHR_surfaceless_context")) {
181 error_report("egl: EGL_KHR_surfaceless_context not supported");
182 goto err;
183 }
184 if (!epoxy_has_egl_extension(qemu_egl_display,
185 "EGL_MESA_image_dma_buf_export")) {
186 error_report("egl: EGL_MESA_image_dma_buf_export not supported");
187 goto err;
188 }
189
190 qemu_egl_rn_ctx = qemu_egl_init_ctx();
191 if (!qemu_egl_rn_ctx) {
192 error_report("egl: egl_init_ctx failed");
193 goto err;
194 }
195
196 return 0;
197
198err:
199 if (qemu_egl_rn_gbm_dev) {
200 gbm_device_destroy(qemu_egl_rn_gbm_dev);
201 }
202 if (qemu_egl_rn_fd != -1) {
203 close(qemu_egl_rn_fd);
204 }
205
206 return -1;
207}
208
209int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc)
210{
211 EGLImageKHR image;
212 EGLint num_planes, fd;
213
214 image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
215 EGL_GL_TEXTURE_2D_KHR,
216 (EGLClientBuffer)(unsigned long)tex_id,
217 NULL);
218 if (!image) {
219 return -1;
220 }
221
222 eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc,
223 &num_planes, NULL);
224 if (num_planes != 1) {
225 eglDestroyImageKHR(qemu_egl_display, image);
226 return -1;
227 }
228 eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL);
229 eglDestroyImageKHR(qemu_egl_display, image);
230
231 return fd;
232}
233
234#endif
235
236
237
238EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
239{
240 EGLSurface esurface;
241 EGLBoolean b;
242
243 esurface = eglCreateWindowSurface(qemu_egl_display,
244 qemu_egl_config,
245 (EGLNativeWindowType)win, NULL);
246 if (esurface == EGL_NO_SURFACE) {
247 error_report("egl: eglCreateWindowSurface failed");
248 return NULL;
249 }
250
251 b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
252 if (b == EGL_FALSE) {
253 error_report("egl: eglMakeCurrent failed");
254 return NULL;
255 }
256
257 return esurface;
258}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native,
291 EGLenum platform)
292{
293 EGLDisplay dpy = EGL_NO_DISPLAY;
294
295
296 if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
297 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
298 (void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
299 if (getPlatformDisplayEXT && platform != 0) {
300 dpy = getPlatformDisplayEXT(platform, native, NULL);
301 }
302 }
303
304 if (dpy == EGL_NO_DISPLAY) {
305
306 dpy = eglGetDisplay(native);
307 }
308 return dpy;
309}
310
311static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
312 EGLenum platform)
313{
314 static const EGLint conf_att_gl[] = {
315 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
316 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
317 EGL_RED_SIZE, 5,
318 EGL_GREEN_SIZE, 5,
319 EGL_BLUE_SIZE, 5,
320 EGL_ALPHA_SIZE, 0,
321 EGL_NONE,
322 };
323 EGLint major, minor;
324 EGLBoolean b;
325 EGLint n;
326
327 qemu_egl_display = qemu_egl_get_display(dpy, platform);
328 if (qemu_egl_display == EGL_NO_DISPLAY) {
329 error_report("egl: eglGetDisplay failed");
330 return -1;
331 }
332
333 b = eglInitialize(qemu_egl_display, &major, &minor);
334 if (b == EGL_FALSE) {
335 error_report("egl: eglInitialize failed");
336 return -1;
337 }
338
339 b = eglBindAPI(EGL_OPENGL_API);
340 if (b == EGL_FALSE) {
341 error_report("egl: eglBindAPI failed");
342 return -1;
343 }
344
345 b = eglChooseConfig(qemu_egl_display, conf_att_gl,
346 &qemu_egl_config, 1, &n);
347 if (b == EGL_FALSE || n != 1) {
348 error_report("egl: eglChooseConfig failed");
349 return -1;
350 }
351 return 0;
352}
353
354int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy)
355{
356#ifdef EGL_KHR_platform_x11
357 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_X11_KHR);
358#else
359 return qemu_egl_init_dpy(dpy, 0);
360#endif
361}
362
363int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy)
364{
365#ifdef EGL_MESA_platform_gbm
366 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_GBM_MESA);
367#else
368 return qemu_egl_init_dpy(dpy, 0);
369#endif
370}
371
372EGLContext qemu_egl_init_ctx(void)
373{
374 static const EGLint ctx_att_gl[] = {
375 EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
376 EGL_NONE
377 };
378 EGLContext ectx;
379 EGLBoolean b;
380
381 ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
382 ctx_att_gl);
383 if (ectx == EGL_NO_CONTEXT) {
384 error_report("egl: eglCreateContext failed");
385 return NULL;
386 }
387
388 b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx);
389 if (b == EGL_FALSE) {
390 error_report("egl: eglMakeCurrent failed");
391 return NULL;
392 }
393
394 return ectx;
395}
396