VIGS: introduce frontends 03/25903/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 11 Aug 2014 17:32:31 +0000 (21:32 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 12 Aug 2014 10:38:01 +0000 (14:38 +0400)
We need to be able to use both old offscreen approach and
new qt5-based onscreen approach. For that to work we separate
vigs_server into 2 subclasses: onscreen and offscreen:

onscreen subclass has almsot no-op update method, it schedules
composite work on rendering thread and expects a client (qt5) to
call 'graphic_hw_text_update' to trigger rendering.
'graphic_hw_text_update' is used just because it's the only
custom GraphicHwOp available, it's basically a hack, but we have no
choice, QEMU graphics console is not "direct rendering aware"

offscreen subclass behaves as old code behaved, i.e. update method
is a memcpy to QEMU surface and it also schedules composite work on
rendering thread. offscreen subclass manages its own work_queue, once
composite work is done it schedules another work on own work_queue that
does glReadPixels, that's done in order not to stall the rendering thread.
'graphic_hw_text_update' is a no-op in this case

Change-Id: I412cba41a123b2e8946112efa75b9ed21368ca84
Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com>
21 files changed:
hw/vigs/Makefile.objs
hw/vigs/display.c
hw/vigs/vigs_backend.h
hw/vigs/vigs_device.c
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend.h
hw/vigs/vigs_gl_backend_glx.c
hw/vigs/vigs_offscreen_server.c [new file with mode: 0644]
hw/vigs/vigs_offscreen_server.h [new file with mode: 0644]
hw/vigs/vigs_onscreen_server.c [new file with mode: 0644]
hw/vigs/vigs_onscreen_server.h [new file with mode: 0644]
hw/vigs/vigs_qt5.cpp
hw/vigs/vigs_server.c
hw/vigs/vigs_server.h
hw/vigs/vigs_sw_backend.c
tizen/src/display/qt5.c
tizen/src/display/qt5_supplement.cpp
tizen/src/display/qt5_supplement.h
tizen/src/ui/displaywidget.cpp
tizen/src/ui/mainwindow.cpp
tizen/src/ui/mainwindow.h

index 572de90946508d2bbecbf7e70b7c295254272a8f..f4a364d63d52a0fffb4e1a55171e1c57d20ddfef 100644 (file)
@@ -4,6 +4,8 @@ obj-y += vigs_device.o
 libs_softmmu += $(GLX_LIBS)
 obj-y += vigs_comm.o
 obj-y += vigs_server.o
+obj-y += vigs_onscreen_server.o
+obj-y += vigs_offscreen_server.o
 obj-y += vigs_backend.o
 obj-y += vigs_surface.o
 obj-y += vigs_utils.o
index 1c55fed87918dea57d93b10f358664b55c44dff4..65dae3e45cc63b3dc44ed9dc3306f7eb6638789b 100644 (file)
@@ -27,6 +27,10 @@ static void displayobject_complete(UserCreatable *obj, Error **errp)
 
     dobj->dpy = (Display*)vigs_qt5_display();
 
+    if (!dobj->dpy) {
+        dobj->dpy = XOpenDisplay(0);
+    }
+
     if (!dobj->dpy) {
         error_setg(errp, "Cannot open X display");
     }
index 0e0830a494a33e9fe70cbf73212f3e283ba30af4..c300195f3531ecfa24c653a23961b3fd45d479e3 100644 (file)
@@ -49,12 +49,16 @@ struct vigs_backend
                                            vigsp_surface_format /*format*/,
                                            vigsp_surface_id /*id*/);
 
-    void (*batch_end)(struct vigs_backend */*backend*/);
-
     bool (*composite)(struct vigs_surface */*surface*/,
                       const struct vigs_plane */*planes*/,
+                      bool /*planes_dirty*/,
                       uint8_t */*display_data*/);
 
+    void (*batch_end)(struct vigs_backend */*backend*/);
+
+    bool (*display)(struct vigs_backend */*backend*/,
+                    uint8_t */*display_data*/);
+
     void (*destroy)(struct vigs_backend */*backend*/);
 };
 
index 464bd10479960b5b3c57cc844d857dbd97399f67..61dbb3709f967a19013ffd8e9049cac85a669828 100644 (file)
  */
 
 #include "vigs_log.h"
-#include "vigs_server.h"
+#include "vigs_onscreen_server.h"
+#include "vigs_offscreen_server.h"
 #include "vigs_backend.h"
 #include "vigs_regs.h"
 #include "vigs_fenceman.h"
+#include "vigs_qt5.h"
 #include "display.h"
 #include "work_queue.h"
 #include "winsys.h"
@@ -145,6 +147,29 @@ static void vigs_hw_update(void *opaque)
     }
 }
 
+static void vigs_hw_display(void *opaque, console_ch_t *text)
+{
+    VIGSState *s = opaque;
+    DisplaySurface *ds = qemu_console_surface(s->con);
+    bool displayed;
+
+    if (!surface_data(ds)) {
+        return;
+    }
+
+    if (vigs_server_display(s->server, &displayed)) {
+        /*
+         * 'vigs_server_display' could have updated the surface,
+         * so fetch it again.
+         */
+        ds = qemu_console_surface(s->con);
+
+        dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds));
+    }
+
+    *text = displayed;
+}
+
 static void vigs_hw_invalidate(void *opaque)
 {
     VIGSState *s = opaque;
@@ -269,7 +294,13 @@ static void vigs_io_write(void *opaque, hwaddr offset,
 static struct GraphicHwOps vigs_hw_ops =
 {
     .invalidate = vigs_hw_invalidate,
-    .gfx_update = vigs_hw_update
+    .gfx_update = vigs_hw_update,
+    /*
+     * Hack. use 'graphic_hw_text_update' to do displaying, but
+     * we have no choice, that's the only way to direct-to-window
+     * rendering from Qt5.
+     */
+    .text_update = vigs_hw_display,
 };
 
 static const MemoryRegionOps vigs_io_ops =
@@ -421,12 +452,21 @@ static int vigs_device_init(PCIDevice *dev)
         goto fail;
     }
 
-    s->server = vigs_server_create(memory_region_get_ram_ptr(&s->vram_bar),
-                                   memory_region_get_ram_ptr(&s->ram_bar),
-                                   &vigs_dpy_ops,
-                                   s,
-                                   backend,
-                                   wqobj->wq);
+    if (vigs_qt5_display()) {
+        s->server = vigs_onscreen_server_create(memory_region_get_ram_ptr(&s->vram_bar),
+                                                memory_region_get_ram_ptr(&s->ram_bar),
+                                                &vigs_dpy_ops,
+                                                s,
+                                                backend,
+                                                wqobj->wq);
+    } else {
+        s->server = vigs_offscreen_server_create(memory_region_get_ram_ptr(&s->vram_bar),
+                                                 memory_region_get_ram_ptr(&s->ram_bar),
+                                                 &vigs_dpy_ops,
+                                                 s,
+                                                 backend,
+                                                 wqobj->wq);
+    }
 
     if (!s->server) {
         goto fail;
@@ -488,7 +528,7 @@ static void vigs_device_exit(PCIDevice *dev)
 {
     VIGSState *s = DO_UPCAST(VIGSState, dev, dev);
 
-    vigs_server_destroy(s->server);
+    s->server->destroy(s->server);
 
     qemu_bh_delete(s->fence_ack_bh);
 
index 8b527b9975d07325fd01c9b883de9a3d32206888..32e7df76290bc4dedce309cadf1debd27f84f7e0 100644 (file)
@@ -34,6 +34,7 @@
 #include "vigs_log.h"
 #include "vigs_utils.h"
 #include "vigs_ref.h"
+#include "vigs_qt5.h"
 #include "winsys_gl.h"
 #include <math.h>
 
@@ -101,13 +102,6 @@ struct vigs_gl_surface
      * Ortho matrix for this surface.
      */
     GLfloat ortho[16];
-
-    /*
-     * Rotation angle and corresponding ortho,
-     * for display.
-     */
-    int dpy_angle;
-    GLfloat dpy_ortho[16];
 };
 
 static __inline struct vigs_winsys_gl_surface
@@ -345,8 +339,6 @@ static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data,
      */
     backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     backend->TexImage2D(GL_TEXTURE_2D, 0, tex_internalformat,
                         width, height, 0,
@@ -734,8 +726,6 @@ static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface
      */
     ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     ws_sfc->backend->TexImage2D(GL_TEXTURE_2D, 0, ws_sfc->tex_internalformat,
                                 ws_sfc->base.base.width, ws_sfc->base.base.height, 0,
@@ -797,6 +787,55 @@ static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc,
     return true;
 }
 
+static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend,
+                                       uint32_t width, uint32_t height,
+                                       GLfloat ortho[16])
+{
+    GLuint cur_tex = 0;
+
+    gl_backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex);
+
+    if (gl_backend->dpy_tex) {
+        if ((gl_backend->dpy_tex_width == width) &&
+            (gl_backend->dpy_tex_height == height)) {
+            return true;
+        }
+        gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->dpy_tex);
+    } else {
+        GLuint tmp_tex = 0;
+
+        gl_backend->GenTextures(1, &tmp_tex);
+
+        if (!tmp_tex) {
+            return false;
+        }
+
+        gl_backend->dpy_tex = tmp_tex;
+
+        gl_backend->BindTexture(GL_TEXTURE_2D, tmp_tex);
+
+        gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+
+    gl_backend->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
+                           width, height, 0,
+                           GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+                           NULL);
+
+    gl_backend->BindTexture(GL_TEXTURE_2D, cur_tex);
+
+    memcpy(gl_backend->dpy_tex_ortho,
+           ortho,
+           sizeof(gl_backend->dpy_tex_ortho));
+    gl_backend->dpy_tex_width = width;
+    gl_backend->dpy_tex_height = height;
+
+    return true;
+}
+
 /*
  * @}
  */
@@ -1420,6 +1459,7 @@ static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend *
 
 static bool vigs_gl_backend_composite(struct vigs_surface *surface,
                                       const struct vigs_plane *planes,
+                                      bool planes_dirty,
                                       uint8_t *display_data)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
@@ -1429,30 +1469,32 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
     GLfloat *vert_coords;
     GLfloat *tex_coords;
     const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES];
-    bool scale;
-    GLfloat *ortho;
 
     VIGS_LOG_TRACE("enter");
 
-    if (!ws_root_sfc->tex) {
-        VIGS_LOG_WARN("compositing garbage (root surface) ???");
-        return false;
-    }
-
-    if (!gl_backend->is_gl_2 && !gl_backend->dpy_vao) {
-        gl_backend->GenVertexArrays(1, &gl_backend->dpy_vao);
-
-        if (!gl_backend->dpy_vao) {
-            VIGS_LOG_CRITICAL("cannot create VAO");
-            exit(1);
+    if (surface->ptr) {
+        if (!vigs_qt5_display() && !planes_dirty) {
+            memcpy(display_data,
+                   surface->ptr,
+                   surface->stride * surface->ws_sfc->height);
+            return true;
+        }
+    } else {
+        if (!ws_root_sfc->tex) {
+            VIGS_LOG_WARN("compositing garbage (root surface) ???");
         }
 
-        gl_backend->BindVertexArray(gl_backend->dpy_vao);
+        if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc)) {
+            goto out;
+        }
     }
 
-    gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->dpy_vbo);
-    gl_backend->Disable(GL_DEPTH_TEST);
-    gl_backend->Disable(GL_BLEND);
+    if (!vigs_gl_update_dpy_texture(gl_backend,
+                                    surface->ws_sfc->width,
+                                    surface->ws_sfc->height,
+                                    gl_root_sfc->ortho)) {
+        goto out;
+    }
 
     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
         struct vigs_gl_surface *gl_sfc;
@@ -1467,54 +1509,25 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
 
         if (!ws_sfc->tex) {
             VIGS_LOG_WARN("compositing garbage (plane %u) ???", i);
-            return false;
         }
-    }
 
-    if (qt5_window_angle == 0) {
-        ortho = gl_root_sfc->ortho;
-    } else {
-        if (gl_root_sfc->dpy_angle != qt5_window_angle) {
-            vigs_gl_rotate_ortho(gl_root_sfc->ortho,
-                                 (float)(360.0f - qt5_window_angle) * M_PI / 180.0f,
-                                 gl_root_sfc->dpy_ortho);
-            gl_root_sfc->dpy_angle = qt5_window_angle;
+        if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) {
+            goto out;
         }
-        ortho = gl_root_sfc->dpy_ortho;
     }
 
-    scale = (qt5_window_width != ws_root_sfc->base.base.width) ||
-            (qt5_window_height != ws_root_sfc->base.base.height);
-
-    gl_backend->Viewport(0, 0,
-                         qt5_window_width,
-                         qt5_window_height);
-
-    if (scale) {
-        float texSize[2];
-
-        gl_backend->UseProgram(gl_backend->dpy_scale_prog_id);
-        gl_backend->UniformMatrix4fv(gl_backend->dpy_scale_prog_proj_loc, 1, GL_FALSE,
-                                     ortho);
-
-        texSize[0] = ws_root_sfc->base.base.width;
-        texSize[1] = ws_root_sfc->base.base.height;
-
-        gl_backend->Uniform2fv(gl_backend->dpy_scale_prog_texSize_loc, 1, texSize);
-    } else {
-        gl_backend->UseProgram(gl_backend->dpy_tex_prog_id);
-        gl_backend->UniformMatrix4fv(gl_backend->dpy_tex_prog_proj_loc, 1, GL_FALSE,
-                                     ortho);
+    if (!vigs_gl_surface_setup_framebuffer(gl_root_sfc,
+                                           gl_backend->tex_prog_id,
+                                           gl_backend->tex_prog_proj_loc)) {
+        goto out;
     }
 
-    gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex);
-
-    vigs_vector_resize(&gl_backend->dpy_v1, 0);
-    vigs_vector_resize(&gl_backend->dpy_v2, 0);
+    vigs_vector_resize(&gl_backend->v1, 0);
+    vigs_vector_resize(&gl_backend->v2, 0);
 
-    vert_coords = vigs_vector_append(&gl_backend->dpy_v1,
+    vert_coords = vigs_vector_append(&gl_backend->v1,
                                      (12 * sizeof(GLfloat)));
-    tex_coords = vigs_vector_append(&gl_backend->dpy_v2,
+    tex_coords = vigs_vector_append(&gl_backend->v2,
                                     (12 * sizeof(GLfloat)));
 
     if (surface->ptr) {
@@ -1528,6 +1541,8 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
         gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
         gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 
+        gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->dpy_tex);
+
         gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                                   ws_root_sfc->base.base.width,
                                   ws_root_sfc->base.base.height,
@@ -1536,16 +1551,24 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
                                   surface->ptr);
     }
 
-    vert_coords[6] = vert_coords[0] = 0;
-    vert_coords[7] = vert_coords[1] = ws_root_sfc->base.base.height;
-    vert_coords[2] = ws_root_sfc->base.base.width;
-    vert_coords[3] = ws_root_sfc->base.base.height;
-    vert_coords[8] = vert_coords[4] = ws_root_sfc->base.base.width;
-    vert_coords[9] = vert_coords[5] = 0;
-    vert_coords[10] = 0;
-    vert_coords[11] = 0;
+    gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                     GL_TEXTURE_2D, gl_backend->dpy_tex, 0);
+
+    if (!surface->ptr) {
+        /*
+         * If root surface is not scanout then we must render
+         * it.
+         */
+
+        vert_coords[6] = vert_coords[0] = 0;
+        vert_coords[7] = vert_coords[1] = ws_root_sfc->base.base.height;
+        vert_coords[2] = ws_root_sfc->base.base.width;
+        vert_coords[3] = ws_root_sfc->base.base.height;
+        vert_coords[8] = vert_coords[4] = ws_root_sfc->base.base.width;
+        vert_coords[9] = vert_coords[5] = 0;
+        vert_coords[10] = 0;
+        vert_coords[11] = 0;
 
-    if (surface->ptr) {
         tex_coords[6] = tex_coords[0] = 0;
         tex_coords[7] = tex_coords[1] = 0;
         tex_coords[2] = 1;
@@ -1554,21 +1577,10 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
         tex_coords[9] = tex_coords[5] = 1;
         tex_coords[10] = 0;
         tex_coords[11] = 1;
-    } else {
-        tex_coords[6] = tex_coords[0] = 0;
-        tex_coords[7] = tex_coords[1] = 1;
-        tex_coords[2] = 1;
-        tex_coords[3] = 1;
-        tex_coords[8] = tex_coords[4] = 1;
-        tex_coords[9] = tex_coords[5] = 0;
-        tex_coords[10] = 0;
-        tex_coords[11] = 0;
-    }
 
-    if (scale) {
-        vigs_gl_draw_dpy_scale_prog(gl_backend, 6);
-    } else {
-        vigs_gl_draw_dpy_tex_prog(gl_backend, 6);
+        gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex);
+
+        vigs_gl_draw_tex_prog(gl_backend, 6);
     }
 
     /*
@@ -1615,39 +1627,160 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface,
         vert_coords[11] = plane->dst_y + (int)plane->dst_size.h;
 
         tex_coords[6] = tex_coords[0] = (GLfloat)plane->src_rect.pos.x / src_w;
-        tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
+        tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
         tex_coords[2] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
-        tex_coords[3] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
+        tex_coords[3] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
         tex_coords[8] = tex_coords[4] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
-        tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
+        tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
         tex_coords[10] = (GLfloat)plane->src_rect.pos.x / src_w;
-        tex_coords[11] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
+        tex_coords[11] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
 
         gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
 
+        vigs_gl_draw_tex_prog(gl_backend, 6);
+    }
+
+out:
+    gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    return false;
+}
+
+static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
+
+    gl_backend->Finish();
+    gl_backend->make_current(gl_backend, false);
+}
+
+static bool vigs_gl_backend_display(struct vigs_backend *backend,
+                                    uint8_t *display_data)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
+
+    VIGS_LOG_TRACE("enter");
+
+    if (vigs_qt5_display()) {
+        GLfloat *vert_coords;
+        GLfloat *tex_coords;
+        bool scale;
+        GLfloat rotated_ortho[16];
+        GLfloat *ortho;
+
+        if (!gl_backend->is_gl_2 && !gl_backend->dpy_vao) {
+            gl_backend->GenVertexArrays(1, &gl_backend->dpy_vao);
+
+            if (!gl_backend->dpy_vao) {
+                VIGS_LOG_CRITICAL("cannot create VAO");
+                exit(1);
+            }
+
+            gl_backend->BindVertexArray(gl_backend->dpy_vao);
+        }
+
+        gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->dpy_vbo);
+        gl_backend->Disable(GL_DEPTH_TEST);
+        gl_backend->Disable(GL_BLEND);
+
+        if (qt5_window_angle == 0) {
+            ortho = gl_backend->dpy_tex_ortho;
+        } else {
+            vigs_gl_rotate_ortho(gl_backend->dpy_tex_ortho,
+                                 (float)(360.0f - qt5_window_angle) * M_PI / 180.0f,
+                                 rotated_ortho);
+            ortho = rotated_ortho;
+        }
+
+        scale = (qt5_window_width != gl_backend->dpy_tex_width) ||
+                (qt5_window_height != gl_backend->dpy_tex_height);
+
+        gl_backend->Viewport(0, 0,
+                             qt5_window_width,
+                             qt5_window_height);
+
         if (scale) {
             float texSize[2];
 
-            texSize[0] = src_w;
-            texSize[1] = src_h;
+            gl_backend->UseProgram(gl_backend->dpy_scale_prog_id);
+            gl_backend->UniformMatrix4fv(gl_backend->dpy_scale_prog_proj_loc, 1, GL_FALSE,
+                                         ortho);
+
+            texSize[0] = gl_backend->dpy_tex_width;
+            texSize[1] = gl_backend->dpy_tex_height;
 
             gl_backend->Uniform2fv(gl_backend->dpy_scale_prog_texSize_loc, 1, texSize);
+        } else {
+            gl_backend->UseProgram(gl_backend->dpy_tex_prog_id);
+            gl_backend->UniformMatrix4fv(gl_backend->dpy_tex_prog_proj_loc, 1, GL_FALSE,
+                                         ortho);
+        }
 
+        gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->dpy_tex);
+
+        vigs_vector_resize(&gl_backend->dpy_v1, 0);
+        vigs_vector_resize(&gl_backend->dpy_v2, 0);
+
+        vert_coords = vigs_vector_append(&gl_backend->dpy_v1,
+                                         (12 * sizeof(GLfloat)));
+        tex_coords = vigs_vector_append(&gl_backend->dpy_v2,
+                                        (12 * sizeof(GLfloat)));
+
+        vert_coords[6] = vert_coords[0] = 0;
+        vert_coords[7] = vert_coords[1] = gl_backend->dpy_tex_height;
+        vert_coords[2] = gl_backend->dpy_tex_width;
+        vert_coords[3] = gl_backend->dpy_tex_height;
+        vert_coords[8] = vert_coords[4] = gl_backend->dpy_tex_width;
+        vert_coords[9] = vert_coords[5] = 0;
+        vert_coords[10] = 0;
+        vert_coords[11] = 0;
+
+        tex_coords[6] = tex_coords[0] = 0;
+        tex_coords[7] = tex_coords[1] = 0;
+        tex_coords[2] = 1;
+        tex_coords[3] = 0;
+        tex_coords[8] = tex_coords[4] = 1;
+        tex_coords[9] = tex_coords[5] = 1;
+        tex_coords[10] = 0;
+        tex_coords[11] = 1;
+
+        if (scale) {
             vigs_gl_draw_dpy_scale_prog(gl_backend, 6);
         } else {
             vigs_gl_draw_dpy_tex_prog(gl_backend, 6);
         }
-    }
 
-    return false;
-}
+        gl_backend->Finish();
 
-static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
-{
-    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
+        return true;
+    } else {
+        if (gl_backend->read_pixels_make_current(gl_backend, true)) {
+            if (!gl_backend->dpy_fb) {
+                gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb);
 
-    gl_backend->Finish();
-    gl_backend->make_current(gl_backend, false);
+                if (!gl_backend->dpy_fb) {
+                    VIGS_LOG_CRITICAL("cannot create FB");
+                    exit(1);
+                }
+
+                gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb);
+            }
+
+            gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                             GL_TEXTURE_2D, gl_backend->dpy_tex, 0);
+
+            gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width,
+                                   gl_backend->dpy_tex_height,
+                                   GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+                                   display_data);
+
+            gl_backend->read_pixels_make_current(gl_backend, false);
+
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
 
 bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
@@ -1817,6 +1950,7 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
     gl_backend->base.composite = &vigs_gl_backend_composite;
     gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
+    gl_backend->base.display = &vigs_gl_backend_display;
 
     gl_backend->make_current(gl_backend, false);
 
@@ -1836,6 +1970,9 @@ fail:
 void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
 {
     if (gl_backend->make_current(gl_backend, true)) {
+        if (gl_backend->dpy_tex) {
+            gl_backend->DeleteTextures(1, &gl_backend->dpy_tex);
+        }
         gl_backend->DeleteBuffers(1, &gl_backend->dpy_vbo);
         gl_backend->DetachShader(gl_backend->dpy_scale_prog_id,
                                  gl_backend->dpy_scale_prog_vs_id);
index 7f900f9e7a419928087ab21aada608df3ed6423e..450d1a22df77f0cf6bf531c900fd3e96e7afb376 100644 (file)
@@ -52,6 +52,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.
      * @{
@@ -210,6 +213,12 @@ struct vigs_gl_backend
     GLuint dpy_vbo;
     uint32_t dpy_vbo_size;
 
+    GLuint dpy_tex;
+    GLuint dpy_fb;
+    GLfloat dpy_tex_ortho[16];
+    uint32_t dpy_tex_width;
+    uint32_t dpy_tex_height;
+
     /*
      * @}
      */
index 64d8324ed4ad0d02e6e91475d10ad8e733942cca..23a485795680c4fbbdc6fe621aebebd3abff36ed 100644 (file)
@@ -94,6 +94,8 @@ struct vigs_gl_backend_glx
     Display *dpy;
     GLXPbuffer sfc;
     GLXContext ctx;
+    GLXPbuffer read_pixels_sfc;
+    GLXContext read_pixels_ctx;
 };
 
 static bool vigs_gl_backend_glx_check_gl_version(struct vigs_gl_backend_glx *gl_backend_glx,
@@ -192,27 +194,50 @@ out:
 
 static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl_backend_glx)
 {
-    int config_attribs[] =
-    {
-        GLX_FBCONFIG_ID, 0,
-        None
-    };
     int n = 0;
     GLXFBConfig *glx_configs;
     GLXFBConfig best_config = NULL;
 
-    if (gl_backend_glx->glXQueryContext(gl_backend_glx->dpy,
-                                        gl_backend_glx->ctx,
-                                        GLX_FBCONFIG_ID,
-                                        &config_attribs[1]) != Success) {
-        VIGS_LOG_CRITICAL("Unable to get context's GLX config");
-        return NULL;
-    }
+    if (vigs_qt5_display()) {
+        int config_attribs[] =
+        {
+            GLX_FBCONFIG_ID, 0,
+            None
+        };
+
+        if (gl_backend_glx->glXQueryContext(gl_backend_glx->dpy,
+                                            gl_backend_glx->ctx,
+                                            GLX_FBCONFIG_ID,
+                                            &config_attribs[1]) != Success) {
+            VIGS_LOG_CRITICAL("Unable to get context's GLX config");
+            return NULL;
+        }
 
-    glx_configs = gl_backend_glx->glXChooseFBConfig(gl_backend_glx->dpy,
-                                                    DefaultScreen(gl_backend_glx->dpy),
-                                                    config_attribs,
-                                                    &n);
+        glx_configs = gl_backend_glx->glXChooseFBConfig(gl_backend_glx->dpy,
+                                                        DefaultScreen(gl_backend_glx->dpy),
+                                                        config_attribs,
+                                                        &n);
+    } else {
+        int config_attribs[] =
+        {
+            GLX_DOUBLEBUFFER, True,
+            GLX_RED_SIZE, 8,
+            GLX_GREEN_SIZE, 8,
+            GLX_BLUE_SIZE, 8,
+            GLX_ALPHA_SIZE, 8,
+            GLX_BUFFER_SIZE, 32,
+            GLX_DEPTH_SIZE, 24,
+            GLX_STENCIL_SIZE, 8,
+            GLX_RENDER_TYPE, GLX_RGBA_BIT,
+            GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
+            None
+        };
+
+        glx_configs = gl_backend_glx->glXChooseFBConfig(gl_backend_glx->dpy,
+                                                        DefaultScreen(gl_backend_glx->dpy),
+                                                        config_attribs,
+                                                        &n);
+    }
 
     if (n > 0) {
         int tmp;
@@ -266,6 +291,42 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba
     return true;
 }
 
+static bool vigs_gl_backend_glx_create_context(struct vigs_gl_backend_glx *gl_backend_glx,
+                                               GLXFBConfig config,
+                                               GLXContext share_ctx,
+                                               GLXContext *ctx)
+{
+    int attribs[] =
+    {
+        GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+        GLX_CONTEXT_MINOR_VERSION_ARB, 1,
+        GLX_RENDER_TYPE, GLX_RGBA_TYPE,
+        GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+        None
+    };
+
+    if (gl_backend_glx->base.is_gl_2) {
+        *ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy,
+                                                   config,
+                                                   GLX_RGBA_TYPE,
+                                                   share_ctx,
+                                                   True);
+    } else {
+        *ctx = gl_backend_glx->glXCreateContextAttribsARB(gl_backend_glx->dpy,
+                                                          config,
+                                                          share_ctx,
+                                                          True,
+                                                          attribs);
+    }
+
+    if (!*ctx) {
+        VIGS_LOG_CRITICAL("glXCreateContextAttribsARB/glXCreateNewContext failed");
+        return false;
+    }
+
+    return true;
+}
+
 static bool vigs_gl_backend_glx_has_current(struct vigs_gl_backend *gl_backend)
 {
     struct vigs_gl_backend_glx *gl_backend_glx =
@@ -294,12 +355,45 @@ 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;
 
     vigs_gl_backend_cleanup(&gl_backend_glx->base);
 
+    if (gl_backend_glx->read_pixels_sfc) {
+        gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+                                          gl_backend_glx->read_pixels_sfc);
+    }
+    if (!vigs_qt5_display() && gl_backend_glx->ctx) {
+        gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                          gl_backend_glx->ctx);
+    }
+    if (gl_backend_glx->read_pixels_ctx) {
+        gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                          gl_backend_glx->read_pixels_ctx);
+    }
+
     gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
                                       gl_backend_glx->sfc);
 
@@ -440,17 +534,45 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         VIGS_GL_GET_PROC(DeleteVertexArrays, glDeleteVertexArrays);
     }
 
-    gl_backend_glx->ctx =
-        (GLXContext)vigs_qt5_gl_context_create(gl_backend_glx->base.is_gl_2);
+    if (vigs_qt5_display()) {
+        gl_backend_glx->ctx =
+            (GLXContext)vigs_qt5_gl_context_create(gl_backend_glx->base.is_gl_2);
 
-    if (!gl_backend_glx->ctx) {
-        goto fail2;
-    }
+        if (!gl_backend_glx->ctx) {
+            goto fail2;
+        }
 
-    config = vigs_gl_backend_glx_get_config(gl_backend_glx);
+        config = vigs_gl_backend_glx_get_config(gl_backend_glx);
 
-    if (!config) {
-        goto fail2;
+        if (!config) {
+            goto fail2;
+        }
+    } else {
+        config = vigs_gl_backend_glx_get_config(gl_backend_glx);
+
+        if (!config) {
+            goto fail2;
+        }
+
+        if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
+                                                config,
+                                                &gl_backend_glx->read_pixels_sfc)) {
+            goto fail2;
+        }
+
+        if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+                                                config,
+                                                NULL,
+                                                &gl_backend_glx->ctx)) {
+            goto fail2;
+        }
+
+        if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+                                                config,
+                                                gl_backend_glx->ctx,
+                                                &gl_backend_glx->read_pixels_ctx)) {
+            goto fail2;
+        }
     }
 
     if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
@@ -462,6 +584,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
     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)) {
@@ -476,6 +599,18 @@ fail3:
     gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
                                       gl_backend_glx->sfc);
 fail2:
+    if (gl_backend_glx->read_pixels_sfc) {
+        gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+                                          gl_backend_glx->read_pixels_sfc);
+    }
+    if (!vigs_qt5_display() && gl_backend_glx->ctx) {
+        gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                          gl_backend_glx->ctx);
+    }
+    if (gl_backend_glx->read_pixels_ctx) {
+        gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+                                          gl_backend_glx->read_pixels_ctx);
+    }
     dlclose(gl_backend_glx->handle);
 fail1:
     vigs_backend_cleanup(&gl_backend_glx->base.base);
diff --git a/hw/vigs/vigs_offscreen_server.c b/hw/vigs/vigs_offscreen_server.c
new file mode 100644 (file)
index 0000000..28b3ea9
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "vigs_offscreen_server.h"
+#include "vigs_backend.h"
+#include "work_queue.h"
+
+struct vigs_display_work_item
+{
+    struct work_queue_item base;
+
+    struct vigs_server *server;
+};
+
+static void vigs_offscreen_server_display_work(struct work_queue_item *wq_item)
+{
+    struct vigs_display_work_item *item = (struct vigs_display_work_item*)wq_item;
+    struct vigs_server *server = item->server;
+    int index = (&server->capture_buffers[0] == server->captured) ? 1 : 0;
+
+    vigs_server_finish_update_display(
+        server, server->backend->display(server->backend,
+                                         server->capture_buffers[index].data));
+
+    g_free(item);
+}
+
+static bool vigs_offscreen_server_begin_update(struct vigs_server *server,
+                                               bool is_capturing,
+                                               bool force)
+{
+    return vigs_server_process_captured(server, force);
+}
+
+static void vigs_offscreen_server_finish_update(struct vigs_server *server,
+                                                bool composited,
+                                                bool dirty)
+{
+    if (dirty) {
+        vigs_server_finish_update_display(server, true);
+    } else if (composited) {
+        struct vigs_offscreen_server *offscreen_server =
+            (struct vigs_offscreen_server*)server;
+
+        struct vigs_display_work_item *item;
+
+        item = g_malloc(sizeof(*item));
+
+        work_queue_item_init(&item->base, &vigs_offscreen_server_display_work);
+
+        item->server = server;
+
+        work_queue_add_item(offscreen_server->display_queue, &item->base);
+    } else {
+        vigs_server_finish_update_display(server, false);
+    }
+}
+
+static bool vigs_offscreen_server_display(struct vigs_server *server,
+                                          bool *displayed)
+{
+    *displayed = false;
+    return false;
+}
+
+static void vigs_offscreen_server_destroy(struct vigs_server *server)
+{
+    struct vigs_offscreen_server *offscreen_server =
+        (struct vigs_offscreen_server*)server;
+
+    work_queue_destroy(offscreen_server->display_queue);
+
+    vigs_server_cleanup(server);
+
+    g_free(server);
+}
+
+struct vigs_server *vigs_offscreen_server_create(uint8_t *vram_ptr,
+                                                 uint8_t *ram_ptr,
+                                                 struct vigs_display_ops *display_ops,
+                                                 void *display_user_data,
+                                                 struct vigs_backend *backend,
+                                                 struct work_queue *render_queue)
+{
+    struct vigs_offscreen_server *server = NULL;
+
+    server = g_malloc0(sizeof(*server));
+
+    if (!vigs_server_init(&server->base, vram_ptr, ram_ptr,
+                          display_ops, display_user_data, backend,
+                          render_queue)) {
+        g_free(server);
+        return NULL;
+    }
+
+    server->display_queue = work_queue_create("display_queue");
+
+    server->base.begin_update = &vigs_offscreen_server_begin_update;
+    server->base.finish_update = &vigs_offscreen_server_finish_update;
+    server->base.display = &vigs_offscreen_server_display;
+    server->base.destroy = &vigs_offscreen_server_destroy;
+
+    return &server->base;
+}
diff --git a/hw/vigs/vigs_offscreen_server.h b/hw/vigs/vigs_offscreen_server.h
new file mode 100644 (file)
index 0000000..1cfa3fd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _QEMU_VIGS_OFFSCREEN_SERVER_H
+#define _QEMU_VIGS_OFFSCREEN_SERVER_H
+
+#include "vigs_server.h"
+
+struct vigs_offscreen_server
+{
+    struct vigs_server base;
+
+    struct work_queue *display_queue;
+};
+
+struct vigs_server *vigs_offscreen_server_create(uint8_t *vram_ptr,
+                                                 uint8_t *ram_ptr,
+                                                 struct vigs_display_ops *display_ops,
+                                                 void *display_user_data,
+                                                 struct vigs_backend *backend,
+                                                 struct work_queue *render_queue);
+
+#endif
diff --git a/hw/vigs/vigs_onscreen_server.c b/hw/vigs/vigs_onscreen_server.c
new file mode 100644 (file)
index 0000000..984fd1b
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "vigs_onscreen_server.h"
+#include "vigs_backend.h"
+
+static bool vigs_onscreen_server_begin_update(struct vigs_server *server,
+                                              bool is_capturing,
+                                              bool force)
+{
+    struct vigs_onscreen_server *onscreen_server =
+        (struct vigs_onscreen_server*)server;
+
+    qemu_mutex_lock(&onscreen_server->mutex);
+
+    if (force) {
+        ++onscreen_server->invalidate_cnt;
+    }
+
+    if (is_capturing) {
+        /*
+         * If capturing is in progress then just skip this update.
+         */
+        goto out;
+    }
+
+    onscreen_server->updated = false;
+    onscreen_server->composited = false;
+    onscreen_server->dirty = false;
+
+out:
+    qemu_mutex_unlock(&onscreen_server->mutex);
+
+    return false;
+}
+
+static void vigs_onscreen_server_finish_update(struct vigs_server *server,
+                                               bool composited,
+                                               bool dirty)
+{
+    struct vigs_onscreen_server *onscreen_server =
+        (struct vigs_onscreen_server*)server;
+
+    qemu_mutex_lock(&onscreen_server->mutex);
+
+    onscreen_server->updated = true;
+    onscreen_server->composited = composited;
+    onscreen_server->dirty = dirty;
+
+    qemu_mutex_unlock(&onscreen_server->mutex);
+
+    qemu_cond_signal(&onscreen_server->cond);
+}
+
+static bool vigs_onscreen_server_display(struct vigs_server *server,
+                                         bool *displayed)
+{
+    struct vigs_onscreen_server *onscreen_server =
+        (struct vigs_onscreen_server*)server;
+    bool force = false;
+
+    qemu_mutex_lock(&onscreen_server->mutex);
+
+    /*
+     * Wait until rendering is finished.
+     */
+    while (!onscreen_server->updated) {
+        qemu_cond_wait(&onscreen_server->cond, &onscreen_server->mutex);
+    }
+
+    if (onscreen_server->invalidate_cnt > 0) {
+        --onscreen_server->invalidate_cnt;
+        force = true;
+    }
+
+    onscreen_server->updated = false;
+
+    qemu_mutex_unlock(&onscreen_server->mutex);
+
+    *displayed = true;
+
+    if (onscreen_server->dirty) {
+        /*
+         * Software composition took place, finish ASAP and
+         * process captured data.
+         */
+        vigs_server_finish_update_display(server, true);
+        return vigs_server_process_captured(server, force);
+    } else if (onscreen_server->composited) {
+        /*
+         * Hw composition took place, display the content.
+         */
+        server->backend->display(server->backend, NULL);
+    } else if (force) {
+        /*
+         * Nothing happened, but if it's a forced display, then
+         * we should try to display hw stuff first, if there isn't any
+         * then display sw stuff.
+         */
+        if (!server->backend->display(server->backend, NULL)) {
+            vigs_server_finish_update_display(server, false);
+            return vigs_server_process_captured(server, force);
+        }
+    } else {
+        *displayed = false;
+    }
+
+    vigs_server_finish_update_display(server, false);
+
+    return false;
+}
+
+static void vigs_onscreen_server_destroy(struct vigs_server *server)
+{
+    struct vigs_onscreen_server *onscreen_server =
+        (struct vigs_onscreen_server*)server;
+
+    qemu_cond_destroy(&onscreen_server->cond);
+    qemu_mutex_destroy(&onscreen_server->mutex);
+
+    vigs_server_cleanup(server);
+
+    g_free(server);
+}
+
+struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr,
+                                                uint8_t *ram_ptr,
+                                                struct vigs_display_ops *display_ops,
+                                                void *display_user_data,
+                                                struct vigs_backend *backend,
+                                                struct work_queue *render_queue)
+{
+    struct vigs_onscreen_server *server = NULL;
+
+    server = g_malloc0(sizeof(*server));
+
+    if (!vigs_server_init(&server->base, vram_ptr, ram_ptr,
+                          display_ops, display_user_data, backend,
+                          render_queue)) {
+        g_free(server);
+        return NULL;
+    }
+
+    qemu_mutex_init(&server->mutex);
+    qemu_cond_init(&server->cond);
+
+    server->base.begin_update = &vigs_onscreen_server_begin_update;
+    server->base.finish_update = &vigs_onscreen_server_finish_update;
+    server->base.display = &vigs_onscreen_server_display;
+    server->base.destroy = &vigs_onscreen_server_destroy;
+
+    return &server->base;
+}
diff --git a/hw/vigs/vigs_onscreen_server.h b/hw/vigs/vigs_onscreen_server.h
new file mode 100644 (file)
index 0000000..a3b4433
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _QEMU_VIGS_ONSCREEN_SERVER_H
+#define _QEMU_VIGS_ONSCREEN_SERVER_H
+
+#include "vigs_server.h"
+
+struct vigs_onscreen_server
+{
+    struct vigs_server base;
+
+    QemuMutex mutex;
+    QemuCond cond;
+    bool updated;
+    bool composited;
+    bool dirty;
+
+    int invalidate_cnt;
+};
+
+struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr,
+                                                uint8_t *ram_ptr,
+                                                struct vigs_display_ops *display_ops,
+                                                void *display_user_data,
+                                                struct vigs_backend *backend,
+                                                struct work_queue *render_queue);
+
+#endif
index 6a05acb4e672a8ee9389881560f177410e5da3c9..fefca0d7d7b135a735482c2669939fa9495d126c 100644 (file)
 #include <qpa/qplatformnativeinterface.h>
 #include <stdio.h>
 
+extern QApplication *qt5App;
 extern QOpenGLContext *qt5GLContext;
 extern QSurfaceFormat qt5GLFormat;
 
 void *vigs_qt5_display(void)
 {
+    if (!qt5App) {
+        return NULL;
+    }
+
     QPlatformNativeInterface *native =
         QGuiApplication::platformNativeInterface();
 
@@ -48,6 +53,11 @@ void *vigs_qt5_display(void)
 
 void *vigs_qt5_gl_context_create(bool is_gl2)
 {
+    if (!qt5App) {
+        fprintf(stderr, "QT5 not enabled!\n");
+        return NULL;
+    }
+
     if (qt5GLContext) {
         fprintf(stderr, "QT5 GL context already created!\n");
         return NULL;
index 6299299ed46844a8075cd1ddf559f3bfc4d48387..082506c4d399de6ff89dcb52cdbd0c63584112e6 100644 (file)
@@ -178,12 +178,8 @@ static void vigs_server_dispatch_destroy_surface(void *user_data,
         return;
     }
 
-    qemu_mutex_lock(&server->dpy_mutex);
-
     vigs_server_unuse_surface(server, sfc);
 
-    qemu_mutex_unlock(&server->dpy_mutex);
-
     g_hash_table_remove(server->surfaces, GUINT_TO_POINTER(id));
 
     VIGS_LOG_TRACE("num_surfaces = %u", g_hash_table_size(server->surfaces));
@@ -326,20 +322,18 @@ static void vigs_server_dispatch_set_plane(void *user_data,
         return;
     }
 
-    qemu_mutex_lock(&server->dpy_mutex);
-
     if (sfc_id) {
         sfc = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(sfc_id));
 
         if (!sfc) {
             VIGS_LOG_ERROR("surface %u not found", sfc_id);
-            goto out;
+            return;
         }
     }
 
     if (plane >= VIGS_MAX_PLANES) {
         VIGS_LOG_ERROR("bad plane %u", plane);
-        goto out;
+        return;
     }
 
     server->planes[plane].sfc = sfc;
@@ -349,9 +343,6 @@ static void vigs_server_dispatch_set_plane(void *user_data,
     server->planes[plane].dst_size = *dst_size;
     server->planes[plane].z_pos = z_pos;
     server->planes[plane].is_dirty = true;
-
-out:
-    qemu_mutex_unlock(&server->dpy_mutex);
 }
 
 static void vigs_server_dispatch_batch_end(void *user_data,
@@ -403,8 +394,6 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item)
         goto out;
     }
 
-    qemu_mutex_lock(&server->dpy_mutex);
-
     if (item->id == 0) {
         if (server->root_sfc) {
             vigs_surface_set_scanout(server->root_sfc, NULL);
@@ -438,7 +427,83 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item)
     }
 
 out:
-    qemu_mutex_unlock(&server->dpy_mutex);
+    g_free(item);
+}
+
+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;
+    bool planes_dirty = false;
+    bool dirty = false;
+    bool composited = false;
+    int i, index;
+
+    if (!root_sfc) {
+        /*
+         * If no root surface then this is a no-op.
+         * TODO: Can planes be enabled without a root surface ?
+         */
+        goto out;
+    }
+
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        /*
+         * If plane was moved/resized or turned on/off
+         * then we're dirty.
+         */
+        if (server->planes[i].is_dirty) {
+            planes_dirty = true;
+        }
+
+        if (server->planes[i].sfc && server->planes[i].sfc->is_dirty) {
+            /*
+             * If plane's surface is dirty then we're dirty.
+             */
+            planes_dirty = true;
+        }
+    }
+
+    if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty) {
+        /*
+         * Composite root surface and planes.
+         */
+        composited = true;
+
+        index = (&server->capture_buffers[0] == server->captured) ? 1 : 0;
+
+        if ((server->capture_buffers[index].stride != root_sfc->stride) ||
+            (server->capture_buffers[index].height != root_sfc->ws_sfc->height)) {
+            g_free(server->capture_buffers[index].data);
+            server->capture_buffers[index].data = g_malloc(root_sfc->stride * root_sfc->ws_sfc->height);
+        }
+
+        server->capture_buffers[index].width = root_sfc->ws_sfc->width;
+        server->capture_buffers[index].height = root_sfc->ws_sfc->height;
+        server->capture_buffers[index].stride = root_sfc->stride;
+        server->capture_buffers[index].format = root_sfc->format;
+
+        server->backend->batch_start(server->backend);
+        dirty = server->backend->composite(root_sfc,
+                                           &server->planes[0],
+                                           planes_dirty,
+                                           server->capture_buffers[index].data);
+        server->backend->batch_end(server->backend);
+
+        root_sfc->is_dirty = false;
+
+        for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+            server->planes[i].is_dirty = false;
+
+            if (server->planes[i].sfc) {
+                server->planes[i].sfc->is_dirty = false;
+            }
+        }
+    }
+
+out:
+    server->finish_update(server, composited, dirty);
 
     g_free(item);
 }
@@ -503,6 +568,7 @@ static void vigs_server_dispatch_set_root_surface(void *user_data,
 {
     struct vigs_server *server = user_data;
     struct vigs_server_set_root_surface_work_item *item;
+    uint32_t capture_fence_seq = 0;
 
     item = g_malloc(sizeof(*item));
 
@@ -515,9 +581,20 @@ static void vigs_server_dispatch_set_root_surface(void *user_data,
 
     work_queue_add_item(server->render_queue, &item->base);
 
-    if (fence_seq) {
+    qemu_mutex_lock(&server->capture_mutex);
+
+    if (server->is_capturing) {
+        capture_fence_seq = server->capture_fence_seq;
+        server->capture_fence_seq = fence_seq;
+    } else {
+        capture_fence_seq = fence_seq;
+    }
+
+    qemu_mutex_unlock(&server->capture_mutex);
+
+    if (capture_fence_seq) {
         server->display_ops->fence_ack(server->display_user_data,
-                                       fence_seq);
+                                       capture_fence_seq);
     }
 }
 
@@ -547,17 +624,14 @@ static struct vigs_comm_ops vigs_server_dispatch_ops =
     .batch = &vigs_server_dispatch_batch
 };
 
-struct vigs_server *vigs_server_create(uint8_t *vram_ptr,
-                                       uint8_t *ram_ptr,
-                                       struct vigs_display_ops *display_ops,
-                                       void *display_user_data,
-                                       struct vigs_backend *backend,
-                                       struct work_queue *render_queue)
+bool vigs_server_init(struct vigs_server *server,
+                      uint8_t *vram_ptr,
+                      uint8_t *ram_ptr,
+                      struct vigs_display_ops *display_ops,
+                      void *display_user_data,
+                      struct vigs_backend *backend,
+                      struct work_queue *render_queue)
 {
-    struct vigs_server *server = NULL;
-
-    server = g_malloc0(sizeof(*server));
-
     server->wsi.ws_info = backend->ws_info;
     server->wsi.acquire_surface = &vigs_server_acquire_surface;
     server->wsi.fence_ack = &vigs_server_fence_ack;
@@ -571,7 +645,7 @@ struct vigs_server *vigs_server_create(uint8_t *vram_ptr,
     server->comm = vigs_comm_create(ram_ptr);
 
     if (!server->comm) {
-        goto fail;
+        return false;
     }
 
     server->surfaces = g_hash_table_new_full(g_direct_hash,
@@ -579,25 +653,23 @@ struct vigs_server *vigs_server_create(uint8_t *vram_ptr,
                                              NULL,
                                              vigs_server_surface_destroy_func);
 
-    qemu_mutex_init(&server->dpy_mutex);
+    qemu_mutex_init(&server->capture_mutex);
 
-    return server;
+    server->captured = &server->capture_buffers[0];
 
-fail:
-    g_free(server);
-
-    return NULL;
+    return true;
 }
 
-void vigs_server_destroy(struct vigs_server *server)
+void vigs_server_cleanup(struct vigs_server *server)
 {
     vigs_server_reset(server);
 
     g_hash_table_destroy(server->surfaces);
     vigs_comm_destroy(server->comm);
     server->backend->destroy(server->backend);
-    qemu_mutex_destroy(&server->dpy_mutex);
-    g_free(server);
+    qemu_mutex_destroy(&server->capture_mutex);
+    g_free(server->capture_buffers[0].data);
+    g_free(server->capture_buffers[1].data);
 }
 
 void vigs_server_reset(struct vigs_server *server)
@@ -633,94 +705,96 @@ void vigs_server_dispatch(struct vigs_server *server,
 }
 
 bool vigs_server_update_display(struct vigs_server *server, int invalidate_cnt)
+{
+    bool is_capturing = server->is_capturing;
+
+    bool updated = server->begin_update(server, is_capturing, (invalidate_cnt > 0));
+
+    if (!is_capturing) {
+        struct vigs_server_work_item *item;
+
+        item = g_malloc(sizeof(*item));
+
+        work_queue_item_init(&item->base, &vigs_server_update_display_work);
+
+        item->server = server;
+
+        server->is_capturing = true;
+
+        work_queue_add_item(server->render_queue, &item->base);
+    }
+
+    return updated;
+}
+
+bool vigs_server_display(struct vigs_server *server, bool *displayed)
+{
+    return server->display(server, displayed);
+}
+
+bool vigs_server_process_captured(struct vigs_server *server, bool force)
 {
     bool updated = false;
-    struct vigs_surface *root_sfc;
     uint32_t display_stride, display_bpp;
     uint8_t *display_data;
-    int i;
-    bool planes_on = false;
-    bool planes_dirty = false;
-
-    qemu_mutex_lock(&server->dpy_mutex);
 
-    root_sfc = server->root_sfc;
+    qemu_mutex_lock(&server->capture_mutex);
 
-    if (!root_sfc) {
+    if (!server->captured->data ||
+        (!server->captured->dirty && !force)) {
         goto out;
     }
 
+    server->captured->dirty = false;
+    updated = true;
+
     server->display_ops->resize(server->display_user_data,
-                                root_sfc->ws_sfc->width,
-                                root_sfc->ws_sfc->height);
+                                server->captured->width,
+                                server->captured->height);
 
     display_stride = server->display_ops->get_stride(server->display_user_data);
     display_bpp = server->display_ops->get_bpp(server->display_user_data);
     display_data = server->display_ops->get_data(server->display_user_data);
 
-    if ((vigs_format_bpp(root_sfc->format) != display_bpp) ||
-        (root_sfc->stride != display_stride)) {
+    if ((vigs_format_bpp(server->captured->format) != display_bpp) ||
+        (server->captured->stride != display_stride)) {
         VIGS_LOG_CRITICAL("bpp/format mismatch");
         assert(false);
         goto out;
     }
 
-    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
-        /*
-         * If plane was moved/resized or turned on/off
-         * then we're dirty.
-         */
-        if (server->planes[i].is_dirty) {
-            planes_dirty = true;
-        }
+    memcpy(display_data,
+           server->captured->data,
+           server->captured->stride * server->captured->height);
 
-        if (server->planes[i].sfc) {
-            planes_on = true;
+    updated = true;
 
-            /*
-             * If plane's surface is dirty then we're dirty.
-             */
-            if (server->planes[i].sfc->is_dirty) {
-                planes_dirty = true;
-            }
-        }
-    }
+out:
+    qemu_mutex_unlock(&server->capture_mutex);
 
-    if (root_sfc->ptr && !root_sfc->is_dirty && !planes_on) {
-        /*
-         * Root surface is scanout, it's not dirty and planes not on.
-         */
+    return updated;
+}
 
-        memcpy(display_data,
-               root_sfc->ptr,
-               root_sfc->stride * root_sfc->ws_sfc->height);
+void vigs_server_finish_update_display(struct vigs_server *server, bool dirty)
+{
+    uint32_t capture_fence_seq = 0;
 
-        updated = true;
-    } else if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty || (invalidate_cnt > 0)) {
-        /*
-         * Composite root surface and planes.
-         */
+    qemu_mutex_lock(&server->capture_mutex);
 
-        updated = server->backend->composite(root_sfc,
-                                             &server->planes[0],
-                                             display_data);
+    if (dirty) {
+        int index = (&server->capture_buffers[0] == server->captured) ? 1 : 0;
+        server->capture_buffers[index].dirty = true;
+        server->captured = &server->capture_buffers[index];
+    }
 
-        root_sfc->is_dirty = false;
+    server->is_capturing = false;
+    capture_fence_seq = server->capture_fence_seq;
+    server->capture_fence_seq = 0;
 
-        for (i = 0; i < VIGS_MAX_PLANES; ++i) {
-            if (server->planes[i].is_dirty) {
-                server->planes[i].is_dirty = false;
-            }
+    qemu_mutex_unlock(&server->capture_mutex);
 
-            if (server->planes[i].sfc &&
-                server->planes[i].sfc->is_dirty) {
-                server->planes[i].sfc->is_dirty = false;
-            }
-        }
+    if (capture_fence_seq) {
+        server->display_ops->fence_ack(server->display_user_data,
+                                       capture_fence_seq);
     }
-
-out:
-    qemu_mutex_unlock(&server->dpy_mutex);
-
-    return updated;
 }
index 6614dce83cdc098f163d7856e7d8ec6e1393f4ab..5c2248510b7cc2867a3e22a4c1adce2acdec1d4d 100644 (file)
@@ -96,21 +96,48 @@ struct vigs_server
 
     struct vigs_plane planes[VIGS_MAX_PLANES];
 
-    QemuMutex dpy_mutex;
+    QemuMutex capture_mutex;
+
+    bool is_capturing;
+
+    uint32_t capture_fence_seq;
+
+    struct
+    {
+        uint8_t *data;
+        uint32_t width;
+        uint32_t height;
+        uint32_t stride;
+        vigsp_surface_format format;
+        bool dirty;
+    } capture_buffers[2], *captured;
 
     /*
      * @}
      */
+
+    bool (*begin_update)(struct vigs_server */*server*/,
+                         bool /*is_capturing*/,
+                         bool /*force*/);
+
+    void (*finish_update)(struct vigs_server */*server*/,
+                          bool /*composited*/,
+                          bool /*dirty*/);
+
+    bool (*display)(struct vigs_server */*server*/, bool */*displayed*/);
+
+    void (*destroy)(struct vigs_server */*server*/);
 };
 
-struct vigs_server *vigs_server_create(uint8_t *vram_ptr,
-                                       uint8_t *ram_ptr,
-                                       struct vigs_display_ops *display_ops,
-                                       void *display_user_data,
-                                       struct vigs_backend *backend,
-                                       struct work_queue *render_queue);
+bool vigs_server_init(struct vigs_server *server,
+                      uint8_t *vram_ptr,
+                      uint8_t *ram_ptr,
+                      struct vigs_display_ops *display_ops,
+                      void *display_user_data,
+                      struct vigs_backend *backend,
+                      struct work_queue *render_queue);
 
-void vigs_server_destroy(struct vigs_server *server);
+void vigs_server_cleanup(struct vigs_server *server);
 
 void vigs_server_reset(struct vigs_server *server);
 
@@ -119,4 +146,19 @@ void vigs_server_dispatch(struct vigs_server *server,
 
 bool vigs_server_update_display(struct vigs_server *server, int invalidate_cnt);
 
+bool vigs_server_display(struct vigs_server *server, bool *displayed);
+
+/*
+ * For internal use only.
+ * @{
+ */
+
+bool vigs_server_process_captured(struct vigs_server *server, bool force);
+
+void vigs_server_finish_update_display(struct vigs_server *server, bool dirty);
+
+/*
+ * @}
+ */
+
 #endif
index 991661b4308a585ea7a8e8054bb9e2f777031718..35224c0628f62b1c4f1fc746241eafd33a1627a1 100644 (file)
@@ -366,6 +366,7 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend *
 
 static bool vigs_sw_backend_composite(struct vigs_surface *surface,
                                       const struct vigs_plane *planes,
+                                      bool planes_dirty,
                                       uint8_t *display_data)
 {
     struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)surface;
@@ -393,6 +394,12 @@ static void vigs_sw_backend_batch_end(struct vigs_backend *backend)
 {
 }
 
+static bool vigs_sw_backend_display(struct vigs_backend *backend,
+                                    uint8_t *display_data)
+{
+    return false;
+}
+
 static void vigs_sw_backend_destroy(struct vigs_backend *backend)
 {
     struct vigs_sw_backend *sw_backend = (struct vigs_sw_backend*)backend;
@@ -413,6 +420,7 @@ struct vigs_backend *vigs_sw_backend_create(void)
     backend->base.create_surface = &vigs_sw_backend_create_surface;
     backend->base.composite = &vigs_sw_backend_composite;
     backend->base.batch_end = &vigs_sw_backend_batch_end;
+    backend->base.display = &vigs_sw_backend_display;
     backend->base.destroy = &vigs_sw_backend_destroy;
 
     return &backend->base;
index 44fb785ccdae0bdf10dcd15a3f378ec684a0268e..87648e34738a04ff3893a331c78217cd34edd215 100644 (file)
@@ -45,6 +45,13 @@ void qt5_graphic_hw_invalidate(void)
     graphic_hw_invalidate(NULL);
 }
 
+int qt5_graphic_hw_display(void)
+{
+    console_ch_t displayed = 0;
+    graphic_hw_text_update(NULL, &displayed);
+    return displayed;
+}
+
 static void qt5_update(DisplayChangeListener *dcl,
                        int x, int y, int w, int h)
 {
@@ -67,9 +74,8 @@ static void qt5_switch(DisplayChangeListener *dcl,
 
 static void qt5_refresh(DisplayChangeListener *dcl)
 {
-    qt5_pre_refresh_internal();
     graphic_hw_update(dcl->con);
-    qt5_post_refresh_internal();
+    qt5_refresh_internal();
 }
 
 static void qt5_mouse_warp(DisplayChangeListener *dcl,
index 7f4b2337fb7b898bf3c2436ddc87383aec3484ab..cb9b595642551b009a39148441212c31238a32b2 100644 (file)
@@ -51,7 +51,7 @@ void qMessageOutput(QtMsgType, const QMessageLogContext &, const QString &);
 void loadSkinFormFromXML(QFile *, UIInformation *);
 void loadControllerFormFromXML(QFile *, UIInformation *);
 
-static QApplication *app;
+QApplication *qt5App = NULL;
 
 static int argc = 0;
 static char *argv[0];
@@ -124,7 +124,7 @@ void qt5_early_prepare(void)
     Q_INIT_RESOURCE(resource);
     qInstallMessageHandler(qMessageOutput);
 
-    app = new QApplication(argc, argv);
+    qt5App = new QApplication(argc, argv);
 }
 
 void qt5_prepare(void)
@@ -148,15 +148,9 @@ void qt5_switch_internal(void)
 {
 }
 
-void qt5_pre_refresh_internal(void)
+void qt5_refresh_internal(void)
 {
-    mainwindow->makeCurrent(true);
-}
-
-void qt5_post_refresh_internal(void)
-{
-    mainwindow->makeCurrent(false);
-    app->processEvents();
+    qt5App->processEvents();
 }
 
 void qMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
index bb6619fed0cbd1aa051657d0f5bed4ef14d2eb1f..1c7af9e1f32e748509f451edc52265171b4dc56f 100644 (file)
 extern "C" {
 #endif
 void qt5_graphic_hw_invalidate(void);
+int qt5_graphic_hw_display(void);
 void qt5_early_prepare(void);
 void qt5_prepare(void);
 
 void qt5_update_internal(void *data, int width, int height);
 void qt5_switch_internal(void);
-void qt5_pre_refresh_internal(void);
-void qt5_post_refresh_internal(void);
+void qt5_refresh_internal(void);
 #ifdef __cplusplus
 }
 #endif
index 6c95f117f0c2399d2ffd9944757d8e2224bad57c..42b060c325453c642579bbd505cc7781556dfc38 100644 (file)
@@ -56,10 +56,21 @@ void DisplayWidget::scale(int scale)
 
 void DisplayWidget::paintEvent(QPaintEvent *event)
 {
+    /*
+     * We offload rendering to separate thread, this must be
+     * a no-op, see: http://qt-project.org/doc/qt-5/QGLWidget.html:
+     * "3. Using QPainter to draw into a QGLWidget in a thread"
+     */
 }
 
 void DisplayWidget::resizeEvent(QResizeEvent *event)
 {
+    /*
+     * We offload rendering to separate thread, this must be
+     * a no-op, see: http://qt-project.org/doc/qt-5/QGLWidget.html:
+     * "3. Using QPainter to draw into a QGLWidget in a thread"
+     */
+
     qDebug("resize display");
 
     //QGLWidget::resizeEvent(event); /* initializeGL */
index 6c7fff83ffb043cbebe0368e3093830af58e022e..7dbcc88e5aa6c34950bdcbc7e9ddfe2862a6f22b 100644 (file)
@@ -3,48 +3,35 @@
 #include "mainwindow.h"
 #include "skinform.h"
 
+extern "C" {
+int qt5_graphic_hw_display(void);
+}
+
 QOpenGLContext *qt5GLContext = NULL;
 QSurfaceFormat qt5GLFormat;
 
 DisplaySwapper::DisplaySwapper(QGLContext* context, QObject* parent)
 : QObject(parent),
   context(context),
-  swapping(false)
-{
-}
-
-void DisplaySwapper::lock()
+  terminating(false)
 {
-    m.lock();
-
-    while (swapping) {
-        c.wait(&m);
-    }
-
-    m.unlock();
 }
 
-void DisplaySwapper::unlock()
-{
-    swapping = true;
-}
-
-void DisplaySwapper::swapBuffers()
+void DisplaySwapper::display()
 {
+    /*
+     * TODO: Currently qt5 skin doesn't terminate properly,
+     * check this once proper termination is implemented.
+     */
     context->makeCurrent();
-    context->swapBuffers();
+    while (!terminating) {
+        if (qt5_graphic_hw_display()) {
+            context->swapBuffers();
+        }
+    }
     context->doneCurrent();
-
-    context->moveToThread(qApp->thread());
-
-    m.lock();
-    swapping = false;
-    m.unlock();
-
-    c.wakeAll();
 }
 
-
 MainWindow::MainWindow(UIInformation *uiInfo, QWidget *parent) :
     QWidget(parent)
 {
@@ -121,11 +108,16 @@ MainWindow::MainWindow(UIInformation *uiInfo, QWidget *parent) :
     /* swapper */
     swapperThread = new QThread(this);
 
+    context->doneCurrent();
+    context->moveToThread(swapperThread);
+
     swapper = new DisplaySwapper(context);
     swapper->moveToThread(swapperThread);
     connect(swapperThread, &QThread::finished, swapper, &QObject::deleteLater);
 
     swapperThread->start();
+
+    QMetaObject::invokeMethod(swapper, "display", Qt::QueuedConnection);
 }
 
 QLabel *MainWindow::getLabel()
@@ -133,19 +125,6 @@ QLabel *MainWindow::getLabel()
     return label;
 }
 
-void MainWindow::makeCurrent(bool value)
-{
-    if (value) {
-        swapper->lock();
-        display->makeCurrent();
-    } else {
-        display->doneCurrent();
-        swapper->unlock();
-        display->context()->moveToThread(swapperThread);
-        QMetaObject::invokeMethod(swapper, "swapBuffers", Qt::QueuedConnection);
-    }
-}
-
 void MainWindow::showContextMenu(const QPoint& pos)
 {
     QAction* selectedItem = 0;
@@ -233,10 +212,6 @@ void MainWindow::scale(int scale)
     adjustSize();
 }
 
-void MainWindow::updateSkin() // TODO: temp
-{
-}
-
 void MainWindow::setRegion(QImage baseImage)
 {
     //qDebug("set region");
@@ -256,6 +231,9 @@ MainWindow::~MainWindow()
 {
     qDebug("destory main window");
 
+    swapper->setTerminating();
+    qt5_graphic_hw_invalidate();
+
     swapperThread->quit();
     swapperThread->wait();
 }
index 71cda0c7b31a180a5644ac01d158cacd336436c7..281c99a277aa21130561e05dbbff2c36eed63c7a 100644 (file)
@@ -26,17 +26,14 @@ class DisplaySwapper : public QObject
 public:
     DisplaySwapper(QGLContext* context, QObject* parent = 0);
 
-    void lock();
-    void unlock();
+    inline void setTerminating() { terminating = true; }
 
 public slots:
-    void swapBuffers();
+    void display();
 
 private:
     QGLContext *context;
-    QMutex m;
-    QWaitCondition c;
-    bool swapping;
+    bool terminating;
 };
 
 class MainWindow : public QWidget
@@ -57,15 +54,12 @@ public:
     UIInformation *uiInfo;
     QLabel *getLabel();
 
-    void makeCurrent(bool value);
-
 public slots:
     void showContextMenu(const QPoint& pos);
 
 protected:
     void resizeEvent(QResizeEvent *event);
 
-    void updateSkin();
     void setRegion(QImage baseImage);
     void closeEvent(QCloseEvent *);
     QLabel *label;