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