From: Vasiliy Ulyanov Date: Tue, 14 Oct 2014 12:34:52 +0000 (+0400) Subject: VIGS: implement screen capture interface for direct rendering X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=63e9157f842b6e4f0a8fa145138d2873ecc1fc96;p=sdk%2Femulator%2Fqemu.git VIGS: implement screen capture interface for direct rendering Change-Id: I04faf08ce4453835ceb459cb6155e90e21b1c7e8 Signed-off-by: Vasiliy Ulyanov --- diff --git a/hw/vigs/vigs_backend.h b/hw/vigs/vigs_backend.h index c300195f35..bbbd90abfe 100644 --- a/hw/vigs/vigs_backend.h +++ b/hw/vigs/vigs_backend.h @@ -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*/, diff --git a/hw/vigs/vigs_device.c b/hw/vigs/vigs_device.c index 90bd2af6aa..8e190df32f 100644 --- a/hw/vigs/vigs_device.c +++ b/hw/vigs/vigs_device.c @@ -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 { diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 24f8b16b78..d80db57170 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -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; diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index 4306420d66..b065dd977c 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -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); diff --git a/hw/vigs/vigs_onscreen_server.c b/hw/vigs/vigs_onscreen_server.c index 984fd1bed2..4c51c17678 100644 --- a/hw/vigs/vigs_onscreen_server.c +++ b/hw/vigs/vigs_onscreen_server.c @@ -29,6 +29,30 @@ #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; } diff --git a/hw/vigs/vigs_onscreen_server.h b/hw/vigs/vigs_onscreen_server.h index a3b443332c..57e6abeaad 100644 --- a/hw/vigs/vigs_onscreen_server.h +++ b/hw/vigs/vigs_onscreen_server.h @@ -32,6 +32,17 @@ #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); diff --git a/hw/vigs/vigs_qt5.cpp b/hw/vigs/vigs_qt5.cpp index 2df737510f..7bef344997 100644 --- a/hw/vigs/vigs_qt5.cpp +++ b/hw/vigs/vigs_qt5.cpp @@ -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() */ +} diff --git a/hw/vigs/vigs_qt5.h b/hw/vigs/vigs_qt5.h index 741cf56197..57b4a5b690 100644 --- a/hw/vigs/vigs_qt5.h +++ b/hw/vigs/vigs_qt5.h @@ -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 diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c index 4839e69f5d..50488f9d39 100644 --- a/hw/vigs/vigs_server.c +++ b/hw/vigs/vigs_server.c @@ -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; diff --git a/hw/vigs/vigs_server.h b/hw/vigs/vigs_server.h index 5c2248510b..8b6af81363 100644 --- a/hw/vigs/vigs_server.h +++ b/hw/vigs/vigs_server.h @@ -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. * @{ diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c index fa8cfb8566..2261ebcb71 100644 --- a/hw/vigs/vigs_sw_backend.c +++ b/hw/vigs/vigs_sw_backend.c @@ -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;