1 #include "qemu/osdep.h" 2 #include "qemu-common.h" 3 #include "sysemu/sysemu.h" 4 #include "ui/console.h" 5 #include "ui/egl-helpers.h" 6 #include "ui/egl-context.h" 7 8 typedef struct egl_dpy { 9 DisplayChangeListener dcl; 10 DisplaySurface *ds; 11 egl_fb guest_fb; 12 egl_fb blit_fb; 13 bool y_0_top; 14 } egl_dpy; 15 16 /* ------------------------------------------------------------------ */ 17 18 static void egl_refresh(DisplayChangeListener *dcl) 19 { 20 graphic_hw_update(dcl->con); 21 } 22 23 static void egl_gfx_update(DisplayChangeListener *dcl, 24 int x, int y, int w, int h) 25 { 26 } 27 28 static void egl_gfx_switch(DisplayChangeListener *dcl, 29 struct DisplaySurface *new_surface) 30 { 31 egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 32 33 edpy->ds = new_surface; 34 } 35 36 static void egl_scanout_disable(DisplayChangeListener *dcl) 37 { 38 egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 39 40 egl_fb_destroy(&edpy->guest_fb); 41 egl_fb_destroy(&edpy->blit_fb); 42 } 43 44 static void egl_scanout_texture(DisplayChangeListener *dcl, 45 uint32_t backing_id, 46 bool backing_y_0_top, 47 uint32_t backing_width, 48 uint32_t backing_height, 49 uint32_t x, uint32_t y, 50 uint32_t w, uint32_t h) 51 { 52 egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 53 54 edpy->y_0_top = backing_y_0_top; 55 56 /* source framebuffer */ 57 egl_fb_create_for_tex(&edpy->guest_fb, 58 backing_width, backing_height, backing_id); 59 60 /* dest framebuffer */ 61 if (edpy->blit_fb.width != backing_width || 62 edpy->blit_fb.height != backing_height) { 63 egl_fb_destroy(&edpy->blit_fb); 64 egl_fb_create_new_tex(&edpy->blit_fb, backing_width, backing_height); 65 } 66 } 67 68 static void egl_scanout_flush(DisplayChangeListener *dcl, 69 uint32_t x, uint32_t y, 70 uint32_t w, uint32_t h) 71 { 72 egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); 73 74 if (!edpy->guest_fb.texture || !edpy->ds) { 75 return; 76 } 77 assert(surface_width(edpy->ds) == edpy->guest_fb.width); 78 assert(surface_height(edpy->ds) == edpy->guest_fb.height); 79 assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8); 80 81 egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top); 82 egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb); 83 84 dpy_gfx_update(edpy->dcl.con, x, y, w, h); 85 } 86 87 static const DisplayChangeListenerOps egl_ops = { 88 .dpy_name = "egl-headless", 89 .dpy_refresh = egl_refresh, 90 .dpy_gfx_update = egl_gfx_update, 91 .dpy_gfx_switch = egl_gfx_switch, 92 93 .dpy_gl_ctx_create = qemu_egl_create_context, 94 .dpy_gl_ctx_destroy = qemu_egl_destroy_context, 95 .dpy_gl_ctx_make_current = qemu_egl_make_context_current, 96 .dpy_gl_ctx_get_current = qemu_egl_get_current_context, 97 98 .dpy_gl_scanout_disable = egl_scanout_disable, 99 .dpy_gl_scanout_texture = egl_scanout_texture, 100 .dpy_gl_update = egl_scanout_flush, 101 }; 102 103 void egl_headless_init(void) 104 { 105 QemuConsole *con; 106 egl_dpy *edpy; 107 int idx; 108 109 if (egl_rendernode_init(NULL) < 0) { 110 error_report("egl: render node init failed"); 111 exit(1); 112 } 113 114 for (idx = 0;; idx++) { 115 con = qemu_console_lookup_by_index(idx); 116 if (!con || !qemu_console_is_graphic(con)) { 117 break; 118 } 119 120 edpy = g_new0(egl_dpy, 1); 121 edpy->dcl.con = con; 122 edpy->dcl.ops = &egl_ops; 123 register_displaychangelistener(&edpy->dcl); 124 } 125 } 126