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*/,
}
}
+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,
.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);
memory_region_get_ram_ptr(&s->ram_bar),
&vigs_dpy_ops,
s,
+ &vigs_capture_ops,
backend,
wqobj->wq);
} else {
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;
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;
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);
#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,
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);
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)
{
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;
}
#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;
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);
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() */
+}
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
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;
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.
* @{
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)
{
}
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;