VIGS: implement screen capture interface for direct rendering 42/29842/1
authorVasiliy Ulyanov <v.ulyanov@samsung.com>
Tue, 14 Oct 2014 12:34:52 +0000 (16:34 +0400)
committerVasiliy Ulyanov <v.ulyanov@samsung.com>
Wed, 5 Nov 2014 07:05:58 +0000 (10:05 +0300)
Change-Id: I04faf08ce4453835ceb459cb6155e90e21b1c7e8
Signed-off-by: Vasiliy Ulyanov <v.ulyanov@samsung.com>
hw/vigs/vigs_backend.h
hw/vigs/vigs_device.c
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_gl_backend_glx.c
hw/vigs/vigs_onscreen_server.c
hw/vigs/vigs_onscreen_server.h
hw/vigs/vigs_qt5.cpp
hw/vigs/vigs_qt5.h
hw/vigs/vigs_server.c
hw/vigs/vigs_server.h
hw/vigs/vigs_sw_backend.c

index c300195f3531ecfa24c653a23961b3fd45d479e3..bbbd90abfed9f169bc8ca2de0f67d87ec4803f10 100644 (file)
@@ -54,6 +54,9 @@ struct vigs_backend
                       bool /*planes_dirty*/,
                       uint8_t */*display_data*/);
 
+    bool (*capture)(struct vigs_surface */*surface*/,
+                    void */*pixels*/);
+
     void (*batch_end)(struct vigs_backend */*backend*/);
 
     bool (*display)(struct vigs_backend */*backend*/,
index 90bd2af6aa8a2babc609d1afac0f27dc224674e1..8e190df32fdcabdb9a7be0f5bff7ab1af1f8224a 100644 (file)
@@ -291,6 +291,23 @@ static void vigs_io_write(void *opaque, hwaddr offset,
     }
 }
 
+static void vigs_register_capture_request_listener(void *listener,
+                                                   void (*handler)(void *))
+{
+    return vigs_qt5_register_capture_request_listener(listener, handler);
+}
+
+static void vigs_unregister_capture_request_listener(void *listener)
+{
+    return vigs_qt5_unregister_capture_request_listener(listener);
+}
+
+static void vigs_process_captured(bool captured, void *pixels,
+                                  uint32_t width, uint32_t height)
+{
+    return vigs_qt5_process_captured(captured, pixels, width, height);
+}
+
 static struct GraphicHwOps vigs_hw_ops =
 {
     .invalidate = vigs_hw_invalidate,
@@ -319,6 +336,13 @@ static struct vigs_display_ops vigs_dpy_ops =
     .fence_ack = vigs_fence_ack,
 };
 
+static struct vigs_onscreen_server_capture_ops vigs_capture_ops =
+{
+    .register_listener = vigs_register_capture_request_listener,
+    .unregister_listener = vigs_unregister_capture_request_listener,
+    .process_captured = vigs_process_captured,
+};
+
 static int vigs_device_init(PCIDevice *dev)
 {
     VIGSState *s = DO_UPCAST(VIGSState, dev, dev);
@@ -457,6 +481,7 @@ static int vigs_device_init(PCIDevice *dev)
                                                 memory_region_get_ram_ptr(&s->ram_bar),
                                                 &vigs_dpy_ops,
                                                 s,
+                                                &vigs_capture_ops,
                                                 backend,
                                                 wqobj->wq);
     } else {
index 24f8b16b786b65f917418a7ee64a4e16fe415807..d80db5717001b906a31d07e0634026475f841c69 100644 (file)
@@ -2234,6 +2234,44 @@ out:
     return false;
 }
 
+static bool vigs_gl_backend_capture(struct vigs_surface *surface,
+                                    void *pixels)
+{
+    struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
+
+    if (gl_backend->read_pixels_make_current(gl_backend, true)) {
+
+        if (!gl_backend->dpy_fb) {
+            gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb);
+
+            if (!gl_backend->dpy_fb) {
+                VIGS_LOG_ERROR("cannot create capture FB");
+
+                gl_backend->read_pixels_make_current(gl_backend, false);
+
+                return false;
+            }
+
+        }
+
+        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,
+                               pixels);
+        gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
+
+        gl_backend->read_pixels_make_current(gl_backend, false);
+
+        return true;
+    }
+
+    return false;
+}
+
 static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
@@ -2623,6 +2661,7 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
     gl_backend->base.batch_start = &vigs_gl_backend_batch_start;
     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
     gl_backend->base.composite = &vigs_gl_backend_composite;
+    gl_backend->base.capture = &vigs_gl_backend_capture;
     gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
     gl_backend->base.display = &vigs_gl_backend_display;
 
index 4306420d660ef4e5192c749b45a44bd0853ebc4f..b065dd977c8f7b475c9b1ffb8f95840f6de84f56 100644 (file)
@@ -552,6 +552,19 @@ struct vigs_backend *vigs_gl_backend_create(void *display)
         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,
+                                                gl_backend_glx->ctx,
+                                                &gl_backend_glx->read_pixels_ctx)) {
+            goto fail2;
+        }
     } else {
         config = vigs_gl_backend_glx_get_config(gl_backend_glx);
 
index 984fd1bed2d8d87eccf5de8130a5537c65d1eeb9..4c51c17678793dbb125b9fae9a9734c82fcf6f49 100644 (file)
 
 #include "vigs_onscreen_server.h"
 #include "vigs_backend.h"
+#include "vigs_log.h"
+#include "work_queue.h"
+
+struct vigs_capture_work_item
+{
+    struct work_queue_item base;
+
+    struct vigs_onscreen_server *server;
+};
+
+static void vigs_onscreen_server_capture_work(struct work_queue_item *wq_item)
+{
+    struct vigs_capture_work_item *item = (struct vigs_capture_work_item*)wq_item;
+    struct vigs_onscreen_server *server = item->server;
+    uint32_t width, height;
+    bool captured;
+    void *pixels;
+
+    pixels = vigs_server_get_capture_buffer(&server->base, &width, &height);
+    captured = server->base.backend->capture(server->base.root_sfc, pixels);
+    server->capture_ops->process_captured(captured, pixels, width, height);
+
+    g_free(item);
+}
 
 static bool vigs_onscreen_server_begin_update(struct vigs_server *server,
                                               bool is_capturing,
@@ -136,11 +160,27 @@ static bool vigs_onscreen_server_display(struct vigs_server *server,
     return false;
 }
 
+static void vigs_onscreen_server_capture(void *data)
+{
+    struct vigs_onscreen_server *server = (struct vigs_onscreen_server*)data;
+    struct vigs_capture_work_item *item;
+
+    item = g_malloc(sizeof(*item));
+
+    work_queue_item_init(&item->base, &vigs_onscreen_server_capture_work);
+
+    item->server = server;
+
+    work_queue_add_item(server->capture_queue, &item->base);
+}
+
 static void vigs_onscreen_server_destroy(struct vigs_server *server)
 {
     struct vigs_onscreen_server *onscreen_server =
         (struct vigs_onscreen_server*)server;
 
+    onscreen_server->capture_ops->unregister_listener(onscreen_server);
+
     qemu_cond_destroy(&onscreen_server->cond);
     qemu_mutex_destroy(&onscreen_server->mutex);
 
@@ -153,6 +193,7 @@ 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_onscreen_server_capture_ops *capture_ops,
                                                 struct vigs_backend *backend,
                                                 struct work_queue *render_queue)
 {
@@ -175,5 +216,10 @@ struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr,
     server->base.display = &vigs_onscreen_server_display;
     server->base.destroy = &vigs_onscreen_server_destroy;
 
+    server->capture_queue = work_queue_create("capture_queue");
+    server->capture_ops = capture_ops;
+    server->capture_ops->register_listener(server,
+                                           vigs_onscreen_server_capture);
+
     return &server->base;
 }
index a3b443332c6c57afe8c85d85dea3fba2eabc35c7..57e6abeaadadb12eddf976cb5fee98e33b2f9a8b 100644 (file)
 
 #include "vigs_server.h"
 
+struct vigs_onscreen_server_capture_ops
+{
+    void (*register_listener)(void */*listener*/,
+                              void (*handler)(void */*listener*/));
+    void (*unregister_listener)(void */*listener*/);
+    void (*process_captured)(bool /*captured*/,
+                             void */*pixels*/,
+                             uint32_t /*width*/,
+                             uint32_t /*height*/);
+};
+
 struct vigs_onscreen_server
 {
     struct vigs_server base;
@@ -43,12 +54,16 @@ struct vigs_onscreen_server
     bool dirty;
 
     int invalidate_cnt;
+
+    struct vigs_onscreen_server_capture_ops *capture_ops;
+    struct work_queue *capture_queue;
 };
 
 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_onscreen_server_capture_ops *capture_ops,
                                                 struct vigs_backend *backend,
                                                 struct work_queue *render_queue);
 
index 2df737510f0ef2e56883e17584224f2a85c980cf..7bef34499713980f20d9f942037645a5d5ac390c 100644 (file)
@@ -138,3 +138,20 @@ void *vigs_qt5_gl_context_create(bool is_gl2)
 
     return ret;
 }
+
+void vigs_qt5_register_capture_request_listener(void *listener,
+                                                void (*handler)(void *))
+{
+    /* TODO implement: mainwin->register() */
+}
+
+void vigs_qt5_unregister_capture_request_listener(void *listener)
+{
+    /* TODO implement: mainwin->unregister() */
+}
+
+void vigs_qt5_process_captured(bool captured, void *pixels,
+                               int width, int height)
+{
+    /* TODO implement: mainwin->process() */
+}
index 741cf56197e49e00890fd7e69b9e8f93b190a1ff..57b4a5b690881f74bb4437e7a68ce91be824c096 100644 (file)
@@ -40,6 +40,12 @@ void *vigs_qt5_display(void);
 
 void *vigs_qt5_gl_context_create(bool is_gl2);
 
+void vigs_qt5_register_capture_request_listener(void *listener,
+                                                void (*handler)(void *));
+void vigs_qt5_unregister_capture_request_listener(void *listener);
+void vigs_qt5_process_captured(bool captured, void *pixels,
+                               int width, int height);
+
 #ifdef __cplusplus
 };
 #endif
index 4839e69f5d0db9b460b77d9ac4b0a18806b11e96..50488f9d39819dd9c81024e516ddf97ff6625197 100644 (file)
@@ -771,6 +771,17 @@ bool vigs_server_display(struct vigs_server *server, bool *displayed)
     return server->display(server, displayed);
 }
 
+void *vigs_server_get_capture_buffer(struct vigs_server *server,
+                                     uint32_t *width, uint32_t *height)
+{
+    int index = (&server->capture_buffers[0] == server->captured) ? 1 : 0;
+
+    *width = server->capture_buffers[index].width;
+    *height = server->capture_buffers[index].height;
+
+    return server->capture_buffers[index].data;
+}
+
 bool vigs_server_process_captured(struct vigs_server *server, bool force)
 {
     bool updated = false;
index 5c2248510b7cc2867a3e22a4c1adce2acdec1d4d..8b6af8136396b28feaefda58095b2227e6dcbd0d 100644 (file)
@@ -148,6 +148,9 @@ bool vigs_server_update_display(struct vigs_server *server, int invalidate_cnt);
 
 bool vigs_server_display(struct vigs_server *server, bool *displayed);
 
+void *vigs_server_get_capture_buffer(struct vigs_server *server,
+                                     uint32_t *width, uint32_t *height);
+
 /*
  * For internal use only.
  * @{
index fa8cfb85663f18f053233419f292fd45751377ac..2261ebcb714314b08e29fbd286f6e047e429b336 100644 (file)
@@ -401,6 +401,14 @@ static bool vigs_sw_backend_composite(struct vigs_surface *surface,
     return true;
 }
 
+static bool vigs_sw_backend_capture(struct vigs_surface *surface,
+                                    void *pixels)
+{
+    vigs_sw_backend_composite(surface, NULL, false, pixels);
+
+    return true;
+}
+
 static void vigs_sw_backend_batch_end(struct vigs_backend *backend)
 {
 }
@@ -430,6 +438,7 @@ struct vigs_backend *vigs_sw_backend_create(void)
     backend->base.batch_start = &vigs_sw_backend_batch_start;
     backend->base.create_surface = &vigs_sw_backend_create_surface;
     backend->base.composite = &vigs_sw_backend_composite;
+    backend->base.capture = &vigs_sw_backend_capture;
     backend->base.batch_end = &vigs_sw_backend_batch_end;
     backend->base.display = &vigs_sw_backend_display;
     backend->base.destroy = &vigs_sw_backend_destroy;