1 #include "qemu/osdep.h" 2 #include <glob.h> 3 #include <dirent.h> 4 5 #include "config-host.h" 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 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 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 } 271