From patchwork Tue Mar 3 12:07:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 445677 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 776261400D5 for ; Tue, 3 Mar 2015 23:08:10 +1100 (AEDT) Received: from localhost ([::1]:36301 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YSlcO-000540-8y for incoming@patchwork.ozlabs.org; Tue, 03 Mar 2015 07:08:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38167) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YSlbf-0004jp-Um for qemu-devel@nongnu.org; Tue, 03 Mar 2015 07:07:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YSlbW-0005cm-MY for qemu-devel@nongnu.org; Tue, 03 Mar 2015 07:07:22 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49362) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YSlbW-0005ca-Es for qemu-devel@nongnu.org; Tue, 03 Mar 2015 07:07:14 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t23C7CuY013782 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 3 Mar 2015 07:07:12 -0500 Received: from nilsson.home.kraxel.org (ovpn-116-39.ams2.redhat.com [10.36.116.39]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t23C7Abo010841; Tue, 3 Mar 2015 07:07:10 -0500 Received: by nilsson.home.kraxel.org (Postfix, from userid 500) id 58E0281A36; Tue, 3 Mar 2015 13:07:09 +0100 (CET) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Tue, 3 Mar 2015 13:07:05 +0100 Message-Id: <1425384427-2551-3-git-send-email-kraxel@redhat.com> In-Reply-To: <1425384427-2551-1-git-send-email-kraxel@redhat.com> References: <1425384427-2551-1-git-send-email-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Gerd Hoffmann , Anthony Liguori Subject: [Qemu-devel] [PATCH 2/4] console-gl: add opengl rendering helper functions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Gerd Hoffmann Reviewed-by: Max Reitz --- Makefile | 3 + configure | 2 +- include/ui/console.h | 31 ++++++ ui/Makefile.objs | 5 + ui/console-gl.c | 253 ++++++++++++++++++++++++++++++++++++++++++++ ui/shader/texture-blit.frag | 10 ++ ui/shader/texture-blit.vert | 10 ++ 7 files changed, 313 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 285eb27..6d77782 100644 --- a/Makefile +++ b/Makefile @@ -451,6 +451,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 a071bbb..8447c14 100755 --- a/configure +++ b/configure @@ -3120,7 +3120,7 @@ libs_softmmu="$libs_softmmu $fdt_libs" ########################################## # opengl probe (for sdl2, milkymist-tmu2) if test "$opengl" != "no" ; then - opengl_pkgs="gl" + opengl_pkgs="gl glesv2" if $pkg_config $opengl_pkgs x11; then opengl_cflags="$($pkg_config --libs $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 0f97d86..5b31492 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 @@ -118,6 +123,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 { @@ -324,6 +334,27 @@ void qemu_console_copy(QemuConsole *con, int src_x, int src_y, DisplaySurface *qemu_console_surface(QemuConsole *con); DisplayState *qemu_console_displaystate(QemuConsole *console); +/* 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/ui/Makefile.objs b/ui/Makefile.objs index 13b5cfb..3173778 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -24,4 +24,9 @@ sdl.mo-objs := sdl2.o sdl2-input.o sdl2-2d.o endif sdl.mo-cflags := $(SDL_CFLAGS) +ifeq ($(CONFIG_OPENGL),y) +common-obj-y += console-gl.o +libs_softmmu += $(OPENGL_LIBS) +endif + gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) diff --git a/ui/console-gl.c b/ui/console-gl.c new file mode 100644 index 0000000..36951b9 --- /dev/null +++ b/ui/console-gl.c @@ -0,0 +1,253 @@ +/* + * 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" + +struct ConsoleGLState { + GLint texture_blit_prog; +}; + +/* ---------------------------------------------------------------------- */ + +#include "shader/texture-blit-vert.h" +#include "shader/texture-blit-frag.h" + +static void gl_run_texture_blit(ConsoleGLState *gls) +{ + GLfloat in_position[] = { + -1, -1, + 1, -1, + -1, 1, + 1, 1, + }; + GLint l_position; + + glUseProgram(gls->texture_blit_prog); + l_position = glGetAttribLocation(gls->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); +} + +/* ---------------------------------------------------------------------- */ + +static GLuint 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; +} + +static GLuint 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; +} + +static GLuint gl_create_compile_link_program(const GLchar *vert_src, + const GLchar *frag_src) +{ + GLuint vert_shader, frag_shader, program; + + vert_shader = gl_create_compile_shader(GL_VERTEX_SHADER, vert_src); + frag_shader = gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src); + if (!vert_shader || !frag_shader) { + return 0; + } + + program = gl_create_link_program(vert_shader, frag_shader); + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + + return program; +} + +/* ---------------------------------------------------------------------- */ + +ConsoleGLState *console_gl_init_context(void) +{ + ConsoleGLState *gls = g_new0(ConsoleGLState, 1); + + gls->texture_blit_prog = 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); + + gl_run_texture_blit(gls); +} + +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/texture-blit.frag b/ui/shader/texture-blit.frag new file mode 100644 index 0000000..bfa202c --- /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 0000000..6fe2744 --- /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; +}