diff options
Diffstat (limited to 'ui')
| -rw-r--r-- | ui/Makefile.objs | 6 | ||||
| -rw-r--r-- | ui/console-gl.c | 7 | ||||
| -rw-r--r-- | ui/console.c | 67 | ||||
| -rw-r--r-- | ui/egl-context.c | 34 | ||||
| -rw-r--r-- | ui/gtk-egl.c | 131 | ||||
| -rw-r--r-- | ui/gtk-gl-area.c | 223 | ||||
| -rw-r--r-- | ui/gtk.c | 137 | ||||
| -rw-r--r-- | ui/sdl2-2d.c | 13 | ||||
| -rw-r--r-- | ui/shader.c | 31 |
9 files changed, 609 insertions, 40 deletions
diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 0034fbb49f..728393c5ea 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -31,11 +31,17 @@ ifeq ($(CONFIG_OPENGL),y) common-obj-y += shader.o common-obj-y += console-gl.o common-obj-y += egl-helpers.o +common-obj-y += egl-context.o +ifeq ($(CONFIG_GTK_GL),y) +common-obj-$(CONFIG_GTK) += gtk-gl-area.o +else common-obj-$(CONFIG_GTK) += gtk-egl.o endif +endif gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS) +gtk-gl-area.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS) shader.o-cflags += $(OPENGL_CFLAGS) console-gl.o-cflags += $(OPENGL_CFLAGS) egl-helpers.o-cflags += $(OPENGL_CFLAGS) diff --git a/ui/console-gl.c b/ui/console-gl.c index cb45cf8a29..baf397b300 100644 --- a/ui/console-gl.c +++ b/ui/console-gl.c @@ -33,6 +33,7 @@ struct ConsoleGLState { GLint texture_blit_prog; + GLint texture_blit_vao; }; /* ---------------------------------------------------------------------- */ @@ -47,6 +48,9 @@ ConsoleGLState *console_gl_init_context(void) exit(1); } + gls->texture_blit_vao = + qemu_gl_init_texture_blit(gls->texture_blit_prog); + return gls; } @@ -131,7 +135,8 @@ void surface_gl_render_texture(ConsoleGLState *gls, glClearColor(0.1f, 0.1f, 0.1f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - qemu_gl_run_texture_blit(gls->texture_blit_prog); + qemu_gl_run_texture_blit(gls->texture_blit_prog, + gls->texture_blit_vao); } void surface_gl_destroy_texture(ConsoleGLState *gls, diff --git a/ui/console.c b/ui/console.c index 75fc492f73..31f0d35987 100644 --- a/ui/console.c +++ b/ui/console.c @@ -121,6 +121,7 @@ struct QemuConsole { DisplayState *ds; DisplaySurface *surface; int dcls; + DisplayChangeListener *gl; /* Graphic console state. */ Object *device; @@ -1332,6 +1333,11 @@ void qemu_free_displaysurface(DisplaySurface *surface) g_free(surface); } +bool console_has_gl(QemuConsole *con) +{ + return con->gl != NULL; +} + void register_displaychangelistener(DisplayChangeListener *dcl) { static const char nodev[] = @@ -1339,6 +1345,17 @@ void register_displaychangelistener(DisplayChangeListener *dcl) static DisplaySurface *dummy; QemuConsole *con; + if (dcl->ops->dpy_gl_ctx_create) { + /* display has opengl support */ + assert(dcl->con); + if (dcl->con->gl) { + fprintf(stderr, "can't register two opengl displays (%s, %s)\n", + dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name); + exit(1); + } + dcl->con->gl = dcl; + } + trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); dcl->ds = get_alloc_displaystate(); QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next); @@ -1417,9 +1434,13 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) { DisplayState *s = con->ds; DisplayChangeListener *dcl; - int width = surface_width(con->surface); - int height = surface_height(con->surface); + int width = w; + int height = h; + if (con->surface) { + width = surface_width(con->surface); + height = surface_height(con->surface); + } x = MAX(x, 0); y = MAX(y, 0); x = MIN(x, width); @@ -1619,6 +1640,48 @@ bool dpy_cursor_define_supported(QemuConsole *con) return false; } +QEMUGLContext dpy_gl_ctx_create(QemuConsole *con, + struct QEMUGLParams *qparams) +{ + assert(con->gl); + return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams); +} + +void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx) +{ + assert(con->gl); + con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx); +} + +int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx) +{ + assert(con->gl); + return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx); +} + +QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con) +{ + assert(con->gl); + return con->gl->ops->dpy_gl_ctx_get_current(con->gl); +} + +void dpy_gl_scanout(QemuConsole *con, + uint32_t backing_id, bool backing_y_0_top, + uint32_t x, uint32_t y, uint32_t width, uint32_t height) +{ + assert(con->gl); + con->gl->ops->dpy_gl_scanout(con->gl, backing_id, + backing_y_0_top, + x, y, width, height); +} + +void dpy_gl_update(QemuConsole *con, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + assert(con->gl); + con->gl->ops->dpy_gl_update(con->gl, x, y, w, h); +} + /***********************************************************/ /* register display */ diff --git a/ui/egl-context.c b/ui/egl-context.c new file mode 100644 index 0000000000..40102e392e --- /dev/null +++ b/ui/egl-context.c @@ -0,0 +1,34 @@ +#include "qemu-common.h" +#include "ui/egl-context.h" + +QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + EGLContext ctx; + EGLint ctx_att[] = { + EGL_CONTEXT_CLIENT_VERSION, params->major_ver, + EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver, + EGL_NONE + }; + + ctx = eglCreateContext(qemu_egl_display, qemu_egl_config, + eglGetCurrentContext(), ctx_att); + return ctx; +} + +void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) +{ + eglDestroyContext(qemu_egl_display, ctx); +} + +int qemu_egl_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ + return eglMakeCurrent(qemu_egl_display, + EGL_NO_SURFACE, EGL_NO_SURFACE, ctx); +} + +QEMUGLContext qemu_egl_get_current_context(DisplayChangeListener *dcl) +{ + return eglGetCurrentContext(); +} diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 15b41f2bab..500c42c9fa 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -21,6 +21,29 @@ #include "sysemu/sysemu.h" +static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout) +{ + if (vc->gfx.scanout_mode == scanout) { + return; + } + + vc->gfx.scanout_mode = scanout; + if (!vc->gfx.scanout_mode) { + if (vc->gfx.fbo_id) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffers(1, &vc->gfx.fbo_id); + vc->gfx.fbo_id = 0; + } + if (vc->gfx.surface) { + surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); + surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); + } + } +} + /** DisplayState Callbacks (opengl version) **/ void gd_egl_init(VirtualConsole *vc) @@ -50,19 +73,26 @@ void gd_egl_draw(VirtualConsole *vc) GdkWindow *window; int ww, wh; - if (!vc->gfx.gls || !vc->gfx.ds) { + if (!vc->gfx.gls) { return; } - eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, - vc->gfx.esurface, vc->gfx.ectx); + if (vc->gfx.scanout_mode) { + gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h); + } else { + if (!vc->gfx.ds) { + return; + } + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); - window = gtk_widget_get_window(vc->gfx.drawing_area); - gdk_drawable_get_size(window, &ww, &wh); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); - surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); + window = gtk_widget_get_window(vc->gfx.drawing_area); + gdk_drawable_get_size(window, &ww, &wh); + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); - eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); + eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); + } } void gd_egl_update(DisplayChangeListener *dcl, @@ -99,6 +129,7 @@ void gd_egl_refresh(DisplayChangeListener *dcl) if (vc->gfx.glupdates) { vc->gfx.glupdates = 0; + gtk_egl_set_scanout_mode(vc, false); gd_egl_draw(vc); } } @@ -128,6 +159,81 @@ void gd_egl_switch(DisplayChangeListener *dcl, } } +QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); + return qemu_egl_create_context(dcl, params); +} + +void gd_egl_scanout(DisplayChangeListener *dcl, + uint32_t backing_id, bool backing_y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + vc->gfx.x = x; + vc->gfx.y = y; + vc->gfx.w = w; + vc->gfx.h = h; + vc->gfx.tex_id = backing_id; + vc->gfx.y0_top = backing_y_0_top; + + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); + + if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) { + gtk_egl_set_scanout_mode(vc, false); + return; + } + + gtk_egl_set_scanout_mode(vc, true); + if (!vc->gfx.fbo_id) { + glGenFramebuffers(1, &vc->gfx.fbo_id); + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, vc->gfx.tex_id, 0); +} + +void gd_egl_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + GdkWindow *window; + int ww, wh, y1, y2; + + if (!vc->gfx.scanout_mode) { + return; + } + if (!vc->gfx.fbo_id) { + return; + } + + eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, vc->gfx.ectx); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + window = gtk_widget_get_window(vc->gfx.drawing_area); + gdk_drawable_get_size(window, &ww, &wh); + glViewport(0, 0, ww, wh); + y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; + y2 = vc->gfx.y0_top ? vc->gfx.h : 0; + glBlitFramebuffer(0, y1, vc->gfx.w, y2, + 0, 0, ww, wh, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); + + eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); +} + void gtk_egl_init(void) { GdkDisplay *gdk_display = gdk_display_get_default(); @@ -139,3 +245,12 @@ void gtk_egl_init(void) display_opengl = 1; } + +int gd_egl_make_current(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, + vc->gfx.esurface, ctx); +} diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c new file mode 100644 index 0000000000..dec3edb296 --- /dev/null +++ b/ui/gtk-gl-area.c @@ -0,0 +1,223 @@ +/* + * GTK UI -- glarea opengl code. + * + * Requires 3.16+ (GtkGLArea widget). + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu-common.h" + +#include "trace.h" + +#include "ui/console.h" +#include "ui/gtk.h" +#include "ui/egl-helpers.h" + +#include "sysemu/sysemu.h" + +static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout) +{ + if (vc->gfx.scanout_mode == scanout) { + return; + } + + vc->gfx.scanout_mode = scanout; + if (!vc->gfx.scanout_mode) { + if (vc->gfx.fbo_id) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffers(1, &vc->gfx.fbo_id); + vc->gfx.fbo_id = 0; + } + if (vc->gfx.surface) { + surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); + surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); + } + } +} + +/** DisplayState Callbacks (opengl version) **/ + +void gd_gl_area_draw(VirtualConsole *vc) +{ + int ww, wh, y1, y2; + + if (!vc->gfx.gls) { + return; + } + + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area); + wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area); + + if (vc->gfx.scanout_mode) { + if (!vc->gfx.fbo_id) { + return; + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id); + /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ + + glViewport(0, 0, ww, wh); + y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; + y2 = vc->gfx.y0_top ? vc->gfx.h : 0; + glBlitFramebuffer(0, y1, vc->gfx.w, y2, + 0, 0, ww, wh, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } else { + if (!vc->gfx.ds) { + return; + } + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); + } +} + +void gd_gl_area_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + if (!vc->gfx.gls || !vc->gfx.ds) { + return; + } + + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h); + vc->gfx.glupdates++; +} + +void gd_gl_area_refresh(DisplayChangeListener *dcl) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + if (!vc->gfx.gls) { + if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { + return; + } + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + vc->gfx.gls = console_gl_init_context(); + if (vc->gfx.ds) { + surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds); + } + } + + graphic_hw_update(dcl->con); + + if (vc->gfx.glupdates) { + vc->gfx.glupdates = 0; + gtk_gl_area_set_scanout_mode(vc, false); + gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); + } +} + +void gd_gl_area_switch(DisplayChangeListener *dcl, + DisplaySurface *surface) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + bool resized = true; + + trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); + + if (vc->gfx.ds && + surface_width(vc->gfx.ds) == surface_width(surface) && + surface_height(vc->gfx.ds) == surface_height(surface)) { + resized = false; + } + + if (vc->gfx.gls) { + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); + surface_gl_create_texture(vc->gfx.gls, surface); + } + vc->gfx.ds = surface; + + if (resized) { + gd_update_windowsize(vc); + } +} + +QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + GdkWindow *window; + GdkGLContext *ctx; + GError *err = NULL; + + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + window = gtk_widget_get_window(vc->gfx.drawing_area); + ctx = gdk_window_create_gl_context(window, &err); + gdk_gl_context_set_required_version(ctx, + params->major_ver, + params->minor_ver); + gdk_gl_context_realize(ctx, &err); + return ctx; +} + +void gd_gl_area_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) +{ + /* FIXME */ +} + +void gd_gl_area_scanout(DisplayChangeListener *dcl, + uint32_t backing_id, bool backing_y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + vc->gfx.x = x; + vc->gfx.y = y; + vc->gfx.w = w; + vc->gfx.h = h; + vc->gfx.tex_id = backing_id; + vc->gfx.y0_top = backing_y_0_top; + + gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); + + if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) { + gtk_gl_area_set_scanout_mode(vc, false); + return; + } + + gtk_gl_area_set_scanout_mode(vc, true); + if (!vc->gfx.fbo_id) { + glGenFramebuffers(1, &vc->gfx.fbo_id); + } + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, vc->gfx.tex_id, 0); +} + +void gd_gl_area_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); + + gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); +} + +void gtk_gl_area_init(void) +{ + display_opengl = 1; +} + +QEMUGLContext gd_gl_area_get_current_context(DisplayChangeListener *dcl) +{ + return gdk_gl_context_get_current(); +} + +int gd_gl_area_make_current(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ + gdk_gl_context_make_current(ctx); + return 0; +} diff --git a/ui/gtk.c b/ui/gtk.c index 3057cdc3f7..294783885f 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -367,6 +367,12 @@ static void gd_update_full_redraw(VirtualConsole *vc) GtkWidget *area = vc->gfx.drawing_area; int ww, wh; gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh); +#if defined(CONFIG_GTK_GL) + if (vc->gfx.gls) { + gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area)); + return; + } +#endif gtk_widget_queue_draw_area(area, 0, 0, ww, wh); } @@ -607,6 +613,27 @@ static const DisplayChangeListenerOps dcl_ops = { /** DisplayState Callbacks (opengl version) **/ +#if defined(CONFIG_GTK_GL) + +static const DisplayChangeListenerOps dcl_gl_area_ops = { + .dpy_name = "gtk-egl", + .dpy_gfx_update = gd_gl_area_update, + .dpy_gfx_switch = gd_gl_area_switch, + .dpy_gfx_check_format = console_gl_check_format, + .dpy_refresh = gd_gl_area_refresh, + .dpy_mouse_set = gd_mouse_set, + .dpy_cursor_define = gd_cursor_define, + + .dpy_gl_ctx_create = gd_gl_area_create_context, + .dpy_gl_ctx_destroy = gd_gl_area_destroy_context, + .dpy_gl_ctx_make_current = gd_gl_area_make_current, + .dpy_gl_ctx_get_current = gd_gl_area_get_current_context, + .dpy_gl_scanout = gd_gl_area_scanout, + .dpy_gl_update = gd_gl_area_scanout_flush, +}; + +#else + static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_name = "gtk-egl", .dpy_gfx_update = gd_egl_update, @@ -615,9 +642,17 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_refresh = gd_egl_refresh, .dpy_mouse_set = gd_mouse_set, .dpy_cursor_define = gd_cursor_define, + + .dpy_gl_ctx_create = gd_egl_create_context, + .dpy_gl_ctx_destroy = qemu_egl_destroy_context, + .dpy_gl_ctx_make_current = gd_egl_make_current, + .dpy_gl_ctx_get_current = qemu_egl_get_current_context, + .dpy_gl_scanout = gd_egl_scanout, + .dpy_gl_update = gd_egl_scanout_flush, }; -#endif +#endif /* CONFIG_GTK_GL */ +#endif /* CONFIG_OPENGL */ /** QEMU Events **/ @@ -667,6 +702,39 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, return TRUE; } +static void gd_set_ui_info(VirtualConsole *vc, gint width, gint height) +{ + QemuUIInfo info; + + memset(&info, 0, sizeof(info)); + info.width = width; + info.height = height; + dpy_set_ui_info(vc->gfx.dcl.con, &info); +} + +#if defined(CONFIG_GTK_GL) + +static gboolean gd_render_event(GtkGLArea *area, GdkGLContext *context, + void *opaque) +{ + VirtualConsole *vc = opaque; + + if (vc->gfx.gls) { + gd_gl_area_draw(vc); + } + return TRUE; +} + +static void gd_resize_event(GtkGLArea *area, + gint width, gint height, gpointer *opaque) +{ + VirtualConsole *vc = (void *)opaque; + + gd_set_ui_info(vc, width, height); +} + +#endif + static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { VirtualConsole *vc = opaque; @@ -677,8 +745,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) #if defined(CONFIG_OPENGL) if (vc->gfx.gls) { +#if defined(CONFIG_GTK_GL) + /* invoke render callback please */ + return FALSE; +#else gd_egl_draw(vc); return TRUE; +#endif } #endif @@ -1466,12 +1539,8 @@ static gboolean gd_configure(GtkWidget *widget, GdkEventConfigure *cfg, gpointer opaque) { VirtualConsole *vc = opaque; - QemuUIInfo info; - memset(&info, 0, sizeof(info)); - info.width = cfg->width; - info.height = cfg->height; - dpy_set_ui_info(vc->gfx.dcl.con, &info); + gd_set_ui_info(vc, cfg->width, cfg->height); return FALSE; } @@ -1628,6 +1697,15 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc) #if GTK_CHECK_VERSION(3, 0, 0) g_signal_connect(vc->gfx.drawing_area, "draw", G_CALLBACK(gd_draw_event), vc); +#if defined(CONFIG_GTK_GL) + if (display_opengl) { + /* wire up GtkGlArea events */ + g_signal_connect(vc->gfx.drawing_area, "render", + G_CALLBACK(gd_render_event), vc); + g_signal_connect(vc->gfx.drawing_area, "resize", + G_CALLBACK(gd_resize_event), vc); + } +#endif #else g_signal_connect(vc->gfx.drawing_area, "expose-event", G_CALLBACK(gd_expose_event), vc); @@ -1736,26 +1814,13 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, vc->gfx.scale_x = 1.0; vc->gfx.scale_y = 1.0; - vc->gfx.drawing_area = gtk_drawing_area_new(); - gtk_widget_add_events(vc->gfx.drawing_area, - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_SCROLL_MASK | - GDK_KEY_PRESS_MASK); - gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE); - - vc->type = GD_VC_GFX; - vc->tab_item = vc->gfx.drawing_area; - vc->focus = vc->gfx.drawing_area; - gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), - vc->tab_item, gtk_label_new(vc->label)); - #if defined(CONFIG_OPENGL) if (display_opengl) { +#if defined(CONFIG_GTK_GL) + vc->gfx.drawing_area = gtk_gl_area_new(); + vc->gfx.dcl.ops = &dcl_gl_area_ops; +#else + vc->gfx.drawing_area = gtk_drawing_area_new(); /* * gtk_widget_set_double_buffered() was deprecated in 3.14. * It is required for opengl rendering on X11 though. A @@ -1771,12 +1836,32 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc, #pragma GCC diagnostic pop #endif vc->gfx.dcl.ops = &dcl_egl_ops; +#endif /* CONFIG_GTK_GL */ } else #endif { + vc->gfx.drawing_area = gtk_drawing_area_new(); vc->gfx.dcl.ops = &dcl_ops; } + + gtk_widget_add_events(vc->gfx.drawing_area, + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_SCROLL_MASK | + GDK_KEY_PRESS_MASK); + gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE); + + vc->type = GD_VC_GFX; + vc->tab_item = vc->gfx.drawing_area; + vc->focus = vc->gfx.drawing_area; + gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), + vc->tab_item, gtk_label_new(vc->label)); + vc->gfx.dcl.con = con; register_displaychangelistener(&vc->gfx.dcl); @@ -2059,8 +2144,12 @@ void early_gtk_display_init(int opengl) break; case 1: /* on */ #if defined(CONFIG_OPENGL) +#if defined(CONFIG_GTK_GL) + gtk_gl_area_init(); +#else gtk_egl_init(); #endif +#endif break; default: g_assert_not_reached(); diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c index d0b340f956..191ee3b52d 100644 --- a/ui/sdl2-2d.c +++ b/ui/sdl2-2d.c @@ -45,10 +45,23 @@ void sdl2_2d_update(DisplayChangeListener *dcl, return; } + /* + * SDL2 seems to do some double-buffering, and trying to only + * update the changed areas results in only one of the two buffers + * being updated. Which flickers alot. So lets not try to be + * clever do a full update every time ... + */ +#if 0 rect.x = x; rect.y = y; rect.w = w; rect.h = h; +#else + rect.x = 0; + rect.y = 0; + rect.w = surface_width(surf); + rect.h = surface_height(surf); +#endif SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), surface_stride(surf)); diff --git a/ui/shader.c b/ui/shader.c index 52a4632930..0588655cfe 100644 --- a/ui/shader.c +++ b/ui/shader.c @@ -29,21 +29,42 @@ /* ---------------------------------------------------------------------- */ -void qemu_gl_run_texture_blit(GLint texture_blit_prog) +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog) { - GLfloat in_position[] = { + static const GLfloat in_position[] = { -1, -1, 1, -1, -1, 1, 1, 1, }; GLint l_position; + GLuint vao, buffer; + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + /* this is the VBO that holds the vertex data */ + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position, + GL_STATIC_DRAW); - glUseProgram(texture_blit_prog); l_position = glGetAttribLocation(texture_blit_prog, "in_position"); - glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position); + glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(l_position); - glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + return vao; +} + +void qemu_gl_run_texture_blit(GLint texture_blit_prog, + GLint texture_blit_vao) +{ + glUseProgram(texture_blit_prog); + glBindVertexArray(texture_blit_vao); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } /* ---------------------------------------------------------------------- */ |