mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 18:05:37 +00:00
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:
commit
874e9aeeeb
17
Makefile
17
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
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -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"
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
11
include/ui/shader.h
Normal 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
16
scripts/shaderinclude.pl
Normal 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;
|
|
@ -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
168
ui/console-gl.c
Normal 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);
|
||||
}
|
||||
}
|
10
ui/sdl.c
10
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;
|
||||
|
|
28
ui/sdl2-2d.c
28
ui/sdl2-2d.c
|
@ -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
112
ui/sdl2-gl.c
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
71
ui/sdl2.c
71
ui/sdl2.c
|
@ -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
114
ui/shader.c
Normal 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;
|
||||
}
|
10
ui/shader/texture-blit.frag
Normal file
10
ui/shader/texture-blit.frag
Normal 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);
|
||||
}
|
10
ui/shader/texture-blit.vert
Normal file
10
ui/shader/texture-blit.vert
Normal 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
23
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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue