All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/9] add virgl rendering support.
@ 2015-09-09 11:20 Gerd Hoffmann
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
                   ` (9 more replies)
  0 siblings, 10 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

This patch series adds infrastructure for opengl rendering
(context management, define scanout textures), adds support
for this to sdl2 and gtk user interfaces and adds virgl/3d
mode to virtio-gpu by hooking up the virglrenderer library.

please review,
  Gerd

Gerd Hoffmann (9):
  shaders: initialize vertexes once
  sdl2: quick & dirty flicker workaround
  ui/console: add opengl context and scanout support interfaces.
  virtio-gpu: update headers for virgl/3d
  virtio-gpu: add 3d mode and virgl rendering support.
  sdl2/opengl: add opengl context and scanout support
  opengl: add egl-context.[ch] helpers
  gtk/opengl: add opengl context and scanout support (egl)
  gtk/opengl: add opengl context and scanout support (GtkGLArea)

 configure                                   |  40 ++
 hw/display/Makefile.objs                    |   6 +-
 hw/display/virtio-gpu-3d.c                  | 598 ++++++++++++++++++++++++++++
 hw/display/virtio-gpu.c                     | 130 +++++-
 include/hw/virtio/virtio-gpu.h              |  22 +-
 include/standard-headers/linux/virtio_gpu.h | 112 +++++-
 include/ui/console.h                        |  36 ++
 include/ui/egl-context.h                    |  14 +
 include/ui/gtk.h                            |  39 ++
 include/ui/sdl2.h                           |  22 +-
 include/ui/shader.h                         |   4 +-
 trace-events                                |   8 +
 ui/Makefile.objs                            |   6 +
 ui/console-gl.c                             |   7 +-
 ui/console.c                                |  67 +++-
 ui/egl-context.c                            |  34 ++
 ui/gtk-egl.c                                | 129 +++++-
 ui/gtk-gl-area.c                            | 219 ++++++++++
 ui/gtk.c                                    | 118 ++++--
 ui/sdl2-2d.c                                |  13 +
 ui/sdl2-gl.c                                | 133 +++++++
 ui/sdl2.c                                   |   7 +
 ui/shader.c                                 |  32 +-
 23 files changed, 1741 insertions(+), 55 deletions(-)
 create mode 100644 hw/display/virtio-gpu-3d.c
 create mode 100644 include/ui/egl-context.h
 create mode 100644 ui/egl-context.c
 create mode 100644 ui/gtk-gl-area.c

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
  2015-09-14 16:00   ` Max Reitz
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround Gerd Hoffmann
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Create a buffer for the vertex data and place vertexes
there at initialization time.  Then just use the buffer
for each texture blit.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/ui/shader.h |  4 +++-
 ui/console-gl.c     |  7 ++++++-
 ui/shader.c         | 32 +++++++++++++++++++++++++++-----
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/include/ui/shader.h b/include/ui/shader.h
index 8509596..f7d8618 100644
--- a/include/ui/shader.h
+++ b/include/ui/shader.h
@@ -3,7 +3,9 @@
 
 #include <epoxy/gl.h>
 
-void qemu_gl_run_texture_blit(GLint texture_blit_prog);
+GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog);
+void qemu_gl_run_texture_blit(GLint texture_blit_prog,
+                              GLint texture_blit_vao);
 
 GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
 GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
diff --git a/ui/console-gl.c b/ui/console-gl.c
index cb45cf8..baf397b 100644
--- a/ui/console-gl.c
+++ b/ui/console-gl.c
@@ -33,6 +33,7 @@
 
 struct ConsoleGLState {
     GLint texture_blit_prog;
+    GLint texture_blit_vao;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -47,6 +48,9 @@ ConsoleGLState *console_gl_init_context(void)
         exit(1);
     }
 
+    gls->texture_blit_vao =
+        qemu_gl_init_texture_blit(gls->texture_blit_prog);
+
     return gls;
 }
 
@@ -131,7 +135,8 @@ 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);
+    qemu_gl_run_texture_blit(gls->texture_blit_prog,
+                             gls->texture_blit_vao);
 }
 
 void surface_gl_destroy_texture(ConsoleGLState *gls,
diff --git a/ui/shader.c b/ui/shader.c
index 52a4632..ada1c4c 100644
--- a/ui/shader.c
+++ b/ui/shader.c
@@ -29,21 +29,43 @@
 
 /* ---------------------------------------------------------------------- */
 
-void qemu_gl_run_texture_blit(GLint texture_blit_prog)
+GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
 {
-    GLfloat in_position[] = {
+    static const GLfloat in_position[] = {
         -1, -1,
         1,  -1,
         -1,  1,
         1,   1,
     };
     GLint l_position;
+    GLuint vao, buffer;
+
+    glGenVertexArrays(1, &vao);
+    glBindVertexArray(vao);
+
+    /* this is the VBO that holds the vertex data */
+    glGenBuffers(1, &buffer);
+    glBindBuffer(GL_ARRAY_BUFFER, buffer);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position,
+                 GL_STATIC_DRAW);
 
-    glUseProgram(texture_blit_prog);
     l_position = glGetAttribLocation(texture_blit_prog, "in_position");
-    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position);
+    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
     glEnableVertexAttribArray(l_position);
-    glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4);
+
+    glBindBuffer (GL_ARRAY_BUFFER, 0);
+    glBindVertexArray (0);
+    glDeleteBuffers (1, &buffer);
+
+    return vao;
+}
+
+void qemu_gl_run_texture_blit(GLint texture_blit_prog,
+                              GLint texture_blit_vao)
+{
+    glUseProgram(texture_blit_prog);
+    glBindVertexArray(texture_blit_vao);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 }
 
 /* ---------------------------------------------------------------------- */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
  2015-09-14 16:16   ` Max Reitz
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces Gerd Hoffmann
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 ui/sdl2-2d.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c
index d0b340f..191ee3b 100644
--- a/ui/sdl2-2d.c
+++ b/ui/sdl2-2d.c
@@ -45,10 +45,23 @@ void sdl2_2d_update(DisplayChangeListener *dcl,
         return;
     }
 
+    /*
+     * SDL2 seems to do some double-buffering, and trying to only
+     * update the changed areas results in only one of the two buffers
+     * being updated.  Which flickers alot.  So lets not try to be
+     * clever do a full update every time ...
+     */
+#if 0
     rect.x = x;
     rect.y = y;
     rect.w = w;
     rect.h = h;
+#else
+    rect.x = 0;
+    rect.y = 0;
+    rect.w = surface_width(surf);
+    rect.h = surface_height(surf);
+#endif
 
     SDL_UpdateTexture(scon->texture, NULL, surface_data(surf),
                       surface_stride(surf));
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces.
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
  2015-09-15  8:30   ` Paolo Bonzini
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d Gerd Hoffmann
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add callbacks for opengl context management and scanout texture
configuration to DisplayChangeListenerOps.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/ui/console.h | 36 ++++++++++++++++++++++++++++
 ui/console.c         | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 101 insertions(+), 2 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 047a2b4..df92ccd 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -157,6 +157,13 @@ void cursor_set_mono(QEMUCursor *c,
 void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
 void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
 
+typedef void *qemu_gl_context;
+
+struct qemu_gl_params {
+    int major_ver;
+    int minor_ver;
+};
+
 typedef struct DisplayChangeListenerOps {
     const char *dpy_name;
 
@@ -183,6 +190,21 @@ typedef struct DisplayChangeListenerOps {
                           int x, int y, int on);
     void (*dpy_cursor_define)(DisplayChangeListener *dcl,
                               QEMUCursor *cursor);
+
+    qemu_gl_context (*dpy_gl_ctx_create)(DisplayChangeListener *dcl,
+                                         struct qemu_gl_params *params);
+    void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl,
+                              qemu_gl_context ctx);
+    int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl,
+                                   qemu_gl_context ctx);
+    qemu_gl_context (*dpy_gl_ctx_get_current)(DisplayChangeListener *dcl);
+
+    void (*dpy_gl_scanout)(DisplayChangeListener *dcl,
+                           uint32_t backing_id, bool backing_y_0_top,
+                           uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+    void (*dpy_gl_update)(DisplayChangeListener *dcl,
+                          uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+
 } DisplayChangeListenerOps;
 
 struct DisplayChangeListener {
@@ -244,6 +266,20 @@ bool dpy_cursor_define_supported(QemuConsole *con);
 bool dpy_gfx_check_format(QemuConsole *con,
                           pixman_format_code_t format);
 
+void dpy_gl_scanout(QemuConsole *con,
+                    uint32_t backing_id, bool backing_y_0_top,
+                    uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+void dpy_gl_update(QemuConsole *con,
+                   uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+
+qemu_gl_context dpy_gl_ctx_create(QemuConsole *con,
+                                  struct qemu_gl_params *params);
+void dpy_gl_ctx_destroy(QemuConsole *con, qemu_gl_context ctx);
+int dpy_gl_ctx_make_current(QemuConsole *con, qemu_gl_context ctx);
+qemu_gl_context dpy_gl_ctx_get_current(QemuConsole *con);
+
+bool console_has_gl(QemuConsole *con);
+
 static inline int surface_stride(DisplaySurface *s)
 {
     return pixman_image_get_stride(s->image);
diff --git a/ui/console.c b/ui/console.c
index 75fc492..61e45af 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -121,6 +121,7 @@ struct QemuConsole {
     DisplayState *ds;
     DisplaySurface *surface;
     int dcls;
+    DisplayChangeListener *gl;
 
     /* Graphic console state.  */
     Object *device;
@@ -1332,6 +1333,11 @@ void qemu_free_displaysurface(DisplaySurface *surface)
     g_free(surface);
 }
 
+bool console_has_gl(QemuConsole *con)
+{
+    return con->gl != NULL;
+}
+
 void register_displaychangelistener(DisplayChangeListener *dcl)
 {
     static const char nodev[] =
@@ -1339,6 +1345,17 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
     static DisplaySurface *dummy;
     QemuConsole *con;
 
+    if (dcl->ops->dpy_gl_ctx_create) {
+        /* display has opengl support */
+        assert(dcl->con);
+        if (dcl->con->gl) {
+            fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
+                    dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
+            exit(1);
+        }
+        dcl->con->gl = dcl;
+    }
+
     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
     dcl->ds = get_alloc_displaystate();
     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
@@ -1417,9 +1434,13 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
 {
     DisplayState *s = con->ds;
     DisplayChangeListener *dcl;
-    int width = surface_width(con->surface);
-    int height = surface_height(con->surface);
+    int width = w;
+    int height = h;
 
+    if (con->surface) {
+        width = surface_width(con->surface);
+        height = surface_height(con->surface);
+    }
     x = MAX(x, 0);
     y = MAX(y, 0);
     x = MIN(x, width);
@@ -1619,6 +1640,48 @@ bool dpy_cursor_define_supported(QemuConsole *con)
     return false;
 }
 
+qemu_gl_context dpy_gl_ctx_create(QemuConsole *con,
+                                  struct qemu_gl_params *qparams)
+{
+    assert(con->gl);
+    return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
+}
+
+void dpy_gl_ctx_destroy(QemuConsole *con, qemu_gl_context ctx)
+{
+    assert(con->gl);
+    con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
+}
+
+int dpy_gl_ctx_make_current(QemuConsole *con, qemu_gl_context ctx)
+{
+    assert(con->gl);
+    return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
+}
+
+qemu_gl_context dpy_gl_ctx_get_current(QemuConsole *con)
+{
+    assert(con->gl);
+    return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
+}
+
+void dpy_gl_scanout(QemuConsole *con,
+                    uint32_t backing_id, bool backing_y_0_top,
+                    uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+{
+    assert(con->gl);
+    con->gl->ops->dpy_gl_scanout(con->gl, backing_id,
+                                 backing_y_0_top,
+                                 x, y, width, height);
+}
+
+void dpy_gl_update(QemuConsole *con,
+                   uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+    assert(con->gl);
+    con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
+}
+
 /***********************************************************/
 /* register display */
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-10 12:41   ` Marc-André Lureau
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support Gerd Hoffmann
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Sync with linux kernel headers with virgl/3d patches applied.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/standard-headers/linux/virtio_gpu.h | 112 +++++++++++++++++++++++++++-
 1 file changed, 111 insertions(+), 1 deletion(-)

diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h
index 72ef815..76e5e52 100644
--- a/include/standard-headers/linux/virtio_gpu.h
+++ b/include/standard-headers/linux/virtio_gpu.h
@@ -40,6 +40,8 @@
 
 #include "standard-headers/linux/types.h"
 
+#define VIRTIO_GPU_FEATURE_VIRGL 0
+
 enum virtio_gpu_ctrl_type {
 	VIRTIO_GPU_UNDEFINED = 0,
 
@@ -52,6 +54,18 @@ enum virtio_gpu_ctrl_type {
 	VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
 	VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
 	VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+	VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+	VIRTIO_GPU_CMD_GET_CAPSET,
+
+	/* 3d commands */
+	VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+	VIRTIO_GPU_CMD_CTX_DESTROY,
+	VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+	VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+	VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+	VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+	VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+	VIRTIO_GPU_CMD_SUBMIT_3D,
 
 	/* cursor commands */
 	VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
@@ -60,6 +74,8 @@ enum virtio_gpu_ctrl_type {
 	/* success responses */
 	VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
 	VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+	VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+	VIRTIO_GPU_RESP_OK_CAPSET,
 
 	/* error responses */
 	VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
@@ -180,13 +196,107 @@ struct virtio_gpu_resp_display_info {
 	} pmodes[VIRTIO_GPU_MAX_SCANOUTS];
 };
 
+/* data passed in the control vq, 3d related */
+
+struct virtio_gpu_box {
+	uint32_t x, y, z;
+	uint32_t w, h, d;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
+struct virtio_gpu_transfer_host_3d {
+	struct virtio_gpu_ctrl_hdr hdr;
+	struct virtio_gpu_box box;
+	uint64_t offset;
+	uint32_t resource_id;
+	uint32_t level;
+	uint32_t stride;
+	uint32_t layer_stride;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
+#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
+struct virtio_gpu_resource_create_3d {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t resource_id;
+	uint32_t target;
+	uint32_t format;
+	uint32_t bind;
+	uint32_t width;
+	uint32_t height;
+	uint32_t depth;
+	uint32_t array_size;
+	uint32_t last_level;
+	uint32_t nr_samples;
+	uint32_t flags;
+	uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_CTX_CREATE */
+struct virtio_gpu_ctx_create {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t nlen;
+	uint32_t padding;
+	char debug_name[64];
+};
+
+/* VIRTIO_GPU_CMD_CTX_DESTROY */
+struct virtio_gpu_ctx_destroy {
+	struct virtio_gpu_ctrl_hdr hdr;
+};
+
+/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
+struct virtio_gpu_ctx_resource {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t resource_id;
+	uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_SUBMIT_3D */
+struct virtio_gpu_cmd_submit {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t size;
+	uint32_t padding;
+};
+
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+
+/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
+struct virtio_gpu_get_capset_info {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t capset_index;
+	uint32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
+struct virtio_gpu_resp_capset_info {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t capset_id;
+	uint32_t capset_max_version;
+	uint32_t capset_max_size;
+	uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_GET_CAPSET */
+struct virtio_gpu_get_capset {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint32_t capset_id;
+	uint32_t capset_version;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET */
+struct virtio_gpu_resp_capset {
+	struct virtio_gpu_ctrl_hdr hdr;
+	uint8_t capset_data[];
+};
+
 #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
 
 struct virtio_gpu_config {
 	uint32_t events_read;
 	uint32_t events_clear;
 	uint32_t num_scanouts;
-	uint32_t reserved;
+	uint32_t num_capsets;
 };
 
 /* simple formats for fbcon/X use */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support.
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-14 18:14   ` Max Reitz
  2015-09-15  8:33   ` Paolo Bonzini
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support Gerd Hoffmann
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Michael S. Tsirkin

Add virglrenderer library detection.  Add 3d mode to virtio-gpu,
wire up virglrenderer library.  When in 3d mode render using the
new context management and texture scanout callbacks.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 configure                      |  32 +++
 hw/display/Makefile.objs       |   6 +-
 hw/display/virtio-gpu-3d.c     | 598 +++++++++++++++++++++++++++++++++++++++++
 hw/display/virtio-gpu.c        | 130 ++++++++-
 include/hw/virtio/virtio-gpu.h |  22 +-
 trace-events                   |   8 +
 6 files changed, 785 insertions(+), 11 deletions(-)
 create mode 100644 hw/display/virtio-gpu-3d.c

diff --git a/configure b/configure
index d854936..2d922d1 100755
--- a/configure
+++ b/configure
@@ -332,6 +332,7 @@ gtkabi=""
 gnutls=""
 gnutls_hash=""
 vte=""
+virglrenderer=""
 tpm="yes"
 libssh2=""
 vhdx=""
@@ -1123,6 +1124,10 @@ for opt do
   ;;
   --enable-vte) vte="yes"
   ;;
+  --disable-virglrenderer) virglrenderer="no"
+  ;;
+  --enable-virglrenderer) virglrenderer="yes"
+  ;;
   --disable-tpm) tpm="no"
   ;;
   --enable-tpm) tpm="yes"
@@ -3906,6 +3911,27 @@ EOF
 fi
 
 ##########################################
+# virgl renderer probe
+
+if test "$virglrenderer" != "no" ; then
+  cat > $TMPC << EOF
+#include <virglrenderer.h>
+int main(void) { virgl_renderer_poll(); return 0; }
+EOF
+  virgl_cflags=$($pkg_config --cflags virglrenderer 2>/dev/null)
+  virgl_libs=$($pkg_config --libs virglrenderer 2>/dev/null)
+  if $pkg_config virglrenderer >/dev/null 2>&1 && \
+     compile_prog "$virgl_cflags" "$virgl_libs" ; then
+    virglrenderer="yes"
+  else
+    if test "$virglrenderer" = "yes" ; then
+      feature_not_found "virglrenderer"
+    fi
+    virglrenderer="no"
+  fi
+fi
+
+##########################################
 # check if we have fdatasync
 
 fdatasync=no
@@ -4521,6 +4547,7 @@ echo "GNUTLS gcrypt     $gnutls_gcrypt"
 echo "GNUTLS nettle     $gnutls_nettle ${gnutls_nettle+($nettle_version)}"
 echo "VTE support       $vte"
 echo "curses support    $curses"
+echo "virgl support     $virglrenderer"
 echo "curl support      $curl"
 echo "mingw32 support   $mingw32"
 echo "Audio drivers     $audio_drv_list"
@@ -4893,6 +4920,11 @@ if test "$vte" = "yes" ; then
   echo "CONFIG_VTE=y" >> $config_host_mak
   echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak
 fi
+if test "$virglrenderer" = "yes" ; then
+  echo "CONFIG_VIRGL=y" >> $config_host_mak
+  echo "VIRGL_CFLAGS=$virgl_cflags" >> $config_host_mak
+  echo "VIRGL_LIBS=$virgl_libs" >> $config_host_mak
+fi
 if test "$xen" = "yes" ; then
   echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
   echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index dd8ea76..f0cf431 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -35,6 +35,10 @@ obj-$(CONFIG_VGA) += vga.o
 
 common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
 
-obj-$(CONFIG_VIRTIO) += virtio-gpu.o
+obj-$(CONFIG_VIRTIO) += virtio-gpu.o virtio-gpu-3d.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
 obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
+virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
+virtio-gpu.o-libs += $(VIRGL_LIBS)
+virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
+virtio-gpu-3d.o-libs += $(VIRGL_LIBS)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
new file mode 100644
index 0000000..ac62fb4
--- /dev/null
+++ b/hw/display/virtio-gpu-3d.c
@@ -0,0 +1,598 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "trace.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-gpu.h"
+
+#ifdef CONFIG_VIRGL
+
+#include "virglrenderer.h"
+
+static struct virgl_renderer_callbacks virtio_gpu_3d_cbs;
+
+static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
+                                         struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_create_2d c2d;
+    struct virgl_renderer_resource_create_args args;
+
+    VIRTIO_GPU_FILL_CMD(c2d);
+    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
+                                       c2d.width, c2d.height);
+
+    args.handle = c2d.resource_id;
+    args.target = 2;
+    args.format = c2d.format;
+    args.bind = (1 << 1);
+    args.width = c2d.width;
+    args.height = c2d.height;
+    args.depth = 1;
+    args.array_size = 1;
+    args.last_level = 0;
+    args.nr_samples = 0;
+    args.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
+    virgl_renderer_resource_create(&args, NULL, 0);
+}
+
+static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
+                                         struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_create_3d c3d;
+    struct virgl_renderer_resource_create_args args;
+
+    VIRTIO_GPU_FILL_CMD(c3d);
+    trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
+                                       c3d.width, c3d.height, c3d.depth);
+
+    args.handle = c3d.resource_id;
+    args.target = c3d.target;
+    args.format = c3d.format;
+    args.bind = c3d.bind;
+    args.width = c3d.width;
+    args.height = c3d.height;
+    args.depth = c3d.depth;
+    args.array_size = c3d.array_size;
+    args.last_level = c3d.last_level;
+    args.nr_samples = c3d.nr_samples;
+    args.flags = c3d.flags;
+    virgl_renderer_resource_create(&args, NULL, 0);
+}
+
+static void virgl_cmd_resource_unref(VirtIOGPU *g,
+                                     struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_unref unref;
+
+    VIRTIO_GPU_FILL_CMD(unref);
+    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
+
+    virgl_renderer_resource_unref(unref.resource_id);
+}
+
+static void virgl_cmd_context_create(VirtIOGPU *g,
+                                     struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_ctx_create cc;
+
+    VIRTIO_GPU_FILL_CMD(cc);
+    trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
+                                    cc.debug_name);
+
+    virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen,
+                                  cc.debug_name);
+}
+
+static void virgl_cmd_context_destroy(VirtIOGPU *g,
+                                      struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_ctx_destroy cd;
+
+    VIRTIO_GPU_FILL_CMD(cd);
+    trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
+
+    virgl_renderer_context_destroy(cd.hdr.ctx_id);
+}
+
+static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y,
+                                int width, int height)
+{
+    if (!g->scanout[idx].con) {
+        return;
+    }
+
+    dpy_gl_update(g->scanout[idx].con, x, y, width, height);
+}
+
+static void virgl_cmd_resource_flush(VirtIOGPU *g,
+                                     struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_flush rf;
+    int i;
+
+    VIRTIO_GPU_FILL_CMD(rf);
+    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
+                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
+
+    for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
+        if (g->scanout[i].resource_id != rf.resource_id) {
+            continue;
+        }
+        virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height);
+    }
+}
+
+static void virgl_cmd_set_scanout(VirtIOGPU *g,
+                                  struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_set_scanout ss;
+    struct virgl_renderer_resource_info info;
+    int ret;
+
+    VIRTIO_GPU_FILL_CMD(ss);
+    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
+                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
+
+    if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+                      __func__, ss.scanout_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+        return;
+    }
+    g->enable = 1;
+
+    memset(&info, 0, sizeof(info));
+
+    if (ss.resource_id && ss.r.width && ss.r.height) {
+        ret = virgl_renderer_resource_get_info(ss.resource_id, &info);
+        if (ret == -1) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: illegal resource specified %d\n",
+                          __func__, ss.resource_id);
+            cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+            return;
+        }
+        qemu_console_resize(g->scanout[ss.scanout_id].con,
+                            ss.r.width, ss.r.height);
+        virgl_renderer_force_ctx_0();
+        dpy_gl_scanout(g->scanout[ss.scanout_id].con, info.tex_id,
+                       info.flags & 1 /* FIXME: Y_0_TOP */,
+                       ss.r.x, ss.r.y, ss.r.width, ss.r.height);
+    } else {
+        if (ss.scanout_id != 0) {
+            dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
+        }
+        dpy_gl_scanout(g->scanout[ss.scanout_id].con, 0, false,
+                       0, 0, 0, 0);
+    }
+    g->scanout[ss.scanout_id].resource_id = ss.resource_id;
+}
+
+static void virgl_cmd_submit_3d(VirtIOGPU *g,
+                                struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_cmd_submit cs;
+    void *buf;
+    size_t s;
+
+    VIRTIO_GPU_FILL_CMD(cs);
+    trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
+
+    buf = g_malloc(cs.size);
+    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
+                   sizeof(cs), buf, cs.size);
+    if (s != cs.size) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: size mismatch (%zd/%d)",
+                      __func__, s, cs.size);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+        return;
+    }
+
+    if (virtio_gpu_stats_enabled(g->conf)) {
+        g->stats.req_3d++;
+        g->stats.bytes_3d += cs.size;
+    }
+
+    virgl_renderer_submit_cmd(buf, cs.hdr.ctx_id, cs.size / 4);
+
+    g_free(buf);
+}
+
+static void virgl_cmd_transfer_to_host_2d(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_transfer_to_host_2d t2d;
+    struct virtio_gpu_box box;
+
+    VIRTIO_GPU_FILL_CMD(t2d);
+    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
+
+    box.x = t2d.r.x;
+    box.y = t2d.r.y;
+    box.z = 0;
+    box.w = t2d.r.width;
+    box.h = t2d.r.height;
+    box.d = 1;
+
+    virgl_renderer_transfer_write_iov(t2d.resource_id,
+                                      0,
+                                      0,
+                                      0,
+                                      0,
+                                      (struct virgl_box *)&box,
+                                      t2d.offset, NULL, 0);
+}
+
+static void virgl_cmd_transfer_to_host_3d(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_transfer_host_3d t3d;
+
+    VIRTIO_GPU_FILL_CMD(t3d);
+    trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
+
+    virgl_renderer_transfer_write_iov(t3d.resource_id,
+                                      t3d.hdr.ctx_id,
+                                      t3d.level,
+                                      t3d.stride,
+                                      t3d.layer_stride,
+                                      (struct virgl_box *)&t3d.box,
+                                      t3d.offset, NULL, 0);
+}
+
+static void
+virgl_cmd_transfer_from_host_3d(VirtIOGPU *g,
+                                struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_transfer_host_3d tf3d;
+
+    VIRTIO_GPU_FILL_CMD(tf3d);
+    trace_virtio_gpu_cmd_res_xfer_fromh_3d(tf3d.resource_id);
+
+    virgl_renderer_transfer_read_iov(tf3d.resource_id,
+                                     tf3d.hdr.ctx_id,
+                                     tf3d.level,
+                                     tf3d.stride,
+                                     tf3d.layer_stride,
+                                     (struct virgl_box *)&tf3d.box,
+                                     tf3d.offset, NULL, 0);
+}
+
+
+static void virgl_resource_attach_backing(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_attach_backing att_rb;
+    struct iovec *res_iovs;
+    int ret;
+
+    VIRTIO_GPU_FILL_CMD(att_rb);
+    trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
+
+    ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, &res_iovs);
+    if (ret != 0) {
+        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+        return;
+    }
+
+    virgl_renderer_resource_attach_iov(att_rb.resource_id,
+                                       res_iovs, att_rb.nr_entries);
+}
+
+static void virgl_resource_detach_backing(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resource_detach_backing detach_rb;
+    struct iovec *res_iovs = NULL;
+    int num_iovs = 0;
+
+    VIRTIO_GPU_FILL_CMD(detach_rb);
+    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
+
+    virgl_renderer_resource_detach_iov(detach_rb.resource_id,
+                                       &res_iovs,
+                                       &num_iovs);
+    if (res_iovs == NULL || num_iovs == 0) {
+        return;
+    }
+    virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);
+}
+
+
+static void virgl_cmd_ctx_attach_resource(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_ctx_resource att_res;
+
+    VIRTIO_GPU_FILL_CMD(att_res);
+    trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
+                                        att_res.resource_id);
+
+    virgl_renderer_ctx_attach_resource(att_res.hdr.ctx_id, att_res.resource_id);
+}
+
+static void virgl_cmd_ctx_detach_resource(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_ctx_resource det_res;
+
+    VIRTIO_GPU_FILL_CMD(det_res);
+    trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
+                                        det_res.resource_id);
+
+    virgl_renderer_ctx_detach_resource(det_res.hdr.ctx_id, det_res.resource_id);
+}
+
+static void virgl_cmd_get_capset_info(VirtIOGPU *g,
+                                      struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_get_capset_info info;
+    struct virtio_gpu_resp_capset_info resp;
+
+    VIRTIO_GPU_FILL_CMD(info);
+
+    if (info.capset_index == 0) {
+        resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL;
+        virgl_renderer_get_cap_set(resp.capset_id,
+                                   &resp.capset_max_version,
+                                   &resp.capset_max_size);
+    } else {
+        resp.capset_max_version = 0;
+        resp.capset_max_size = 0;
+    }
+    resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
+    virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
+}
+
+static void virgl_cmd_get_capset(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_get_capset gc;
+    struct virtio_gpu_resp_capset *resp;
+    uint32_t max_ver, max_size;
+    VIRTIO_GPU_FILL_CMD(gc);
+
+    virgl_renderer_get_cap_set(gc.capset_id, &max_ver,
+                               &max_size);
+    resp = g_malloc(sizeof(*resp) + max_size);
+
+    resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
+    virgl_renderer_fill_caps(gc.capset_id,
+                             gc.capset_version,
+                             (void *)resp->capset_data);
+    virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + max_size);
+    g_free(resp);
+}
+
+void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
+                                      struct virtio_gpu_ctrl_command *cmd)
+{
+    VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
+
+    virgl_renderer_force_ctx_0();
+    switch (cmd->cmd_hdr.type) {
+    case VIRTIO_GPU_CMD_CTX_CREATE:
+        virgl_cmd_context_create(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_DESTROY:
+        virgl_cmd_context_destroy(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
+        virgl_cmd_create_resource_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
+        virgl_cmd_create_resource_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_SUBMIT_3D:
+        virgl_cmd_submit_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
+        virgl_cmd_transfer_to_host_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
+        virgl_cmd_transfer_to_host_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
+        virgl_cmd_transfer_from_host_3d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
+        virgl_resource_attach_backing(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
+        virgl_resource_detach_backing(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_SET_SCANOUT:
+        virgl_cmd_set_scanout(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
+        virgl_cmd_resource_flush(g, cmd);
+       break;
+    case VIRTIO_GPU_CMD_RESOURCE_UNREF:
+        virgl_cmd_resource_unref(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
+        /* TODO add security */
+        virgl_cmd_ctx_attach_resource(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
+        /* TODO add security */
+        virgl_cmd_ctx_detach_resource(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
+        virgl_cmd_get_capset_info(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_GET_CAPSET:
+        virgl_cmd_get_capset(g, cmd);
+        break;
+
+    case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
+        virtio_gpu_get_display_info(g, cmd);
+        break;
+    default:
+        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+        break;
+    }
+
+    if (cmd->finished) {
+        return;
+    }
+    if (cmd->error) {
+        fprintf(stderr, "%s: ctrl 0x%x, error 0x%x\n", __func__,
+                cmd->cmd_hdr.type, cmd->error);
+        virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error);
+        return;
+    }
+    if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
+        virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
+        return;
+    }
+
+    trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
+    virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
+}
+
+static void virgl_write_fence(void *opaque, uint32_t fence)
+{
+    VirtIOGPU *g = opaque;
+    struct virtio_gpu_ctrl_command *cmd, *tmp;
+
+    QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
+        /*
+	 * the guest can end up emitting fences out of order
+	 * so we should check all fenced cmds not just the first one.
+	 */
+        if (cmd->cmd_hdr.fence_id > fence) {
+            continue;
+        }
+        trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
+        virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
+        QTAILQ_REMOVE(&g->fenceq, cmd, next);
+        g_free(cmd);
+        g->inflight--;
+        if (virtio_gpu_stats_enabled(g->conf)) {
+            fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+        }
+    }
+}
+
+static virgl_renderer_gl_context
+virgl_create_context(void *opaque, int scanout_idx,
+                     struct virgl_renderer_gl_ctx_param *params)
+{
+    VirtIOGPU *g = opaque;
+    qemu_gl_context ctx;
+    struct qemu_gl_params qparams;
+
+    qparams.major_ver = params->major_ver;
+    qparams.minor_ver = params->minor_ver;
+
+    ctx = dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams);
+    return (virgl_renderer_gl_context)ctx;
+}
+
+static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx)
+{
+    VirtIOGPU *g = opaque;
+    qemu_gl_context qctx = (qemu_gl_context)ctx;
+
+    dpy_gl_ctx_destroy(g->scanout[0].con, qctx);
+}
+
+static int virgl_make_context_current(void *opaque, int scanout_idx,
+                                      virgl_renderer_gl_context ctx)
+{
+    VirtIOGPU *g = opaque;
+    qemu_gl_context qctx = (qemu_gl_context)ctx;
+
+    return dpy_gl_ctx_make_current(g->scanout[scanout_idx].con, qctx);
+}
+
+static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
+    .version             = 1,
+    .write_fence         = virgl_write_fence,
+    .create_gl_context   = virgl_create_context,
+    .destroy_gl_context  = virgl_destroy_context,
+    .make_current        = virgl_make_context_current,
+};
+
+static void virtio_gpu_print_stats(void *opaque)
+{
+    VirtIOGPU *g = opaque;
+
+    if (g->stats.requests) {
+        fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n",
+                g->stats.requests,
+                g->stats.max_inflight,
+                g->stats.req_3d,
+                g->stats.bytes_3d);
+        g->stats.requests     = 0;
+        g->stats.max_inflight = 0;
+        g->stats.req_3d       = 0;
+        g->stats.bytes_3d     = 0;
+    } else {
+        fprintf(stderr, "stats: idle\r");
+    }
+    timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+}
+
+static void virtio_gpu_fence_poll(void *opaque)
+{
+    VirtIOGPU *g = opaque;
+
+    virgl_renderer_poll();
+    if (g->inflight) {
+        timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
+    }
+}
+
+void virtio_gpu_virgl_fence_poll(VirtIOGPU *g)
+{
+    virtio_gpu_fence_poll(g);
+}
+
+void virtio_gpu_virgl_reset(VirtIOGPU *g)
+{
+    int i;
+
+    /* virgl_renderer_reset() ??? */
+    for (i = 0; i < g->conf.max_outputs; i++) {
+        if (i != 0) {
+            dpy_gfx_replace_surface(g->scanout[i].con, NULL);
+        }
+        dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0);
+    }
+}
+
+int virtio_gpu_virgl_init(VirtIOGPU *g)
+{
+    int ret;
+
+    ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs);
+    if (ret != 0) {
+        return ret;
+    }
+
+    g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+                                 virtio_gpu_fence_poll, g);
+
+    if (virtio_gpu_stats_enabled(g->conf)) {
+        g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+                                      virtio_gpu_print_stats, g);
+        timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+    }
+    return 0;
+}
+
+#endif /* CONFIG_VIRGL */
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index a67d927..4dbdd12 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -22,6 +22,23 @@
 static struct virtio_gpu_simple_resource*
 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
 
+#ifdef CONFIG_VIRGL
+#include "virglrenderer.h"
+#define VIRGL(_g, _virgl, _simple, ...)                     \
+    do {                                                    \
+        if (_g->use_virgl_renderer) {                       \
+            _virgl(__VA_ARGS__);                            \
+        } else {                                            \
+            _simple(__VA_ARGS__);                           \
+        }                                                   \
+    } while (0)
+#else
+#define VIRGL(_g, _virgl, _simple, ...)                 \
+    do {                                                \
+        _simple(__VA_ARGS__);                           \
+    } while (0)
+#endif
+
 static void update_cursor_data_simple(VirtIOGPU *g,
                                       struct virtio_gpu_scanout *s,
                                       uint32_t resource_id)
@@ -45,6 +62,27 @@ static void update_cursor_data_simple(VirtIOGPU *g,
            pixels * sizeof(uint32_t));
 }
 
+#ifdef CONFIG_VIRGL
+
+static void update_cursor_data_virgl(VirtIOGPU *g,
+                                     struct virtio_gpu_scanout *s,
+                                     uint32_t resource_id)
+{
+    uint32_t width, height;
+    uint32_t pixels, *data;
+
+    data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
+    if (!data) {
+        return;
+    }
+
+    pixels = s->current_cursor->width * s->current_cursor->height;
+    memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
+    free(data);
+}
+
+#endif
+
 static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
 {
     struct virtio_gpu_scanout *s;
@@ -63,7 +101,8 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
         s->current_cursor->hot_y = cursor->hot_y;
 
         if (cursor->resource_id > 0) {
-            update_cursor_data_simple(g, s, cursor->resource_id);
+            VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple,
+                  g, s, cursor->resource_id);
         }
         dpy_cursor_define(s->con, s->current_cursor);
     }
@@ -92,9 +131,23 @@ static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
 static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
                                         Error **errp)
 {
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+
+    if (virtio_gpu_virgl_enabled(g->conf)) {
+        features |= (1 << VIRTIO_GPU_FEATURE_VIRGL);
+    }
     return features;
 }
 
+static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
+{
+    static const uint32_t virgl = (1 << VIRTIO_GPU_FEATURE_VIRGL);
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+
+    g->use_virgl_renderer = ((features & virgl) == virgl);
+    trace_virtio_gpu_features(g->use_virgl_renderer);
+}
+
 static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
 {
     g->virtio_config.events_read |= event_type;
@@ -699,25 +752,43 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         return;
     }
 
+#ifdef CONFIG_VIRGL
+    if (!g->renderer_inited && g->use_virgl_renderer) {
+        virtio_gpu_virgl_init(g);
+        g->renderer_inited = true;
+    }
+#endif
+
     cmd = g_new(struct virtio_gpu_ctrl_command, 1);
     while (virtqueue_pop(vq, &cmd->elem)) {
         cmd->vq = vq;
         cmd->error = 0;
         cmd->finished = false;
-        g->stats.requests++;
+        if (virtio_gpu_stats_enabled(g->conf)) {
+            g->stats.requests++;
+        }
 
-        virtio_gpu_simple_process_cmd(g, cmd);
+        VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
+              g, cmd);
         if (!cmd->finished) {
             QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
-            g->stats.inflight++;
-            if (g->stats.max_inflight < g->stats.inflight) {
-                g->stats.max_inflight = g->stats.inflight;
+            g->inflight++;
+            if (virtio_gpu_stats_enabled(g->conf)) {
+                if (g->stats.max_inflight < g->inflight) {
+                    g->stats.max_inflight = g->inflight;
+                }
+                fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
             }
-            fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight);
             cmd = g_new(struct virtio_gpu_ctrl_command, 1);
         }
     }
     g_free(cmd);
+
+#ifdef CONFIG_VIRGL
+    if (g->use_virgl_renderer) {
+        virtio_gpu_virgl_fence_poll(g);
+    }
+#endif
 }
 
 static void virtio_gpu_ctrl_bh(void *opaque)
@@ -804,6 +875,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
     VirtIOGPU *g = VIRTIO_GPU(qdev);
+    bool have_virgl;
     int i;
 
     g->config_size = sizeof(struct virtio_gpu_config);
@@ -814,8 +886,25 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
     g->req_state[0].width = 1024;
     g->req_state[0].height = 768;
 
-    g->ctrl_vq   = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
-    g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
+    g->use_virgl_renderer = false;
+#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
+    have_virgl = false;
+#else
+    have_virgl = display_opengl;
+#endif
+    if (!have_virgl) {
+        g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
+    }
+
+    if (virtio_gpu_virgl_enabled(g->conf)) {
+        /* use larger control queue in 3d mode */
+        g->ctrl_vq   = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
+        g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
+        g->virtio_config.num_capsets = 1;
+    } else {
+        g->ctrl_vq   = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb);
+        g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb);
+    }
 
     g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
     g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
@@ -869,10 +958,21 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
         g->scanout[i].ds = NULL;
     }
     g->enabled_output_bitmask = 1;
+
+#ifdef CONFIG_VIRGL
+    if (g->use_virgl_renderer) {
+        virtio_gpu_virgl_reset(g);
+        g->use_virgl_renderer = 0;
+    }
+#endif
 }
 
 static Property virtio_gpu_properties[] = {
     DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1),
+    DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags,
+                    VIRTIO_GPU_FLAG_VIRGL_ENABLED, false),
+    DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags,
+                    VIRTIO_GPU_FLAG_STATS_ENABLED, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -885,6 +985,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
     vdc->get_config = virtio_gpu_get_config;
     vdc->set_config = virtio_gpu_set_config;
     vdc->get_features = virtio_gpu_get_features;
+    vdc->set_features = virtio_gpu_set_features;
 
     vdc->reset = virtio_gpu_reset;
 
@@ -917,3 +1018,14 @@ QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry)               != 16);
 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info)       != 408);
+
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d)        != 72);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d)      != 72);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create)              != 96);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy)             != 24);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource)            != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit)              != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info)         != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info)        != 40);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset)              != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset)             != 24);
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 8896761..9b279d7 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -56,8 +56,19 @@ struct virtio_gpu_requested_state {
     int x, y;
 };
 
+enum virtio_gpu_conf_flags {
+    VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1,
+    VIRTIO_GPU_FLAG_STATS_ENABLED,
+};
+
+#define virtio_gpu_virgl_enabled(_cfg) \
+    (_cfg.flags & (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED))
+#define virtio_gpu_stats_enabled(_cfg) \
+    (_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED))
+
 struct virtio_gpu_conf {
     uint32_t max_outputs;
+    uint32_t flags;
 };
 
 struct virtio_gpu_ctrl_command {
@@ -92,11 +103,13 @@ typedef struct VirtIOGPU {
     int enabled_output_bitmask;
     struct virtio_gpu_config virtio_config;
 
+    bool use_virgl_renderer;
+    bool renderer_inited;
     QEMUTimer *fence_poll;
     QEMUTimer *print_stats;
 
+    uint32_t inflight;
     struct {
-        uint32_t inflight;
         uint32_t max_inflight;
         uint32_t requests;
         uint32_t req_3d;
@@ -139,4 +152,11 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
                                   struct iovec **iov);
 void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count);
 
+/* virtio-gpu-3d.c */
+void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
+                                  struct virtio_gpu_ctrl_command *cmd);
+void virtio_gpu_virgl_fence_poll(VirtIOGPU *g);
+void virtio_gpu_virgl_reset(VirtIOGPU *g);
+int virtio_gpu_virgl_init(VirtIOGPU *g);
+
 #endif
diff --git a/trace-events b/trace-events
index 0a82f0c..f8eb16d 100644
--- a/trace-events
+++ b/trace-events
@@ -1172,6 +1172,7 @@ vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
 vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
 
 # hw/display/virtio-gpu.c
+virtio_gpu_features(bool virgl) "virgl %d"
 virtio_gpu_cmd_get_display_info(void) ""
 virtio_gpu_cmd_get_caps(void) ""
 virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
@@ -1181,7 +1182,14 @@ virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x"
 virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x"
 virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x"
 virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_xfer_toh_3d(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_xfer_fromh_3d(uint32_t res) "res 0x%x"
 virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d"
+virtio_gpu_cmd_ctx_create(uint32_t ctx, const char *name) "ctx 0x%x, name %s"
+virtio_gpu_cmd_ctx_destroy(uint32_t ctx) "ctx 0x%x"
+virtio_gpu_cmd_ctx_res_attach(uint32_t ctx, uint32_t res) "ctx 0x%x, res 0x%x"
+virtio_gpu_cmd_ctx_res_detach(uint32_t ctx, uint32_t res) "ctx 0x%x, res 0x%x"
+virtio_gpu_cmd_ctx_submit(uint32_t ctx, uint32_t size) "ctx 0x%x, size %d"
 virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x"
 virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-14 18:49   ` Max Reitz
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers Gerd Hoffmann
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This allows virtio-gpu to render in 3d mode.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/ui/sdl2.h |  22 ++++++++-
 ui/sdl2-gl.c      | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/sdl2.c         |   7 +++
 3 files changed, 161 insertions(+), 1 deletion(-)

diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index 2fdad8f..b397631 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -15,12 +15,18 @@ struct sdl2_console {
     SDL_Renderer *real_renderer;
     int idx;
     int last_vm_running; /* per console for caption reasons */
-    int x, y;
+    int x, y, w, h;
     int hidden;
     int opengl;
     int updates;
     SDL_GLContext winctx;
+#ifdef CONFIG_OPENGL
     ConsoleGLState *gls;
+    GLuint tex_id;
+    GLuint fbo_id;
+    bool y0_top;
+    bool scanout_mode;
+#endif
 };
 
 void sdl2_window_create(struct sdl2_console *scon);
@@ -48,4 +54,18 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,
 void sdl2_gl_refresh(DisplayChangeListener *dcl);
 void sdl2_gl_redraw(struct sdl2_console *scon);
 
+qemu_gl_context sdl2_gl_create_context(DisplayChangeListener *dcl,
+                                       struct qemu_gl_params *params);
+void sdl2_gl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx);
+int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
+                                 qemu_gl_context ctx);
+qemu_gl_context sdl2_gl_get_current_context(DisplayChangeListener *dcl);
+
+void sdl2_gl_scanout(DisplayChangeListener *dcl,
+                     uint32_t backing_id, bool backing_y_0_top,
+                     uint32_t x, uint32_t y,
+                     uint32_t w, uint32_t h);
+void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
+                           uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+
 #endif /* SDL2_H */
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index b604c06..bc73c0e 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -31,11 +31,36 @@
 #include "ui/sdl2.h"
 #include "sysemu/sysemu.h"
 
+#include <epoxy/gl.h>
+
+static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
+{
+    if (scon->scanout_mode == scanout) {
+        return;
+    }
+
+    scon->scanout_mode = scanout;
+    if (!scon->scanout_mode) {
+        if (scon->fbo_id) {
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+                                      GL_COLOR_ATTACHMENT0_EXT,
+                                      GL_TEXTURE_2D, 0, 0);
+            glDeleteFramebuffers(1, &scon->fbo_id);
+            scon->fbo_id = 0;
+        }
+        if (scon->surface) {
+            surface_gl_destroy_texture(scon->gls, scon->surface);
+            surface_gl_create_texture(scon->gls, scon->surface);
+        }
+    }
+}
+
 static void sdl2_gl_render_surface(struct sdl2_console *scon)
 {
     int ww, wh;
 
     SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
+    sdl2_set_scanout_mode(scon, false);
 
     SDL_GetWindowSize(scon->real_window, &ww, &wh);
     surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
@@ -110,3 +135,111 @@ void sdl2_gl_redraw(struct sdl2_console *scon)
         sdl2_gl_render_surface(scon);
     }
 }
+
+qemu_gl_context sdl2_gl_create_context(DisplayChangeListener *dcl,
+                                       struct qemu_gl_params *params)
+{
+    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
+    SDL_GLContext ctx;
+
+    assert(scon->opengl);
+
+    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
+
+    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
+                        SDL_GL_CONTEXT_PROFILE_CORE);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
+
+    ctx = SDL_GL_CreateContext(scon->real_window);
+    return (qemu_gl_context)ctx;
+}
+
+void sdl2_gl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
+{
+    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
+
+    SDL_GL_DeleteContext(sdlctx);
+}
+
+int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
+                                 qemu_gl_context ctx)
+{
+    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
+    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
+
+    assert(scon->opengl);
+
+    return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
+}
+
+qemu_gl_context sdl2_gl_get_current_context(DisplayChangeListener *dcl)
+{
+    SDL_GLContext sdlctx;
+
+    sdlctx = SDL_GL_GetCurrentContext();
+    return (qemu_gl_context)sdlctx;
+}
+
+void sdl2_gl_scanout(DisplayChangeListener *dcl,
+                     uint32_t backing_id, bool backing_y_0_top,
+                     uint32_t x, uint32_t y,
+                     uint32_t w, uint32_t h)
+{
+    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
+
+    assert(scon->opengl);
+    scon->x = x;
+    scon->y = y;
+    scon->w = w;
+    scon->h = h;
+    scon->tex_id = backing_id;
+    scon->y0_top = backing_y_0_top;
+
+    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
+
+    if (scon->tex_id == 0 || scon->w == 0 || scon->h == 0) {
+        sdl2_set_scanout_mode(scon, false);
+        return;
+    }
+
+    sdl2_set_scanout_mode(scon, true);
+    if (!scon->fbo_id) {
+        glGenFramebuffers(1, &scon->fbo_id);
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, scon->tex_id, 0);
+}
+
+void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
+                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
+    int ww, wh, y1, y2;
+
+    assert(scon->opengl);
+    if (!scon->scanout_mode) {
+        return;
+    }
+    if (!scon->fbo_id) {
+        return;
+    }
+
+    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+    SDL_GetWindowSize(scon->real_window, &ww, &wh);
+    glViewport(0, 0, ww, wh);
+    y1 = scon->y0_top ? 0 : scon->h;
+    y2 = scon->y0_top ? scon->h : 0;
+    glBlitFramebuffer(0, y1, scon->w, y2,
+                      0, 0, ww, wh,
+                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+    SDL_GL_SwapWindow(scon->real_window);
+}
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 5cb75aa..73a84a8 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -700,6 +700,13 @@ static const DisplayChangeListenerOps dcl_gl_ops = {
     .dpy_refresh             = sdl2_gl_refresh,
     .dpy_mouse_set           = sdl_mouse_warp,
     .dpy_cursor_define       = sdl_mouse_define,
+
+    .dpy_gl_ctx_create       = sdl2_gl_create_context,
+    .dpy_gl_ctx_destroy      = sdl2_gl_destroy_context,
+    .dpy_gl_ctx_make_current = sdl2_gl_make_context_current,
+    .dpy_gl_ctx_get_current  = sdl2_gl_get_current_context,
+    .dpy_gl_scanout          = sdl2_gl_scanout,
+    .dpy_gl_update           = sdl2_gl_scanout_flush,
 };
 #endif
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-11 14:13   ` Marc-André Lureau
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl) Gerd Hoffmann
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add helper functions to manage opengl contexts using egl.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/ui/egl-context.h | 14 ++++++++++++++
 ui/Makefile.objs         |  1 +
 ui/egl-context.c         | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+)
 create mode 100644 include/ui/egl-context.h
 create mode 100644 ui/egl-context.c

diff --git a/include/ui/egl-context.h b/include/ui/egl-context.h
new file mode 100644
index 0000000..a1c8007
--- /dev/null
+++ b/include/ui/egl-context.h
@@ -0,0 +1,14 @@
+#ifndef EGL_CONTEXT_H
+#define EGL_CONTEXT_H
+
+#include "ui/console.h"
+#include "ui/egl-helpers.h"
+
+qemu_gl_context qemu_egl_create_context(DisplayChangeListener *dcl,
+                                        struct qemu_gl_params *params);
+void qemu_egl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx);
+int qemu_egl_make_context_current(DisplayChangeListener *dcl,
+                                  qemu_gl_context ctx);
+qemu_gl_context qemu_egl_get_current_context(DisplayChangeListener *dcl);
+
+#endif /* EGL_CONTEXT_H */
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index c62d4d9..9bc64a0 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -31,6 +31,7 @@ ifeq ($(CONFIG_OPENGL),y)
 common-obj-y += shader.o
 common-obj-y += console-gl.o
 common-obj-y += egl-helpers.o
+common-obj-y += egl-context.o
 common-obj-$(CONFIG_GTK) += gtk-egl.o
 endif
 
diff --git a/ui/egl-context.c b/ui/egl-context.c
new file mode 100644
index 0000000..233ed37
--- /dev/null
+++ b/ui/egl-context.c
@@ -0,0 +1,34 @@
+#include "qemu-common.h"
+#include "ui/egl-context.h"
+
+qemu_gl_context qemu_egl_create_context(DisplayChangeListener *dcl,
+                                        struct qemu_gl_params *params)
+{
+   EGLContext ctx;
+   EGLint ctx_att[] = {
+      EGL_CONTEXT_CLIENT_VERSION, params->major_ver,
+      EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
+      EGL_NONE
+   };
+
+   ctx = eglCreateContext(qemu_egl_display, qemu_egl_config,
+                          eglGetCurrentContext(), ctx_att);
+   return ctx;
+}
+
+void qemu_egl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
+{
+    eglDestroyContext(qemu_egl_display, ctx);
+}
+
+int qemu_egl_make_context_current(DisplayChangeListener *dcl,
+                                  qemu_gl_context ctx)
+{
+   return eglMakeCurrent(qemu_egl_display,
+                         EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
+}
+
+qemu_gl_context qemu_egl_get_current_context(DisplayChangeListener *dcl)
+{
+    return eglGetCurrentContext();
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl)
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-11 14:36   ` Marc-André Lureau
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea) Gerd Hoffmann
  2015-09-11 16:10 ` [Qemu-devel] [PATCH 0/9] add virgl rendering support Marc-André Lureau
  9 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This allows virtio-gpu to render in 3d mode.
Uses egl, for gtk versions 3.14 and older.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/ui/gtk.h |  16 +++++++
 ui/gtk-egl.c     | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 ui/gtk.c         |   7 +++
 3 files changed, 144 insertions(+), 8 deletions(-)

diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index ee6dffd..1e04c0c 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -24,6 +24,7 @@
 
 #if defined(CONFIG_OPENGL)
 #include "ui/egl-helpers.h"
+#include "ui/egl-context.h"
 #endif
 
 /* Compatibility define to let us build on both Gtk2 and Gtk3 */
@@ -50,6 +51,11 @@ typedef struct VirtualGfxConsole {
     EGLContext ectx;
     EGLSurface esurface;
     int glupdates;
+    int x, y, w, h;
+    GLuint tex_id;
+    GLuint fbo_id;
+    bool y0_top;
+    bool scanout_mode;
 #endif
 } VirtualGfxConsole;
 
@@ -94,6 +100,16 @@ void gd_egl_update(DisplayChangeListener *dcl,
 void gd_egl_refresh(DisplayChangeListener *dcl);
 void gd_egl_switch(DisplayChangeListener *dcl,
                    DisplaySurface *surface);
+qemu_gl_context gd_egl_create_context(DisplayChangeListener *dcl,
+                                      struct qemu_gl_params *params);
+void gd_egl_scanout(DisplayChangeListener *dcl,
+                    uint32_t backing_id, bool backing_y_0_top,
+                    uint32_t x, uint32_t y,
+                    uint32_t w, uint32_t h);
+void gd_egl_scanout_flush(DisplayChangeListener *dcl,
+                          uint32_t x, uint32_t y, uint32_t w, uint32_t h);
 void gtk_egl_init(void);
+int gd_egl_make_current(DisplayChangeListener *dcl,
+                        qemu_gl_context ctx);
 
 #endif /* UI_GTK_H */
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 15b41f2..ae5c7d0 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -21,6 +21,28 @@
 
 #include "sysemu/sysemu.h"
 
+static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout)
+{
+    if (vc->gfx.scanout_mode == scanout) {
+        return;
+    }
+
+    vc->gfx.scanout_mode = scanout;
+    if (!vc->gfx.scanout_mode) {
+        if (vc->gfx.fbo_id) {
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+                                      GL_COLOR_ATTACHMENT0_EXT,
+                                      GL_TEXTURE_2D, 0, 0);
+            glDeleteFramebuffers(1, &vc->gfx.fbo_id);
+            vc->gfx.fbo_id = 0;
+        }
+        if (vc->gfx.surface) {
+            surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
+            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
+        }
+    }
+}
+
 /** DisplayState Callbacks (opengl version) **/
 
 void gd_egl_init(VirtualConsole *vc)
@@ -50,19 +72,26 @@ void gd_egl_draw(VirtualConsole *vc)
     GdkWindow *window;
     int ww, wh;
 
-    if (!vc->gfx.gls || !vc->gfx.ds) {
+    if (!vc->gfx.gls) {
         return;
     }
 
-    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
-                   vc->gfx.esurface, vc->gfx.ectx);
+    if (vc->gfx.scanout_mode) {
+        gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
+    } else {
+        if (!vc->gfx.ds) {
+            return;
+        }
+        eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                       vc->gfx.esurface, vc->gfx.ectx);
 
-    window = gtk_widget_get_window(vc->gfx.drawing_area);
-    gdk_drawable_get_size(window, &ww, &wh);
-    surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
-    surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
+        window = gtk_widget_get_window(vc->gfx.drawing_area);
+        gdk_drawable_get_size(window, &ww, &wh);
+        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+        surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
 
-    eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
+        eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
+    }
 }
 
 void gd_egl_update(DisplayChangeListener *dcl,
@@ -99,6 +128,7 @@ void gd_egl_refresh(DisplayChangeListener *dcl)
 
     if (vc->gfx.glupdates) {
         vc->gfx.glupdates = 0;
+        gtk_egl_set_scanout_mode(vc, false);
         gd_egl_draw(vc);
     }
 }
@@ -128,6 +158,80 @@ void gd_egl_switch(DisplayChangeListener *dcl,
     }
 }
 
+qemu_gl_context gd_egl_create_context(DisplayChangeListener *dcl,
+                                      struct qemu_gl_params *params)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                   vc->gfx.esurface, vc->gfx.ectx);
+    return qemu_egl_create_context(dcl, params);
+}
+
+void gd_egl_scanout(DisplayChangeListener *dcl,
+                    uint32_t backing_id, bool backing_y_0_top,
+                    uint32_t x, uint32_t y,
+                    uint32_t w, uint32_t h)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    vc->gfx.x = x;
+    vc->gfx.y = y;
+    vc->gfx.w = w;
+    vc->gfx.h = h;
+    vc->gfx.tex_id = backing_id;
+    vc->gfx.y0_top = backing_y_0_top;
+
+    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                   vc->gfx.esurface, vc->gfx.ectx);
+
+    if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
+        gtk_egl_set_scanout_mode(vc, false);
+        return;
+    }
+
+    gtk_egl_set_scanout_mode(vc, true);
+    if (!vc->gfx.fbo_id) {
+        glGenFramebuffers(1, &vc->gfx.fbo_id);
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, vc->gfx.tex_id, 0);
+}
+
+void gd_egl_scanout_flush(DisplayChangeListener *dcl,
+                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+    GdkWindow *window;
+    int ww, wh, y1, y2;
+
+    if (!vc->gfx.scanout_mode) {
+        return;
+    }
+    if (!vc->gfx.fbo_id) {
+        return;
+    }
+
+    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                   vc->gfx.esurface, vc->gfx.ectx);
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+    window = gtk_widget_get_window(vc->gfx.drawing_area);
+    gdk_drawable_get_size(window, &ww, &wh);
+    glViewport(0, 0, ww, wh);
+    y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
+    y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
+    glBlitFramebuffer(0, y1, vc->gfx.w, y2,
+                      0, 0, ww, wh,
+                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+    eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
+}
+
 void gtk_egl_init(void)
 {
     GdkDisplay *gdk_display = gdk_display_get_default();
@@ -139,3 +243,12 @@ void gtk_egl_init(void)
 
     display_opengl = 1;
 }
+
+int gd_egl_make_current(DisplayChangeListener *dcl,
+                        qemu_gl_context ctx)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
+                          vc->gfx.esurface, ctx);
+}
diff --git a/ui/gtk.c b/ui/gtk.c
index df2a79e..6faf5a5 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -604,6 +604,13 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
     .dpy_refresh          = gd_egl_refresh,
     .dpy_mouse_set        = gd_mouse_set,
     .dpy_cursor_define    = gd_cursor_define,
+
+    .dpy_gl_ctx_create       = gd_egl_create_context,
+    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,
+    .dpy_gl_ctx_make_current = gd_egl_make_current,
+    .dpy_gl_ctx_get_current  = qemu_egl_get_current_context,
+    .dpy_gl_scanout          = gd_egl_scanout,
+    .dpy_gl_update           = gd_egl_scanout_flush,
 };
 
 #endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea)
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl) Gerd Hoffmann
@ 2015-09-09 11:20 ` Gerd Hoffmann
  2015-09-11 14:44   ` Marc-André Lureau
  2015-09-11 16:10 ` [Qemu-devel] [PATCH 0/9] add virgl rendering support Marc-André Lureau
  9 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-09 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This allows virtio-gpu to render in 3d mode.
Uses native opengl support which is present
in gtk versions 3.16 and newer.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 configure        |   8 ++
 include/ui/gtk.h |  23 ++++++
 ui/Makefile.objs |   5 ++
 ui/gtk-gl-area.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/gtk.c         | 111 +++++++++++++++++++++-------
 5 files changed, 341 insertions(+), 25 deletions(-)
 create mode 100644 ui/gtk-gl-area.c

diff --git a/configure b/configure
index 2d922d1..f7692d2 100755
--- a/configure
+++ b/configure
@@ -329,6 +329,7 @@ glusterfs_zerofill="no"
 archipelago="no"
 gtk=""
 gtkabi=""
+gtk_gl="no"
 gnutls=""
 gnutls_hash=""
 vte=""
@@ -3182,6 +3183,9 @@ if test "$opengl" != "no" ; then
     opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
     opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
     opengl=yes
+    if test "$gtk" = "yes" && $pkg_config --exists "$gtkpackage >= 3.16"; then
+        gtk_gl="yes"
+    fi
   else
     if test "$opengl" = "yes" ; then
       feature_not_found "opengl" "Please install opengl (mesa) devel pkgs: $opengl_pkgs"
@@ -4541,6 +4545,7 @@ fi
 echo "pixman            $pixman"
 echo "SDL support       $sdl"
 echo "GTK support       $gtk"
+echo "GTK GL support    $gtk_gl"
 echo "GNUTLS support    $gnutls"
 echo "GNUTLS hash       $gnutls_hash"
 echo "GNUTLS gcrypt     $gnutls_gcrypt"
@@ -4902,6 +4907,9 @@ if test "$gtk" = "yes" ; then
   echo "CONFIG_GTK=y" >> $config_host_mak
   echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
   echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
+  if test "$gtk_gl" = "yes" ; then
+    echo "CONFIG_GTK_GL=y" >> $config_host_mak
+  fi
 fi
 if test "$gnutls" = "yes" ; then
   echo "CONFIG_GNUTLS=y" >> $config_host_mak
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 1e04c0c..76aabd0 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -112,4 +112,27 @@ void gtk_egl_init(void);
 int gd_egl_make_current(DisplayChangeListener *dcl,
                         qemu_gl_context ctx);
 
+/* ui/gtk-gl-area.c */
+void gd_gl_area_init(VirtualConsole *vc);
+void gd_gl_area_draw(VirtualConsole *vc);
+void gd_gl_area_update(DisplayChangeListener *dcl,
+                       int x, int y, int w, int h);
+void gd_gl_area_refresh(DisplayChangeListener *dcl);
+void gd_gl_area_switch(DisplayChangeListener *dcl,
+                       DisplaySurface *surface);
+qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
+                                          struct qemu_gl_params *params);
+void gd_gl_area_destroy_context(DisplayChangeListener *dcl,
+                                qemu_gl_context ctx);
+void gd_gl_area_scanout(DisplayChangeListener *dcl,
+                        uint32_t backing_id, bool backing_y_0_top,
+                        uint32_t x, uint32_t y,
+                        uint32_t w, uint32_t h);
+void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
+                              uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+void gtk_gl_area_init(void);
+qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl);
+int gd_gl_area_make_current(DisplayChangeListener *dcl,
+                            qemu_gl_context ctx);
+
 #endif /* UI_GTK_H */
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 9bc64a0..bc79bdb 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -32,11 +32,16 @@ common-obj-y += shader.o
 common-obj-y += console-gl.o
 common-obj-y += egl-helpers.o
 common-obj-y += egl-context.o
+ifeq ($(CONFIG_GTK_GL),y)
+common-obj-$(CONFIG_GTK) += gtk-gl-area.o
+else
 common-obj-$(CONFIG_GTK) += gtk-egl.o
 endif
+endif
 
 gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
 gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
+gtk-gl-area.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
 shader.o-cflags += $(OPENGL_CFLAGS)
 console-gl.o-cflags += $(OPENGL_CFLAGS)
 egl-helpers.o-cflags += $(OPENGL_CFLAGS)
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
new file mode 100644
index 0000000..8973c36
--- /dev/null
+++ b/ui/gtk-gl-area.c
@@ -0,0 +1,219 @@
+/*
+ * GTK UI -- glarea opengl code.
+ *
+ * Requires 3.16+ (GtkGLArea widget).
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+
+#include "trace.h"
+
+#include "ui/console.h"
+#include "ui/gtk.h"
+#include "ui/egl-helpers.h"
+
+#include "sysemu/sysemu.h"
+
+static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout)
+{
+    if (vc->gfx.scanout_mode == scanout) {
+        return;
+    }
+
+    vc->gfx.scanout_mode = scanout;
+    if (!vc->gfx.scanout_mode) {
+        if (vc->gfx.fbo_id) {
+            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+                                      GL_COLOR_ATTACHMENT0_EXT,
+                                      GL_TEXTURE_2D, 0, 0);
+            glDeleteFramebuffers(1, &vc->gfx.fbo_id);
+            vc->gfx.fbo_id = 0;
+        }
+        if (vc->gfx.surface) {
+            surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
+            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
+        }
+    }
+}
+
+/** DisplayState Callbacks (opengl version) **/
+
+void gd_gl_area_draw(VirtualConsole *vc)
+{
+    int ww, wh, y1, y2;
+
+    if (!vc->gfx.gls) {
+        return;
+    }
+
+    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+    ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
+    wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
+
+    if (vc->gfx.scanout_mode) {
+        if (!vc->gfx.fbo_id) {
+            return;
+        }
+
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id);
+        /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
+
+        glViewport(0, 0, ww, wh);
+        y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
+        y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
+        glBlitFramebuffer(0, y1, vc->gfx.w, y2,
+                          0, 0, ww, wh,
+                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
+    } else {
+        if (!vc->gfx.ds) {
+            return;
+        }
+        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+
+        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
+        surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
+    }
+}
+
+void gd_gl_area_update(DisplayChangeListener *dcl,
+                   int x, int y, int w, int h)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    if (!vc->gfx.gls || !vc->gfx.ds) {
+        return;
+    }
+
+    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+    surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
+    vc->gfx.glupdates++;
+}
+
+void gd_gl_area_refresh(DisplayChangeListener *dcl)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    if (!vc->gfx.gls) {
+        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+        vc->gfx.gls = console_gl_init_context();
+        if (vc->gfx.ds) {
+            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
+        }
+    }
+
+    graphic_hw_update(dcl->con);
+
+    if (vc->gfx.glupdates) {
+        vc->gfx.glupdates = 0;
+        gtk_gl_area_set_scanout_mode(vc, false);
+        gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+    }
+}
+
+void gd_gl_area_switch(DisplayChangeListener *dcl,
+                       DisplaySurface *surface)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+    bool resized = true;
+
+    trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
+
+    if (vc->gfx.ds &&
+        surface_width(vc->gfx.ds) == surface_width(surface) &&
+        surface_height(vc->gfx.ds) == surface_height(surface)) {
+        resized = false;
+    }
+
+    if (vc->gfx.gls) {
+        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+        surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
+        surface_gl_create_texture(vc->gfx.gls, surface);
+    }
+    vc->gfx.ds = surface;
+
+    if (resized) {
+        gd_update_windowsize(vc);
+    }
+}
+
+qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
+                                          struct qemu_gl_params *params)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+    GdkWindow *window;
+    GdkGLContext *ctx;
+    GError *err = NULL;
+
+    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+    window = gtk_widget_get_window(vc->gfx.drawing_area);
+    ctx = gdk_window_create_gl_context(window, &err);
+    gdk_gl_context_set_required_version(ctx,
+                                        params->major_ver,
+                                        params->minor_ver);
+    gdk_gl_context_realize(ctx, &err);
+    return ctx;
+}
+
+void gd_gl_area_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
+{
+    /* FIXME */
+}
+
+void gd_gl_area_scanout(DisplayChangeListener *dcl,
+                        uint32_t backing_id, bool backing_y_0_top,
+                        uint32_t x, uint32_t y,
+                        uint32_t w, uint32_t h)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    vc->gfx.x = x;
+    vc->gfx.y = y;
+    vc->gfx.w = w;
+    vc->gfx.h = h;
+    vc->gfx.tex_id = backing_id;
+    vc->gfx.y0_top = backing_y_0_top;
+
+    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
+
+    if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
+        gtk_gl_area_set_scanout_mode(vc, false);
+        return;
+    }
+
+    gtk_gl_area_set_scanout_mode(vc, true);
+    if (!vc->gfx.fbo_id) {
+        glGenFramebuffers(1, &vc->gfx.fbo_id);
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, vc->gfx.tex_id, 0);
+}
+
+void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
+                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
+
+    gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+}
+
+void gtk_gl_area_init(void)
+{
+    display_opengl = 1;
+}
+
+qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl)
+{
+    return gdk_gl_context_get_current();
+}
+
+int gd_gl_area_make_current(DisplayChangeListener *dcl,
+                            qemu_gl_context ctx)
+{
+    gdk_gl_context_make_current(ctx);
+    return 0;
+}
diff --git a/ui/gtk.c b/ui/gtk.c
index 6faf5a5..5cbb389 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -356,6 +356,12 @@ static void gd_update_full_redraw(VirtualConsole *vc)
     GtkWidget *area = vc->gfx.drawing_area;
     int ww, wh;
     gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
+#if defined(CONFIG_GTK_GL)
+    if (vc->gfx.gls) {
+        gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
+        return;
+    }
+#endif
     gtk_widget_queue_draw_area(area, 0, 0, ww, wh);
 }
 
@@ -596,6 +602,27 @@ static const DisplayChangeListenerOps dcl_ops = {
 
 /** DisplayState Callbacks (opengl version) **/
 
+#if defined(CONFIG_GTK_GL)
+
+static const DisplayChangeListenerOps dcl_gl_area_ops = {
+    .dpy_name             = "gtk-egl",
+    .dpy_gfx_update       = gd_gl_area_update,
+    .dpy_gfx_switch       = gd_gl_area_switch,
+    .dpy_gfx_check_format = console_gl_check_format,
+    .dpy_refresh          = gd_gl_area_refresh,
+    .dpy_mouse_set        = gd_mouse_set,
+    .dpy_cursor_define    = gd_cursor_define,
+
+    .dpy_gl_ctx_create       = gd_gl_area_create_context,
+    .dpy_gl_ctx_destroy      = gd_gl_area_destroy_context,
+    .dpy_gl_ctx_make_current = gd_gl_area_make_current,
+    .dpy_gl_ctx_get_current  = gd_gl_area_get_current_context,
+    .dpy_gl_scanout          = gd_gl_area_scanout,
+    .dpy_gl_update           = gd_gl_area_scanout_flush,
+};
+
+#else
+
 static const DisplayChangeListenerOps dcl_egl_ops = {
     .dpy_name             = "gtk-egl",
     .dpy_gfx_update       = gd_egl_update,
@@ -613,7 +640,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
     .dpy_gl_update           = gd_egl_scanout_flush,
 };
 
-#endif
+#endif /* CONFIG_GTK_GL */
+#endif /* CONFIG_OPENGL */
 
 /** QEMU Events **/
 
@@ -663,6 +691,19 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
     return TRUE;
 }
 
+#if defined(CONFIG_GTK_GL)
+static gboolean gd_render_event(GtkGLArea *area, GdkGLContext *context,
+                                void *opaque)
+{
+    VirtualConsole *vc = opaque;
+
+    if (vc->gfx.gls) {
+        gd_gl_area_draw(vc);
+    }
+    return TRUE;
+}
+#endif
+
 static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
 {
     VirtualConsole *vc = opaque;
@@ -673,8 +714,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
 
 #if defined(CONFIG_OPENGL)
     if (vc->gfx.gls) {
+#if defined(CONFIG_GTK_GL)
+        /* invoke render callback please */
+        return FALSE;
+#else
         gd_egl_draw(vc);
         return TRUE;
+#endif
     }
 #endif
 
@@ -1618,6 +1664,10 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
 #if GTK_CHECK_VERSION(3, 0, 0)
     g_signal_connect(vc->gfx.drawing_area, "draw",
                      G_CALLBACK(gd_draw_event), vc);
+#if defined(CONFIG_GTK_GL)
+    g_signal_connect(vc->gfx.drawing_area, "render",
+                     G_CALLBACK(gd_render_event), vc);
+#endif
 #else
     g_signal_connect(vc->gfx.drawing_area, "expose-event",
                      G_CALLBACK(gd_expose_event), vc);
@@ -1726,7 +1776,37 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
     vc->gfx.scale_x = 1.0;
     vc->gfx.scale_y = 1.0;
 
-    vc->gfx.drawing_area = gtk_drawing_area_new();
+#if defined(CONFIG_OPENGL)
+    if (display_opengl) {
+#if defined(CONFIG_GTK_GL)
+        vc->gfx.drawing_area = gtk_gl_area_new();
+        vc->gfx.dcl.ops = &dcl_gl_area_ops;
+#else
+        vc->gfx.drawing_area = gtk_drawing_area_new();
+        /*
+         * gtk_widget_set_double_buffered() was deprecated in 3.14.
+         * It is required for opengl rendering on X11 though.  A
+         * proper replacement (native opengl support) is only
+         * available in 3.16+.  Silence the warning if possible.
+         */
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+        gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
+#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
+#pragma GCC diagnostic pop
+#endif
+        vc->gfx.dcl.ops = &dcl_egl_ops;
+#endif /* CONFIG_GTK_GL */
+    } else
+#endif
+    {
+        vc->gfx.drawing_area = gtk_drawing_area_new();
+        vc->gfx.dcl.ops = &dcl_ops;
+    }
+
+
     gtk_widget_add_events(vc->gfx.drawing_area,
                           GDK_POINTER_MOTION_MASK |
                           GDK_BUTTON_PRESS_MASK |
@@ -1744,29 +1824,6 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
     gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
                              vc->tab_item, gtk_label_new(vc->label));
 
-#if defined(CONFIG_OPENGL)
-    if (display_opengl) {
-        /*
-         * gtk_widget_set_double_buffered() was deprecated in 3.14.
-         * It is required for opengl rendering on X11 though.  A
-         * proper replacement (native opengl support) is only
-         * available in 3.16+.  Silence the warning if possible.
-         */
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-        gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
-#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
-#pragma GCC diagnostic pop
-#endif
-        vc->gfx.dcl.ops = &dcl_egl_ops;
-    } else
-#endif
-    {
-        vc->gfx.dcl.ops = &dcl_ops;
-    }
-
     vc->gfx.dcl.con = con;
     register_displaychangelistener(&vc->gfx.dcl);
 
@@ -2029,8 +2086,12 @@ void early_gtk_display_init(int opengl)
         break;
     case 1: /* on */
 #if defined(CONFIG_OPENGL)
+#if defined(CONFIG_GTK_GL)
+        gtk_gl_area_init();
+#else
         gtk_egl_init();
 #endif
+#endif
         break;
     default:
         g_assert_not_reached();
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
@ 2015-09-10 12:40   ` Marc-André Lureau
  2015-09-10 13:22     ` Gerd Hoffmann
  2015-09-14 16:00   ` Max Reitz
  1 sibling, 1 reply; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-10 12:40 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

Hi

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Create a buffer for the vertex data and place vertexes
> there at initialization time.  Then just use the buffer
> for each texture blit.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/shader.h |  4 +++-
>  ui/console-gl.c     |  7 ++++++-
>  ui/shader.c         | 32 +++++++++++++++++++++++++++-----
>  3 files changed, 36 insertions(+), 7 deletions(-)
>
> diff --git a/include/ui/shader.h b/include/ui/shader.h
> index 8509596..f7d8618 100644
> --- a/include/ui/shader.h
> +++ b/include/ui/shader.h
> @@ -3,7 +3,9 @@
>
>  #include <epoxy/gl.h>
>
> -void qemu_gl_run_texture_blit(GLint texture_blit_prog);
> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog);
> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
> +                              GLint texture_blit_vao);
>
>  GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
>  GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
> diff --git a/ui/console-gl.c b/ui/console-gl.c
> index cb45cf8..baf397b 100644
> --- a/ui/console-gl.c
> +++ b/ui/console-gl.c
> @@ -33,6 +33,7 @@
>
>  struct ConsoleGLState {
>      GLint texture_blit_prog;
> +    GLint texture_blit_vao;
>  };
>
>  /* ---------------------------------------------------------------------- */
> @@ -47,6 +48,9 @@ ConsoleGLState *console_gl_init_context(void)
>          exit(1);
>      }
>
> +    gls->texture_blit_vao =
> +        qemu_gl_init_texture_blit(gls->texture_blit_prog);
> +

The gl console doesn't have cleanup, ok

>      return gls;
>  }
>
> @@ -131,7 +135,8 @@ 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);
> +    qemu_gl_run_texture_blit(gls->texture_blit_prog,
> +                             gls->texture_blit_vao);
>  }
>
>  void surface_gl_destroy_texture(ConsoleGLState *gls,
> diff --git a/ui/shader.c b/ui/shader.c
> index 52a4632..ada1c4c 100644
> --- a/ui/shader.c
> +++ b/ui/shader.c
> @@ -29,21 +29,43 @@
>
>  /* ---------------------------------------------------------------------- */
>
> -void qemu_gl_run_texture_blit(GLint texture_blit_prog)
> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
>  {
> -    GLfloat in_position[] = {
> +    static const GLfloat in_position[] = {
>          -1, -1,
>          1,  -1,
>          -1,  1,
>          1,   1,
>      };
>      GLint l_position;
> +    GLuint vao, buffer;
> +
> +    glGenVertexArrays(1, &vao);
> +    glBindVertexArray(vao);
> +
> +    /* this is the VBO that holds the vertex data */
> +    glGenBuffers(1, &buffer);
> +    glBindBuffer(GL_ARRAY_BUFFER, buffer);
> +    glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position,
> +                 GL_STATIC_DRAW);
>
> -    glUseProgram(texture_blit_prog);
>      l_position = glGetAttribLocation(texture_blit_prog, "in_position");
> -    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position);
> +    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
>      glEnableVertexAttribArray(l_position);
> -    glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4);
> +
> +    glBindBuffer (GL_ARRAY_BUFFER, 0);
> +    glBindVertexArray (0);
> +    glDeleteBuffers (1, &buffer);
> +

extra space before (

Is the unbinding necessary?

> +    return vao;
> +}
> +
> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
> +                              GLint texture_blit_vao)
> +{
> +    glUseProgram(texture_blit_prog);
> +    glBindVertexArray(texture_blit_vao);
> +    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
>  }
>
>  /* ---------------------------------------------------------------------- */
> --
> 1.8.3.1
>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround Gerd Hoffmann
@ 2015-09-10 12:40   ` Marc-André Lureau
  2015-09-14 16:16   ` Max Reitz
  1 sibling, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-10 12:40 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  ui/sdl2-2d.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c
> index d0b340f..191ee3b 100644
> --- a/ui/sdl2-2d.c
> +++ b/ui/sdl2-2d.c
> @@ -45,10 +45,23 @@ void sdl2_2d_update(DisplayChangeListener *dcl,
>          return;
>      }
>
> +    /*
> +     * SDL2 seems to do some double-buffering, and trying to only
> +     * update the changed areas results in only one of the two buffers
> +     * being updated.  Which flickers alot.  So lets not try to be
> +     * clever do a full update every time ...
> +     */
> +#if 0
>      rect.x = x;
>      rect.y = y;
>      rect.w = w;
>      rect.h = h;
> +#else
> +    rect.x = 0;
> +    rect.y = 0;
> +    rect.w = surface_width(surf);
> +    rect.h = surface_height(surf);
> +#endif
>
>      SDL_UpdateTexture(scon->texture, NULL, surface_data(surf),
>                        surface_stride(surf));
> --
> 1.8.3.1
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces.
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces Gerd Hoffmann
@ 2015-09-10 12:40   ` Marc-André Lureau
  2015-09-15  8:30   ` Paolo Bonzini
  1 sibling, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-10 12:40 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Add callbacks for opengl context management and scanout texture
> configuration to DisplayChangeListenerOps.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/console.h | 36 ++++++++++++++++++++++++++++
>  ui/console.c         | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 101 insertions(+), 2 deletions(-)
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 047a2b4..df92ccd 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -157,6 +157,13 @@ void cursor_set_mono(QEMUCursor *c,
>  void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
>  void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
>
> +typedef void *qemu_gl_context;
> +
> +struct qemu_gl_params {
> +    int major_ver;
> +    int minor_ver;
> +};
> +
>  typedef struct DisplayChangeListenerOps {
>      const char *dpy_name;
>
> @@ -183,6 +190,21 @@ typedef struct DisplayChangeListenerOps {
>                            int x, int y, int on);
>      void (*dpy_cursor_define)(DisplayChangeListener *dcl,
>                                QEMUCursor *cursor);
> +
> +    qemu_gl_context (*dpy_gl_ctx_create)(DisplayChangeListener *dcl,
> +                                         struct qemu_gl_params *params);
> +    void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl,
> +                              qemu_gl_context ctx);
> +    int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl,
> +                                   qemu_gl_context ctx);
> +    qemu_gl_context (*dpy_gl_ctx_get_current)(DisplayChangeListener *dcl);
> +
> +    void (*dpy_gl_scanout)(DisplayChangeListener *dcl,
> +                           uint32_t backing_id, bool backing_y_0_top,
> +                           uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +    void (*dpy_gl_update)(DisplayChangeListener *dcl,
> +                          uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +
>  } DisplayChangeListenerOps;
>
>  struct DisplayChangeListener {
> @@ -244,6 +266,20 @@ bool dpy_cursor_define_supported(QemuConsole *con);
>  bool dpy_gfx_check_format(QemuConsole *con,
>                            pixman_format_code_t format);
>
> +void dpy_gl_scanout(QemuConsole *con,
> +                    uint32_t backing_id, bool backing_y_0_top,
> +                    uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +void dpy_gl_update(QemuConsole *con,
> +                   uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +
> +qemu_gl_context dpy_gl_ctx_create(QemuConsole *con,
> +                                  struct qemu_gl_params *params);
> +void dpy_gl_ctx_destroy(QemuConsole *con, qemu_gl_context ctx);
> +int dpy_gl_ctx_make_current(QemuConsole *con, qemu_gl_context ctx);
> +qemu_gl_context dpy_gl_ctx_get_current(QemuConsole *con);
> +
> +bool console_has_gl(QemuConsole *con);
> +
>  static inline int surface_stride(DisplaySurface *s)
>  {
>      return pixman_image_get_stride(s->image);
> diff --git a/ui/console.c b/ui/console.c
> index 75fc492..61e45af 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -121,6 +121,7 @@ struct QemuConsole {
>      DisplayState *ds;
>      DisplaySurface *surface;
>      int dcls;
> +    DisplayChangeListener *gl;
>
>      /* Graphic console state.  */
>      Object *device;
> @@ -1332,6 +1333,11 @@ void qemu_free_displaysurface(DisplaySurface *surface)
>      g_free(surface);
>  }
>
> +bool console_has_gl(QemuConsole *con)
> +{
> +    return con->gl != NULL;
> +}
> +
>  void register_displaychangelistener(DisplayChangeListener *dcl)
>  {
>      static const char nodev[] =
> @@ -1339,6 +1345,17 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
>      static DisplaySurface *dummy;
>      QemuConsole *con;
>
> +    if (dcl->ops->dpy_gl_ctx_create) {
> +        /* display has opengl support */
> +        assert(dcl->con);
> +        if (dcl->con->gl) {
> +            fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
> +                    dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
> +            exit(1);
> +        }
> +        dcl->con->gl = dcl;
> +    }
> +
>      trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
>      dcl->ds = get_alloc_displaystate();
>      QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
> @@ -1417,9 +1434,13 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
>  {
>      DisplayState *s = con->ds;
>      DisplayChangeListener *dcl;
> -    int width = surface_width(con->surface);
> -    int height = surface_height(con->surface);
> +    int width = w;
> +    int height = h;
>
> +    if (con->surface) {
> +        width = surface_width(con->surface);
> +        height = surface_height(con->surface);
> +    }
>      x = MAX(x, 0);
>      y = MAX(y, 0);
>      x = MIN(x, width);
> @@ -1619,6 +1640,48 @@ bool dpy_cursor_define_supported(QemuConsole *con)
>      return false;
>  }
>
> +qemu_gl_context dpy_gl_ctx_create(QemuConsole *con,
> +                                  struct qemu_gl_params *qparams)
> +{
> +    assert(con->gl);
> +    return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
> +}
> +
> +void dpy_gl_ctx_destroy(QemuConsole *con, qemu_gl_context ctx)
> +{
> +    assert(con->gl);
> +    con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
> +}
> +
> +int dpy_gl_ctx_make_current(QemuConsole *con, qemu_gl_context ctx)
> +{
> +    assert(con->gl);
> +    return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
> +}
> +
> +qemu_gl_context dpy_gl_ctx_get_current(QemuConsole *con)
> +{
> +    assert(con->gl);
> +    return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
> +}
> +
> +void dpy_gl_scanout(QemuConsole *con,
> +                    uint32_t backing_id, bool backing_y_0_top,
> +                    uint32_t x, uint32_t y, uint32_t width, uint32_t height)
> +{
> +    assert(con->gl);
> +    con->gl->ops->dpy_gl_scanout(con->gl, backing_id,
> +                                 backing_y_0_top,
> +                                 x, y, width, height);
> +}
> +
> +void dpy_gl_update(QemuConsole *con,
> +                   uint32_t x, uint32_t y, uint32_t w, uint32_t h)
> +{
> +    assert(con->gl);
> +    con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
> +}
> +
>  /***********************************************************/
>  /* register display */
>
> --
> 1.8.3.1
>
>

dpy_gl_scanout() will eventually need to be extended to provide more
details, but that can be changed later.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d Gerd Hoffmann
@ 2015-09-10 12:41   ` Marc-André Lureau
  0 siblings, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-10 12:41 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Sync with linux kernel headers with virgl/3d patches applied.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/standard-headers/linux/virtio_gpu.h | 112 +++++++++++++++++++++++++++-
>  1 file changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/include/standard-headers/linux/virtio_gpu.h b/include/standard-headers/linux/virtio_gpu.h
> index 72ef815..76e5e52 100644
> --- a/include/standard-headers/linux/virtio_gpu.h
> +++ b/include/standard-headers/linux/virtio_gpu.h
> @@ -40,6 +40,8 @@
>
>  #include "standard-headers/linux/types.h"
>
> +#define VIRTIO_GPU_FEATURE_VIRGL 0
> +
>  enum virtio_gpu_ctrl_type {
>         VIRTIO_GPU_UNDEFINED = 0,
>
> @@ -52,6 +54,18 @@ enum virtio_gpu_ctrl_type {
>         VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
>         VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
>         VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
> +       VIRTIO_GPU_CMD_GET_CAPSET_INFO,
> +       VIRTIO_GPU_CMD_GET_CAPSET,
> +
> +       /* 3d commands */
> +       VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
> +       VIRTIO_GPU_CMD_CTX_DESTROY,
> +       VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
> +       VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
> +       VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
> +       VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
> +       VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
> +       VIRTIO_GPU_CMD_SUBMIT_3D,
>
>         /* cursor commands */
>         VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
> @@ -60,6 +74,8 @@ enum virtio_gpu_ctrl_type {
>         /* success responses */
>         VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
>         VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
> +       VIRTIO_GPU_RESP_OK_CAPSET_INFO,
> +       VIRTIO_GPU_RESP_OK_CAPSET,
>
>         /* error responses */
>         VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
> @@ -180,13 +196,107 @@ struct virtio_gpu_resp_display_info {
>         } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
>  };
>
> +/* data passed in the control vq, 3d related */
> +
> +struct virtio_gpu_box {
> +       uint32_t x, y, z;
> +       uint32_t w, h, d;
> +};
> +
> +/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
> +struct virtio_gpu_transfer_host_3d {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       struct virtio_gpu_box box;
> +       uint64_t offset;
> +       uint32_t resource_id;
> +       uint32_t level;
> +       uint32_t stride;
> +       uint32_t layer_stride;
> +};
> +
> +/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
> +#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
> +struct virtio_gpu_resource_create_3d {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t resource_id;
> +       uint32_t target;
> +       uint32_t format;
> +       uint32_t bind;
> +       uint32_t width;
> +       uint32_t height;
> +       uint32_t depth;
> +       uint32_t array_size;
> +       uint32_t last_level;
> +       uint32_t nr_samples;
> +       uint32_t flags;
> +       uint32_t padding;
> +};
> +
> +/* VIRTIO_GPU_CMD_CTX_CREATE */
> +struct virtio_gpu_ctx_create {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t nlen;
> +       uint32_t padding;
> +       char debug_name[64];
> +};
> +
> +/* VIRTIO_GPU_CMD_CTX_DESTROY */
> +struct virtio_gpu_ctx_destroy {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +};
> +
> +/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
> +struct virtio_gpu_ctx_resource {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t resource_id;
> +       uint32_t padding;
> +};
> +
> +/* VIRTIO_GPU_CMD_SUBMIT_3D */
> +struct virtio_gpu_cmd_submit {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t size;
> +       uint32_t padding;
> +};
> +
> +#define VIRTIO_GPU_CAPSET_VIRGL 1
> +
> +/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
> +struct virtio_gpu_get_capset_info {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t capset_index;
> +       uint32_t padding;
> +};
> +
> +/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
> +struct virtio_gpu_resp_capset_info {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t capset_id;
> +       uint32_t capset_max_version;
> +       uint32_t capset_max_size;
> +       uint32_t padding;
> +};
> +
> +/* VIRTIO_GPU_CMD_GET_CAPSET */
> +struct virtio_gpu_get_capset {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint32_t capset_id;
> +       uint32_t capset_version;
> +};
> +
> +/* VIRTIO_GPU_RESP_OK_CAPSET */
> +struct virtio_gpu_resp_capset {
> +       struct virtio_gpu_ctrl_hdr hdr;
> +       uint8_t capset_data[];
> +};
> +
>  #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
>
>  struct virtio_gpu_config {
>         uint32_t events_read;
>         uint32_t events_clear;
>         uint32_t num_scanouts;
> -       uint32_t reserved;
> +       uint32_t num_capsets;
>  };
>
>  /* simple formats for fbcon/X use */
> --
> 1.8.3.1
>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-10 12:40   ` Marc-André Lureau
@ 2015-09-10 13:22     ` Gerd Hoffmann
  2015-09-10 13:42       ` Marc-André Lureau
  0 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-10 13:22 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU

> > +    glBindBuffer (GL_ARRAY_BUFFER, 0);
> > +    glBindVertexArray (0);
> > +    glDeleteBuffers (1, &buffer);
> > +
> 
> extra space before (

Fixed.

> Is the unbinding necessary?

Unbinding?  Do you mam the DeleteBuffers?

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-10 13:22     ` Gerd Hoffmann
@ 2015-09-10 13:42       ` Marc-André Lureau
  2015-09-10 14:59         ` Gerd Hoffmann
  0 siblings, 1 reply; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-10 13:42 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

Hi

On Thu, Sep 10, 2015 at 3:22 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> > +    glBindBuffer (GL_ARRAY_BUFFER, 0);
>> > +    glBindVertexArray (0);
>> > +    glDeleteBuffers (1, &buffer);
>> > +
>>
>> extra space before (
>
> Fixed.
>
>> Is the unbinding necessary?
>
> Unbinding?  Do you mam the DeleteBuffers?
>

The glBind..(.., 0)

I think they shouldn't be necessary unless you have some other gl
context sensitive code.

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-10 13:42       ` Marc-André Lureau
@ 2015-09-10 14:59         ` Gerd Hoffmann
  0 siblings, 0 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-10 14:59 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU

On Do, 2015-09-10 at 15:42 +0200, Marc-André Lureau wrote:
> Hi
> 
> On Thu, Sep 10, 2015 at 3:22 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> >> > +    glBindBuffer (GL_ARRAY_BUFFER, 0);
> >> > +    glBindVertexArray (0);
> >> > +    glDeleteBuffers (1, &buffer);
> >> > +
> >>
> >> extra space before (
> >
> > Fixed.
> >
> >> Is the unbinding necessary?
> >
> > Unbinding?  Do you mam the DeleteBuffers?
> >
> 
> The glBind..(.., 0)
> 
> I think they shouldn't be necessary unless you have some other gl
> context sensitive code.

Just good style copied from sample code.
Probably it's not really needed here.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers Gerd Hoffmann
@ 2015-09-11 14:13   ` Marc-André Lureau
  0 siblings, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-11 14:13 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Add helper functions to manage opengl contexts using egl.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/egl-context.h | 14 ++++++++++++++
>  ui/Makefile.objs         |  1 +
>  ui/egl-context.c         | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 49 insertions(+)
>  create mode 100644 include/ui/egl-context.h
>  create mode 100644 ui/egl-context.c
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

> diff --git a/include/ui/egl-context.h b/include/ui/egl-context.h
> new file mode 100644
> index 0000000..a1c8007
> --- /dev/null
> +++ b/include/ui/egl-context.h
> @@ -0,0 +1,14 @@
> +#ifndef EGL_CONTEXT_H
> +#define EGL_CONTEXT_H
> +
> +#include "ui/console.h"
> +#include "ui/egl-helpers.h"
> +
> +qemu_gl_context qemu_egl_create_context(DisplayChangeListener *dcl,
> +                                        struct qemu_gl_params *params);
> +void qemu_egl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx);
> +int qemu_egl_make_context_current(DisplayChangeListener *dcl,
> +                                  qemu_gl_context ctx);
> +qemu_gl_context qemu_egl_get_current_context(DisplayChangeListener *dcl);
> +
> +#endif /* EGL_CONTEXT_H */
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index c62d4d9..9bc64a0 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -31,6 +31,7 @@ ifeq ($(CONFIG_OPENGL),y)
>  common-obj-y += shader.o
>  common-obj-y += console-gl.o
>  common-obj-y += egl-helpers.o
> +common-obj-y += egl-context.o
>  common-obj-$(CONFIG_GTK) += gtk-egl.o
>  endif
>
> diff --git a/ui/egl-context.c b/ui/egl-context.c
> new file mode 100644
> index 0000000..233ed37
> --- /dev/null
> +++ b/ui/egl-context.c
> @@ -0,0 +1,34 @@
> +#include "qemu-common.h"
> +#include "ui/egl-context.h"
> +
> +qemu_gl_context qemu_egl_create_context(DisplayChangeListener *dcl,
> +                                        struct qemu_gl_params *params)
> +{
> +   EGLContext ctx;
> +   EGLint ctx_att[] = {
> +      EGL_CONTEXT_CLIENT_VERSION, params->major_ver,
> +      EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
> +      EGL_NONE
> +   };
> +
> +   ctx = eglCreateContext(qemu_egl_display, qemu_egl_config,
> +                          eglGetCurrentContext(), ctx_att);
> +   return ctx;
> +}
> +
> +void qemu_egl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
> +{
> +    eglDestroyContext(qemu_egl_display, ctx);
> +}
> +
> +int qemu_egl_make_context_current(DisplayChangeListener *dcl,
> +                                  qemu_gl_context ctx)
> +{
> +   return eglMakeCurrent(qemu_egl_display,
> +                         EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
> +}
> +
> +qemu_gl_context qemu_egl_get_current_context(DisplayChangeListener *dcl)
> +{
> +    return eglGetCurrentContext();
> +}
> --
> 1.8.3.1
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl) Gerd Hoffmann
@ 2015-09-11 14:36   ` Marc-André Lureau
  0 siblings, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-11 14:36 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This allows virtio-gpu to render in 3d mode.
> Uses egl, for gtk versions 3.14 and older.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/gtk.h |  16 +++++++
>  ui/gtk-egl.c     | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++----
>  ui/gtk.c         |   7 +++
>  3 files changed, 144 insertions(+), 8 deletions(-)
>
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index ee6dffd..1e04c0c 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -24,6 +24,7 @@
>
>  #if defined(CONFIG_OPENGL)
>  #include "ui/egl-helpers.h"
> +#include "ui/egl-context.h"
>  #endif
>
>  /* Compatibility define to let us build on both Gtk2 and Gtk3 */
> @@ -50,6 +51,11 @@ typedef struct VirtualGfxConsole {
>      EGLContext ectx;
>      EGLSurface esurface;
>      int glupdates;
> +    int x, y, w, h;
> +    GLuint tex_id;
> +    GLuint fbo_id;
> +    bool y0_top;
> +    bool scanout_mode;
>  #endif
>  } VirtualGfxConsole;
>
> @@ -94,6 +100,16 @@ void gd_egl_update(DisplayChangeListener *dcl,
>  void gd_egl_refresh(DisplayChangeListener *dcl);
>  void gd_egl_switch(DisplayChangeListener *dcl,
>                     DisplaySurface *surface);
> +qemu_gl_context gd_egl_create_context(DisplayChangeListener *dcl,
> +                                      struct qemu_gl_params *params);
> +void gd_egl_scanout(DisplayChangeListener *dcl,
> +                    uint32_t backing_id, bool backing_y_0_top,
> +                    uint32_t x, uint32_t y,
> +                    uint32_t w, uint32_t h);
> +void gd_egl_scanout_flush(DisplayChangeListener *dcl,
> +                          uint32_t x, uint32_t y, uint32_t w, uint32_t h);
>  void gtk_egl_init(void);
> +int gd_egl_make_current(DisplayChangeListener *dcl,
> +                        qemu_gl_context ctx);
>
>  #endif /* UI_GTK_H */
> diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
> index 15b41f2..ae5c7d0 100644
> --- a/ui/gtk-egl.c
> +++ b/ui/gtk-egl.c
> @@ -21,6 +21,28 @@
>
>  #include "sysemu/sysemu.h"
>
> +static void gtk_egl_set_scanout_mode(VirtualConsole *vc, bool scanout)
> +{
> +    if (vc->gfx.scanout_mode == scanout) {
> +        return;
> +    }
> +
> +    vc->gfx.scanout_mode = scanout;
> +    if (!vc->gfx.scanout_mode) {
> +        if (vc->gfx.fbo_id) {
> +            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
> +                                      GL_COLOR_ATTACHMENT0_EXT,
> +                                      GL_TEXTURE_2D, 0, 0);
> +            glDeleteFramebuffers(1, &vc->gfx.fbo_id);
> +            vc->gfx.fbo_id = 0;
> +        }
> +        if (vc->gfx.surface) {
> +            surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
> +            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
> +        }
> +    }
> +}
> +
>  /** DisplayState Callbacks (opengl version) **/
>
>  void gd_egl_init(VirtualConsole *vc)
> @@ -50,19 +72,26 @@ void gd_egl_draw(VirtualConsole *vc)
>      GdkWindow *window;
>      int ww, wh;
>
> -    if (!vc->gfx.gls || !vc->gfx.ds) {
> +    if (!vc->gfx.gls) {
>          return;
>      }
>
> -    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> -                   vc->gfx.esurface, vc->gfx.ectx);
> +    if (vc->gfx.scanout_mode) {
> +        gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
> +    } else {
> +        if (!vc->gfx.ds) {
> +            return;
> +        }
> +        eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +                       vc->gfx.esurface, vc->gfx.ectx);
>
> -    window = gtk_widget_get_window(vc->gfx.drawing_area);
> -    gdk_drawable_get_size(window, &ww, &wh);
> -    surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
> -    surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
> +        window = gtk_widget_get_window(vc->gfx.drawing_area);
> +        gdk_drawable_get_size(window, &ww, &wh);
> +        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
> +        surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
>
> -    eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
> +        eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);

> +    }
>  }
>
>  void gd_egl_update(DisplayChangeListener *dcl,
> @@ -99,6 +128,7 @@ void gd_egl_refresh(DisplayChangeListener *dcl)
>
>      if (vc->gfx.glupdates) {
>          vc->gfx.glupdates = 0;
> +        gtk_egl_set_scanout_mode(vc, false);
>          gd_egl_draw(vc);
>      }
>  }
> @@ -128,6 +158,80 @@ void gd_egl_switch(DisplayChangeListener *dcl,
>      }
>  }
>
> +qemu_gl_context gd_egl_create_context(DisplayChangeListener *dcl,
> +                                      struct qemu_gl_params *params)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +                   vc->gfx.esurface, vc->gfx.ectx);
> +    return qemu_egl_create_context(dcl, params);
> +}
> +
> +void gd_egl_scanout(DisplayChangeListener *dcl,
> +                    uint32_t backing_id, bool backing_y_0_top,
> +                    uint32_t x, uint32_t y,
> +                    uint32_t w, uint32_t h)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    vc->gfx.x = x;
> +    vc->gfx.y = y;
> +    vc->gfx.w = w;
> +    vc->gfx.h = h;
> +    vc->gfx.tex_id = backing_id;
> +    vc->gfx.y0_top = backing_y_0_top;
> +
> +    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +                   vc->gfx.esurface, vc->gfx.ectx);
> +
> +    if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
> +        gtk_egl_set_scanout_mode(vc, false);
> +        return;
> +    }
> +
> +    gtk_egl_set_scanout_mode(vc, true);
> +    if (!vc->gfx.fbo_id) {
> +        glGenFramebuffers(1, &vc->gfx.fbo_id);
> +    }
> +
> +    glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id);
> +    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
> +                              GL_TEXTURE_2D, vc->gfx.tex_id, 0);
> +}
> +

looks like this doesn't respect aspect-ratio (like the rest of the
zoom code), but that's not new,

> +void gd_egl_scanout_flush(DisplayChangeListener *dcl,
> +                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +    GdkWindow *window;
> +    int ww, wh, y1, y2;
> +
> +    if (!vc->gfx.scanout_mode) {
> +        return;
> +    }
> +    if (!vc->gfx.fbo_id) {
> +        return;
> +    }
> +
> +    eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +                   vc->gfx.esurface, vc->gfx.ectx);
> +
> +    glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id);
> +    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
> +
> +    window = gtk_widget_get_window(vc->gfx.drawing_area);
> +    gdk_drawable_get_size(window, &ww, &wh);
> +    glViewport(0, 0, ww, wh);
> +    y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
> +    y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
> +    glBlitFramebuffer(0, y1, vc->gfx.w, y2,
> +                      0, 0, ww, wh,
> +                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
> +
> +    eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
> +}
> +
>  void gtk_egl_init(void)
>  {
>      GdkDisplay *gdk_display = gdk_display_get_default();
> @@ -139,3 +243,12 @@ void gtk_egl_init(void)
>
>      display_opengl = 1;
>  }
> +
> +int gd_egl_make_current(DisplayChangeListener *dcl,
> +                        qemu_gl_context ctx)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
> +                          vc->gfx.esurface, ctx);
> +}
> diff --git a/ui/gtk.c b/ui/gtk.c
> index df2a79e..6faf5a5 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -604,6 +604,13 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
>      .dpy_refresh          = gd_egl_refresh,
>      .dpy_mouse_set        = gd_mouse_set,
>      .dpy_cursor_define    = gd_cursor_define,
> +
> +    .dpy_gl_ctx_create       = gd_egl_create_context,
> +    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,
> +    .dpy_gl_ctx_make_current = gd_egl_make_current,
> +    .dpy_gl_ctx_get_current  = qemu_egl_get_current_context,
> +    .dpy_gl_scanout          = gd_egl_scanout,
> +    .dpy_gl_update           = gd_egl_scanout_flush,
>  };
>
>  #endif
> --
> 1.8.3.1
>
>

looks good to me, (and I get stuff rendered fast on screen :)

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea) Gerd Hoffmann
@ 2015-09-11 14:44   ` Marc-André Lureau
  2015-09-14 13:50     ` Gerd Hoffmann
  0 siblings, 1 reply; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-11 14:44 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

 Hi

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This allows virtio-gpu to render in 3d mode.
> Uses native opengl support which is present
> in gtk versions 3.16 and newer.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

After this patch, when starting qemu I get:

(qemu-system-x86_64:28264): Gtk-CRITICAL **: gtk_gl_area_make_current:
assertion 'gtk_widget_get_realized (widget)' failed
qemu-system-x86_64: Couldn't find current GLX or EGL context.



> ---
>  configure        |   8 ++
>  include/ui/gtk.h |  23 ++++++
>  ui/Makefile.objs |   5 ++
>  ui/gtk-gl-area.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  ui/gtk.c         | 111 +++++++++++++++++++++-------
>  5 files changed, 341 insertions(+), 25 deletions(-)
>  create mode 100644 ui/gtk-gl-area.c
>
> diff --git a/configure b/configure
> index 2d922d1..f7692d2 100755
> --- a/configure
> +++ b/configure
> @@ -329,6 +329,7 @@ glusterfs_zerofill="no"
>  archipelago="no"
>  gtk=""
>  gtkabi=""
> +gtk_gl="no"
>  gnutls=""
>  gnutls_hash=""
>  vte=""
> @@ -3182,6 +3183,9 @@ if test "$opengl" != "no" ; then
>      opengl_cflags="$($pkg_config --cflags $opengl_pkgs) $x11_cflags"
>      opengl_libs="$($pkg_config --libs $opengl_pkgs) $x11_libs"
>      opengl=yes
> +    if test "$gtk" = "yes" && $pkg_config --exists "$gtkpackage >= 3.16"; then
> +        gtk_gl="yes"
> +    fi
>    else
>      if test "$opengl" = "yes" ; then
>        feature_not_found "opengl" "Please install opengl (mesa) devel pkgs: $opengl_pkgs"
> @@ -4541,6 +4545,7 @@ fi
>  echo "pixman            $pixman"
>  echo "SDL support       $sdl"
>  echo "GTK support       $gtk"
> +echo "GTK GL support    $gtk_gl"
>  echo "GNUTLS support    $gnutls"
>  echo "GNUTLS hash       $gnutls_hash"
>  echo "GNUTLS gcrypt     $gnutls_gcrypt"
> @@ -4902,6 +4907,9 @@ if test "$gtk" = "yes" ; then
>    echo "CONFIG_GTK=y" >> $config_host_mak
>    echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
>    echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak
> +  if test "$gtk_gl" = "yes" ; then
> +    echo "CONFIG_GTK_GL=y" >> $config_host_mak
> +  fi
>  fi
>  if test "$gnutls" = "yes" ; then
>    echo "CONFIG_GNUTLS=y" >> $config_host_mak
> diff --git a/include/ui/gtk.h b/include/ui/gtk.h
> index 1e04c0c..76aabd0 100644
> --- a/include/ui/gtk.h
> +++ b/include/ui/gtk.h
> @@ -112,4 +112,27 @@ void gtk_egl_init(void);
>  int gd_egl_make_current(DisplayChangeListener *dcl,
>                          qemu_gl_context ctx);
>
> +/* ui/gtk-gl-area.c */
> +void gd_gl_area_init(VirtualConsole *vc);
> +void gd_gl_area_draw(VirtualConsole *vc);
> +void gd_gl_area_update(DisplayChangeListener *dcl,
> +                       int x, int y, int w, int h);
> +void gd_gl_area_refresh(DisplayChangeListener *dcl);
> +void gd_gl_area_switch(DisplayChangeListener *dcl,
> +                       DisplaySurface *surface);
> +qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
> +                                          struct qemu_gl_params *params);
> +void gd_gl_area_destroy_context(DisplayChangeListener *dcl,
> +                                qemu_gl_context ctx);
> +void gd_gl_area_scanout(DisplayChangeListener *dcl,
> +                        uint32_t backing_id, bool backing_y_0_top,
> +                        uint32_t x, uint32_t y,
> +                        uint32_t w, uint32_t h);
> +void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
> +                              uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +void gtk_gl_area_init(void);
> +qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl);
> +int gd_gl_area_make_current(DisplayChangeListener *dcl,
> +                            qemu_gl_context ctx);
> +
>  #endif /* UI_GTK_H */
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index 9bc64a0..bc79bdb 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -32,11 +32,16 @@ common-obj-y += shader.o
>  common-obj-y += console-gl.o
>  common-obj-y += egl-helpers.o
>  common-obj-y += egl-context.o
> +ifeq ($(CONFIG_GTK_GL),y)
> +common-obj-$(CONFIG_GTK) += gtk-gl-area.o
> +else
>  common-obj-$(CONFIG_GTK) += gtk-egl.o
>  endif
> +endif
>
>  gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS)
>  gtk-egl.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
> +gtk-gl-area.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) $(OPENGL_CFLAGS)
>  shader.o-cflags += $(OPENGL_CFLAGS)
>  console-gl.o-cflags += $(OPENGL_CFLAGS)
>  egl-helpers.o-cflags += $(OPENGL_CFLAGS)
> diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
> new file mode 100644
> index 0000000..8973c36
> --- /dev/null
> +++ b/ui/gtk-gl-area.c
> @@ -0,0 +1,219 @@
> +/*
> + * GTK UI -- glarea opengl code.
> + *
> + * Requires 3.16+ (GtkGLArea widget).
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu-common.h"
> +
> +#include "trace.h"
> +
> +#include "ui/console.h"
> +#include "ui/gtk.h"
> +#include "ui/egl-helpers.h"
> +
> +#include "sysemu/sysemu.h"
> +
> +static void gtk_gl_area_set_scanout_mode(VirtualConsole *vc, bool scanout)
> +{
> +    if (vc->gfx.scanout_mode == scanout) {
> +        return;
> +    }
> +
> +    vc->gfx.scanout_mode = scanout;
> +    if (!vc->gfx.scanout_mode) {
> +        if (vc->gfx.fbo_id) {
> +            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
> +                                      GL_COLOR_ATTACHMENT0_EXT,
> +                                      GL_TEXTURE_2D, 0, 0);
> +            glDeleteFramebuffers(1, &vc->gfx.fbo_id);
> +            vc->gfx.fbo_id = 0;
> +        }
> +        if (vc->gfx.surface) {
> +            surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
> +            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
> +        }
> +    }
> +}
> +
> +/** DisplayState Callbacks (opengl version) **/
> +
> +void gd_gl_area_draw(VirtualConsole *vc)
> +{
> +    int ww, wh, y1, y2;
> +
> +    if (!vc->gfx.gls) {
> +        return;
> +    }
> +
> +    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +    ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area);
> +    wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area);
> +
> +    if (vc->gfx.scanout_mode) {
> +        if (!vc->gfx.fbo_id) {
> +            return;
> +        }
> +
> +        glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.fbo_id);
> +        /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */
> +
> +        glViewport(0, 0, ww, wh);
> +        y1 = vc->gfx.y0_top ? 0 : vc->gfx.h;
> +        y2 = vc->gfx.y0_top ? vc->gfx.h : 0;
> +        glBlitFramebuffer(0, y1, vc->gfx.w, y2,
> +                          0, 0, ww, wh,
> +                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
> +    } else {
> +        if (!vc->gfx.ds) {
> +            return;
> +        }
> +        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +
> +        surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
> +        surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
> +    }
> +}
> +
> +void gd_gl_area_update(DisplayChangeListener *dcl,
> +                   int x, int y, int w, int h)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    if (!vc->gfx.gls || !vc->gfx.ds) {
> +        return;
> +    }
> +
> +    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +    surface_gl_update_texture(vc->gfx.gls, vc->gfx.ds, x, y, w, h);
> +    vc->gfx.glupdates++;
> +}
> +
> +void gd_gl_area_refresh(DisplayChangeListener *dcl)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    if (!vc->gfx.gls) {
> +        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +        vc->gfx.gls = console_gl_init_context();
> +        if (vc->gfx.ds) {
> +            surface_gl_create_texture(vc->gfx.gls, vc->gfx.ds);
> +        }
> +    }
> +
> +    graphic_hw_update(dcl->con);
> +
> +    if (vc->gfx.glupdates) {
> +        vc->gfx.glupdates = 0;
> +        gtk_gl_area_set_scanout_mode(vc, false);
> +        gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
> +    }
> +}
> +
> +void gd_gl_area_switch(DisplayChangeListener *dcl,
> +                       DisplaySurface *surface)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +    bool resized = true;
> +
> +    trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
> +
> +    if (vc->gfx.ds &&
> +        surface_width(vc->gfx.ds) == surface_width(surface) &&
> +        surface_height(vc->gfx.ds) == surface_height(surface)) {
> +        resized = false;
> +    }
> +
> +    if (vc->gfx.gls) {
> +        gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +        surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds);
> +        surface_gl_create_texture(vc->gfx.gls, surface);
> +    }
> +    vc->gfx.ds = surface;
> +
> +    if (resized) {
> +        gd_update_windowsize(vc);
> +    }
> +}
> +
> +qemu_gl_context gd_gl_area_create_context(DisplayChangeListener *dcl,
> +                                          struct qemu_gl_params *params)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +    GdkWindow *window;
> +    GdkGLContext *ctx;
> +    GError *err = NULL;
> +
> +    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +    window = gtk_widget_get_window(vc->gfx.drawing_area);
> +    ctx = gdk_window_create_gl_context(window, &err);
> +    gdk_gl_context_set_required_version(ctx,
> +                                        params->major_ver,
> +                                        params->minor_ver);
> +    gdk_gl_context_realize(ctx, &err);
> +    return ctx;
> +}
> +
> +void gd_gl_area_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
> +{
> +    /* FIXME */
> +}
> +
> +void gd_gl_area_scanout(DisplayChangeListener *dcl,
> +                        uint32_t backing_id, bool backing_y_0_top,
> +                        uint32_t x, uint32_t y,
> +                        uint32_t w, uint32_t h)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    vc->gfx.x = x;
> +    vc->gfx.y = y;
> +    vc->gfx.w = w;
> +    vc->gfx.h = h;
> +    vc->gfx.tex_id = backing_id;
> +    vc->gfx.y0_top = backing_y_0_top;
> +
> +    gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area));
> +
> +    if (vc->gfx.tex_id == 0 || vc->gfx.w == 0 || vc->gfx.h == 0) {
> +        gtk_gl_area_set_scanout_mode(vc, false);
> +        return;
> +    }
> +
> +    gtk_gl_area_set_scanout_mode(vc, true);
> +    if (!vc->gfx.fbo_id) {
> +        glGenFramebuffers(1, &vc->gfx.fbo_id);
> +    }
> +
> +    glBindFramebuffer(GL_FRAMEBUFFER_EXT, vc->gfx.fbo_id);
> +    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
> +                              GL_TEXTURE_2D, vc->gfx.tex_id, 0);
> +}
> +
> +void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
> +                          uint32_t x, uint32_t y, uint32_t w, uint32_t h)
> +{
> +    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
> +
> +    gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
> +}
> +
> +void gtk_gl_area_init(void)
> +{
> +    display_opengl = 1;
> +}
> +
> +qemu_gl_context gd_gl_area_get_current_context(DisplayChangeListener *dcl)
> +{
> +    return gdk_gl_context_get_current();
> +}
> +
> +int gd_gl_area_make_current(DisplayChangeListener *dcl,
> +                            qemu_gl_context ctx)
> +{
> +    gdk_gl_context_make_current(ctx);
> +    return 0;
> +}
> diff --git a/ui/gtk.c b/ui/gtk.c
> index 6faf5a5..5cbb389 100644
> --- a/ui/gtk.c
> +++ b/ui/gtk.c
> @@ -356,6 +356,12 @@ static void gd_update_full_redraw(VirtualConsole *vc)
>      GtkWidget *area = vc->gfx.drawing_area;
>      int ww, wh;
>      gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
> +#if defined(CONFIG_GTK_GL)
> +    if (vc->gfx.gls) {
> +        gtk_gl_area_queue_render(GTK_GL_AREA(vc->gfx.drawing_area));
> +        return;
> +    }
> +#endif
>      gtk_widget_queue_draw_area(area, 0, 0, ww, wh);
>  }
>
> @@ -596,6 +602,27 @@ static const DisplayChangeListenerOps dcl_ops = {
>
>  /** DisplayState Callbacks (opengl version) **/
>
> +#if defined(CONFIG_GTK_GL)
> +
> +static const DisplayChangeListenerOps dcl_gl_area_ops = {
> +    .dpy_name             = "gtk-egl",
> +    .dpy_gfx_update       = gd_gl_area_update,
> +    .dpy_gfx_switch       = gd_gl_area_switch,
> +    .dpy_gfx_check_format = console_gl_check_format,
> +    .dpy_refresh          = gd_gl_area_refresh,
> +    .dpy_mouse_set        = gd_mouse_set,
> +    .dpy_cursor_define    = gd_cursor_define,
> +
> +    .dpy_gl_ctx_create       = gd_gl_area_create_context,
> +    .dpy_gl_ctx_destroy      = gd_gl_area_destroy_context,
> +    .dpy_gl_ctx_make_current = gd_gl_area_make_current,
> +    .dpy_gl_ctx_get_current  = gd_gl_area_get_current_context,
> +    .dpy_gl_scanout          = gd_gl_area_scanout,
> +    .dpy_gl_update           = gd_gl_area_scanout_flush,
> +};
> +
> +#else
> +
>  static const DisplayChangeListenerOps dcl_egl_ops = {
>      .dpy_name             = "gtk-egl",
>      .dpy_gfx_update       = gd_egl_update,
> @@ -613,7 +640,8 @@ static const DisplayChangeListenerOps dcl_egl_ops = {
>      .dpy_gl_update           = gd_egl_scanout_flush,
>  };
>
> -#endif
> +#endif /* CONFIG_GTK_GL */
> +#endif /* CONFIG_OPENGL */
>
>  /** QEMU Events **/
>
> @@ -663,6 +691,19 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
>      return TRUE;
>  }
>
> +#if defined(CONFIG_GTK_GL)
> +static gboolean gd_render_event(GtkGLArea *area, GdkGLContext *context,
> +                                void *opaque)
> +{
> +    VirtualConsole *vc = opaque;
> +
> +    if (vc->gfx.gls) {
> +        gd_gl_area_draw(vc);
> +    }
> +    return TRUE;
> +}
> +#endif
> +
>  static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>  {
>      VirtualConsole *vc = opaque;
> @@ -673,8 +714,13 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
>
>  #if defined(CONFIG_OPENGL)
>      if (vc->gfx.gls) {
> +#if defined(CONFIG_GTK_GL)
> +        /* invoke render callback please */
> +        return FALSE;
> +#else
>          gd_egl_draw(vc);
>          return TRUE;
> +#endif
>      }
>  #endif
>
> @@ -1618,6 +1664,10 @@ static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
>  #if GTK_CHECK_VERSION(3, 0, 0)
>      g_signal_connect(vc->gfx.drawing_area, "draw",
>                       G_CALLBACK(gd_draw_event), vc);
> +#if defined(CONFIG_GTK_GL)
> +    g_signal_connect(vc->gfx.drawing_area, "render",
> +                     G_CALLBACK(gd_render_event), vc);
> +#endif
>  #else
>      g_signal_connect(vc->gfx.drawing_area, "expose-event",
>                       G_CALLBACK(gd_expose_event), vc);
> @@ -1726,7 +1776,37 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
>      vc->gfx.scale_x = 1.0;
>      vc->gfx.scale_y = 1.0;
>
> -    vc->gfx.drawing_area = gtk_drawing_area_new();
> +#if defined(CONFIG_OPENGL)
> +    if (display_opengl) {
> +#if defined(CONFIG_GTK_GL)
> +        vc->gfx.drawing_area = gtk_gl_area_new();
> +        vc->gfx.dcl.ops = &dcl_gl_area_ops;
> +#else
> +        vc->gfx.drawing_area = gtk_drawing_area_new();
> +        /*
> +         * gtk_widget_set_double_buffered() was deprecated in 3.14.
> +         * It is required for opengl rendering on X11 though.  A
> +         * proper replacement (native opengl support) is only
> +         * available in 3.16+.  Silence the warning if possible.
> +         */
> +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
> +#endif
> +        gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
> +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
> +#pragma GCC diagnostic pop
> +#endif
> +        vc->gfx.dcl.ops = &dcl_egl_ops;
> +#endif /* CONFIG_GTK_GL */
> +    } else
> +#endif
> +    {
> +        vc->gfx.drawing_area = gtk_drawing_area_new();
> +        vc->gfx.dcl.ops = &dcl_ops;
> +    }
> +
> +
>      gtk_widget_add_events(vc->gfx.drawing_area,
>                            GDK_POINTER_MOTION_MASK |
>                            GDK_BUTTON_PRESS_MASK |
> @@ -1744,29 +1824,6 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
>      gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
>                               vc->tab_item, gtk_label_new(vc->label));
>
> -#if defined(CONFIG_OPENGL)
> -    if (display_opengl) {
> -        /*
> -         * gtk_widget_set_double_buffered() was deprecated in 3.14.
> -         * It is required for opengl rendering on X11 though.  A
> -         * proper replacement (native opengl support) is only
> -         * available in 3.16+.  Silence the warning if possible.
> -         */
> -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
> -#pragma GCC diagnostic push
> -#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
> -#endif
> -        gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
> -#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE
> -#pragma GCC diagnostic pop
> -#endif
> -        vc->gfx.dcl.ops = &dcl_egl_ops;
> -    } else
> -#endif
> -    {
> -        vc->gfx.dcl.ops = &dcl_ops;
> -    }
> -
>      vc->gfx.dcl.con = con;
>      register_displaychangelistener(&vc->gfx.dcl);
>
> @@ -2029,8 +2086,12 @@ void early_gtk_display_init(int opengl)
>          break;
>      case 1: /* on */
>  #if defined(CONFIG_OPENGL)
> +#if defined(CONFIG_GTK_GL)
> +        gtk_gl_area_init();
> +#else
>          gtk_egl_init();
>  #endif
> +#endif
>          break;
>      default:
>          g_assert_not_reached();
> --
> 1.8.3.1
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 0/9] add virgl rendering support.
  2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea) Gerd Hoffmann
@ 2015-09-11 16:10 ` Marc-André Lureau
  9 siblings, 0 replies; 33+ messages in thread
From: Marc-André Lureau @ 2015-09-11 16:10 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: QEMU

Hi

On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
>   Hi,
>
> This patch series adds infrastructure for opengl rendering
> (context management, define scanout textures), adds support
> for this to sdl2 and gtk user interfaces and adds virgl/3d
> mode to virtio-gpu by hooking up the virglrenderer library.
>

Before I dig further, let me give some feedback on testing. I used f22
host, and a f22 guest with xserver/modesetting from git master.

- the sdl2 gl backend doesn't display virgl rendering, I have this
"extra" errors (not the one I usually get from virgl)
Mesa: User error: GL_INVALID_OPERATION in
glFramebufferTexture2D(window-system framebuffer)
Mesa: User error: GL_INVALID_OPERATION in glGetnTexImageARB(missing image)
Mesa: User error: GL_INVALID_OPERATION in glTexSubImage2D(invalid texture image)

- gtk egl works ok

- gtkglarea fails to initialize

- regardless of the backend I get these errors in the guest:
Sep 11 11:58:34 localhost.localdomain
/usr/libexec/gdm-x-session[1669]: (WW) modeset(0): flip queue failed:
Invalid argument
Sep 11 11:58:34 localhost.localdomain
/usr/libexec/gdm-x-session[1669]: (WW) modeset(0): Page flip failed:
Invalid argument
Sep 11 11:58:34 localhost.localdomain
/usr/libexec/gdm-x-session[1669]: (EE) modeset(0): present flip failed

- apart from the aspect-ratio issue (cursor doesn't follow it either),
there is a off-by-one cursor update bug (that I know existed before,
and I plan to look at)

Finally, wayland (gnome-shell --wayland gdm session):
- has some refresh issues that X doesn't have
- give black screen why virtio-vga,virgl=false

> please review,
>   Gerd
>
> Gerd Hoffmann (9):
>   shaders: initialize vertexes once
>   sdl2: quick & dirty flicker workaround
>   ui/console: add opengl context and scanout support interfaces.
>   virtio-gpu: update headers for virgl/3d
>   virtio-gpu: add 3d mode and virgl rendering support.
>   sdl2/opengl: add opengl context and scanout support
>   opengl: add egl-context.[ch] helpers
>   gtk/opengl: add opengl context and scanout support (egl)
>   gtk/opengl: add opengl context and scanout support (GtkGLArea)
>
>  configure                                   |  40 ++
>  hw/display/Makefile.objs                    |   6 +-
>  hw/display/virtio-gpu-3d.c                  | 598 ++++++++++++++++++++++++++++
>  hw/display/virtio-gpu.c                     | 130 +++++-
>  include/hw/virtio/virtio-gpu.h              |  22 +-
>  include/standard-headers/linux/virtio_gpu.h | 112 +++++-
>  include/ui/console.h                        |  36 ++
>  include/ui/egl-context.h                    |  14 +
>  include/ui/gtk.h                            |  39 ++
>  include/ui/sdl2.h                           |  22 +-
>  include/ui/shader.h                         |   4 +-
>  trace-events                                |   8 +
>  ui/Makefile.objs                            |   6 +
>  ui/console-gl.c                             |   7 +-
>  ui/console.c                                |  67 +++-
>  ui/egl-context.c                            |  34 ++
>  ui/gtk-egl.c                                | 129 +++++-
>  ui/gtk-gl-area.c                            | 219 ++++++++++
>  ui/gtk.c                                    | 118 ++++--
>  ui/sdl2-2d.c                                |  13 +
>  ui/sdl2-gl.c                                | 133 +++++++
>  ui/sdl2.c                                   |   7 +
>  ui/shader.c                                 |  32 +-
>  23 files changed, 1741 insertions(+), 55 deletions(-)
>  create mode 100644 hw/display/virtio-gpu-3d.c
>  create mode 100644 include/ui/egl-context.h
>  create mode 100644 ui/egl-context.c
>  create mode 100644 ui/gtk-gl-area.c
>
> --
> 1.8.3.1
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea)
  2015-09-11 14:44   ` Marc-André Lureau
@ 2015-09-14 13:50     ` Gerd Hoffmann
  0 siblings, 0 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-14 13:50 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU

On Fr, 2015-09-11 at 16:44 +0200, Marc-André Lureau wrote:
>  Hi
> 
> On Wed, Sep 9, 2015 at 1:20 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> > This allows virtio-gpu to render in 3d mode.
> > Uses native opengl support which is present
> > in gtk versions 3.16 and newer.
> >
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> After this patch, when starting qemu I get:
> 
> (qemu-system-x86_64:28264): Gtk-CRITICAL **: gtk_gl_area_make_current:
> assertion 'gtk_widget_get_realized (widget)' failed
> qemu-system-x86_64: Couldn't find current GLX or EGL context.

Can you set a breakpoint to gtk_gl_area_make_current and print a
stacktrace when qemu arrives there?  I suspect the caller will be
gd_gl_area_refresh, can you confirm?

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
@ 2015-09-14 16:00   ` Max Reitz
  2015-09-14 16:19     ` Max Reitz
  1 sibling, 1 reply; 33+ messages in thread
From: Max Reitz @ 2015-09-14 16:00 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5280 bytes --]

On 09.09.2015 13:20, Gerd Hoffmann wrote:
> Create a buffer for the vertex data and place vertexes
> there at initialization time.  Then just use the buffer
> for each texture blit.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/shader.h |  4 +++-
>  ui/console-gl.c     |  7 ++++++-
>  ui/shader.c         | 32 +++++++++++++++++++++++++++-----
>  3 files changed, 36 insertions(+), 7 deletions(-)
> 
> diff --git a/include/ui/shader.h b/include/ui/shader.h
> index 8509596..f7d8618 100644
> --- a/include/ui/shader.h
> +++ b/include/ui/shader.h
> @@ -3,7 +3,9 @@
>  
>  #include <epoxy/gl.h>
>  
> -void qemu_gl_run_texture_blit(GLint texture_blit_prog);
> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog);
> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
> +                              GLint texture_blit_vao);
>  
>  GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
>  GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
> diff --git a/ui/console-gl.c b/ui/console-gl.c
> index cb45cf8..baf397b 100644
> --- a/ui/console-gl.c
> +++ b/ui/console-gl.c
> @@ -33,6 +33,7 @@
>  
>  struct ConsoleGLState {
>      GLint texture_blit_prog;
> +    GLint texture_blit_vao;
>  };
>  
>  /* ---------------------------------------------------------------------- */
> @@ -47,6 +48,9 @@ ConsoleGLState *console_gl_init_context(void)
>          exit(1);
>      }
>  
> +    gls->texture_blit_vao =
> +        qemu_gl_init_texture_blit(gls->texture_blit_prog);
> +
>      return gls;
>  }
>  
> @@ -131,7 +135,8 @@ 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);
> +    qemu_gl_run_texture_blit(gls->texture_blit_prog,
> +                             gls->texture_blit_vao);
>  }
>  
>  void surface_gl_destroy_texture(ConsoleGLState *gls,
> diff --git a/ui/shader.c b/ui/shader.c
> index 52a4632..ada1c4c 100644
> --- a/ui/shader.c
> +++ b/ui/shader.c
> @@ -29,21 +29,43 @@
>  
>  /* ---------------------------------------------------------------------- */
>  
> -void qemu_gl_run_texture_blit(GLint texture_blit_prog)
> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
>  {
> -    GLfloat in_position[] = {
> +    static const GLfloat in_position[] = {
>          -1, -1,
>          1,  -1,
>          -1,  1,
>          1,   1,
>      };
>      GLint l_position;
> +    GLuint vao, buffer;
> +
> +    glGenVertexArrays(1, &vao);
> +    glBindVertexArray(vao);
> +
> +    /* this is the VBO that holds the vertex data */
> +    glGenBuffers(1, &buffer);
> +    glBindBuffer(GL_ARRAY_BUFFER, buffer);
> +    glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position,
> +                 GL_STATIC_DRAW);
>  
> -    glUseProgram(texture_blit_prog);
>      l_position = glGetAttribLocation(texture_blit_prog, "in_position");
> -    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position);
> +    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
>      glEnableVertexAttribArray(l_position);
> -    glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4);
> +
> +    glBindBuffer (GL_ARRAY_BUFFER, 0);
> +    glBindVertexArray (0);
> +    glDeleteBuffers (1, &buffer);

Although I may be wrong, I don't think glVertexAttribPointer() loads the
buffer data into the given vertex attribute.

As far as I can see from the specification regarding vertex array
objects, they only represent which data is to be used for vertex
attributes ("All state related to the definition of data used by the
vertex processor is encapsulated in a vertex array object.").

glVertexAttribPointer():
(1) determines the attribute's format,
(2) binds a vertex attribute index to a shader attribute index,
(3) binds the data to the vertex attribute.

Step (3) (glBindVertexBuffer()) does not appear to load the data, but
only define its origin ("The source of data for a generic vertex
attribute may be determined by attaching a buffer object to a vertex
array object with [glBindVertexBuffer()]").

Therefore, I'm not sure whether deleting the buffer is right here. Maybe
OpenGL uses reference counting here, too, so it remembers that the
buffer is still in use by the VAO, and so the glDeleteBuffers()
operation will only decrease its refcount, but not actually end up
deleting it. But I don't think so (compare the documentation of
glDeleteBuffers() with glDeleteShader(); the former says it will delete
the buffer, whereas the latter explicitly mentions that the shader will
not be deleted as long as it is attached to a program).

All in all I don't think we should delete the buffer as long as it is in
use by the VAO.

Max

> +
> +    return vao;
> +}
> +
> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
> +                              GLint texture_blit_vao)
> +{
> +    glUseProgram(texture_blit_prog);
> +    glBindVertexArray(texture_blit_vao);
> +    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
>  }
>  
>  /* ---------------------------------------------------------------------- */
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
@ 2015-09-14 16:16   ` Max Reitz
  1 sibling, 0 replies; 33+ messages in thread
From: Max Reitz @ 2015-09-14 16:16 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 223 bytes --]

On 09.09.2015 13:20, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  ui/sdl2-2d.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-14 16:00   ` Max Reitz
@ 2015-09-14 16:19     ` Max Reitz
  2015-09-15  7:10       ` Gerd Hoffmann
  0 siblings, 1 reply; 33+ messages in thread
From: Max Reitz @ 2015-09-14 16:19 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5662 bytes --]

On 14.09.2015 18:00, Max Reitz wrote:
> On 09.09.2015 13:20, Gerd Hoffmann wrote:
>> Create a buffer for the vertex data and place vertexes
>> there at initialization time.  Then just use the buffer
>> for each texture blit.
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>> ---
>>  include/ui/shader.h |  4 +++-
>>  ui/console-gl.c     |  7 ++++++-
>>  ui/shader.c         | 32 +++++++++++++++++++++++++++-----
>>  3 files changed, 36 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/ui/shader.h b/include/ui/shader.h
>> index 8509596..f7d8618 100644
>> --- a/include/ui/shader.h
>> +++ b/include/ui/shader.h
>> @@ -3,7 +3,9 @@
>>  
>>  #include <epoxy/gl.h>
>>  
>> -void qemu_gl_run_texture_blit(GLint texture_blit_prog);
>> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog);
>> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
>> +                              GLint texture_blit_vao);
>>  
>>  GLuint qemu_gl_create_compile_shader(GLenum type, const GLchar *src);
>>  GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag);
>> diff --git a/ui/console-gl.c b/ui/console-gl.c
>> index cb45cf8..baf397b 100644
>> --- a/ui/console-gl.c
>> +++ b/ui/console-gl.c
>> @@ -33,6 +33,7 @@
>>  
>>  struct ConsoleGLState {
>>      GLint texture_blit_prog;
>> +    GLint texture_blit_vao;
>>  };
>>  
>>  /* ---------------------------------------------------------------------- */
>> @@ -47,6 +48,9 @@ ConsoleGLState *console_gl_init_context(void)
>>          exit(1);
>>      }
>>  
>> +    gls->texture_blit_vao =
>> +        qemu_gl_init_texture_blit(gls->texture_blit_prog);
>> +
>>      return gls;
>>  }
>>  
>> @@ -131,7 +135,8 @@ 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);
>> +    qemu_gl_run_texture_blit(gls->texture_blit_prog,
>> +                             gls->texture_blit_vao);
>>  }
>>  
>>  void surface_gl_destroy_texture(ConsoleGLState *gls,
>> diff --git a/ui/shader.c b/ui/shader.c
>> index 52a4632..ada1c4c 100644
>> --- a/ui/shader.c
>> +++ b/ui/shader.c
>> @@ -29,21 +29,43 @@
>>  
>>  /* ---------------------------------------------------------------------- */
>>  
>> -void qemu_gl_run_texture_blit(GLint texture_blit_prog)
>> +GLuint qemu_gl_init_texture_blit(GLint texture_blit_prog)
>>  {
>> -    GLfloat in_position[] = {
>> +    static const GLfloat in_position[] = {
>>          -1, -1,
>>          1,  -1,
>>          -1,  1,
>>          1,   1,
>>      };
>>      GLint l_position;
>> +    GLuint vao, buffer;
>> +
>> +    glGenVertexArrays(1, &vao);
>> +    glBindVertexArray(vao);
>> +
>> +    /* this is the VBO that holds the vertex data */
>> +    glGenBuffers(1, &buffer);
>> +    glBindBuffer(GL_ARRAY_BUFFER, buffer);
>> +    glBufferData(GL_ARRAY_BUFFER, sizeof(in_position), in_position,
>> +                 GL_STATIC_DRAW);
>>  
>> -    glUseProgram(texture_blit_prog);
>>      l_position = glGetAttribLocation(texture_blit_prog, "in_position");
>> -    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, in_position);
>> +    glVertexAttribPointer(l_position, 2, GL_FLOAT, GL_FALSE, 0, 0);
>>      glEnableVertexAttribArray(l_position);
>> -    glDrawArrays(GL_TRIANGLE_STRIP, l_position, 4);
>> +
>> +    glBindBuffer (GL_ARRAY_BUFFER, 0);
>> +    glBindVertexArray (0);
>> +    glDeleteBuffers (1, &buffer);
> 
> Although I may be wrong, I don't think glVertexAttribPointer() loads the
> buffer data into the given vertex attribute.
> 
> As far as I can see from the specification regarding vertex array
> objects, they only represent which data is to be used for vertex
> attributes ("All state related to the definition of data used by the
> vertex processor is encapsulated in a vertex array object.").
> 
> glVertexAttribPointer():
> (1) determines the attribute's format,
> (2) binds a vertex attribute index to a shader attribute index,
> (3) binds the data to the vertex attribute.
> 
> Step (3) (glBindVertexBuffer()) does not appear to load the data, but
> only define its origin ("The source of data for a generic vertex
> attribute may be determined by attaching a buffer object to a vertex
> array object with [glBindVertexBuffer()]").
> 
> Therefore, I'm not sure whether deleting the buffer is right here. Maybe
> OpenGL uses reference counting here, too, so it remembers that the
> buffer is still in use by the VAO, and so the glDeleteBuffers()
> operation will only decrease its refcount, but not actually end up
> deleting it. But I don't think so (compare the documentation of
> glDeleteBuffers() with glDeleteShader(); the former says it will delete
> the buffer, whereas the latter explicitly mentions that the shader will
> not be deleted as long as it is attached to a program).
> 
> All in all I don't think we should delete the buffer as long as it is in
> use by the VAO.

Oh, and I just noticed: With glDeleteBuffers(), I get a segmentation
fault when qemu exits (somewhere deep in fglrx_dri.so). Without, the
segfault disappears.

Max

>> +
>> +    return vao;
>> +}
>> +
>> +void qemu_gl_run_texture_blit(GLint texture_blit_prog,
>> +                              GLint texture_blit_vao)
>> +{
>> +    glUseProgram(texture_blit_prog);
>> +    glBindVertexArray(texture_blit_vao);
>> +    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
>>  }
>>  
>>  /* ---------------------------------------------------------------------- */
>>
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support.
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support Gerd Hoffmann
@ 2015-09-14 18:14   ` Max Reitz
  2015-09-15  7:33     ` Gerd Hoffmann
  2015-09-15  8:33   ` Paolo Bonzini
  1 sibling, 1 reply; 33+ messages in thread
From: Max Reitz @ 2015-09-14 18:14 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel; +Cc: Michael S. Tsirkin

[-- Attachment #1: Type: text/plain, Size: 4381 bytes --]

On 09.09.2015 13:20, Gerd Hoffmann wrote:
> Add virglrenderer library detection.  Add 3d mode to virtio-gpu,
> wire up virglrenderer library.  When in 3d mode render using the
> new context management and texture scanout callbacks.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  configure                      |  32 +++
>  hw/display/Makefile.objs       |   6 +-
>  hw/display/virtio-gpu-3d.c     | 598 +++++++++++++++++++++++++++++++++++++++++
>  hw/display/virtio-gpu.c        | 130 ++++++++-
>  include/hw/virtio/virtio-gpu.h |  22 +-
>  trace-events                   |   8 +
>  6 files changed, 785 insertions(+), 11 deletions(-)
>  create mode 100644 hw/display/virtio-gpu-3d.c

As always when it comes to virtio-gpu, I'm just a very, very naive
reviewer, thus I only have "local" things to complain about.

[snip]

> diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
> new file mode 100644
> index 0000000..ac62fb4
> --- /dev/null
> +++ b/hw/display/virtio-gpu-3d.c
> @@ -0,0 +1,598 @@

[snip]

> +static void virgl_resource_detach_backing(VirtIOGPU *g,
> +                                          struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_resource_detach_backing detach_rb;
> +    struct iovec *res_iovs = NULL;
> +    int num_iovs = 0;
> +
> +    VIRTIO_GPU_FILL_CMD(detach_rb);
> +    trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
> +
> +    virgl_renderer_resource_detach_iov(detach_rb.resource_id,
> +                                       &res_iovs,
> +                                       &num_iovs);
> +    if (res_iovs == NULL || num_iovs == 0) {
> +        return;
> +    }
> +    virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);

Is res_iovs leaked here?

> +}

[snip]

> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index a67d927..4dbdd12 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c

[snip]

> @@ -45,6 +62,27 @@ static void update_cursor_data_simple(VirtIOGPU *g,
>             pixels * sizeof(uint32_t));
>  }
>  
> +#ifdef CONFIG_VIRGL
> +
> +static void update_cursor_data_virgl(VirtIOGPU *g,
> +                                     struct virtio_gpu_scanout *s,
> +                                     uint32_t resource_id)
> +{
> +    uint32_t width, height;
> +    uint32_t pixels, *data;
> +
> +    data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
> +    if (!data) {
> +        return;
> +    }
> +
> +    pixels = s->current_cursor->width * s->current_cursor->height;
> +    memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
> +    free(data);

width and height are unused; should they be compared against
s->current_cursor->{width,height} to spot discrepancies?

> +}
> +
> +#endif
> +
>  static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
>  {
>      struct virtio_gpu_scanout *s;

[snip]

> @@ -92,9 +131,23 @@ static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
>  static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
>                                          Error **errp)
>  {
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +
> +    if (virtio_gpu_virgl_enabled(g->conf)) {
> +        features |= (1 << VIRTIO_GPU_FEATURE_VIRGL);
> +    }
>      return features;
>  }
>  
> +static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
> +{
> +    static const uint32_t virgl = (1 << VIRTIO_GPU_FEATURE_VIRGL);
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +
> +    g->use_virgl_renderer = ((features & virgl) == virgl);

Could a non-well-behaving guest just set this feature bit even if it was
not reported by virtio_gpu_get_features() because it has been disabled?
This would then result in g->use_virgl_renderer being set to true, which
would have two implications:

(1) In case CONFIG_VIRGL is not defined, no implication right now. But
    maybe in the future there may be cases where the flag is queried
    even with !defined(CONFIG_VIRGL).
(2) virgl may be disabled even with CONFIG_VIRGL being defined; namely
    with HOST_WORDS_BIGENDIAN. That would probably be a problem, because
    we'd then call the virgl functions even though we meant not to.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support Gerd Hoffmann
@ 2015-09-14 18:49   ` Max Reitz
  2015-09-15  7:54     ` Gerd Hoffmann
  0 siblings, 1 reply; 33+ messages in thread
From: Max Reitz @ 2015-09-14 18:49 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 8170 bytes --]

On 09.09.2015 13:20, Gerd Hoffmann wrote:
> This allows virtio-gpu to render in 3d mode.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/ui/sdl2.h |  22 ++++++++-
>  ui/sdl2-gl.c      | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  ui/sdl2.c         |   7 +++
>  3 files changed, 161 insertions(+), 1 deletion(-)
> 
> diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
> index 2fdad8f..b397631 100644
> --- a/include/ui/sdl2.h
> +++ b/include/ui/sdl2.h
> @@ -15,12 +15,18 @@ struct sdl2_console {
>      SDL_Renderer *real_renderer;
>      int idx;
>      int last_vm_running; /* per console for caption reasons */
> -    int x, y;
> +    int x, y, w, h;
>      int hidden;
>      int opengl;
>      int updates;
>      SDL_GLContext winctx;
> +#ifdef CONFIG_OPENGL
>      ConsoleGLState *gls;
> +    GLuint tex_id;
> +    GLuint fbo_id;
> +    bool y0_top;
> +    bool scanout_mode;
> +#endif
>  };
>  
>  void sdl2_window_create(struct sdl2_console *scon);
> @@ -48,4 +54,18 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,
>  void sdl2_gl_refresh(DisplayChangeListener *dcl);
>  void sdl2_gl_redraw(struct sdl2_console *scon);
>  
> +qemu_gl_context sdl2_gl_create_context(DisplayChangeListener *dcl,
> +                                       struct qemu_gl_params *params);
> +void sdl2_gl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx);
> +int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
> +                                 qemu_gl_context ctx);
> +qemu_gl_context sdl2_gl_get_current_context(DisplayChangeListener *dcl);
> +
> +void sdl2_gl_scanout(DisplayChangeListener *dcl,
> +                     uint32_t backing_id, bool backing_y_0_top,
> +                     uint32_t x, uint32_t y,
> +                     uint32_t w, uint32_t h);
> +void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
> +                           uint32_t x, uint32_t y, uint32_t w, uint32_t h);
> +
>  #endif /* SDL2_H */
> diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
> index b604c06..bc73c0e 100644
> --- a/ui/sdl2-gl.c
> +++ b/ui/sdl2-gl.c
> @@ -31,11 +31,36 @@
>  #include "ui/sdl2.h"
>  #include "sysemu/sysemu.h"
>  
> +#include <epoxy/gl.h>
> +
> +static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout)
> +{
> +    if (scon->scanout_mode == scanout) {
> +        return;
> +    }
> +
> +    scon->scanout_mode = scanout;
> +    if (!scon->scanout_mode) {
> +        if (scon->fbo_id) {
> +            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
> +                                      GL_COLOR_ATTACHMENT0_EXT,
> +                                      GL_TEXTURE_2D, 0, 0);
> +            glDeleteFramebuffers(1, &scon->fbo_id);

I'm not sure, but maybe the framebuffer itself should be unbound here,
too? (i.e., glBindFramebuffer(GL_FRAMEBUFFER, 0))

I know it's deleted but I don't know whether that's enough.

> +            scon->fbo_id = 0;
> +        }
> +        if (scon->surface) {
> +            surface_gl_destroy_texture(scon->gls, scon->surface);
> +            surface_gl_create_texture(scon->gls, scon->surface);
> +        }
> +    }
> +}
> +
>  static void sdl2_gl_render_surface(struct sdl2_console *scon)
>  {
>      int ww, wh;
>  
>      SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
> +    sdl2_set_scanout_mode(scon, false);
>  
>      SDL_GetWindowSize(scon->real_window, &ww, &wh);
>      surface_gl_setup_viewport(scon->gls, scon->surface, ww, wh);
> @@ -110,3 +135,111 @@ void sdl2_gl_redraw(struct sdl2_console *scon)
>          sdl2_gl_render_surface(scon);
>      }
>  }
> +
> +qemu_gl_context sdl2_gl_create_context(DisplayChangeListener *dcl,
> +                                       struct qemu_gl_params *params)
> +{
> +    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
> +    SDL_GLContext ctx;
> +
> +    assert(scon->opengl);
> +
> +    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
> +
> +    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
> +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
> +                        SDL_GL_CONTEXT_PROFILE_CORE);
> +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, params->major_ver);
> +    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, params->minor_ver);
> +
> +    ctx = SDL_GL_CreateContext(scon->real_window);
> +    return (qemu_gl_context)ctx;
> +}
> +
> +void sdl2_gl_destroy_context(DisplayChangeListener *dcl, qemu_gl_context ctx)
> +{
> +    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
> +
> +    SDL_GL_DeleteContext(sdlctx);
> +}
> +
> +int sdl2_gl_make_context_current(DisplayChangeListener *dcl,
> +                                 qemu_gl_context ctx)
> +{
> +    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
> +    SDL_GLContext sdlctx = (SDL_GLContext)ctx;
> +
> +    assert(scon->opengl);
> +
> +    return SDL_GL_MakeCurrent(scon->real_window, sdlctx);
> +}
> +
> +qemu_gl_context sdl2_gl_get_current_context(DisplayChangeListener *dcl)
> +{
> +    SDL_GLContext sdlctx;
> +
> +    sdlctx = SDL_GL_GetCurrentContext();
> +    return (qemu_gl_context)sdlctx;
> +}
> +
> +void sdl2_gl_scanout(DisplayChangeListener *dcl,
> +                     uint32_t backing_id, bool backing_y_0_top,
> +                     uint32_t x, uint32_t y,
> +                     uint32_t w, uint32_t h)
> +{
> +    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
> +
> +    assert(scon->opengl);
> +    scon->x = x;
> +    scon->y = y;
> +    scon->w = w;
> +    scon->h = h;
> +    scon->tex_id = backing_id;
> +    scon->y0_top = backing_y_0_top;
> +
> +    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
> +
> +    if (scon->tex_id == 0 || scon->w == 0 || scon->h == 0) {
> +        sdl2_set_scanout_mode(scon, false);
> +        return;
> +    }
> +
> +    sdl2_set_scanout_mode(scon, true);
> +    if (!scon->fbo_id) {
> +        glGenFramebuffers(1, &scon->fbo_id);
> +    }
> +
> +    glBindFramebuffer(GL_FRAMEBUFFER_EXT, scon->fbo_id);
> +    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
> +                              GL_TEXTURE_2D, scon->tex_id, 0);
> +}
> +
> +void sdl2_gl_scanout_flush(DisplayChangeListener *dcl,
> +                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
> +{
> +    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
> +    int ww, wh, y1, y2;
> +
> +    assert(scon->opengl);
> +    if (!scon->scanout_mode) {
> +        return;
> +    }
> +    if (!scon->fbo_id) {
> +        return;
> +    }
> +
> +    SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
> +
> +    glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id);
> +    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
> +
> +    SDL_GetWindowSize(scon->real_window, &ww, &wh);
> +    glViewport(0, 0, ww, wh);
> +    y1 = scon->y0_top ? 0 : scon->h;
> +    y2 = scon->y0_top ? scon->h : 0;
> +    glBlitFramebuffer(0, y1, scon->w, y2,
> +                      0, 0, ww, wh,
> +                      GL_COLOR_BUFFER_BIT, GL_NEAREST);

Should we bind the FBO back to GL_DRAW_FRAMEBUFFER after the blit operation?

Max

> +
> +    SDL_GL_SwapWindow(scon->real_window);
> +}
> diff --git a/ui/sdl2.c b/ui/sdl2.c
> index 5cb75aa..73a84a8 100644
> --- a/ui/sdl2.c
> +++ b/ui/sdl2.c
> @@ -700,6 +700,13 @@ static const DisplayChangeListenerOps dcl_gl_ops = {
>      .dpy_refresh             = sdl2_gl_refresh,
>      .dpy_mouse_set           = sdl_mouse_warp,
>      .dpy_cursor_define       = sdl_mouse_define,
> +
> +    .dpy_gl_ctx_create       = sdl2_gl_create_context,
> +    .dpy_gl_ctx_destroy      = sdl2_gl_destroy_context,
> +    .dpy_gl_ctx_make_current = sdl2_gl_make_context_current,
> +    .dpy_gl_ctx_get_current  = sdl2_gl_get_current_context,
> +    .dpy_gl_scanout          = sdl2_gl_scanout,
> +    .dpy_gl_update           = sdl2_gl_scanout_flush,
>  };
>  #endif
>  
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once
  2015-09-14 16:19     ` Max Reitz
@ 2015-09-15  7:10       ` Gerd Hoffmann
  0 siblings, 0 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-15  7:10 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel

> > Therefore, I'm not sure whether deleting the buffer is right here. Maybe
> > OpenGL uses reference counting here, too, so it remembers that the
> > buffer is still in use by the VAO, and so the glDeleteBuffers()
> > operation will only decrease its refcount, but not actually end up
> > deleting it.

Hmm, my docs sayed it's refcounted and as long as the vao uses it
everything should be fine ...

> Oh, and I just noticed: With glDeleteBuffers(), I get a segmentation
> fault when qemu exits (somewhere deep in fglrx_dri.so). Without, the
> segfault disappears.

... but appearently it isn't.  Ok, dropping the glDeleteBuffers call.
It isn't freed anyway until qemu exits, so at the end of the day it
doesn't matter much.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support.
  2015-09-14 18:14   ` Max Reitz
@ 2015-09-15  7:33     ` Gerd Hoffmann
  0 siblings, 0 replies; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-15  7:33 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, Michael S. Tsirkin

  Hi,

> > +    virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);
> 
> Is res_iovs leaked here?

Oops, yes.  Moving the iov release to virtio_gpu_cleanup_mapping_iov (so
things is symmetrical to virtio_gpu_create_mapping_iov which allocates
it), that'll fix it.

> > +    pixels = s->current_cursor->width * s->current_cursor->height;
> > +    memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
> > +    free(data);
> 
> width and height are unused; should they be compared against
> s->current_cursor->{width,height} to spot discrepancies?

Added.

> > +static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
> > +{
> > +    static const uint32_t virgl = (1 << VIRTIO_GPU_FEATURE_VIRGL);
> > +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> > +
> > +    g->use_virgl_renderer = ((features & virgl) == virgl);
> 
> Could a non-well-behaving guest just set this feature bit even if it was
> not reported by virtio_gpu_get_features() because it has been disabled?

I'm pretty sure virtio core doesn't allow this.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support
  2015-09-14 18:49   ` Max Reitz
@ 2015-09-15  7:54     ` Gerd Hoffmann
  2015-09-16 13:44       ` Max Reitz
  0 siblings, 1 reply; 33+ messages in thread
From: Gerd Hoffmann @ 2015-09-15  7:54 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel

  Hi,

> > +    scon->scanout_mode = scanout;
> > +    if (!scon->scanout_mode) {
> > +        if (scon->fbo_id) {
> > +            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
> > +                                      GL_COLOR_ATTACHMENT0_EXT,
> > +                                      GL_TEXTURE_2D, 0, 0);
> > +            glDeleteFramebuffers(1, &scon->fbo_id);
> 
> I'm not sure, but maybe the framebuffer itself should be unbound here,
> too? (i.e., glBindFramebuffer(GL_FRAMEBUFFER, 0))
> 
> I know it's deleted but I don't know whether that's enough.

Fixed.

> > +    glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id);
> > +    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
> > +
> > +    SDL_GetWindowSize(scon->real_window, &ww, &wh);
> > +    glViewport(0, 0, ww, wh);
> > +    y1 = scon->y0_top ? 0 : scon->h;
> > +    y2 = scon->y0_top ? scon->h : 0;
> > +    glBlitFramebuffer(0, y1, scon->w, y2,
> > +                      0, 0, ww, wh,
> > +                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
> 
> Should we bind the FBO back to GL_DRAW_FRAMEBUFFER after the blit operation?

Isn't READ/DRAW used for framebuffer blits only?  Normal rendering goes
to GL_FRAMEBUFFER I think ...

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces.
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces Gerd Hoffmann
  2015-09-10 12:40   ` Marc-André Lureau
@ 2015-09-15  8:30   ` Paolo Bonzini
  1 sibling, 0 replies; 33+ messages in thread
From: Paolo Bonzini @ 2015-09-15  8:30 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel



On 09/09/2015 13:20, Gerd Hoffmann wrote:
> +typedef void *qemu_gl_context;
> +
> +struct qemu_gl_params {
> +    int major_ver;
> +    int minor_ver;
> +};
> +

Please use QEMUGLContext and QEMUGLParams (with a typedef for the latter).

Paolo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support.
  2015-09-09 11:20 ` [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support Gerd Hoffmann
  2015-09-14 18:14   ` Max Reitz
@ 2015-09-15  8:33   ` Paolo Bonzini
  1 sibling, 0 replies; 33+ messages in thread
From: Paolo Bonzini @ 2015-09-15  8:33 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel; +Cc: Michael S. Tsirkin



On 09/09/2015 13:20, Gerd Hoffmann wrote:
> + * This work is licensed under the terms of the GNU GPL, version 2.
> + * See the COPYING file in the top-level directory.
> + */

GPLv2-only contributions are not allowed anymore, please upgrade this
file and hw/display/virtio-gpu*.c to v2+.

Paolo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support
  2015-09-15  7:54     ` Gerd Hoffmann
@ 2015-09-16 13:44       ` Max Reitz
  0 siblings, 0 replies; 33+ messages in thread
From: Max Reitz @ 2015-09-16 13:44 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1587 bytes --]

On 15.09.2015 09:54, Gerd Hoffmann wrote:
>   Hi,
> 
>>> +    scon->scanout_mode = scanout;
>>> +    if (!scon->scanout_mode) {
>>> +        if (scon->fbo_id) {
>>> +            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
>>> +                                      GL_COLOR_ATTACHMENT0_EXT,
>>> +                                      GL_TEXTURE_2D, 0, 0);
>>> +            glDeleteFramebuffers(1, &scon->fbo_id);
>>
>> I'm not sure, but maybe the framebuffer itself should be unbound here,
>> too? (i.e., glBindFramebuffer(GL_FRAMEBUFFER, 0))
>>
>> I know it's deleted but I don't know whether that's enough.
> 
> Fixed.
> 
>>> +    glBindFramebuffer(GL_READ_FRAMEBUFFER, scon->fbo_id);
>>> +    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
>>> +
>>> +    SDL_GetWindowSize(scon->real_window, &ww, &wh);
>>> +    glViewport(0, 0, ww, wh);
>>> +    y1 = scon->y0_top ? 0 : scon->h;
>>> +    y2 = scon->y0_top ? scon->h : 0;
>>> +    glBlitFramebuffer(0, y1, scon->w, y2,
>>> +                      0, 0, ww, wh,
>>> +                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
>>
>> Should we bind the FBO back to GL_DRAW_FRAMEBUFFER after the blit operation?
> 
> Isn't READ/DRAW used for framebuffer blits only?  Normal rendering goes
> to GL_FRAMEBUFFER I think ...

http://docs.gl/gl4/glBindFramebuffer says: "Calling glBindFramebuffer
with target set to GL_FRAMEBUFFER binds framebuffer to both the read and
draw framebuffer targets.", so to me it looks like GL_FRAMEBUFFER is
just an alias for GL_{DRAW,READ}_FRAMEBUFFER at the same time.

Max


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2015-09-16 13:44 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-09 11:20 [Qemu-devel] [PATCH 0/9] add virgl rendering support Gerd Hoffmann
2015-09-09 11:20 ` [Qemu-devel] [PATCH 1/9] shaders: initialize vertexes once Gerd Hoffmann
2015-09-10 12:40   ` Marc-André Lureau
2015-09-10 13:22     ` Gerd Hoffmann
2015-09-10 13:42       ` Marc-André Lureau
2015-09-10 14:59         ` Gerd Hoffmann
2015-09-14 16:00   ` Max Reitz
2015-09-14 16:19     ` Max Reitz
2015-09-15  7:10       ` Gerd Hoffmann
2015-09-09 11:20 ` [Qemu-devel] [PATCH 2/9] sdl2: quick & dirty flicker workaround Gerd Hoffmann
2015-09-10 12:40   ` Marc-André Lureau
2015-09-14 16:16   ` Max Reitz
2015-09-09 11:20 ` [Qemu-devel] [PATCH 3/9] ui/console: add opengl context and scanout support interfaces Gerd Hoffmann
2015-09-10 12:40   ` Marc-André Lureau
2015-09-15  8:30   ` Paolo Bonzini
2015-09-09 11:20 ` [Qemu-devel] [PATCH 4/9] virtio-gpu: update headers for virgl/3d Gerd Hoffmann
2015-09-10 12:41   ` Marc-André Lureau
2015-09-09 11:20 ` [Qemu-devel] [PATCH 5/9] virtio-gpu: add 3d mode and virgl rendering support Gerd Hoffmann
2015-09-14 18:14   ` Max Reitz
2015-09-15  7:33     ` Gerd Hoffmann
2015-09-15  8:33   ` Paolo Bonzini
2015-09-09 11:20 ` [Qemu-devel] [PATCH 6/9] sdl2/opengl: add opengl context and scanout support Gerd Hoffmann
2015-09-14 18:49   ` Max Reitz
2015-09-15  7:54     ` Gerd Hoffmann
2015-09-16 13:44       ` Max Reitz
2015-09-09 11:20 ` [Qemu-devel] [PATCH 7/9] opengl: add egl-context.[ch] helpers Gerd Hoffmann
2015-09-11 14:13   ` Marc-André Lureau
2015-09-09 11:20 ` [Qemu-devel] [PATCH 8/9] gtk/opengl: add opengl context and scanout support (egl) Gerd Hoffmann
2015-09-11 14:36   ` Marc-André Lureau
2015-09-09 11:20 ` [Qemu-devel] [PATCH 9/9] gtk/opengl: add opengl context and scanout support (GtkGLArea) Gerd Hoffmann
2015-09-11 14:44   ` Marc-André Lureau
2015-09-14 13:50     ` Gerd Hoffmann
2015-09-11 16:10 ` [Qemu-devel] [PATCH 0/9] add virgl rendering support Marc-André Lureau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.