Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 1 | /* |
| 2 | * GTK UI -- glarea opengl code. |
| 3 | * |
| 4 | * Requires 3.16+ (GtkGLArea widget). |
| 5 | * |
| 6 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 7 | * See the COPYING file in the top-level directory. |
| 8 | */ |
| 9 | |
Peter Maydell | e16f4c8 | 2016-01-29 17:49:51 +0000 | [diff] [blame] | 10 | #include "qemu/osdep.h" |
Vivek Kasireddy | 65b847d | 2021-09-14 14:18:35 -0700 | [diff] [blame] | 11 | #include "qemu/main-loop.h" |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 12 | |
| 13 | #include "trace.h" |
| 14 | |
| 15 | #include "ui/console.h" |
| 16 | #include "ui/gtk.h" |
| 17 | #include "ui/egl-helpers.h" |
| 18 | |
| 19 | #include "sysemu/sysemu.h" |
| 20 | |
| 21 | static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout) |
| 22 | { |
| 23 | if (vc->gfx.scanout_mode == scanout) { |
| 24 | return; |
| 25 | } |
| 26 | |
| 27 | vc->gfx.scanout_mode = scanout; |
| 28 | if (!vc->gfx.scanout_mode) { |
Gerd Hoffmann | a4f113f | 2017-06-14 10:41:49 +0200 | [diff] [blame] | 29 | egl_fb_destroy(&vc->gfx.guest_fb); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 30 | if (vc->gfx.surface) { |
| 31 | surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); |
| 32 | surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); |
| 33 | } |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | /** DisplayState Callbacks (opengl version) **/ |
| 38 | |
| 39 | void gd_gl_area_draw(VirtualConsole *vc) |
| 40 | { |
Dongwon Kim | 55f4b76 | 2021-09-24 15:51:05 -0700 | [diff] [blame] | 41 | #ifdef CONFIG_GBM |
| 42 | QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; |
| 43 | #endif |
Alexander Orzechowski | 4323118 | 2021-11-21 01:55:03 -0500 | [diff] [blame] | 44 | int ww, wh, ws, y1, y2; |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 45 | |
| 46 | if (!vc->gfx.gls) { |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
Alexander Orzechowski | 4323118 | 2021-11-21 01:55:03 -0500 | [diff] [blame] | 51 | ws = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); |
| 52 | ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * ws; |
| 53 | wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * ws; |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 54 | |
| 55 | if (vc->gfx.scanout_mode) { |
Gerd Hoffmann | a4f113f | 2017-06-14 10:41:49 +0200 | [diff] [blame] | 56 | if (!vc->gfx.guest_fb.framebuffer) { |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 57 | return; |
| 58 | } |
| 59 | |
Dongwon Kim | 55f4b76 | 2021-09-24 15:51:05 -0700 | [diff] [blame] | 60 | #ifdef CONFIG_GBM |
| 61 | if (dmabuf) { |
| 62 | if (!dmabuf->draw_submitted) { |
| 63 | return; |
| 64 | } else { |
| 65 | dmabuf->draw_submitted = false; |
| 66 | } |
| 67 | } |
| 68 | #endif |
| 69 | |
Gerd Hoffmann | a4f113f | 2017-06-14 10:41:49 +0200 | [diff] [blame] | 70 | glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 71 | /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ |
| 72 | |
| 73 | glViewport(0, 0, ww, wh); |
| 74 | y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; |
| 75 | y2 = vc->gfx.y0_top ? vc->gfx.h : 0; |
| 76 | glBlitFramebuffer(0, y1, vc->gfx.w, y2, |
| 77 | 0, 0, ww, wh, |
| 78 | GL_COLOR_BUFFER_BIT, GL_NEAREST); |
Dongwon Kim | 55f4b76 | 2021-09-24 15:51:05 -0700 | [diff] [blame] | 79 | #ifdef CONFIG_GBM |
| 80 | if (dmabuf) { |
| 81 | egl_dmabuf_create_sync(dmabuf); |
| 82 | } |
| 83 | #endif |
| 84 | glFlush(); |
| 85 | #ifdef CONFIG_GBM |
| 86 | if (dmabuf) { |
| 87 | egl_dmabuf_create_fence(dmabuf); |
| 88 | if (dmabuf->fence_fd > 0) { |
| 89 | qemu_set_fd_handler(dmabuf->fence_fd, gd_hw_gl_flushed, NULL, vc); |
| 90 | return; |
| 91 | } |
| 92 | graphic_hw_gl_block(vc->gfx.dcl.con, false); |
| 93 | } |
| 94 | #endif |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 95 | } else { |
| 96 | if (!vc->gfx.ds) { |
| 97 | return; |
| 98 | } |
| 99 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 100 | |
| 101 | surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); |
| 102 | surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | void gd_gl_area_update(DisplayChangeListener *dcl, |
| 107 | int x, int y, int w, int h) |
| 108 | { |
| 109 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 110 | |
| 111 | if (!vc->gfx.gls || !vc->gfx.ds) { |
| 112 | return; |
| 113 | } |
| 114 | |
| 115 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 116 | surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h); |
| 117 | vc->gfx.glupdates++; |
| 118 | } |
| 119 | |
| 120 | void gd_gl_area_refresh(DisplayChangeListener *dcl) |
| 121 | { |
| 122 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 123 | |
Akihiko Odaki | aeffd07 | 2022-02-26 20:55:15 +0900 | [diff] [blame] | 124 | gd_update_monitor_refresh_rate(vc, vc->window ? vc->window : vc->gfx.drawing_area); |
Nikola Pavlica | 760deab | 2021-10-24 16:31:10 +0200 | [diff] [blame] | 125 | |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 126 | if (!vc->gfx.gls) { |
| 127 | if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { |
| 128 | return; |
| 129 | } |
| 130 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
Gerd Hoffmann | 46e19e1 | 2017-10-10 15:54:49 +0200 | [diff] [blame] | 131 | vc->gfx.gls = qemu_gl_init_shader(); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 132 | if (vc->gfx.ds) { |
| 133 | surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | graphic_hw_update(dcl->con); |
| 138 | |
| 139 | if (vc->gfx.glupdates) { |
| 140 | vc->gfx.glupdates = 0; |
| 141 | gtk_gl_area_set_scanout_mode(vc, false); |
| 142 | gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | void gd_gl_area_switch(DisplayChangeListener *dcl, |
| 147 | DisplaySurface *surface) |
| 148 | { |
| 149 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 150 | bool resized = true; |
| 151 | |
| 152 | trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); |
| 153 | |
| 154 | if (vc->gfx.ds && |
| 155 | surface_width(vc->gfx.ds) == surface_width(surface) && |
| 156 | surface_height(vc->gfx.ds) == surface_height(surface)) { |
| 157 | resized = false; |
| 158 | } |
| 159 | |
| 160 | if (vc->gfx.gls) { |
| 161 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 162 | surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); |
| 163 | surface_gl_create_texture(vc->gfx.gls, surface); |
| 164 | } |
| 165 | vc->gfx.ds = surface; |
| 166 | |
| 167 | if (resized) { |
| 168 | gd_update_windowsize(vc); |
| 169 | } |
| 170 | } |
| 171 | |
Volker Rümelin | 0905367 | 2022-06-05 10:51:31 +0200 | [diff] [blame] | 172 | static int gd_cmp_gl_context_version(int major, int minor, QEMUGLParams *params) |
| 173 | { |
| 174 | if (major > params->major_ver) { |
| 175 | return 1; |
| 176 | } |
| 177 | if (major < params->major_ver) { |
| 178 | return -1; |
| 179 | } |
| 180 | if (minor > params->minor_ver) { |
| 181 | return 1; |
| 182 | } |
| 183 | if (minor < params->minor_ver) { |
| 184 | return -1; |
| 185 | } |
| 186 | return 0; |
| 187 | } |
| 188 | |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 189 | QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc, |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 190 | QEMUGLParams *params) |
| 191 | { |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 192 | VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 193 | GdkWindow *window; |
| 194 | GdkGLContext *ctx; |
| 195 | GError *err = NULL; |
Volker Rümelin | 0905367 | 2022-06-05 10:51:31 +0200 | [diff] [blame] | 196 | int major, minor; |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 197 | |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 198 | window = gtk_widget_get_window(vc->gfx.drawing_area); |
| 199 | ctx = gdk_window_create_gl_context(window, &err); |
Pan Nengyuan | 2cd1e3f | 2020-08-31 09:43:10 -0400 | [diff] [blame] | 200 | if (err) { |
| 201 | g_printerr("Create gdk gl context failed: %s\n", err->message); |
| 202 | g_error_free(err); |
| 203 | return NULL; |
| 204 | } |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 205 | gdk_gl_context_set_required_version(ctx, |
| 206 | params->major_ver, |
| 207 | params->minor_ver); |
| 208 | gdk_gl_context_realize(ctx, &err); |
Pan Nengyuan | 2cd1e3f | 2020-08-31 09:43:10 -0400 | [diff] [blame] | 209 | if (err) { |
| 210 | g_printerr("Realize gdk gl context failed: %s\n", err->message); |
| 211 | g_error_free(err); |
| 212 | g_clear_object(&ctx); |
| 213 | return NULL; |
| 214 | } |
Volker Rümelin | 0905367 | 2022-06-05 10:51:31 +0200 | [diff] [blame] | 215 | |
| 216 | gdk_gl_context_make_current(ctx); |
| 217 | gdk_gl_context_get_version(ctx, &major, &minor); |
| 218 | gdk_gl_context_clear_current(); |
| 219 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 220 | |
| 221 | if (gd_cmp_gl_context_version(major, minor, params) == -1) { |
| 222 | /* created ctx version < requested version */ |
| 223 | g_clear_object(&ctx); |
| 224 | } |
| 225 | |
| 226 | trace_gd_gl_area_create_context(ctx, params->major_ver, params->minor_ver); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 227 | return ctx; |
| 228 | } |
| 229 | |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 230 | void gd_gl_area_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx) |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 231 | { |
Volker Rümelin | e561b3b | 2022-06-05 10:51:30 +0200 | [diff] [blame] | 232 | GdkGLContext *current_ctx = gdk_gl_context_get_current(); |
| 233 | |
| 234 | trace_gd_gl_area_destroy_context(ctx, current_ctx); |
| 235 | if (ctx == current_ctx) { |
| 236 | gdk_gl_context_clear_current(); |
| 237 | } |
| 238 | g_clear_object(&ctx); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 239 | } |
| 240 | |
Gerd Hoffmann | f4c36bd | 2017-02-21 10:37:16 +0100 | [diff] [blame] | 241 | void gd_gl_area_scanout_texture(DisplayChangeListener *dcl, |
| 242 | uint32_t backing_id, |
| 243 | bool backing_y_0_top, |
| 244 | uint32_t backing_width, |
| 245 | uint32_t backing_height, |
| 246 | uint32_t x, uint32_t y, |
| 247 | uint32_t w, uint32_t h) |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 248 | { |
| 249 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 250 | |
| 251 | vc->gfx.x = x; |
| 252 | vc->gfx.y = y; |
| 253 | vc->gfx.w = w; |
| 254 | vc->gfx.h = h; |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 255 | vc->gfx.y0_top = backing_y_0_top; |
| 256 | |
| 257 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 258 | |
Anthoine Bourgeois | 2ff408d | 2017-10-02 14:40:52 +0200 | [diff] [blame] | 259 | if (backing_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) { |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 260 | gtk_gl_area_set_scanout_mode(vc, false); |
| 261 | return; |
| 262 | } |
| 263 | |
| 264 | gtk_gl_area_set_scanout_mode(vc, true); |
Gerd Hoffmann | 74083f9 | 2017-09-27 13:50:31 +0200 | [diff] [blame] | 265 | egl_fb_setup_for_tex(&vc->gfx.guest_fb, backing_width, backing_height, |
| 266 | backing_id, false); |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 267 | } |
| 268 | |
Marc-André Lureau | 568b12f | 2021-02-04 14:52:19 +0400 | [diff] [blame] | 269 | void gd_gl_area_scanout_disable(DisplayChangeListener *dcl) |
| 270 | { |
| 271 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 272 | |
| 273 | gtk_gl_area_set_scanout_mode(vc, false); |
| 274 | } |
| 275 | |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 276 | void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, |
| 277 | uint32_t x, uint32_t y, uint32_t w, uint32_t h) |
| 278 | { |
| 279 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 280 | |
Vivek Kasireddy | 65b847d | 2021-09-14 14:18:35 -0700 | [diff] [blame] | 281 | if (vc->gfx.guest_fb.dmabuf) { |
| 282 | graphic_hw_gl_block(vc->gfx.dcl.con, true); |
Dongwon Kim | 55f4b76 | 2021-09-24 15:51:05 -0700 | [diff] [blame] | 283 | vc->gfx.guest_fb.dmabuf->draw_submitted = true; |
Vivek Kasireddy | 65b847d | 2021-09-14 14:18:35 -0700 | [diff] [blame] | 284 | } |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 285 | gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 286 | } |
| 287 | |
Marc-André Lureau | 2606519 | 2021-02-04 14:52:28 +0400 | [diff] [blame] | 288 | void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl, |
| 289 | QemuDmaBuf *dmabuf) |
| 290 | { |
Akihiko Odaki | bc6a356 | 2021-02-23 15:03:07 +0900 | [diff] [blame] | 291 | #ifdef CONFIG_GBM |
Marc-André Lureau | 2606519 | 2021-02-04 14:52:28 +0400 | [diff] [blame] | 292 | VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); |
| 293 | |
| 294 | gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); |
| 295 | egl_dmabuf_import_texture(dmabuf); |
| 296 | if (!dmabuf->texture) { |
| 297 | return; |
| 298 | } |
| 299 | |
| 300 | gd_gl_area_scanout_texture(dcl, dmabuf->texture, |
| 301 | false, dmabuf->width, dmabuf->height, |
| 302 | 0, 0, dmabuf->width, dmabuf->height); |
Vivek Kasireddy | 65b847d | 2021-09-14 14:18:35 -0700 | [diff] [blame] | 303 | |
| 304 | if (dmabuf->allow_fences) { |
| 305 | vc->gfx.guest_fb.dmabuf = dmabuf; |
| 306 | } |
Marc-André Lureau | 2606519 | 2021-02-04 14:52:28 +0400 | [diff] [blame] | 307 | #endif |
| 308 | } |
| 309 | |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 310 | void gtk_gl_area_init(void) |
| 311 | { |
| 312 | display_opengl = 1; |
| 313 | } |
| 314 | |
Marc-André Lureau | 5e79d51 | 2021-10-09 23:48:46 +0400 | [diff] [blame] | 315 | int gd_gl_area_make_current(DisplayGLCtx *dgc, |
Gerd Hoffmann | 925a040 | 2015-05-26 12:26:21 +0200 | [diff] [blame] | 316 | QEMUGLContext ctx) |
| 317 | { |
| 318 | gdk_gl_context_make_current(ctx); |
| 319 | return 0; |
| 320 | } |