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