1bb1599b6SGerd Hoffmann #include "qemu/osdep.h"
25feed38cSThomas Huth #include "qemu/error-report.h"
30b8fa32fSMarkus Armbruster #include "qemu/module.h"
40e1be59eSMarc-André Lureau #include "qapi/error.h"
5bb1599b6SGerd Hoffmann #include "ui/console.h"
6bb1599b6SGerd Hoffmann #include "ui/egl-helpers.h"
7bb1599b6SGerd Hoffmann #include "ui/egl-context.h"
8a3517917SGerd Hoffmann #include "ui/shader.h"
9bb1599b6SGerd Hoffmann
10bb1599b6SGerd Hoffmann typedef struct egl_dpy {
11bb1599b6SGerd Hoffmann DisplayChangeListener dcl;
12bb1599b6SGerd Hoffmann DisplaySurface *ds;
13a3517917SGerd Hoffmann QemuGLShader *gls;
14d8dc67e1SGerd Hoffmann egl_fb guest_fb;
15a3517917SGerd Hoffmann egl_fb cursor_fb;
16d8dc67e1SGerd Hoffmann egl_fb blit_fb;
17bb1599b6SGerd Hoffmann bool y_0_top;
18a3517917SGerd Hoffmann uint32_t pos_x;
19a3517917SGerd Hoffmann uint32_t pos_y;
20bb1599b6SGerd Hoffmann } egl_dpy;
21bb1599b6SGerd Hoffmann
22d8dc67e1SGerd Hoffmann /* ------------------------------------------------------------------ */
23d8dc67e1SGerd Hoffmann
egl_refresh(DisplayChangeListener * dcl)24bb1599b6SGerd Hoffmann static void egl_refresh(DisplayChangeListener *dcl)
25bb1599b6SGerd Hoffmann {
26bb1599b6SGerd Hoffmann graphic_hw_update(dcl->con);
27bb1599b6SGerd Hoffmann }
28bb1599b6SGerd Hoffmann
egl_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)29bb1599b6SGerd Hoffmann static void egl_gfx_update(DisplayChangeListener *dcl,
30bb1599b6SGerd Hoffmann int x, int y, int w, int h)
31bb1599b6SGerd Hoffmann {
32bb1599b6SGerd Hoffmann }
33bb1599b6SGerd Hoffmann
egl_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)34bb1599b6SGerd Hoffmann static void egl_gfx_switch(DisplayChangeListener *dcl,
35bb1599b6SGerd Hoffmann struct DisplaySurface *new_surface)
36bb1599b6SGerd Hoffmann {
37bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
38bb1599b6SGerd Hoffmann
39bb1599b6SGerd Hoffmann edpy->ds = new_surface;
40bb1599b6SGerd Hoffmann }
41bb1599b6SGerd Hoffmann
egl_create_context(DisplayGLCtx * dgc,QEMUGLParams * params)425e79d516SMarc-André Lureau static QEMUGLContext egl_create_context(DisplayGLCtx *dgc,
43952e5d58SGerd Hoffmann QEMUGLParams *params)
44952e5d58SGerd Hoffmann {
45952e5d58SGerd Hoffmann eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
46952e5d58SGerd Hoffmann qemu_egl_rn_ctx);
475e79d516SMarc-André Lureau return qemu_egl_create_context(dgc, params);
48952e5d58SGerd Hoffmann }
49952e5d58SGerd Hoffmann
egl_scanout_disable(DisplayChangeListener * dcl)50bb1599b6SGerd Hoffmann static void egl_scanout_disable(DisplayChangeListener *dcl)
51bb1599b6SGerd Hoffmann {
52bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
53bb1599b6SGerd Hoffmann
54d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->guest_fb);
55d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb);
56bb1599b6SGerd Hoffmann }
57bb1599b6SGerd Hoffmann
egl_scanout_texture(DisplayChangeListener * dcl,uint32_t backing_id,bool backing_y_0_top,uint32_t backing_width,uint32_t backing_height,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * d3d_tex2d)58bb1599b6SGerd Hoffmann static void egl_scanout_texture(DisplayChangeListener *dcl,
59bb1599b6SGerd Hoffmann uint32_t backing_id,
60bb1599b6SGerd Hoffmann bool backing_y_0_top,
61bb1599b6SGerd Hoffmann uint32_t backing_width,
62bb1599b6SGerd Hoffmann uint32_t backing_height,
63bb1599b6SGerd Hoffmann uint32_t x, uint32_t y,
64bf41ab61SMarc-André Lureau uint32_t w, uint32_t h,
65bf41ab61SMarc-André Lureau void *d3d_tex2d)
66bb1599b6SGerd Hoffmann {
67bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
68bb1599b6SGerd Hoffmann
69bb1599b6SGerd Hoffmann edpy->y_0_top = backing_y_0_top;
70bb1599b6SGerd Hoffmann
71bb1599b6SGerd Hoffmann /* source framebuffer */
7274083f9cSGerd Hoffmann egl_fb_setup_for_tex(&edpy->guest_fb,
7374083f9cSGerd Hoffmann backing_width, backing_height, backing_id, false);
74bb1599b6SGerd Hoffmann
75bb1599b6SGerd Hoffmann /* dest framebuffer */
76d8dc67e1SGerd Hoffmann if (edpy->blit_fb.width != backing_width ||
77d8dc67e1SGerd Hoffmann edpy->blit_fb.height != backing_height) {
78d8dc67e1SGerd Hoffmann egl_fb_destroy(&edpy->blit_fb);
7974083f9cSGerd Hoffmann egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height);
80bb1599b6SGerd Hoffmann }
81bb1599b6SGerd Hoffmann }
82bb1599b6SGerd Hoffmann
8339324b49SMarc-André Lureau #ifdef CONFIG_GBM
8439324b49SMarc-André Lureau
egl_scanout_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)85a3517917SGerd Hoffmann static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
86a3517917SGerd Hoffmann QemuDmaBuf *dmabuf)
87a3517917SGerd Hoffmann {
886779a307SDongwon Kim uint32_t width, height, texture;
896779a307SDongwon Kim
90a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf);
916779a307SDongwon Kim texture = qemu_dmabuf_get_texture(dmabuf);
926779a307SDongwon Kim if (!texture) {
93a3517917SGerd Hoffmann return;
94a3517917SGerd Hoffmann }
95a3517917SGerd Hoffmann
966779a307SDongwon Kim width = qemu_dmabuf_get_width(dmabuf);
976779a307SDongwon Kim height = qemu_dmabuf_get_height(dmabuf);
986779a307SDongwon Kim
996779a307SDongwon Kim egl_scanout_texture(dcl, texture, false, width, height, 0, 0,
1006779a307SDongwon Kim width, height, NULL);
101a3517917SGerd Hoffmann }
102a3517917SGerd Hoffmann
egl_cursor_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf,bool have_hot,uint32_t hot_x,uint32_t hot_y)103a3517917SGerd Hoffmann static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
1046e1f2cb5SGerd Hoffmann QemuDmaBuf *dmabuf, bool have_hot,
1056e1f2cb5SGerd Hoffmann uint32_t hot_x, uint32_t hot_y)
106a3517917SGerd Hoffmann {
1076779a307SDongwon Kim uint32_t width, height, texture;
108a3517917SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
109a3517917SGerd Hoffmann
110b0916928SGerd Hoffmann if (dmabuf) {
111a3517917SGerd Hoffmann egl_dmabuf_import_texture(dmabuf);
1126779a307SDongwon Kim texture = qemu_dmabuf_get_texture(dmabuf);
1136779a307SDongwon Kim if (!texture) {
114a3517917SGerd Hoffmann return;
115a3517917SGerd Hoffmann }
1166779a307SDongwon Kim
1176779a307SDongwon Kim width = qemu_dmabuf_get_width(dmabuf);
1186779a307SDongwon Kim height = qemu_dmabuf_get_height(dmabuf);
1196779a307SDongwon Kim egl_fb_setup_for_tex(&edpy->cursor_fb, width, height, texture, false);
120b0916928SGerd Hoffmann } else {
121b0916928SGerd Hoffmann egl_fb_destroy(&edpy->cursor_fb);
122b0916928SGerd Hoffmann }
123a3517917SGerd Hoffmann }
124a3517917SGerd Hoffmann
egl_release_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)12539324b49SMarc-André Lureau static void egl_release_dmabuf(DisplayChangeListener *dcl,
12639324b49SMarc-André Lureau QemuDmaBuf *dmabuf)
12739324b49SMarc-André Lureau {
12839324b49SMarc-André Lureau egl_dmabuf_release_texture(dmabuf);
12939324b49SMarc-André Lureau }
13039324b49SMarc-André Lureau
13139324b49SMarc-André Lureau #endif
13239324b49SMarc-André Lureau
egl_cursor_position(DisplayChangeListener * dcl,uint32_t pos_x,uint32_t pos_y)1336e1f2cb5SGerd Hoffmann static void egl_cursor_position(DisplayChangeListener *dcl,
1346e1f2cb5SGerd Hoffmann uint32_t pos_x, uint32_t pos_y)
1356e1f2cb5SGerd Hoffmann {
1366e1f2cb5SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
1376e1f2cb5SGerd Hoffmann
1386e1f2cb5SGerd Hoffmann edpy->pos_x = pos_x;
1396e1f2cb5SGerd Hoffmann edpy->pos_y = pos_y;
1406e1f2cb5SGerd Hoffmann }
1416e1f2cb5SGerd Hoffmann
egl_scanout_flush(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)142bb1599b6SGerd Hoffmann static void egl_scanout_flush(DisplayChangeListener *dcl,
143bb1599b6SGerd Hoffmann uint32_t x, uint32_t y,
144bb1599b6SGerd Hoffmann uint32_t w, uint32_t h)
145bb1599b6SGerd Hoffmann {
146bb1599b6SGerd Hoffmann egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
147bb1599b6SGerd Hoffmann
148d8dc67e1SGerd Hoffmann if (!edpy->guest_fb.texture || !edpy->ds) {
149bb1599b6SGerd Hoffmann return;
150bb1599b6SGerd Hoffmann }
151bb1599b6SGerd Hoffmann assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
152bb1599b6SGerd Hoffmann
153a3517917SGerd Hoffmann if (edpy->cursor_fb.texture) {
154a3517917SGerd Hoffmann /* have cursor -> render using textures */
155a3517917SGerd Hoffmann egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
156a3517917SGerd Hoffmann !edpy->y_0_top);
157a3517917SGerd Hoffmann egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
158051a0cdeSChen Zhang !edpy->y_0_top, edpy->pos_x, edpy->pos_y,
159051a0cdeSChen Zhang 1.0, 1.0);
160a3517917SGerd Hoffmann } else {
161a3517917SGerd Hoffmann /* no cursor -> use simple framebuffer blit */
162d8dc67e1SGerd Hoffmann egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
163a3517917SGerd Hoffmann }
164bb1599b6SGerd Hoffmann
165d2329237SGerd Hoffmann egl_fb_read(edpy->ds, &edpy->blit_fb);
166bb1599b6SGerd Hoffmann dpy_gfx_update(edpy->dcl.con, x, y, w, h);
167bb1599b6SGerd Hoffmann }
168bb1599b6SGerd Hoffmann
169bb1599b6SGerd Hoffmann static const DisplayChangeListenerOps egl_ops = {
170bb1599b6SGerd Hoffmann .dpy_name = "egl-headless",
171bb1599b6SGerd Hoffmann .dpy_refresh = egl_refresh,
172bb1599b6SGerd Hoffmann .dpy_gfx_update = egl_gfx_update,
173bb1599b6SGerd Hoffmann .dpy_gfx_switch = egl_gfx_switch,
174bb1599b6SGerd Hoffmann
175bb1599b6SGerd Hoffmann .dpy_gl_scanout_disable = egl_scanout_disable,
176bb1599b6SGerd Hoffmann .dpy_gl_scanout_texture = egl_scanout_texture,
17739324b49SMarc-André Lureau #ifdef CONFIG_GBM
178a3517917SGerd Hoffmann .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf,
179a3517917SGerd Hoffmann .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf,
180a3517917SGerd Hoffmann .dpy_gl_release_dmabuf = egl_release_dmabuf,
18139324b49SMarc-André Lureau #endif
18239324b49SMarc-André Lureau .dpy_gl_cursor_position = egl_cursor_position,
183bb1599b6SGerd Hoffmann .dpy_gl_update = egl_scanout_flush,
184bb1599b6SGerd Hoffmann };
185bb1599b6SGerd Hoffmann
186a62c4a17SMarc-André Lureau static bool
egl_is_compatible_dcl(DisplayGLCtx * dgc,DisplayChangeListener * dcl)187a62c4a17SMarc-André Lureau egl_is_compatible_dcl(DisplayGLCtx *dgc,
188a62c4a17SMarc-André Lureau DisplayChangeListener *dcl)
189a62c4a17SMarc-André Lureau {
190cd19c25fSMarc-André Lureau if (!dcl->ops->dpy_gl_update) {
191cd19c25fSMarc-André Lureau /*
192cd19c25fSMarc-André Lureau * egl-headless is compatible with all 2d listeners, as it blits the GL
193cd19c25fSMarc-André Lureau * updates on the 2d console surface.
194cd19c25fSMarc-André Lureau */
195cd19c25fSMarc-André Lureau return true;
196cd19c25fSMarc-André Lureau }
197cd19c25fSMarc-André Lureau
198a62c4a17SMarc-André Lureau return dcl->ops == &egl_ops;
199a62c4a17SMarc-André Lureau }
200a62c4a17SMarc-André Lureau
2015e79d516SMarc-André Lureau static const DisplayGLCtxOps eglctx_ops = {
202a62c4a17SMarc-André Lureau .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl,
2035e79d516SMarc-André Lureau .dpy_gl_ctx_create = egl_create_context,
2045e79d516SMarc-André Lureau .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
2055e79d516SMarc-André Lureau .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
2065e79d516SMarc-André Lureau };
2075e79d516SMarc-André Lureau
early_egl_headless_init(DisplayOptions * opts)20816ab0a74SGerd Hoffmann static void early_egl_headless_init(DisplayOptions *opts)
20916ab0a74SGerd Hoffmann {
210*154fd4d1SMarkus Armbruster DisplayGLMode mode = DISPLAY_GL_MODE_ON;
2110e1be59eSMarc-André Lureau
2120e1be59eSMarc-André Lureau if (opts->has_gl) {
2130e1be59eSMarc-André Lureau mode = opts->gl;
2140e1be59eSMarc-André Lureau }
2150e1be59eSMarc-André Lureau
2160e1be59eSMarc-André Lureau egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal);
21716ab0a74SGerd Hoffmann }
21816ab0a74SGerd Hoffmann
egl_headless_init(DisplayState * ds,DisplayOptions * opts)21916ab0a74SGerd Hoffmann static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
220bb1599b6SGerd Hoffmann {
221bb1599b6SGerd Hoffmann QemuConsole *con;
222bb1599b6SGerd Hoffmann egl_dpy *edpy;
223bb1599b6SGerd Hoffmann int idx;
224bb1599b6SGerd Hoffmann
225bb1599b6SGerd Hoffmann for (idx = 0;; idx++) {
2265e79d516SMarc-André Lureau DisplayGLCtx *ctx;
2275e79d516SMarc-André Lureau
228bb1599b6SGerd Hoffmann con = qemu_console_lookup_by_index(idx);
229bb1599b6SGerd Hoffmann if (!con || !qemu_console_is_graphic(con)) {
230bb1599b6SGerd Hoffmann break;
231bb1599b6SGerd Hoffmann }
232bb1599b6SGerd Hoffmann
233bb1599b6SGerd Hoffmann edpy = g_new0(egl_dpy, 1);
234bb1599b6SGerd Hoffmann edpy->dcl.con = con;
235bb1599b6SGerd Hoffmann edpy->dcl.ops = &egl_ops;
236a3517917SGerd Hoffmann edpy->gls = qemu_gl_init_shader();
2375e79d516SMarc-André Lureau ctx = g_new0(DisplayGLCtx, 1);
2385e79d516SMarc-André Lureau ctx->ops = &eglctx_ops;
2395e79d516SMarc-André Lureau qemu_console_set_display_gl_ctx(con, ctx);
240bb1599b6SGerd Hoffmann register_displaychangelistener(&edpy->dcl);
241bb1599b6SGerd Hoffmann }
242bb1599b6SGerd Hoffmann }
24316ab0a74SGerd Hoffmann
24416ab0a74SGerd Hoffmann static QemuDisplay qemu_display_egl = {
24516ab0a74SGerd Hoffmann .type = DISPLAY_TYPE_EGL_HEADLESS,
24616ab0a74SGerd Hoffmann .early_init = early_egl_headless_init,
24716ab0a74SGerd Hoffmann .init = egl_headless_init,
24816ab0a74SGerd Hoffmann };
24916ab0a74SGerd Hoffmann
register_egl(void)25016ab0a74SGerd Hoffmann static void register_egl(void)
25116ab0a74SGerd Hoffmann {
25216ab0a74SGerd Hoffmann qemu_display_register(&qemu_display_egl);
25316ab0a74SGerd Hoffmann }
25416ab0a74SGerd Hoffmann
25516ab0a74SGerd Hoffmann type_init(register_egl);
256b36ae1c1SGerd Hoffmann
257b36ae1c1SGerd Hoffmann module_dep("ui-opengl");
258