From cd2bc889e5b30c69926fc1511b6522e7cb4c705d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 9 Jan 2015 11:40:23 +0100 Subject: [PATCH] console-gl: add opengl rendering helper functions Signed-off-by: Gerd Hoffmann Reviewed-by: Max Reitz --- Makefile | 3 + configure | 2 +- include/ui/console.h | 31 +++++++ include/ui/shader.h | 2 + ui/Makefile.objs | 3 + ui/console-gl.c | 168 ++++++++++++++++++++++++++++++++++++ ui/shader.c | 19 ++++ ui/shader/texture-blit.frag | 10 +++ ui/shader/texture-blit.vert | 10 +++ 9 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 ui/console-gl.c create mode 100644 ui/shader/texture-blit.frag create mode 100644 ui/shader/texture-blit.vert diff --git a/Makefile b/Makefile index 49e456769c..f032158645 100644 --- a/Makefile +++ b/Makefile @@ -455,6 +455,9 @@ ui/shader/%-frag.h: $(SRC_PATH)/ui/shader/%.frag $(SRC_PATH)/scripts/shaderinclu 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 diff --git a/configure b/configure index 255d85bf1d..b18aa9ebd5 100755 --- 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" diff --git a/include/ui/console.h b/include/ui/console.h index 03cd665a8f..ee00fc58f2 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -9,6 +9,11 @@ #include "qapi-types.h" #include "qapi/error.h" +#ifdef CONFIG_OPENGL +# include +# include +#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 { @@ -322,6 +332,27 @@ 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_init(DisplayState *ds, int full_screen, int no_frame); diff --git a/include/ui/shader.h b/include/ui/shader.h index e1b0caf796..1ff926c9e1 100644 --- a/include/ui/shader.h +++ b/include/ui/shader.h @@ -3,6 +3,8 @@ # include #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, diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 7a76df578f..67fe278c15 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -26,9 +26,12 @@ 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 index 0000000000..cb45cf8a29 --- /dev/null +++ b/ui/console-gl.c @@ -0,0 +1,168 @@ +/* + * QEMU graphical console -- opengl helper bits + * + * Copyright (c) 2014 Red Hat + * + * Authors: + * Gerd Hoffmann + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/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); + } +} diff --git a/ui/shader.c b/ui/shader.c index c3272d690b..52a4632930 100644 --- a/ui/shader.c +++ b/ui/shader.c @@ -29,6 +29,25 @@ /* ---------------------------------------------------------------------- */ +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; diff --git a/ui/shader/texture-blit.frag b/ui/shader/texture-blit.frag new file mode 100644 index 0000000000..bfa202c22b --- /dev/null +++ b/ui/shader/texture-blit.frag @@ -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 index 0000000000..6fe2744d68 --- /dev/null +++ b/ui/shader/texture-blit.vert @@ -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; +}