summary refs log tree commit diff stats
path: root/ui
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-10-19 12:09:53 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-10-19 12:09:53 +0100
commitba6f0fc25e3c14fbb36f4b5a616a89cd3f1de6d0 (patch)
tree2bbf92549c6a4d29ad93374c1bd57e169ec8d9b0 /ui
parent73b733e6907e1193e562f498272108c95c00868c (diff)
parenta35179170034b60bcfb997e06bc63258caaf5049 (diff)
downloadfocaccia-qemu-ba6f0fc25e3c14fbb36f4b5a616a89cd3f1de6d0.tar.gz
focaccia-qemu-ba6f0fc25e3c14fbb36f4b5a616a89cd3f1de6d0.zip
Merge remote-tracking branch 'remotes/kraxel/tags/opengl-20171017-pull-request' into staging
ui: opengl updates for dma-buf support.

# gpg: Signature made Tue 17 Oct 2017 12:13:36 BST
# gpg:                using RSA key 0x4CB6D8EED3E87138
# 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>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/opengl-20171017-pull-request:
  egl-headless: add dmabuf support
  egl-helpers: add egl_texture_blit and egl_texture_blend
  egl-helpers: add dmabuf import support
  opengl: add flipping vertex shader
  opengl: move shader init from console-gl.c to shader.c
  console: add support for dmabufs

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'ui')
-rw-r--r--ui/console-gl.c45
-rw-r--r--ui/console.c33
-rw-r--r--ui/egl-headless.c59
-rw-r--r--ui/egl-helpers.c73
-rw-r--r--ui/gtk-egl.c2
-rw-r--r--ui/gtk-gl-area.c2
-rw-r--r--ui/sdl2-gl.c4
-rw-r--r--ui/shader.c57
-rw-r--r--ui/shader/texture-blit-flip.vert10
-rw-r--r--ui/spice-display.c2
10 files changed, 232 insertions, 55 deletions
diff --git a/ui/console-gl.c b/ui/console-gl.c
index 5165e21646..5b77e7aa88 100644
--- a/ui/console-gl.c
+++ b/ui/console-gl.c
@@ -29,40 +29,8 @@
 #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;
-    GLint texture_blit_vao;
-};
-
 /* ---------------------------------------------------------------------- */
 
-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);
-    }
-
-    gls->texture_blit_vao =
-        qemu_gl_init_texture_blit(gls->texture_blit_prog);
-
-    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)
 {
@@ -76,7 +44,7 @@ bool console_gl_check_format(DisplayChangeListener *dcl,
     }
 }
 
-void surface_gl_create_texture(ConsoleGLState *gls,
+void surface_gl_create_texture(QemuGLShader *gls,
                                DisplaySurface *surface)
 {
     assert(gls);
@@ -116,7 +84,7 @@ void surface_gl_create_texture(ConsoleGLState *gls,
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 }
 
-void surface_gl_update_texture(ConsoleGLState *gls,
+void surface_gl_update_texture(QemuGLShader *gls,
                                DisplaySurface *surface,
                                int x, int y, int w, int h)
 {
@@ -133,7 +101,7 @@ void surface_gl_update_texture(ConsoleGLState *gls,
                     + surface_bytes_per_pixel(surface) * x);
 }
 
-void surface_gl_render_texture(ConsoleGLState *gls,
+void surface_gl_render_texture(QemuGLShader *gls,
                                DisplaySurface *surface)
 {
     assert(gls);
@@ -141,11 +109,10 @@ void surface_gl_render_texture(ConsoleGLState *gls,
     glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 
-    qemu_gl_run_texture_blit(gls->texture_blit_prog,
-                             gls->texture_blit_vao);
+    qemu_gl_run_texture_blit(gls, false);
 }
 
-void surface_gl_destroy_texture(ConsoleGLState *gls,
+void surface_gl_destroy_texture(QemuGLShader *gls,
                                 DisplaySurface *surface)
 {
     if (!surface || !surface->texture) {
@@ -155,7 +122,7 @@ void surface_gl_destroy_texture(ConsoleGLState *gls,
     surface->texture = 0;
 }
 
-void surface_gl_setup_viewport(ConsoleGLState *gls,
+void surface_gl_setup_viewport(QemuGLShader *gls,
                                DisplaySurface *surface,
                                int ww, int wh)
 {
diff --git a/ui/console.c b/ui/console.c
index b82c27960a..eca854cbd5 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1404,6 +1404,11 @@ bool console_has_gl(QemuConsole *con)
     return con->gl != NULL;
 }
 
+bool console_has_gl_dmabuf(QemuConsole *con)
+{
+    return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
+}
+
 void register_displaychangelistener(DisplayChangeListener *dcl)
 {
     static const char nodev[] =
@@ -1745,6 +1750,34 @@ void dpy_gl_scanout_texture(QemuConsole *con,
                                          x, y, width, height);
 }
 
+void dpy_gl_scanout_dmabuf(QemuConsole *con,
+                           QemuDmaBuf *dmabuf)
+{
+    assert(con->gl);
+    con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
+}
+
+void dpy_gl_cursor_dmabuf(QemuConsole *con,
+                          QemuDmaBuf *dmabuf,
+                          uint32_t pos_x, uint32_t pos_y)
+{
+    assert(con->gl);
+
+    if (con->gl->ops->dpy_gl_cursor_dmabuf) {
+        con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf, pos_x, pos_y);
+    }
+}
+
+void dpy_gl_release_dmabuf(QemuConsole *con,
+                          QemuDmaBuf *dmabuf)
+{
+    assert(con->gl);
+
+    if (con->gl->ops->dpy_gl_release_dmabuf) {
+        con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
+    }
+}
+
 void dpy_gl_update(QemuConsole *con,
                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 {
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 12ad64e995..5d50226869 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -4,13 +4,18 @@
 #include "ui/console.h"
 #include "ui/egl-helpers.h"
 #include "ui/egl-context.h"
+#include "ui/shader.h"
 
 typedef struct egl_dpy {
     DisplayChangeListener dcl;
     DisplaySurface *ds;
+    QemuGLShader *gls;
     egl_fb guest_fb;
+    egl_fb cursor_fb;
     egl_fb blit_fb;
     bool y_0_top;
+    uint32_t pos_x;
+    uint32_t pos_y;
 } egl_dpy;
 
 /* ------------------------------------------------------------------ */
@@ -65,6 +70,43 @@ static void egl_scanout_texture(DisplayChangeListener *dcl,
     }
 }
 
+static void egl_scanout_dmabuf(DisplayChangeListener *dcl,
+                               QemuDmaBuf *dmabuf)
+{
+    egl_dmabuf_import_texture(dmabuf);
+    if (!dmabuf->texture) {
+        return;
+    }
+
+    egl_scanout_texture(dcl, dmabuf->texture,
+                        false, dmabuf->width, dmabuf->height,
+                        0, 0, dmabuf->width, dmabuf->height);
+}
+
+static void egl_cursor_dmabuf(DisplayChangeListener *dcl,
+                              QemuDmaBuf *dmabuf,
+                              uint32_t pos_x, uint32_t pos_y)
+{
+    egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
+
+    edpy->pos_x = pos_x;
+    edpy->pos_y = pos_y;
+
+    egl_dmabuf_import_texture(dmabuf);
+    if (!dmabuf->texture) {
+        return;
+    }
+
+    egl_fb_setup_for_tex(&edpy->cursor_fb, dmabuf->width, dmabuf->height,
+                         dmabuf->texture, false);
+}
+
+static void egl_release_dmabuf(DisplayChangeListener *dcl,
+                               QemuDmaBuf *dmabuf)
+{
+    egl_dmabuf_release_texture(dmabuf);
+}
+
 static void egl_scanout_flush(DisplayChangeListener *dcl,
                               uint32_t x, uint32_t y,
                               uint32_t w, uint32_t h)
@@ -78,9 +120,18 @@ static void egl_scanout_flush(DisplayChangeListener *dcl,
     assert(surface_height(edpy->ds) == edpy->guest_fb.height);
     assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
 
-    egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
-    egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb);
+    if (edpy->cursor_fb.texture) {
+        /* have cursor -> render using textures */
+        egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb,
+                         !edpy->y_0_top);
+        egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb,
+                          !edpy->y_0_top, edpy->pos_x, edpy->pos_y);
+    } else {
+        /* no cursor -> use simple framebuffer blit */
+        egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top);
+    }
 
+    egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb);
     dpy_gfx_update(edpy->dcl.con, x, y, w, h);
 }
 
@@ -97,6 +148,9 @@ static const DisplayChangeListenerOps egl_ops = {
 
     .dpy_gl_scanout_disable  = egl_scanout_disable,
     .dpy_gl_scanout_texture  = egl_scanout_texture,
+    .dpy_gl_scanout_dmabuf   = egl_scanout_dmabuf,
+    .dpy_gl_cursor_dmabuf    = egl_cursor_dmabuf,
+    .dpy_gl_release_dmabuf   = egl_release_dmabuf,
     .dpy_gl_update           = egl_scanout_flush,
 };
 
@@ -120,6 +174,7 @@ void egl_headless_init(void)
         edpy = g_new0(egl_dpy, 1);
         edpy->dcl.con = con;
         edpy->dcl.ops = &egl_ops;
+        edpy->gls = qemu_gl_init_shader();
         register_displaychangelistener(&edpy->dcl);
     }
 }
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index cde9965dea..5fa60ef4e8 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -19,6 +19,7 @@
 #include <dirent.h>
 
 #include "qemu/error-report.h"
+#include "ui/console.h"
 #include "ui/egl-helpers.h"
 
 EGLDisplay *qemu_egl_display;
@@ -110,6 +111,33 @@ void egl_fb_read(void *dst, egl_fb *src)
                  GL_BGRA, GL_UNSIGNED_BYTE, dst);
 }
 
+void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip)
+{
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
+    glViewport(0, 0, dst->width, dst->height);
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, src->texture);
+    qemu_gl_run_texture_blit(gls, flip);
+}
+
+void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
+                       int x, int y)
+{
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
+    if (flip) {
+        glViewport(x, y, src->width, src->height);
+    } else {
+        glViewport(x, dst->height - src->height - y,
+                   src->width, src->height);
+    }
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, src->texture);
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    qemu_gl_run_texture_blit(gls, flip);
+    glDisable(GL_BLEND);
+}
+
 /* ---------------------------------------------------------------------- */
 
 #ifdef CONFIG_OPENGL_DMABUF
@@ -241,6 +269,51 @@ int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc)
     return fd;
 }
 
+void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
+{
+    EGLImageKHR image = EGL_NO_IMAGE_KHR;
+    EGLint attrs[] = {
+        EGL_DMA_BUF_PLANE0_FD_EXT,      dmabuf->fd,
+        EGL_DMA_BUF_PLANE0_PITCH_EXT,   dmabuf->stride,
+        EGL_DMA_BUF_PLANE0_OFFSET_EXT,  0,
+        EGL_WIDTH,                      dmabuf->width,
+        EGL_HEIGHT,                     dmabuf->height,
+        EGL_LINUX_DRM_FOURCC_EXT,       dmabuf->fourcc,
+        EGL_NONE, /* end of list */
+    };
+
+    if (dmabuf->texture != 0) {
+        return;
+    }
+
+    image = eglCreateImageKHR(qemu_egl_display,
+                              EGL_NO_CONTEXT,
+                              EGL_LINUX_DMA_BUF_EXT,
+                              NULL, attrs);
+    if (image == EGL_NO_IMAGE_KHR) {
+        error_report("eglCreateImageKHR failed");
+        return;
+    }
+
+    glGenTextures(1, &dmabuf->texture);
+    glBindTexture(GL_TEXTURE_2D, dmabuf->texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+    eglDestroyImageKHR(qemu_egl_display, image);
+}
+
+void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf)
+{
+    if (dmabuf->texture == 0) {
+        return;
+    }
+
+    glDeleteTextures(1, &dmabuf->texture);
+    dmabuf->texture = 0;
+}
+
 #endif /* CONFIG_OPENGL_DMABUF */
 
 /* ---------------------------------------------------------------------- */
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 0f0d35e041..eb86c26a1d 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -113,7 +113,7 @@ void gd_egl_refresh(DisplayChangeListener *dcl)
         if (!vc->gfx.esurface) {
             return;
         }
-        vc->gfx.gls = console_gl_init_context();
+        vc->gfx.gls = qemu_gl_init_shader();
         if (vc->gfx.ds) {
             surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
         }
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index 7080f4e14f..147ad6f9b5 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -96,7 +96,7 @@ void gd_gl_area_refresh(DisplayChangeListener *dcl)
             return;
         }
         gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
-        vc->gfx.gls = console_gl_init_context();
+        vc->gfx.gls = qemu_gl_init_shader();
         if (vc->gfx.ds) {
             surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
         }
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index 9110491ee5..5e1073a084 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -90,7 +90,7 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,
     scon->surface = new_surface;
 
     if (!new_surface) {
-        console_gl_fini_context(scon->gls);
+        qemu_gl_fini_shader(scon->gls);
         scon->gls = NULL;
         sdl2_window_destroy(scon);
         return;
@@ -98,7 +98,7 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,
 
     if (!scon->real_window) {
         sdl2_window_create(scon);
-        scon->gls = console_gl_init_context();
+        scon->gls = qemu_gl_init_shader();
     } else if (old_surface &&
                ((surface_width(old_surface)  != surface_width(new_surface)) ||
                 (surface_height(old_surface) != surface_height(new_surface)))) {
diff --git a/ui/shader.c b/ui/shader.c
index 1ffddbef3b..008458bf94 100644
--- a/ui/shader.c
+++ b/ui/shader.c
@@ -28,9 +28,19 @@
 #include "qemu-common.h"
 #include "ui/shader.h"
 
+#include "shader/texture-blit-vert.h"
+#include "shader/texture-blit-flip-vert.h"
+#include "shader/texture-blit-frag.h"
+
+struct QemuGLShader {
+    GLint texture_blit_prog;
+    GLint texture_blit_flip_prog;
+    GLint texture_blit_vao;
+};
+
 /* ---------------------------------------------------------------------- */
 
-GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
+static GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
 {
     static const GLfloat in_position[] = {
         -1, -1,
@@ -60,17 +70,18 @@ GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
     return vao;
 }
 
-void qemu_gl_run_texture_blit(GLint texture_blit_prog,
-                              GLint texture_blit_vao)
+void qemu_gl_run_texture_blit(QemuGLShader *gls, bool flip)
 {
-    glUseProgram(texture_blit_prog);
-    glBindVertexArray(texture_blit_vao);
+    glUseProgram(flip
+                 ? gls->texture_blit_flip_prog
+                 : gls->texture_blit_prog);
+    glBindVertexArray(gls->texture_blit_vao);
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 }
 
 /* ---------------------------------------------------------------------- */
 
-GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src)
+static GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src)
 {
     GLuint shader;
     GLint status, length;
@@ -94,7 +105,7 @@ GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src)
     return shader;
 }
 
-GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag)
+static GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag)
 {
     GLuint program;
     GLint status, length;
@@ -117,8 +128,8 @@ GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag)
     return program;
 }
 
-GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
-                                           const GLchar *frag_src)
+static GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
+                                                  const GLchar *frag_src)
 {
     GLuint vert_shader, frag_shader, program;
 
@@ -134,3 +145,31 @@ GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src,
 
     return program;
 }
+
+/* ---------------------------------------------------------------------- */
+
+QemuGLShader *qemu_gl_init_shader(void)
+{
+    QemuGLShader *gls = g_new0(QemuGLShader, 1);
+
+    gls->texture_blit_prog = qemu_gl_create_compile_link_program
+        (texture_blit_vert_src, texture_blit_frag_src);
+    gls->texture_blit_flip_prog = qemu_gl_create_compile_link_program
+        (texture_blit_flip_vert_src, texture_blit_frag_src);
+    if (!gls->texture_blit_prog || !gls->texture_blit_flip_prog) {
+        exit(1);
+    }
+
+    gls->texture_blit_vao =
+        qemu_gl_init_texture_blit(gls->texture_blit_prog);
+
+    return gls;
+}
+
+void qemu_gl_fini_shader(QemuGLShader *gls)
+{
+    if (!gls) {
+        return;
+    }
+    g_free(gls);
+}
diff --git a/ui/shader/texture-blit-flip.vert b/ui/shader/texture-blit-flip.vert
new file mode 100644
index 0000000000..ba081fa5a6
--- /dev/null
+++ b/ui/shader/texture-blit-flip.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;
+}
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 0963c7825f..ad1ceafb3f 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1019,7 +1019,7 @@ static void qemu_spice_display_init_one(QemuConsole *con)
         ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);
         ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
                                              qemu_spice_gl_block_timer, ssd);
-        ssd->gls = console_gl_init_context();
+        ssd->gls = qemu_gl_init_shader();
         ssd->have_surface = false;
         ssd->have_scanout = false;
     }