sdl2: add opengl support

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJVSI8ZAAoJEEy22O7T6HE466UP/AoBptoGXuk4e4/XMRBydTbg
 SEEYHDL0iLQMhnsiVbdPKcRvgmsjuUgM8t5iwcK2YHiyxfhH5VxEgeK24llrSYye
 EBZtOAUq9hqgmJUZ/ma4PDv0B+4muqEQetoPV20zF8hmabw4tKQ7X49tI0K947Zy
 KYgOaoo4BkIuzXKjVo/kdk/Lj123muNAfs1zBzvMWsriHyQ1MI5GYerryIOaUVpA
 64sruQytgsimErUdYdeWRkd+7PR8JkWRc8kUQCFkRSYpfqYGFCdh733SCQbYNAkg
 mmtWuAfOR7drf/01c1xO7/W9BRiVEYgjdRgM0vus6LIdmPhh9kilOpz9txnkAMO6
 1reYchCdj8SgKIEoSMs8yhdRFnHx+au3wLWw6GhEH0WbBTrI3J42nzhxUI+vvC7M
 wxxOv1WvaTYm212pzmpxH72/T8BMhhZ5jb1/7gTduxn82OetuzT0zPKrhmbiIxVf
 azD48H9VK75vPHeoXUCWetK5L5V5pC49jGRfFcv+xtvNLbwAV8wTlCK2MV8HeVTM
 pmtxl8mtJ9PxkcbtXom5L+3DGCTFtuTPNRQMT/aI7V8bawLSsbs75FTjNDWzxFwz
 T19nh2+Id+tSuT1huY67D84UBBuRo4RvVeNO55pQlp1RhXOp04b9fJ45bgIVF0BF
 zrJ4mNoTQAAq5Ie8PO33
 =QrjG
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/pull-sdl-20150505-1' into staging

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>
This commit is contained in:
Peter Maydell 2015-05-05 14:06:12 +01:00
commit 874e9aeeeb
17 changed files with 637 additions and 28 deletions

View File

@ -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

2
configure vendored
View File

@ -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"

View 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 */

View 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 */

11
include/ui/shader.h Normal file
View File

@ -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);

16
scripts/shaderinclude.pl Normal file
View File

@ -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;

View 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)

168
ui/console-gl.c Normal file
View File

@ -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);
}
}

View File

@ -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;

View File

@ -23,12 +23,6 @@
*/
/* 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;
}

112
ui/sdl2-gl.c Normal file
View File

@ -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);
}
}

View File

@ -23,12 +23,6 @@
*/
/* 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"

View File

@ -23,12 +23,6 @@
*/
/* 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. */

114
ui/shader.c Normal file
View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

23
vl.c
View File

@ -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();