xref: /qemu/ui/egl-headless.c (revision 0d2dd9f0096327831121e2e4b75249b551f8d8ef)
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,
87a3517917SGerd Hoffmann                               QemuDmaBuf *dmabuf,
88a3517917SGerd Hoffmann                               uint32_t pos_x, uint32_t pos_y)
89a3517917SGerd Hoffmann {
90a3517917SGerd Hoffmann     egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
91a3517917SGerd Hoffmann 
92a3517917SGerd Hoffmann     edpy->pos_x = pos_x;
93a3517917SGerd Hoffmann     edpy->pos_y = pos_y;
94a3517917SGerd Hoffmann 
95a3517917SGerd Hoffmann     egl_dmabuf_import_texture(dmabuf);
96a3517917SGerd Hoffmann     if (!dmabuf->texture) {
97a3517917SGerd Hoffmann         return;
98a3517917SGerd Hoffmann     }
99a3517917SGerd Hoffmann 
100a3517917SGerd Hoffmann     egl_fb_setup_for_tex(&edpy->cursor_fb, dmabuf->width, dmabuf->height,
101a3517917SGerd Hoffmann                          dmabuf->texture, false);
102a3517917SGerd Hoffmann }
103a3517917SGerd Hoffmann 
104a3517917SGerd Hoffmann static void egl_release_dmabuf(DisplayChangeListener *dcl,
105a3517917SGerd Hoffmann                                QemuDmaBuf *dmabuf)
106a3517917SGerd Hoffmann {
107a3517917SGerd Hoffmann     egl_dmabuf_release_texture(dmabuf);
108a3517917SGerd Hoffmann }
109a3517917SGerd 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 
123a3517917SGerd Hoffmann     if (edpy->cursor_fb.texture) {
124a3517917SGerd Hoffmann         /* have cursor -> render using textures */
125a3517917SGerd Hoffmann         egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
126a3517917SGerd Hoffmann                          !edpy->y_0_top);
127a3517917SGerd Hoffmann         egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
128a3517917SGerd Hoffmann                           !edpy->y_0_top, edpy->pos_x, edpy->pos_y);
129a3517917SGerd Hoffmann     } else {
130a3517917SGerd Hoffmann         /* no cursor -> use simple framebuffer blit */
131d8dc67e1SGerd Hoffmann         egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
132a3517917SGerd Hoffmann     }
133bb1599b6SGerd Hoffmann 
134a3517917SGerd 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,
151a3517917SGerd Hoffmann     .dpy_gl_scanout_dmabuf   = egl_scanout_dmabuf,
152a3517917SGerd Hoffmann     .dpy_gl_cursor_dmabuf    = egl_cursor_dmabuf,
153a3517917SGerd Hoffmann     .dpy_gl_release_dmabuf   = egl_release_dmabuf,
154bb1599b6SGerd Hoffmann     .dpy_gl_update           = egl_scanout_flush,
155bb1599b6SGerd Hoffmann };
156bb1599b6SGerd Hoffmann 
157*0d2dd9f0SGerd Hoffmann void egl_headless_init(DisplayOptions *opts)
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;
177a3517917SGerd Hoffmann         edpy->gls = qemu_gl_init_shader();
178bb1599b6SGerd Hoffmann         register_displaychangelistener(&edpy->dcl);
179bb1599b6SGerd Hoffmann     }
180bb1599b6SGerd Hoffmann }
181