From: Stanislav Vorobiov Date: Mon, 28 Jul 2014 17:07:06 +0000 (+0400) Subject: VIGS: Initial qt5 display support X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F78%2F25078%2F3;p=sdk%2Femulator%2Fqemu.git VIGS: Initial qt5 display support There're few things to note: * X11-only, support for other platforms is to be implemented * Qt5 only allows accessing raw GLX/WGL/CGL OpenGL contexts and X11 display through 'gui-private' package, i.e. gui-private must be installed in system: sudo apt-get install qtbase5-private-dev * 'gui-private' is not stable interface, it depends on Qt minor version, but we don't care since we'll have our own Qt build anyway (in order to support windows and mac) TODO: * resizing - use bicubic shader * rotation - use y-flipped ortho matrix * move swapBuffers to background thread - to avoid block-waiting with some drivers * support remaining platforms (windows, mac) * improve Qt5/qemu interoperability - currently there're hacks such as global QtApplication object, global QOpenGLContext object, etc. this is all because of QEMU's graphics console architecture, currently it's completely useless for us, it doesn't help us, it just stands in our way and forces us to workaround. It's probably better to just drop it and perform the rendering on our own... Change-Id: Ib613b1457e7bf7166b019ad916178ecdba168d29 Signed-off-by: Stanislav Vorobiov --- diff --git a/configure b/configure index aa7bc7945f..b03fa35a9f 100755 --- a/configure +++ b/configure @@ -2087,14 +2087,16 @@ fi qtversion="" if test "$qt" != "no"; then if test "$qtabi" = "5.0" ; then - qtpackage="Qt5Widgets Qt5Qml Qt5OpenGL" + qtpackage="Qt5Widgets Qt5Qml Qt5OpenGL Qt5Gui" qtversion="5.0.0" if $pkg_config --exists "$qtpackage >= $qtversion"; then qt_cflags=`$pkg_config --cflags $qtpackage` qt_libs=`$pkg_config --libs $qtpackage` libs_softmmu="$qt_libs $libs_softmmu" - qt_cflags="$qt_cflags -fPIC" + qt_cflags_private=`pkg-config --modversion Qt5Gui` + qt_cflags_private=`pkg-config --cflags Qt5Gui | sed "s,QtGui,QtGui/$qt_cflags_private/QtGui,g"` + qt_cflags="$qt_cflags $qt_cflags_private -fPIC" qt="yes" elif test "$qt" = "yes"; then feature_not_found "qt" "Install qt devel" diff --git a/hw/vigs/Makefile.objs b/hw/vigs/Makefile.objs index ca42e65be8..572de90946 100644 --- a/hw/vigs/Makefile.objs +++ b/hw/vigs/Makefile.objs @@ -13,6 +13,7 @@ obj-y += vigs_fenceman.o obj-y += vigs_gl_pool.o obj-y += vigs_gl_backend.o obj-y += vigs_sw_backend.o +obj-y += vigs_qt5.o obj-y += work_queue.o obj-y += winsys.o obj-y += display.o diff --git a/hw/vigs/display.c b/hw/vigs/display.c index 961e7aa63e..1c55fed879 100644 --- a/hw/vigs/display.c +++ b/hw/vigs/display.c @@ -1,4 +1,5 @@ #include "display.h" +#include "vigs_qt5.h" #include "qom/object_interfaces.h" #if defined(CONFIG_LINUX) #include @@ -24,7 +25,7 @@ static void displayobject_complete(UserCreatable *obj, Error **errp) XSetErrorHandler(x_error_handler); XInitThreads(); - dobj->dpy = XOpenDisplay(0); + dobj->dpy = (Display*)vigs_qt5_display(); if (!dobj->dpy) { error_setg(errp, "Cannot open X display"); diff --git a/hw/vigs/vigs_backend.h b/hw/vigs/vigs_backend.h index cffcd2bb55..0e0830a494 100644 --- a/hw/vigs/vigs_backend.h +++ b/hw/vigs/vigs_backend.h @@ -36,16 +36,6 @@ struct winsys_info; struct vigs_surface; struct vigs_plane; -typedef uint8_t *(*vigs_composite_start_cb)(void */*user_data*/, - uint32_t /*width*/, - uint32_t /*height*/, - uint32_t /*stride*/, - vigsp_surface_format /*format*/); - -typedef void (*vigs_composite_end_cb)(void */*user_data*/, - bool /*was_started*/, - bool /*dirty*/); - struct vigs_backend { struct winsys_info *ws_info; @@ -59,14 +49,12 @@ struct vigs_backend vigsp_surface_format /*format*/, vigsp_surface_id /*id*/); - void (*composite)(struct vigs_surface */*surface*/, - const struct vigs_plane */*planes*/, - vigs_composite_start_cb /*start_cb*/, - vigs_composite_end_cb /*end_cb*/, - void */*user_data*/); - void (*batch_end)(struct vigs_backend */*backend*/); + bool (*composite)(struct vigs_surface */*surface*/, + const struct vigs_plane */*planes*/, + uint8_t */*display_data*/); + void (*destroy)(struct vigs_backend */*backend*/); }; diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 720e6186ff..8c79f8c993 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -35,25 +35,9 @@ #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_composite_start_cb start_cb; - vigs_composite_end_cb end_cb; - void *user_data; - uint32_t width; - uint32_t height; - uint32_t stride; - vigsp_surface_format format; -}; - struct vigs_winsys_gl_surface { struct winsys_gl_surface base; @@ -451,6 +435,54 @@ static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend, backend->DisableVertexAttribArray(backend->color_prog_vertCoord_loc); } +static void vigs_gl_draw_dpy_tex_prog(struct vigs_gl_backend *backend, + uint32_t count) +{ + uint32_t size = count * 16; + void *ptr; + + if (size > backend->dpy_vbo_size) { + backend->dpy_vbo_size = size; + backend->BufferData(GL_ARRAY_BUFFER, + size, + 0, + GL_STREAM_DRAW); + } + + if (backend->MapBufferRange) { + ptr = backend->MapBufferRange(GL_ARRAY_BUFFER, 0, size, + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT); + + if (ptr) { + memcpy(ptr, vigs_vector_data(&backend->dpy_v1), size / 2); + memcpy(ptr + (size / 2), vigs_vector_data(&backend->dpy_v2), size / 2); + + backend->UnmapBuffer(GL_ARRAY_BUFFER); + } else { + VIGS_LOG_ERROR("glMapBufferRange failed"); + } + } else { + backend->Finish(); + backend->BufferSubData(GL_ARRAY_BUFFER, 0, + (size / 2), vigs_vector_data(&backend->dpy_v1)); + backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2), + (size / 2), vigs_vector_data(&backend->dpy_v2)); + } + + backend->EnableVertexAttribArray(backend->dpy_tex_prog_vertCoord_loc); + backend->EnableVertexAttribArray(backend->dpy_tex_prog_texCoord_loc); + + backend->VertexAttribPointer(backend->dpy_tex_prog_vertCoord_loc, + 2, GL_FLOAT, GL_FALSE, 0, NULL); + backend->VertexAttribPointer(backend->dpy_tex_prog_texCoord_loc, + 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); + + backend->DrawArrays(GL_TRIANGLES, 0, count); + + backend->DisableVertexAttribArray(backend->dpy_tex_prog_texCoord_loc); + backend->DisableVertexAttribArray(backend->dpy_tex_prog_vertCoord_loc); +} + static void vigs_gl_create_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearf, GLfloat farf, @@ -489,20 +521,20 @@ static void vigs_gl_translate_color(vigsp_color color, static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface *ws_sfc) { - GLuint cur_tex = 0; + GLuint cur_tex = 0, tmp_tex = 0; if (ws_sfc->tex) { return true; } - ws_sfc->backend->GenTextures(1, &ws_sfc->tex); + ws_sfc->backend->GenTextures(1, &tmp_tex); - if (!ws_sfc->tex) { + if (!tmp_tex) { return false; } ws_sfc->backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex); - ws_sfc->backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); + ws_sfc->backend->BindTexture(GL_TEXTURE_2D, tmp_tex); /* * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3": @@ -518,6 +550,8 @@ static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface NULL); ws_sfc->backend->BindTexture(GL_TEXTURE_2D, cur_tex); + ws_sfc->tex = tmp_tex; + return true; } @@ -1191,50 +1225,9 @@ static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend * return &gl_sfc->base; } -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; - uint8_t *dst = NULL; - - VIGS_LOG_TRACE("enter"); - - if (backend->read_pixels_make_current(backend, true)) { - uint8_t *src; - - backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, backend->pbo); - - src = backend->MapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); - - if (src) { - dst = item->start_cb(item->user_data, - item->width, item->height, - item->stride, item->format); - - memcpy(dst, src, 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->end_cb(item->user_data, (dst != NULL), true); - - g_free(item); -} - -static void vigs_gl_backend_composite(struct vigs_surface *surface, +static bool vigs_gl_backend_composite(struct vigs_surface *surface, const struct vigs_plane *planes, - vigs_composite_start_cb start_cb, - vigs_composite_end_cb end_cb, - void *user_data) + uint8_t *display_data) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend; struct vigs_gl_surface *gl_root_sfc = (struct vigs_gl_surface*)surface; @@ -1243,25 +1236,29 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface, GLfloat *vert_coords; GLfloat *tex_coords; const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES]; - uint32_t size = surface->stride * surface->ws_sfc->height; - struct vigs_gl_backend_read_pixels_work_item *item; VIGS_LOG_TRACE("enter"); - if (!surface->ptr) { - if (!ws_root_sfc->tex) { - VIGS_LOG_WARN("compositing garbage (root surface) ???"); - } + if (!ws_root_sfc->tex) { + VIGS_LOG_WARN("compositing garbage (root surface) ???"); + return false; + } - if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc)) { - goto out; + if (!gl_backend->is_gl_2 && !gl_backend->dpy_vao) { + gl_backend->GenVertexArrays(1, &gl_backend->dpy_vao); + + if (!gl_backend->dpy_vao) { + VIGS_LOG_CRITICAL("cannot create VAO"); + exit(1); } - } - if (!vigs_gl_surface_create_tmp_texture(gl_root_sfc)) { - goto out; + gl_backend->BindVertexArray(gl_backend->dpy_vao); } + gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->dpy_vbo); + gl_backend->Disable(GL_DEPTH_TEST); + gl_backend->Disable(GL_BLEND); + for (i = 0; i < VIGS_MAX_PLANES; ++i) { struct vigs_gl_surface *gl_sfc; struct vigs_winsys_gl_surface *ws_sfc; @@ -1275,25 +1272,30 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface, if (!ws_sfc->tex) { VIGS_LOG_WARN("compositing garbage (plane %u) ???", i); - } - - if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { - goto out; + return false; } } - if (!vigs_gl_surface_setup_framebuffer(gl_root_sfc, - gl_backend->tex_prog_id, - gl_backend->tex_prog_proj_loc)) { - goto out; - } + /* + * TODO: scale. + */ - vigs_vector_resize(&gl_backend->v1, 0); - vigs_vector_resize(&gl_backend->v2, 0); + gl_backend->Viewport(0, 0, + gl_root_sfc->base.ws_sfc->width / 2, + gl_root_sfc->base.ws_sfc->height / 2); - vert_coords = vigs_vector_append(&gl_backend->v1, + gl_backend->UseProgram(gl_backend->dpy_tex_prog_id); + gl_backend->UniformMatrix4fv(gl_backend->dpy_tex_prog_proj_loc, 1, GL_FALSE, + gl_root_sfc->ortho); + + gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex); + + vigs_vector_resize(&gl_backend->dpy_v1, 0); + vigs_vector_resize(&gl_backend->dpy_v2, 0); + + vert_coords = vigs_vector_append(&gl_backend->dpy_v1, (12 * sizeof(GLfloat))); - tex_coords = vigs_vector_append(&gl_backend->v2, + tex_coords = vigs_vector_append(&gl_backend->dpy_v2, (12 * sizeof(GLfloat))); if (surface->ptr) { @@ -1307,8 +1309,6 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface, gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); - gl_backend->BindTexture(GL_TEXTURE_2D, gl_root_sfc->tmp_tex); - gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ws_root_sfc->base.base.width, ws_root_sfc->base.base.height, @@ -1317,38 +1317,37 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface, surface->ptr); } - gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, gl_root_sfc->tmp_tex, 0); - - if (!surface->ptr) { - /* - * If root surface is not scanout then we must render - * it. - */ - - vert_coords[6] = vert_coords[0] = 0; - vert_coords[7] = vert_coords[1] = ws_root_sfc->base.base.height; - vert_coords[2] = ws_root_sfc->base.base.width; - vert_coords[3] = ws_root_sfc->base.base.height; - vert_coords[8] = vert_coords[4] = ws_root_sfc->base.base.width; - vert_coords[9] = vert_coords[5] = 0; - vert_coords[10] = 0; - vert_coords[11] = 0; + vert_coords[6] = vert_coords[0] = 0; + vert_coords[7] = vert_coords[1] = ws_root_sfc->base.base.height; + vert_coords[2] = ws_root_sfc->base.base.width; + vert_coords[3] = ws_root_sfc->base.base.height; + vert_coords[8] = vert_coords[4] = ws_root_sfc->base.base.width; + vert_coords[9] = vert_coords[5] = 0; + vert_coords[10] = 0; + vert_coords[11] = 0; + if (surface->ptr) { tex_coords[6] = tex_coords[0] = 0; - tex_coords[7] =tex_coords[1] = 0; + tex_coords[7] = tex_coords[1] = 0; tex_coords[2] = 1; tex_coords[3] = 0; tex_coords[8] = tex_coords[4] = 1; tex_coords[9] = tex_coords[5] = 1; tex_coords[10] = 0; tex_coords[11] = 1; - - gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex); - - vigs_gl_draw_tex_prog(gl_backend, 6); + } else { + tex_coords[6] = tex_coords[0] = 0; + tex_coords[7] = tex_coords[1] = 1; + tex_coords[2] = 1; + tex_coords[3] = 1; + tex_coords[8] = tex_coords[4] = 1; + tex_coords[9] = tex_coords[5] = 0; + tex_coords[10] = 0; + tex_coords[11] = 0; } + vigs_gl_draw_dpy_tex_prog(gl_backend, 6); + /* * Sort planes, only 2 of them now, don't bother... */ @@ -1393,68 +1392,22 @@ static void vigs_gl_backend_composite(struct vigs_surface *surface, vert_coords[11] = plane->dst_y + (int)plane->dst_size.h; tex_coords[6] = tex_coords[0] = (GLfloat)plane->src_rect.pos.x / src_w; - tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h; + tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h; tex_coords[2] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w; - tex_coords[3] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h; + tex_coords[3] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h; tex_coords[8] = tex_coords[4] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w; - tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h; + tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h; tex_coords[10] = (GLfloat)plane->src_rect.pos.x / src_w; - tex_coords[11] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h; + tex_coords[11] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h; gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); - vigs_gl_draw_tex_prog(gl_backend, 6); - } - - /* - * Now schedule asynchronous glReadPixels. - */ - - 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); + vigs_gl_draw_dpy_tex_prog(gl_backend, 6); } - gl_backend->PixelStorei(GL_PACK_ALIGNMENT, 1); - gl_backend->ReadPixels(0, 0, - surface->ws_sfc->width, surface->ws_sfc->height, - ws_root_sfc->tex_format, ws_root_sfc->tex_type, - 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->start_cb = start_cb; - item->end_cb = end_cb; - item->user_data = user_data; - 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); - -out: - gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); + return false; } static void vigs_gl_backend_batch_end(struct vigs_backend *backend) @@ -1556,9 +1509,10 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) gl_backend->color_prog_color_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "color"); gl_backend->GenBuffers(1, &gl_backend->vbo); + gl_backend->GenBuffers(1, &gl_backend->dpy_vbo); - if (!gl_backend->vbo) { - VIGS_LOG_CRITICAL("cannot create VBO"); + if (!gl_backend->vbo || !gl_backend->dpy_vbo) { + VIGS_LOG_CRITICAL("cannot create VBOs"); goto fail; } @@ -1567,13 +1521,34 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) gl_backend->UseProgram(gl_backend->tex_prog_id); gl_backend->cur_prog_id = gl_backend->tex_prog_id; - gl_backend->GenBuffers(1, &gl_backend->pbo); + gl_backend->dpy_tex_prog_vs_id = vigs_gl_create_shader(gl_backend, + (gl_backend->is_gl_2 ? g_vs_tex_source_gl2 : g_vs_tex_source_gl3), + GL_VERTEX_SHADER); - if (!gl_backend->pbo) { - VIGS_LOG_CRITICAL("cannot create read_pixels PBO"); + if (!gl_backend->dpy_tex_prog_vs_id) { goto fail; } + gl_backend->dpy_tex_prog_fs_id = vigs_gl_create_shader(gl_backend, + (gl_backend->is_gl_2 ? g_fs_tex_source_gl2 : g_fs_tex_source_gl3), + GL_FRAGMENT_SHADER); + + if (!gl_backend->dpy_tex_prog_fs_id) { + goto fail; + } + + gl_backend->dpy_tex_prog_id = vigs_gl_create_program(gl_backend, + gl_backend->dpy_tex_prog_vs_id, + gl_backend->dpy_tex_prog_fs_id); + + if (!gl_backend->dpy_tex_prog_id) { + goto fail; + } + + gl_backend->dpy_tex_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->dpy_tex_prog_id, "proj"); + gl_backend->dpy_tex_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->dpy_tex_prog_id, "vertCoord"); + gl_backend->dpy_tex_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->dpy_tex_prog_id, "texCoord"); + gl_backend->Disable(GL_DEPTH_TEST); gl_backend->Disable(GL_BLEND); @@ -1586,8 +1561,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("vigs_work_queue"); + vigs_vector_init(&gl_backend->dpy_v1, 0); + vigs_vector_init(&gl_backend->dpy_v2, 0); return true; @@ -1599,10 +1574,15 @@ 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->DeleteBuffers(1, &gl_backend->dpy_vbo); + gl_backend->DetachShader(gl_backend->dpy_tex_prog_id, + gl_backend->dpy_tex_prog_vs_id); + gl_backend->DetachShader(gl_backend->dpy_tex_prog_id, + gl_backend->dpy_tex_prog_fs_id); + gl_backend->DeleteShader(gl_backend->dpy_tex_prog_vs_id); + gl_backend->DeleteShader(gl_backend->dpy_tex_prog_fs_id); + gl_backend->DeleteProgram(gl_backend->dpy_tex_prog_id); gl_backend->DeleteBuffers(1, &gl_backend->vbo); gl_backend->DetachShader(gl_backend->color_prog_id, gl_backend->color_prog_vs_id); @@ -1629,6 +1609,8 @@ void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend) gl_backend->make_current(gl_backend, false); } + vigs_vector_cleanup(&gl_backend->dpy_v2); + vigs_vector_cleanup(&gl_backend->dpy_v1); 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 e761ed196c..f3643be689 100644 --- a/hw/vigs/vigs_gl_backend.h +++ b/hw/vigs/vigs_gl_backend.h @@ -37,7 +37,6 @@ #include #include "winsys_gl.h" -struct work_queue; struct vigs_gl_pool; struct vigs_gl_backend @@ -53,9 +52,6 @@ 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. * @{ @@ -159,7 +155,8 @@ struct vigs_gl_backend */ /* - * Other. + * Rendering thread related. + * @{ */ GLuint vao; @@ -183,10 +180,30 @@ struct vigs_gl_backend GLuint cur_prog_id; - struct work_queue *read_pixels_queue; + /* + * @} + * Display thread related. + * @{ + */ + + struct vigs_vector dpy_v1; + struct vigs_vector dpy_v2; - GLuint pbo; - uint32_t pbo_size; + GLuint dpy_vao; + + GLuint dpy_tex_prog_vs_id; + GLuint dpy_tex_prog_fs_id; + GLuint dpy_tex_prog_id; + GLint dpy_tex_prog_proj_loc; + GLint dpy_tex_prog_vertCoord_loc; + GLint dpy_tex_prog_texCoord_loc; + + GLuint dpy_vbo; + uint32_t dpy_vbo_size; + + /* + * @} + */ }; bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend); diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index 5394b19f85..294bdef2a8 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -29,6 +29,7 @@ #include "vigs_gl_backend.h" #include "vigs_log.h" +#include "vigs_qt5.h" #include #include @@ -85,6 +86,7 @@ struct vigs_gl_backend_glx PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrent; PFNGLXGETCURRENTCONTEXTPROC glXGetCurrentContext; PFNGLXCREATENEWCONTEXTPROC glXCreateNewContext; + PFNGLXQUERYCONTEXTPROC glXQueryContext; /* GLX_ARB_create_context */ PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB; @@ -92,8 +94,6 @@ struct vigs_gl_backend_glx Display *dpy; GLXPbuffer sfc; GLXContext ctx; - GLXPbuffer read_pixels_sfc; - GLXContext read_pixels_ctx; }; static bool vigs_gl_backend_glx_check_gl_version(struct vigs_gl_backend_glx *gl_backend_glx, @@ -194,22 +194,21 @@ static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl { int config_attribs[] = { - GLX_DOUBLEBUFFER, True, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_BUFFER_SIZE, 32, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_FBCONFIG_ID, 0, None }; int n = 0; GLXFBConfig *glx_configs; GLXFBConfig best_config = NULL; + if (gl_backend_glx->glXQueryContext(gl_backend_glx->dpy, + gl_backend_glx->ctx, + GLX_FBCONFIG_ID, + &config_attribs[1]) != Success) { + VIGS_LOG_CRITICAL("Unable to get context's GLX config"); + return NULL; + } + glx_configs = gl_backend_glx->glXChooseFBConfig(gl_backend_glx->dpy, DefaultScreen(gl_backend_glx->dpy), config_attribs, @@ -267,42 +266,6 @@ static bool vigs_gl_backend_glx_create_surface(struct vigs_gl_backend_glx *gl_ba return true; } -static bool vigs_gl_backend_glx_create_context(struct vigs_gl_backend_glx *gl_backend_glx, - GLXFBConfig config, - GLXContext share_ctx, - GLXContext *ctx) -{ - int attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 1, - GLX_RENDER_TYPE, GLX_RGBA_TYPE, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None - }; - - if (gl_backend_glx->base.is_gl_2) { - *ctx = gl_backend_glx->glXCreateNewContext(gl_backend_glx->dpy, - config, - GLX_RGBA_TYPE, - share_ctx, - True); - } else { - *ctx = gl_backend_glx->glXCreateContextAttribsARB(gl_backend_glx->dpy, - config, - share_ctx, - True, - attribs); - } - - if (!*ctx) { - VIGS_LOG_CRITICAL("glXCreateContextAttribsARB/glXCreateNewContext failed"); - return false; - } - - return true; -} - static bool vigs_gl_backend_glx_has_current(struct vigs_gl_backend *gl_backend) { struct vigs_gl_backend_glx *gl_backend_glx = @@ -331,41 +294,12 @@ 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); @@ -418,6 +352,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display) VIGS_GLX_GET_PROC(PFNGLXGETCURRENTCONTEXTPROC, glXGetCurrentContext); VIGS_GLX_GET_PROC(PFNGLXCREATENEWCONTEXTPROC, glXCreateNewContext); VIGS_GLX_GET_PROC(PFNGLXCREATECONTEXTATTRIBSARBPROC, glXCreateContextAttribsARB); + VIGS_GLX_GET_PROC(PFNGLXQUERYCONTEXTPROC, glXQueryContext); VIGS_GL_GET_PROC(GenTextures, glGenTextures); VIGS_GL_GET_PROC(DeleteTextures, glDeleteTextures); @@ -504,6 +439,13 @@ struct vigs_backend *vigs_gl_backend_create(void *display) VIGS_GL_GET_PROC(DeleteVertexArrays, glDeleteVertexArrays); } + gl_backend_glx->ctx = + (GLXContext)vigs_qt5_gl_context_create(gl_backend_glx->base.is_gl_2); + + if (!gl_backend_glx->ctx) { + goto fail2; + } + config = vigs_gl_backend_glx_get_config(gl_backend_glx); if (!config) { @@ -516,49 +458,19 @@ struct vigs_backend *vigs_gl_backend_create(void *display) goto fail2; } - 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 fail6; + goto fail3; } VIGS_LOG_DEBUG("created"); return &gl_backend_glx->base.base; -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_qt5.cpp b/hw/vigs/vigs_qt5.cpp new file mode 100644 index 0000000000..6a05acb4e6 --- /dev/null +++ b/hw/vigs/vigs_qt5.cpp @@ -0,0 +1,120 @@ +/* + * vigs + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Stanislav Vorobiov + * Jinhyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "vigs_qt5.h" +#include "config-host.h" +#include +#include +#include +#include + +extern QOpenGLContext *qt5GLContext; +extern QSurfaceFormat qt5GLFormat; + +void *vigs_qt5_display(void) +{ + QPlatformNativeInterface *native = + QGuiApplication::platformNativeInterface(); + + return native->nativeResourceForScreen(QByteArray("display"), + QGuiApplication::primaryScreen()); +} + +void *vigs_qt5_gl_context_create(bool is_gl2) +{ + if (qt5GLContext) { + fprintf(stderr, "QT5 GL context already created!\n"); + return NULL; + } + + qt5GLContext = new QOpenGLContext(); + + QSurfaceFormat format; + + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + format.setAlphaBufferSize(8); + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + if (!is_gl2) { + format.setMajorVersion(3); + format.setMinorVersion(1); + } + + qt5GLContext->setScreen(QGuiApplication::primaryScreen()); + qt5GLContext->setFormat(format); + + if (!qt5GLContext->create()) { + fprintf(stderr, "Cannot create QT5 GL context!\n"); + + delete qt5GLContext; + qt5GLContext = NULL; + + return NULL; + } + + if (!is_gl2) { + if ((qt5GLContext->format().majorVersion() < 3) || + ((qt5GLContext->format().majorVersion() == 3) && + (qt5GLContext->format().minorVersion() < 1))) { + fprintf(stderr, "Cannot create QT5 3.1 GL context!\n"); + + delete qt5GLContext; + qt5GLContext = NULL; + + return NULL; + } + } + + QPlatformNativeInterface *native = + QGuiApplication::platformNativeInterface(); + + void *ret = NULL; + +#if defined(CONFIG_LINUX) + ret = native->nativeResourceForContext(QByteArray("glxcontext"), qt5GLContext); +#elif defined(CONFIG_WIN32) + ret = native->nativeResourceForContext(QByteArray("renderingContext"), qt5GLContext); +#elif defined(CONFIG_DARWIN) + ret = native->nativeResourceForContext(QByteArray("cglContextObj"), qt5GLContext); +#endif + + if (!ret) { + fprintf(stderr, "Cannot get native QT5 GL context!\n"); + + delete qt5GLContext; + qt5GLContext = NULL; + } + + qt5GLFormat = format; + + return ret; +} diff --git a/hw/vigs/vigs_qt5.h b/hw/vigs/vigs_qt5.h new file mode 100644 index 0000000000..5d5d31eb5d --- /dev/null +++ b/hw/vigs/vigs_qt5.h @@ -0,0 +1,45 @@ +/* + * vigs + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Stanislav Vorobiov + * Jinhyung Jo + * YeongKyoon Lee + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef _QEMU_VIGS_QT5_H +#define _QEMU_VIGS_QT5_H + +#ifdef __cplusplus +extern "C" { +#endif + +void *vigs_qt5_display(void); + +void *vigs_qt5_gl_context_create(bool is_gl2); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c index 6be06b75bd..6299299ed4 100644 --- a/hw/vigs/vigs_server.c +++ b/hw/vigs/vigs_server.c @@ -178,8 +178,12 @@ static void vigs_server_dispatch_destroy_surface(void *user_data, return; } + qemu_mutex_lock(&server->dpy_mutex); + vigs_server_unuse_surface(server, sfc); + qemu_mutex_unlock(&server->dpy_mutex); + g_hash_table_remove(server->surfaces, GUINT_TO_POINTER(id)); VIGS_LOG_TRACE("num_surfaces = %u", g_hash_table_size(server->surfaces)); @@ -322,18 +326,20 @@ static void vigs_server_dispatch_set_plane(void *user_data, return; } + qemu_mutex_lock(&server->dpy_mutex); + if (sfc_id) { sfc = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(sfc_id)); if (!sfc) { VIGS_LOG_ERROR("surface %u not found", sfc_id); - return; + goto out; } } if (plane >= VIGS_MAX_PLANES) { VIGS_LOG_ERROR("bad plane %u", plane); - return; + goto out; } server->planes[plane].sfc = sfc; @@ -343,6 +349,9 @@ static void vigs_server_dispatch_set_plane(void *user_data, server->planes[plane].dst_size = *dst_size; server->planes[plane].z_pos = z_pos; server->planes[plane].is_dirty = true; + +out: + qemu_mutex_unlock(&server->dpy_mutex); } static void vigs_server_dispatch_batch_end(void *user_data, @@ -394,6 +403,8 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item) goto out; } + qemu_mutex_lock(&server->dpy_mutex); + if (item->id == 0) { if (server->root_sfc) { vigs_surface_set_scanout(server->root_sfc, NULL); @@ -427,147 +438,8 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item) } out: - g_free(item); -} - -static uint8_t *vigs_server_update_display_start_cb(void *user_data, - uint32_t width, - uint32_t height, - uint32_t stride, - vigsp_surface_format format) -{ - struct vigs_server *server = user_data; - - qemu_mutex_lock(&server->capture_mutex); - - if ((server->captured.stride != stride) || - (server->captured.height != height)) { - g_free(server->captured.data); - server->captured.data = g_malloc(stride * height); - } - - server->captured.width = width; - server->captured.height = height; - server->captured.stride = stride; - server->captured.format = format; - - return server->captured.data; -} - -static void vigs_server_update_display_end_cb(void *user_data, - bool was_started, - bool dirty) -{ - struct vigs_server *server = user_data; - uint32_t capture_fence_seq; - - if (!was_started) { - qemu_mutex_lock(&server->capture_mutex); - } - - if (dirty) { - server->captured.dirty = true; - } - - server->is_capturing = false; - capture_fence_seq = server->capture_fence_seq; - server->capture_fence_seq = 0; - - qemu_mutex_unlock(&server->capture_mutex); - - if (capture_fence_seq) { - 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; - int i; - bool planes_on = false; - bool planes_dirty = false; - - if (!root_sfc) { - /* - * If no root surface then this is a no-op. - * TODO: Can planes be enabled without a root surface ? - */ - vigs_server_update_display_end_cb(server, false, false); - goto out; - } - - for (i = 0; i < VIGS_MAX_PLANES; ++i) { - /* - * If plane was moved/resized or turned on/off - * then we're dirty. - */ - if (server->planes[i].is_dirty) { - planes_dirty = true; - } - - if (server->planes[i].sfc) { - planes_on = true; - - /* - * If plane's surface is dirty then we're dirty. - */ - if (server->planes[i].sfc->is_dirty) { - planes_dirty = true; - } - } - } - - if (root_sfc->ptr && !root_sfc->is_dirty && !planes_on) { - /* - * Root surface is scanout, it's not dirty and planes not on, - * finish immediately. - */ - uint8_t *buff = vigs_server_update_display_start_cb(server, - root_sfc->ws_sfc->width, - root_sfc->ws_sfc->height, - root_sfc->stride, - root_sfc->format); - - memcpy(buff, - root_sfc->ptr, - root_sfc->stride * root_sfc->ws_sfc->height); - - vigs_server_update_display_end_cb(server, true, true); - } else if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty) { - /* - * Composite root surface and planes. - */ - server->backend->batch_start(server->backend); - server->backend->composite(root_sfc, - &server->planes[0], - &vigs_server_update_display_start_cb, - &vigs_server_update_display_end_cb, - server); - server->backend->batch_end(server->backend); - - root_sfc->is_dirty = false; - - for (i = 0; i < VIGS_MAX_PLANES; ++i) { - if (server->planes[i].is_dirty) { - server->planes[i].is_dirty = false; - } - - if (server->planes[i].sfc && - server->planes[i].sfc->is_dirty) { - server->planes[i].sfc->is_dirty = false; - } - } - } else { - /* - * No changes, no-op. - */ - vigs_server_update_display_end_cb(server, false, false); - } + qemu_mutex_unlock(&server->dpy_mutex); -out: g_free(item); } @@ -631,7 +503,6 @@ static void vigs_server_dispatch_set_root_surface(void *user_data, { struct vigs_server *server = user_data; struct vigs_server_set_root_surface_work_item *item; - uint32_t capture_fence_seq = 0; item = g_malloc(sizeof(*item)); @@ -644,20 +515,9 @@ static void vigs_server_dispatch_set_root_surface(void *user_data, work_queue_add_item(server->render_queue, &item->base); - qemu_mutex_lock(&server->capture_mutex); - - if (server->is_capturing) { - capture_fence_seq = server->capture_fence_seq; - server->capture_fence_seq = fence_seq; - } else { - capture_fence_seq = fence_seq; - } - - qemu_mutex_unlock(&server->capture_mutex); - - if (capture_fence_seq) { + if (fence_seq) { server->display_ops->fence_ack(server->display_user_data, - capture_fence_seq); + fence_seq); } } @@ -719,7 +579,7 @@ struct vigs_server *vigs_server_create(uint8_t *vram_ptr, NULL, vigs_server_surface_destroy_func); - qemu_mutex_init(&server->capture_mutex); + qemu_mutex_init(&server->dpy_mutex); return server; @@ -736,8 +596,7 @@ void vigs_server_destroy(struct vigs_server *server) g_hash_table_destroy(server->surfaces); vigs_comm_destroy(server->comm); server->backend->destroy(server->backend); - qemu_mutex_destroy(&server->capture_mutex); - g_free(server->captured.data); + qemu_mutex_destroy(&server->dpy_mutex); g_free(server); } @@ -776,86 +635,92 @@ void vigs_server_dispatch(struct vigs_server *server, bool vigs_server_update_display(struct vigs_server *server, int invalidate_cnt) { bool updated = false; - uint32_t sfc_bpp; + struct vigs_surface *root_sfc; uint32_t display_stride, display_bpp; uint8_t *display_data; + int i; + bool planes_on = false; + bool planes_dirty = false; + + qemu_mutex_lock(&server->dpy_mutex); - qemu_mutex_lock(&server->capture_mutex); + root_sfc = server->root_sfc; - if (!server->captured.data || - (!server->captured.dirty && invalidate_cnt <= 0)) { + if (!root_sfc) { goto out; } - server->captured.dirty = false; - updated = true; - - sfc_bpp = vigs_format_bpp(server->captured.format); - server->display_ops->resize(server->display_user_data, - server->captured.width, - server->captured.height); + root_sfc->ws_sfc->width, + root_sfc->ws_sfc->height); display_stride = server->display_ops->get_stride(server->display_user_data); display_bpp = server->display_ops->get_bpp(server->display_user_data); display_data = server->display_ops->get_data(server->display_user_data); - if (sfc_bpp != display_bpp) { - VIGS_LOG_CRITICAL("bpp mismatch"); + if ((vigs_format_bpp(root_sfc->format) != display_bpp) || + (root_sfc->stride != display_stride)) { + VIGS_LOG_CRITICAL("bpp/format mismatch"); assert(false); - exit(1); - } - - if (display_stride == server->captured.stride) { - switch (server->captured.format) { - case vigsp_surface_bgrx8888: - case vigsp_surface_bgra8888: - memcpy(display_data, - server->captured.data, - server->captured.height * display_stride); - break; - default: - assert(false); - VIGS_LOG_CRITICAL("unknown format: %d", server->captured.format); - exit(1); + goto out; + } + + for (i = 0; i < VIGS_MAX_PLANES; ++i) { + /* + * If plane was moved/resized or turned on/off + * then we're dirty. + */ + if (server->planes[i].is_dirty) { + planes_dirty = true; } - } else { - uint32_t i; - uint8_t *src = server->captured.data; - uint8_t *dst = display_data; - - for (i = 0; i < server->captured.height; ++i) { - switch (server->captured.format) { - case vigsp_surface_bgrx8888: - case vigsp_surface_bgra8888: - memcpy(dst, src, server->captured.width * sfc_bpp); - break; - default: - assert(false); - VIGS_LOG_CRITICAL("unknown format: %d", server->captured.format); - exit(1); + + if (server->planes[i].sfc) { + planes_on = true; + + /* + * If plane's surface is dirty then we're dirty. + */ + if (server->planes[i].sfc->is_dirty) { + planes_dirty = true; } - src += server->captured.stride; - dst += display_stride; } } -out: - qemu_mutex_unlock(&server->capture_mutex); + if (root_sfc->ptr && !root_sfc->is_dirty && !planes_on) { + /* + * Root surface is scanout, it's not dirty and planes not on. + */ - if (!server->is_capturing) { - struct vigs_server_work_item *item; + memcpy(display_data, + root_sfc->ptr, + root_sfc->stride * root_sfc->ws_sfc->height); - item = g_malloc(sizeof(*item)); + updated = true; + } else if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty || (invalidate_cnt > 0)) { + /* + * Composite root surface and planes. + */ - work_queue_item_init(&item->base, &vigs_server_update_display_work); + updated = server->backend->composite(root_sfc, + &server->planes[0], + display_data); - item->server = server; + root_sfc->is_dirty = false; - server->is_capturing = true; + for (i = 0; i < VIGS_MAX_PLANES; ++i) { + if (server->planes[i].is_dirty) { + server->planes[i].is_dirty = false; + } - work_queue_add_item(server->render_queue, &item->base); + if (server->planes[i].sfc && + server->planes[i].sfc->is_dirty) { + server->planes[i].sfc->is_dirty = false; + } + } } +out: + qemu_mutex_unlock(&server->dpy_mutex); + return updated; } diff --git a/hw/vigs/vigs_server.h b/hw/vigs/vigs_server.h index 7bb902bd87..6614dce83c 100644 --- a/hw/vigs/vigs_server.h +++ b/hw/vigs/vigs_server.h @@ -96,21 +96,7 @@ struct vigs_server struct vigs_plane planes[VIGS_MAX_PLANES]; - QemuMutex capture_mutex; - - bool is_capturing; - - uint32_t capture_fence_seq; - - struct - { - uint8_t *data; - uint32_t width; - uint32_t height; - uint32_t stride; - vigsp_surface_format format; - bool dirty; - } captured; + QemuMutex dpy_mutex; /* * @} diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c index 5991089237..991661b430 100644 --- a/hw/vigs/vigs_sw_backend.c +++ b/hw/vigs/vigs_sw_backend.c @@ -364,33 +364,29 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend * return &sw_sfc->base; } -static void vigs_sw_backend_composite(struct vigs_surface *surface, +static bool vigs_sw_backend_composite(struct vigs_surface *surface, const struct vigs_plane *planes, - vigs_composite_start_cb start_cb, - vigs_composite_end_cb end_cb, - void *user_data) + uint8_t *display_data) { struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)surface; - uint8_t *buff; /* * TODO: Render planes. */ - buff = start_cb(user_data, surface->ws_sfc->width, surface->ws_sfc->height, - surface->stride, surface->format); - if (surface->ptr) { - memcpy(buff, + memcpy(display_data, surface->ptr, surface->stride * surface->ws_sfc->height); + return true; } else if (surface->is_dirty) { - memcpy(buff, + memcpy(display_data, sw_sfc->data, surface->stride * surface->ws_sfc->height); + return true; } - end_cb(user_data, true, true); + return false; } static void vigs_sw_backend_batch_end(struct vigs_backend *backend) diff --git a/tizen/src/display/maru_display.c b/tizen/src/display/maru_display.c index 5c585e6620..d351ae9021 100644 --- a/tizen/src/display/maru_display.c +++ b/tizen/src/display/maru_display.c @@ -54,6 +54,19 @@ static void maru_display_notify_exit(Notifier *notifier, void *data) { } static Notifier maru_display_exit = { .notify = maru_display_notify_exit }; +void maru_display_early_init(DisplayType display_type) +{ + switch (display_type) { +#ifdef CONFIG_QT + case DT_MARU_QT: + maru_qt5_display_early_init(); + break; +#endif + default: + break; + } +} + //TODO: interface void maru_display_init(DisplayState *ds, DisplayType display_type, int full_screen) { diff --git a/tizen/src/display/maru_display.h b/tizen/src/display/maru_display.h index b1ff6f63d7..a4814cbfd3 100644 --- a/tizen/src/display/maru_display.h +++ b/tizen/src/display/maru_display.h @@ -52,6 +52,7 @@ typedef struct MaruScreenShot { bool ready; } MaruScreenShot; +void maru_display_early_init(DisplayType display_type); void maru_display_init(DisplayState *ds, DisplayType display_type, int full_screen); void maru_display_resize(void); void maru_display_update(void); @@ -72,6 +73,8 @@ void maru_sdl_pre_init(MaruDisplayChangeListener *mdcl); void maru_shm_pre_init(MaruDisplayChangeListener *mdcl); // maru_qt +void maru_qt5_display_early_init(void); + void maru_qt5_display_init(MaruDisplayChangeListener *mdcl, int full_screen); #endif /* __MARU_DISPLAY_H__ */ diff --git a/tizen/src/display/qt5.c b/tizen/src/display/qt5.c index 64e3976f6a..43d3c30aab 100644 --- a/tizen/src/display/qt5.c +++ b/tizen/src/display/qt5.c @@ -60,8 +60,9 @@ static void qt5_switch(DisplayChangeListener *dcl, static void qt5_refresh(DisplayChangeListener *dcl) { + qt5_pre_refresh_internal(); graphic_hw_update(dcl->con); - qt5_refresh_internal(); + qt5_post_refresh_internal(); } static void qt5_mouse_warp(DisplayChangeListener *dcl, @@ -83,6 +84,11 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = qt5_mouse_define, }; +void maru_qt5_display_early_init(void) +{ + qt5_early_prepare(); +} + void maru_qt5_display_init(MaruDisplayChangeListener *mdcl, int full_screen) { int i; diff --git a/tizen/src/display/qt5_supplement.cpp b/tizen/src/display/qt5_supplement.cpp index 87a1507823..0003cd9589 100644 --- a/tizen/src/display/qt5_supplement.cpp +++ b/tizen/src/display/qt5_supplement.cpp @@ -115,6 +115,13 @@ void qt5_skin_init(void) // app.exec(); } +void qt5_early_prepare(void) +{ + Q_INIT_RESOURCE(resource); + + app = new QApplication(argc, argv); +} + void qt5_prepare(void) { qt5_skin_init(); @@ -140,8 +147,14 @@ void qt5_switch_internal(void) { } -void qt5_refresh_internal(void) +void qt5_pre_refresh_internal(void) +{ + mainwindow->makeCurrent(true); +} + +void qt5_post_refresh_internal(void) { + mainwindow->makeCurrent(false); app->processEvents(); } diff --git a/tizen/src/display/qt5_supplement.h b/tizen/src/display/qt5_supplement.h index c83410b047..999c34ebc8 100644 --- a/tizen/src/display/qt5_supplement.h +++ b/tizen/src/display/qt5_supplement.h @@ -48,11 +48,13 @@ private: #ifdef __cplusplus extern "C" { #endif +void qt5_early_prepare(void); void qt5_prepare(void); void qt5_update_internal(void *data, int width, int height); void qt5_switch_internal(void); -void qt5_refresh_internal(void); +void qt5_pre_refresh_internal(void); +void qt5_post_refresh_internal(void); #ifdef __cplusplus } #endif diff --git a/tizen/src/ui/displaywidget.cpp b/tizen/src/ui/displaywidget.cpp index b159361852..e92fd36ee3 100644 --- a/tizen/src/ui/displaywidget.cpp +++ b/tizen/src/ui/displaywidget.cpp @@ -8,8 +8,8 @@ void do_mouse_event(int button_type, int event_type, int origin_x, int origin_y, int x, int y, int z); } -DisplayWidget::DisplayWidget(QSize resolution, QWidget *parent) : - QGLWidget(QGLFormat(QGL::SampleBuffers), parent) +DisplayWidget::DisplayWidget(QSize resolution, QGLContext *context, QWidget *parent) : + QGLWidget(context, parent) { /* initialize */ // TODO: compare display region with resolution @@ -21,51 +21,13 @@ DisplayWidget::DisplayWidget(QSize resolution, QWidget *parent) : elapsed = 0; //setAutoFillBackground(false); + + setAutoBufferSwap(false); } void DisplayWidget::initializeGL() { qDebug("initialize GL"); - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(300); -} - -void DisplayWidget::update() -{ - elapsed += 100; - repaint(); -} - -void DisplayWidget::paintEvent(QPaintEvent *event) -{ - /* temporary */ - - QPainter painter; - painter.begin(this); - painter.setRenderHint(QPainter::Antialiasing); - - painter.fillRect(event->rect(), QBrush(QColor(255, 255, 255))); - painter.translate(size().width() / 2, size().height() / 2); - - painter.scale(scaleFactor, scaleFactor); - painter.rotate(rotateAngle); - - /* drawing */ - painter.save(); - painter.rotate(elapsed * 0.030); - - for (int i = 0; i < 11; ++i) { - painter.rotate(30); - qreal circleRadius = 20; - painter.drawEllipse(QRect(120, -circleRadius, circleRadius * 2, circleRadius * 2)); - } - painter.restore(); - - painter.drawText(QRect(0, 0, 50, 50), Qt::AlignCenter, "Tizen"); - - painter.end(); } void DisplayWidget::rotate(int angle) diff --git a/tizen/src/ui/displaywidget.h b/tizen/src/ui/displaywidget.h index 69e6a39c72..6bdf09ab04 100644 --- a/tizen/src/ui/displaywidget.h +++ b/tizen/src/ui/displaywidget.h @@ -8,19 +8,15 @@ class DisplayWidget : public QGLWidget Q_OBJECT public: - DisplayWidget(QSize resolution, QWidget *parent = 0); + DisplayWidget(QSize resolution, QGLContext *context, QWidget *parent = 0); ~DisplayWidget(); void rotate(int angle); void scale(int scale); -public slots: - void update(); - protected: void initializeGL(); - void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); void mousePressEvent(QMouseEvent *event); diff --git a/tizen/src/ui/mainwindow.cpp b/tizen/src/ui/mainwindow.cpp index 5a4b609ae7..09c48b038e 100644 --- a/tizen/src/ui/mainwindow.cpp +++ b/tizen/src/ui/mainwindow.cpp @@ -9,6 +9,9 @@ extern "C" void shutdown_qemu_gracefully(void); #endif +QOpenGLContext *qt5GLContext = NULL; +QSurfaceFormat qt5GLFormat; + MainWindow::MainWindow(UIInformation *uiInfo, QWidget *parent) : QWidget(parent) { @@ -61,8 +64,28 @@ MainWindow::MainWindow(UIInformation *uiInfo, QWidget *parent) : winLayout->addWidget(conView); } + QGLContext *wrapperContext = QGLContext::fromOpenGLContext(qt5GLContext); + + /* + * Qt5 bug, wrapperContext->requestedFormat() doesn't return + * originating format, it returns actual format, this may result + * in wrong OpenGL context version here. + */ + + QGLFormat format = QGLFormat::fromSurfaceFormat(qt5GLFormat); + + /* + * Qt5 bug, format set here doesn't always have effect, must + * set it after QGLWidget is created. + */ + QGLContext *context = new QGLContext(format); + /* display */ - display = new DisplayWidget(uiInfo->resolution, skinView); + display = new DisplayWidget(uiInfo->resolution, context, skinView); + + context->setFormat(format); + + context->create(wrapperContext); /* popup menu */ popupMenu = new ContextMenu(this); @@ -77,6 +100,16 @@ QLabel *MainWindow::getLabel() return label; } +void MainWindow::makeCurrent(bool value) +{ + if (value) { + display->makeCurrent(); + } else { + display->swapBuffers(); + display->doneCurrent(); + } +} + void MainWindow::showContextMenu(const QPoint& pos) { QPoint globalPos = this->mapToGlobal(pos); diff --git a/tizen/src/ui/mainwindow.h b/tizen/src/ui/mainwindow.h index 2ffd47dc5a..363b599dcf 100644 --- a/tizen/src/ui/mainwindow.h +++ b/tizen/src/ui/mainwindow.h @@ -29,6 +29,9 @@ public: UIInformation *uiInfo; QLabel *getLabel(); QImage *image; + + void makeCurrent(bool value); + public slots: void showContextMenu(const QPoint& pos); diff --git a/vl.c b/vl.c index bfbd739c8b..35a248e6b0 100644 --- a/vl.c +++ b/vl.c @@ -4065,6 +4065,8 @@ int main(int argc, char **argv, char **envp) exit(1); } + maru_display_early_init(display_type); + current_machine = MACHINE(object_new(object_class_get_name( OBJECT_CLASS(machine_class)))); object_property_add_child(object_get_root(), "machine",