From: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] opengl rendering in the sdl window
Date: Fri, 29 Aug 2008 16:22:11 +0100 [thread overview]
Message-ID: <48B81423.9050502@eu.citrix.com> (raw)
This patch comes from xen-unstable and adds opengl support for rendering
the guest framebuffer in the SDL window.
SDL is needed anyway to open the window and handle the events.
Opengl rendering is optional and can be turned off at both compile time
and run time (--disable-opengl).
Some of the benefits of using opengl are:
-faster rendering, less CPU intensive, especially with good graphic
cards;
-makes the window resizing possible and hardware accelerated, thus very
efficient and smooth;
-allows other optimizations like sharing directly a buffer in vram with
the guest (not yet implemented).
Opengl rendering actually is enabled only when the buffer is shared to
avoid adding one more copy of the pixel buffer.
This patch depends upon the shared buffer patch and the previous sdl
patch.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
diff --git a/configure b/configure
index acb4a4a..a794827 100755
--- a/configure
+++ b/configure
@@ -271,6 +271,8 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
+ --disable-opengl) opengl="no"
+ ;;
--fmod-lib=*) fmod_lib="$optarg"
;;
--fmod-inc=*) fmod_inc="$optarg"
@@ -749,6 +751,26 @@ else
fi # -z $sdl
##########################################
+# OpenGL test
+
+if test -z "$opengl" && test "$sdl" = "yes"
+then
+cat > $TMPC << EOF
+#include <GL/gl.h>
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#error "Opengl doesn't support GL_TEXTURE_RECTANGLE_ARB"
+#endif
+int main( void ) { return (int) glGetString(GL_EXTENSIONS); }
+EOF
+if $cc -o $TMPE $TMPC -lGL 2> /dev/null
+then
+opengl="yes"
+else
+opengl="no"
+fi
+fi
+
+##########################################
# VNC TLS detection
if test "$vnc_tls" = "yes" ; then
cat > $TMPC <<EOF
@@ -941,6 +963,7 @@ if test "$sdl" != "no" ; then
echo "SDL static link $sdl_static"
fi
echo "curses support $curses"
+echo "OpenGL support $opengl"
echo "mingw32 support $mingw32"
echo "Audio drivers $audio_drv_list"
echo "Extra audio cards $audio_card_list"
@@ -1199,6 +1222,14 @@ if test "$sdl1" = "yes" ; then
echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
fi
fi
+if test $opengl = "yes"
+then
+ echo "#define CONFIG_OPENGL 1" >> $config_h
+ echo "CONFIG_OPENGL=yes" >> $config_mak
+ echo "SDL_CFLAGS+=-I/usr/include/GL" >> $config_mak
+ echo "SDL_LIBS+=-lXext" >> $config_mak
+ echo "SDL_LIBS+=-lGL" >> $config_mak
+fi
if test "$cocoa" = "yes" ; then
echo "#define CONFIG_COCOA 1" >> $config_h
echo "CONFIG_COCOA=yes" >> $config_mak
diff --git a/console.h b/console.h
index 7d252b7..a2004ba 100644
--- a/console.h
+++ b/console.h
@@ -153,7 +153,7 @@ void qemu_console_resize_shared(QEMUConsole *console, int width, int height,
int depth, int linesize, void *pixels);
/* sdl.c */
-void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame, int opengl_enable);
/* cocoa.m */
void cocoa_display_init(DisplayState *ds, int full_screen);
diff --git a/sdl.c b/sdl.c
index 8e78323..18792b4 100644
--- a/sdl.c
+++ b/sdl.c
@@ -31,6 +31,10 @@
#include <signal.h>
#endif
+#ifdef CONFIG_OPENGL
+#include <SDL_opengl.h>
+#endif
+
static SDL_Surface *screen;
static SDL_Surface *shared;
static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
@@ -50,9 +54,115 @@ static int absolute_enabled = 0;
static int guest_cursor = 0;
static int guest_x, guest_y;
static SDL_Cursor *guest_sprite = 0;
+static int opengl_enabled;
static void sdl_colourdepth(DisplayState *ds, int depth);
+#ifdef CONFIG_OPENGL
+static GLint tex_format;
+static GLint tex_type;
+static GLuint texture_ref = 0;
+static GLint gl_format;
+
+static void opengl_setdata(DisplayState *ds, void *pixels)
+{
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glClearColor(0, 0, 0, 0);
+ glDisable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_CULL_FACE);
+ glViewport( 0, 0, screen->w, screen->h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, screen->w, screen->h, 0, -1,1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glClear(GL_COLOR_BUFFER_BIT);
+ ds->data = pixels;
+
+ if (texture_ref) {
+ glDeleteTextures(1, &texture_ref);
+ texture_ref = 0;
+ }
+
+ glGenTextures(1, &texture_ref);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
+ glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
+ switch (ds->depth) {
+ case 8:
+ if (ds->palette == NULL) {
+ tex_format = GL_RGB;
+ tex_type = GL_UNSIGNED_BYTE_3_3_2;
+ } else {
+ int i;
+ GLushort paletter[256], paletteg[256], paletteb[256];
+ for (i = 0; i < 256; i++) {
+ uint8_t rgb = ds->palette[i] >> 16;
+ paletter[i] = ((rgb & 0xe0) >> 5) * 65535 / 7;
+ paletteg[i] = ((rgb & 0x1c) >> 2) * 65535 / 7;
+ paletteb[i] = (rgb & 0x3) * 65535 / 3;
+ }
+ glPixelMapusv(GL_PIXEL_MAP_I_TO_R, 256, paletter);
+ glPixelMapusv(GL_PIXEL_MAP_I_TO_G, 256, paletteg);
+ glPixelMapusv(GL_PIXEL_MAP_I_TO_B, 256, paletteb);
+
+ tex_format = GL_COLOR_INDEX;
+ tex_type = GL_UNSIGNED_BYTE;
+ }
+ break;
+ case 16:
+ tex_format = GL_RGB;
+ tex_type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case 24:
+ tex_format = GL_BGR;
+ tex_type = GL_UNSIGNED_BYTE;
+ break;
+ case 32:
+ if (!ds->bgr) {
+ tex_format = GL_BGRA;
+ tex_type = GL_UNSIGNED_BYTE;
+ } else {
+ tex_format = GL_RGBA;
+ tex_type = GL_UNSIGNED_BYTE;
+ }
+ break;
+ }
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, (ds->linesize * 8) / ds->depth);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds->width, ds->height, 0, tex_format, tex_type, pixels);
+ glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_PRIORITY, 1.0);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+}
+
+static void opengl_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ int bpp = ds->depth / 8;
+ GLvoid *pixels = ds->data + y * ds->linesize + x * bpp;
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, ds->linesize / bpp);
+ glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, x, y, w, h, tex_format, tex_type, pixels);
+ glBegin(GL_QUADS);
+ glTexCoord2d(0, 0);
+ glVertex2d(0, 0);
+ glTexCoord2d(ds->width, 0);
+ glVertex2d(screen->w, 0);
+ glTexCoord2d(ds->width, ds->height);
+ glVertex2d(screen->w, screen->h);
+ glTexCoord2d(0, ds->height);
+ glVertex2d(0, screen->h);
+ glEnd();
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ SDL_GL_SwapBuffers();
+}
+#endif
+
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
{
// printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
@@ -117,7 +227,12 @@ static void sdl_resize_shared(DisplayState *ds, int w, int h, int depth, int lin
sdl_colourdepth(ds, depth);
- flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE;
+#ifdef CONFIG_OPENGL
+ if (ds->shared_buf && opengl_enabled)
+ flags = SDL_OPENGL|SDL_RESIZABLE;
+ else
+#endif
+ flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE;
if (gui_fullscreen) {
flags |= SDL_FULLSCREEN;
@@ -131,19 +246,33 @@ static void sdl_resize_shared(DisplayState *ds, int w, int h, int depth, int lin
again:
screen = SDL_SetVideoMode(w, h, 0, flags);
+
if (!screen) {
fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError());
+ if (opengl_enabled) {
+ /* Fallback to SDL */
+ opengl_enabled = 0;
+ ds->dpy_update = sdl_update;
+ ds->dpy_setdata = sdl_setdata;
+ ds->dpy_resize_shared = sdl_resize_shared;
+ sdl_resize_shared(ds, w, h, depth, linesize, pixels);
+ return;
+ }
exit(1);
}
- if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
- flags &= ~SDL_HWSURFACE;
- goto again;
- }
- if (!screen->pixels) {
- fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError());
- exit(1);
+ if (!opengl_enabled) {
+ if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
+ flags &= ~SDL_HWSURFACE;
+ goto again;
+ }
+
+ if (!screen->pixels) {
+ fprintf(stderr, "Could not open SDL display: %s\n", SDL_GetError());
+ exit(1);
+ }
}
+
ds->width = w;
ds->height = h;
if (!ds->shared_buf) {
@@ -158,6 +287,25 @@ static void sdl_resize_shared(DisplayState *ds, int w, int h, int depth, int lin
ds->linesize = screen->pitch;
} else {
ds->linesize = linesize;
+#ifdef CONFIG_OPENGL
+ switch(screen->format->BitsPerPixel) {
+ case 8:
+ gl_format = GL_RGB;
+ break;
+ case 16:
+ gl_format = GL_RGB;
+ break;
+ case 24:
+ gl_format = GL_RGB;
+ break;
+ case 32:
+ if (!screen->format->Rshift)
+ gl_format = GL_BGRA;
+ else
+ gl_format = GL_RGBA;
+ break;
+ };
+#endif
}
if (ds->shared_buf) ds->dpy_setdata(ds, pixels);
}
@@ -176,6 +324,11 @@ static void sdl_colourdepth(DisplayState *ds, int depth)
}
ds->shared_buf = 1;
ds->depth = depth;
+#ifdef CONFIG_OPENGL
+ if (opengl_enabled) {
+ ds->dpy_update = opengl_update;
+ }
+#endif
}
/* generic keyboard conversion */
@@ -388,8 +541,8 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
absolute_enabled = 1;
}
- dx = x * 0x7FFF / (width - 1);
- dy = y * 0x7FFF / (height - 1);
+ dx = x * 0x7FFF / (screen->w - 1);
+ dy = y * 0x7FFF / (screen->h - 1);
} else if (absolute_enabled) {
sdl_show_cursor();
absolute_enabled = 0;
@@ -437,7 +590,7 @@ static void sdl_refresh(DisplayState *ds)
while (SDL_PollEvent(ev)) {
switch (ev->type) {
case SDL_VIDEOEXPOSE:
- sdl_update(ds, 0, 0, screen->w, screen->h);
+ ds->dpy_update(ds, 0, 0, ds->width, ds->height);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
@@ -601,6 +754,18 @@ static void sdl_refresh(DisplayState *ds)
}
}
break;
+#ifdef CONFIG_OPENGL
+ case SDL_VIDEORESIZE:
+ {
+ if (ds->shared_buf && opengl_enabled) {
+ SDL_ResizeEvent *rev = &ev->resize;
+ screen = SDL_SetVideoMode(rev->w, rev->h, 0, SDL_OPENGL|SDL_RESIZABLE);
+ opengl_setdata(ds, ds->data);
+ opengl_update(ds, 0, 0, ds->width, ds->height);
+ }
+ break;
+ }
+#endif
default:
break;
}
@@ -676,15 +841,19 @@ static void sdl_mouse_define(int width, int height, int bpp,
static void sdl_cleanup(void)
{
+#ifdef CONFIG_OPENGL
+ if (texture_ref) glDeleteTextures(1, &texture_ref);
+#endif
if (guest_sprite)
SDL_FreeCursor(guest_sprite);
SDL_Quit();
}
-void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame, int opengl)
{
int flags;
uint8_t data = 0;
+ opengl_enabled = opengl;
#if defined(__APPLE__)
/* always use generic keymaps */
@@ -711,6 +880,10 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
ds->dpy_resize_shared = sdl_resize_shared;
ds->dpy_refresh = sdl_refresh;
ds->dpy_setdata = sdl_setdata;
+#ifdef CONFIG_OPENGL
+ if (opengl_enabled)
+ ds->dpy_setdata = opengl_setdata;
+#endif
ds->dpy_fill = sdl_fill;
ds->mouse_set = sdl_mouse_warp;
ds->cursor_define = sdl_mouse_define;
diff --git a/vl.c b/vl.c
index 245177a..c661fa9 100644
--- a/vl.c
+++ b/vl.c
@@ -201,6 +201,11 @@ int graphic_height = 600;
int graphic_depth = 15;
#endif
int full_screen = 0;
+#ifdef CONFIG_OPENGL
+int opengl_enabled = 1;
+#else
+int opengl_enabled = 0;
+#endif
int no_frame = 0;
int no_quit = 0;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
@@ -7681,6 +7686,9 @@ static void help(int exitcode)
"-no-frame open SDL window without a frame and window decorations\n"
"-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
"-no-quit disable SDL window close capability\n"
+#ifdef CONFIG_OPENGL
+ "-disable-opengl disable OpenGL rendering, using SDL\n"
+#endif
#endif
#ifdef TARGET_I386
"-no-fd-bootchk disable boot signature checking for floppy disks\n"
@@ -7881,6 +7889,7 @@ enum {
QEMU_OPTION_no_frame,
QEMU_OPTION_alt_grab,
QEMU_OPTION_no_quit,
+ QEMU_OPTION_disable_opengl,
QEMU_OPTION_pidfile,
QEMU_OPTION_no_kqemu,
QEMU_OPTION_kernel_kqemu,
@@ -7983,6 +7992,9 @@ const QEMUOption qemu_options[] = {
{ "no-frame", 0, QEMU_OPTION_no_frame },
{ "alt-grab", 0, QEMU_OPTION_alt_grab },
{ "no-quit", 0, QEMU_OPTION_no_quit },
+#ifdef CONFIG_OPENGL
+ { "disable-opengl", 0, QEMU_OPTION_disable_opengl },
+#endif
#endif
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
{ "win2k-hack", 0, QEMU_OPTION_win2k_hack },
@@ -8729,6 +8741,11 @@ int main(int argc, char **argv)
case QEMU_OPTION_no_quit:
no_quit = 1;
break;
+#ifdef CONFIG_OPENGL
+ case QEMU_OPTION_disable_opengl:
+ opengl_enabled = 0;
+ break;
+#endif
#endif
case QEMU_OPTION_pidfile:
pid_file = optarg;
@@ -9104,7 +9121,7 @@ int main(int argc, char **argv)
#endif
{
#if defined(CONFIG_SDL)
- sdl_display_init(ds, full_screen, no_frame);
+ sdl_display_init(ds, full_screen, no_frame, opengl_enabled);
#elif defined(CONFIG_COCOA)
cocoa_display_init(ds, full_screen);
#else
next reply other threads:[~2008-08-29 15:21 UTC|newest]
Thread overview: 75+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-29 15:22 Stefano Stabellini [this message]
2008-09-02 16:53 ` [Qemu-devel] [PATCH] opengl rendering in the sdl window Ian Jackson
2008-09-04 3:00 ` Anthony Liguori
2008-09-04 7:41 ` Gerd Hoffmann
2008-09-04 9:42 ` Daniel P. Berrange
2008-09-04 10:06 ` Andreas Färber
2008-09-04 10:20 ` Daniel P. Berrange
2008-09-05 16:42 ` Andreas Färber
2008-09-07 7:51 ` Avi Kivity
2008-09-07 3:07 ` Anthony Liguori
2008-09-07 16:31 ` Daniel P. Berrange
2008-09-08 0:12 ` Anthony Liguori
2008-09-04 10:06 ` Stefano Stabellini
2008-09-05 12:02 ` Jamie Lokier
2008-09-05 12:11 ` Samuel Thibault
2008-09-06 23:27 ` Jamie Lokier
2008-09-07 14:22 ` Samuel Thibault
2008-09-07 14:36 ` Paul Brook
2008-09-07 14:42 ` Samuel Thibault
2008-09-07 15:03 ` Paul Brook
2008-09-07 15:12 ` Samuel Thibault
2008-09-07 15:35 ` Paul Brook
2008-09-07 15:41 ` Samuel Thibault
2008-09-07 15:57 ` Paul Brook
2008-09-08 0:08 ` Anthony Liguori
2008-09-08 0:21 ` Samuel Thibault
2008-09-08 1:18 ` Jamie Lokier
2008-09-08 10:38 ` Stefano Stabellini
2008-09-08 13:21 ` Jamie Lokier
2008-09-05 16:44 ` Stefano Stabellini
2008-09-05 16:55 ` Daniel P. Berrange
2008-09-05 17:13 ` Stefano Stabellini
2008-09-07 3:21 ` Anthony Liguori
2008-09-08 10:48 ` Stefano Stabellini
2008-09-08 13:16 ` Jamie Lokier
2008-09-08 13:51 ` Stefano Stabellini
2008-09-08 13:41 ` Jamie Lokier
2008-09-08 13:48 ` Daniel P. Berrange
2008-09-08 14:56 ` Gerd Hoffmann
2008-09-08 15:08 ` Jamie Lokier
2008-09-08 15:35 ` Gerd Hoffmann
2008-09-08 15:39 ` Jamie Lokier
2008-09-08 16:23 ` Gerd Hoffmann
2008-09-08 16:47 ` Anthony Liguori
2008-09-08 19:15 ` Gerd Hoffmann
2008-09-08 19:43 ` Jamie Lokier
2008-09-08 15:47 ` Daniel P. Berrange
2008-09-08 16:05 ` Anthony Liguori
2008-09-08 17:08 ` Mike Kronenberg
2008-09-08 19:21 ` Gerd Hoffmann
2008-09-08 21:06 ` Mike Kronenberg
2008-09-08 19:32 ` Jamie Lokier
2008-09-08 19:48 ` Jamie Lokier
2008-09-08 19:57 ` Anthony Liguori
2008-09-08 20:11 ` Jamie Lokier
2008-09-08 23:18 ` Daniel P. Berrange
2008-09-09 0:10 ` Jamie Lokier
2008-09-09 2:45 ` Anthony Liguori
2008-09-09 4:17 ` Jamie Lokier
2008-09-08 14:22 ` Anthony Liguori
2008-09-07 7:48 ` Avi Kivity
2008-09-07 11:57 ` Daniel P. Berrange
2008-09-07 13:12 ` Avi Kivity
2008-09-08 10:30 ` Stefano Stabellini
2008-09-08 10:35 ` Daniel P. Berrange
2008-09-08 10:53 ` Stefano Stabellini
2008-09-08 11:00 ` Daniel P. Berrange
2008-09-08 12:38 ` François Revol
2008-09-08 13:05 ` Jamie Lokier
2008-09-08 13:08 ` Anthony Liguori
2008-09-08 13:44 ` François Revol
2008-09-05 18:11 ` malc
2008-09-04 10:14 ` Stefano Stabellini
2008-09-07 3:09 ` Anthony Liguori
2008-09-04 10:21 ` Andreas Färber
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48B81423.9050502@eu.citrix.com \
--to=stefano.stabellini@eu.citrix.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).