From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53016) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YDCVx-0004fC-MD for qemu-devel@nongnu.org; Mon, 19 Jan 2015 08:37:11 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YDCVl-0002x1-WF for qemu-devel@nongnu.org; Mon, 19 Jan 2015 08:37:09 -0500 Received: from mx1.redhat.com ([209.132.183.28]:42540) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YDCVl-0002wv-Mc for qemu-devel@nongnu.org; Mon, 19 Jan 2015 08:36:57 -0500 From: Gerd Hoffmann Date: Mon, 19 Jan 2015 14:36:43 +0100 Message-Id: <1421674603-31575-8-git-send-email-kraxel@redhat.com> In-Reply-To: <1421674603-31575-1-git-send-email-kraxel@redhat.com> References: <1421674603-31575-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH v2 7/7] sdl2: add support for display rendering using opengl. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Gerd Hoffmann , Anthony Liguori , Max Reitz Add new sdl2-gl.c file, with display rendering functions using opengl. Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 + include/ui/sdl2.h | 11 +++++ ui/Makefile.objs | 3 ++ ui/sdl.c | 11 +++++ ui/sdl2-2d.c | 7 ++++ ui/sdl2-gl.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ ui/sdl2.c | 67 ++++++++++++++++++++++++++---- vl.c | 11 +++++ 8 files changed, 216 insertions(+), 7 deletions(-) create mode 100644 ui/sdl2-gl.c diff --git a/include/ui/console.h b/include/ui/console.h index 9157b64..1540d67 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -352,6 +352,7 @@ void surface_gl_setup_viewport(ConsoleGLState *gls, #endif /* sdl.c */ +void sdl_display_early_init(int opengl); void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); /* cocoa.m */ diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h index 148308c..3f89d30 100644 --- a/include/ui/sdl2.h +++ b/include/ui/sdl2.h @@ -17,6 +17,10 @@ struct sdl2_console { int last_vm_running; /* per console for caption reasons */ int x, y; int hidden; + int opengl; + int updates; + SDL_GLContext winctx; + ConsoleGLState *gls; }; void sdl2_window_create(struct sdl2_console *scon); @@ -35,4 +39,11 @@ void sdl2_2d_switch(DisplayChangeListener *dcl, void sdl2_2d_refresh(DisplayChangeListener *dcl); void sdl2_2d_redraw(struct sdl2_console *scon); +void sdl2_gl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h); +void sdl2_gl_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface); +void sdl2_gl_refresh(DisplayChangeListener *dcl); +void sdl2_gl_redraw(struct sdl2_console *scon); + #endif /* SDL2_H */ diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 3173778..a88f730 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -21,6 +21,9 @@ sdl.mo-objs := sdl.o sdl_zoom.o endif ifeq ($(CONFIG_SDLABI),2.0) sdl.mo-objs := sdl2.o sdl2-input.o sdl2-2d.o +ifeq ($(CONFIG_OPENGL),y) +sdl.mo-objs += sdl2-gl.o +endif endif sdl.mo-cflags := $(SDL_CFLAGS) diff --git a/ui/sdl.c b/ui/sdl.c index 3e9d810..1fe002d 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -873,6 +873,17 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = sdl_mouse_define, }; +void sdl_display_early_init(int opengl) +{ + if (opengl == 1 /* on */) { + fprintf(stderr, + "SDL1 display code has no opengl support.\n" + "Please recompile qemu with SDL2, using\n" + "./configure --enable-sdl --with-sdlabi=2.0\n"); + exit(1); + } +} + void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { int flags; diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c index 7a82d50..f6cb438 100644 --- a/ui/sdl2-2d.c +++ b/ui/sdl2-2d.c @@ -36,6 +36,8 @@ void sdl2_2d_update(DisplayChangeListener *dcl, DisplaySurface *surf = qemu_console_surface(dcl->con); SDL_Rect rect; + assert(!scon->opengl); + if (!surf) { return; } @@ -61,6 +63,8 @@ void sdl2_2d_switch(DisplayChangeListener *dcl, DisplaySurface *old_surface = scon->surface; int format = 0; + assert(!scon->opengl); + scon->surface = new_surface; if (scon->texture) { @@ -101,12 +105,15 @@ void sdl2_2d_refresh(DisplayChangeListener *dcl) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + assert(!scon->opengl); graphic_hw_update(dcl->con); sdl2_poll_events(scon); } void sdl2_2d_redraw(struct sdl2_console *scon) { + assert(!scon->opengl); + if (!scon->surface) { return; } diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c new file mode 100644 index 0000000..b604c06 --- /dev/null +++ b/ui/sdl2-gl.c @@ -0,0 +1,112 @@ +/* + * QEMU SDL display driver -- opengl support + * + * Copyright (c) 2014 Red Hat + * + * Authors: + * Gerd Hoffmann + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/input.h" +#include "ui/sdl2.h" +#include "sysemu/sysemu.h" + +static void sdl2_gl_render_surface(struct sdl2_console *scon) +{ + int ww, wh; + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + + SDL_GetWindowSize(scon->real_window, &ww, &wh); + surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh); + + surface_gl_render_texture(scon->gls, scon->surface); + SDL_GL_SwapWindow(scon->real_window); +} + +void sdl2_gl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + + assert(scon->opengl); + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h); + scon->updates++; +} + +void sdl2_gl_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + DisplaySurface *old_surface = scon->surface; + + assert(scon->opengl); + + SDL_GL_MakeCurrent(scon->real_window, scon->winctx); + surface_gl_destroy_texture(scon->gls, scon->surface); + + scon->surface = new_surface; + + if (!new_surface) { + console_gl_fini_context(scon->gls); + scon->gls = NULL; + sdl2_window_destroy(scon); + return; + } + + if (!scon->real_window) { + sdl2_window_create(scon); + scon->gls = console_gl_init_context(); + } else if (old_surface && + ((surface_width(old_surface) != surface_width(new_surface)) || + (surface_height(old_surface) != surface_height(new_surface)))) { + sdl2_window_resize(scon); + } + + surface_gl_create_texture(scon->gls, scon->surface); +} + +void sdl2_gl_refresh(DisplayChangeListener *dcl) +{ + struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); + + assert(scon->opengl); + + graphic_hw_update(dcl->con); + if (scon->updates && scon->surface) { + scon->updates = 0; + sdl2_gl_render_surface(scon); + } + sdl2_poll_events(scon); +} + +void sdl2_gl_redraw(struct sdl2_console *scon) +{ + assert(scon->opengl); + + if (scon->surface) { + sdl2_gl_render_surface(scon); + } +} diff --git a/ui/sdl2.c b/ui/sdl2.c index 943d1da..3be9de7 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -86,6 +86,9 @@ void sdl2_window_create(struct sdl2_console *scon) surface_height(scon->surface), flags); scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); + if (scon->opengl) { + scon->winctx = SDL_GL_GetCurrentContext(); + } sdl_update_caption(scon); } @@ -112,6 +115,17 @@ void sdl2_window_resize(struct sdl2_console *scon) surface_height(scon->surface)); } +static void sdl2_redraw(struct sdl2_console *scon) +{ + if (scon->opengl) { +#ifdef CONFIG_OPENGL + sdl2_gl_redraw(scon); +#endif + } else { + sdl2_2d_redraw(scon); + } +} + static void sdl_update_caption(struct sdl2_console *scon) { char win_title[1024]; @@ -310,7 +324,7 @@ static void toggle_full_screen(struct sdl2_console *scon) } SDL_SetWindowFullscreen(scon->real_window, 0); } - sdl2_2d_redraw(scon); + sdl2_redraw(scon); } static void handle_keydown(SDL_Event *ev) @@ -358,8 +372,10 @@ static void handle_keydown(SDL_Event *ev) case SDL_SCANCODE_U: sdl2_window_destroy(scon); sdl2_window_create(scon); - /* re-create texture */ - sdl2_2d_switch(&scon->dcl, scon->surface); + if (!scon->opengl) { + /* re-create scon->texture */ + sdl2_2d_switch(&scon->dcl, scon->surface); + } gui_keysym = 1; break; #if 0 @@ -378,7 +394,7 @@ static void handle_keydown(SDL_Event *ev) fprintf(stderr, "%s: scale to %dx%d\n", __func__, width, height); sdl_scale(scon, width, height); - sdl2_2d_redraw(scon); + sdl2_redraw(scon); gui_keysym = 1; } #endif @@ -514,10 +530,10 @@ static void handle_windowevent(SDL_Event *ev) info.height = ev->window.data2; dpy_set_ui_info(scon->dcl.con, &info); } - sdl2_2d_redraw(scon); + sdl2_redraw(scon); break; case SDL_WINDOWEVENT_EXPOSED: - sdl2_2d_redraw(scon); + sdl2_redraw(scon); break; case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_ENTER: @@ -670,6 +686,37 @@ static const DisplayChangeListenerOps dcl_2d_ops = { .dpy_cursor_define = sdl_mouse_define, }; +#ifdef CONFIG_OPENGL +static const DisplayChangeListenerOps dcl_gl_ops = { + .dpy_name = "sdl2-gl", + .dpy_gfx_update = sdl2_gl_update, + .dpy_gfx_switch = sdl2_gl_switch, + .dpy_refresh = sdl2_gl_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, +}; +#endif + +void sdl_display_early_init(int opengl) +{ + switch (opengl) { + case -1: /* default */ + case 0: /* off */ + break; + case 1: /* on */ +#ifdef CONFIG_OPENGL + display_opengl = 1; +#else + fprintf(stderr, "SDL2 has been compiled without opengl support\n"); + exit(1); +#endif + break; + default: + g_assert_not_reached(); + break; + } +} + void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { int flags; @@ -715,10 +762,16 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) if (!qemu_console_is_graphic(con)) { sdl2_console[i].hidden = true; } + sdl2_console[i].idx = i; +#ifdef CONFIG_OPENGL + sdl2_console[i].opengl = display_opengl; + sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops; +#else + sdl2_console[i].opengl = 0; sdl2_console[i].dcl.ops = &dcl_2d_ops; +#endif sdl2_console[i].dcl.con = con; register_displaychangelistener(&sdl2_console[i].dcl); - sdl2_console[i].idx = i; } /* Load a 32x32x4 image. White pixels are transparent. */ diff --git a/vl.c b/vl.c index 0bf2acb..3ce1389 100644 --- a/vl.c +++ b/vl.c @@ -1947,6 +1947,7 @@ static DisplayType select_display(const char *p) { const char *opts; DisplayType display = DT_DEFAULT; + int opengl = -1; if (strstart(p, "sdl", &opts)) { #ifdef CONFIG_SDL @@ -1990,6 +1991,15 @@ static DisplayType select_display(const char *p) } else { goto invalid_sdl_args; } + } else if (strstart(opts, ",gl=", &nextopt)) { + opts = nextopt; + if (strstart(opts, "on", &nextopt)) { + opengl = 1; + } else if (strstart(opts, "off", &nextopt)) { + opengl = 0; + } else { + goto invalid_sdl_args; + } } else { invalid_sdl_args: fprintf(stderr, "Invalid SDL option string: %s\n", p); @@ -1997,6 +2007,7 @@ static DisplayType select_display(const char *p) } opts = nextopt; } + sdl_display_early_init(opengl); #else fprintf(stderr, "SDL support is disabled\n"); exit(1); -- 1.8.3.1