Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 1 | #include "qemu/osdep.h" |
Thomas Huth | 5feed38 | 2023-02-10 12:19:31 +0100 | [diff] [blame] | 2 | #include "qemu/error-report.h" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 3 | #include "qemu/module.h" |
Marc-André Lureau | 0e1be59 | 2023-02-14 16:11:24 +0400 | [diff] [blame] | 4 | #include "qapi/error.h" |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 5 | #include "ui/console.h" |
| 6 | #include "ui/egl-helpers.h" |
| 7 | #include "ui/egl-context.h" |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 8 | #include "ui/shader.h" |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 9 | |
| 10 | typedef struct egl_dpy { |
| 11 | DisplayChangeListener dcl; |
| 12 | DisplaySurface *ds; |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 13 | QemuGLShader *gls; |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 14 | egl_fb guest_fb; |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 15 | egl_fb cursor_fb; |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 16 | egl_fb blit_fb; |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 17 | bool y_0_top; |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 18 | uint32_t pos_x; |
| 19 | uint32_t pos_y; |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 20 | } egl_dpy; |
| 21 | |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 22 | /* ------------------------------------------------------------------ */ |
| 23 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 24 | static void egl_refresh(DisplayChangeListener *dcl) |
| 25 | { |
| 26 | graphic_hw_update(dcl->con); |
| 27 | } |
| 28 | |
| 29 | static void egl_gfx_update(DisplayChangeListener *dcl, |
| 30 | int x, int y, int w, int h) |
| 31 | { |
| 32 | } |
| 33 | |
| 34 | static void egl_gfx_switch(DisplayChangeListener *dcl, |
| 35 | struct DisplaySurface *new_surface) |
| 36 | { |
| 37 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
| 38 | |
| 39 | edpy->ds = new_surface; |
| 40 | } |
| 41 | |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 42 | static QEMUGLContext egl_create_context(DisplayGLCtx *dgc, |
Gerd Hoffmann | 952e5d5 | 2018-11-29 13:35:02 +0100 | [diff] [blame] | 43 | QEMUGLParams *params) |
| 44 | { |
| 45 | eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, |
| 46 | qemu_egl_rn_ctx); |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 47 | return qemu_egl_create_context(dgc, params); |
Gerd Hoffmann | 952e5d5 | 2018-11-29 13:35:02 +0100 | [diff] [blame] | 48 | } |
| 49 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 50 | static void egl_scanout_disable(DisplayChangeListener *dcl) |
| 51 | { |
| 52 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
| 53 | |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 54 | egl_fb_destroy(&edpy->guest_fb); |
| 55 | egl_fb_destroy(&edpy->blit_fb); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | static void egl_scanout_texture(DisplayChangeListener *dcl, |
| 59 | uint32_t backing_id, |
| 60 | bool backing_y_0_top, |
| 61 | uint32_t backing_width, |
| 62 | uint32_t backing_height, |
| 63 | uint32_t x, uint32_t y, |
Marc-André Lureau | bf41ab6 | 2023-06-06 15:56:56 +0400 | [diff] [blame] | 64 | uint32_t w, uint32_t h, |
| 65 | void *d3d_tex2d) |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 66 | { |
| 67 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
| 68 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 69 | edpy->y_0_top = backing_y_0_top; |
| 70 | |
| 71 | /* source framebuffer */ |
Gerd Hoffmann | 74083f9 | 2017-09-27 13:50:31 +0200 | [diff] [blame] | 72 | egl_fb_setup_for_tex(&edpy->guest_fb, |
| 73 | backing_width, backing_height, backing_id, false); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 74 | |
| 75 | /* dest framebuffer */ |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 76 | if (edpy->blit_fb.width != backing_width || |
| 77 | edpy->blit_fb.height != backing_height) { |
| 78 | egl_fb_destroy(&edpy->blit_fb); |
Gerd Hoffmann | 74083f9 | 2017-09-27 13:50:31 +0200 | [diff] [blame] | 79 | egl_fb_setup_new_tex(&edpy->blit_fb, backing_width, backing_height); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 80 | } |
| 81 | } |
| 82 | |
Marc-André Lureau | 39324b4 | 2023-06-06 15:56:49 +0400 | [diff] [blame] | 83 | #ifdef CONFIG_GBM |
| 84 | |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 85 | static void egl_scanout_dmabuf(DisplayChangeListener *dcl, |
| 86 | QemuDmaBuf *dmabuf) |
| 87 | { |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 88 | uint32_t width, height, texture; |
| 89 | |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 90 | egl_dmabuf_import_texture(dmabuf); |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 91 | texture = qemu_dmabuf_get_texture(dmabuf); |
| 92 | if (!texture) { |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 93 | return; |
| 94 | } |
| 95 | |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 96 | width = qemu_dmabuf_get_width(dmabuf); |
| 97 | height = qemu_dmabuf_get_height(dmabuf); |
| 98 | |
| 99 | egl_scanout_texture(dcl, texture, false, width, height, 0, 0, |
| 100 | width, height, NULL); |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | static void egl_cursor_dmabuf(DisplayChangeListener *dcl, |
Gerd Hoffmann | 6e1f2cb | 2018-02-20 12:04:31 +0100 | [diff] [blame] | 104 | QemuDmaBuf *dmabuf, bool have_hot, |
| 105 | uint32_t hot_x, uint32_t hot_y) |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 106 | { |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 107 | uint32_t width, height, texture; |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 108 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
| 109 | |
Gerd Hoffmann | b091692 | 2018-02-20 12:04:32 +0100 | [diff] [blame] | 110 | if (dmabuf) { |
| 111 | egl_dmabuf_import_texture(dmabuf); |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 112 | texture = qemu_dmabuf_get_texture(dmabuf); |
| 113 | if (!texture) { |
Gerd Hoffmann | b091692 | 2018-02-20 12:04:32 +0100 | [diff] [blame] | 114 | return; |
| 115 | } |
Dongwon Kim | 6779a30 | 2024-05-08 10:54:00 -0700 | [diff] [blame] | 116 | |
| 117 | width = qemu_dmabuf_get_width(dmabuf); |
| 118 | height = qemu_dmabuf_get_height(dmabuf); |
| 119 | egl_fb_setup_for_tex(&edpy->cursor_fb, width, height, texture, false); |
Gerd Hoffmann | b091692 | 2018-02-20 12:04:32 +0100 | [diff] [blame] | 120 | } else { |
| 121 | egl_fb_destroy(&edpy->cursor_fb); |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 122 | } |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 123 | } |
| 124 | |
Marc-André Lureau | 39324b4 | 2023-06-06 15:56:49 +0400 | [diff] [blame] | 125 | static void egl_release_dmabuf(DisplayChangeListener *dcl, |
| 126 | QemuDmaBuf *dmabuf) |
| 127 | { |
| 128 | egl_dmabuf_release_texture(dmabuf); |
| 129 | } |
| 130 | |
| 131 | #endif |
| 132 | |
Gerd Hoffmann | 6e1f2cb | 2018-02-20 12:04:31 +0100 | [diff] [blame] | 133 | static void egl_cursor_position(DisplayChangeListener *dcl, |
| 134 | uint32_t pos_x, uint32_t pos_y) |
| 135 | { |
| 136 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
| 137 | |
| 138 | edpy->pos_x = pos_x; |
| 139 | edpy->pos_y = pos_y; |
| 140 | } |
| 141 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 142 | static void egl_scanout_flush(DisplayChangeListener *dcl, |
| 143 | uint32_t x, uint32_t y, |
| 144 | uint32_t w, uint32_t h) |
| 145 | { |
| 146 | egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 147 | |
Gerd Hoffmann | d8dc67e | 2017-06-14 10:41:47 +0200 | [diff] [blame] | 148 | if (!edpy->guest_fb.texture || !edpy->ds) { |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 149 | return; |
| 150 | } |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 151 | assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8); |
| 152 | |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 153 | if (edpy->cursor_fb.texture) { |
| 154 | /* have cursor -> render using textures */ |
| 155 | egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb, |
| 156 | !edpy->y_0_top); |
| 157 | egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb, |
Chen Zhang | 051a0cd | 2019-01-25 15:47:23 +0800 | [diff] [blame] | 158 | !edpy->y_0_top, edpy->pos_x, edpy->pos_y, |
| 159 | 1.0, 1.0); |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 160 | } else { |
| 161 | /* no cursor -> use simple framebuffer blit */ |
| 162 | egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top); |
| 163 | } |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 164 | |
Gerd Hoffmann | d232923 | 2019-09-09 09:39:11 +0200 | [diff] [blame] | 165 | egl_fb_read(edpy->ds, &edpy->blit_fb); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 166 | dpy_gfx_update(edpy->dcl.con, x, y, w, h); |
| 167 | } |
| 168 | |
| 169 | static const DisplayChangeListenerOps egl_ops = { |
| 170 | .dpy_name = "egl-headless", |
| 171 | .dpy_refresh = egl_refresh, |
| 172 | .dpy_gfx_update = egl_gfx_update, |
| 173 | .dpy_gfx_switch = egl_gfx_switch, |
| 174 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 175 | .dpy_gl_scanout_disable = egl_scanout_disable, |
| 176 | .dpy_gl_scanout_texture = egl_scanout_texture, |
Marc-André Lureau | 39324b4 | 2023-06-06 15:56:49 +0400 | [diff] [blame] | 177 | #ifdef CONFIG_GBM |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 178 | .dpy_gl_scanout_dmabuf = egl_scanout_dmabuf, |
| 179 | .dpy_gl_cursor_dmabuf = egl_cursor_dmabuf, |
| 180 | .dpy_gl_release_dmabuf = egl_release_dmabuf, |
Marc-André Lureau | 39324b4 | 2023-06-06 15:56:49 +0400 | [diff] [blame] | 181 | #endif |
| 182 | .dpy_gl_cursor_position = egl_cursor_position, |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 183 | .dpy_gl_update = egl_scanout_flush, |
| 184 | }; |
| 185 | |
Marc-André Lureau | a62c4a1 | 2022-02-16 19:33:37 +0400 | [diff] [blame] | 186 | static bool |
| 187 | egl_is_compatible_dcl(DisplayGLCtx *dgc, |
| 188 | DisplayChangeListener *dcl) |
| 189 | { |
Marc-André Lureau | cd19c25 | 2022-02-16 19:42:40 +0400 | [diff] [blame] | 190 | if (!dcl->ops->dpy_gl_update) { |
| 191 | /* |
| 192 | * egl-headless is compatible with all 2d listeners, as it blits the GL |
| 193 | * updates on the 2d console surface. |
| 194 | */ |
| 195 | return true; |
| 196 | } |
| 197 | |
Marc-André Lureau | a62c4a1 | 2022-02-16 19:33:37 +0400 | [diff] [blame] | 198 | return dcl->ops == &egl_ops; |
| 199 | } |
| 200 | |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 201 | static const DisplayGLCtxOps eglctx_ops = { |
Marc-André Lureau | a62c4a1 | 2022-02-16 19:33:37 +0400 | [diff] [blame] | 202 | .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl, |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 203 | .dpy_gl_ctx_create = egl_create_context, |
| 204 | .dpy_gl_ctx_destroy = qemu_egl_destroy_context, |
| 205 | .dpy_gl_ctx_make_current = qemu_egl_make_context_current, |
| 206 | }; |
| 207 | |
Gerd Hoffmann | 16ab0a7 | 2018-03-01 11:05:39 +0100 | [diff] [blame] | 208 | static void early_egl_headless_init(DisplayOptions *opts) |
| 209 | { |
Markus Armbruster | 154fd4d | 2024-09-04 13:18:25 +0200 | [diff] [blame] | 210 | DisplayGLMode mode = DISPLAY_GL_MODE_ON; |
Marc-André Lureau | 0e1be59 | 2023-02-14 16:11:24 +0400 | [diff] [blame] | 211 | |
| 212 | if (opts->has_gl) { |
| 213 | mode = opts->gl; |
| 214 | } |
| 215 | |
| 216 | egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal); |
Gerd Hoffmann | 16ab0a7 | 2018-03-01 11:05:39 +0100 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | static void egl_headless_init(DisplayState *ds, DisplayOptions *opts) |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 220 | { |
| 221 | QemuConsole *con; |
| 222 | egl_dpy *edpy; |
| 223 | int idx; |
| 224 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 225 | for (idx = 0;; idx++) { |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 226 | DisplayGLCtx *ctx; |
| 227 | |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 228 | con = qemu_console_lookup_by_index(idx); |
| 229 | if (!con || !qemu_console_is_graphic(con)) { |
| 230 | break; |
| 231 | } |
| 232 | |
| 233 | edpy = g_new0(egl_dpy, 1); |
| 234 | edpy->dcl.con = con; |
| 235 | edpy->dcl.ops = &egl_ops; |
Gerd Hoffmann | a351791 | 2017-10-10 15:54:53 +0200 | [diff] [blame] | 236 | edpy->gls = qemu_gl_init_shader(); |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 237 | ctx = g_new0(DisplayGLCtx, 1); |
| 238 | ctx->ops = &eglctx_ops; |
| 239 | qemu_console_set_display_gl_ctx(con, ctx); |
Gerd Hoffmann | bb1599b | 2017-05-05 12:41:01 +0200 | [diff] [blame] | 240 | register_displaychangelistener(&edpy->dcl); |
| 241 | } |
| 242 | } |
Gerd Hoffmann | 16ab0a7 | 2018-03-01 11:05:39 +0100 | [diff] [blame] | 243 | |
| 244 | static QemuDisplay qemu_display_egl = { |
| 245 | .type = DISPLAY_TYPE_EGL_HEADLESS, |
| 246 | .early_init = early_egl_headless_init, |
| 247 | .init = egl_headless_init, |
| 248 | }; |
| 249 | |
| 250 | static void register_egl(void) |
| 251 | { |
| 252 | qemu_display_register(&qemu_display_egl); |
| 253 | } |
| 254 | |
| 255 | type_init(register_egl); |
Gerd Hoffmann | b36ae1c | 2021-06-24 12:38:13 +0200 | [diff] [blame] | 256 | |
Gerd Hoffmann | b36ae1c | 2021-06-24 12:38:13 +0200 | [diff] [blame] | 257 | module_dep("ui-opengl"); |