X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ui%2Fegl-helpers.c;h=edc53f6d3464523bde9195b22e467c7b511586bd;hb=HEAD;hp=6d0cb2b5cb93298c9c6a463fd462cc80f3e8d8ee;hpb=fe352f5c0056b4d21ae033ec49acc0bce9897e53;p=mirror_qemu.git diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 6d0cb2b5cb..99b2ebbe23 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -15,17 +15,62 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" + #include "qemu/drm.h" #include "qemu/error-report.h" #include "ui/console.h" #include "ui/egl-helpers.h" +#include "sysemu/sysemu.h" +#include "qapi/error.h" +#include "trace.h" EGLDisplay *qemu_egl_display; EGLConfig qemu_egl_config; DisplayGLMode qemu_egl_mode; +bool qemu_egl_angle_d3d; /* ------------------------------------------------------------------ */ +const char *qemu_egl_get_error_string(void) +{ + EGLint error = eglGetError(); + + switch (error) { + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + case EGL_CONTEXT_LOST: + return "EGL_CONTEXT_LOST"; + default: + return "Unknown EGL error"; + } +} + static void egl_fb_delete_texture(egl_fb *fb) { if (!fb->delete_texture) { @@ -90,14 +135,31 @@ void egl_fb_setup_new_tex(egl_fb *fb, int width, int height) void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) { - GLuint y1, y2; + GLuint x1 = 0; + GLuint y1 = 0; + GLuint x2, y2; + GLuint w = src->width; + GLuint h = src->height; glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer); glViewport(0, 0, dst->width, dst->height); - y1 = flip ? src->height : 0; - y2 = flip ? 0 : src->height; - glBlitFramebuffer(0, y1, src->width, y2, + + if (src->dmabuf) { + x1 = qemu_dmabuf_get_x(src->dmabuf); + y1 = qemu_dmabuf_get_y(src->dmabuf); + w = qemu_dmabuf_get_width(src->dmabuf); + h = qemu_dmabuf_get_height(src->dmabuf); + } + + w = (x1 + w) > src->width ? src->width - x1 : w; + h = (y1 + h) > src->height ? src->height - y1 : h; + + y2 = flip ? y1 : h + y1; + y1 = flip ? h + y1 : y1; + x2 = x1 + w; + + glBlitFramebuffer(x1, y1, x2, y2, 0, 0, dst->width, dst->height, GL_COLOR_BUFFER_BIT, GL_LINEAR); } @@ -110,6 +172,20 @@ void egl_fb_read(DisplaySurface *dst, egl_fb *src) GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst)); } +void egl_fb_read_rect(DisplaySurface *dst, egl_fb *src, int x, int y, int w, int h) +{ + assert(surface_width(dst) == src->width); + assert(surface_height(dst) == src->height); + assert(surface_format(dst) == PIXMAN_x8r8g8b8); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glPixelStorei(GL_PACK_ROW_LENGTH, surface_stride(dst) / 4); + glReadPixels(x, y, w, h, + GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst) + x * 4); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); +} + void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip) { glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer); @@ -140,11 +216,12 @@ void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip, /* ---------------------------------------------------------------------- */ +EGLContext qemu_egl_rn_ctx; + #ifdef CONFIG_GBM int qemu_egl_rn_fd; struct gbm_device *qemu_egl_rn_gbm_dev; -EGLContext qemu_egl_rn_ctx; int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) { @@ -231,30 +308,33 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) EGLImageKHR image = EGL_NO_IMAGE_KHR; EGLint attrs[64]; int i = 0; + uint64_t modifier; + uint32_t texture = qemu_dmabuf_get_texture(dmabuf); - if (dmabuf->texture != 0) { + if (texture != 0) { return; } attrs[i++] = EGL_WIDTH; - attrs[i++] = dmabuf->width; + attrs[i++] = qemu_dmabuf_get_backing_width(dmabuf); attrs[i++] = EGL_HEIGHT; - attrs[i++] = dmabuf->height; + attrs[i++] = qemu_dmabuf_get_backing_height(dmabuf); attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT; - attrs[i++] = dmabuf->fourcc; + attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf); attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT; - attrs[i++] = dmabuf->fd; + attrs[i++] = qemu_dmabuf_get_fd(dmabuf); attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; - attrs[i++] = dmabuf->stride; + attrs[i++] = qemu_dmabuf_get_stride(dmabuf); attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attrs[i++] = 0; #ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT - if (dmabuf->modifier) { + modifier = qemu_dmabuf_get_modifier(dmabuf); + if (modifier) { attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; - attrs[i++] = (dmabuf->modifier >> 0) & 0xffffffff; + attrs[i++] = (modifier >> 0) & 0xffffffff; attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; - attrs[i++] = (dmabuf->modifier >> 32) & 0xffffffff; + attrs[i++] = (modifier >> 32) & 0xffffffff; } #endif attrs[i++] = EGL_NONE; @@ -268,8 +348,9 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) return; } - glGenTextures(1, &dmabuf->texture); - glBindTexture(GL_TEXTURE_2D, dmabuf->texture); + glGenTextures(1, &texture); + qemu_dmabuf_set_texture(dmabuf, texture); + glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -279,12 +360,45 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf) { - if (dmabuf->texture == 0) { + uint32_t texture; + + texture = qemu_dmabuf_get_texture(dmabuf); + if (texture == 0) { return; } - glDeleteTextures(1, &dmabuf->texture); - dmabuf->texture = 0; + glDeleteTextures(1, &texture); + qemu_dmabuf_set_texture(dmabuf, 0); +} + +void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf) +{ + EGLSyncKHR sync; + + if (epoxy_has_egl_extension(qemu_egl_display, + "EGL_KHR_fence_sync") && + epoxy_has_egl_extension(qemu_egl_display, + "EGL_ANDROID_native_fence_sync")) { + sync = eglCreateSyncKHR(qemu_egl_display, + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + if (sync != EGL_NO_SYNC_KHR) { + qemu_dmabuf_set_sync(dmabuf, sync); + } + } +} + +void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf) +{ + void *sync = qemu_dmabuf_get_sync(dmabuf); + int fence_fd; + + if (sync) { + fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display, + sync); + qemu_dmabuf_set_fence_fd(dmabuf, fence_fd); + eglDestroySyncKHR(qemu_egl_display, sync); + qemu_dmabuf_set_sync(dmabuf, NULL); + } } #endif /* CONFIG_GBM */ @@ -315,7 +429,7 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win) /* ---------------------------------------------------------------------- */ -#if defined(CONFIG_X11) || defined(CONFIG_GBM) +#if defined(CONFIG_X11) || defined(CONFIG_GBM) || defined(WIN32) /* * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed @@ -352,10 +466,8 @@ static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native, /* In practise any EGL 1.5 implementation would support the EXT extension */ if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) { - PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT = - (void *) eglGetProcAddress("eglGetPlatformDisplayEXT"); - if (getPlatformDisplayEXT && platform != 0) { - dpy = getPlatformDisplayEXT(platform, native, NULL); + if (platform != 0) { + dpy = eglGetPlatformDisplayEXT(platform, native, NULL); } } @@ -395,20 +507,20 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy, qemu_egl_display = qemu_egl_get_display(dpy, platform); if (qemu_egl_display == EGL_NO_DISPLAY) { - error_report("egl: eglGetDisplay failed"); + error_report("egl: eglGetDisplay failed: %s", qemu_egl_get_error_string()); return -1; } b = eglInitialize(qemu_egl_display, &major, &minor); if (b == EGL_FALSE) { - error_report("egl: eglInitialize failed"); + error_report("egl: eglInitialize failed: %s", qemu_egl_get_error_string()); return -1; } b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API); if (b == EGL_FALSE) { - error_report("egl: eglBindAPI failed (%s mode)", - gles ? "gles" : "core"); + error_report("egl: eglBindAPI failed (%s mode): %s", + gles ? "gles" : "core", qemu_egl_get_error_string()); return -1; } @@ -416,8 +528,8 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy, gles ? conf_att_gles : conf_att_core, &qemu_egl_config, 1, &n); if (b == EGL_FALSE || n != 1) { - error_report("egl: eglChooseConfig failed (%s mode)", - gles ? "gles" : "core"); + error_report("egl: eglChooseConfig failed (%s mode): %s", + gles ? "gles" : "core", qemu_egl_get_error_string()); return -1; } @@ -425,6 +537,9 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy, return 0; } +#endif + +#if defined(CONFIG_X11) || defined(CONFIG_GBM) int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode) { #ifdef EGL_KHR_platform_x11 @@ -442,7 +557,45 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode) return qemu_egl_init_dpy(dpy, 0, mode); #endif } +#endif + +#ifdef WIN32 +int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode) +{ + /* prefer GL ES, as that's what ANGLE supports */ + if (mode == DISPLAYGL_MODE_ON) { + mode = DISPLAYGL_MODE_ES; + } + + if (qemu_egl_init_dpy(dpy, 0, mode) < 0) { + return -1; + } + +#ifdef EGL_D3D11_DEVICE_ANGLE + if (epoxy_has_egl_extension(qemu_egl_display, "EGL_EXT_device_query")) { + EGLDeviceEXT device; + void *d3d11_device; + + if (!eglQueryDisplayAttribEXT(qemu_egl_display, + EGL_DEVICE_EXT, + (EGLAttrib *)&device)) { + return 0; + } + + if (!eglQueryDeviceAttribEXT(device, + EGL_D3D11_DEVICE_ANGLE, + (EGLAttrib *)&d3d11_device)) { + return 0; + } + + trace_egl_init_d3d11_device(device); + qemu_egl_angle_d3d = device != NULL; + } +#endif + + return 0; +} #endif bool qemu_egl_has_dmabuf(void) @@ -484,3 +637,38 @@ EGLContext qemu_egl_init_ctx(void) return ectx; } + +bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp) +{ + ERRP_GUARD(); + + if (mode == DISPLAYGL_MODE_OFF) { + error_setg(errp, "egl: turning off GL doesn't make sense"); + return false; + } + +#ifdef WIN32 + if (qemu_egl_init_dpy_win32(EGL_DEFAULT_DISPLAY, mode) < 0) { + error_setg(errp, "egl: init failed"); + return false; + } + qemu_egl_rn_ctx = qemu_egl_init_ctx(); + if (!qemu_egl_rn_ctx) { + error_setg(errp, "egl: egl_init_ctx failed"); + return false; + } +#elif defined(CONFIG_GBM) + if (egl_rendernode_init(rendernode, mode) < 0) { + error_setg(errp, "egl: render node init failed"); + return false; + } +#endif + + if (!qemu_egl_rn_ctx) { + error_setg(errp, "egl: not available on this platform"); + return false; + } + + display_opengl = 1; + return true; +}