From: Stanislav Vorobiov Date: Thu, 9 Jan 2014 14:13:35 +0000 (+0400) Subject: VIGS: Using asynchronous glReadPixels for display update X-Git-Tag: Tizen_Studio_1.3_Release_p2.3.1~519 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b797b869bebd16a0b79eba5e016a789bda53e5b0;p=sdk%2Femulator%2Fqemu.git VIGS: Using asynchronous glReadPixels for display update On somy GPUs like Intel HD Graphics 2000 glReadPixels is too slow, so we use so called asynchronous version of glReadPixels - it uses PBO for pixel storage and separate work queue to read back results Change-Id: I43f30daf57166a30cecf356fa2170da640de1ae3 --- diff --git a/hw/vigs/vigs_backend.h b/hw/vigs/vigs_backend.h index 1eb7bfaf63..c918c7dcfe 100644 --- a/hw/vigs/vigs_backend.h +++ b/hw/vigs/vigs_backend.h @@ -35,6 +35,13 @@ 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; @@ -48,6 +55,11 @@ struct vigs_backend 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*/); diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index dc50908c89..65ace1b88c 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -33,9 +33,25 @@ #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; @@ -334,10 +350,6 @@ static void vigs_gl_backend_batch_start(struct vigs_backend *backend) */ 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; @@ -347,9 +359,6 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc, 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; @@ -421,7 +430,7 @@ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc, 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); @@ -824,6 +833,93 @@ fail: 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; @@ -857,8 +953,16 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_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); @@ -866,6 +970,8 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) 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: @@ -876,6 +982,14 @@ 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); } diff --git a/hw/vigs/vigs_gl_backend.h b/hw/vigs/vigs_gl_backend.h index 5b6a8eb277..223aa02d9f 100644 --- a/hw/vigs/vigs_gl_backend.h +++ b/hw/vigs/vigs_gl_backend.h @@ -37,6 +37,8 @@ #include #include "winsys_gl.h" +struct work_queue; + struct vigs_gl_backend { struct vigs_backend base; @@ -48,6 +50,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. * @{ @@ -105,6 +110,12 @@ struct vigs_gl_backend 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); /* * @} @@ -121,6 +132,15 @@ struct vigs_gl_backend /* * @} */ + + /* + * + */ + + struct work_queue *read_pixels_queue; + + GLuint pbo; + uint32_t pbo_size; }; bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend); diff --git a/hw/vigs/vigs_gl_backend_agl.c b/hw/vigs/vigs_gl_backend_agl.c index c92f946a19..ba5c04a256 100644 --- a/hw/vigs/vigs_gl_backend_agl.c +++ b/hw/vigs/vigs_gl_backend_agl.c @@ -50,6 +50,8 @@ struct vigs_gl_backend_agl { struct vigs_gl_backend base; void *handle; + AGLContext read_pixels_context; + AGLPbuffer read_pixels_surface; AGLContext context; AGLPbuffer surface; AGLPixelFormat pixfmt; @@ -86,14 +88,13 @@ static int vigs_gl_backend_agl_choose_config(struct vigs_gl_backend_agl } 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; } @@ -102,11 +103,13 @@ static bool vigs_gl_backend_agl_create_surface(struct vigs_gl_backend_agl } 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; } @@ -125,10 +128,18 @@ static void vigs_gl_backend_agl_destroy(struct vigs_backend *backend) 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); } @@ -181,6 +192,37 @@ static bool vigs_gl_backend_agl_make_current(struct vigs_gl_backend *gl_backend, 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; @@ -245,6 +287,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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); @@ -252,17 +300,30 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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)) { @@ -283,10 +344,18 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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); diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index 6b913b0d00..372ec52bab 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -89,6 +89,8 @@ struct vigs_gl_backend_glx 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) @@ -145,7 +147,8 @@ static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl } 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[] = { @@ -155,11 +158,11 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba 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; } @@ -168,15 +171,17 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba } 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; } @@ -212,15 +217,41 @@ 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); + 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); @@ -325,6 +356,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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; @@ -334,30 +371,55 @@ struct vigs_backend *vigs_gl_backend_create(void *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); diff --git a/hw/vigs/vigs_gl_backend_wgl.c b/hw/vigs/vigs_gl_backend_wgl.c index 72b94ab100..101c376568 100644 --- a/hw/vigs/vigs_gl_backend_wgl.c +++ b/hw/vigs/vigs_gl_backend_wgl.c @@ -98,6 +98,7 @@ struct vigs_gl_backend_wgl PFNWGLGETPROCADDRESSPROC wglGetProcAddress; PFNWGLMAKECURRENTPROC wglMakeCurrent; PFNWGLGETCURRENTCONTEXTPROC wglGetCurrentContext; + PFNWGLSHARELISTSPROC wglShareLists; /* WGL extensions */ PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT; @@ -113,6 +114,9 @@ struct vigs_gl_backend_wgl 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) @@ -162,7 +166,9 @@ static int vigs_gl_backend_wgl_choose_config(struct vigs_gl_backend_wgl *gl_back } 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, @@ -171,18 +177,17 @@ static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_ba 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; } @@ -190,15 +195,26 @@ static bool vigs_gl_backend_wgl_create_surface(struct vigs_gl_backend_wgl *gl_ba 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; } @@ -231,6 +247,27 @@ static bool vigs_gl_backend_wgl_make_current(struct vigs_gl_backend *gl_backend, 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; @@ -238,8 +275,11 @@ static void vigs_gl_backend_wgl_destroy(struct vigs_backend *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); @@ -310,6 +350,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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, @@ -429,6 +470,12 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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); @@ -460,17 +507,34 @@ struct vigs_backend *vigs_gl_backend_create(void *display) 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)) { @@ -485,12 +549,21 @@ fail: 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); } diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c index 983f30c85a..7438c21cc6 100644 --- a/hw/vigs/vigs_server.c +++ b/hw/vigs/vigs_server.c @@ -192,10 +192,6 @@ static void vigs_server_dispatch_update_vram(void *user_data, } 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; @@ -365,49 +361,35 @@ out: 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; @@ -418,7 +400,42 @@ out: 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); } diff --git a/hw/vigs/vigs_surface.h b/hw/vigs/vigs_surface.h index 06af7d3b70..95daa927b2 100644 --- a/hw/vigs/vigs_surface.h +++ b/hw/vigs/vigs_surface.h @@ -48,10 +48,6 @@ struct vigs_surface 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*/, diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c index b1e96c49b6..4489e7dfc6 100644 --- a/hw/vigs/vigs_sw_backend.c +++ b/hw/vigs/vigs_sw_backend.c @@ -112,35 +112,11 @@ static void vigs_sw_backend_batch_start(struct vigs_backend *backend) */ 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, @@ -334,6 +310,17 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend * 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) { } @@ -354,6 +341,7 @@ struct vigs_backend *vigs_sw_backend_create(void) 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; diff --git a/tizen/src/hw/maru_board.c b/tizen/src/hw/maru_board.c index 069f70a7d5..d37d951ec0 100644 --- a/tizen/src/hw/maru_board.c +++ b/tizen/src/hw/maru_board.c @@ -106,6 +106,7 @@ static void maru_device_init(void) 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");