struct winsys_info;
struct vigs_surface;
+typedef void (*vigs_read_pixels_cb)(void */*user_data*/,
+ uint8_t */*pixels*/,
+ uint32_t /*width*/,
+ uint32_t /*height*/,
+ uint32_t /*stride*/,
+ vigsp_surface_format /*format*/);
+
struct vigs_backend
{
struct winsys_info *ws_info;
vigsp_surface_format /*format*/,
vigsp_surface_id /*id*/);
+ void (*read_pixels)(struct vigs_surface */*surface*/,
+ uint8_t */*pixels*/,
+ vigs_read_pixels_cb /*cb*/,
+ void */*user_data*/);
+
void (*batch_end)(struct vigs_backend */*backend*/);
void (*destroy)(struct vigs_backend */*backend*/);
#include "vigs_utils.h"
#include "vigs_ref.h"
#include "winsys_gl.h"
+#include "work_queue.h"
struct vigs_gl_surface;
+struct vigs_gl_backend_read_pixels_work_item
+{
+ struct work_queue_item base;
+
+ struct vigs_gl_backend *backend;
+
+ vigs_read_pixels_cb cb;
+ void *user_data;
+ uint8_t *pixels;
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+ vigsp_surface_format format;
+};
+
struct vigs_winsys_gl_surface
{
struct winsys_gl_surface base;
*/
static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc,
- uint32_t x,
- uint32_t y,
- uint32_t width,
- uint32_t height,
uint8_t *pixels)
{
struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend;
GLfloat *vert_coords;
GLfloat *tex_coords;
- VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
- x, y, width, height);
-
if (!ws_sfc->tex) {
VIGS_LOG_TRACE("skipping blank read");
goto out;
gl_backend->DisableClientState(GL_VERTEX_ARRAY);
gl_backend->PixelStorei(GL_PACK_ALIGNMENT, ws_sfc->tex_bpp);
- gl_backend->ReadPixels(x, y, width, height,
+ gl_backend->ReadPixels(0, 0, sfc_w, sfc_h,
ws_sfc->tex_format, ws_sfc->tex_type,
pixels);
return NULL;
}
+static void vigs_gl_backend_read_pixels_work(struct work_queue_item *wq_item)
+{
+ struct vigs_gl_backend_read_pixels_work_item *item = (struct vigs_gl_backend_read_pixels_work_item*)wq_item;
+ struct vigs_gl_backend *backend = item->backend;
+
+ VIGS_LOG_TRACE("enter");
+
+ if (backend->read_pixels_make_current(backend, true)) {
+ uint8_t *pixels;
+
+ backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, backend->pbo);
+
+ pixels = backend->MapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+
+ if (pixels) {
+ memcpy(item->pixels, pixels, item->stride * item->height);
+
+ if (!backend->UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB)) {
+ VIGS_LOG_CRITICAL("glUnmapBuffer failed");
+ }
+ } else {
+ VIGS_LOG_CRITICAL("glMapBuffer failed");
+ }
+
+ backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+ backend->read_pixels_make_current(backend, false);
+ }
+
+ item->cb(item->user_data,
+ item->pixels, item->width, item->height,
+ item->stride, item->format);
+
+ g_free(item);
+}
+
+static void vigs_gl_backend_read_pixels(struct vigs_surface *surface,
+ uint8_t *pixels,
+ vigs_read_pixels_cb cb,
+ void *user_data)
+{
+ struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
+ uint32_t size = surface->stride * surface->ws_sfc->height;
+ struct vigs_gl_backend_read_pixels_work_item *item;
+
+ VIGS_LOG_TRACE("enter");
+
+ gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, gl_backend->pbo);
+
+ if (size > gl_backend->pbo_size) {
+ gl_backend->pbo_size = size;
+ gl_backend->BufferData(GL_PIXEL_PACK_BUFFER_ARB,
+ size,
+ 0,
+ GL_STREAM_READ);
+ }
+
+ surface->read_pixels(surface, NULL);
+
+ gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+
+ /*
+ * That's a tricky one, if we don't do this then it's not
+ * guaranteed that PBO will actually be updated by the time
+ * 'vigs_gl_backend_read_pixels_work' runs and since
+ * 'vigs_gl_backend_read_pixels_work' uses another OpenGL context
+ * we might get old results.
+ */
+ gl_backend->Finish();
+
+ item = g_malloc(sizeof(*item));
+
+ work_queue_item_init(&item->base, &vigs_gl_backend_read_pixels_work);
+
+ item->backend = gl_backend;
+
+ item->cb = cb;
+ item->user_data = user_data;
+ item->pixels = pixels;
+ item->width = surface->ws_sfc->width;
+ item->height = surface->ws_sfc->height;
+ item->stride = surface->stride;
+ item->format = surface->format;
+
+ work_queue_add_item(gl_backend->read_pixels_queue, &item->base);
+}
+
static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
{
struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend;
goto fail;
}
+ gl_backend->GenBuffers(1, &gl_backend->pbo);
+
+ if (!gl_backend->pbo) {
+ VIGS_LOG_CRITICAL("cannot create read_pixels PBO");
+ goto fail;
+ }
+
gl_backend->base.batch_start = &vigs_gl_backend_batch_start;
gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
+ gl_backend->base.read_pixels = &vigs_gl_backend_read_pixels;
gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
gl_backend->make_current(gl_backend, false);
vigs_vector_init(&gl_backend->v1, 0);
vigs_vector_init(&gl_backend->v2, 0);
+ gl_backend->read_pixels_queue = work_queue_create();
+
return true;
fail:
void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend)
{
+ work_queue_destroy(gl_backend->read_pixels_queue);
+
+ if (gl_backend->make_current(gl_backend, true)) {
+ gl_backend->DeleteBuffers(1, &gl_backend->pbo);
+
+ gl_backend->make_current(gl_backend, false);
+ }
+
vigs_vector_cleanup(&gl_backend->v2);
vigs_vector_cleanup(&gl_backend->v1);
}
#include <GL/glext.h>
#include "winsys_gl.h"
+struct work_queue;
+
struct vigs_gl_backend
{
struct vigs_backend base;
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.
* @{
void (GLAPIENTRY *BlendFunc)(GLenum sfactor, GLenum dfactor);
void (GLAPIENTRY *CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
void (GLAPIENTRY *BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+ void (GLAPIENTRY *GenBuffers)(GLsizei n, GLuint *buffers);
+ void (GLAPIENTRY *DeleteBuffers)(GLsizei n, const GLuint *buffers);
+ void (GLAPIENTRY *BindBuffer)(GLenum target, GLuint buffer);
+ void (GLAPIENTRY *BufferData)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+ GLvoid *(GLAPIENTRY *MapBuffer)(GLenum target, GLenum access);
+ GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum target);
/*
* @}
/*
* @}
*/
+
+ /*
+ *
+ */
+
+ struct work_queue *read_pixels_queue;
+
+ GLuint pbo;
+ uint32_t pbo_size;
};
bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend);
struct vigs_gl_backend base;
void *handle;
+ AGLContext read_pixels_context;
+ AGLPbuffer read_pixels_surface;
AGLContext context;
AGLPbuffer surface;
AGLPixelFormat pixfmt;
}
static bool vigs_gl_backend_agl_create_surface(struct vigs_gl_backend_agl
- *gl_backend_agl, int config_id)
+ *gl_backend_agl, int config_id,
+ AGLPbuffer *surface)
{
- gl_backend_agl->surface = NULL;
+ aglCreatePBuffer(1, 1, GL_TEXTURE_2D, GL_RGBA, 0,
+ surface);
- aglCreatePBuffer(2048, 2048, GL_TEXTURE_2D, GL_RGBA, 0,
- &gl_backend_agl->surface);
-
- if (!gl_backend_agl->surface) {
+ if (!*surface) {
VIGS_LOG_CRITICAL("aglCreatePBuffer failed");
return false;
}
}
static bool vigs_gl_backend_agl_create_context(struct vigs_gl_backend_agl
- *gl_backend_agl)
+ *gl_backend_agl,
+ AGLContext share_context,
+ AGLContext *context)
{
- gl_backend_agl->context = aglCreateContext(gl_backend_agl->pixfmt, NULL);
+ *context = aglCreateContext(gl_backend_agl->pixfmt, share_context);
- if (!gl_backend_agl->context) {
+ if (!*context) {
VIGS_LOG_CRITICAL("aglCreateContext failed");
return false;
}
aglDestroyPBuffer(gl_backend_agl->surface);
}
+ if (gl_backend_agl->read_pixels_surface) {
+ aglDestroyPBuffer(gl_backend_agl->read_pixels_surface);
+ }
+
if (gl_backend_agl->context) {
aglDestroyContext(gl_backend_agl->context);
}
+ if (gl_backend_agl->read_pixels_context) {
+ aglDestroyContext(gl_backend_agl->read_pixels_context);
+ }
+
if (gl_backend_agl->handle) {
dlclose(gl_backend_agl->handle);
}
return true;
}
+static bool vigs_gl_backend_agl_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
+ bool enable)
+{
+ struct vigs_gl_backend_agl *gl_backend_agl =
+ (struct vigs_gl_backend_agl *)gl_backend;
+ AGLPbuffer buf = NULL;
+ AGLContext context = gl_backend_agl->read_pixels_context;
+
+ if (enable) {
+ buf = gl_backend_agl->read_pixels_surface;
+
+ if (aglSetPBuffer(context, buf, 0, 0, 0) == GL_FALSE) {
+ VIGS_LOG_CRITICAL("aglSetPBuffer failed");
+ return false;
+ }
+
+ if (aglSetCurrentContext(context) == GL_FALSE) {
+ VIGS_LOG_CRITICAL("aglSetCurrentContext failed");
+ aglSetPBuffer(context, NULL, 0, 0, 0);
+ return false;
+ }
+ } else {
+ if (aglSetCurrentContext(NULL) == GL_FALSE) {
+ VIGS_LOG_CRITICAL("aglSetCurrentContext(NULL) failed");
+ return false;
+ }
+ }
+
+ return true;
+}
+
struct vigs_backend *vigs_gl_backend_create(void *display)
{
struct vigs_gl_backend_agl *gl_backend_agl;
VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+ VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+ VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+ VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+ VIGS_GL_GET_PROC(BufferData, glBufferData);
+ VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+ VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
config_id = vigs_gl_backend_agl_choose_config(gl_backend_agl);
goto fail;
}
- if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id)) {
+ if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id,
+ &gl_backend_agl->surface)) {
goto fail;
}
- if (!vigs_gl_backend_agl_create_context(gl_backend_agl)) {
+ if (!vigs_gl_backend_agl_create_surface(gl_backend_agl, config_id,
+ &gl_backend_agl->read_pixels_surface)) {
+ goto fail;
+ }
+
+ if (!vigs_gl_backend_agl_create_context(gl_backend_agl, NULL,
+ &gl_backend_agl->context)) {
+ goto fail;
+ }
+
+ if (!vigs_gl_backend_agl_create_context(gl_backend_agl, gl_backend_agl->context,
+ &gl_backend_agl->read_pixels_context)) {
goto fail;
}
gl_backend_agl->base.base.destroy = &vigs_gl_backend_agl_destroy;
gl_backend_agl->base.has_current = &vigs_gl_backend_agl_has_current;
gl_backend_agl->base.make_current = &vigs_gl_backend_agl_make_current;
+ gl_backend_agl->base.read_pixels_make_current = &vigs_gl_backend_agl_read_pixels_make_current;
gl_backend_agl->base.ws_info.context = &gl_backend_agl->context;
if (!vigs_gl_backend_init(&gl_backend_agl->base)) {
aglDestroyPBuffer(gl_backend_agl->surface);
}
+ if (gl_backend_agl->read_pixels_surface) {
+ aglDestroyPBuffer(gl_backend_agl->read_pixels_surface);
+ }
+
if (gl_backend_agl->context) {
aglDestroyContext(gl_backend_agl->context);
}
+ if (gl_backend_agl->read_pixels_context) {
+ aglDestroyContext(gl_backend_agl->read_pixels_context);
+ }
+
vigs_backend_cleanup(&gl_backend_agl->base.base);
g_free(gl_backend_agl);
Display *dpy;
GLXPbuffer sfc;
GLXContext ctx;
+ GLXPbuffer read_pixels_sfc;
+ GLXContext read_pixels_ctx;
};
static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl_backend_glx)
}
static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_backend_glx,
- GLXFBConfig config)
+ GLXFBConfig config,
+ GLXPbuffer *sfc)
{
int surface_attribs[] =
{
None
};
- gl_backend_glx->sfc = gl_backend_glx->glXCreatePbuffer(gl_backend_glx->dpy,
- config,
- surface_attribs);
+ *sfc = gl_backend_glx->glXCreatePbuffer(gl_backend_glx->dpy,
+ config,
+ surface_attribs);
- if (!gl_backend_glx->sfc) {
+ if (!*sfc) {
VIGS_LOG_CRITICAL("glXCreatePbuffer failed");
return false;
}
}
static bool vigs_gl_backend_glx_create_context(struct vigs_gl_backend_glx *gl_backend_glx,
- GLXFBConfig config)
+ GLXFBConfig config,
+ GLXContext share_ctx,
+ GLXContext *ctx)
{
- gl_backend_glx->ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy,
- config,
- GLX_RGBA_TYPE,
- NULL,
- True);
+ *ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy,
+ config,
+ GLX_RGBA_TYPE,
+ share_ctx,
+ True);
- if (!gl_backend_glx->ctx) {
+ if (!*ctx) {
VIGS_LOG_CRITICAL("glXCreateNewContext failed");
return false;
}
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);
gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+ gl_backend_glx->read_pixels_ctx);
+
+ gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
gl_backend_glx->ctx);
gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+ gl_backend_glx->read_pixels_sfc);
+
+ gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
gl_backend_glx->sfc);
dlclose(gl_backend_glx->handle);
VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+ VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+ VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+ VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+ VIGS_GL_GET_PROC(BufferData, glBufferData);
+ VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+ VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
gl_backend_glx->dpy = x_display;
goto fail2;
}
- if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, config)) {
+ if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
+ config,
+ &gl_backend_glx->sfc)) {
goto fail2;
}
- if (!vigs_gl_backend_glx_create_context(gl_backend_glx, config)) {
+ if (!vigs_gl_backend_glx_create_surface(gl_backend_glx,
+ config,
+ &gl_backend_glx->read_pixels_sfc)) {
goto fail3;
}
+ if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+ config,
+ NULL,
+ &gl_backend_glx->ctx)) {
+ goto fail4;
+ }
+
+ if (!vigs_gl_backend_glx_create_context(gl_backend_glx,
+ config,
+ gl_backend_glx->ctx,
+ &gl_backend_glx->read_pixels_ctx)) {
+ goto fail5;
+ }
+
gl_backend_glx->base.base.destroy = &vigs_gl_backend_glx_destroy;
gl_backend_glx->base.has_current = &vigs_gl_backend_glx_has_current;
gl_backend_glx->base.make_current = &vigs_gl_backend_glx_make_current;
+ gl_backend_glx->base.read_pixels_make_current = &vigs_gl_backend_glx_read_pixels_make_current;
gl_backend_glx->base.ws_info.context = gl_backend_glx->ctx;
if (!vigs_gl_backend_init(&gl_backend_glx->base)) {
- goto fail4;
+ goto fail6;
}
VIGS_LOG_DEBUG("created");
return &gl_backend_glx->base.base;
-fail4:
+fail6:
+ gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
+ gl_backend_glx->read_pixels_ctx);
+fail5:
gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy,
gl_backend_glx->ctx);
+fail4:
+ gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
+ gl_backend_glx->read_pixels_sfc);
fail3:
gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy,
gl_backend_glx->sfc);
PFNWGLGETPROCADDRESSPROC wglGetProcAddress;
PFNWGLMAKECURRENTPROC wglMakeCurrent;
PFNWGLGETCURRENTCONTEXTPROC wglGetCurrentContext;
+ PFNWGLSHARELISTSPROC wglShareLists;
/* WGL extensions */
PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT;
HPBUFFERARB sfc;
HDC sfc_dc;
HGLRC ctx;
+ HPBUFFERARB read_pixels_sfc;
+ HDC read_pixels_sfc_dc;
+ HGLRC read_pixels_ctx;
};
static int vigs_gl_backend_wgl_choose_config(struct vigs_gl_backend_wgl *gl_backend_wgl)
}
static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_backend_wgl,
- int config_id)
+ int config_id,
+ HPBUFFERARB *sfc,
+ HDC *sfc_dc)
{
int surface_attribs[] = {
WGL_PBUFFER_LARGEST_ARB, FALSE,
0
};
- gl_backend_wgl->sfc =
- gl_backend_wgl->wglCreatePbufferARB(gl_backend_wgl->dc, config_id,
- 1, 1, surface_attribs);
+ *sfc = gl_backend_wgl->wglCreatePbufferARB(gl_backend_wgl->dc, config_id,
+ 1, 1, surface_attribs);
- if (!gl_backend_wgl->sfc) {
+ if (!*sfc) {
VIGS_LOG_CRITICAL("wglCreatePbufferARB failed");
return false;
}
- gl_backend_wgl->sfc_dc = gl_backend_wgl->wglGetPbufferDCARB(gl_backend_wgl->sfc);
+ *sfc_dc = gl_backend_wgl->wglGetPbufferDCARB(*sfc);
- if (!gl_backend_wgl->sfc_dc) {
+ if (!*sfc_dc) {
VIGS_LOG_CRITICAL("wglGetPbufferDCARB failed");
return false;
}
return true;
}
-static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_backend_wgl)
+static bool vigs_gl_backend_wgl_create_context(struct vigs_gl_backend_wgl *gl_backend_wgl,
+ HGLRC share_ctx,
+ HGLRC *ctx)
{
- gl_backend_wgl->ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc);
+ *ctx = gl_backend_wgl->wglCreateContext(gl_backend_wgl->dc);
- if (!gl_backend_wgl->ctx) {
+ if (!*ctx) {
VIGS_LOG_CRITICAL("wglCreateContext failed");
return false;
}
+ if (share_ctx) {
+ if (!gl_backend_wgl->wglShareLists(share_ctx, *ctx)) {
+ VIGS_LOG_CRITICAL("wglShareLists failed");
+ gl_backend_wgl->wglDeleteContext(*ctx);
+ *ctx = NULL;
+ return false;
+ }
+ }
+
return true;
}
return true;
}
+static bool vigs_gl_backend_wgl_read_pixels_make_current(struct vigs_gl_backend *gl_backend,
+ bool enable)
+{
+ struct vigs_gl_backend_wgl *gl_backend_wgl =
+ (struct vigs_gl_backend_wgl*)gl_backend;
+
+ if (enable) {
+ if (!gl_backend_wgl->wglMakeCurrent(gl_backend_wgl->read_pixels_sfc_dc, gl_backend_wgl->read_pixels_ctx)) {
+ VIGS_LOG_CRITICAL("wglMakeCurrent failed");
+ return false;
+ }
+ } else {
+ if (!gl_backend_wgl->wglMakeCurrent(NULL, NULL)) {
+ VIGS_LOG_CRITICAL("wglMakeCurrent failed");
+ return false;
+ }
+ }
+
+ return true;
+}
+
static void vigs_gl_backend_wgl_destroy(struct vigs_backend *backend)
{
struct vigs_gl_backend_wgl *gl_backend_wgl = (struct vigs_gl_backend_wgl*)backend;
vigs_gl_backend_cleanup(&gl_backend_wgl->base);
gl_backend_wgl->wglDeleteContext(gl_backend_wgl->ctx);
+ gl_backend_wgl->wglDeleteContext(gl_backend_wgl->read_pixels_ctx);
gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->sfc, gl_backend_wgl->sfc_dc);
gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->sfc);
+ gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->read_pixels_sfc, gl_backend_wgl->read_pixels_sfc_dc);
+ gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->read_pixels_sfc);
ReleaseDC(gl_backend_wgl->win, gl_backend_wgl->dc);
DestroyWindow(gl_backend_wgl->win);
VIGS_WGL_GET_PROC(PFNWGLGETPROCADDRESSPROC, wglGetProcAddress, fail);
VIGS_WGL_GET_PROC(PFNWGLMAKECURRENTPROC, wglMakeCurrent, fail);
VIGS_WGL_GET_PROC(PFNWGLGETCURRENTCONTEXTPROC, wglGetCurrentContext, fail);
+ VIGS_WGL_GET_PROC(PFNWGLSHARELISTSPROC, wglShareLists, fail);
tmp_win = CreateWindow(VIGS_WGL_WIN_CLASS, "VIGSWin",
WS_DISABLED | WS_POPUP,
VIGS_GL_GET_PROC(BlendFunc, glBlendFunc);
VIGS_GL_GET_PROC(CopyTexImage2D, glCopyTexImage2D);
VIGS_GL_GET_PROC(BlitFramebuffer, glBlitFramebufferEXT);
+ VIGS_GL_GET_PROC(GenBuffers, glGenBuffers);
+ VIGS_GL_GET_PROC(DeleteBuffers, glDeleteBuffers);
+ VIGS_GL_GET_PROC(BindBuffer, glBindBuffer);
+ VIGS_GL_GET_PROC(BufferData, glBufferData);
+ VIGS_GL_GET_PROC(MapBuffer, glMapBuffer);
+ VIGS_GL_GET_PROC(UnmapBuffer, glUnmapBuffer);
gl_backend_wgl->wglMakeCurrent(NULL, NULL);
gl_backend_wgl->wglDeleteContext(tmp_ctx);
goto fail;
}
- if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id)) {
+ if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
+ &gl_backend_wgl->sfc,
+ &gl_backend_wgl->sfc_dc)) {
goto fail;
}
- if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl)) {
+ if (!vigs_gl_backend_wgl_create_surface(gl_backend_wgl, config_id,
+ &gl_backend_wgl->read_pixels_sfc,
+ &gl_backend_wgl->read_pixels_sfc_dc)) {
+ goto fail;
+ }
+
+ if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
+ NULL,
+ &gl_backend_wgl->ctx)) {
+ goto fail;
+ }
+
+ if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl,
+ gl_backend_wgl->ctx,
+ &gl_backend_wgl->read_pixels_ctx)) {
goto fail;
}
gl_backend_wgl->base.base.destroy = &vigs_gl_backend_wgl_destroy;
gl_backend_wgl->base.has_current = &vigs_gl_backend_wgl_has_current;
gl_backend_wgl->base.make_current = &vigs_gl_backend_wgl_make_current;
+ gl_backend_wgl->base.read_pixels_make_current = &vigs_gl_backend_wgl_read_pixels_make_current;
gl_backend_wgl->base.ws_info.context = gl_backend_wgl->ctx;
if (!vigs_gl_backend_init(&gl_backend_wgl->base)) {
if (gl_backend_wgl->ctx) {
gl_backend_wgl->wglDeleteContext(gl_backend_wgl->ctx);
}
+ if (gl_backend_wgl->read_pixels_ctx) {
+ gl_backend_wgl->wglDeleteContext(gl_backend_wgl->read_pixels_ctx);
+ }
if (gl_backend_wgl->sfc_dc) {
gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->sfc, gl_backend_wgl->sfc_dc);
}
if (gl_backend_wgl->sfc) {
gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->sfc);
}
+ if (gl_backend_wgl->read_pixels_sfc_dc) {
+ gl_backend_wgl->wglReleasePbufferDCARB(gl_backend_wgl->read_pixels_sfc, gl_backend_wgl->read_pixels_sfc_dc);
+ }
+ if (gl_backend_wgl->read_pixels_sfc) {
+ gl_backend_wgl->wglDestroyPbufferARB(gl_backend_wgl->read_pixels_sfc);
+ }
if (gl_backend_wgl->dc) {
ReleaseDC(gl_backend_wgl->win, gl_backend_wgl->dc);
}
}
vigs_sfc->read_pixels(vigs_sfc,
- 0,
- 0,
- vigs_sfc->ws_sfc->width,
- vigs_sfc->ws_sfc->height,
server->vram_ptr + offset);
vigs_sfc->is_dirty = false;
g_free(item);
}
-static void vigs_server_update_display_work(struct work_queue_item *wq_item)
+static void vigs_server_update_display_cb(void *user_data,
+ uint8_t *pixels,
+ uint32_t width,
+ uint32_t height,
+ uint32_t stride,
+ vigsp_surface_format format)
{
- struct vigs_server_work_item *item = (struct vigs_server_work_item*)wq_item;
- struct vigs_server *server = item->server;
- struct vigs_surface *root_sfc = server->root_sfc;
+ struct vigs_server *server = user_data;
uint32_t capture_fence_seq;
- if (!root_sfc) {
- qemu_mutex_lock(&server->capture_mutex);
- goto out;
- }
-
- if (root_sfc->is_dirty) {
- server->backend->batch_start(server->backend);
- root_sfc->read_pixels(root_sfc,
- 0,
- 0,
- root_sfc->ws_sfc->width,
- root_sfc->ws_sfc->height,
- server->root_sfc_ptr);
- server->backend->batch_end(server->backend);
- root_sfc->is_dirty = false;
- }
-
qemu_mutex_lock(&server->capture_mutex);
- if ((server->captured.stride != root_sfc->stride) ||
- (server->captured.height != root_sfc->ws_sfc->height)) {
- g_free(server->captured.data);
- server->captured.data = g_malloc(root_sfc->stride *
- root_sfc->ws_sfc->height);
- }
+ if (pixels) {
+ if ((server->captured.stride != stride) ||
+ (server->captured.height != height)) {
+ g_free(server->captured.data);
+ server->captured.data = g_malloc(stride * height);
+ }
- memcpy(server->captured.data,
- server->root_sfc_ptr,
- root_sfc->stride * root_sfc->ws_sfc->height);
+ memcpy(server->captured.data,
+ pixels,
+ stride * height);
- server->captured.width = root_sfc->ws_sfc->width;
- server->captured.height = root_sfc->ws_sfc->height;
- server->captured.stride = root_sfc->stride;
- server->captured.format = root_sfc->format;
+ server->captured.width = width;
+ server->captured.height = height;
+ server->captured.stride = stride;
+ server->captured.format = format;
+ }
-out:
server->is_capturing = false;
capture_fence_seq = server->capture_fence_seq;
server->capture_fence_seq = 0;
server->display_ops->fence_ack(server->display_user_data,
capture_fence_seq);
}
+}
+
+static void vigs_server_update_display_work(struct work_queue_item *wq_item)
+{
+ struct vigs_server_work_item *item = (struct vigs_server_work_item*)wq_item;
+ struct vigs_server *server = item->server;
+ struct vigs_surface *root_sfc = server->root_sfc;
+ if (!root_sfc) {
+ vigs_server_update_display_cb(server,
+ NULL,
+ 0,
+ 0,
+ 0,
+ vigsp_surface_bgrx8888);
+ goto out;
+ }
+
+ if (root_sfc->is_dirty) {
+ root_sfc->is_dirty = false;
+ server->backend->batch_start(server->backend);
+ server->backend->read_pixels(root_sfc,
+ server->root_sfc_ptr,
+ &vigs_server_update_display_cb,
+ server);
+ server->backend->batch_end(server->backend);
+ } else {
+ vigs_server_update_display_cb(server,
+ server->root_sfc_ptr,
+ root_sfc->ws_sfc->width,
+ root_sfc->ws_sfc->height,
+ root_sfc->stride,
+ root_sfc->format);
+ }
+
+out:
g_free(item);
}
bool is_dirty;
void (*read_pixels)(struct vigs_surface */*sfc*/,
- uint32_t /*x*/,
- uint32_t /*y*/,
- uint32_t /*width*/,
- uint32_t /*height*/,
uint8_t */*pixels*/);
void (*draw_pixels)(struct vigs_surface */*sfc*/,
*/
static void vigs_sw_surface_read_pixels(struct vigs_surface *sfc,
- uint32_t x,
- uint32_t y,
- uint32_t width,
- uint32_t height,
uint8_t *pixels)
{
struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)sfc;
- uint32_t bpp = vigs_format_bpp(sfc->format);
- uint32_t row_length = width * bpp;
- const uint8_t *src;
- uint8_t *dest;
- uint32_t i;
-
- VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u",
- x, y, width, height);
-
- src = sw_sfc->data + y * sfc->stride + x * bpp;
- dest = pixels + y * sfc->stride + x * bpp;
- if (width == sfc->ws_sfc->width) {
- row_length = sfc->stride * height;
- height = 1;
- }
-
- for (i = 0; i < height; ++i) {
- memcpy(dest, src, row_length);
- src += sfc->stride;
- dest += sfc->stride;
- }
+ memcpy(pixels, sw_sfc->data, sfc->stride * sfc->ws_sfc->height);
}
static void vigs_sw_surface_draw_pixels(struct vigs_surface *sfc,
return &sw_sfc->base;
}
+static void vigs_sw_backend_read_pixels(struct vigs_surface *surface,
+ uint8_t *pixels,
+ vigs_read_pixels_cb cb,
+ void *user_data)
+{
+ surface->read_pixels(surface, pixels);
+
+ cb(user_data, pixels, surface->ws_sfc->width, surface->ws_sfc->height,
+ surface->stride, surface->format);
+}
+
static void vigs_sw_backend_batch_end(struct vigs_backend *backend)
{
}
backend->batch_start = &vigs_sw_backend_batch_start;
backend->create_surface = &vigs_sw_backend_create_surface;
+ backend->read_pixels = &vigs_sw_backend_read_pixels;
backend->batch_end = &vigs_sw_backend_batch_end;
backend->destroy = &vigs_sw_backend_destroy;
PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
#if defined(CONFIG_LINUX)
+ XInitThreads();
Display *display = XOpenDisplay(0);
if (!display && !enable_spice) {
fprintf(stderr, "Cannot open X display\n");