xref: /qemu/ui/egl-headless.c (revision 91e61947eb2be21b00091d34f5692f89cef41376)
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