1bb1599b6SGerd Hoffmann #include "qemu/osdep.h" 2bb1599b6SGerd Hoffmann #include "qemu-common.h" 3bb1599b6SGerd Hoffmann #include "sysemu/sysemu.h" 4bb1599b6SGerd Hoffmann #include "ui/console.h" 5bb1599b6SGerd Hoffmann #include "ui/egl-helpers.h" 6bb1599b6SGerd Hoffmann #include "ui/egl-context.h" 7a3517917SGerd Hoffmann #include "ui/shader.h" 8bb1599b6SGerd Hoffmann 9bb1599b6SGerd Hoffmann typedef struct egl_dpy { 10bb1599b6SGerd Hoffmann DisplayChangeListener dcl; 11bb1599b6SGerd Hoffmann DisplaySurface *ds; 12a3517917SGerd Hoffmann QemuGLShader *gls; 13d8dc67e1SGerd Hoffmann egl_fb guest_fb; 14a3517917SGerd Hoffmann egl_fb cursor_fb; 15d8dc67e1SGerd Hoffmann egl_fb blit_fb; 16bb1599b6SGerd Hoffmann bool y_0_top; 17a3517917SGerd Hoffmann uint32_t pos_x; 18a3517917SGerd Hoffmann uint32_t pos_y; 19bb1599b6SGerd Hoffmann } egl_dpy; 20bb1599b6SGerd Hoffmann 21d8dc67e1SGerd Hoffmann /* ------------------------------------------------------------------ */ 22d8dc67e1SGerd Hoffmann 23bb1599b6SGerd Hoffmann static void egl_refresh(DisplayChangeListener *dcl) 24bb1599b6SGerd Hoffmann { 25bb1599b6SGerd Hoffmann graphic_hw_update(dcl->con); 26bb1599b6SGerd Hoffmann } 27bb1599b6SGerd Hoffmann 28bb1599b6SGerd Hoffmann static void egl_gfx_update(DisplayChangeListener *dcl, 29bb1599b6SGerd Hoffmann int x, int y, int w, int h) 30bb1599b6SGerd Hoffmann { 31bb1599b6SGerd Hoffmann } 32bb1599b6SGerd Hoffmann 33bb1599b6SGerd Hoffmann static void egl_gfx_switch(DisplayChangeListener *dcl, 34bb1599b6SGerd Hoffmann struct DisplaySurface *new_surface) 35bb1599b6SGerd Hoffmann { 36bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 37bb1599b6SGerd Hoffmann 38bb1599b6SGerd Hoffmann edpy->ds = new_surface; 39bb1599b6SGerd Hoffmann } 40bb1599b6SGerd Hoffmann 41bb1599b6SGerd Hoffmann static void egl_scanout_disable(DisplayChangeListener *dcl) 42bb1599b6SGerd Hoffmann { 43bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 44bb1599b6SGerd Hoffmann 45d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->guest_fb); 46d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb); 47bb1599b6SGerd Hoffmann } 48bb1599b6SGerd Hoffmann 49bb1599b6SGerd Hoffmann static void egl_scanout_texture(DisplayChangeListener *dcl, 50bb1599b6SGerd Hoffmann uint32_t backing_id, 51bb1599b6SGerd Hoffmann bool backing_y_0_top, 52bb1599b6SGerd Hoffmann uint32_t backing_width, 53bb1599b6SGerd Hoffmann uint32_t backing_height, 54bb1599b6SGerd Hoffmann uint32_t x, uint32_t y, 55bb1599b6SGerd Hoffmann uint32_t w, uint32_t h) 56bb1599b6SGerd Hoffmann { 57bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 58bb1599b6SGerd Hoffmann 59bb1599b6SGerd Hoffmann edpy->y_0_top = backing_y_0_top; 60bb1599b6SGerd Hoffmann 61bb1599b6SGerd Hoffmann /* source framebuffer */ 6274083f9cSGerd Hoffmann egl_fb_setup_for_tex(&edpy->guest_fb, 6374083f9cSGerd Hoffmann backing_width, backing_height, backing_id, false); 64bb1599b6SGerd Hoffmann 65bb1599b6SGerd Hoffmann /* dest framebuffer */ 66d8dc67e1SGerd Hoffmann if (edpy->blit_fb.width != backing_width || 67d8dc67e1SGerd Hoffmann edpy->blit_fb.height != backing_height) { 68d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb); 6974083f9cSGerd Hoffmann egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height); 70bb1599b6SGerd Hoffmann } 71bb1599b6SGerd Hoffmann } 72bb1599b6SGerd Hoffmann 73a3517917SGerd Hoffmann static void egl_scanout_dmabuf(DisplayChangeListener *dcl, 74a3517917SGerd Hoffmann QemuDmaBuf *dmabuf) 75a3517917SGerd Hoffmann { 76a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf); 77a3517917SGerd Hoffmann if (!dmabuf->texture) { 78a3517917SGerd Hoffmann return; 79a3517917SGerd Hoffmann } 80a3517917SGerd Hoffmann 81a3517917SGerd Hoffmann egl_scanout_texture(dcl, dmabuf->texture, 82a3517917SGerd Hoffmann false, dmabuf->width, dmabuf->height, 83a3517917SGerd Hoffmann 0, 0, dmabuf->width, dmabuf->height); 84a3517917SGerd Hoffmann } 85a3517917SGerd Hoffmann 86a3517917SGerd Hoffmann static void egl_cursor_dmabuf(DisplayChangeListener *dcl, 876e1f2cb5SGerd Hoffmann QemuDmaBuf *dmabuf, bool have_hot, 886e1f2cb5SGerd Hoffmann uint32_t hot_x, uint32_t hot_y) 89a3517917SGerd Hoffmann { 90a3517917SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 91a3517917SGerd Hoffmann 92b0916928SGerd Hoffmann if (dmabuf) { 93a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf); 94a3517917SGerd Hoffmann if (!dmabuf->texture) { 95a3517917SGerd Hoffmann return; 96a3517917SGerd Hoffmann } 97a3517917SGerd Hoffmann egl_fb_setup_for_tex(&edpy->cursor_fb, dmabuf->width, dmabuf->height, 98a3517917SGerd Hoffmann dmabuf->texture, false); 99b0916928SGerd Hoffmann } else { 100b0916928SGerd Hoffmann egl_fb_destroy(&edpy->cursor_fb); 101b0916928SGerd Hoffmann } 102a3517917SGerd Hoffmann } 103a3517917SGerd Hoffmann 1046e1f2cb5SGerd Hoffmann static void egl_cursor_position(DisplayChangeListener *dcl, 1056e1f2cb5SGerd Hoffmann uint32_t pos_x, uint32_t pos_y) 1066e1f2cb5SGerd Hoffmann { 1076e1f2cb5SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 1086e1f2cb5SGerd Hoffmann 1096e1f2cb5SGerd Hoffmann edpy->pos_x = pos_x; 1106e1f2cb5SGerd Hoffmann edpy->pos_y = pos_y; 1116e1f2cb5SGerd Hoffmann } 1126e1f2cb5SGerd Hoffmann 113a3517917SGerd Hoffmann static void egl_release_dmabuf(DisplayChangeListener *dcl, 114a3517917SGerd Hoffmann QemuDmaBuf *dmabuf) 115a3517917SGerd Hoffmann { 116a3517917SGerd Hoffmann egl_dmabuf_release_texture(dmabuf); 117a3517917SGerd Hoffmann } 118a3517917SGerd Hoffmann 119bb1599b6SGerd Hoffmann static void egl_scanout_flush(DisplayChangeListener *dcl, 120bb1599b6SGerd Hoffmann uint32_t x, uint32_t y, 121bb1599b6SGerd Hoffmann uint32_t w, uint32_t h) 122bb1599b6SGerd Hoffmann { 123bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 124bb1599b6SGerd Hoffmann 125d8dc67e1SGerd Hoffmann if (!edpy->guest_fb.texture || !edpy->ds) { 126bb1599b6SGerd Hoffmann return; 127bb1599b6SGerd Hoffmann } 128d8dc67e1SGerd Hoffmann assert(surface_width(edpy->ds) == edpy->guest_fb.width); 129d8dc67e1SGerd Hoffmann assert(surface_height(edpy->ds) == edpy->guest_fb.height); 130bb1599b6SGerd Hoffmann assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8); 131bb1599b6SGerd Hoffmann 132a3517917SGerd Hoffmann if (edpy->cursor_fb.texture) { 133a3517917SGerd Hoffmann /* have cursor -> render using textures */ 134a3517917SGerd Hoffmann egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb, 135a3517917SGerd Hoffmann !edpy->y_0_top); 136a3517917SGerd Hoffmann egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb, 137a3517917SGerd Hoffmann !edpy->y_0_top, edpy->pos_x, edpy->pos_y); 138a3517917SGerd Hoffmann } else { 139a3517917SGerd Hoffmann /* no cursor -> use simple framebuffer blit */ 140d8dc67e1SGerd Hoffmann egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top); 141a3517917SGerd Hoffmann } 142bb1599b6SGerd Hoffmann 143a3517917SGerd Hoffmann egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb); 144bb1599b6SGerd Hoffmann dpy_gfx_update(edpy->dcl.con, x, y, w, h); 145bb1599b6SGerd Hoffmann } 146bb1599b6SGerd Hoffmann 147bb1599b6SGerd Hoffmann static const DisplayChangeListenerOps egl_ops = { 148bb1599b6SGerd Hoffmann .dpy_name = "egl-headless", 149bb1599b6SGerd Hoffmann .dpy_refresh = egl_refresh, 150bb1599b6SGerd Hoffmann .dpy_gfx_update = egl_gfx_update, 151bb1599b6SGerd Hoffmann .dpy_gfx_switch = egl_gfx_switch, 152bb1599b6SGerd Hoffmann 153bb1599b6SGerd Hoffmann .dpy_gl_ctx_create = qemu_egl_create_context, 154bb1599b6SGerd Hoffmann .dpy_gl_ctx_destroy = qemu_egl_destroy_context, 155bb1599b6SGerd Hoffmann .dpy_gl_ctx_make_current = qemu_egl_make_context_current, 156bb1599b6SGerd Hoffmann .dpy_gl_ctx_get_current = qemu_egl_get_current_context, 157bb1599b6SGerd Hoffmann 158bb1599b6SGerd Hoffmann .dpy_gl_scanout_disable = egl_scanout_disable, 159bb1599b6SGerd Hoffmann .dpy_gl_scanout_texture = egl_scanout_texture, 160a3517917SGerd Hoffmann .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf, 161a3517917SGerd Hoffmann .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf, 1626e1f2cb5SGerd Hoffmann .dpy_gl_cursor_position = egl_cursor_position, 163a3517917SGerd Hoffmann .dpy_gl_release_dmabuf = egl_release_dmabuf, 164bb1599b6SGerd Hoffmann .dpy_gl_update = egl_scanout_flush, 165bb1599b6SGerd Hoffmann }; 166bb1599b6SGerd Hoffmann 16716ab0a74SGerd Hoffmann static void early_egl_headless_init(DisplayOptions *opts) 16816ab0a74SGerd Hoffmann { 16916ab0a74SGerd Hoffmann display_opengl = 1; 17016ab0a74SGerd Hoffmann } 17116ab0a74SGerd Hoffmann 17216ab0a74SGerd Hoffmann static void egl_headless_init(DisplayState *ds, DisplayOptions *opts) 173bb1599b6SGerd Hoffmann { 17454d208ffSGerd Hoffmann DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON; 175bb1599b6SGerd Hoffmann QemuConsole *con; 176bb1599b6SGerd Hoffmann egl_dpy *edpy; 177bb1599b6SGerd Hoffmann int idx; 178bb1599b6SGerd Hoffmann 179*91e61947SErik Skultety if (egl_rendernode_init(opts->u.egl_headless.rendernode, mode) < 0) { 180bb1599b6SGerd Hoffmann error_report("egl: render node init failed"); 181bb1599b6SGerd Hoffmann exit(1); 182bb1599b6SGerd Hoffmann } 183bb1599b6SGerd Hoffmann 184bb1599b6SGerd Hoffmann for (idx = 0;; idx++) { 185bb1599b6SGerd Hoffmann con = qemu_console_lookup_by_index(idx); 186bb1599b6SGerd Hoffmann if (!con || !qemu_console_is_graphic(con)) { 187bb1599b6SGerd Hoffmann break; 188bb1599b6SGerd Hoffmann } 189bb1599b6SGerd Hoffmann 190bb1599b6SGerd Hoffmann edpy = g_new0(egl_dpy, 1); 191bb1599b6SGerd Hoffmann edpy->dcl.con = con; 192bb1599b6SGerd Hoffmann edpy->dcl.ops = &egl_ops; 193a3517917SGerd Hoffmann edpy->gls = qemu_gl_init_shader(); 194bb1599b6SGerd Hoffmann register_displaychangelistener(&edpy->dcl); 195bb1599b6SGerd Hoffmann } 196bb1599b6SGerd Hoffmann } 19716ab0a74SGerd Hoffmann 19816ab0a74SGerd Hoffmann static QemuDisplay qemu_display_egl = { 19916ab0a74SGerd Hoffmann .type = DISPLAY_TYPE_EGL_HEADLESS, 20016ab0a74SGerd Hoffmann .early_init = early_egl_headless_init, 20116ab0a74SGerd Hoffmann .init = egl_headless_init, 20216ab0a74SGerd Hoffmann }; 20316ab0a74SGerd Hoffmann 20416ab0a74SGerd Hoffmann static void register_egl(void) 20516ab0a74SGerd Hoffmann { 20616ab0a74SGerd Hoffmann qemu_display_register(&qemu_display_egl); 20716ab0a74SGerd Hoffmann } 20816ab0a74SGerd Hoffmann 20916ab0a74SGerd Hoffmann type_init(register_egl); 210