1 #include "qemu/osdep.h" 2 #include <glob.h> 3 #include <dirent.h> 4 5 #include "qemu/error-report.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 p = g_strdup_printf("/dev/dri/%s", e->d_name); 54 55 r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 56 if (r < 0) { 57 g_free(p); 58 continue; 59 } 60 fd = r; 61 g_free(p); 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) { 78 error_report("egl: no drm render node available"); 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) { 84 error_report("egl: gbm_create_device failed"); 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")) { 92 error_report("egl: EGL_KHR_surfaceless_context not supported"); 93 goto err; 94 } 95 if (!epoxy_has_egl_extension(qemu_egl_display, 96 "EGL_MESA_image_dma_buf_export")) { 97 error_report("egl: EGL_MESA_image_dma_buf_export not supported"); 98 goto err; 99 } 100 101 qemu_egl_rn_ctx = qemu_egl_init_ctx(); 102 if (!qemu_egl_rn_ctx) { 103 error_report("egl: egl_init_ctx failed"); 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 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) { 160 error_report("egl: eglCreateWindowSurface failed"); 161 return NULL; 162 } 163 164 b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx); 165 if (b == EGL_FALSE) { 166 error_report("egl: eglMakeCurrent failed"); 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) { 208 error_report("egl: eglGetDisplay failed"); 209 return -1; 210 } 211 212 egl_dbg("eglInitialize ...\n"); 213 b = eglInitialize(qemu_egl_display, &major, &minor); 214 if (b == EGL_FALSE) { 215 error_report("egl: eglInitialize failed"); 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) { 222 error_report("egl: eglBindAPI failed"); 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) { 231 error_report("egl: eglChooseConfig failed"); 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) { 256 error_report("egl: eglCreateContext failed"); 257 return NULL; 258 } 259 260 b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx); 261 if (b == EGL_FALSE) { 262 error_report("egl: eglMakeCurrent failed"); 263 return NULL; 264 } 265 266 return ectx; 267 } 268