1 /* 2 * Copyright (C) 2015-2016 Gerd Hoffmann <kraxel@redhat.com> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 #include "qemu/osdep.h" 18 #include <glob.h> 19 #include <dirent.h> 20 21 #include "qemu/error-report.h" 22 #include "ui/console.h" 23 #include "ui/egl-helpers.h" 24 25 EGLDisplay *qemu_egl_display; 26 EGLConfig qemu_egl_config; 27 DisplayGLMode qemu_egl_mode; 28 29 /* ------------------------------------------------------------------ */ 30 31 static void egl_fb_delete_texture(egl_fb *fb) 32 { 33 if (!fb->delete_texture) { 34 return; 35 } 36 37 glDeleteTextures(1, &fb->texture); 38 fb->delete_texture = false; 39 } 40 41 void egl_fb_destroy(egl_fb *fb) 42 { 43 if (!fb->framebuffer) { 44 return; 45 } 46 47 egl_fb_delete_texture(fb); 48 glDeleteFramebuffers(1, &fb->framebuffer); 49 50 fb->width = 0; 51 fb->height = 0; 52 fb->texture = 0; 53 fb->framebuffer = 0; 54 } 55 56 void egl_fb_setup_default(egl_fb *fb, int width, int height) 57 { 58 fb->width = width; 59 fb->height = height; 60 fb->framebuffer = 0; /* default framebuffer */ 61 } 62 63 void egl_fb_setup_for_tex(egl_fb *fb, int width, int height, 64 GLuint texture, bool delete) 65 { 66 egl_fb_delete_texture(fb); 67 68 fb->width = width; 69 fb->height = height; 70 fb->texture = texture; 71 fb->delete_texture = delete; 72 if (!fb->framebuffer) { 73 glGenFramebuffers(1, &fb->framebuffer); 74 } 75 76 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb->framebuffer); 77 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 78 GL_TEXTURE_2D, fb->texture, 0); 79 } 80 81 void egl_fb_setup_new_tex(egl_fb *fb, int width, int height) 82 { 83 GLuint texture; 84 85 glGenTextures(1, &texture); 86 glBindTexture(GL_TEXTURE_2D, texture); 87 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 88 0, GL_BGRA, GL_UNSIGNED_BYTE, 0); 89 90 egl_fb_setup_for_tex(fb, width, height, texture, true); 91 } 92 93 void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) 94 { 95 GLuint y1, y2; 96 97 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); 98 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer); 99 glViewport(0, 0, dst->width, dst->height); 100 y1 = flip ? src->height : 0; 101 y2 = flip ? 0 : src->height; 102 glBlitFramebuffer(0, y1, src->width, y2, 103 0, 0, dst->width, dst->height, 104 GL_COLOR_BUFFER_BIT, GL_LINEAR); 105 } 106 107 void egl_fb_read(void *dst, egl_fb *src) 108 { 109 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); 110 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); 111 glReadPixels(0, 0, src->width, src->height, 112 GL_BGRA, GL_UNSIGNED_BYTE, dst); 113 } 114 115 void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip) 116 { 117 glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer); 118 glViewport(0, 0, dst->width, dst->height); 119 glEnable(GL_TEXTURE_2D); 120 glBindTexture(GL_TEXTURE_2D, src->texture); 121 qemu_gl_run_texture_blit(gls, flip); 122 } 123 124 void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip, 125 int x, int y) 126 { 127 glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer); 128 if (flip) { 129 glViewport(x, y, src->width, src->height); 130 } else { 131 glViewport(x, dst->height - src->height - y, 132 src->width, src->height); 133 } 134 glEnable(GL_TEXTURE_2D); 135 glBindTexture(GL_TEXTURE_2D, src->texture); 136 glEnable(GL_BLEND); 137 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 138 qemu_gl_run_texture_blit(gls, flip); 139 glDisable(GL_BLEND); 140 } 141 142 /* ---------------------------------------------------------------------- */ 143 144 #ifdef CONFIG_OPENGL_DMABUF 145 146 int qemu_egl_rn_fd; 147 struct gbm_device *qemu_egl_rn_gbm_dev; 148 EGLContext qemu_egl_rn_ctx; 149 150 static int qemu_egl_rendernode_open(const char *rendernode) 151 { 152 DIR *dir; 153 struct dirent *e; 154 int r, fd; 155 char *p; 156 157 if (rendernode) { 158 return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 159 } 160 161 dir = opendir("/dev/dri"); 162 if (!dir) { 163 return -1; 164 } 165 166 fd = -1; 167 while ((e = readdir(dir))) { 168 if (e->d_type != DT_CHR) { 169 continue; 170 } 171 172 if (strncmp(e->d_name, "renderD", 7)) { 173 continue; 174 } 175 176 p = g_strdup_printf("/dev/dri/%s", e->d_name); 177 178 r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); 179 if (r < 0) { 180 g_free(p); 181 continue; 182 } 183 fd = r; 184 g_free(p); 185 break; 186 } 187 188 closedir(dir); 189 if (fd < 0) { 190 return -1; 191 } 192 return fd; 193 } 194 195 int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) 196 { 197 qemu_egl_rn_fd = -1; 198 int rc; 199 200 qemu_egl_rn_fd = qemu_egl_rendernode_open(rendernode); 201 if (qemu_egl_rn_fd == -1) { 202 error_report("egl: no drm render node available"); 203 goto err; 204 } 205 206 qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd); 207 if (!qemu_egl_rn_gbm_dev) { 208 error_report("egl: gbm_create_device failed"); 209 goto err; 210 } 211 212 rc = qemu_egl_init_dpy_mesa((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, 213 mode); 214 if (rc != 0) { 215 /* qemu_egl_init_dpy_mesa reports error */ 216 goto err; 217 } 218 219 if (!epoxy_has_egl_extension(qemu_egl_display, 220 "EGL_KHR_surfaceless_context")) { 221 error_report("egl: EGL_KHR_surfaceless_context not supported"); 222 goto err; 223 } 224 if (!epoxy_has_egl_extension(qemu_egl_display, 225 "EGL_MESA_image_dma_buf_export")) { 226 error_report("egl: EGL_MESA_image_dma_buf_export not supported"); 227 goto err; 228 } 229 230 qemu_egl_rn_ctx = qemu_egl_init_ctx(); 231 if (!qemu_egl_rn_ctx) { 232 error_report("egl: egl_init_ctx failed"); 233 goto err; 234 } 235 236 return 0; 237 238 err: 239 if (qemu_egl_rn_gbm_dev) { 240 gbm_device_destroy(qemu_egl_rn_gbm_dev); 241 } 242 if (qemu_egl_rn_fd != -1) { 243 close(qemu_egl_rn_fd); 244 } 245 246 return -1; 247 } 248 249 int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc) 250 { 251 EGLImageKHR image; 252 EGLint num_planes, fd; 253 254 image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), 255 EGL_GL_TEXTURE_2D_KHR, 256 (EGLClientBuffer)(unsigned long)tex_id, 257 NULL); 258 if (!image) { 259 return -1; 260 } 261 262 eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, 263 &num_planes, NULL); 264 if (num_planes != 1) { 265 eglDestroyImageKHR(qemu_egl_display, image); 266 return -1; 267 } 268 eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); 269 eglDestroyImageKHR(qemu_egl_display, image); 270 271 return fd; 272 } 273 274 void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) 275 { 276 EGLImageKHR image = EGL_NO_IMAGE_KHR; 277 EGLint attrs[] = { 278 EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf->fd, 279 EGL_DMA_BUF_PLANE0_PITCH_EXT, dmabuf->stride, 280 EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, 281 EGL_WIDTH, dmabuf->width, 282 EGL_HEIGHT, dmabuf->height, 283 EGL_LINUX_DRM_FOURCC_EXT, dmabuf->fourcc, 284 EGL_NONE, /* end of list */ 285 }; 286 287 if (dmabuf->texture != 0) { 288 return; 289 } 290 291 image = eglCreateImageKHR(qemu_egl_display, 292 EGL_NO_CONTEXT, 293 EGL_LINUX_DMA_BUF_EXT, 294 NULL, attrs); 295 if (image == EGL_NO_IMAGE_KHR) { 296 error_report("eglCreateImageKHR failed"); 297 return; 298 } 299 300 glGenTextures(1, &dmabuf->texture); 301 glBindTexture(GL_TEXTURE_2D, dmabuf->texture); 302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 303 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 304 305 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); 306 eglDestroyImageKHR(qemu_egl_display, image); 307 } 308 309 void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf) 310 { 311 if (dmabuf->texture == 0) { 312 return; 313 } 314 315 glDeleteTextures(1, &dmabuf->texture); 316 dmabuf->texture = 0; 317 } 318 319 #endif /* CONFIG_OPENGL_DMABUF */ 320 321 /* ---------------------------------------------------------------------- */ 322 323 EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win) 324 { 325 EGLSurface esurface; 326 EGLBoolean b; 327 328 esurface = eglCreateWindowSurface(qemu_egl_display, 329 qemu_egl_config, 330 (EGLNativeWindowType)win, NULL); 331 if (esurface == EGL_NO_SURFACE) { 332 error_report("egl: eglCreateWindowSurface failed"); 333 return NULL; 334 } 335 336 b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx); 337 if (b == EGL_FALSE) { 338 error_report("egl: eglMakeCurrent failed"); 339 return NULL; 340 } 341 342 return esurface; 343 } 344 345 /* ---------------------------------------------------------------------- */ 346 347 /* 348 * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed 349 * 350 * Create an EGLDisplay from a native display type. This is a little quirky 351 * for a few reasons. 352 * 353 * 1: GetPlatformDisplayEXT and GetPlatformDisplay are the API you want to 354 * use, but have different function signatures in the third argument; this 355 * happens not to matter for us, at the moment, but it means epoxy won't alias 356 * them together. 357 * 358 * 2: epoxy 1.3 and earlier don't understand EGL client extensions, which 359 * means you can't call "eglGetPlatformDisplayEXT" directly, as the resolver 360 * will crash. 361 * 362 * 3: You can't tell whether you have EGL 1.5 at this point, because 363 * eglQueryString(EGL_VERSION) is a property of the display, which we don't 364 * have yet. So you have to query for extensions no matter what. Fortunately 365 * epoxy_has_egl_extension _does_ let you query for client extensions, so 366 * we don't have to write our own extension string parsing. 367 * 368 * 4. There is no EGL_KHR_platform_base to complement the EXT one, thus one 369 * needs to know EGL 1.5 is supported in order to use the eglGetPlatformDisplay 370 * function pointer. 371 * We can workaround this (circular dependency) by probing for the EGL 1.5 372 * platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem 373 * like mesa will be able to advertise these (even though it can do EGL 1.5). 374 */ 375 static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native, 376 EGLenum platform) 377 { 378 EGLDisplay dpy = EGL_NO_DISPLAY; 379 380 /* In practise any EGL 1.5 implementation would support the EXT extension */ 381 if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) { 382 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT = 383 (void *) eglGetProcAddress("eglGetPlatformDisplayEXT"); 384 if (getPlatformDisplayEXT && platform != 0) { 385 dpy = getPlatformDisplayEXT(platform, native, NULL); 386 } 387 } 388 389 if (dpy == EGL_NO_DISPLAY) { 390 /* fallback */ 391 dpy = eglGetDisplay(native); 392 } 393 return dpy; 394 } 395 396 static int qemu_egl_init_dpy(EGLNativeDisplayType dpy, 397 EGLenum platform, 398 DisplayGLMode mode) 399 { 400 static const EGLint conf_att_core[] = { 401 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 402 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 403 EGL_RED_SIZE, 5, 404 EGL_GREEN_SIZE, 5, 405 EGL_BLUE_SIZE, 5, 406 EGL_ALPHA_SIZE, 0, 407 EGL_NONE, 408 }; 409 static const EGLint conf_att_gles[] = { 410 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 411 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 412 EGL_RED_SIZE, 5, 413 EGL_GREEN_SIZE, 5, 414 EGL_BLUE_SIZE, 5, 415 EGL_ALPHA_SIZE, 0, 416 EGL_NONE, 417 }; 418 EGLint major, minor; 419 EGLBoolean b; 420 EGLint n; 421 bool gles = (mode == DISPLAYGL_MODE_ES); 422 423 qemu_egl_display = qemu_egl_get_display(dpy, platform); 424 if (qemu_egl_display == EGL_NO_DISPLAY) { 425 error_report("egl: eglGetDisplay failed"); 426 return -1; 427 } 428 429 b = eglInitialize(qemu_egl_display, &major, &minor); 430 if (b == EGL_FALSE) { 431 error_report("egl: eglInitialize failed"); 432 return -1; 433 } 434 435 b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); 436 if (b == EGL_FALSE) { 437 error_report("egl: eglBindAPI failed (%s mode)", 438 gles ? "gles" : "core"); 439 return -1; 440 } 441 442 b = eglChooseConfig(qemu_egl_display, 443 gles ? conf_att_gles : conf_att_core, 444 &qemu_egl_config, 1, &n); 445 if (b == EGL_FALSE || n != 1) { 446 error_report("egl: eglChooseConfig failed (%s mode)", 447 gles ? "gles" : "core"); 448 return -1; 449 } 450 451 qemu_egl_mode = gles ? DISPLAYGL_MODE_ES : DISPLAYGL_MODE_CORE; 452 return 0; 453 } 454 455 int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode) 456 { 457 #ifdef EGL_KHR_platform_x11 458 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_X11_KHR, mode); 459 #else 460 return qemu_egl_init_dpy(dpy, 0, mode); 461 #endif 462 } 463 464 int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode) 465 { 466 #ifdef EGL_MESA_platform_gbm 467 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_GBM_MESA, mode); 468 #else 469 return qemu_egl_init_dpy(dpy, 0, mode); 470 #endif 471 } 472 473 EGLContext qemu_egl_init_ctx(void) 474 { 475 static const EGLint ctx_att_core[] = { 476 EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, 477 EGL_NONE 478 }; 479 static const EGLint ctx_att_gles[] = { 480 EGL_CONTEXT_CLIENT_VERSION, 2, 481 EGL_NONE 482 }; 483 bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES); 484 EGLContext ectx; 485 EGLBoolean b; 486 487 ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT, 488 gles ? ctx_att_gles : ctx_att_core); 489 if (ectx == EGL_NO_CONTEXT) { 490 error_report("egl: eglCreateContext failed"); 491 return NULL; 492 } 493 494 b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx); 495 if (b == EGL_FALSE) { 496 error_report("egl: eglMakeCurrent failed"); 497 return NULL; 498 } 499 500 return ectx; 501 } 502