VIGS: Using asynchronous glReadPixels for display update 44/14844/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 9 Jan 2014 14:13:35 +0000 (18:13 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 13 Jan 2014 07:20:21 +0000 (11:20 +0400)
On somy GPUs like Intel HD Graphics 2000 glReadPixels is too
slow, so we use so called asynchronous version of
glReadPixels - it uses PBO for pixel storage and separate work
queue to read back results

Change-Id: I43f30daf57166a30cecf356fa2170da640de1ae3

hw/vigs/vigs_backend.h
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_gl_backend_agl.c
hw/vigs/vigs_gl_backend_glx.c
hw/vigs/vigs_gl_backend_wgl.c
hw/vigs/vigs_server.c
hw/vigs/vigs_surface.h
hw/vigs/vigs_sw_backend.c
tizen/src/hw/maru_board.c

index 1eb7bfa..c918c7d 100644 (file)
 struct winsys_info;
 struct vigs_surface;
 
+typedef void (*vigs_read_pixels_cb)(void */*user_data*/,
+                                    uint8_t */*pixels*/,
+                                    uint32_t /*width*/,
+                                    uint32_t /*height*/,
+                                    uint32_t /*stride*/,
+                                    vigsp_surface_format /*format*/);
+
 struct vigs_backend
 {
     struct winsys_info *ws_info;
@@ -48,6 +55,11 @@ struct vigs_backend
                                            vigsp_surface_format /*format*/,
                                            vigsp_surface_id /*id*/);
 
+    void (*read_pixels)(struct vigs_surface */*surface*/,
+                        uint8_t */*pixels*/,
+                        vigs_read_pixels_cb /*cb*/,
+                        void */*user_data*/);
+
     void (*batch_end)(struct vigs_backend */*backend*/);
 
     void (*destroy)(struct vigs_backend */*backend*/);
index dc50908..65ace1b 100644 (file)
 #include "vigs_utils.h"
 #include "vigs_ref.h"
 #include "winsys_gl.h"
+#include "work_queue.h"
 
 struct vigs_gl_surface;
 
+struct vigs_gl_backend_read_pixels_work_item
+{
+    struct work_queue_item base;
+
+    struct vigs_gl_backend *backend;
+
+    vigs_read_pixels_cb cb;
+    void *user_data;
+    uint8_t *pixels;
+    uint32_t width;
+    uint32_t height;
+    uint32_t stride;
+    vigsp_surface_format format;
+};
+
 struct vigs_winsys_gl_surface
 {
     struct winsys_gl_surface base;
@@ -334,10 +350,6 @@ static void vigs_gl_backend_batch_start(struct vigs_backend *backend)
  */
 
 static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
-                                        uint32_t x,
-                                        uint32_t y,
-                                        uint32_t width,
-                                        uint32_t height,
                                         uint8_t *pixels)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
@@ -347,9 +359,6 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
     GLfloat *vert_coords;
     GLfloat *tex_coords;
 
-    VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
-                   x, y, width, height);
-
     if (!ws_sfc->tex) {
         VIGS_LOG_TRACE("skipping blank read");
         goto out;
@@ -421,7 +430,7 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
     gl_backend->DisableClientState(GL_VERTEX_ARRAY);
 
     gl_backend->PixelStorei(GL_PACK_ALIGNMENT, ws_sfc->tex_bpp);
-    gl_backend->ReadPixels(x, y, width, height,
+    gl_backend->ReadPixels(0, 0, sfc_w, sfc_h,
                            ws_sfc->tex_format, ws_sfc->tex_type,
                            pixels);
 
@@ -824,6 +833,93 @@ fail:
     return NULL;
 }
 
+static void vigs_gl_backend_read_pixels_work(struct work_queue_item *wq_item)
+{
+    struct vigs_gl_backend_read_pixels_work_item *item = (struct vigs_gl_backend_read_pixels_work_item*)wq_item;
+    struct vigs_gl_backend *backend = item->backend;
+
+    VIGS_LOG_TRACE("enter");
+
+    if (backend->read_pixels_make_current(backend, true)) {
+        uint8_t *pixels;
+
+        backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, backend->pbo);
+
+        pixels = backend->MapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+
+        if (pixels) {
+            memcpy(item->pixels, pixels, item->stride * item->height);
+
+            if (!backend->UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB)) {
+                VIGS_LOG_CRITICAL("glUnmapBuffer failed");
+            }
+        } else {
+            VIGS_LOG_CRITICAL("glMapBuffer failed");
+        }
+
+        backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+        backend->read_pixels_make_current(backend, false);
+    }
+
+    item->cb(item->user_data,
+             item->pixels, item->width, item->height,
+             item->stride, item->format);
+
+    g_free(item);
+}
+
+static void vigs_gl_backend_read_pixels(struct vigs_surface *surface,
+                                        uint8_t *pixels,
+                                        vigs_read_pixels_cb cb,
+                                        void *user_data)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
+    uint32_t size = surface->stride * surface->ws_sfc->height;
+    struct vigs_gl_backend_read_pixels_work_item *item;
+
+    VIGS_LOG_TRACE("enter");
+
+    gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, gl_backend->pbo);
+
+    if (size > gl_backend->pbo_size) {
+        gl_backend->pbo_size = size;
+        gl_backend->BufferData(GL_PIXEL_PACK_BUFFER_ARB,
+                               size,
+                               0,
+                               GL_STREAM_READ);
+    }
+
+    surface->read_pixels(surface, NULL);
+
+    gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+    /*
+     * That's a tricky one, if we don't do this then it's not
+     * guaranteed that PBO will actually be updated by the time
+     * 'vigs_gl_backend_read_pixels_work' runs and since
+     * 'vigs_gl_backend_read_pixels_work' uses another OpenGL context
+     * we might get old results.
+     */
+    gl_backend->Finish();
+
+    item = g_malloc(sizeof(*item));
+
+    work_queue_item_init(&item->base, &vigs_gl_backend_read_pixels_work);
+
+    item->backend = gl_backend;
+
+    item->cb = cb;
+    item->user_data = user_data;
+    item->pixels = pixels;
+    item->width = surface->ws_sfc->width;
+    item->height = surface->ws_sfc->height;
+    item->stride = surface->stride;
+    item->format = surface->format;
+
+    work_queue_add_item(gl_backend->read_pixels_queue, &item->base);
+}
+
 static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
@@ -857,8 +953,16 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
         goto fail;
     }
 
+    gl_backend->GenBuffers(1, &gl_backend->pbo);
+
+    if (!gl_backend->pbo) {
+        VIGS_LOG_CRITICAL("cannot create read_pixels PBO");
+        goto fail;
+    }
+
     gl_backend->base.batch_start = &vigs_gl_backend_batch_start;
     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
+    gl_backend->base.read_pixels = &vigs_gl_backend_read_pixels;
     gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
 
     gl_backend->make_current(gl_backend, false);
@@ -866,6 +970,8 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     vigs_vector_init(&gl_backend->v1, 0);
     vigs_vector_init(&gl_backend->v2, 0);
 
+    gl_backend->read_pixels_queue = work_queue_create();
+
     return true;
 
 fail:
@@ -876,6 +982,14 @@ fail:
 
 void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
 {
+    work_queue_destroy(gl_backend->read_pixels_queue);
+
+    if (gl_backend->make_current(gl_backend, true)) {
+        gl_backend->DeleteBuffers(1, &gl_backend->pbo);
+
+        gl_backend->make_current(gl_backend, false);
+    }
+
     vigs_vector_cleanup(&gl_backend->v2);
     vigs_vector_cleanup(&gl_backend->v1);
 }
index 5b6a8eb..223aa02 100644 (file)
@@ -37,6 +37,8 @@
 #include <GL/glext.h>
 #include "winsys_gl.h"
 
+struct work_queue;
+
 struct vigs_gl_backend
 {
     struct vigs_backend base;
@@ -48,6 +50,9 @@ struct vigs_gl_backend
     bool (*make_current)(struct vigs_gl_backend */*gl_backend*/,
                          bool /*enable*/);
 
+    bool (*read_pixels_make_current)(struct vigs_gl_backend */*gl_backend*/,
+                                     bool /*enable*/);
+
     /*
      * Mandatory GL functions and extensions.
      * @{
@@ -105,6 +110,12 @@ struct vigs_gl_backend
     void (GLAPIENTRY *BlendFunc)(GLenum sfactor, GLenum dfactor);
     void (GLAPIENTRY *CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
     void (GLAPIENTRY *BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+    void (GLAPIENTRY *GenBuffers)(GLsizei n, GLuint *buffers);
+    void (GLAPIENTRY *DeleteBuffers)(GLsizei n, const GLuint *buffers);
+    void (GLAPIENTRY *BindBuffer)(GLenum target, GLuint buffer);
+    void (GLAPIENTRY *BufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+    GLvoid *(GLAPIENTRY *MapBuffer)(GLenum target, GLenum access);
+    GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum target);
 
     /*
      * @}
@@ -121,6 +132,15 @@ struct vigs_gl_backend
     /*
      * @}
      */
+
+    /*
+     *
+     */
+
+    struct work_queue *read_pixels_queue;
+
+    GLuint pbo;
+    uint32_t pbo_size;
 };
 
 bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend);
index c92f946..ba5c04a 100644 (file)
@@ -50,6 +50,8 @@ struct vigs_gl_backend_agl {
     struct vigs_gl_backend base;
 
     void *handle;
+    AGLContext read_pixels_context;
+    AGLPbuffer read_pixels_surface;
     AGLContext context;
     AGLPbuffer surface;
     AGLPixelFormat pixfmt;
@@ -86,14 +88,13 @@ static int vigs_gl_backend_agl_choose_config(struct vigs_gl_backend_agl
 }
 
 static bool vigs_gl_backend_agl_create_surface(struct vigs_gl_backend_agl
-                                               *gl_backend_agl, int config_id)
+                                               *gl_backend_agl, int config_id,
+                                               AGLPbuffer *surface)
 {
-    gl_backend_agl->surface = NULL;
+    aglCreatePBuffer(1, 1, GL_TEXTURE_2D, GL_RGBA, 0,
+                     surface);
 
-    aglCreatePBuffer(2048, 2048, GL_TEXTURE_2D, GL_RGBA, 0,
-                     &gl_backend_agl->surface);
-
-    if (!gl_backend_agl->surface) {
+    if (!*surface) {
         VIGS_LOG_CRITICAL("aglCreatePBuffer failed");
         return false;
     }
@@ -102,11 +103,13 @@ static bool vigs_gl_backend_agl_create_surface(struct vigs_gl_backend_agl
 }
 
 static bool vigs_gl_backend_agl_create_context(struct vigs_gl_backend_agl
-                                               *gl_backend_agl)
+                                               *gl_backend_agl,
+                                               AGLContext share_context,
+                                               AGLContext *context)
 {
-    gl_backend_agl->context = aglCreateContext(gl_backend_agl->pixfmt, NULL);
+    *context = aglCreateContext(gl_backend_agl->pixfmt, share_context);
 
-    if (!gl_backend_agl->context) {
+    if (!*context) {
         VIGS_LOG_CRITICAL("aglCreateContext failed");
         return false;
     }
@@ -125,10 +128,18 @@ static void vigs_gl_backend_agl_destroy(struct vigs_backend *backend)
         aglDestroyPBuffer(gl_backend_agl->surface);
     }
 
+    if (gl_backend_agl->read_pixels_surface) {
+        aglDestroyPBuffer(gl_backend_agl->read_pixels_surface);
+    }
+
     if (gl_backend_agl->context) {
         aglDestroyContext(gl_backend_agl->context);
     }
 
+    if (gl_backend_agl->read_pixels_context) {
+        aglDestroyContext(gl_backend_agl->read_pixels_context);
+    }
+
     if (gl_backend_agl->handle) {
         dlclose(gl_backend_agl->handle);
     }
@@ -181,6 +192,37 @@ static bool vigs_gl_backend_agl_make_current(struct vigs_gl_backend *gl_backend,
     return true;
 }
 
+static bool vigs_gl_backend_agl_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
+                                                         bool enable)
+{
+    struct vigs_gl_backend_agl *gl_backend_agl =
+        (struct vigs_gl_backend_agl *)gl_backend;
+    AGLPbuffer buf = NULL;
+    AGLContext context = gl_backend_agl->read_pixels_context;
+
+    if (enable) {
+        buf = gl_backend_agl->read_pixels_surface;
+
+        if (aglSetPBuffer(context, buf, 0, 0, 0) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetPBuffer failed");
+            return false;
+        }
+
+        if (aglSetCurrentContext(context) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetCurrentContext failed");
+            aglSetPBuffer(context, NULL, 0, 0, 0);
+            return false;
+        }
+    } else {
+        if (aglSetCurrentContext(NULL) == GL_FALSE) {
+            VIGS_LOG_CRITICAL("aglSetCurrentContext(NULL) failed");
+            return false;
+        }
+    }
+
+    return true;
+}
+
 struct vigs_backend *vigs_gl_backend_create(void *display)
 {
     struct vigs_gl_backend_agl *gl_backend_agl;
@@ -245,6 +287,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
     VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
     VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+    VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+    VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+    VIGS_GL_GET_PROC(BufferData, glBufferData);
+    VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+    VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
 
     config_id = vigs_gl_backend_agl_choose_config(gl_backend_agl);
 
@@ -252,17 +300,30 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         goto fail;
     }
 
-    if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id)) {
+    if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id,
+                                            &gl_backend_agl->surface)) {
         goto fail;
     }
 
-    if (!vigs_gl_backend_agl_create_context(gl_backend_agl)) {
+    if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id,
+                                            &gl_backend_agl->read_pixels_surface)) {
+        goto fail;
+    }
+
+    if (!vigs_gl_backend_agl_create_context(gl_backend_agl, NULL,
+                                            &gl_backend_agl->context)) {
+        goto fail;
+    }
+
+    if (!vigs_gl_backend_agl_create_context(gl_backend_agl, gl_backend_agl->context,
+                                            &gl_backend_agl->read_pixels_context)) {
         goto fail;
     }
 
     gl_backend_agl->base.base.destroy = &vigs_gl_backend_agl_destroy;
     gl_backend_agl->base.has_current = &vigs_gl_backend_agl_has_current;
     gl_backend_agl->base.make_current = &vigs_gl_backend_agl_make_current;
+    gl_backend_agl->base.read_pixels_make_current = &vigs_gl_backend_agl_read_pixels_make_current;
     gl_backend_agl->base.ws_info.context = &gl_backend_agl->context;
 
     if (!vigs_gl_backend_init(&gl_backend_agl->base)) {
@@ -283,10 +344,18 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         aglDestroyPBuffer(gl_backend_agl->surface);
     }
 
+    if (gl_backend_agl->read_pixels_surface) {
+        aglDestroyPBuffer(gl_backend_agl->read_pixels_surface);
+    }
+
     if (gl_backend_agl->context) {
         aglDestroyContext(gl_backend_agl->context);
     }
 
+    if (gl_backend_agl->read_pixels_context) {
+        aglDestroyContext(gl_backend_agl->read_pixels_context);
+    }
+
     vigs_backend_cleanup(&gl_backend_agl->base.base);
 
     g_free(gl_backend_agl);
index 6b913b0..372ec52 100644 (file)
@@ -89,6 +89,8 @@ struct vigs_gl_backend_glx
     Display *dpy;
     GLXPbuffer sfc;
     GLXContext ctx;
+    GLXPbuffer read_pixels_sfc;
+    GLXContext read_pixels_ctx;
 };
 
 static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl_backend_glx)
@@ -145,7 +147,8 @@ static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl
 }
 
 static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_backend_glx,
-                                               GLXFBConfig config)
+                                               GLXFBConfig config,
+                                               GLXPbuffer *sfc)
 {
     int surface_attribs[] =
     {
@@ -155,11 +158,11 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba
         None
     };
 
-    gl_backend_glx->sfc = gl_backend_glx->glXCreatePbuffer(gl_backend_glx->dpy,
-                                                           config,
-                                                           surface_attribs);
+    *sfc = gl_backend_glx->glXCreatePbuffer(gl_backend_glx->dpy,
+                                            config,
+                                            surface_attribs);
 
-    if (!gl_backend_glx->sfc) {
+    if (!*sfc) {
         VIGS_LOG_CRITICAL("glXCreatePbuffer failed");
         return false;
     }
@@ -168,15 +171,17 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba
 }
 
 static bool vigs_gl_backend_glx_create_context(struct vigs_gl_backend_glx *gl_backend_glx,
-                                               GLXFBConfig config)
+                                               GLXFBConfig config,
+                                               GLXContext share_ctx,
+                                               GLXContext *ctx)
 {
-    gl_backend_glx->ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy,
-                                                              config,
-                                                              GLX_RGBA_TYPE,
-                                                              NULL,
-                                                              True);
+    *ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy,
+                                               config,
+                                               GLX_RGBA_TYPE,
+                                               share_ctx,
+                                               True);
 
-    if (!gl_backend_glx->ctx) {
+    if (!*ctx) {
         VIGS_LOG_CRITICAL("glXCreateNewContext failed");
         return false;
     }
@@ -212,6 +217,26 @@ static bool vigs_gl_backend_glx_make_current(struct vigs_gl_backend *gl_backend,
     return true;
 }
 
+static bool vigs_gl_backend_glx_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
+                                                         bool enable)
+{
+    struct vigs_gl_backend_glx *gl_backend_glx =
+        (struct vigs_gl_backend_glx*)gl_backend;
+    Bool ret;
+
+    ret = gl_backend_glx->glXMakeContextCurrent(gl_backend_glx->dpy,
+                                                (enable ? gl_backend_glx->read_pixels_sfc : None),
+                                                (enable ? gl_backend_glx->read_pixels_sfc : None),
+                                                (enable ? gl_backend_glx->read_pixels_ctx : NULL));
+
+    if (!ret) {
+        VIGS_LOG_CRITICAL("glXMakeContextCurrent failed");
+        return false;
+    }
+
+    return true;
+}
+
 static void vigs_gl_backend_glx_destroy(struct vigs_backend *backend)
 {
     struct vigs_gl_backend_glx *gl_backend_glx = (struct vigs_gl_backend_glx*)backend;
@@ -219,9 +244,15 @@ static void vigs_gl_backend_glx_destroy(struct vigs_backend *backend)
     vigs_gl_backend_cleanup(&gl_backend_glx->base);
 
     gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                      gl_backend_glx->read_pixels_ctx);
+
+    gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
                                       gl_backend_glx->ctx);
 
     gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+                                      gl_backend_glx->read_pixels_sfc);
+
+    gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
                                       gl_backend_glx->sfc);
 
     dlclose(gl_backend_glx->handle);
@@ -325,6 +356,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
     VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
     VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+    VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+    VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+    VIGS_GL_GET_PROC(BufferData, glBufferData);
+    VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+    VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
 
     gl_backend_glx->dpy = x_display;
 
@@ -334,30 +371,55 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         goto fail2;
     }
 
-    if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, config)) {
+    if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
+                                            config,
+                                            &gl_backend_glx->sfc)) {
         goto fail2;
     }
 
-    if (!vigs_gl_backend_glx_create_context(gl_backend_glx, config)) {
+    if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
+                                            config,
+                                            &gl_backend_glx->read_pixels_sfc)) {
         goto fail3;
     }
 
+    if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+                                            config,
+                                            NULL,
+                                            &gl_backend_glx->ctx)) {
+        goto fail4;
+    }
+
+    if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+                                            config,
+                                            gl_backend_glx->ctx,
+                                            &gl_backend_glx->read_pixels_ctx)) {
+        goto fail5;
+    }
+
     gl_backend_glx->base.base.destroy = &vigs_gl_backend_glx_destroy;
     gl_backend_glx->base.has_current = &vigs_gl_backend_glx_has_current;
     gl_backend_glx->base.make_current = &vigs_gl_backend_glx_make_current;
+    gl_backend_glx->base.read_pixels_make_current = &vigs_gl_backend_glx_read_pixels_make_current;
     gl_backend_glx->base.ws_info.context = gl_backend_glx->ctx;
 
     if (!vigs_gl_backend_init(&gl_backend_glx->base)) {
-        goto fail4;
+        goto fail6;
     }
 
     VIGS_LOG_DEBUG("created");
 
     return &gl_backend_glx->base.base;
 
-fail4:
+fail6:
+    gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                      gl_backend_glx->read_pixels_ctx);
+fail5:
     gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
                                       gl_backend_glx->ctx);
+fail4:
+    gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+                                      gl_backend_glx->read_pixels_sfc);
 fail3:
     gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
                                       gl_backend_glx->sfc);
index 72b94ab..101c376 100644 (file)
@@ -98,6 +98,7 @@ struct vigs_gl_backend_wgl
     PFNWGLGETPROCADDRESSPROC wglGetProcAddress;
     PFNWGLMAKECURRENTPROC wglMakeCurrent;
     PFNWGLGETCURRENTCONTEXTPROC wglGetCurrentContext;
+    PFNWGLSHARELISTSPROC wglShareLists;
 
     /* WGL extensions */
     PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT;
@@ -113,6 +114,9 @@ struct vigs_gl_backend_wgl
     HPBUFFERARB sfc;
     HDC sfc_dc;
     HGLRC ctx;
+    HPBUFFERARB read_pixels_sfc;
+    HDC read_pixels_sfc_dc;
+    HGLRC read_pixels_ctx;
 };
 
 static int vigs_gl_backend_wgl_choose_config(struct vigs_gl_backend_wgl *gl_backend_wgl)
@@ -162,7 +166,9 @@ static int vigs_gl_backend_wgl_choose_config(struct vigs_gl_backend_wgl *gl_back
 }
 
 static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_backend_wgl,
-                                               int config_id)
+                                               int config_id,
+                                               HPBUFFERARB *sfc,
+                                               HDC *sfc_dc)
 {
     int surface_attribs[] = {
         WGL_PBUFFER_LARGEST_ARB, FALSE,
@@ -171,18 +177,17 @@ static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_ba
         0
     };
 
-    gl_backend_wgl->sfc =
-        gl_backend_wgl->wglCreatePbufferARB(gl_backend_wgl->dc, config_id,
-                                            1, 1, surface_attribs);
+    *sfc = gl_backend_wgl->wglCreatePbufferARB(gl_backend_wgl->dc, config_id,
+                                               1, 1, surface_attribs);
 
-    if (!gl_backend_wgl->sfc) {
+    if (!*sfc) {
         VIGS_LOG_CRITICAL("wglCreatePbufferARB failed");
         return false;
     }
 
-    gl_backend_wgl->sfc_dc = gl_backend_wgl->wglGetPbufferDCARB(gl_backend_wgl->sfc);
+    *sfc_dc = gl_backend_wgl->wglGetPbufferDCARB(*sfc);
 
-    if (!gl_backend_wgl->sfc_dc) {
+    if (!*sfc_dc) {
         VIGS_LOG_CRITICAL("wglGetPbufferDCARB failed");
         return false;
     }
@@ -190,15 +195,26 @@ static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_ba
     return true;
 }
 
-static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_backend_wgl)
+static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_backend_wgl,
+                                               HGLRC share_ctx,
+                                               HGLRC *ctx)
 {
-    gl_backend_wgl->ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc);
+    *ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc);
 
-    if (!gl_backend_wgl->ctx) {
+    if (!*ctx) {
         VIGS_LOG_CRITICAL("wglCreateContext failed");
         return false;
     }
 
+    if (share_ctx) {
+        if (!gl_backend_wgl->wglShareLists(share_ctx, *ctx)) {
+            VIGS_LOG_CRITICAL("wglShareLists failed");
+            gl_backend_wgl->wglDeleteContext(*ctx);
+            *ctx = NULL;
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -231,6 +247,27 @@ static bool vigs_gl_backend_wgl_make_current(struct vigs_gl_backend *gl_backend,
     return true;
 }
 
+static bool vigs_gl_backend_wgl_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
+                                                         bool enable)
+{
+    struct vigs_gl_backend_wgl *gl_backend_wgl =
+        (struct vigs_gl_backend_wgl*)gl_backend;
+
+    if (enable) {
+        if (!gl_backend_wgl->wglMakeCurrent(gl_backend_wgl->read_pixels_sfc_dc, gl_backend_wgl->read_pixels_ctx)) {
+            VIGS_LOG_CRITICAL("wglMakeCurrent failed");
+            return false;
+        }
+    } else {
+        if (!gl_backend_wgl->wglMakeCurrent(NULL, NULL)) {
+            VIGS_LOG_CRITICAL("wglMakeCurrent failed");
+            return false;
+        }
+    }
+
+    return true;
+}
+
 static void vigs_gl_backend_wgl_destroy(struct vigs_backend *backend)
 {
     struct vigs_gl_backend_wgl *gl_backend_wgl = (struct vigs_gl_backend_wgl*)backend;
@@ -238,8 +275,11 @@ static void vigs_gl_backend_wgl_destroy(struct vigs_backend *backend)
     vigs_gl_backend_cleanup(&gl_backend_wgl->base);
 
     gl_backend_wgl->wglDeleteContext(gl_backend_wgl->ctx);
+    gl_backend_wgl->wglDeleteContext(gl_backend_wgl->read_pixels_ctx);
     gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->sfc, gl_backend_wgl->sfc_dc);
     gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->sfc);
+    gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->read_pixels_sfc, gl_backend_wgl->read_pixels_sfc_dc);
+    gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->read_pixels_sfc);
 
     ReleaseDC(gl_backend_wgl->win, gl_backend_wgl->dc);
     DestroyWindow(gl_backend_wgl->win);
@@ -310,6 +350,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_WGL_GET_PROC(PFNWGLGETPROCADDRESSPROC, wglGetProcAddress, fail);
     VIGS_WGL_GET_PROC(PFNWGLMAKECURRENTPROC, wglMakeCurrent, fail);
     VIGS_WGL_GET_PROC(PFNWGLGETCURRENTCONTEXTPROC, wglGetCurrentContext, fail);
+    VIGS_WGL_GET_PROC(PFNWGLSHARELISTSPROC, wglShareLists, fail);
 
     tmp_win = CreateWindow(VIGS_WGL_WIN_CLASS, "VIGSWin",
                            WS_DISABLED | WS_POPUP,
@@ -429,6 +470,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
     VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
     VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+    VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+    VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+    VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+    VIGS_GL_GET_PROC(BufferData, glBufferData);
+    VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+    VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
 
     gl_backend_wgl->wglMakeCurrent(NULL, NULL);
     gl_backend_wgl->wglDeleteContext(tmp_ctx);
@@ -460,17 +507,34 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         goto fail;
     }
 
-    if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id)) {
+    if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
+                                            &gl_backend_wgl->sfc,
+                                            &gl_backend_wgl->sfc_dc)) {
         goto fail;
     }
 
-    if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl)) {
+    if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
+                                            &gl_backend_wgl->read_pixels_sfc,
+                                            &gl_backend_wgl->read_pixels_sfc_dc)) {
+        goto fail;
+    }
+
+    if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
+                                            NULL,
+                                            &gl_backend_wgl->ctx)) {
+        goto fail;
+    }
+
+    if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
+                                            gl_backend_wgl->ctx,
+                                            &gl_backend_wgl->read_pixels_ctx)) {
         goto fail;
     }
 
     gl_backend_wgl->base.base.destroy = &vigs_gl_backend_wgl_destroy;
     gl_backend_wgl->base.has_current = &vigs_gl_backend_wgl_has_current;
     gl_backend_wgl->base.make_current = &vigs_gl_backend_wgl_make_current;
+    gl_backend_wgl->base.read_pixels_make_current = &vigs_gl_backend_wgl_read_pixels_make_current;
     gl_backend_wgl->base.ws_info.context = gl_backend_wgl->ctx;
 
     if (!vigs_gl_backend_init(&gl_backend_wgl->base)) {
@@ -485,12 +549,21 @@ fail:
     if (gl_backend_wgl->ctx) {
         gl_backend_wgl->wglDeleteContext(gl_backend_wgl->ctx);
     }
+    if (gl_backend_wgl->read_pixels_ctx) {
+        gl_backend_wgl->wglDeleteContext(gl_backend_wgl->read_pixels_ctx);
+    }
     if (gl_backend_wgl->sfc_dc) {
         gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->sfc, gl_backend_wgl->sfc_dc);
     }
     if (gl_backend_wgl->sfc) {
         gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->sfc);
     }
+    if (gl_backend_wgl->read_pixels_sfc_dc) {
+        gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->read_pixels_sfc, gl_backend_wgl->read_pixels_sfc_dc);
+    }
+    if (gl_backend_wgl->read_pixels_sfc) {
+        gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->read_pixels_sfc);
+    }
     if (gl_backend_wgl->dc) {
         ReleaseDC(gl_backend_wgl->win, gl_backend_wgl->dc);
     }
index 983f30c..7438c21 100644 (file)
@@ -192,10 +192,6 @@ static void vigs_server_dispatch_update_vram(void *user_data,
     }
 
     vigs_sfc->read_pixels(vigs_sfc,
-                          0,
-                          0,
-                          vigs_sfc->ws_sfc->width,
-                          vigs_sfc->ws_sfc->height,
                           server->vram_ptr + offset);
 
     vigs_sfc->is_dirty = false;
@@ -365,49 +361,35 @@ out:
     g_free(item);
 }
 
-static void vigs_server_update_display_work(struct work_queue_item *wq_item)
+static void vigs_server_update_display_cb(void *user_data,
+                                          uint8_t *pixels,
+                                          uint32_t width,
+                                          uint32_t height,
+                                          uint32_t stride,
+                                          vigsp_surface_format format)
 {
-    struct vigs_server_work_item *item = (struct vigs_server_work_item*)wq_item;
-    struct vigs_server *server = item->server;
-    struct vigs_surface *root_sfc = server->root_sfc;
+    struct vigs_server *server = user_data;
     uint32_t capture_fence_seq;
 
-    if (!root_sfc) {
-        qemu_mutex_lock(&server->capture_mutex);
-        goto out;
-    }
-
-    if (root_sfc->is_dirty) {
-        server->backend->batch_start(server->backend);
-        root_sfc->read_pixels(root_sfc,
-                              0,
-                              0,
-                              root_sfc->ws_sfc->width,
-                              root_sfc->ws_sfc->height,
-                              server->root_sfc_ptr);
-        server->backend->batch_end(server->backend);
-        root_sfc->is_dirty = false;
-    }
-
     qemu_mutex_lock(&server->capture_mutex);
 
-    if ((server->captured.stride != root_sfc->stride) ||
-        (server->captured.height != root_sfc->ws_sfc->height)) {
-        g_free(server->captured.data);
-        server->captured.data = g_malloc(root_sfc->stride *
-                                         root_sfc->ws_sfc->height);
-    }
+    if (pixels) {
+        if ((server->captured.stride != stride) ||
+            (server->captured.height != height)) {
+            g_free(server->captured.data);
+            server->captured.data = g_malloc(stride * height);
+        }
 
-    memcpy(server->captured.data,
-           server->root_sfc_ptr,
-           root_sfc->stride * root_sfc->ws_sfc->height);
+        memcpy(server->captured.data,
+               pixels,
+               stride * height);
 
-    server->captured.width = root_sfc->ws_sfc->width;
-    server->captured.height = root_sfc->ws_sfc->height;
-    server->captured.stride = root_sfc->stride;
-    server->captured.format = root_sfc->format;
+        server->captured.width = width;
+        server->captured.height = height;
+        server->captured.stride = stride;
+        server->captured.format = format;
+    }
 
-out:
     server->is_capturing = false;
     capture_fence_seq = server->capture_fence_seq;
     server->capture_fence_seq = 0;
@@ -418,7 +400,42 @@ out:
         server->display_ops->fence_ack(server->display_user_data,
                                        capture_fence_seq);
     }
+}
+
+static void vigs_server_update_display_work(struct work_queue_item *wq_item)
+{
+    struct vigs_server_work_item *item = (struct vigs_server_work_item*)wq_item;
+    struct vigs_server *server = item->server;
+    struct vigs_surface *root_sfc = server->root_sfc;
 
+    if (!root_sfc) {
+        vigs_server_update_display_cb(server,
+                                      NULL,
+                                      0,
+                                      0,
+                                      0,
+                                      vigsp_surface_bgrx8888);
+        goto out;
+    }
+
+    if (root_sfc->is_dirty) {
+        root_sfc->is_dirty = false;
+        server->backend->batch_start(server->backend);
+        server->backend->read_pixels(root_sfc,
+                                     server->root_sfc_ptr,
+                                     &vigs_server_update_display_cb,
+                                     server);
+        server->backend->batch_end(server->backend);
+    } else {
+        vigs_server_update_display_cb(server,
+                                      server->root_sfc_ptr,
+                                      root_sfc->ws_sfc->width,
+                                      root_sfc->ws_sfc->height,
+                                      root_sfc->stride,
+                                      root_sfc->format);
+    }
+
+out:
     g_free(item);
 }
 
index 06af7d3..95daa92 100644 (file)
@@ -48,10 +48,6 @@ struct vigs_surface
     bool is_dirty;
 
     void (*read_pixels)(struct vigs_surface */*sfc*/,
-                        uint32_t /*x*/,
-                        uint32_t /*y*/,
-                        uint32_t /*width*/,
-                        uint32_t /*height*/,
                         uint8_t */*pixels*/);
 
     void (*draw_pixels)(struct vigs_surface */*sfc*/,
index b1e96c4..4489e7d 100644 (file)
@@ -112,35 +112,11 @@ static void vigs_sw_backend_batch_start(struct vigs_backend *backend)
  */
 
 static void vigs_sw_surface_read_pixels(struct vigs_surface *sfc,
-                                        uint32_t x,
-                                        uint32_t y,
-                                        uint32_t width,
-                                        uint32_t height,
                                         uint8_t *pixels)
 {
     struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)sfc;
-    uint32_t bpp = vigs_format_bpp(sfc->format);
-    uint32_t row_length = width * bpp;
-    const uint8_t *src;
-    uint8_t *dest;
-    uint32_t i;
-
-    VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
-                   x, y, width, height);
-
-    src = sw_sfc->data + y * sfc->stride + x * bpp;
-    dest = pixels + y * sfc->stride + x * bpp;
 
-    if (width == sfc->ws_sfc->width) {
-        row_length = sfc->stride * height;
-        height = 1;
-    }
-
-    for (i = 0; i < height; ++i) {
-        memcpy(dest, src, row_length);
-        src += sfc->stride;
-        dest += sfc->stride;
-    }
+    memcpy(pixels, sw_sfc->data, sfc->stride * sfc->ws_sfc->height);
 }
 
 static void vigs_sw_surface_draw_pixels(struct vigs_surface *sfc,
@@ -334,6 +310,17 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend *
     return &sw_sfc->base;
 }
 
+static void vigs_sw_backend_read_pixels(struct vigs_surface *surface,
+                                        uint8_t *pixels,
+                                        vigs_read_pixels_cb cb,
+                                        void *user_data)
+{
+    surface->read_pixels(surface, pixels);
+
+    cb(user_data, pixels, surface->ws_sfc->width, surface->ws_sfc->height,
+       surface->stride, surface->format);
+}
+
 static void vigs_sw_backend_batch_end(struct vigs_backend *backend)
 {
 }
@@ -354,6 +341,7 @@ struct vigs_backend *vigs_sw_backend_create(void)
 
     backend->batch_start = &vigs_sw_backend_batch_start;
     backend->create_surface = &vigs_sw_backend_create_surface;
+    backend->read_pixels = &vigs_sw_backend_read_pixels;
     backend->batch_end = &vigs_sw_backend_batch_end;
     backend->destroy = &vigs_sw_backend_destroy;
 
index 069f70a..d37d951 100644 (file)
@@ -106,6 +106,7 @@ static void maru_device_init(void)
     PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
 
 #if defined(CONFIG_LINUX)
+    XInitThreads();
     Display *display = XOpenDisplay(0);
     if (!display && !enable_spice) {
         fprintf(stderr, "Cannot open X display\n");