diff options
26 files changed, 1084 insertions, 684 deletions
diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c index 9995d1c15a..94b95ff5c0 100644 --- a/hw/vigs/vigs_gl_backend.c +++ b/hw/vigs/vigs_gl_backend.c @@ -36,8 +36,20 @@ #include "vigs_ref.h" #include "vigs_qt5.h" #include "winsys_gl.h" +#include "hw/pci/maru_brightness.h" #include <math.h> +extern uint32_t qt5_window_width; +extern uint32_t qt5_window_height; +extern int qt5_window_angle; + +/* multitouch data */ +extern float *qt5_mt_points; +extern int qt5_mt_count; +extern const void *qt5_mt_pixels; +extern int qt5_mt_width; +extern int qt5_mt_height; + struct vigs_gl_surface; struct vigs_winsys_gl_surface @@ -189,6 +201,136 @@ static const char *g_fs_color_source_gl3 = " FragColor = color;\n" "}\n"; +static const char *g_fs_dpy_source_gl2 = + "#version 120\n\n" + "uniform sampler2D tex;\n" + "uniform float brightness;\n" + "varying vec2 v_texCoord;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(tex, v_texCoord) * brightness;\n" + "}\n"; + +static const char *g_fs_dpy_source_gl3 = + "#version 140\n\n" + "uniform sampler2D tex;\n" + "uniform float brightness;\n" + "in vec2 v_texCoord;\n" + "out vec4 FragColor;\n" + "void main()\n" + "{\n" + " FragColor = texture(tex, v_texCoord) * brightness;\n" + "}\n"; + +static const char *g_fs_scale_source_gl2 = +"#version 120\n\ +\n\ +uniform sampler2D tex;\n\ +uniform float brightness;\n\ +uniform vec2 texSize;\n\ +varying vec2 v_texCoord;\n\ +vec4 cubic(float x)\n\ +{\n\ + float x2 = x * x;\n\ + float x3 = x2 * x;\n\ + vec4 w;\n\ + w.x = -x3 + 3*x2 - 3*x + 1;\n\ + w.y = 3*x3 - 6*x2 + 4;\n\ + w.z = -3*x3 + 3*x2 + 3*x + 1;\n\ + w.w = x3;\n\ + return w / 6.f;\n\ +}\n\ +void main()\n\ +{\n\ + vec2 texscale = vec2(1.0 / texSize.x, 1.0 / texSize.y);\n\ + vec2 texcoord = vec2(v_texCoord.x * texSize.x, v_texCoord.y * texSize.y);\n\ + float fx = fract(texcoord.x);\n\ + float fy = fract(texcoord.y);\n\ + texcoord.x -= fx;\n\ + texcoord.y -= fy;\n\ +\n\ + vec4 xcubic = cubic(fx);\n\ + vec4 ycubic = cubic(fy);\n\ +\n\ + vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y -\n\ +0.5, texcoord.y + 1.5);\n\ + vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x +\n\ +ycubic.y, ycubic.z + ycubic.w);\n\ + vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) /\n\ +s;\n\ +\n\ + vec4 sample0 = texture2D(tex, vec2(offset.x, offset.z) *\n\ +texscale);\n\ + vec4 sample1 = texture2D(tex, vec2(offset.y, offset.z) *\n\ +texscale);\n\ + vec4 sample2 = texture2D(tex, vec2(offset.x, offset.w) *\n\ +texscale);\n\ + vec4 sample3 = texture2D(tex, vec2(offset.y, offset.w) *\n\ +texscale);\n\ +\n\ + float sx = s.x / (s.x + s.y);\n\ + float sy = s.z / (s.z + s.w);\n\ +\n\ + gl_FragColor = mix(\n\ + mix(sample3, sample2, sx),\n\ + mix(sample1, sample0, sx), sy) * brightness;\n\ +}"; + +static const char *g_fs_scale_source_gl3 = +"#version 140\n\ +\n\ +uniform sampler2D tex;\n\ +uniform float brightness;\n\ +uniform vec2 texSize;\n\ +in vec2 v_texCoord;\n\ +out vec4 FragColor;\n\ +vec4 cubic(float x)\n\ +{\n\ + float x2 = x * x;\n\ + float x3 = x2 * x;\n\ + vec4 w;\n\ + w.x = -x3 + 3*x2 - 3*x + 1;\n\ + w.y = 3*x3 - 6*x2 + 4;\n\ + w.z = -3*x3 + 3*x2 + 3*x + 1;\n\ + w.w = x3;\n\ + return w / 6.f;\n\ +}\n\ +void main()\n\ +{\n\ + vec2 texscale = vec2(1.0 / texSize.x, 1.0 / texSize.y);\n\ + vec2 texcoord = vec2(v_texCoord.x * texSize.x, v_texCoord.y * texSize.y);\n\ + float fx = fract(texcoord.x);\n\ + float fy = fract(texcoord.y);\n\ + texcoord.x -= fx;\n\ + texcoord.y -= fy;\n\ +\n\ + vec4 xcubic = cubic(fx);\n\ + vec4 ycubic = cubic(fy);\n\ +\n\ + vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y -\n\ +0.5, texcoord.y + 1.5);\n\ + vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x +\n\ +ycubic.y, ycubic.z + ycubic.w);\n\ + vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) /\n\ +s;\n\ +\n\ + vec4 sample0 = texture(tex, vec2(offset.x, offset.z) *\n\ +texscale);\n\ + vec4 sample1 = texture(tex, vec2(offset.y, offset.z) *\n\ +texscale);\n\ + vec4 sample2 = texture(tex, vec2(offset.x, offset.w) *\n\ +texscale);\n\ + vec4 sample3 = texture(tex, vec2(offset.y, offset.w) *\n\ +texscale);\n\ +\n\ + float sx = s.x / (s.x + s.y);\n\ + float sy = s.z / (s.z + s.w);\n\ +\n\ + FragColor = mix(\n\ + mix(sample3, sample2, sx),\n\ + mix(sample1, sample0, sx), sy) * brightness;\n\ +}"; + static const char *g_vs_nv21_source_gl2 = "#version 120\n\n" "attribute vec4 vertCoord;\n" @@ -600,6 +742,102 @@ 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_draw_dpy_scale_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_scale_prog_vertCoord_loc); + backend->EnableVertexAttribArray(backend->dpy_scale_prog_texCoord_loc); + + backend->VertexAttribPointer(backend->dpy_scale_prog_vertCoord_loc, + 2, GL_FLOAT, GL_FALSE, 0, NULL); + backend->VertexAttribPointer(backend->dpy_scale_prog_texCoord_loc, + 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); + + backend->DrawArrays(GL_TRIANGLES, 0, count); + + backend->DisableVertexAttribArray(backend->dpy_scale_prog_texCoord_loc); + backend->DisableVertexAttribArray(backend->dpy_scale_prog_vertCoord_loc); +} + static void vigs_gl_draw_nv21_prog(struct vigs_gl_backend *backend, uint32_t count) { @@ -656,6 +894,28 @@ static void vigs_gl_create_ortho(GLfloat left, GLfloat right, ortho[15] = 1.0f; } +static void vigs_gl_rotate_ortho(const GLfloat ortho[16], + GLfloat angle, + GLfloat res[16]) +{ + GLfloat rot[4][4] = { + { cos(angle), sin(angle), 0, 0 }, + { -sin(angle), cos(angle), 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }; + int i, j, k; + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + res[i * 4 + j] = 0.0f; + for (k = 0; k < 4; ++k) { + res[i * 4 + j] += ortho[i * 4 + k] * rot[k][j]; + } + } + } +} + static void vigs_gl_translate_color(vigsp_color color, vigsp_surface_format format, GLfloat res[4]) @@ -766,7 +1026,8 @@ static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc, } static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend, - uint32_t width, uint32_t height) + uint32_t width, uint32_t height, + GLfloat ortho[16]) { GLuint cur_tex = 0; @@ -804,6 +1065,9 @@ static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend, gl_backend->BindTexture(GL_TEXTURE_2D, cur_tex); + memcpy(gl_backend->dpy_tex_ortho, + ortho, + sizeof(gl_backend->dpy_tex_ortho)); gl_backend->dpy_tex_width = width; gl_backend->dpy_tex_height = height; @@ -1971,7 +2235,8 @@ static bool vigs_gl_backend_composite(struct vigs_surface *surface, if (!vigs_gl_update_dpy_texture(gl_backend, surface->ws_sfc->width, - surface->ws_sfc->height)) { + surface->ws_sfc->height, + gl_root_sfc->ortho)) { goto out; } @@ -2176,34 +2441,219 @@ static bool vigs_gl_backend_display(struct vigs_backend *backend, VIGS_LOG_TRACE("enter"); if (vigs_qt5_onscreen_enabled()) { - vigs_qt5_dpy_render_texture(gl_backend->dpy_tex); - return true; - } + GLfloat *vert_coords; + GLfloat *tex_coords; + bool scale; + GLfloat rotated_ortho[16]; + GLfloat *ortho; + float brightness = (float)(255 - brightness_tbl[brightness_level]) / 255.0f; + int i, mt_count = qt5_mt_count; + + if (display_off) { + brightness = 0.0f; + } - if (gl_backend->read_pixels_make_current(gl_backend, true)) { - if (!gl_backend->dpy_fb) { - gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb); - if (!gl_backend->dpy_fb) { - VIGS_LOG_CRITICAL("cannot create FB"); + 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); } - gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb); + gl_backend->BindVertexArray(gl_backend->dpy_vao); } - gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, gl_backend->dpy_tex, 0); + gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->dpy_vbo); + gl_backend->Disable(GL_DEPTH_TEST); + gl_backend->Disable(GL_BLEND); - gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width, - gl_backend->dpy_tex_height, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - display_data); + if (qt5_window_angle == 0) { + ortho = gl_backend->dpy_tex_ortho; + } else { + vigs_gl_rotate_ortho(gl_backend->dpy_tex_ortho, + (float)(360.0f - qt5_window_angle) * M_PI / 180.0f, + rotated_ortho); + ortho = rotated_ortho; + } - gl_backend->read_pixels_make_current(gl_backend, false); + scale = (qt5_window_width != gl_backend->dpy_tex_width) || + (qt5_window_height != gl_backend->dpy_tex_height); + + gl_backend->Viewport(0, 0, + qt5_window_width, + qt5_window_height); + + if (scale) { + float texSize[2]; + + gl_backend->UseProgram(gl_backend->dpy_scale_prog_id); + gl_backend->UniformMatrix4fv(gl_backend->dpy_scale_prog_proj_loc, 1, GL_FALSE, + ortho); + + texSize[0] = gl_backend->dpy_tex_width; + texSize[1] = gl_backend->dpy_tex_height; + + gl_backend->Uniform2fv(gl_backend->dpy_scale_prog_texSize_loc, 1, texSize); + gl_backend->Uniform1f(gl_backend->dpy_scale_prog_brightness_loc, brightness); + } else { + gl_backend->UseProgram(gl_backend->dpy_tex_prog_id); + gl_backend->UniformMatrix4fv(gl_backend->dpy_tex_prog_proj_loc, 1, GL_FALSE, + ortho); + gl_backend->Uniform1f(gl_backend->dpy_tex_prog_brightness_loc, brightness); + } + + gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->dpy_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->dpy_v2, + (12 * sizeof(GLfloat))); + + vert_coords[6] = vert_coords[0] = 0; + vert_coords[7] = vert_coords[1] = gl_backend->dpy_tex_height; + vert_coords[2] = gl_backend->dpy_tex_width; + vert_coords[3] = gl_backend->dpy_tex_height; + vert_coords[8] = vert_coords[4] = gl_backend->dpy_tex_width; + vert_coords[9] = vert_coords[5] = 0; + vert_coords[10] = 0; + vert_coords[11] = 0; + + tex_coords[6] = tex_coords[0] = 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; + + if (scale) { + vigs_gl_draw_dpy_scale_prog(gl_backend, 6); + } else { + vigs_gl_draw_dpy_tex_prog(gl_backend, 6); + } + + if (!gl_backend->mt_tex) { + GLuint mt_tex = 0; + + if (!qt5_mt_pixels || qt5_mt_width == 0 || qt5_mt_height == 0) { + /* multitouch not initialized */ + goto out; + } + + gl_backend->GenTextures(1, &mt_tex); + + if (!mt_tex) { + VIGS_LOG_WARN("MT: GenTextures failed"); + goto out; + } + + gl_backend->BindTexture(GL_TEXTURE_2D, mt_tex); + + gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + gl_backend->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, + qt5_mt_width, qt5_mt_height, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + qt5_mt_pixels); + + gl_backend->mt_tex = mt_tex; + gl_backend->mt_tex_width = qt5_mt_width; + gl_backend->mt_tex_height = qt5_mt_height; + } else { + gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->mt_tex); + } + + vigs_vector_resize(&gl_backend->dpy_v1, 0); + vigs_vector_resize(&gl_backend->dpy_v2, 0); + + for (i = 0; i < mt_count; i++) { + GLfloat w = (GLfloat)gl_backend->mt_tex_width; + GLfloat h = (GLfloat)gl_backend->mt_tex_height; + GLfloat x = qt5_mt_points[2 * i + 0] - w / 2; + GLfloat y = qt5_window_height - qt5_mt_points[2 * i + 1] - h / 2; + + vert_coords = vigs_vector_append(&gl_backend->dpy_v1, + (12 * sizeof(GLfloat))); + tex_coords = vigs_vector_append(&gl_backend->dpy_v2, + (12 * sizeof(GLfloat))); + + vert_coords[6] = vert_coords[0] = x; + vert_coords[7] = vert_coords[1] = y; + vert_coords[2] = x + w; + vert_coords[3] = y; + vert_coords[8] = vert_coords[4] = x + w; + vert_coords[9] = vert_coords[5] = y + h; + vert_coords[10] = x; + vert_coords[11] = y + h; + + 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; + } + + if (mt_count) { + vigs_gl_create_ortho(0.0f, qt5_window_width, + 0.0f, qt5_window_height, + -1.0f, 1.0f, + gl_backend->mt_tex_ortho); + + gl_backend->Enable(GL_BLEND); + gl_backend->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + gl_backend->UseProgram(gl_backend->dpy_tex_prog_id); + gl_backend->UniformMatrix4fv(gl_backend->dpy_tex_prog_proj_loc, 1, GL_FALSE, + gl_backend->mt_tex_ortho); + gl_backend->Uniform1f(gl_backend->dpy_tex_prog_brightness_loc, 1.0f); + + vigs_gl_draw_dpy_tex_prog(gl_backend, mt_count * 6); + + gl_backend->Disable(GL_BLEND); + } + +out: + gl_backend->Finish(); return true; } else { - return false; + if (gl_backend->read_pixels_make_current(gl_backend, true)) { + if (!gl_backend->dpy_fb) { + gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb); + + if (!gl_backend->dpy_fb) { + VIGS_LOG_CRITICAL("cannot create FB"); + exit(1); + } + + gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb); + } + + gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, gl_backend->dpy_tex, 0); + + gl_backend->ReadPixels(0, 0, gl_backend->dpy_tex_width, + gl_backend->dpy_tex_height, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + display_data); + + gl_backend->read_pixels_make_current(gl_backend, false); + + return true; + } else { + return false; + } } } @@ -2373,7 +2823,9 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) gl_backend->yuv420_prog_vtex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtex"); gl_backend->GenBuffers(1, &gl_backend->vbo); - if (!gl_backend->vbo) { + gl_backend->GenBuffers(1, &gl_backend->dpy_vbo); + + if (!gl_backend->vbo || !gl_backend->dpy_vbo) { VIGS_LOG_CRITICAL("cannot create VBOs"); goto fail; } @@ -2392,6 +2844,65 @@ 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->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->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_dpy_source_gl2 : g_fs_dpy_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->dpy_tex_prog_brightness_loc = gl_backend->GetUniformLocation(gl_backend->dpy_tex_prog_id, "brightness"); + + gl_backend->dpy_scale_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->dpy_scale_prog_vs_id) { + goto fail; + } + + gl_backend->dpy_scale_prog_fs_id = vigs_gl_create_shader(gl_backend, + (gl_backend->is_gl_2 ? g_fs_scale_source_gl2 : g_fs_scale_source_gl3), + GL_FRAGMENT_SHADER); + + if (!gl_backend->dpy_scale_prog_fs_id) { + goto fail; + } + + gl_backend->dpy_scale_prog_id = vigs_gl_create_program(gl_backend, + gl_backend->dpy_scale_prog_vs_id, + gl_backend->dpy_scale_prog_fs_id); + + if (!gl_backend->dpy_scale_prog_id) { + goto fail; + } + + gl_backend->dpy_scale_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->dpy_scale_prog_id, "proj"); + gl_backend->dpy_scale_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->dpy_scale_prog_id, "vertCoord"); + gl_backend->dpy_scale_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->dpy_scale_prog_id, "texCoord"); + gl_backend->dpy_scale_prog_texSize_loc = gl_backend->GetUniformLocation(gl_backend->dpy_scale_prog_id, "texSize"); + gl_backend->dpy_scale_prog_brightness_loc = gl_backend->GetUniformLocation(gl_backend->dpy_scale_prog_id, "brightness"); + gl_backend->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl_backend->Disable(GL_DEPTH_TEST); gl_backend->Disable(GL_BLEND); @@ -2407,6 +2918,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); + vigs_vector_init(&gl_backend->dpy_v1, 0); + vigs_vector_init(&gl_backend->dpy_v2, 0); return true; @@ -2419,12 +2932,30 @@ fail: void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend) { if (gl_backend->make_current(gl_backend, true)) { + if (gl_backend->mt_tex) { + gl_backend->DeleteTextures(1, &gl_backend->mt_tex); + } if (gl_backend->dpy_tex) { gl_backend->DeleteTextures(1, &gl_backend->dpy_tex); } if (gl_backend->dpy_fb) { gl_backend->DeleteFramebuffers(1, &gl_backend->dpy_fb); } + gl_backend->DeleteBuffers(1, &gl_backend->dpy_vbo); + gl_backend->DetachShader(gl_backend->dpy_scale_prog_id, + gl_backend->dpy_scale_prog_vs_id); + gl_backend->DetachShader(gl_backend->dpy_scale_prog_id, + gl_backend->dpy_scale_prog_fs_id); + gl_backend->DeleteShader(gl_backend->dpy_scale_prog_vs_id); + gl_backend->DeleteShader(gl_backend->dpy_scale_prog_fs_id); + gl_backend->DeleteProgram(gl_backend->dpy_scale_prog_id); + 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->yuv420_prog_id, gl_backend->yuv420_prog_vs_id); @@ -2465,6 +2996,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 ca2d3658ab..dca456b06c 100644 --- a/hw/vigs/vigs_gl_backend.h +++ b/hw/vigs/vigs_gl_backend.h @@ -220,11 +220,43 @@ struct vigs_gl_backend * Display thread related. * @{ */ + + struct vigs_vector dpy_v1; + struct vigs_vector dpy_v2; + + 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; + GLint dpy_tex_prog_brightness_loc; + + GLuint dpy_scale_prog_vs_id; + GLuint dpy_scale_prog_fs_id; + GLuint dpy_scale_prog_id; + GLint dpy_scale_prog_proj_loc; + GLint dpy_scale_prog_vertCoord_loc; + GLint dpy_scale_prog_texCoord_loc; + GLint dpy_scale_prog_texSize_loc; + GLint dpy_scale_prog_brightness_loc; + + GLuint dpy_vbo; + uint32_t dpy_vbo_size; + GLuint dpy_tex; GLuint dpy_fb; + GLfloat dpy_tex_ortho[16]; uint32_t dpy_tex_width; uint32_t dpy_tex_height; + GLuint mt_tex; + GLfloat mt_tex_ortho[16]; + uint32_t mt_tex_width; + uint32_t mt_tex_height; + /* * @} */ diff --git a/hw/vigs/vigs_gl_backend_cgl.c b/hw/vigs/vigs_gl_backend_cgl.c index cc0eabe2e5..7a41d0a8ab 100644 --- a/hw/vigs/vigs_gl_backend_cgl.c +++ b/hw/vigs/vigs_gl_backend_cgl.c @@ -62,7 +62,7 @@ static const CGLPixelFormatAttribute pixel_format_legacy_attrs[] = kCGLPFAAlphaSize, 8, kCGLPFADepthSize, 24, kCGLPFAStencilSize, 8, - kCGLPFAOpenGLProfile, kCGLOGLPVersion_Legacy, + kCGLPFAPBuffer, 0 }; @@ -255,7 +255,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display, CGLError error; CGLPixelFormatObj pixel_format; int n; - CGLContextObj share_ctx = NULL; + CGLContextObj qt5_ctx = NULL; gl_backend_cgl = g_malloc0(sizeof(*gl_backend_cgl)); @@ -378,15 +378,15 @@ struct vigs_backend *vigs_gl_backend_create(void *display, } if (vigs_qt5_onscreen_enabled()) { - share_ctx = (CGLContextObj)vigs_qt5_gl_context_get(); - if (!share_ctx) { + qt5_ctx = (CGLContextObj)vigs_qt5_gl_context_create(gl_backend_cgl->base.is_gl_2); + if (!qt5_ctx) { goto fail2; } } if (!vigs_gl_backend_cgl_create_context(gl_backend_cgl, pixel_format, - share_ctx, + qt5_ctx, &gl_backend_cgl->context)) { goto fail3; } diff --git a/hw/vigs/vigs_gl_backend_glx.c b/hw/vigs/vigs_gl_backend_glx.c index 8212b88dbb..4014a832e3 100644 --- a/hw/vigs/vigs_gl_backend_glx.c +++ b/hw/vigs/vigs_gl_backend_glx.c @@ -238,7 +238,7 @@ static GLXFBConfig vigs_gl_backend_glx_get_config(struct vigs_gl_backend_glx *gl }; if (gl_backend_glx->glXQueryContext(gl_backend_glx->dpy, - vigs_qt5_gl_context_get(), + gl_backend_glx->ctx, GLX_FBCONFIG_ID, &config_attribs[1]) != Success) { VIGS_LOG_CRITICAL("Unable to get context's GLX config"); @@ -417,7 +417,7 @@ static void vigs_gl_backend_glx_destroy(struct vigs_backend *backend) gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy, gl_backend_glx->read_pixels_sfc); } - if (gl_backend_glx->ctx) { + if (!vigs_qt5_onscreen_enabled() && gl_backend_glx->ctx) { gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy, gl_backend_glx->ctx); } @@ -443,7 +443,6 @@ struct vigs_backend *vigs_gl_backend_create(void *display, { struct vigs_gl_backend_glx *gl_backend_glx; GLXFBConfig config; - GLXContext share_ctx = NULL; Display *x_display = display; gl_backend_glx = g_malloc0(sizeof(*gl_backend_glx)); @@ -575,35 +574,57 @@ struct vigs_backend *vigs_gl_backend_create(void *display, } if (vigs_qt5_onscreen_enabled()) { - share_ctx = (GLXContext)vigs_qt5_gl_context_get(); - if (!share_ctx) { + 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) { - goto fail2; - } + config = vigs_gl_backend_glx_get_config(gl_backend_glx); - if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, - config, - &gl_backend_glx->read_pixels_sfc)) { - goto fail2; - } + if (!config) { + goto fail2; + } - if (!vigs_gl_backend_glx_create_context(gl_backend_glx, - config, - share_ctx, - &gl_backend_glx->ctx)) { - goto fail2; - } + if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, + config, + &gl_backend_glx->read_pixels_sfc)) { + goto fail2; + } - if (!vigs_gl_backend_glx_create_context(gl_backend_glx, - config, - gl_backend_glx->ctx, - &gl_backend_glx->read_pixels_ctx)) { - goto fail2; + if (!vigs_gl_backend_glx_create_context(gl_backend_glx, + config, + gl_backend_glx->ctx, + &gl_backend_glx->read_pixels_ctx)) { + goto fail2; + } + } else { + config = vigs_gl_backend_glx_get_config(gl_backend_glx); + + if (!config) { + goto fail2; + } + + if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, + config, + &gl_backend_glx->read_pixels_sfc)) { + goto fail2; + } + + if (!vigs_gl_backend_glx_create_context(gl_backend_glx, + config, + NULL, + &gl_backend_glx->ctx)) { + goto fail2; + } + + if (!vigs_gl_backend_glx_create_context(gl_backend_glx, + config, + gl_backend_glx->ctx, + &gl_backend_glx->read_pixels_ctx)) { + goto fail2; + } } if (!vigs_gl_backend_glx_create_surface(gl_backend_glx, @@ -634,7 +655,7 @@ fail2: gl_backend_glx->glXDestroyPbuffer(gl_backend_glx->dpy, gl_backend_glx->read_pixels_sfc); } - if (gl_backend_glx->ctx) { + if (!vigs_qt5_onscreen_enabled() && gl_backend_glx->ctx) { gl_backend_glx->glXDestroyContext(gl_backend_glx->dpy, gl_backend_glx->ctx); } diff --git a/hw/vigs/vigs_gl_backend_wgl.c b/hw/vigs/vigs_gl_backend_wgl.c index 9db01a0a7e..b5b45bcef0 100644 --- a/hw/vigs/vigs_gl_backend_wgl.c +++ b/hw/vigs/vigs_gl_backend_wgl.c @@ -482,7 +482,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display, }; const char *ext_str = NULL; struct vigs_gl_backend_wgl *gl_backend_wgl = NULL; - HGLRC share_ctx = NULL; + HGLRC qt5_ctx = NULL; vigs_win_class.cbSize = sizeof(WNDCLASSEXA); vigs_win_class.style = 0; @@ -687,8 +687,9 @@ struct vigs_backend *vigs_gl_backend_create(void *display, tmp_win = NULL; if (vigs_qt5_onscreen_enabled()) { - share_ctx = (HGLRC)vigs_qt5_gl_context_get(); - if (!share_ctx) { + qt5_ctx = + (HGLRC)vigs_qt5_gl_context_create(gl_backend_wgl->base.is_gl_2); + if (!qt5_ctx) { goto fail; } } @@ -728,7 +729,7 @@ struct vigs_backend *vigs_gl_backend_create(void *display, } if (!vigs_gl_backend_wgl_create_context(gl_backend_wgl, - share_ctx, + qt5_ctx, &gl_backend_wgl->ctx)) { goto fail; } diff --git a/hw/vigs/vigs_onscreen_server.c b/hw/vigs/vigs_onscreen_server.c index d6830783cd..7fcc352b33 100644 --- a/hw/vigs/vigs_onscreen_server.c +++ b/hw/vigs/vigs_onscreen_server.c @@ -32,24 +32,6 @@ #include "vigs_log.h" #include "work_queue.h" -struct vigs_display_work_item -{ - struct work_queue_item base; - - struct vigs_server *server; -}; - -static void vigs_onscreen_server_display_work(struct work_queue_item *wq_item) -{ - struct vigs_display_work_item *item = (struct vigs_display_work_item*)wq_item; - struct vigs_server *server = item->server; - - server->backend->display(server->backend, NULL); - vigs_server_finish_update_display(server, false); - - g_free(item); -} - static bool vigs_onscreen_server_begin_update(struct vigs_server *server, bool is_capturing, bool force) @@ -70,6 +52,10 @@ static bool vigs_onscreen_server_begin_update(struct vigs_server *server, goto out; } + onscreen_server->updated = false; + onscreen_server->composited = false; + onscreen_server->dirty = false; + out: qemu_mutex_unlock(&onscreen_server->mutex); @@ -82,37 +68,73 @@ static void vigs_onscreen_server_finish_update(struct vigs_server *server, { struct vigs_onscreen_server *onscreen_server = (struct vigs_onscreen_server*)server; + + qemu_mutex_lock(&onscreen_server->mutex); + + onscreen_server->updated = true; + onscreen_server->composited = composited; + onscreen_server->dirty = dirty; + + qemu_mutex_unlock(&onscreen_server->mutex); + + qemu_cond_signal(&onscreen_server->cond); +} + +static bool vigs_onscreen_server_display(struct vigs_server *server, + bool *displayed) +{ + struct vigs_onscreen_server *onscreen_server = + (struct vigs_onscreen_server*)server; bool force = false; qemu_mutex_lock(&onscreen_server->mutex); + /* + * Wait until rendering is finished. + */ + while (!onscreen_server->updated) { + qemu_cond_wait(&onscreen_server->cond, &onscreen_server->mutex); + } + if (onscreen_server->invalidate_cnt > 0) { --onscreen_server->invalidate_cnt; force = true; } - qemu_mutex_unlock(&onscreen_server->mutex); - - if (composited || force) { - struct vigs_display_work_item *item; - - item = g_malloc(sizeof(*item)); + onscreen_server->updated = false; - work_queue_item_init(&item->base, &vigs_onscreen_server_display_work); + qemu_mutex_unlock(&onscreen_server->mutex); - item->server = server; + *displayed = true; - work_queue_add_item(onscreen_server->display_queue, &item->base); + if (onscreen_server->dirty) { + /* + * Software composition took place, finish ASAP and + * process captured data. + */ + vigs_server_finish_update_display(server, true); + return vigs_server_process_captured(server, force); + } else if (onscreen_server->composited) { + /* + * Hw composition took place, display the content. + */ + server->backend->display(server->backend, NULL); + } else if (force) { + /* + * Nothing happened, but if it's a forced display, then + * we should try to display hw stuff first, if there isn't any + * then display sw stuff. + */ + if (!server->backend->display(server->backend, NULL)) { + vigs_server_finish_update_display(server, false); + return vigs_server_process_captured(server, force); + } } else { - vigs_server_finish_update_display(server, false); + *displayed = false; } -} + vigs_server_finish_update_display(server, false); -static bool vigs_onscreen_server_display(struct vigs_server *server, - bool *displayed) -{ - *displayed = false; return false; } @@ -128,6 +150,7 @@ static void vigs_onscreen_server_destroy(struct vigs_server *server) struct vigs_onscreen_server *onscreen_server = (struct vigs_onscreen_server*)server; + qemu_cond_destroy(&onscreen_server->cond); qemu_mutex_destroy(&onscreen_server->mutex); vigs_server_cleanup(server); @@ -155,8 +178,7 @@ struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr, } qemu_mutex_init(&server->mutex); - - server->display_queue = render_queue; + qemu_cond_init(&server->cond); server->base.begin_update = &vigs_onscreen_server_begin_update; server->base.finish_update = &vigs_onscreen_server_finish_update; diff --git a/hw/vigs/vigs_onscreen_server.h b/hw/vigs/vigs_onscreen_server.h index 19d083e49c..b0ea1e93d7 100644 --- a/hw/vigs/vigs_onscreen_server.h +++ b/hw/vigs/vigs_onscreen_server.h @@ -37,8 +37,12 @@ struct vigs_onscreen_server struct vigs_server base; QemuMutex mutex; + QemuCond cond; + bool updated; + bool composited; + bool dirty; + int invalidate_cnt; - struct work_queue *display_queue; }; struct vigs_server *vigs_onscreen_server_create(uint8_t *vram_ptr, diff --git a/hw/vigs/vigs_qt5.cpp b/hw/vigs/vigs_qt5.cpp index 286014eff7..927d558320 100644 --- a/hw/vigs/vigs_qt5.cpp +++ b/hw/vigs/vigs_qt5.cpp @@ -27,26 +27,27 @@ * */ -#include <stdio.h> +#include "vigs_qt5.h" +#include "config-host.h" #include <QGuiApplication> #include <QOpenGLContext> #include <qpa/qplatformnativeinterface.h> -#include "config-host.h" -#include "vigs_qt5.h" +#include <stdio.h> extern bool qt5IsOnscreen; extern QApplication *qt5App; extern QOpenGLContext *qt5GLContext; +extern QSurfaceFormat qt5GLFormat; extern void qt5_register_capture_request_listener(void *listener, void (*handler)(void *)); extern void qt5_unregister_capture_request_listener(void *listener); extern void qt5_process_captured(bool captured, void *pixels, int width, int height); -extern void qt5_update_texture(unsigned int tex_id); bool vigs_qt5_onscreen_enabled(void) { + // TODO: on Darwin? if (qt5App != NULL && qt5IsOnscreen) { return true; } @@ -66,7 +67,7 @@ void *vigs_qt5_display(void) QGuiApplication::primaryScreen()); } -void *vigs_qt5_gl_context_get(void) +void *vigs_qt5_gl_context_create(bool is_gl2) { if (!qt5App) { fprintf(stderr, "QT5 not enabled!\n"); @@ -74,27 +75,79 @@ void *vigs_qt5_gl_context_get(void) } if (qt5GLContext) { - QPlatformNativeInterface *native = - QGuiApplication::platformNativeInterface(); + 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); +#ifdef CONFIG_DARWIN + format.setMinorVersion(2); + format.setProfile(QSurfaceFormat::CoreProfile); +#else + format.setMinorVersion(1); +#endif + } + + 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; + void *ret = NULL; #if defined(CONFIG_LINUX) - ret = native->nativeResourceForContext(QByteArray("glxcontext"), - qt5GLContext); + ret = native->nativeResourceForContext(QByteArray("glxcontext"), qt5GLContext); #elif defined(CONFIG_WIN32) - ret = native->nativeResourceForContext(QByteArray("renderingContext"), - qt5GLContext); + ret = native->nativeResourceForContext(QByteArray("renderingContext"), qt5GLContext); #elif defined(CONFIG_DARWIN) - ret = native->nativeResourceForContext(QByteArray("cglContextObj"), - qt5GLContext); + ret = native->nativeResourceForContext(QByteArray("cglContextObj"), qt5GLContext); #endif - if (!ret) { - fprintf(stderr, "Cannot get native QT5 GL context!\n"); - } - return ret; + + if (!ret) { + fprintf(stderr, "Cannot get native QT5 GL context!\n"); + + delete qt5GLContext; + qt5GLContext = NULL; } - return NULL; + + qt5GLFormat = format; + + return ret; } void vigs_qt5_register_capture_request_listener(void *listener, @@ -113,8 +166,3 @@ void vigs_qt5_process_captured(bool captured, void *pixels, { qt5_process_captured(captured, pixels, width, height); } - -void vigs_qt5_dpy_render_texture(uint32_t tex_id) -{ - qt5_update_texture(tex_id); -} diff --git a/hw/vigs/vigs_qt5.h b/hw/vigs/vigs_qt5.h index a27ae6184b..b88c84ebf8 100644 --- a/hw/vigs/vigs_qt5.h +++ b/hw/vigs/vigs_qt5.h @@ -38,14 +38,14 @@ bool vigs_qt5_onscreen_enabled(void); void *vigs_qt5_display(void); -void *vigs_qt5_gl_context_get(void); +void *vigs_qt5_gl_context_create(bool is_gl2); void vigs_qt5_register_capture_request_listener(void *listener, void (*handler)(void *)); void vigs_qt5_unregister_capture_request_listener(void *listener); void vigs_qt5_process_captured(bool captured, void *pixels, int width, int height); -void vigs_qt5_dpy_render_texture(uint32_t tex_id); + #ifdef __cplusplus }; #endif diff --git a/hw/vigs/vigs_qt5_stub.c b/hw/vigs/vigs_qt5_stub.c index cf490f323c..9b3c80729b 100644 --- a/hw/vigs/vigs_qt5_stub.c +++ b/hw/vigs/vigs_qt5_stub.c @@ -34,6 +34,17 @@ #include "emulator_common.h" #include "vigs_qt5.h" +uint32_t qt5_window_width = 0; +uint32_t qt5_window_height = 0; +int qt5_window_angle = 0; + +/* mutlitouch data */ +float *qt5_mt_points = NULL; +int qt5_mt_count = 0; +const void *qt5_mt_pixels = NULL; +int qt5_mt_width = 0; +int qt5_mt_height = 0; + bool vigs_qt5_onscreen_enabled(void) { return false; @@ -44,7 +55,7 @@ void *vigs_qt5_display(void) return NULL; } -void *vigs_qt5_gl_context_get(void) +void *vigs_qt5_gl_context_create(bool is_gl2) { return NULL; } @@ -65,9 +76,3 @@ void vigs_qt5_process_captured(bool captured, void *pixels, { return; } - -void vigs_qt5_dpy_render_texture(uint32_t tex_id) -{ - return; -} - diff --git a/tizen/src/ui/Makefile.objs b/tizen/src/ui/Makefile.objs index 76ddc8469c..b18942f2a1 100644 --- a/tizen/src/ui/Makefile.objs +++ b/tizen/src/ui/Makefile.objs @@ -11,6 +11,7 @@ $(obj)/qrc_resource.cpp: $(TIZEN_UI)/resource/resource.qrc obj-$(CONFIG_QT) += displaybase.o obj-$(CONFIG_QT) += displayglwidget.o moc_displayglwidget.o obj-$(CONFIG_QT) += displayswwidget.o moc_displayswwidget.o +obj-$(CONFIG_QT) += displayswapper.o moc_displayswapper.o obj-$(CONFIG_QT) += movingwidget.o obj-$(CONFIG_QT) += mainwindow.o moc_mainwindow.o obj-$(CONFIG_QT) += skinbezelitem.o @@ -33,6 +34,8 @@ $(obj)/moc_displayglwidget.cpp: $(obj)/displayglwidget.h moc $< -o $@ $(obj)/moc_displayswwidget.cpp: $(obj)/displayswwidget.h moc $< -o $@ +$(obj)/moc_displayswapper.cpp: $(obj)/displayswapper.h + moc $< -o $@ $(obj)/moc_mainwindow.cpp: $(obj)/mainwindow.h moc $< -o $@ $(obj)/moc_skinkeyitem.cpp: $(obj)/skinkeyitem.h diff --git a/tizen/src/ui/controller/dockingcontroller.cpp b/tizen/src/ui/controller/dockingcontroller.cpp index 51d4daf0f5..ec6030a5e6 100644 --- a/tizen/src/ui/controller/dockingcontroller.cpp +++ b/tizen/src/ui/controller/dockingcontroller.cpp @@ -38,10 +38,10 @@ DockingController::DockingController(ControllerForm *conForm, this->menu = menu; this->dockPos = dockPos; - setStyleSheet("background: transparent; border-style: none"); + setStyleSheet("border-style: none"); QGraphicsScene *conScene = new QGraphicsScene(this); - conScene->setBackgroundBrush(Qt::transparent); + conScene->setBackgroundBrush(Qt::black); conView = new DockingConView(this, conForm, conScene); conView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); diff --git a/tizen/src/ui/controller/floatingcontroller.cpp b/tizen/src/ui/controller/floatingcontroller.cpp index 1f807d85eb..0d6eab0bd5 100644 --- a/tizen/src/ui/controller/floatingcontroller.cpp +++ b/tizen/src/ui/controller/floatingcontroller.cpp @@ -36,12 +36,12 @@ FloatingController::FloatingController(ControllerForm *conForm, this->conForm = conForm; this->menu = menu; - setStyleSheet("background: transparent; border-style: none"); + setStyleSheet("border-style: none"); setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); setWindowTitle(conForm->getName()); QGraphicsScene *conScene = new QGraphicsScene(this); - conScene->setBackgroundBrush(Qt::transparent); + conScene->setBackgroundBrush(Qt::black); conView = new FloatingConView(this, conForm, conScene); conView->resize(conForm->skinImg[LayoutForm::normal].size()); diff --git a/tizen/src/ui/displaybase.cpp b/tizen/src/ui/displaybase.cpp index 04601fa952..80b8b9b9e1 100644 --- a/tizen/src/ui/displaybase.cpp +++ b/tizen/src/ui/displaybase.cpp @@ -41,6 +41,10 @@ void qt5_graphic_hw_invalidate(void); void req_set_sensor_accel_angle(int angle); } +uint32_t qt5_window_width = 0; +uint32_t qt5_window_height = 0; +int qt5_window_angle = 0; + DisplayBase::DisplayBase(DisplayType *displayForm, QSize resolution, qreal scaleFactor, QWidget *w) : resolution(resolution), widget(w) { @@ -123,7 +127,6 @@ void DisplayBase::showOffGuideImg() maskImage.height() * scaleFactor).mask()); } - widget->update(); offGuide->show(); } @@ -146,7 +149,7 @@ void DisplayBase::switchForm(DisplayType *displayForm) { qDebug() << "display switch angle:" << displayForm->getAngle(); - rotateAngle = displayForm->getAngle(); + qt5_window_angle = rotateAngle = displayForm->getAngle(); rect = displayForm->getRect(); maskImage = displayForm->getMask(); @@ -154,8 +157,8 @@ void DisplayBase::switchForm(DisplayType *displayForm) req_set_sensor_accel_angle(rotateAngle); /* update sensor */ updateGeometry(); - invalidateDisplay(); - widget->update(); + update(); + widget->repaint(); } void DisplayBase::scaleForm(qreal scaleFactor) @@ -166,11 +169,11 @@ void DisplayBase::scaleForm(qreal scaleFactor) updateGeometry(); - invalidateDisplay(); - widget->update(); + update(); + widget->repaint(); } -void DisplayBase::invalidateDisplay() +void DisplayBase::update() { qt5_graphic_hw_invalidate(); } @@ -198,14 +201,17 @@ QRegion DisplayBase::getMask() return widget->mask(); } -void DisplayBase::handlePaint() +void DisplayBase::handlePaint(QPaintEvent *event) { /* do nothing */ } -void DisplayBase::handleResize() +void DisplayBase::handleResize(QResizeEvent *event) { - qDebug() << "resize display:" << widget->size(); + qDebug() << "resize display:" << event->size(); + + qt5_window_width = widget->width(); + qt5_window_height = widget->height(); qt5_graphic_hw_invalidate(); diff --git a/tizen/src/ui/displaybase.h b/tizen/src/ui/displaybase.h index ffed69593d..73d96c6274 100644 --- a/tizen/src/ui/displaybase.h +++ b/tizen/src/ui/displaybase.h @@ -50,7 +50,7 @@ public: SdbHelper *sdbHelper; void switchForm(DisplayType *displayForm); void scaleForm(qreal scaleFactor); - void invalidateDisplay(); + void update(); void updateGeometry(); QWidget *getWidget(); const QRect &getGeometry(); @@ -74,8 +74,8 @@ protected: DisplayBase(DisplayType *displayForm, QSize resolution, qreal scaleFactor, QWidget *w); virtual ~DisplayBase(); - void handlePaint(); - void handleResize(); + void handlePaint(QPaintEvent *event); + void handleResize(QResizeEvent *event); void handleMousePress(QMouseEvent *event); void handleMouseRelease(QMouseEvent *event); diff --git a/tizen/src/ui/displayglwidget.cpp b/tizen/src/ui/displayglwidget.cpp index 6ccb3eb2a0..f4dcb67ed0 100644 --- a/tizen/src/ui/displayglwidget.cpp +++ b/tizen/src/ui/displayglwidget.cpp @@ -4,9 +4,9 @@ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: - * Jinhyung Jo <jinhyung.jo@samsung.com> * GiWoong Kim <giwoong.kim@samsung.com> * SeokYeon Hwang <syeon.hwang@samsung.com> + * Sangho Park <sangho.p@samsung.com> * Stanislav Vorobiov * * This program is free software; you can redistribute it and/or @@ -29,456 +29,61 @@ * */ -#include <QtOpenGL> -#include <QOpenGLShaderProgram> #include "displayglwidget.h" -#include "input/multitouchtracker.h" extern "C" { -extern uint32_t brightness_level; -extern bool display_off; -extern uint8_t brightness_tbl[]; +#include "emul_state.h" }; -// number of coordinates that two triangles to make a rectangle -#define COORD_COUNT (6) -// coordinate is the point of two float -#define COORDS_SIZE (2 * 4 * COORD_COUNT) -// vertex coords + texture coords -#define FULL_COORDS_SIZE (2 * COORDS_SIZE) - -// cast an uint to void pointer -#define TO_VOIDP(x) ((const void *)((uintptr_t)(x))) - -static const char *vs_tex_source_gl2 = - "#version 120\n\n" - "attribute vec4 vertCoord;\n" - "uniform mat4 proj;\n" - "attribute vec2 texCoord;\n" - "varying vec2 v_texCoord;\n" - "void main()\n" - "{\n" - " v_texCoord = texCoord;\n" - " gl_Position = proj * vertCoord;\n" - "}\n"; - -static const char *vs_tex_source_gl3 = - "#version 140\n\n" - "in vec4 vertCoord;\n" - "uniform mat4 proj;\n" - "in vec2 texCoord;\n" - "out vec2 v_texCoord;\n" - "void main()\n" - "{\n" - " v_texCoord = texCoord;\n" - " gl_Position = proj * vertCoord;\n" - "}\n"; - -static const char *fs_dpy_source_gl2 = - "#version 120\n\n" - "uniform sampler2D tex;\n" - "uniform float brightness;\n" - "varying vec2 v_texCoord;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(tex, v_texCoord) * brightness;\n" - "}\n"; - -static const char *fs_dpy_source_gl3 = - "#version 140\n\n" - "uniform sampler2D tex;\n" - "uniform float brightness;\n" - "in vec2 v_texCoord;\n" - "out vec4 FragColor;\n" - "void main()\n" - "{\n" - " FragColor = texture(tex, v_texCoord) * brightness;\n" - "}\n"; - - -static const char *fs_scale_source_gl2 = -"#version 120\n\ -\n\ -uniform sampler2D tex;\n\ -uniform float brightness;\n\ -uniform vec2 texSize;\n\ -varying vec2 v_texCoord;\n\ -vec4 cubic(float x)\n\ -{\n\ - float x2 = x * x;\n\ - float x3 = x2 * x;\n\ - vec4 w;\n\ - w.x = -x3 + 3*x2 - 3*x + 1;\n\ - w.y = 3*x3 - 6*x2 + 4;\n\ - w.z = -3*x3 + 3*x2 + 3*x + 1;\n\ - w.w = x3;\n\ - return w / 6.f;\n\ -}\n\ -void main()\n\ -{\n\ - vec2 texscale = vec2(1.0 / texSize.x, 1.0 / texSize.y);\n\ - vec2 texcoord = vec2(v_texCoord.x * texSize.x, v_texCoord.y * texSize.y);\n\ - float fx = fract(texcoord.x);\n\ - float fy = fract(texcoord.y);\n\ - texcoord.x -= fx;\n\ - texcoord.y -= fy;\n\ -\n\ - vec4 xcubic = cubic(fx);\n\ - vec4 ycubic = cubic(fy);\n\ -\n\ - vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y -\n\ -0.5, texcoord.y + 1.5);\n\ - vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x +\n\ -ycubic.y, ycubic.z + ycubic.w);\n\ - vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) / s;\n\ -\n\ - vec4 sample0 = texture2D(tex, vec2(offset.x, offset.z) *\n\ -texscale);\n\ - vec4 sample1 = texture2D(tex, vec2(offset.y, offset.z) *\n\ -texscale);\n\ - vec4 sample2 = texture2D(tex, vec2(offset.x, offset.w) *\n\ -texscale);\n\ - vec4 sample3 = texture2D(tex, vec2(offset.y, offset.w) *\n\ -texscale);\n\ -\n\ - float sx = s.x / (s.x + s.y);\n\ - float sy = s.z / (s.z + s.w);\n\ -\n\ - gl_FragColor = mix(\n\ - mix(sample3, sample2, sx),\n\ - mix(sample1, sample0, sx), sy) * brightness;\n\ -}"; - -static const char *fs_scale_source_gl3 = -"#version 140\n\ -\n\ -uniform sampler2D tex;\n\ -uniform float brightness;\n\ -uniform vec2 texSize;\n\ -in vec2 v_texCoord;\n\ -out vec4 FragColor;\n\ -vec4 cubic(float x)\n\ -{\n\ - float x2 = x * x;\n\ - float x3 = x2 * x;\n\ - vec4 w;\n\ - w.x = -x3 + 3*x2 - 3*x + 1;\n\ - w.y = 3*x3 - 6*x2 + 4;\n\ - w.z = -3*x3 + 3*x2 + 3*x + 1;\n\ - w.w = x3;\n\ - return w / 6.f;\n\ -}\n\ -void main()\n\ -{\n\ - vec2 texscale = vec2(1.0 / texSize.x, 1.0 / texSize.y);\n\ - vec2 texcoord = vec2(v_texCoord.x * texSize.x, v_texCoord.y * texSize.y);\n\ - float fx = fract(texcoord.x);\n\ - float fy = fract(texcoord.y);\n\ - texcoord.x -= fx;\n\ - texcoord.y -= fy;\n\ -\n\ - vec4 xcubic = cubic(fx);\n\ - vec4 ycubic = cubic(fy);\n\ -\n\ - vec4 c = vec4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y -\n\ -0.5, texcoord.y + 1.5);\n\ - vec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x +\n\ -ycubic.y, ycubic.z + ycubic.w);\n\ - vec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) /\n\ -s;\n\ -\n\ - vec4 sample0 = texture(tex, vec2(offset.x, offset.z) *\n\ -texscale);\n\ - vec4 sample1 = texture(tex, vec2(offset.y, offset.z) *\n\ -texscale);\n\ - vec4 sample2 = texture(tex, vec2(offset.x, offset.w) *\n\ -texscale);\n\ - vec4 sample3 = texture(tex, vec2(offset.y, offset.w) *\n\ -texscale);\n\ -\n\ - float sx = s.x / (s.x + s.y);\n\ - float sy = s.z / (s.z + s.w);\n\ -\n\ - FragColor = mix(\n\ - mix(sample3, sample2, sx),\n\ - mix(sample1, sample0, sx), sy) * brightness;\n\ -}"; - -DisplayGLWidget::DisplayGLWidget(QWidget *parent, +DisplayGLWidget::DisplayGLWidget(QWidget *parent, QGLContext *context, DisplayType *displayForm, QSize resolution, qreal scaleFactor) : - QOpenGLWidget(parent), DisplayBase(displayForm, resolution, scaleFactor, this), - mGuestResolution(resolution) + QGLWidget(context, parent), DisplayBase(displayForm, resolution, scaleFactor, this) { - this->maskQImage = displayForm->getMask().toImage(); - this->maskTexture = 0; - this->needScale = false; - this->dpyTexture = 0; - this->mtTexture = 0; - this->texProgram = NULL; - this->scaleProgram = NULL; - + setAutoBufferSwap(false); /* to be enable to drop events */ setAcceptDrops(true); } -void DisplayGLWidget::changedTexture(unsigned int id) -{ - if (dpyTexture != id) { - dpyTexture = id; - } - this->update(); -} - -float DisplayGLWidget::getBrightness() -{ - if (display_off) { - return 0.0f; - } - return ((float)(255 - brightness_tbl[brightness_level]) / 255.0f); -} - -// TODO: if possible, simply clean up rendeing & init code -void DisplayGLWidget::drawQuad(GLuint textureID, bool isMask) -{ - QOpenGLShaderProgram *program = needScale ? scaleProgram : texProgram; - - mFuncs->glBindTexture(GL_TEXTURE_2D, textureID); - - program->bind(); - program->enableAttributeArray("vertCoord"); - program->enableAttributeArray("texCoord"); - int vertCoordLoc = program->attributeLocation("vertCoord"); - int texCoordLoc = program->attributeLocation("texCoord"); - program->setUniformValue("proj", mOrtho); - if (needScale) { - GLfloat texSize[2]; - texSize[0] = (GLfloat)mGuestResolution.width(); - texSize[1] = (GLfloat)mGuestResolution.height(); - program->setUniformValueArray("texSize", texSize, 1, 2); - } - program->setUniformValue("brightness", isMask ? 1.0f : getBrightness()); - - mVBO->bind(); - mVBO->write(0, mVertCoords, COORDS_SIZE); - mVBO->write(COORDS_SIZE, mTexCoords, COORDS_SIZE); - mFuncs->glVertexAttribPointer(vertCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); - mFuncs->glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, - TO_VOIDP(COORDS_SIZE)); - mVBO->release(); - - mFuncs->glDrawArrays(GL_TRIANGLES, 0, COORD_COUNT); - - program->disableAttributeArray("texCoord"); - program->disableAttributeArray("vertCoord"); - - program->release(); -} - -void DisplayGLWidget::drawMultiTouchPoints() -{ - MultiTouchTracker *mtTracker = getTouchScreenHelper()->getMtTracker(); - QList<TouchPoint *> pointList = mtTracker->getTouchPointList(); - - if (pointList.isEmpty()) { - return; - } - - mVBO->bind(); - if (mVBO->size() < pointList.count() * (int)FULL_COORDS_SIZE) { - mVBO->allocate(pointList.count() * FULL_COORDS_SIZE); - } - - for (int i = 0; i < pointList.count(); i++) { - TouchPoint *p = pointList.at(i); - GLfloat vertCoords[12]; - GLfloat x = p->getHostPos().x() - 32 / 2; - GLfloat y = height() - p->getHostPos().y() - 32 / 2; - - vertCoords[6] = vertCoords[0] = x; - vertCoords[7] = vertCoords[1] = y; - vertCoords[2] = x + 32; - vertCoords[3] = y; - vertCoords[8] = vertCoords[4] = x + 32; - vertCoords[9] = vertCoords[5] = y + 32; - vertCoords[10] = x; - vertCoords[11] = y + 32; - - mVBO->write(i * COORDS_SIZE, vertCoords, COORDS_SIZE); - mVBO->write(pointList.count() * COORDS_SIZE + i * COORDS_SIZE, - mTexCoords, COORDS_SIZE); - } - - mFuncs->glBlendFunc(GL_SRC_COLOR, GL_ONE); - mFuncs->glBindTexture(GL_TEXTURE_2D, mtTexture); - - texProgram->bind(); - texProgram->enableAttributeArray("vertCoord"); - texProgram->enableAttributeArray("texCoord"); - int vertCoordLoc = texProgram->attributeLocation("vertCoord"); - int texCoordLoc = texProgram->attributeLocation("texCoord"); - - QMatrix4x4 mat; - mat.ortho(0.0f, (float)width(), - 0.0f, (float)height(), - -1.0f, 1.0f); - texProgram->setUniformValue("proj", mat); - texProgram->setUniformValue("brightness", 0.7f); - - mFuncs->glVertexAttribPointer(vertCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); - mFuncs->glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 0, - TO_VOIDP(pointList.count() * COORDS_SIZE)); - mVBO->release(); - - mFuncs->glDrawArrays(GL_TRIANGLES, 0, pointList.count() * COORD_COUNT); - - texProgram->disableAttributeArray("texCoord"); - texProgram->disableAttributeArray("vertCoord"); - - texProgram->release(); -} - - /* override */ void DisplayGLWidget::initializeGL() { qDebug("initialize GL"); - - mFuncs = QOpenGLContext::currentContext()->functions(); - - QOpenGLShader *vShader = new QOpenGLShader(QOpenGLShader::Vertex, this); - QOpenGLShader *dpyFgShader = new QOpenGLShader(QOpenGLShader::Fragment, this); - QOpenGLShader *scaleFgShader = new QOpenGLShader(QOpenGLShader::Fragment, this); - if (format().majorVersion() > 2) { - vShader->compileSourceCode(vs_tex_source_gl3); - dpyFgShader->compileSourceCode(fs_dpy_source_gl3); - scaleFgShader->compileSourceCode(fs_scale_source_gl3); - } else { - vShader->compileSourceCode(vs_tex_source_gl2); - dpyFgShader->compileSourceCode(fs_dpy_source_gl2); - scaleFgShader->compileSourceCode(fs_scale_source_gl2); - } - - texProgram = new QOpenGLShaderProgram(this); - texProgram->addShader(vShader); - texProgram->addShader(dpyFgShader); - scaleProgram = new QOpenGLShaderProgram(this); - scaleProgram->addShader(vShader); - scaleProgram->addShader(scaleFgShader); - - texProgram->link(); - scaleProgram->link(); - - mVAO = new QOpenGLVertexArrayObject; - if (mVAO->create()) { - mVAO->bind(); - } - mVBO = new QOpenGLBuffer; - mVBO->setUsagePattern(QOpenGLBuffer::StreamDraw); - mVBO->create(); - mVBO->bind(); - mVBO->allocate(FULL_COORDS_SIZE); - mVBO->release(); - - mVertCoords[6] = mVertCoords[0] = 0; - mVertCoords[7] = mVertCoords[1] = mGuestResolution.height(); - mVertCoords[2] = mGuestResolution.width(); - mVertCoords[3] = mGuestResolution.height(); - mVertCoords[8] = mVertCoords[4] = mGuestResolution.width(); - mVertCoords[9] = mVertCoords[5] = 0; - mVertCoords[10] = 0; - mVertCoords[11] = 0; - - mTexCoords[6] = mTexCoords[0] = 0; - mTexCoords[7] = mTexCoords[1] = 0; - mTexCoords[2] = 1; - mTexCoords[3] = 0; - mTexCoords[8] = mTexCoords[4] = 1; - mTexCoords[9] = mTexCoords[5] = 1; - mTexCoords[10] = 0; - mTexCoords[11] = 1; - - GLuint curTexture = 0; - mFuncs->glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&curTexture); - - const QImage img = getTouchScreenHelper()->getMtTracker()->getPointImage(); - mFuncs->glGenTextures(1, &mtTexture); - mFuncs->glBindTexture(GL_TEXTURE_2D, mtTexture); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - mFuncs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 32, 32, 0, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, - (const void *)img.constBits()); - mFuncs->glBindTexture(GL_TEXTURE_2D, curTexture); - - if (!maskQImage.isNull()) { - mFuncs->glGenTextures(1, &maskTexture); - mFuncs->glBindTexture(GL_TEXTURE_2D, maskTexture); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - mFuncs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - mFuncs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, - maskQImage.width(), maskQImage.height(), - 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, - (const void *)maskQImage.constBits()); - mFuncs->glBindTexture(GL_TEXTURE_2D, curTexture); - } } /* override */ -void DisplayGLWidget::paintGL() +void DisplayGLWidget::dragEnterEvent(QDragEnterEvent *event) { - mFuncs->glDisable(GL_DEPTH_TEST); - mFuncs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mFuncs->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - mFuncs->glEnable(GL_BLEND); - - if (maskTexture) { - mFuncs->glBlendFuncSeparate(GL_ONE, GL_ZERO, - GL_SRC_ALPHA, GL_ZERO); - drawQuad(maskTexture, true); - } - mFuncs->glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - mOrtho.setToIdentity(); - mOrtho.rotate((float)-rotateAngle, 0.0f, 0.0f, 1.0f); - mOrtho.ortho(0.0f, (float)mGuestResolution.width(), - 0.0f, (float)mGuestResolution.height(), - -1.0f, 1.0f); - needScale = (mGuestResolution.width() != width()) - || (mGuestResolution.height() != height()); - - drawQuad(dpyTexture, false); - if (isTsEnabled) { - drawMultiTouchPoints(); - } - - mFuncs->glDisable(GL_BLEND); - mFuncs->glFinish(); + handleDragEnterEvent(event); } /* override */ -void DisplayGLWidget::resizeGL(int w, int h) +void DisplayGLWidget::dropEvent(QDropEvent *event) { - qDebug("resizeGL"); - handleResize(); - - // TODO: check changing of the guest resolution - // for 'Runtime Resolution Change' + handleDropEvent(event); } /* override */ -void DisplayGLWidget::dragEnterEvent(QDragEnterEvent *event) +void DisplayGLWidget::paintEvent(QPaintEvent *event) { - handleDragEnterEvent(event); + /* + * We offload rendering to separate thread, this must be + * a no-op, see: http://qt-project.org/doc/qt-5/QGLWidget.html: + * "3. Using QPainter to draw into a QGLWidget in a thread" + */ + + handlePaint(event); } /* override */ -void DisplayGLWidget::dropEvent(QDropEvent *event) +void DisplayGLWidget::resizeEvent(QResizeEvent *event) { - handleDropEvent(event); + /* + * We offload rendering to separate thread, this must be + * a no-op, see: http://qt-project.org/doc/qt-5/QGLWidget.html: + * "3. Using QPainter to draw into a QGLWidget in a thread" + */ + + handleResize(event); } /* override */ @@ -536,23 +141,7 @@ void DisplayGLWidget::leaveEvent(QEvent *event) } } -// TODO: To correct releasing resources DisplayGLWidget::~DisplayGLWidget() { - makeCurrent(); - if (mtTexture) { - mFuncs->glDeleteTextures(1, &mtTexture); - } - if (maskTexture) { - mFuncs->glDeleteTextures(1, &maskTexture); - } - mVAO->destroy(); - mVBO->destroy(); - texProgram->removeAllShaders(); - scaleProgram->removeAllShaders(); - delete mVAO; - delete mVBO; - delete texProgram; - delete scaleProgram; - doneCurrent(); + /* do nothing */ } diff --git a/tizen/src/ui/displayglwidget.h b/tizen/src/ui/displayglwidget.h index cc327f56a6..491d6fe594 100644 --- a/tizen/src/ui/displayglwidget.h +++ b/tizen/src/ui/displayglwidget.h @@ -4,9 +4,9 @@ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: - * Jinhyung Jo <jinhyung.jo@samsung.com> * GiWoong Kim <giwoong.kim@samsung.com> * SeokYeon Hwang <syeon.hwang@samsung.com> + * Sangho Park <sangho.p@samsung.com> * Stanislav Vorobiov * * This program is free software; you can redistribute it and/or @@ -32,33 +32,25 @@ #ifndef DISPLAYGLWIDGET_H #define DISPLAYGLWIDGET_H +#include <QGLWidget> #include "displaybase.h" -#include <QOpenGLWidget> -#include <QMatrix4x4> -class QOpenGLFunctions; -class QOpenGLShaderProgram; -class QOpenGLVertexArrayObject; -class QOpenGLBuffer; - -class DisplayGLWidget : public QOpenGLWidget, +class DisplayGLWidget : public QGLWidget, public DisplayBase { Q_OBJECT public: - DisplayGLWidget(QWidget *parent, - DisplayType *displayForm, - QSize resolution, qreal scaleFactor); + DisplayGLWidget(QWidget *parent, QGLContext *context, + DisplayType *displayForm, QSize resolution, qreal scaleFactor); ~DisplayGLWidget(); - void changedTexture(unsigned int texture); - protected: void initializeGL(); - void paintGL(); - void resizeGL(int w, int h); + + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); @@ -69,29 +61,6 @@ protected: void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); - -private: - float getBrightness(); - void drawQuad(GLuint texture, bool isMask); - void drawMultiTouchPoints(); - - QSize mGuestResolution; - QOpenGLFunctions *mFuncs; - - bool needScale; - QImage maskQImage; - GLuint maskTexture; - - GLuint dpyTexture; - GLuint mtTexture; - QMatrix4x4 mOrtho; - GLfloat mVertCoords[12]; - GLfloat mTexCoords[12]; - - QOpenGLVertexArrayObject *mVAO; - QOpenGLBuffer *mVBO; - QOpenGLShaderProgram *texProgram; - QOpenGLShaderProgram *scaleProgram; }; #endif // DISPLAYGLWIDGET_H diff --git a/tizen/src/ui/displayswapper.cpp b/tizen/src/ui/displayswapper.cpp new file mode 100644 index 0000000000..95b30db5c1 --- /dev/null +++ b/tizen/src/ui/displayswapper.cpp @@ -0,0 +1,62 @@ +/* + * Qt UI + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * GiWoong Kim <giwoong.kim@samsung.com> + * Sangho Park <sangho1206.park@samsung.com> + * Stanislav Vorobiov + * + * 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 "displayswapper.h" + +extern "C" { +int qt5_graphic_hw_display(void); +} + +DisplaySwapper::DisplaySwapper(QGLContext* context, QObject* parent) : + QObject(parent), context(context), terminating(false) +{ + /* do nothing */ +} + +void DisplaySwapper::display() +{ + if (context) { + while (!terminating) { + context->makeCurrent(); + if (qt5_graphic_hw_display()) { + context->swapBuffers(); + } + context->doneCurrent(); + } + } else { + while (!terminating) { + qt5_graphic_hw_display(); + } + } + + qDebug("DisplaySwapper::display() terminated"); + + emit displayFinished(); +} diff --git a/tizen/src/ui/displayswapper.h b/tizen/src/ui/displayswapper.h new file mode 100644 index 0000000000..aa5714b0c2 --- /dev/null +++ b/tizen/src/ui/displayswapper.h @@ -0,0 +1,57 @@ +/* + * Qt UI + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * GiWoong Kim <giwoong.kim@samsung.com> + * Sangho Park <sangho1206.park@samsung.com> + * Stanislav Vorobiov + * + * 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 DISPLAYSWAPPER_H +#define DISPLAYSWAPPER_H + +#include <QWidget> +#include <QGLContext> + +class DisplaySwapper : public QObject +{ + Q_OBJECT + +public: + DisplaySwapper(QGLContext* context, QObject* parent = 0); + + inline void setTerminating() { terminating = true; } + +public slots: + void display(); + +signals: + void displayFinished(); + +private: + QGLContext *context; + bool terminating; +}; + +#endif // DISPLAYSWAPPER_H diff --git a/tizen/src/ui/displayswwidget.cpp b/tizen/src/ui/displayswwidget.cpp index 97c968ee32..ec149a5c9f 100644 --- a/tizen/src/ui/displayswwidget.cpp +++ b/tizen/src/ui/displayswwidget.cpp @@ -71,7 +71,7 @@ void DisplaySWWidget::drawMtPoints(QPainter &painter) void DisplaySWWidget::paintEvent(QPaintEvent *event) { QLabel::paintEvent(event); - handlePaint(); + handlePaint(event); if (isTsEnabled == true) { /* draw multi-touch points */ @@ -96,7 +96,7 @@ void DisplaySWWidget::dropEvent(QDropEvent *event) void DisplaySWWidget::resizeEvent(QResizeEvent *event) { QLabel::resizeEvent(event); - handleResize(); + handleResize(event); repaint(); } diff --git a/tizen/src/ui/input/multitouchtracker.cpp b/tizen/src/ui/input/multitouchtracker.cpp index 8f1bc33588..04594f58f5 100644 --- a/tizen/src/ui/input/multitouchtracker.cpp +++ b/tizen/src/ui/input/multitouchtracker.cpp @@ -34,6 +34,12 @@ #include "multitouchtracker.h" #include "displaybase.h" +float *qt5_mt_points = 0; +int qt5_mt_count = 0; +const void *qt5_mt_pixels = 0; +int qt5_mt_width = 0; +int qt5_mt_height = 0; + extern "C" { bool virtio_touchscreen_ready(void); void virtio_touchscreen_event(int x, int y, int z, int buttons_state); @@ -73,6 +79,8 @@ void TouchPoint::updatePos(QPoint hostPos, QPoint guestPos) this->hostPos = hostPos; this->guestPos = guestPos; + qt5_mt_points[2 * (this->id - 1) + 0] = hostPos.x(); + qt5_mt_points[2 * (this->id - 1) + 1] = hostPos.y(); qt5_graphic_hw_invalidate(); } @@ -101,6 +109,11 @@ MultiTouchTracker::MultiTouchTracker( painter.setBrush(QBrush(QColor(128, 128, 128, 128))); painter.setRenderHint(QPainter::Antialiasing, true); painter.drawEllipse(1, 1, 30, 30); + + qt5_mt_points = new float[2 * maxTouchPoint](); + qt5_mt_count = 0; + qt5_mt_pixels = touchPointImage.constBits(); + qt5_mt_width = qt5_mt_height = 32; } int MultiTouchTracker::getPointRadius() @@ -156,6 +169,9 @@ int MultiTouchTracker::addTouchPoint(QPoint hostPos, QPoint guestPos) touchPointList.append(point); qDebug() << "ID" << point->getID() << "point touching" << hostPos << guestPos; + qt5_mt_points[2 * qt5_mt_count + 0] = hostPos.x(); + qt5_mt_points[2 * qt5_mt_count + 1] = hostPos.y(); + qt5_mt_count++; qt5_graphic_hw_invalidate(); return touchPointList.count(); @@ -223,6 +239,8 @@ int MultiTouchTracker::limitTouchCnt(int max) delete point; } touchPointList.removeLast(); + + qt5_mt_count--; } diff = beforeCnt - touchPointList.count(); @@ -504,6 +522,7 @@ void MultiTouchTracker::finishTracking() } touchPointList.clear(); + qt5_mt_count = 0; qt5_graphic_hw_invalidate(); } @@ -512,4 +531,10 @@ MultiTouchTracker::~MultiTouchTracker() qDebug("destroy multi-touch tracker"); finishTracking(); + + delete[] qt5_mt_points; + qt5_mt_points = 0; + qt5_mt_count = 0; + qt5_mt_pixels = 0; + qt5_mt_width = qt5_mt_height = 0; } diff --git a/tizen/src/ui/mainwindow.cpp b/tizen/src/ui/mainwindow.cpp index aeab23c9ab..7737da1d66 100644 --- a/tizen/src/ui/mainwindow.cpp +++ b/tizen/src/ui/mainwindow.cpp @@ -46,7 +46,10 @@ void qt5_graphic_hw_update(void); void qemu_system_graceful_shutdown_request(unsigned int sec); } -MainWindow::MainWindow(UiInformation *uiInfo, bool useGL, QWidget *parent) : +QOpenGLContext *qt5GLContext = NULL; +QSurfaceFormat qt5GLFormat; + +MainWindow::MainWindow(UiInformation *uiInfo, QWidget *parent) : QWidget(parent) { /* initialize */ @@ -56,6 +59,8 @@ MainWindow::MainWindow(UiInformation *uiInfo, bool useGL, QWidget *parent) : this->display = NULL; this->rotary = NULL; + this->swapper = NULL; + this->swapperThread = NULL; this->screenWidget = NULL; this->captureRequestHandler = NULL; @@ -67,11 +72,10 @@ MainWindow::MainWindow(UiInformation *uiInfo, bool useGL, QWidget *parent) : setWindowIcon(QIcon(":/icons/emulator_icon.ico")); setWindowFlags(Qt::FramelessWindowHint | Qt::WindowCloseButtonHint); setMinimumSize(0, 0); - setAttribute(Qt::WA_TranslucentBackground, true); /* scene */ mainScene = new QGraphicsScene(this); - mainScene->setBackgroundBrush(Qt::transparent); + mainScene->setBackgroundBrush(Qt::black); /* view */ mainView = new MainView(mainScene, this); @@ -94,7 +98,7 @@ MainWindow::MainWindow(UiInformation *uiInfo, bool useGL, QWidget *parent) : /* display */ updateDisplayMatrix(); - createDisplay(useGL); + display = createDisplay(uiInfo->getMainFormDpyType()); /* set HW Key shortcut */ keyboardShortcut = new KeyboardShortcut(this); @@ -107,20 +111,60 @@ MainWindow::MainWindow(UiInformation *uiInfo, bool useGL, QWidget *parent) : SLOT(slotContextMenu(const QPoint&))); } -void MainWindow::createDisplay(bool useGL) +DisplayBase *MainWindow::createDisplay(DisplayType *displayForm) { qDebug("create a display"); - if (useGL) { /* on-screen rendering */ - this->display = new DisplayGLWidget(this, - uiInfo->getMainFormDpyType(), uiInfo->getResolution(), getUiState()->getScaleFactor()); + DisplayBase *displayWidget = NULL; + + if (qt5GLContext) { /* on-screen rendering */ + 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); + + displayWidget = new DisplayGLWidget(this, context, + displayForm, uiInfo->getResolution(), getUiState()->getScaleFactor()); + + context->setFormat(format); + context->create(wrapperContext); + + /* display swapper */ + swapperThread = new QThread(this); + + context->doneCurrent(); + context->moveToThread(swapperThread); + + swapper = new DisplaySwapper(context); + swapper->moveToThread(swapperThread); + + connect(swapper, SIGNAL(displayFinished()), + swapperThread, SLOT(quit()), Qt::DirectConnection); + connect(swapperThread, SIGNAL(finished()), swapper, SLOT(deleteLater())); + connect(swapperThread, SIGNAL(finished()), swapperThread, SLOT(deleteLater())); + + swapperThread->start(); } else { /* off-screen rendering */ DisplaySWWidget *widget = new DisplaySWWidget(this, - uiInfo->getMainFormDpyType(), uiInfo->getResolution(), getUiState()->getScaleFactor()); + displayForm, uiInfo->getResolution(), getUiState()->getScaleFactor()); - this->screenWidget = widget; - this->display = widget; + screenWidget = widget; + displayWidget = widget; } + + return displayWidget; } RotaryView *MainWindow::createRotary() @@ -129,6 +173,21 @@ RotaryView *MainWindow::createRotary() return new RotaryView(this); } +void MainWindow::startDisplaySwapper() +{ + if (swapper != NULL) { + QMetaObject::invokeMethod(swapper, "display", Qt::QueuedConnection); + } +} + +void MainWindow::terminateDisplaySwapper() +{ + if (swapper != NULL) { + swapper->setTerminating(); + qt5_graphic_hw_update(); + } +} + QLabel *MainWindow::getScreenWidget() { return screenWidget; @@ -267,7 +326,7 @@ void MainWindow::openController(int index, int dockPos) /* Some part of QGLWidget's surface might be lost on Windows when view changing. * So, we need an additional updating for display. */ - display->invalidateDisplay(); + display->update(); #ifdef CONFIG_LINUX popupMenu->slotOnTop(getUiState()->isOnTop()); @@ -304,7 +363,7 @@ void MainWindow::closeController() /* Some part of QGLWidget's surface might be lost on Windows when view changing. * So, we need an additional updating for display. */ - display->invalidateDisplay(); + display->update(); } /* override */ @@ -459,7 +518,6 @@ void MainWindow::processCaptured(bool captured, void *pixels, if (captured) { qDebug("save captured image: %p", pixels); - // pixels's format is ARGB32 QImage image = QImage((uchar *)pixels, width, height, QImage::Format_ARGB32); @@ -529,11 +587,6 @@ bool MainWindow::isMovingMode() return (movingWidget != NULL); } -void MainWindow::updateTexture(unsigned int texture) -{ - ((DisplayGLWidget *)getDisplay())->changedTexture(texture); -} - /* override */ void MainWindow::closeEvent(QCloseEvent *event) { diff --git a/tizen/src/ui/mainwindow.h b/tizen/src/ui/mainwindow.h index 5e10476cc4..183aeb337c 100644 --- a/tizen/src/ui/mainwindow.h +++ b/tizen/src/ui/mainwindow.h @@ -35,10 +35,12 @@ #define MAINWINDOW_H #include <QWidget> +#include <QGLContext> #include "menu/contextmenu.h" #include "mainview.h" #include "displaybase.h" +#include "displayswapper.h" #include "rotaryview.h" #include "uiinformation.h" #include "controller/dockingcontroller.h" @@ -51,9 +53,7 @@ class MainWindow : public QWidget Q_OBJECT public: - explicit MainWindow(UiInformation *uiInfo, - bool useGL, - QWidget *parent = 0); + explicit MainWindow(UiInformation *uiInfo, QWidget *parent = 0); ~MainWindow(); UiInformation *getUiInfo(void); @@ -79,13 +79,13 @@ public: FloatingController *getFloatingCon(); void openController(int index, int dockPos); void closeController(); + void startDisplaySwapper(); + void terminateDisplaySwapper(); void turnOnMovingMode(); void turnOffMovingMode(); bool isMovingMode(); - void updateTexture(unsigned int texture); - public slots: void slotContextMenu(const QPoint &pos); @@ -99,7 +99,7 @@ protected: QLabel *screenWidget; private: - void createDisplay(bool useGL); + DisplayBase *createDisplay(DisplayType *displayForm); RotaryView *createRotary(); UiInformation *uiInfo; @@ -112,6 +112,8 @@ private: RotaryView *rotary; ContextMenu *popupMenu; + QThread *swapperThread; + DisplaySwapper *swapper; KeyboardShortcut *keyboardShortcut; MovingWidget *movingWidget; diff --git a/tizen/src/ui/qt5_supplement.cpp b/tizen/src/ui/qt5_supplement.cpp index 7bf99152f6..33c68a49f9 100644 --- a/tizen/src/ui/qt5_supplement.cpp +++ b/tizen/src/ui/qt5_supplement.cpp @@ -29,7 +29,6 @@ */ #include <QApplication> -#include <QOpenGLContext> #include "qt5_supplement.h" #include "propertykeyword.h" @@ -55,7 +54,6 @@ bool is_display_off(void); //using namespace std; bool qt5IsOnscreen; QApplication *qt5App = NULL; -QOpenGLContext *qt5GLContext; bool isForceLegacy; static int argc = 0; @@ -333,7 +331,7 @@ static void qt5_gui_init(void) /* GUI */ qDebug("start!"); - mainwindow = new MainWindow(uiInfo, qt5IsOnscreen); + mainwindow = new MainWindow(uiInfo); mainwindow->setCaptureRequestHandler(captureRequestListener, captureRequestHandler); /* position */ @@ -392,12 +390,16 @@ static void qt5_gui_init(void) mainwindow->getMainView()->resize(viewSize / 2); mainwindow->getMainView()->resize(viewSize); #endif + + mainwindow->startDisplaySwapper(); } void qt5_destroy() { qDebug("qt5 destroy"); + mainwindow->terminateDisplaySwapper(); + /* write most recently used data information */ QString mruPath( uiInfo->getVmDataPath() + QDir::separator() + GUI_PROPERTIES_FILE); @@ -463,30 +465,6 @@ void qt5_early_prepare(bool isOnscreen) * QApplication is constructed. */ QCoreApplication::setAttribute(Qt::AA_X11InitThreads); #endif - if (qt5IsOnscreen) { - QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); - QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); - - QSurfaceFormat sfcFormat; - sfcFormat.setRedBufferSize(8); - sfcFormat.setGreenBufferSize(8); - sfcFormat.setBlueBufferSize(8); - sfcFormat.setAlphaBufferSize(8); - sfcFormat.setDepthBufferSize(24); - sfcFormat.setStencilBufferSize(8); -#ifdef CONFIG_DARWIN - // The default OpenGL version for QSurfaceFormat is 2.0. - if (!isForceLegacy) { - sfcFormat.setMajorVersion(3); - sfcFormat.setMinorVersion(2); - sfcFormat.setProfile(QSurfaceFormat::CoreProfile); - } -#else - sfcFormat.setMajorVersion(3); - sfcFormat.setMinorVersion(1); -#endif - QSurfaceFormat::setDefaultFormat(sfcFormat); - } qt5App = new QApplication(argc, argv); @@ -502,9 +480,6 @@ void qt5_early_prepare(bool isOnscreen) eventFilter = new EventFilter(); qt5App->installNativeEventFilter(eventFilter); #endif - if (qt5IsOnscreen) { - qt5GLContext = QOpenGLContext::globalShareContext(); - } } void qt5_prepare(void) @@ -581,10 +556,3 @@ void qt5_process_captured(bool captured, void *pixels, int width, int height) mainwindow->processCaptured(captured, pixels, width, height); } } - -void qt5_update_texture(unsigned int tex_id) -{ - if (mainwindow) { - mainwindow->updateTexture(tex_id); - } -} diff --git a/tizen/src/ui/skinview.cpp b/tizen/src/ui/skinview.cpp index fd4ee5602b..83b33889a3 100644 --- a/tizen/src/ui/skinview.cpp +++ b/tizen/src/ui/skinview.cpp @@ -38,7 +38,7 @@ SkinView::SkinView(QWidget *parent, QGraphicsScene *scene) : this->grabPos = SKINVIEW_NULLITY_POSITION; /* note: do not call setStyleSheet() separately for each style */ - setStyleSheet("QGraphicsView { background: transparent; border-style: none; }" + + setStyleSheet("QGraphicsView { border-style: none; }" + QString(STYLE_TOOLTIP)); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -2295,7 +2295,7 @@ static DisplayType select_display(const char *p) nextopt = endptr; } else if (strstart(opts, ",forcelegacy", &nextopt)) { opts = nextopt; - maru_qt5_set_force_legacy(true); + //maru_qt5_set_force_legacy(true); } else { invalid_maru_qt_args: error_report(FAILED_TO_DISPLAY_PARSING); |