1bb1599b6SGerd Hoffmann #include "qemu/osdep.h" 25feed38cSThomas Huth #include "qemu/error-report.h" 30b8fa32fSMarkus Armbruster #include "qemu/module.h" 40e1be59eSMarc-André Lureau #include "qapi/error.h" 5bb1599b6SGerd Hoffmann #include "ui/console.h" 6bb1599b6SGerd Hoffmann #include "ui/egl-helpers.h" 7bb1599b6SGerd Hoffmann #include "ui/egl-context.h" 8a3517917SGerd Hoffmann #include "ui/shader.h" 9bb1599b6SGerd Hoffmann 10bb1599b6SGerd Hoffmann typedef struct egl_dpy { 11bb1599b6SGerd Hoffmann DisplayChangeListener dcl; 12bb1599b6SGerd Hoffmann DisplaySurface *ds; 13a3517917SGerd Hoffmann QemuGLShader *gls; 14d8dc67e1SGerd Hoffmann egl_fb guest_fb; 15a3517917SGerd Hoffmann egl_fb cursor_fb; 16d8dc67e1SGerd Hoffmann egl_fb blit_fb; 17bb1599b6SGerd Hoffmann bool y_0_top; 18a3517917SGerd Hoffmann uint32_t pos_x; 19a3517917SGerd Hoffmann uint32_t pos_y; 20bb1599b6SGerd Hoffmann } egl_dpy; 21bb1599b6SGerd Hoffmann 22d8dc67e1SGerd Hoffmann /* ------------------------------------------------------------------ */ 23d8dc67e1SGerd Hoffmann 24bb1599b6SGerd Hoffmann static void egl_refresh(DisplayChangeListener *dcl) 25bb1599b6SGerd Hoffmann { 26bb1599b6SGerd Hoffmann graphic_hw_update(dcl->con); 27bb1599b6SGerd Hoffmann } 28bb1599b6SGerd Hoffmann 29bb1599b6SGerd Hoffmann static void egl_gfx_update(DisplayChangeListener *dcl, 30bb1599b6SGerd Hoffmann int x, int y, int w, int h) 31bb1599b6SGerd Hoffmann { 32bb1599b6SGerd Hoffmann } 33bb1599b6SGerd Hoffmann 34bb1599b6SGerd Hoffmann static void egl_gfx_switch(DisplayChangeListener *dcl, 35bb1599b6SGerd Hoffmann struct DisplaySurface *new_surface) 36bb1599b6SGerd Hoffmann { 37bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 38bb1599b6SGerd Hoffmann 39bb1599b6SGerd Hoffmann edpy->ds = new_surface; 40bb1599b6SGerd Hoffmann } 41bb1599b6SGerd Hoffmann 425e79d516SMarc-André Lureau static QEMUGLContext egl_create_context(DisplayGLCtx *dgc, 43952e5d58SGerd Hoffmann QEMUGLParams *params) 44952e5d58SGerd Hoffmann { 45952e5d58SGerd Hoffmann eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, 46952e5d58SGerd Hoffmann qemu_egl_rn_ctx); 475e79d516SMarc-André Lureau return qemu_egl_create_context(dgc, params); 48952e5d58SGerd Hoffmann } 49952e5d58SGerd Hoffmann 50bb1599b6SGerd Hoffmann static void egl_scanout_disable(DisplayChangeListener *dcl) 51bb1599b6SGerd Hoffmann { 52bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 53bb1599b6SGerd Hoffmann 54d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->guest_fb); 55d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb); 56bb1599b6SGerd Hoffmann } 57bb1599b6SGerd Hoffmann 58bb1599b6SGerd Hoffmann static void egl_scanout_texture(DisplayChangeListener *dcl, 59bb1599b6SGerd Hoffmann uint32_t backing_id, 60bb1599b6SGerd Hoffmann bool backing_y_0_top, 61bb1599b6SGerd Hoffmann uint32_t backing_width, 62bb1599b6SGerd Hoffmann uint32_t backing_height, 63bb1599b6SGerd Hoffmann uint32_t x, uint32_t y, 64bf41ab61SMarc-André Lureau uint32_t w, uint32_t h, 65bf41ab61SMarc-André Lureau void *d3d_tex2d) 66bb1599b6SGerd Hoffmann { 67bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 68bb1599b6SGerd Hoffmann 69bb1599b6SGerd Hoffmann edpy->y_0_top = backing_y_0_top; 70bb1599b6SGerd Hoffmann 71bb1599b6SGerd Hoffmann /* source framebuffer */ 7274083f9cSGerd Hoffmann egl_fb_setup_for_tex(&edpy->guest_fb, 7374083f9cSGerd Hoffmann backing_width, backing_height, backing_id, false); 74bb1599b6SGerd Hoffmann 75bb1599b6SGerd Hoffmann /* dest framebuffer */ 76d8dc67e1SGerd Hoffmann if (edpy->blit_fb.width != backing_width || 77d8dc67e1SGerd Hoffmann edpy->blit_fb.height != backing_height) { 78d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb); 7974083f9cSGerd Hoffmann egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height); 80bb1599b6SGerd Hoffmann } 81bb1599b6SGerd Hoffmann } 82bb1599b6SGerd Hoffmann 8339324b49SMarc-André Lureau #ifdef CONFIG_GBM 8439324b49SMarc-André Lureau 85a3517917SGerd Hoffmann static void egl_scanout_dmabuf(DisplayChangeListener *dcl, 86a3517917SGerd Hoffmann QemuDmaBuf *dmabuf) 87a3517917SGerd Hoffmann { 886779a307SDongwon Kim uint32_t width, height, texture; 896779a307SDongwon Kim 90a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf); 916779a307SDongwon Kim texture = qemu_dmabuf_get_texture(dmabuf); 926779a307SDongwon Kim if (!texture) { 93a3517917SGerd Hoffmann return; 94a3517917SGerd Hoffmann } 95a3517917SGerd Hoffmann 966779a307SDongwon Kim width = qemu_dmabuf_get_width(dmabuf); 976779a307SDongwon Kim height = qemu_dmabuf_get_height(dmabuf); 986779a307SDongwon Kim 996779a307SDongwon Kim egl_scanout_texture(dcl, texture, false, width, height, 0, 0, 1006779a307SDongwon Kim width, height, NULL); 101a3517917SGerd Hoffmann } 102a3517917SGerd Hoffmann 103a3517917SGerd Hoffmann static void egl_cursor_dmabuf(DisplayChangeListener *dcl, 1046e1f2cb5SGerd Hoffmann QemuDmaBuf *dmabuf, bool have_hot, 1056e1f2cb5SGerd Hoffmann uint32_t hot_x, uint32_t hot_y) 106a3517917SGerd Hoffmann { 1076779a307SDongwon Kim uint32_t width, height, texture; 108a3517917SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 109a3517917SGerd Hoffmann 110b0916928SGerd Hoffmann if (dmabuf) { 111a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf); 1126779a307SDongwon Kim texture = qemu_dmabuf_get_texture(dmabuf); 1136779a307SDongwon Kim if (!texture) { 114a3517917SGerd Hoffmann return; 115a3517917SGerd Hoffmann } 1166779a307SDongwon Kim 1176779a307SDongwon Kim width = qemu_dmabuf_get_width(dmabuf); 1186779a307SDongwon Kim height = qemu_dmabuf_get_height(dmabuf); 1196779a307SDongwon Kim egl_fb_setup_for_tex(&edpy->cursor_fb, width, height, texture, false); 120b0916928SGerd Hoffmann } else { 121b0916928SGerd Hoffmann egl_fb_destroy(&edpy->cursor_fb); 122b0916928SGerd Hoffmann } 123a3517917SGerd Hoffmann } 124a3517917SGerd Hoffmann 12539324b49SMarc-André Lureau static void egl_release_dmabuf(DisplayChangeListener *dcl, 12639324b49SMarc-André Lureau QemuDmaBuf *dmabuf) 12739324b49SMarc-André Lureau { 12839324b49SMarc-André Lureau egl_dmabuf_release_texture(dmabuf); 12939324b49SMarc-André Lureau } 13039324b49SMarc-André Lureau 13139324b49SMarc-André Lureau #endif 13239324b49SMarc-André Lureau 1336e1f2cb5SGerd Hoffmann static void egl_cursor_position(DisplayChangeListener *dcl, 1346e1f2cb5SGerd Hoffmann uint32_t pos_x, uint32_t pos_y) 1356e1f2cb5SGerd Hoffmann { 1366e1f2cb5SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 1376e1f2cb5SGerd Hoffmann 1386e1f2cb5SGerd Hoffmann edpy->pos_x = pos_x; 1396e1f2cb5SGerd Hoffmann edpy->pos_y = pos_y; 1406e1f2cb5SGerd Hoffmann } 1416e1f2cb5SGerd Hoffmann 142bb1599b6SGerd Hoffmann static void egl_scanout_flush(DisplayChangeListener *dcl, 143bb1599b6SGerd Hoffmann uint32_t x, uint32_t y, 144bb1599b6SGerd Hoffmann uint32_t w, uint32_t h) 145bb1599b6SGerd Hoffmann { 146bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 147bb1599b6SGerd Hoffmann 148d8dc67e1SGerd Hoffmann if (!edpy->guest_fb.texture || !edpy->ds) { 149bb1599b6SGerd Hoffmann return; 150bb1599b6SGerd Hoffmann } 151bb1599b6SGerd Hoffmann assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8); 152bb1599b6SGerd Hoffmann 153a3517917SGerd Hoffmann if (edpy->cursor_fb.texture) { 154a3517917SGerd Hoffmann /* have cursor -> render using textures */ 155a3517917SGerd Hoffmann egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb, 156a3517917SGerd Hoffmann !edpy->y_0_top); 157a3517917SGerd Hoffmann egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb, 158051a0cdeSChen Zhang !edpy->y_0_top, edpy->pos_x, edpy->pos_y, 159051a0cdeSChen Zhang 1.0, 1.0); 160a3517917SGerd Hoffmann } else { 161a3517917SGerd Hoffmann /* no cursor -> use simple framebuffer blit */ 162d8dc67e1SGerd Hoffmann egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top); 163a3517917SGerd Hoffmann } 164bb1599b6SGerd Hoffmann 165d2329237SGerd Hoffmann egl_fb_read(edpy->ds, &edpy->blit_fb); 166bb1599b6SGerd Hoffmann dpy_gfx_update(edpy->dcl.con, x, y, w, h); 167bb1599b6SGerd Hoffmann } 168bb1599b6SGerd Hoffmann 169bb1599b6SGerd Hoffmann static const DisplayChangeListenerOps egl_ops = { 170bb1599b6SGerd Hoffmann .dpy_name = "egl-headless", 171bb1599b6SGerd Hoffmann .dpy_refresh = egl_refresh, 172bb1599b6SGerd Hoffmann .dpy_gfx_update = egl_gfx_update, 173bb1599b6SGerd Hoffmann .dpy_gfx_switch = egl_gfx_switch, 174bb1599b6SGerd Hoffmann 175bb1599b6SGerd Hoffmann .dpy_gl_scanout_disable = egl_scanout_disable, 176bb1599b6SGerd Hoffmann .dpy_gl_scanout_texture = egl_scanout_texture, 17739324b49SMarc-André Lureau #ifdef CONFIG_GBM 178a3517917SGerd Hoffmann .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf, 179a3517917SGerd Hoffmann .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf, 180a3517917SGerd Hoffmann .dpy_gl_release_dmabuf = egl_release_dmabuf, 18139324b49SMarc-André Lureau #endif 18239324b49SMarc-André Lureau .dpy_gl_cursor_position = egl_cursor_position, 183bb1599b6SGerd Hoffmann .dpy_gl_update = egl_scanout_flush, 184bb1599b6SGerd Hoffmann }; 185bb1599b6SGerd Hoffmann 186a62c4a17SMarc-André Lureau static bool 187a62c4a17SMarc-André Lureau egl_is_compatible_dcl(DisplayGLCtx *dgc, 188a62c4a17SMarc-André Lureau DisplayChangeListener *dcl) 189a62c4a17SMarc-André Lureau { 190cd19c25fSMarc-André Lureau if (!dcl->ops->dpy_gl_update) { 191cd19c25fSMarc-André Lureau /* 192cd19c25fSMarc-André Lureau * egl-headless is compatible with all 2d listeners, as it blits the GL 193cd19c25fSMarc-André Lureau * updates on the 2d console surface. 194cd19c25fSMarc-André Lureau */ 195cd19c25fSMarc-André Lureau return true; 196cd19c25fSMarc-André Lureau } 197cd19c25fSMarc-André Lureau 198a62c4a17SMarc-André Lureau return dcl->ops == &egl_ops; 199a62c4a17SMarc-André Lureau } 200a62c4a17SMarc-André Lureau 2015e79d516SMarc-André Lureau static const DisplayGLCtxOps eglctx_ops = { 202a62c4a17SMarc-André Lureau .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl, 2035e79d516SMarc-André Lureau .dpy_gl_ctx_create = egl_create_context, 2045e79d516SMarc-André Lureau .dpy_gl_ctx_destroy = qemu_egl_destroy_context, 2055e79d516SMarc-André Lureau .dpy_gl_ctx_make_current = qemu_egl_make_context_current, 2065e79d516SMarc-André Lureau }; 2075e79d516SMarc-André Lureau 20816ab0a74SGerd Hoffmann static void early_egl_headless_init(DisplayOptions *opts) 20916ab0a74SGerd Hoffmann { 210*154fd4d1SMarkus Armbruster DisplayGLMode mode = DISPLAY_GL_MODE_ON; 2110e1be59eSMarc-André Lureau 2120e1be59eSMarc-André Lureau if (opts->has_gl) { 2130e1be59eSMarc-André Lureau mode = opts->gl; 2140e1be59eSMarc-André Lureau } 2150e1be59eSMarc-André Lureau 2160e1be59eSMarc-André Lureau egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal); 21716ab0a74SGerd Hoffmann } 21816ab0a74SGerd Hoffmann 21916ab0a74SGerd Hoffmann static void egl_headless_init(DisplayState *ds, DisplayOptions *opts) 220bb1599b6SGerd Hoffmann { 221bb1599b6SGerd Hoffmann QemuConsole *con; 222bb1599b6SGerd Hoffmann egl_dpy *edpy; 223bb1599b6SGerd Hoffmann int idx; 224bb1599b6SGerd Hoffmann 225bb1599b6SGerd Hoffmann for (idx = 0;; idx++) { 2265e79d516SMarc-André Lureau DisplayGLCtx *ctx; 2275e79d516SMarc-André Lureau 228bb1599b6SGerd Hoffmann con = qemu_console_lookup_by_index(idx); 229bb1599b6SGerd Hoffmann if (!con || !qemu_console_is_graphic(con)) { 230bb1599b6SGerd Hoffmann break; 231bb1599b6SGerd Hoffmann } 232bb1599b6SGerd Hoffmann 233bb1599b6SGerd Hoffmann edpy = g_new0(egl_dpy, 1); 234bb1599b6SGerd Hoffmann edpy->dcl.con = con; 235bb1599b6SGerd Hoffmann edpy->dcl.ops = &egl_ops; 236a3517917SGerd Hoffmann edpy->gls = qemu_gl_init_shader(); 2375e79d516SMarc-André Lureau ctx = g_new0(DisplayGLCtx, 1); 2385e79d516SMarc-André Lureau ctx->ops = &eglctx_ops; 2395e79d516SMarc-André Lureau qemu_console_set_display_gl_ctx(con, ctx); 240bb1599b6SGerd Hoffmann register_displaychangelistener(&edpy->dcl); 241bb1599b6SGerd Hoffmann } 242bb1599b6SGerd Hoffmann } 24316ab0a74SGerd Hoffmann 24416ab0a74SGerd Hoffmann static QemuDisplay qemu_display_egl = { 24516ab0a74SGerd Hoffmann .type = DISPLAY_TYPE_EGL_HEADLESS, 24616ab0a74SGerd Hoffmann .early_init = early_egl_headless_init, 24716ab0a74SGerd Hoffmann .init = egl_headless_init, 24816ab0a74SGerd Hoffmann }; 24916ab0a74SGerd Hoffmann 25016ab0a74SGerd Hoffmann static void register_egl(void) 25116ab0a74SGerd Hoffmann { 25216ab0a74SGerd Hoffmann qemu_display_register(&qemu_display_egl); 25316ab0a74SGerd Hoffmann } 25416ab0a74SGerd Hoffmann 25516ab0a74SGerd Hoffmann type_init(register_egl); 256b36ae1c1SGerd Hoffmann 257b36ae1c1SGerd Hoffmann module_dep("ui-opengl"); 258