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 "qemu/drm.h" 19 #include "qemu/error-report.h" 20 #include "ui/console.h" 21 #include "ui/egl-helpers.h" 22 #include "sysemu/sysemu.h" 23 #include "qapi/error.h" 24 25 EGLDisplay *qemu_egl_display; 26 EGLConfig qemu_egl_config; 27 DisplayGLMode qemu_egl_mode; 28 29 /* ------------------------------------------------------------------ */ 30 31 const char *qemu_egl_get_error_string(void) 32 { 33 EGLint error = eglGetError(); 34 35 switch (error) { 36 case EGL_SUCCESS: 37 return "EGL_SUCCESS"; 38 case EGL_NOT_INITIALIZED: 39 return "EGL_NOT_INITIALIZED"; 40 case EGL_BAD_ACCESS: 41 return "EGL_BAD_ACCESS"; 42 case EGL_BAD_ALLOC: 43 return "EGL_BAD_ALLOC"; 44 case EGL_BAD_ATTRIBUTE: 45 return "EGL_BAD_ATTRIBUTE"; 46 case EGL_BAD_CONTEXT: 47 return "EGL_BAD_CONTEXT"; 48 case EGL_BAD_CONFIG: 49 return "EGL_BAD_CONFIG"; 50 case EGL_BAD_CURRENT_SURFACE: 51 return "EGL_BAD_CURRENT_SURFACE"; 52 case EGL_BAD_DISPLAY: 53 return "EGL_BAD_DISPLAY"; 54 case EGL_BAD_SURFACE: 55 return "EGL_BAD_SURFACE"; 56 case EGL_BAD_MATCH: 57 return "EGL_BAD_MATCH"; 58 case EGL_BAD_PARAMETER: 59 return "EGL_BAD_PARAMETER"; 60 case EGL_BAD_NATIVE_PIXMAP: 61 return "EGL_BAD_NATIVE_PIXMAP"; 62 case EGL_BAD_NATIVE_WINDOW: 63 return "EGL_BAD_NATIVE_WINDOW"; 64 case EGL_CONTEXT_LOST: 65 return "EGL_CONTEXT_LOST"; 66 default: 67 return "Unknown EGL error"; 68 } 69 } 70 71 static void egl_fb_delete_texture(egl_fb *fb) 72 { 73 if (!fb->delete_texture) { 74 return; 75 } 76 77 glDeleteTextures(1, &fb->texture); 78 fb->delete_texture = false; 79 } 80 81 void egl_fb_destroy(egl_fb *fb) 82 { 83 if (!fb->framebuffer) { 84 return; 85 } 86 87 egl_fb_delete_texture(fb); 88 glDeleteFramebuffers(1, &fb->framebuffer); 89 90 fb->width = 0; 91 fb->height = 0; 92 fb->texture = 0; 93 fb->framebuffer = 0; 94 } 95 96 void egl_fb_setup_default(egl_fb *fb, int width, int height) 97 { 98 fb->width = width; 99 fb->height = height; 100 fb->framebuffer = 0; /* default framebuffer */ 101 } 102 103 void egl_fb_setup_for_tex(egl_fb *fb, int width, int height, 104 GLuint texture, bool delete) 105 { 106 egl_fb_delete_texture(fb); 107 108 fb->width = width; 109 fb->height = height; 110 fb->texture = texture; 111 fb->delete_texture = delete; 112 if (!fb->framebuffer) { 113 glGenFramebuffers(1, &fb->framebuffer); 114 } 115 116 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb->framebuffer); 117 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 118 GL_TEXTURE_2D, fb->texture, 0); 119 } 120 121 void egl_fb_setup_new_tex(egl_fb *fb, int width, int height) 122 { 123 GLuint texture; 124 125 glGenTextures(1, &texture); 126 glBindTexture(GL_TEXTURE_2D, texture); 127 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 128 0, GL_BGRA, GL_UNSIGNED_BYTE, 0); 129 130 egl_fb_setup_for_tex(fb, width, height, texture, true); 131 } 132 133 void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) 134 { 135 GLuint x1 = 0; 136 GLuint y1 = 0; 137 GLuint x2, y2; 138 GLuint w = src->width; 139 GLuint h = src->height; 140 141 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); 142 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer); 143 glViewport(0, 0, dst->width, dst->height); 144 145 if (src->dmabuf) { 146 x1 = src->dmabuf->x; 147 y1 = src->dmabuf->y; 148 w = src->dmabuf->scanout_width; 149 h = src->dmabuf->scanout_height; 150 } 151 152 w = (x1 + w) > src->width ? src->width - x1 : w; 153 h = (y1 + h) > src->height ? src->height - y1 : h; 154 155 y2 = flip ? y1 : h + y1; 156 y1 = flip ? h + y1 : y1; 157 x2 = x1 + w; 158 159 glBlitFramebuffer(x1, y1, x2, y2, 160 0, 0, dst->width, dst->height, 161 GL_COLOR_BUFFER_BIT, GL_LINEAR); 162 } 163 164 void egl_fb_read(DisplaySurface *dst, egl_fb *src) 165 { 166 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); 167 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); 168 glReadPixels(0, 0, surface_width(dst), surface_height(dst), 169 GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst)); 170 } 171 172 void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip) 173 { 174 glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer); 175 glViewport(0, 0, dst->width, dst->height); 176 glEnable(GL_TEXTURE_2D); 177 glBindTexture(GL_TEXTURE_2D, src->texture); 178 qemu_gl_run_texture_blit(gls, flip); 179 } 180 181 void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip, 182 int x, int y, double scale_x, double scale_y) 183 { 184 glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer); 185 int w = scale_x * src->width; 186 int h = scale_y * src->height; 187 if (flip) { 188 glViewport(x, y, w, h); 189 } else { 190 glViewport(x, dst->height - h - y, w, h); 191 } 192 glEnable(GL_TEXTURE_2D); 193 glBindTexture(GL_TEXTURE_2D, src->texture); 194 glEnable(GL_BLEND); 195 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 196 qemu_gl_run_texture_blit(gls, flip); 197 glDisable(GL_BLEND); 198 } 199 200 /* ---------------------------------------------------------------------- */ 201 202 EGLContext qemu_egl_rn_ctx; 203 204 #ifdef CONFIG_GBM 205 206 int qemu_egl_rn_fd; 207 struct gbm_device *qemu_egl_rn_gbm_dev; 208 209 int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) 210 { 211 qemu_egl_rn_fd = -1; 212 int rc; 213 214 qemu_egl_rn_fd = qemu_drm_rendernode_open(rendernode); 215 if (qemu_egl_rn_fd == -1) { 216 error_report("egl: no drm render node available"); 217 goto err; 218 } 219 220 qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd); 221 if (!qemu_egl_rn_gbm_dev) { 222 error_report("egl: gbm_create_device failed"); 223 goto err; 224 } 225 226 rc = qemu_egl_init_dpy_mesa((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, 227 mode); 228 if (rc != 0) { 229 /* qemu_egl_init_dpy_mesa reports error */ 230 goto err; 231 } 232 233 if (!epoxy_has_egl_extension(qemu_egl_display, 234 "EGL_KHR_surfaceless_context")) { 235 error_report("egl: EGL_KHR_surfaceless_context not supported"); 236 goto err; 237 } 238 if (!epoxy_has_egl_extension(qemu_egl_display, 239 "EGL_MESA_image_dma_buf_export")) { 240 error_report("egl: EGL_MESA_image_dma_buf_export not supported"); 241 goto err; 242 } 243 244 qemu_egl_rn_ctx = qemu_egl_init_ctx(); 245 if (!qemu_egl_rn_ctx) { 246 error_report("egl: egl_init_ctx failed"); 247 goto err; 248 } 249 250 return 0; 251 252 err: 253 if (qemu_egl_rn_gbm_dev) { 254 gbm_device_destroy(qemu_egl_rn_gbm_dev); 255 } 256 if (qemu_egl_rn_fd != -1) { 257 close(qemu_egl_rn_fd); 258 } 259 260 return -1; 261 } 262 263 int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc, 264 EGLuint64KHR *modifier) 265 { 266 EGLImageKHR image; 267 EGLint num_planes, fd; 268 269 image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), 270 EGL_GL_TEXTURE_2D_KHR, 271 (EGLClientBuffer)(unsigned long)tex_id, 272 NULL); 273 if (!image) { 274 return -1; 275 } 276 277 eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, 278 &num_planes, modifier); 279 if (num_planes != 1) { 280 eglDestroyImageKHR(qemu_egl_display, image); 281 return -1; 282 } 283 eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); 284 eglDestroyImageKHR(qemu_egl_display, image); 285 286 return fd; 287 } 288 289 void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) 290 { 291 EGLImageKHR image = EGL_NO_IMAGE_KHR; 292 EGLint attrs[64]; 293 int i = 0; 294 295 if (dmabuf->texture != 0) { 296 return; 297 } 298 299 attrs[i++] = EGL_WIDTH; 300 attrs[i++] = dmabuf->width; 301 attrs[i++] = EGL_HEIGHT; 302 attrs[i++] = dmabuf->height; 303 attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT; 304 attrs[i++] = dmabuf->fourcc; 305 306 attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT; 307 attrs[i++] = dmabuf->fd; 308 attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; 309 attrs[i++] = dmabuf->stride; 310 attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; 311 attrs[i++] = 0; 312 #ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 313 if (dmabuf->modifier) { 314 attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; 315 attrs[i++] = (dmabuf->modifier >> 0) & 0xffffffff; 316 attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; 317 attrs[i++] = (dmabuf->modifier >> 32) & 0xffffffff; 318 } 319 #endif 320 attrs[i++] = EGL_NONE; 321 322 image = eglCreateImageKHR(qemu_egl_display, 323 EGL_NO_CONTEXT, 324 EGL_LINUX_DMA_BUF_EXT, 325 NULL, attrs); 326 if (image == EGL_NO_IMAGE_KHR) { 327 error_report("eglCreateImageKHR failed"); 328 return; 329 } 330 331 glGenTextures(1, &dmabuf->texture); 332 glBindTexture(GL_TEXTURE_2D, dmabuf->texture); 333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 334 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 335 336 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); 337 eglDestroyImageKHR(qemu_egl_display, image); 338 } 339 340 void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf) 341 { 342 if (dmabuf->texture == 0) { 343 return; 344 } 345 346 glDeleteTextures(1, &dmabuf->texture); 347 dmabuf->texture = 0; 348 } 349 350 void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf) 351 { 352 EGLSyncKHR sync; 353 354 if (epoxy_has_egl_extension(qemu_egl_display, 355 "EGL_KHR_fence_sync") && 356 epoxy_has_egl_extension(qemu_egl_display, 357 "EGL_ANDROID_native_fence_sync")) { 358 sync = eglCreateSyncKHR(qemu_egl_display, 359 EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); 360 if (sync != EGL_NO_SYNC_KHR) { 361 dmabuf->sync = sync; 362 } 363 } 364 } 365 366 void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf) 367 { 368 if (dmabuf->sync) { 369 dmabuf->fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display, 370 dmabuf->sync); 371 eglDestroySyncKHR(qemu_egl_display, dmabuf->sync); 372 dmabuf->sync = NULL; 373 } 374 } 375 376 #endif /* CONFIG_GBM */ 377 378 /* ---------------------------------------------------------------------- */ 379 380 EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win) 381 { 382 EGLSurface esurface; 383 EGLBoolean b; 384 385 esurface = eglCreateWindowSurface(qemu_egl_display, 386 qemu_egl_config, 387 win, NULL); 388 if (esurface == EGL_NO_SURFACE) { 389 error_report("egl: eglCreateWindowSurface failed"); 390 return NULL; 391 } 392 393 b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx); 394 if (b == EGL_FALSE) { 395 error_report("egl: eglMakeCurrent failed"); 396 return NULL; 397 } 398 399 return esurface; 400 } 401 402 /* ---------------------------------------------------------------------- */ 403 404 #if defined(CONFIG_X11) || defined(CONFIG_GBM) || defined(WIN32) 405 406 /* 407 * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed 408 * 409 * Create an EGLDisplay from a native display type. This is a little quirky 410 * for a few reasons. 411 * 412 * 1: GetPlatformDisplayEXT and GetPlatformDisplay are the API you want to 413 * use, but have different function signatures in the third argument; this 414 * happens not to matter for us, at the moment, but it means epoxy won't alias 415 * them together. 416 * 417 * 2: epoxy 1.3 and earlier don't understand EGL client extensions, which 418 * means you can't call "eglGetPlatformDisplayEXT" directly, as the resolver 419 * will crash. 420 * 421 * 3: You can't tell whether you have EGL 1.5 at this point, because 422 * eglQueryString(EGL_VERSION) is a property of the display, which we don't 423 * have yet. So you have to query for extensions no matter what. Fortunately 424 * epoxy_has_egl_extension _does_ let you query for client extensions, so 425 * we don't have to write our own extension string parsing. 426 * 427 * 4. There is no EGL_KHR_platform_base to complement the EXT one, thus one 428 * needs to know EGL 1.5 is supported in order to use the eglGetPlatformDisplay 429 * function pointer. 430 * We can workaround this (circular dependency) by probing for the EGL 1.5 431 * platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem 432 * like mesa will be able to advertise these (even though it can do EGL 1.5). 433 */ 434 static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native, 435 EGLenum platform) 436 { 437 EGLDisplay dpy = EGL_NO_DISPLAY; 438 439 /* In practise any EGL 1.5 implementation would support the EXT extension */ 440 if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) { 441 if (platform != 0) { 442 dpy = eglGetPlatformDisplayEXT(platform, native, NULL); 443 } 444 } 445 446 if (dpy == EGL_NO_DISPLAY) { 447 /* fallback */ 448 dpy = eglGetDisplay(native); 449 } 450 return dpy; 451 } 452 453 static int qemu_egl_init_dpy(EGLNativeDisplayType dpy, 454 EGLenum platform, 455 DisplayGLMode mode) 456 { 457 static const EGLint conf_att_core[] = { 458 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 459 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, 460 EGL_RED_SIZE, 5, 461 EGL_GREEN_SIZE, 5, 462 EGL_BLUE_SIZE, 5, 463 EGL_ALPHA_SIZE, 0, 464 EGL_NONE, 465 }; 466 static const EGLint conf_att_gles[] = { 467 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 468 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 469 EGL_RED_SIZE, 5, 470 EGL_GREEN_SIZE, 5, 471 EGL_BLUE_SIZE, 5, 472 EGL_ALPHA_SIZE, 0, 473 EGL_NONE, 474 }; 475 EGLint major, minor; 476 EGLBoolean b; 477 EGLint n; 478 bool gles = (mode == DISPLAYGL_MODE_ES); 479 480 qemu_egl_display = qemu_egl_get_display(dpy, platform); 481 if (qemu_egl_display == EGL_NO_DISPLAY) { 482 error_report("egl: eglGetDisplay failed: %s", qemu_egl_get_error_string()); 483 return -1; 484 } 485 486 b = eglInitialize(qemu_egl_display, &major, &minor); 487 if (b == EGL_FALSE) { 488 error_report("egl: eglInitialize failed: %s", qemu_egl_get_error_string()); 489 return -1; 490 } 491 492 b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); 493 if (b == EGL_FALSE) { 494 error_report("egl: eglBindAPI failed (%s mode): %s", 495 gles ? "gles" : "core", qemu_egl_get_error_string()); 496 return -1; 497 } 498 499 b = eglChooseConfig(qemu_egl_display, 500 gles ? conf_att_gles : conf_att_core, 501 &qemu_egl_config, 1, &n); 502 if (b == EGL_FALSE || n != 1) { 503 error_report("egl: eglChooseConfig failed (%s mode): %s", 504 gles ? "gles" : "core", qemu_egl_get_error_string()); 505 return -1; 506 } 507 508 qemu_egl_mode = gles ? DISPLAYGL_MODE_ES : DISPLAYGL_MODE_CORE; 509 return 0; 510 } 511 512 #endif 513 514 #if defined(CONFIG_X11) || defined(CONFIG_GBM) 515 int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode) 516 { 517 #ifdef EGL_KHR_platform_x11 518 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_X11_KHR, mode); 519 #else 520 return qemu_egl_init_dpy(dpy, 0, mode); 521 #endif 522 } 523 524 int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode) 525 { 526 #ifdef EGL_MESA_platform_gbm 527 return qemu_egl_init_dpy(dpy, EGL_PLATFORM_GBM_MESA, mode); 528 #else 529 return qemu_egl_init_dpy(dpy, 0, mode); 530 #endif 531 } 532 #endif 533 534 535 #ifdef WIN32 536 int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode) 537 { 538 return qemu_egl_init_dpy(dpy, 0, mode); 539 } 540 #endif 541 542 bool qemu_egl_has_dmabuf(void) 543 { 544 if (qemu_egl_display == EGL_NO_DISPLAY) { 545 return false; 546 } 547 548 return epoxy_has_egl_extension(qemu_egl_display, 549 "EGL_EXT_image_dma_buf_import"); 550 } 551 552 EGLContext qemu_egl_init_ctx(void) 553 { 554 static const EGLint ctx_att_core[] = { 555 EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, 556 EGL_NONE 557 }; 558 static const EGLint ctx_att_gles[] = { 559 EGL_CONTEXT_CLIENT_VERSION, 2, 560 EGL_NONE 561 }; 562 bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES); 563 EGLContext ectx; 564 EGLBoolean b; 565 566 ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT, 567 gles ? ctx_att_gles : ctx_att_core); 568 if (ectx == EGL_NO_CONTEXT) { 569 error_report("egl: eglCreateContext failed"); 570 return NULL; 571 } 572 573 b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx); 574 if (b == EGL_FALSE) { 575 error_report("egl: eglMakeCurrent failed"); 576 return NULL; 577 } 578 579 return ectx; 580 } 581 582 bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp) 583 { 584 ERRP_GUARD(); 585 586 if (mode == DISPLAYGL_MODE_OFF) { 587 error_setg(errp, "egl: turning off GL doesn't make sense"); 588 return false; 589 } 590 591 #ifdef WIN32 592 if (qemu_egl_init_dpy_win32(EGL_DEFAULT_DISPLAY, mode) < 0) { 593 error_setg(errp, "egl: init failed"); 594 return false; 595 } 596 qemu_egl_rn_ctx = qemu_egl_init_ctx(); 597 if (!qemu_egl_rn_ctx) { 598 error_setg(errp, "egl: egl_init_ctx failed"); 599 return false; 600 } 601 #elif defined(CONFIG_GBM) 602 if (egl_rendernode_init(rendernode, mode) < 0) { 603 error_setg(errp, "egl: render node init failed"); 604 return false; 605 } 606 #endif 607 608 if (!qemu_egl_rn_ctx) { 609 error_setg(errp, "egl: not available on this platform"); 610 return false; 611 } 612 613 display_opengl = 1; 614 return true; 615 } 616