OSDN Git Service

Merge remote-tracking branch 'remotes/kraxel/tags/pull-sdl-20150505-1' into staging
authorPeter Maydell <peter.maydell@linaro.org>
Tue, 5 May 2015 13:06:12 +0000 (14:06 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Tue, 5 May 2015 13:06:12 +0000 (14:06 +0100)
sdl2: add opengl support

# gpg: Signature made Tue May  5 10:36:25 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-sdl-20150505-1:
  sdl2: Fix RGB555
  sdl2: add support for display rendering using opengl.
  sdl2: move SDL_* includes to sdl2.h
  console-gl: add opengl rendering helper functions
  opengl: add shader helper functions.
  opengl: add shader build infrastructure

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17 files changed:
Makefile
configure
include/ui/console.h
include/ui/sdl2.h
include/ui/shader.h [new file with mode: 0644]
scripts/shaderinclude.pl [new file with mode: 0644]
ui/Makefile.objs
ui/console-gl.c [new file with mode: 0644]
ui/sdl.c
ui/sdl2-2d.c
ui/sdl2-gl.c [new file with mode: 0644]
ui/sdl2-input.c
ui/sdl2.c
ui/shader.c [new file with mode: 0644]
ui/shader/texture-blit.frag [new file with mode: 0644]
ui/shader/texture-blit.vert [new file with mode: 0644]
vl.c

index 93af871..f032158 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -296,6 +296,7 @@ clean:
        rm -f fsdev/*.pod
        rm -rf .libs */.libs
        rm -f qemu-img-cmds.h
+       rm -f ui/shader/*-vert.h ui/shader/*-frag.h
        @# May not be present in GENERATED_HEADERS
        rm -f trace/generated-tracers-dtrace.dtrace*
        rm -f trace/generated-tracers-dtrace.h*
@@ -441,6 +442,22 @@ cscope:
        find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
        cscope -b
 
+# opengl shader programs
+ui/shader/%-vert.h: $(SRC_PATH)/ui/shader/%.vert $(SRC_PATH)/scripts/shaderinclude.pl
+       @mkdir -p $(dir $@)
+       $(call quiet-command,\
+               perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
+               "  VERT  $@")
+
+ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclude.pl
+       @mkdir -p $(dir $@)
+       $(call quiet-command,\
+               perl $(SRC_PATH)/scripts/shaderinclude.pl $< > $@,\
+               "  FRAG  $@")
+
+ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
+       ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h
+
 # documentation
 MAKEINFO=makeinfo
 MAKEINFOFLAGS=--no-headers --no-split --number-sections
index 255d85b..b18aa9e 100755 (executable)
--- a/configure
+++ b/configure
@@ -3142,7 +3142,7 @@ else
 fi
 
 if test "$opengl" != "no" ; then
-  opengl_pkgs="gl"
+  opengl_pkgs="gl glesv2"
   if $pkg_config $opengl_pkgs x11 && test "$have_glx" = "yes"; then
     opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
     opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
index 03cd665..0b75896 100644 (file)
@@ -9,6 +9,11 @@
 #include "qapi-types.h"
 #include "qapi/error.h"
 
+#ifdef CONFIG_OPENGL
+# include <GLES2/gl2.h>
+# include <GLES2/gl2ext.h>
+#endif
+
 /* keyboard/mouse support */
 
 #define MOUSE_EVENT_LBUTTON 0x01
@@ -117,6 +122,11 @@ struct DisplaySurface {
     pixman_format_code_t format;
     pixman_image_t *image;
     uint8_t flags;
+#ifdef CONFIG_OPENGL
+    GLenum glformat;
+    GLenum gltype;
+    GLuint texture;
+#endif
 };
 
 typedef struct QemuUIInfo {
@@ -270,6 +280,11 @@ static inline int surface_bytes_per_pixel(DisplaySurface *s)
     return (bits + 7) / 8;
 }
 
+static inline pixman_format_code_t surface_format(DisplaySurface *s)
+{
+    return s->format;
+}
+
 #ifdef CONFIG_CURSES
 #include <curses.h>
 typedef chtype console_ch_t;
@@ -322,7 +337,29 @@ void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
                        int dst_x, int dst_y, int w, int h);
 DisplaySurface *qemu_console_surface(QemuConsole *con);
 
+/* console-gl.c */
+typedef struct ConsoleGLState ConsoleGLState;
+#ifdef CONFIG_OPENGL
+ConsoleGLState *console_gl_init_context(void);
+void console_gl_fini_context(ConsoleGLState *gls);
+bool console_gl_check_format(DisplayChangeListener *dcl,
+                             pixman_format_code_t format);
+void surface_gl_create_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface);
+void surface_gl_update_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface,
+                               int x, int y, int w, int h);
+void surface_gl_render_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface);
+void surface_gl_destroy_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface);
+void surface_gl_setup_viewport(ConsoleGLState *gls,
+                               DisplaySurface *surface,
+                               int ww, int wh);
+#endif
+
 /* sdl.c */
+void sdl_display_early_init(int opengl);
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 
 /* cocoa.m */
index 51fff2e..2fdad8f 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef SDL2_H
 #define SDL2_H
 
+/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
+#undef WIN32_LEAN_AND_MEAN
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+
 struct sdl2_console {
     DisplayChangeListener dcl;
     DisplaySurface *surface;
@@ -11,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);
@@ -31,4 +41,11 @@ void sdl2_2d_redraw(struct sdl2_console *scon);
 bool sdl2_2d_check_format(DisplayChangeListener *dcl,
                           pixman_format_code_t format);
 
+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/include/ui/shader.h b/include/ui/shader.h
new file mode 100644 (file)
index 0000000..1ff926c
--- /dev/null
@@ -0,0 +1,11 @@
+#ifdef CONFIG_OPENGL
+# include <GLES2/gl2.h>
+# include <GLES2/gl2ext.h>
+#endif
+
+void qemu_gl_run_texture_blit(GLint texture_blit_prog);
+
+GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
+GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
+GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
+                                           const GLchar *frag_src);
diff --git a/scripts/shaderinclude.pl b/scripts/shaderinclude.pl
new file mode 100644 (file)
index 0000000..81b5146
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+my $file = shift;
+open FILE, "<", $file or die "open $file: $!";
+my $name = $file;
+$name =~ s|.*/||;
+$name =~ s/[-.]/_/g;
+print "static GLchar ${name}_src[] =\n";
+while (<FILE>) {
+    chomp;
+    printf "    \"%s\\n\"\n", $_;
+}
+print "    \"\\n\";\n";
+close FILE;
index 13b5cfb..029a42a 100644 (file)
@@ -21,7 +21,20 @@ 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)
 
+ifeq ($(CONFIG_OPENGL),y)
+common-obj-y += shader.o
+common-obj-y += console-gl.o
+endif
+
 gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
+shader.o-cflags += $(OPENGL_CFLAGS)
+console-gl.o-cflags += $(OPENGL_CFLAGS)
+
+shader.o-libs += $(OPENGL_LIBS)
+console-gl.o-libs += $(OPENGL_LIBS)
diff --git a/ui/console-gl.c b/ui/console-gl.c
new file mode 100644 (file)
index 0000000..cb45cf8
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * QEMU graphical console -- opengl helper bits
+ *
+ * Copyright (c) 2014 Red Hat
+ *
+ * Authors:
+ *    Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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/shader.h"
+
+#include "shader/texture-blit-vert.h"
+#include "shader/texture-blit-frag.h"
+
+struct ConsoleGLState {
+    GLint texture_blit_prog;
+};
+
+/* ---------------------------------------------------------------------- */
+
+ConsoleGLState *console_gl_init_context(void)
+{
+    ConsoleGLState *gls = g_new0(ConsoleGLState, 1);
+
+    gls->texture_blit_prog = qemu_gl_create_compile_link_program
+        (texture_blit_vert_src, texture_blit_frag_src);
+    if (!gls->texture_blit_prog) {
+        exit(1);
+    }
+
+    return gls;
+}
+
+void console_gl_fini_context(ConsoleGLState *gls)
+{
+    if (!gls) {
+        return;
+    }
+    g_free(gls);
+}
+
+bool console_gl_check_format(DisplayChangeListener *dcl,
+                             pixman_format_code_t format)
+{
+    switch (format) {
+    case PIXMAN_BE_b8g8r8x8:
+    case PIXMAN_BE_b8g8r8a8:
+    case PIXMAN_r5g6b5:
+        return true;
+    default:
+        return false;
+    }
+}
+
+void surface_gl_create_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface)
+{
+    assert(gls);
+    assert(surface_stride(surface) % surface_bytes_per_pixel(surface) == 0);
+
+    switch (surface->format) {
+    case PIXMAN_BE_b8g8r8x8:
+    case PIXMAN_BE_b8g8r8a8:
+        surface->glformat = GL_BGRA_EXT;
+        surface->gltype = GL_UNSIGNED_BYTE;
+        break;
+    case PIXMAN_r5g6b5:
+        surface->glformat = GL_RGB;
+        surface->gltype = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    glGenTextures(1, &surface->texture);
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, surface->texture);
+    glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
+                  surface_stride(surface) / surface_bytes_per_pixel(surface));
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+                 surface_width(surface),
+                 surface_height(surface),
+                 0, surface->glformat, surface->gltype,
+                 surface_data(surface));
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+void surface_gl_update_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface,
+                               int x, int y, int w, int h)
+{
+    uint8_t *data = (void *)surface_data(surface);
+
+    assert(gls);
+
+    glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
+                  surface_stride(surface) / surface_bytes_per_pixel(surface));
+    glTexSubImage2D(GL_TEXTURE_2D, 0,
+                    x, y, w, h,
+                    surface->glformat, surface->gltype,
+                    data + surface_stride(surface) * y
+                    + surface_bytes_per_pixel(surface) * x);
+}
+
+void surface_gl_render_texture(ConsoleGLState *gls,
+                               DisplaySurface *surface)
+{
+    assert(gls);
+
+    glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    qemu_gl_run_texture_blit(gls->texture_blit_prog);
+}
+
+void surface_gl_destroy_texture(ConsoleGLState *gls,
+                                DisplaySurface *surface)
+{
+    if (!surface || !surface->texture) {
+        return;
+    }
+    glDeleteTextures(1, &surface->texture);
+    surface->texture = 0;
+}
+
+void surface_gl_setup_viewport(ConsoleGLState *gls,
+                               DisplaySurface *surface,
+                               int ww, int wh)
+{
+    int gw, gh, stripe;
+    float sw, sh;
+
+    assert(gls);
+
+    gw = surface_width(surface);
+    gh = surface_height(surface);
+
+    sw = (float)ww/gw;
+    sh = (float)wh/gh;
+    if (sw < sh) {
+        stripe = wh - wh*sw/sh;
+        glViewport(0, stripe / 2, ww, wh - stripe);
+    } else {
+        stripe = ww - ww*sh/sw;
+        glViewport(stripe / 2, 0, ww - stripe, wh);
+    }
+}
index 8bdbf52..3be2910 100644 (file)
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -908,6 +908,16 @@ 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");
+    }
+}
+
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
 {
     int flags;
index f907c21..d0b340f 100644 (file)
  */
 /* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
 
-/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
-#undef WIN32_LEAN_AND_MEAN
-
-#include <SDL.h>
-#include <SDL_syswm.h>
-
 #include "qemu-common.h"
 #include "ui/console.h"
 #include "ui/input.h"
@@ -42,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;
     }
@@ -67,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) {
@@ -91,10 +89,21 @@ void sdl2_2d_switch(DisplayChangeListener *dcl,
                              surface_width(new_surface),
                              surface_height(new_surface));
 
-    if (surface_bits_per_pixel(scon->surface) == 16) {
+    switch (surface_format(scon->surface)) {
+    case PIXMAN_x1r5g5b5:
+        format = SDL_PIXELFORMAT_ARGB1555;
+        break;
+    case PIXMAN_r5g6b5:
         format = SDL_PIXELFORMAT_RGB565;
-    } else if (surface_bits_per_pixel(scon->surface) == 32) {
+        break;
+    case PIXMAN_x8r8g8b8:
         format = SDL_PIXELFORMAT_ARGB8888;
+        break;
+    case PIXMAN_r8g8b8x8:
+        format = SDL_PIXELFORMAT_RGBA8888;
+        break;
+    default:
+        g_assert_not_reached();
     }
     scon->texture = SDL_CreateTexture(scon->real_renderer, format,
                                       SDL_TEXTUREACCESS_STREAMING,
@@ -107,12 +116,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 (file)
index 0000000..b604c06
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * QEMU SDL display driver -- opengl support
+ *
+ * Copyright (c) 2014 Red Hat
+ *
+ * Authors:
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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);
+    }
+}
index a1973fc..ac5dc94 100644 (file)
  */
 /* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
 
-/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
-#undef WIN32_LEAN_AND_MEAN
-
-#include <SDL.h>
-#include <SDL_syswm.h>
-
 #include "qemu-common.h"
 #include "ui/console.h"
 #include "ui/input.h"
index 60e3c3b..2d60179 100644 (file)
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
  */
 /* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
 
-/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
-#undef WIN32_LEAN_AND_MEAN
-
-#include <SDL.h>
-#include <SDL_syswm.h>
-
 #include "qemu-common.h"
 #include "ui/console.h"
 #include "ui/input.h"
@@ -92,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);
 }
 
@@ -118,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];
@@ -316,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)
@@ -364,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
@@ -384,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
@@ -520,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:
@@ -677,6 +687,35 @@ 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_gfx_check_format    = console_gl_check_format,
+    .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;
+#endif
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+}
+
 void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
 {
     int flags;
@@ -722,10 +761,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/ui/shader.c b/ui/shader.c
new file mode 100644 (file)
index 0000000..52a4632
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * QEMU opengl shader helper functions
+ *
+ * Copyright (c) 2014 Red Hat
+ *
+ * Authors:
+ *    Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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/shader.h"
+
+/* ---------------------------------------------------------------------- */
+
+void qemu_gl_run_texture_blit(GLint texture_blit_prog)
+{
+    GLfloat in_position[] = {
+        -1, -1,
+        1,  -1,
+        -1,  1,
+        1,   1,
+    };
+    GLint l_position;
+
+    glUseProgram(texture_blit_prog);
+    l_position = glGetAttribLocation(texture_blit_prog, "in_position");
+    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position);
+    glEnableVertexAttribArray(l_position);
+    glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4);
+}
+
+/* ---------------------------------------------------------------------- */
+
+GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src)
+{
+    GLuint shader;
+    GLint status, length;
+    char *errmsg;
+
+    shader = glCreateShader(type);
+    glShaderSource(shader, 1, &src, 0);
+    glCompileShader(shader);
+
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+    if (!status) {
+        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+        errmsg = malloc(length);
+        glGetShaderInfoLog(shader, length, &length, errmsg);
+        fprintf(stderr, "%s: compile %s error\n%s\n", __func__,
+                (type == GL_VERTEX_SHADER) ? "vertex" : "fragment",
+                errmsg);
+        free(errmsg);
+        return 0;
+    }
+    return shader;
+}
+
+GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag)
+{
+    GLuint program;
+    GLint status, length;
+    char *errmsg;
+
+    program = glCreateProgram();
+    glAttachShader(program, vert);
+    glAttachShader(program, frag);
+    glLinkProgram(program);
+
+    glGetProgramiv(program, GL_LINK_STATUS, &status);
+    if (!status) {
+        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
+        errmsg = malloc(length);
+        glGetProgramInfoLog(program, length, &length, errmsg);
+        fprintf(stderr, "%s: link program: %s\n", __func__, errmsg);
+        free(errmsg);
+        return 0;
+    }
+    return program;
+}
+
+GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
+                                           const GLchar *frag_src)
+{
+    GLuint vert_shader, frag_shader, program;
+
+    vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src);
+    frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src);
+    if (!vert_shader || !frag_shader) {
+        return 0;
+    }
+
+    program = qemu_gl_create_link_program(vert_shader, frag_shader);
+    glDeleteShader(vert_shader);
+    glDeleteShader(frag_shader);
+
+    return program;
+}
diff --git a/ui/shader/texture-blit.frag b/ui/shader/texture-blit.frag
new file mode 100644 (file)
index 0000000..bfa202c
--- /dev/null
@@ -0,0 +1,10 @@
+
+#version 300 es
+
+uniform sampler2D image;
+in  mediump vec2 ex_tex_coord;
+out mediump vec4 out_frag_color;
+
+void main(void) {
+     out_frag_color = texture(image, ex_tex_coord);
+}
diff --git a/ui/shader/texture-blit.vert b/ui/shader/texture-blit.vert
new file mode 100644 (file)
index 0000000..6fe2744
--- /dev/null
@@ -0,0 +1,10 @@
+
+#version 300 es
+
+in vec2  in_position;
+out vec2 ex_tex_coord;
+
+void main(void) {
+    gl_Position = vec4(in_position, 0.0, 1.0);
+    ex_tex_coord = vec2(1.0 + in_position.x, 1.0 - in_position.y) * 0.5;
+}
diff --git a/vl.c b/vl.c
index 74c2681..15bccc4 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -130,6 +130,7 @@ static int data_dir_idx;
 const char *bios_name = NULL;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 DisplayType display_type = DT_DEFAULT;
+int request_opengl = -1;
 int display_opengl;
 static int display_remote;
 const char* keyboard_layout = NULL;
@@ -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)) {
+                    request_opengl = 1;
+                } else if (strstart(opts, "off", &nextopt)) {
+                    request_opengl = 0;
+                } else {
+                    goto invalid_sdl_args;
+                }
             } else {
             invalid_sdl_args:
                 fprintf(stderr, "Invalid SDL option string: %s\n", p);
@@ -4005,6 +4015,19 @@ int main(int argc, char **argv, char **envp)
         early_gtk_display_init();
     }
 #endif
+#if defined(CONFIG_SDL)
+    if (display_type == DT_SDL) {
+        sdl_display_early_init(request_opengl);
+    }
+#endif
+    if (request_opengl == 1 && display_opengl == 0) {
+#if defined(CONFIG_OPENGL)
+        fprintf(stderr, "OpenGL is not supported by the display.\n");
+#else
+        fprintf(stderr, "QEMU was built without opengl support.\n");
+#endif
+        exit(1);
+    }
 
     socket_init();