xref: /qemu/ui/egl-headless.c (revision a35179170034b60bcfb997e06bc63258caaf5049)
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"
7*a3517917SGerd Hoffmann #include "ui/shader.h"
8bb1599b6SGerd Hoffmann 
9bb1599b6SGerd Hoffmann typedef struct egl_dpy {
10bb1599b6SGerd Hoffmann     DisplayChangeListener dcl;
11bb1599b6SGerd Hoffmann     DisplaySurface *ds;
12*a3517917SGerd Hoffmann     QemuGLShader *gls;
13d8dc67e1SGerd Hoffmann     egl_fb guest_fb;
14*a3517917SGerd Hoffmann     egl_fb cursor_fb;
15d8dc67e1SGerd Hoffmann     egl_fb blit_fb;
16bb1599b6SGerd Hoffmann     bool y_0_top;
17*a3517917SGerd Hoffmann     uint32_t pos_x;
18*a3517917SGerd 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 
73*a3517917SGerd Hoffmann static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
74*a3517917SGerd Hoffmann                                QemuDmaBuf *dmabuf)
75*a3517917SGerd Hoffmann {
76*a3517917SGerd Hoffmann     egl_dmabuf_import_texture(dmabuf);
77*a3517917SGerd Hoffmann     if (!dmabuf->texture) {
78*a3517917SGerd Hoffmann         return;
79*a3517917SGerd Hoffmann     }
80*a3517917SGerd Hoffmann 
81*a3517917SGerd Hoffmann     egl_scanout_texture(dcl, dmabuf->texture,
82*a3517917SGerd Hoffmann                         false, dmabuf->width, dmabuf->height,
83*a3517917SGerd Hoffmann                         0, 0, dmabuf->width, dmabuf->height);
84*a3517917SGerd Hoffmann }
85*a3517917SGerd Hoffmann 
86*a3517917SGerd Hoffmann static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
87*a3517917SGerd Hoffmann                               QemuDmaBuf *dmabuf,
88*a3517917SGerd Hoffmann                               uint32_t pos_x, uint32_t pos_y)
89*a3517917SGerd Hoffmann {
90*a3517917SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
91*a3517917SGerd Hoffmann 
92*a3517917SGerd Hoffmann     edpy->pos_x = pos_x;
93*a3517917SGerd Hoffmann     edpy->pos_y = pos_y;
94*a3517917SGerd Hoffmann 
95*a3517917SGerd Hoffmann     egl_dmabuf_import_texture(dmabuf);
96*a3517917SGerd Hoffmann     if (!dmabuf->texture) {
97*a3517917SGerd Hoffmann         return;
98*a3517917SGerd Hoffmann     }
99*a3517917SGerd Hoffmann 
100*a3517917SGerd Hoffmann     egl_fb_setup_for_tex(&edpy->cursor_fb, dmabuf->width, dmabuf->height,
101*a3517917SGerd Hoffmann                          dmabuf->texture, false);
102*a3517917SGerd Hoffmann }
103*a3517917SGerd Hoffmann 
104*a3517917SGerd Hoffmann static void egl_release_dmabuf(DisplayChangeListener *dcl,
105*a3517917SGerd Hoffmann                                QemuDmaBuf *dmabuf)
106*a3517917SGerd Hoffmann {
107*a3517917SGerd Hoffmann     egl_dmabuf_release_texture(dmabuf);
108*a3517917SGerd Hoffmann }
109*a3517917SGerd Hoffmann 
110bb1599b6SGerd Hoffmann static void egl_scanout_flush(DisplayChangeListener *dcl,
111bb1599b6SGerd Hoffmann                               uint32_t x, uint32_t y,
112bb1599b6SGerd Hoffmann                               uint32_t w, uint32_t h)
113bb1599b6SGerd Hoffmann {
114bb1599b6SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
115bb1599b6SGerd Hoffmann 
116d8dc67e1SGerd Hoffmann     if (!edpy->guest_fb.texture || !edpy->ds) {
117bb1599b6SGerd Hoffmann         return;
118bb1599b6SGerd Hoffmann     }
119d8dc67e1SGerd Hoffmann     assert(surface_width(edpy->ds)  == edpy->guest_fb.width);
120d8dc67e1SGerd Hoffmann     assert(surface_height(edpy->ds) == edpy->guest_fb.height);
121bb1599b6SGerd Hoffmann     assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
122bb1599b6SGerd Hoffmann 
123*a3517917SGerd Hoffmann     if (edpy->cursor_fb.texture) {
124*a3517917SGerd Hoffmann         /* have cursor -> render using textures */
125*a3517917SGerd Hoffmann         egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
126*a3517917SGerd Hoffmann                          !edpy->y_0_top);
127*a3517917SGerd Hoffmann         egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
128*a3517917SGerd Hoffmann                           !edpy->y_0_top, edpy->pos_x, edpy->pos_y);
129*a3517917SGerd Hoffmann     } else {
130*a3517917SGerd Hoffmann         /* no cursor -> use simple framebuffer blit */
131d8dc67e1SGerd Hoffmann         egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
132*a3517917SGerd Hoffmann     }
133bb1599b6SGerd Hoffmann 
134*a3517917SGerd Hoffmann     egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb);
135bb1599b6SGerd Hoffmann     dpy_gfx_update(edpy->dcl.con, x, y, w, h);
136bb1599b6SGerd Hoffmann }
137bb1599b6SGerd Hoffmann 
138bb1599b6SGerd Hoffmann static const DisplayChangeListenerOps egl_ops = {
139bb1599b6SGerd Hoffmann     .dpy_name                = "egl-headless",
140bb1599b6SGerd Hoffmann     .dpy_refresh             = egl_refresh,
141bb1599b6SGerd Hoffmann     .dpy_gfx_update          = egl_gfx_update,
142bb1599b6SGerd Hoffmann     .dpy_gfx_switch          = egl_gfx_switch,
143bb1599b6SGerd Hoffmann 
144bb1599b6SGerd Hoffmann     .dpy_gl_ctx_create       = qemu_egl_create_context,
145bb1599b6SGerd Hoffmann     .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,
146bb1599b6SGerd Hoffmann     .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
147bb1599b6SGerd Hoffmann     .dpy_gl_ctx_get_current  = qemu_egl_get_current_context,
148bb1599b6SGerd Hoffmann 
149bb1599b6SGerd Hoffmann     .dpy_gl_scanout_disable  = egl_scanout_disable,
150bb1599b6SGerd Hoffmann     .dpy_gl_scanout_texture  = egl_scanout_texture,
151*a3517917SGerd Hoffmann     .dpy_gl_scanout_dmabuf   = egl_scanout_dmabuf,
152*a3517917SGerd Hoffmann     .dpy_gl_cursor_dmabuf    = egl_cursor_dmabuf,
153*a3517917SGerd Hoffmann     .dpy_gl_release_dmabuf   = egl_release_dmabuf,
154bb1599b6SGerd Hoffmann     .dpy_gl_update           = egl_scanout_flush,
155bb1599b6SGerd Hoffmann };
156bb1599b6SGerd Hoffmann 
157bb1599b6SGerd Hoffmann void egl_headless_init(void)
158bb1599b6SGerd Hoffmann {
159bb1599b6SGerd Hoffmann     QemuConsole *con;
160bb1599b6SGerd Hoffmann     egl_dpy *edpy;
161bb1599b6SGerd Hoffmann     int idx;
162bb1599b6SGerd Hoffmann 
163bb1599b6SGerd Hoffmann     if (egl_rendernode_init(NULL) < 0) {
164bb1599b6SGerd Hoffmann         error_report("egl: render node init failed");
165bb1599b6SGerd Hoffmann         exit(1);
166bb1599b6SGerd Hoffmann     }
167bb1599b6SGerd Hoffmann 
168bb1599b6SGerd Hoffmann     for (idx = 0;; idx++) {
169bb1599b6SGerd Hoffmann         con = qemu_console_lookup_by_index(idx);
170bb1599b6SGerd Hoffmann         if (!con || !qemu_console_is_graphic(con)) {
171bb1599b6SGerd Hoffmann             break;
172bb1599b6SGerd Hoffmann         }
173bb1599b6SGerd Hoffmann 
174bb1599b6SGerd Hoffmann         edpy = g_new0(egl_dpy, 1);
175bb1599b6SGerd Hoffmann         edpy->dcl.con = con;
176bb1599b6SGerd Hoffmann         edpy->dcl.ops = &egl_ops;
177*a3517917SGerd Hoffmann         edpy->gls = qemu_gl_init_shader();
178bb1599b6SGerd Hoffmann         register_displaychangelistener(&edpy->dcl);
179bb1599b6SGerd Hoffmann     }
180bb1599b6SGerd Hoffmann }
181