/* * 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_gl_backend.h" #include "vigs_gl_pool.h" #include "vigs_surface.h" #include "vigs_plane.h" #include "vigs_log.h" #include "vigs_utils.h" #include "vigs_ref.h" #include "vigs_qt5.h" #include "winsys_gl.h" #include #ifdef __linux__ #include "drm/drm_fourcc.h" #else #define MAKE_FOURCC(a, b, c, d) (((unsigned int)(a)) | \ (((unsigned int)(b)) << 8) | \ (((unsigned int)(c)) << 16) | \ (((unsigned int)(d)) << 24)) #define DRM_FORMAT_ARGB8888 MAKE_FOURCC('A', 'R', '2', '4') #define DRM_FORMAT_YUV420 MAKE_FOURCC('Y', 'U', '1', '2') #define DRM_FORMAT_XBGR8888 MAKE_FOURCC('X', 'B', '2', '4') #endif struct vigs_gl_surface; struct vigs_winsys_gl_surface { struct winsys_gl_surface base; struct vigs_ref ref; struct vigs_gl_backend *backend; /* * Will be set to NULL when orphaned. */ struct vigs_gl_surface *parent; /* * GL texture format. * @{ */ GLint tex_internalformat; GLenum tex_format; GLenum tex_type; /* * @} */ /* * Texture that represent this surface. * Used as color attachment in 'fb'. * * Allocated on first access. */ GLuint tex; }; struct vigs_gl_surface { struct vigs_surface base; /* * Framebuffer that is used for rendering * into front buffer. * * Allocated on first access. */ GLuint fb; /* * Texture for temporary storage. * * Allocated on first access. */ GLuint tmp_tex; /* * Ortho matrix for this surface. */ GLfloat ortho[16]; /* * Input textures for * YUV conversion shader */ GLuint yuv_textures[3]; }; static __inline struct vigs_winsys_gl_surface *get_ws_sfc(struct vigs_gl_surface *sfc) { return (struct vigs_winsys_gl_surface*)sfc->base.ws_sfc; } /* * PRIVATE. * @{ */ static const char *g_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 *g_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 *g_fs_tex_source_gl2 = "#version 120\n\n" "uniform sampler2D tex;\n" "varying vec2 v_texCoord;\n" "void main()\n" "{\n" " gl_FragColor = texture2D(tex, v_texCoord);\n" "}\n"; static const char *g_fs_tex_source_gl3 = "#version 140\n\n" "uniform sampler2D tex;\n" "in vec2 v_texCoord;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = texture(tex, v_texCoord);\n" "}\n"; static const char *g_vs_color_source_gl2 = "#version 120\n\n" "attribute vec4 vertCoord;\n" "uniform mat4 proj;\n" "void main()\n" "{\n" " gl_Position = proj * vertCoord;\n" "}\n"; static const char *g_vs_color_source_gl3 = "#version 140\n\n" "in vec4 vertCoord;\n" "uniform mat4 proj;\n" "void main()\n" "{\n" " gl_Position = proj * vertCoord;\n" "}\n"; static const char *g_fs_color_source_gl2 = "#version 120\n\n" "uniform vec4 color;\n" "void main()\n" "{\n" " gl_FragColor = color;\n" "}\n"; static const char *g_fs_color_source_gl3 = "#version 140\n\n" "uniform vec4 color;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = color;\n" "}\n"; static const char *g_vs_nv21_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 *g_vs_nv21_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 *g_fs_nv21_source_gl2 = "#version 120\n\n" "uniform sampler2D ytex;\n" "uniform sampler2D ctex;\n" "uniform vec2 size;\n" "uniform vec2 ytexSize;\n" "uniform vec2 ctexSize;\n" "varying vec2 v_texCoord;\n" "void main()\n" "{\n" " float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n" " float ytexPos = floor(ypos / 4);\n" " vec4 ytexColor = texture2D(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n" " float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n" " float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n" " float ctexPos = floor(cpos / 4);\n" " vec4 ctexColor = texture2D(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n" " int index = 2 * int(mod(floor(cpos / 2) + 1, 2));" " float u = ctexColor[index];\n" " float v = ctexColor[3 - index];\n" " u -= 0.5;" " v -= 0.5;" " gl_FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n" "}\n"; static const char *g_fs_nv21_source_gl3 = "#version 140\n\n" "uniform sampler2D ytex;\n" "uniform sampler2D ctex;\n" "uniform vec2 size;\n" "uniform vec2 ytexSize;\n" "uniform vec2 ctexSize;\n" "in vec2 v_texCoord;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n" " float ytexPos = floor(ypos / 4);\n" " vec4 ytexColor = texture(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n" " float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n" " float cpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n" " float ctexPos = floor(cpos / 4);\n" " vec4 ctexColor = texture(ctex, vec2((mod(ctexPos, ctexSize.x) + 0.5) / ctexSize.x, 1.0 - (floor(ctexPos / ctexSize.x) + 0.5) / ctexSize.y));\n" " int index = 2 * int(mod(floor(cpos / 2) + 1, 2));" " float u = ctexColor[index];\n" " float v = ctexColor[3 - index];\n" " u -= 0.5;" " v -= 0.5;" " FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n" "}\n"; static const char *g_vs_yuv420_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 *g_vs_yuv420_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 *g_fs_yuv420_source_gl2 = "#version 120\n\n" "uniform sampler2D ytex;\n" "uniform sampler2D utex;\n" "uniform sampler2D vtex;\n" "uniform vec2 size;\n" "uniform vec2 ytexSize;\n" "uniform vec2 utexSize;\n" "uniform vec2 vtexSize;\n" "varying vec2 v_texCoord;\n" "void main()\n" "{\n" " float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n" " float ytexPos = floor(ypos / 4);\n" " vec4 ytexColor = texture2D(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n" " float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n" " float uvpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n" " float uvtexPos = floor(uvpos / 8);\n" " vec4 utexColor = texture2D(utex, vec2((mod(uvtexPos, utexSize.x) + 0.5) / utexSize.x, 1.0 - (floor(uvtexPos / utexSize.x) + 0.5) / utexSize.y));\n" " vec4 vtexColor = texture2D(vtex, vec2((mod(uvtexPos, vtexSize.x) + 0.5) / vtexSize.x, 1.0 - (floor(uvtexPos / vtexSize.x) + 0.5) / vtexSize.y));\n" " int index = 3 - int(mod((uvpos / 2) + 1, 4));\n" " float u = utexColor[index];\n" " float v = vtexColor[index];\n" " u -= 0.5;\n" " v -= 0.5;\n" " gl_FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n" "}\n"; static const char *g_fs_yuv420_source_gl3 = "#version 140\n\n" "uniform sampler2D ytex;\n" "uniform sampler2D utex;\n" "uniform sampler2D vtex;\n" "uniform vec2 size;\n" "uniform vec2 ytexSize;\n" "uniform vec2 utexSize;\n" "uniform vec2 vtexSize;\n" "in vec2 v_texCoord;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " float ypos = floor((1.0 - v_texCoord.y) * size.y) * size.x + floor(v_texCoord.x * size.x);\n" " float ytexPos = floor(ypos / 4);\n" " vec4 ytexColor = texture(ytex, vec2((mod(ytexPos, ytexSize.x) + 0.5) / ytexSize.x, 1.0 - (floor(ytexPos / ytexSize.x) + 0.5) / ytexSize.y));\n" " float y = ytexColor[3 - int(mod(ypos + 1, 4))];\n" " float uvpos = floor(floor((1.0 - v_texCoord.y) * size.y) / 2) * size.x + floor(v_texCoord.x * size.x);\n" " float uvtexPos = floor(uvpos / 8);\n" " vec4 utexColor = texture(utex, vec2((mod(uvtexPos, utexSize.x) + 0.5) / utexSize.x, 1.0 - (floor(uvtexPos / utexSize.x) + 0.5) / utexSize.y));\n" " vec4 vtexColor = texture(vtex, vec2((mod(uvtexPos, vtexSize.x) + 0.5) / vtexSize.x, 1.0 - (floor(uvtexPos / vtexSize.x) + 0.5) / vtexSize.y));\n" " int index = 3 - int(mod((uvpos / 2) + 1, 4));\n" " float u = utexColor[index];\n" " float v = vtexColor[index];\n" " u -= 0.5;\n" " v -= 0.5;\n" " FragColor = vec4(y + 1.59765625 * v, y - 0.390625 * u - 0.8125 * v, y + 2.015625 * u, 1.0);\n" "}\n"; static const char *g_fs_xbgr_source_gl2 = "#version 120\n\n" "uniform sampler2D tex;\n" "varying vec2 v_texCoord;\n" "void main()\n" "{\n" " gl_FragColor = vec4(texture2D(tex, v_texCoord).bgr, 1.0);\n" "}\n"; static const char *g_fs_xbgr_source_gl3 = "#version 140\n\n" "uniform sampler2D tex;\n" "in vec2 v_texCoord;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(texture(tex, v_texCoord).bgr, 1.0);\n" "}\n"; static GLuint vigs_gl_backend_alloc_tmp_texture(void *user_data, uint32_t width, uint32_t height, vigsp_surface_format format) { struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data; GLint tex_internalformat; GLenum tex_format; GLenum tex_type; GLuint tex = 0, cur_tex = 0; backend->GenTextures(1, &tex); if (!tex) { return 0; } switch (format) { case vigsp_surface_bgrx8888: case vigsp_surface_bgra8888: tex_internalformat = GL_RGBA8; tex_format = GL_BGRA; tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; default: assert(false); return 0; } backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_tex); backend->BindTexture(GL_TEXTURE_2D, tex); /* * Workaround for problem in "Mesa DRI Intel(R) Ivybridge Desktop x86/MMX/SSE2, version 9.0.3": * These lines used to be in 'vigs_gl_backend_init', but it turned out that they must * be called after 'glBindTexture'. */ backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); backend->TexImage2D(GL_TEXTURE_2D, 0, tex_internalformat, width, height, 0, tex_format, tex_type, NULL); backend->BindTexture(GL_TEXTURE_2D, cur_tex); return tex; } static void vigs_gl_backend_release_tmp_texture(void *user_data, GLuint id) { struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data; backend->DeleteTextures(1, &id); } static GLuint vigs_gl_backend_alloc_framebuffer(void *user_data, uint32_t width, uint32_t height, vigsp_surface_format format) { struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data; GLuint fb = 0; backend->GenFramebuffers(1, &fb); return fb; } static void vigs_gl_backend_release_framebuffer(void *user_data, GLuint id) { struct vigs_gl_backend *backend = (struct vigs_gl_backend*)user_data; backend->DeleteFramebuffers(1, &id); } static GLuint vigs_gl_create_shader(struct vigs_gl_backend *backend, const char *source, GLenum type) { GLuint shader = backend->CreateShader(type); GLint tmp = 0; if (!shader) { VIGS_LOG_CRITICAL("Unable to create shader type %d", type); return 0; } backend->ShaderSource(shader, 1, &source, NULL); backend->CompileShader(shader); backend->GetShaderiv(shader, GL_COMPILE_STATUS, &tmp); if (!tmp) { char *buff; tmp = 0; backend->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &tmp); buff = g_malloc0(tmp); backend->GetShaderInfoLog(shader, tmp, NULL, buff); VIGS_LOG_CRITICAL("Unable to compile shader (type = %d) - %s", type, buff); backend->DeleteShader(shader); g_free(buff); return 0; } return shader; } static GLuint vigs_gl_create_program(struct vigs_gl_backend *backend, GLuint vs_id, GLuint fs_id) { GLuint program = backend->CreateProgram(); GLint tmp = 0; if (!program) { VIGS_LOG_CRITICAL("Unable to create program"); return 0; } backend->AttachShader(program, vs_id); backend->AttachShader(program, fs_id); backend->LinkProgram(program); backend->GetProgramiv(program, GL_LINK_STATUS, &tmp); if (!tmp) { char *buff; tmp = 0; backend->GetProgramiv(program, GL_INFO_LOG_LENGTH, &tmp); buff = g_malloc0(tmp); backend->GetProgramInfoLog(program, tmp, NULL, buff); VIGS_LOG_CRITICAL("Unable to link program - %s", buff); backend->DeleteProgram(program); g_free(buff); return 0; } return program; } static void vigs_gl_draw_update_vert_tex_buffer(struct vigs_gl_backend *backend, uint32_t size) { void *ptr; if (size > backend->vbo_size) { backend->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->v1), size / 2); memcpy(ptr + (size / 2), vigs_vector_data(&backend->v2), size / 2); backend->UnmapBuffer(GL_ARRAY_BUFFER); } else { VIGS_LOG_ERROR("glMapBufferRange failed"); } } else { ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); if (ptr) { memcpy(ptr, vigs_vector_data(&backend->v1), size / 2); memcpy(ptr + (size / 2), vigs_vector_data(&backend->v2), size / 2); backend->UnmapBuffer(GL_ARRAY_BUFFER); } else { backend->Finish(); backend->BufferSubData(GL_ARRAY_BUFFER, 0, (size / 2), vigs_vector_data(&backend->v1)); backend->BufferSubData(GL_ARRAY_BUFFER, (size / 2), (size / 2), vigs_vector_data(&backend->v2)); } } } static void vigs_gl_draw_tex_prog(struct vigs_gl_backend *backend, uint32_t count) { uint32_t size = count * 16; vigs_gl_draw_update_vert_tex_buffer(backend, size); backend->EnableVertexAttribArray(backend->tex_prog_vertCoord_loc); backend->EnableVertexAttribArray(backend->tex_prog_texCoord_loc); backend->VertexAttribPointer(backend->tex_prog_vertCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL); backend->VertexAttribPointer(backend->tex_prog_texCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); backend->DrawArrays(GL_TRIANGLES, 0, count); backend->DisableVertexAttribArray(backend->tex_prog_texCoord_loc); backend->DisableVertexAttribArray(backend->tex_prog_vertCoord_loc); } static void vigs_gl_draw_color_prog(struct vigs_gl_backend *backend, const GLfloat color[4], uint32_t count) { uint32_t size = count * 8; void *ptr; if (size > backend->vbo_size) { backend->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->v1), size); backend->UnmapBuffer(GL_ARRAY_BUFFER); } else { VIGS_LOG_ERROR("glMapBufferRange failed"); } } else { ptr = backend->MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); if (ptr) { memcpy(ptr, vigs_vector_data(&backend->v1), size); backend->UnmapBuffer(GL_ARRAY_BUFFER); } else { backend->Finish(); backend->BufferSubData(GL_ARRAY_BUFFER, 0, size, vigs_vector_data(&backend->v1)); } } backend->Uniform4fv(backend->color_prog_color_loc, 1, color); backend->EnableVertexAttribArray(backend->color_prog_vertCoord_loc); backend->VertexAttribPointer(backend->color_prog_vertCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL); backend->DrawArrays(GL_TRIANGLES, 0, count); backend->DisableVertexAttribArray(backend->color_prog_vertCoord_loc); } static void vigs_gl_draw_nv21_prog(struct vigs_gl_backend *backend, uint32_t count) { uint32_t size = count * 16; vigs_gl_draw_update_vert_tex_buffer(backend, size); backend->EnableVertexAttribArray(backend->nv21_prog_vertCoord_loc); backend->EnableVertexAttribArray(backend->nv21_prog_texCoord_loc); backend->VertexAttribPointer(backend->nv21_prog_vertCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL); backend->VertexAttribPointer(backend->nv21_prog_texCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); backend->DrawArrays(GL_TRIANGLES, 0, count); backend->DisableVertexAttribArray(backend->nv21_prog_texCoord_loc); backend->DisableVertexAttribArray(backend->nv21_prog_vertCoord_loc); } static void vigs_gl_draw_yuv420_prog(struct vigs_gl_backend *backend, uint32_t count) { uint32_t size = count * 16; vigs_gl_draw_update_vert_tex_buffer(backend, size); backend->EnableVertexAttribArray(backend->yuv420_prog_vertCoord_loc); backend->EnableVertexAttribArray(backend->yuv420_prog_texCoord_loc); backend->VertexAttribPointer(backend->yuv420_prog_vertCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL); backend->VertexAttribPointer(backend->yuv420_prog_texCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); backend->DrawArrays(GL_TRIANGLES, 0, count); backend->DisableVertexAttribArray(backend->yuv420_prog_texCoord_loc); backend->DisableVertexAttribArray(backend->yuv420_prog_vertCoord_loc); } static void vigs_gl_draw_xbgr_prog(struct vigs_gl_backend *backend, uint32_t count) { uint32_t size = count * 16; vigs_gl_draw_update_vert_tex_buffer(backend, size); backend->EnableVertexAttribArray(backend->xbgr_prog_vertCoord_loc); backend->EnableVertexAttribArray(backend->xbgr_prog_texCoord_loc); backend->VertexAttribPointer(backend->xbgr_prog_vertCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL); backend->VertexAttribPointer(backend->xbgr_prog_texCoord_loc, 2, GL_FLOAT, GL_FALSE, 0, NULL + (size / 2)); backend->DrawArrays(GL_TRIANGLES, 0, count); backend->DisableVertexAttribArray(backend->xbgr_prog_texCoord_loc); backend->DisableVertexAttribArray(backend->xbgr_prog_vertCoord_loc); } static void vigs_gl_create_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat nearf, GLfloat farf, GLfloat ortho[16]) { ortho[0] = 2.0f / (right - left); ortho[5] = 2.0f / (top - bottom); ortho[10] = -2.0f / (farf - nearf); ortho[12] = -(right + left) / (right - left); ortho[13] = -(top + bottom) / (top - bottom); ortho[14] = -(farf + nearf) / (farf - nearf); ortho[15] = 1.0f; } static void vigs_gl_translate_color(vigsp_color color, vigsp_surface_format format, GLfloat res[4]) { res[3] = 1.0f; switch (format) { case vigsp_surface_bgra8888: res[3] = (GLfloat)((color >> 24) & 0xFF) / 255.0f; /* Fall through. */ case vigsp_surface_bgrx8888: res[0] = (GLfloat)((color >> 16) & 0xFF) / 255.0f; res[1] = (GLfloat)((color >> 8) & 0xFF) / 255.0f; res[2] = (GLfloat)(color & 0xFF) / 255.0f; break; default: assert(false); res[0] = 0.0f; res[1] = 0.0f; res[2] = 0.0f; } } static bool vigs_winsys_gl_surface_create_texture(struct vigs_winsys_gl_surface *ws_sfc) { GLuint cur_tex = 0, tmp_tex = 0; if (ws_sfc->tex) { return true; } ws_sfc->backend->GenTextures(1, &tmp_tex); if (!tmp_tex) { return false; } ws_sfc->backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&cur_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": * These lines used to be in 'vigs_gl_backend_init', but it turned out that they must * be called after 'glBindTexture'. */ ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ws_sfc->backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ws_sfc->backend->TexImage2D(GL_TEXTURE_2D, 0, ws_sfc->tex_internalformat, ws_sfc->base.base.width, ws_sfc->base.base.height, 0, ws_sfc->tex_format, ws_sfc->tex_type, NULL); ws_sfc->backend->BindTexture(GL_TEXTURE_2D, cur_tex); ws_sfc->tex = tmp_tex; return true; } static bool vigs_gl_surface_create_tmp_texture(struct vigs_gl_surface *gl_sfc) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend; if (gl_sfc->tmp_tex) { return true; } gl_sfc->tmp_tex = vigs_gl_pool_alloc(gl_backend->tex_pool, gl_sfc->base.ws_sfc->width, gl_sfc->base.ws_sfc->height, gl_sfc->base.format); return gl_sfc->tmp_tex != 0; } static bool vigs_gl_surface_setup_framebuffer(struct vigs_gl_surface *gl_sfc, GLuint prog_id, GLint proj_loc) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)gl_sfc->base.backend; if (!gl_sfc->fb) { gl_sfc->fb = vigs_gl_pool_alloc(gl_backend->fb_pool, gl_sfc->base.ws_sfc->width, gl_sfc->base.ws_sfc->height, gl_sfc->base.format); if (!gl_sfc->fb) { return false; } } if (gl_backend->cur_prog_id != prog_id) { gl_backend->UseProgram(prog_id); gl_backend->cur_prog_id = prog_id; } gl_backend->Viewport(0, 0, gl_sfc->base.ws_sfc->width, gl_sfc->base.ws_sfc->height); gl_backend->UniformMatrix4fv(proj_loc, 1, GL_FALSE, gl_sfc->ortho); gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_sfc->fb); gl_backend->Disable(GL_BLEND); return true; } static bool vigs_gl_update_dpy_texture(struct vigs_gl_backend *gl_backend, uint32_t width, uint32_t height) { GLuint cur_tex = 0; if (vigs_qt5_onscreen_enabled()) { // find available texture by iteration. // it is OK, since we have only very few textures. gl_backend->current_dpy = NULL; int i; for (i = 0; i < TEXTURE_NUM; ++i) { struct dpy_item *item = &(gl_backend->dpy_items[i]); if(likely(!qemu_mutex_trylock(&item->mutex))) { if (item->available) { item->available = false; gl_backend->current_dpy = item; qemu_mutex_unlock(&item->mutex); break; } qemu_mutex_unlock(&item->mutex); } } if (unlikely(!gl_backend->current_dpy)) { // can not enter here. // simply we drop this frame. return false; } } else { gl_backend->current_dpy = &gl_backend->dpy_items[0]; } gl_backend->GetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&cur_tex); if (gl_backend->current_dpy->tex) { if ((gl_backend->current_dpy->width == width) && (gl_backend->current_dpy->height == height)) { return true; } gl_backend->BindTexture(GL_TEXTURE_2D, gl_backend->current_dpy->tex); } else { GLuint tmp_tex = 0; gl_backend->GenTextures(1, &tmp_tex); if (!tmp_tex) { return false; } gl_backend->current_dpy->tex = tmp_tex; gl_backend->BindTexture(GL_TEXTURE_2D, tmp_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, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); gl_backend->BindTexture(GL_TEXTURE_2D, cur_tex); gl_backend->current_dpy->width = width; gl_backend->current_dpy->height = height; return true; } /* * @} */ /* * vigs_winsys_gl_surface. * @{ */ static void vigs_winsys_gl_surface_acquire(struct winsys_surface *sfc) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; vigs_ref_acquire(&vigs_sfc->ref); } static void vigs_winsys_gl_surface_release(struct winsys_surface *sfc) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; vigs_ref_release(&vigs_sfc->ref); } static void vigs_winsys_gl_surface_set_dirty(struct winsys_surface *sfc) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; if (vigs_sfc->parent) { vigs_sfc->parent->base.is_dirty = true; } } static void vigs_winsys_gl_surface_draw_pixels(struct winsys_surface *sfc, uint8_t *pixels) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend); if (!vigs_sfc->parent) { return; } if (has_current || vigs_sfc->backend->make_current(vigs_sfc->backend, true)) { struct vigsp_rect rect; rect.pos.x = 0; rect.pos.y = 0; rect.size.w = sfc->width; rect.size.h = sfc->height; vigs_sfc->parent->base.draw_pixels(&vigs_sfc->parent->base, pixels, &rect, 1); vigs_sfc->parent->base.is_dirty = true; vigs_sfc->backend->Finish(); if (!has_current) { vigs_sfc->backend->make_current(vigs_sfc->backend, false); } } else { VIGS_LOG_CRITICAL("make_current failed"); } } static void vigs_winsys_gl_surface_draw_pixels_scaled(struct winsys_surface *sfc, uint8_t *pixels, uint32_t width, uint32_t height) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend); if (!vigs_sfc->parent) { return; } if (has_current || vigs_sfc->backend->make_current(vigs_sfc->backend, true)) { vigs_sfc->parent->base.draw_pixels_scaled(&vigs_sfc->parent->base, pixels, width, height); vigs_sfc->parent->base.is_dirty = true; vigs_sfc->backend->Finish(); if (!has_current) { vigs_sfc->backend->make_current(vigs_sfc->backend, false); } } else { VIGS_LOG_CRITICAL("make_current failed"); } } static GLuint vigs_winsys_gl_surface_get_texture(struct winsys_gl_surface *sfc) { struct vigs_winsys_gl_surface *vigs_sfc = (struct vigs_winsys_gl_surface*)sfc; bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend); if (!vigs_sfc->tex && (has_current || vigs_sfc->backend->make_current(vigs_sfc->backend, true))) { vigs_winsys_gl_surface_create_texture(vigs_sfc); if (!has_current) { vigs_sfc->backend->make_current(vigs_sfc->backend, false); } } return vigs_sfc->tex; } static void vigs_winsys_gl_surface_destroy(struct vigs_ref *ref) { struct vigs_winsys_gl_surface *vigs_sfc = container_of(ref, struct vigs_winsys_gl_surface, ref); bool has_current = vigs_sfc->backend->has_current(vigs_sfc->backend); if (has_current || vigs_sfc->backend->make_current(vigs_sfc->backend, true)) { if (vigs_sfc->tex) { vigs_sfc->backend->DeleteTextures(1, &vigs_sfc->tex); } if (!has_current) { vigs_sfc->backend->make_current(vigs_sfc->backend, false); } } vigs_ref_cleanup(&vigs_sfc->ref); g_free(vigs_sfc); } static struct vigs_winsys_gl_surface *vigs_winsys_gl_surface_create(struct vigs_gl_backend *backend, struct vigs_gl_surface *parent, uint32_t width, uint32_t height, GLint tex_internalformat, GLenum tex_format, GLenum tex_type) { struct vigs_winsys_gl_surface *ws_sfc; ws_sfc = g_malloc0(sizeof(*ws_sfc)); ws_sfc->base.base.width = width; ws_sfc->base.base.height = height; ws_sfc->base.base.acquire = &vigs_winsys_gl_surface_acquire; ws_sfc->base.base.release = &vigs_winsys_gl_surface_release; ws_sfc->base.base.set_dirty = &vigs_winsys_gl_surface_set_dirty; ws_sfc->base.base.draw_pixels = &vigs_winsys_gl_surface_draw_pixels; ws_sfc->base.base.draw_pixels_scaled = &vigs_winsys_gl_surface_draw_pixels_scaled; ws_sfc->base.get_texture = &vigs_winsys_gl_surface_get_texture; ws_sfc->tex_internalformat = tex_internalformat; ws_sfc->tex_format = tex_format; ws_sfc->tex_type = tex_type; ws_sfc->backend = backend; ws_sfc->parent = parent; vigs_ref_init(&ws_sfc->ref, &vigs_winsys_gl_surface_destroy); return ws_sfc; } static void vigs_winsys_gl_surface_orphan(struct vigs_winsys_gl_surface *sfc) { sfc->parent = NULL; } /* * @} */ static void vigs_gl_backend_batch_start(struct vigs_backend *backend) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend; if (!gl_backend->make_current(gl_backend, true)) { VIGS_LOG_CRITICAL("make_current failed"); } } /* * vigs_gl_surface. * @{ */ static void vigs_gl_surface_read_pixels(struct vigs_surface *sfc, uint8_t *pixels) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); GLfloat sfc_w, sfc_h; GLfloat *vert_coords; GLfloat *tex_coords; if (!ws_sfc->tex) { VIGS_LOG_TRACE("skipping blank read"); goto out; } if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { goto out; } if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_sfc, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); sfc_w = ws_sfc->base.base.width; sfc_h = ws_sfc->base.base.height; gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_sfc->tmp_tex, 0); vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = sfc_h; vert_coords[2] = sfc_w; vert_coords[3] = sfc_h; vert_coords[8] = vert_coords[4] = sfc_w; 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; gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); vigs_gl_draw_tex_prog(gl_backend, 6); gl_backend->PixelStorei(GL_PACK_ALIGNMENT, 1); gl_backend->ReadPixels(0, 0, sfc_w, sfc_h, ws_sfc->tex_format, ws_sfc->tex_type, pixels); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_draw_pixels(struct vigs_surface *sfc, uint8_t *pixels, const struct vigsp_rect *entries, uint32_t num_entries) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); GLfloat sfc_w, sfc_h; GLfloat *vert_coords; GLfloat *tex_coords; uint32_t i; if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { goto out; } if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_sfc, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } sfc_w = ws_sfc->base.base.width; sfc_h = ws_sfc->base.base.height; gl_backend->BindTexture(GL_TEXTURE_2D, gl_sfc->tmp_tex); gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, sfc_w); for (i = 0; i < num_entries; ++i) { uint32_t x = entries[i].pos.x; uint32_t y = entries[i].pos.y; uint32_t width = entries[i].size.w; uint32_t height = entries[i].size.h; VIGS_LOG_TRACE("x = %u, y = %u, width = %u, height = %u", x, y, width, height); gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, x); gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, y); gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, ws_sfc->tex_format, ws_sfc->tex_type, pixels); } vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_sfc->tex, 0); for (i = 0; i < num_entries; ++i) { vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = entries[i].pos.x; vert_coords[7] = vert_coords[1] = sfc_h - entries[i].pos.y; vert_coords[2] = entries[i].pos.x + entries[i].size.w; vert_coords[3] = sfc_h - entries[i].pos.y; vert_coords[8] = vert_coords[4] = entries[i].pos.x + entries[i].size.w; vert_coords[9] = vert_coords[5] = sfc_h - (entries[i].pos.y + entries[i].size.h); vert_coords[10] = entries[i].pos.x; vert_coords[11] = sfc_h - (entries[i].pos.y + entries[i].size.h); tex_coords[6] = tex_coords[0] = (GLfloat)entries[i].pos.x / sfc_w; tex_coords[7] = tex_coords[1] = (GLfloat)entries[i].pos.y / sfc_h; tex_coords[2] = (GLfloat)(entries[i].pos.x + entries[i].size.w) / sfc_w; tex_coords[3] = (GLfloat)entries[i].pos.y / sfc_h; tex_coords[8] = tex_coords[4] = (GLfloat)(entries[i].pos.x + entries[i].size.w) / sfc_w; tex_coords[9] = tex_coords[5] = (GLfloat)(entries[i].pos.y + entries[i].size.h) / sfc_h; tex_coords[10] = (GLfloat)entries[i].pos.x / sfc_w; tex_coords[11] = (GLfloat)(entries[i].pos.y + entries[i].size.h) / sfc_h; } vigs_gl_draw_tex_prog(gl_backend, num_entries * 6); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_draw_pixels_scaled(struct vigs_surface *sfc, uint8_t *pixels, uint32_t width, uint32_t height) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); GLfloat sfc_w, sfc_h; GLfloat *vert_coords; GLfloat *tex_coords; sfc_w = ws_sfc->base.base.width; sfc_h = ws_sfc->base.base.height; if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { goto out; } if (!vigs_gl_surface_create_tmp_texture(gl_sfc)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_sfc, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } gl_backend->BindTexture(GL_TEXTURE_2D, gl_sfc->tmp_tex); gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl_backend->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 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->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, width); gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); if (width > sfc_w || height > sfc_h) { gl_backend->TexImage2D(GL_TEXTURE_2D, 0, ws_sfc->tex_internalformat, width, height, 0, ws_sfc->tex_format, ws_sfc->tex_type, pixels); } else { gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, ws_sfc->tex_format, ws_sfc->tex_type, pixels); } vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_sfc->tex, 0); vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = sfc_h; vert_coords[2] = sfc_w; vert_coords[3] = sfc_h; vert_coords[8] = vert_coords[4] = sfc_w; 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] = (GLfloat)width / sfc_w; tex_coords[3] = 0; tex_coords[8] = tex_coords[4] = (GLfloat)width / sfc_w; tex_coords[9] = tex_coords[5] = (GLfloat)height / sfc_h; tex_coords[10] = 0; tex_coords[11] = (GLfloat)height / sfc_h; vigs_gl_draw_tex_prog(gl_backend, 6); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_copy(struct vigs_surface *dst, struct vigs_surface *src, const struct vigsp_copy *entries, uint32_t num_entries) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst; struct vigs_gl_surface *gl_src = (struct vigs_gl_surface*)src; struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst); struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src); uint32_t total_entries = num_entries, i; GLfloat src_w, src_h; GLfloat dst_h; GLfloat *vert_coords; GLfloat *tex_coords; if (!vigs_winsys_gl_surface_create_texture(ws_dst)) { goto out; } if (!ws_src->tex) { VIGS_LOG_WARN("copying garbage ???"); } if (!vigs_winsys_gl_surface_create_texture(ws_src)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_dst, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); src_w = ws_src->base.base.width; src_h = ws_src->base.base.height; dst_h = ws_dst->base.base.height; if (src == dst) { /* * Feedback loop is possible, use 'tmp_tex' instead. */ if (!vigs_gl_surface_create_tmp_texture(gl_dst)) { goto out; } gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_dst->tmp_tex, 0); ++total_entries; vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = src_h; vert_coords[2] = src_w; vert_coords[3] = src_h; vert_coords[8] = vert_coords[4] = src_w; 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] = 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; } else { /* * No feedback loop possible, render to 'front_tex'. */ gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_dst->tex, 0); } for (i = 0; i < num_entries; ++i) { vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = entries[i].to.x; vert_coords[7] = vert_coords[1] = dst_h - entries[i].to.y; vert_coords[2] = entries[i].to.x + entries[i].size.w; vert_coords[3] = dst_h - entries[i].to.y; vert_coords[8] = vert_coords[4] = entries[i].to.x + entries[i].size.w; vert_coords[9] = vert_coords[5] = dst_h - (entries[i].to.y + entries[i].size.h); vert_coords[10] = entries[i].to.x; vert_coords[11] = dst_h - (entries[i].to.y + entries[i].size.h); tex_coords[6] = tex_coords[0] = (GLfloat)entries[i].from.x / src_w; tex_coords[7] = tex_coords[1] = (GLfloat)(src_h - entries[i].from.y) / src_h; tex_coords[2] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w; tex_coords[3] = (GLfloat)(src_h - entries[i].from.y) / src_h; tex_coords[8] = tex_coords[4] = (GLfloat)(entries[i].from.x + entries[i].size.w) / src_w; tex_coords[9] = tex_coords[5] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h; tex_coords[10] = (GLfloat)entries[i].from.x / src_w; tex_coords[11] = (GLfloat)(src_h - (entries[i].from.y + entries[i].size.h)) / src_h; } gl_backend->BindTexture(GL_TEXTURE_2D, ws_src->tex); vigs_gl_draw_tex_prog(gl_backend, total_entries * 6); if (src == dst) { vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = src_h; vert_coords[2] = src_w; vert_coords[3] = src_h; vert_coords[8] = vert_coords[4] = src_w; 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] = 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; gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_dst->tex, 0); gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->tmp_tex); vigs_gl_draw_tex_prog(gl_backend, 6); } out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_solid_fill(struct vigs_surface *sfc, vigsp_color color, const struct vigsp_rect *entries, uint32_t num_entries) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); uint32_t i; GLfloat colorf[4]; GLfloat sfc_h; if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_sfc, gl_backend->color_prog_id, gl_backend->color_prog_proj_loc)) { goto out; } sfc_h = ws_sfc->base.base.height; gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_sfc->tex, 0); vigs_vector_resize(&gl_backend->v1, 0); for (i = 0; i < num_entries; ++i) { GLfloat *vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = entries[i].pos.x; vert_coords[7] = vert_coords[1] = sfc_h - entries[i].pos.y; vert_coords[2] = entries[i].pos.x + entries[i].size.w; vert_coords[3] = sfc_h - entries[i].pos.y; vert_coords[8] = vert_coords[4] = entries[i].pos.x + entries[i].size.w; vert_coords[9] = vert_coords[5] = sfc_h - (entries[i].pos.y + entries[i].size.h); vert_coords[10] = entries[i].pos.x; vert_coords[11] = sfc_h - (entries[i].pos.y + entries[i].size.h); } vigs_gl_translate_color(color, sfc->format, colorf); vigs_gl_draw_color_prog(gl_backend, colorf, num_entries * 6); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_ga_copy(struct vigs_surface *dst, uint32_t dst_stride, struct vigs_surface *src, uint8_t *src_pixels, uint32_t src_stride, const struct vigsp_copy *entry) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst; struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst); GLfloat dst_w, dst_h, height; GLfloat *vert_coords; GLfloat *tex_coords; if ((entry->from.x != 0) || (entry->to.x != 0) || (entry->to.y != 0)) { VIGS_LOG_ERROR("not supported"); } if (entry->from.y * src_stride + entry->size.w * entry->size.h > src->stride * src->ws_sfc->height) { VIGS_LOG_ERROR("out of bounds"); return; } if (!src_pixels) { /* * Contents were flushed to GPU, so read them back, * not very pretty, but this path should be triggered * very rarely. */ vigs_vector_resize(&gl_backend->v1, src->stride * src->ws_sfc->height); src_pixels = vigs_vector_data(&gl_backend->v1); vigs_gl_surface_read_pixels(src, src_pixels); } if (!vigs_winsys_gl_surface_create_texture(ws_dst)) { goto out; } if (!vigs_gl_surface_create_tmp_texture(gl_dst)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_dst, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } height = (entry->size.w * entry->size.h + dst->stride - 1) / dst->stride; dst_w = ws_dst->base.base.width; dst_h = ws_dst->base.base.height; gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->tmp_tex); gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, dst_w, height, ws_dst->tex_format, ws_dst->tex_type, src_pixels + entry->from.y * src_stride); vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_dst->tex, 0); vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); vert_coords[6] = vert_coords[0] = entry->to.x; vert_coords[7] = vert_coords[1] = dst_h - entry->to.y; vert_coords[2] = entry->to.x + dst_w; vert_coords[3] = dst_h - entry->to.y; vert_coords[8] = vert_coords[4] = entry->to.x + dst_w; vert_coords[9] = vert_coords[5] = dst_h - (entry->to.y + height); vert_coords[10] = entry->to.x; vert_coords[11] = dst_h - (entry->to.y + height); tex_coords[6] = tex_coords[0] = (GLfloat)entry->to.x / dst_w; tex_coords[7] = tex_coords[1] = (GLfloat)entry->to.y / dst_h; tex_coords[2] = (GLfloat)(entry->to.x + dst_w) / dst_w; tex_coords[3] = (GLfloat)entry->to.y / dst_h; tex_coords[8] = tex_coords[4] = (GLfloat)(entry->to.x + dst_w) / dst_w; tex_coords[9] = tex_coords[5] = (GLfloat)(entry->to.y + height) / dst_h; tex_coords[10] = (GLfloat)entry->to.x / dst_w; tex_coords[11] = (GLfloat)(entry->to.y + height) / dst_h; vigs_gl_draw_tex_prog(gl_backend, 6); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static GLuint vigs_gl_surface_create_pixel_buf(struct vigs_surface *sfc) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); GLsizei sfc_stride = sfc->stride; GLsizei sfc_h = ws_sfc->base.base.height; GLuint pbuf; if (!ws_sfc->tex) { VIGS_LOG_ERROR("source surface must be not empty"); return 0; } gl_backend->GenBuffers(1, &pbuf); gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER, pbuf); gl_backend->BufferData(GL_PIXEL_PACK_BUFFER, sfc_stride * sfc_h, NULL, GL_STREAM_COPY); vigs_gl_surface_read_pixels(sfc, 0); gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER, 0); return pbuf; } static bool vigs_gl_surface_setup_yuv_textures(struct vigs_surface *dst, struct vigs_surface *src) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst; struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst); GLsizei dst_w = ws_dst->base.base.width; GLsizei dst_h = ws_dst->base.base.height; GLsizei tex_widths[3] = {dst_w / 4, dst_w / 8, dst_w / 8}; GLsizei tex_heights[3] = {dst_h, dst_h / 2, dst_h / 2}; GLsizei pbuf_offsets[3] = {0, dst_w * dst_h, 5 * dst_w * dst_h / 4}; int i; bool need_alloc = false; GLuint pbuf; /* * We have to create and destroy pixel buffer at every yuv conversion, * because we can't check restoring of source texture. */ pbuf = vigs_gl_surface_create_pixel_buf(src); if (pbuf == 0) { return false; } if (gl_dst->yuv_textures[0] == 0) { gl_backend->GenTextures(3, &gl_dst->yuv_textures[0]); need_alloc = true; } gl_backend->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbuf); for (i = 0; i < 3; i++) { gl_backend->ActiveTexture(GL_TEXTURE0 + i); gl_backend->BindTexture(GL_TEXTURE_2D, gl_dst->yuv_textures[i]); 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->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, tex_widths[i]); if (need_alloc) { gl_backend->TexImage2D(GL_TEXTURE_2D, 0, ws_dst->tex_internalformat, tex_widths[i], tex_heights[i], 0, ws_dst->tex_format, ws_dst->tex_type, (GLvoid *)(intptr_t)pbuf_offsets[i]); } else { gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_widths[i], tex_heights[i], ws_dst->tex_format, ws_dst->tex_type, (GLvoid *)(intptr_t)pbuf_offsets[i]); } } gl_backend->ActiveTexture(GL_TEXTURE0); gl_backend->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); gl_backend->DeleteBuffers(1, &pbuf); return true; } static void vigs_gl_surface_convert_yuv2argb(struct vigs_surface *dst, struct vigs_surface *src) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst; struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst); GLsizei dst_w = ws_dst->base.base.width; GLsizei dst_h = ws_dst->base.base.height; GLfloat *vert_coords; GLfloat *tex_coords; if (!vigs_winsys_gl_surface_create_texture(ws_dst)) { goto out; } if (!vigs_gl_surface_setup_yuv_textures(dst, src)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_dst, gl_backend->yuv420_prog_id, gl_backend->yuv420_prog_proj_loc)) { goto out; } vigs_vector_resize(&gl_backend->v1, 12 * sizeof(GLfloat)); vigs_vector_resize(&gl_backend->v2, 12 * sizeof(GLfloat)); vert_coords = vigs_vector_data(&gl_backend->v1); tex_coords = vigs_vector_data(&gl_backend->v2); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = dst_h; vert_coords[2] = dst_w; vert_coords[3] = dst_h; vert_coords[8] = vert_coords[4] = dst_w; vert_coords[9] = vert_coords[5] = 0.0; vert_coords[10] = 0.0; vert_coords[11] = 0.0; tex_coords[6] = tex_coords[0] = 0.0; tex_coords[7] = tex_coords[1] = 1.0; tex_coords[2] = 1.0; tex_coords[3] = 1.0; tex_coords[8] = tex_coords[4] = 1.0; tex_coords[9] = tex_coords[5] = 0.0; tex_coords[10] = 0.0; tex_coords[11] = 0.0; gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_dst->tex, 0); gl_backend->UseProgram(gl_backend->yuv420_prog_id); gl_backend->Uniform2f(gl_backend->yuv420_prog_ytexSize_loc, dst_w / 4, dst_h); gl_backend->Uniform2f(gl_backend->yuv420_prog_utexSize_loc, dst_w / 8, dst_h / 2); gl_backend->Uniform2f(gl_backend->yuv420_prog_vtexSize_loc, dst_w / 8, dst_h / 2); gl_backend->Uniform2f(gl_backend->yuv420_prog_size_loc, dst_w, dst_h); vigs_gl_draw_yuv420_prog(gl_backend, 6); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_convert_argb2xbgr(struct vigs_surface *dst, struct vigs_surface *src) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)dst->backend; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface*)dst; struct vigs_gl_surface *gl_src = (struct vigs_gl_surface*)src; struct vigs_winsys_gl_surface *ws_dst = get_ws_sfc(gl_dst); struct vigs_winsys_gl_surface *ws_src = get_ws_sfc(gl_src); GLsizei dst_w = ws_dst->base.base.width; GLsizei dst_h = ws_dst->base.base.height; GLfloat *vert_coords; GLfloat *tex_coords; if (!vigs_winsys_gl_surface_create_texture(ws_dst)) { goto out; } if (!ws_src->tex) { VIGS_LOG_WARN("copying garbage ???"); } if (!vigs_winsys_gl_surface_create_texture(ws_src)) { goto out; } if (!vigs_gl_surface_setup_framebuffer(gl_dst, gl_backend->xbgr_prog_id, gl_backend->xbgr_prog_proj_loc)) { goto out; } vigs_vector_resize(&gl_backend->v1, 12 * sizeof(GLfloat)); vigs_vector_resize(&gl_backend->v2, 12 * sizeof(GLfloat)); vert_coords = vigs_vector_data(&gl_backend->v1); tex_coords = vigs_vector_data(&gl_backend->v2); vert_coords[6] = vert_coords[0] = 0; vert_coords[7] = vert_coords[1] = dst_h; vert_coords[2] = dst_w; vert_coords[3] = dst_h; vert_coords[8] = vert_coords[4] = dst_w; vert_coords[9] = vert_coords[5] = 0.0; vert_coords[10] = 0.0; vert_coords[11] = 0.0; tex_coords[6] = tex_coords[0] = 0.0; tex_coords[7] = tex_coords[1] = 1.0; tex_coords[2] = 1.0; tex_coords[3] = 1.0; tex_coords[8] = tex_coords[4] = 1.0; tex_coords[9] = tex_coords[5] = 0.0; tex_coords[10] = 0.0; tex_coords[11] = 0.0; gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ws_dst->tex, 0); gl_backend->BindTexture(GL_TEXTURE_2D, ws_src->tex); gl_backend->UseProgram(gl_backend->xbgr_prog_id); vigs_gl_draw_xbgr_prog(gl_backend, 6); gl_backend->UseProgram(gl_backend->tex_prog_id); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); } static void vigs_gl_surface_convert(struct vigs_surface *dst, uint32_t dst_format, struct vigs_surface *src, uint32_t src_format, int y_invert) { uint32_t width = dst->ws_sfc->width; uint32_t height = dst->ws_sfc->height; bool conversion_supported = true; struct vigsp_copy entry = { .from = { 0, 0 }, .to = { 0, 0 }, .size = { width, height } }; struct vigs_gl_surface *gl_dst = (struct vigs_gl_surface *)dst; if (y_invert) { vigs_gl_create_ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f, gl_dst->ortho); } switch (dst_format) { case DRM_FORMAT_ARGB8888: switch (src_format) { case DRM_FORMAT_YUV420: vigs_gl_surface_convert_yuv2argb(dst, src); break; case DRM_FORMAT_ARGB8888: vigs_gl_surface_copy(dst, src, &entry, 1); break; default: conversion_supported = false; break; } break; case DRM_FORMAT_XBGR8888: switch (src_format) { case DRM_FORMAT_ARGB8888: vigs_gl_surface_convert_argb2xbgr(dst, src); break; default: conversion_supported = false; break; } break; default: conversion_supported = false; break; } if (y_invert) { vigs_gl_create_ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f, gl_dst->ortho); } if (!conversion_supported) { VIGS_LOG_ERROR("format conversion from 0x%x to 0x%x is not supported", src_format, dst_format); } } static void vigs_gl_surface_destroy(struct vigs_surface *sfc) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)sfc->backend; struct vigs_gl_surface *gl_sfc = (struct vigs_gl_surface*)sfc; struct vigs_winsys_gl_surface *ws_sfc = get_ws_sfc(gl_sfc); vigs_winsys_gl_surface_orphan(ws_sfc); if (gl_sfc->fb) { vigs_gl_pool_release(gl_backend->fb_pool, sfc->ws_sfc->width, sfc->ws_sfc->height, sfc->format); } if (gl_sfc->tmp_tex) { vigs_gl_pool_release(gl_backend->tex_pool, sfc->ws_sfc->width, sfc->ws_sfc->height, sfc->format); } gl_backend->DeleteTextures(3, &gl_sfc->yuv_textures[0]); vigs_surface_cleanup(&gl_sfc->base); g_free(gl_sfc); } /* * @} */ static struct vigs_surface *vigs_gl_backend_create_surface(struct vigs_backend *backend, uint32_t width, uint32_t height, uint32_t stride, vigsp_surface_format format, vigsp_surface_id id) { struct vigs_gl_surface *gl_sfc = NULL; struct vigs_winsys_gl_surface *ws_sfc = NULL; GLint tex_internalformat; GLenum tex_format; GLenum tex_type; GLint tex_bpp; switch (format) { case vigsp_surface_bgrx8888: case vigsp_surface_bgra8888: tex_internalformat = GL_RGBA8; tex_format = GL_BGRA; tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; break; default: assert(false); return NULL; } tex_bpp = vigs_format_bpp(format); if ((width * tex_bpp) != stride) { VIGS_LOG_ERROR("Custom strides not supported yet"); return NULL; } gl_sfc = g_malloc0(sizeof(*gl_sfc)); ws_sfc = vigs_winsys_gl_surface_create((struct vigs_gl_backend*)backend, gl_sfc, width, height, tex_internalformat, tex_format, tex_type); vigs_surface_init(&gl_sfc->base, &ws_sfc->base.base, backend, stride, format, id); vigs_gl_create_ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f, gl_sfc->ortho); ws_sfc->base.base.release(&ws_sfc->base.base); gl_sfc->base.read_pixels = &vigs_gl_surface_read_pixels; gl_sfc->base.draw_pixels = &vigs_gl_surface_draw_pixels; gl_sfc->base.draw_pixels_scaled = &vigs_gl_surface_draw_pixels_scaled; gl_sfc->base.copy = &vigs_gl_surface_copy; gl_sfc->base.solid_fill = &vigs_gl_surface_solid_fill; gl_sfc->base.ga_copy = &vigs_gl_surface_ga_copy; gl_sfc->base.convert = &vigs_gl_surface_convert; gl_sfc->base.destroy = &vigs_gl_surface_destroy; return &gl_sfc->base; } static inline void vigs_gl_backend_sort_planes(const struct vigs_plane *planes, const struct vigs_plane **sorted_planes) { /* * Sort planes, only 2 of them now, don't bother... * The 3rd plane is for HW cursor (should always be on top). */ assert(VIGS_MAX_PLANES == 3); if (planes[0].z_pos <= planes[1].z_pos) { sorted_planes[0] = &planes[0]; sorted_planes[1] = &planes[1]; } else { sorted_planes[0] = &planes[1]; sorted_planes[1] = &planes[0]; } sorted_planes[2] = &planes[2]; } /* * 'above_root' means we want to render only planes that are above root surface. * 'bottom' means that if at least one plane is going to be rendered it'll be * bottom plane, i.e. the first one in surface stack. */ static bool vigs_gl_backend_composite_planes(struct vigs_gl_backend *gl_backend, const struct vigs_plane **planes, bool above_root, bool bottom, GLfloat ortho[16]) { uint32_t i; GLfloat *vert_coords = vigs_vector_data(&gl_backend->v1); GLfloat *tex_coords = vigs_vector_data(&gl_backend->v2); for (i = 0; i < VIGS_MAX_PLANES; ++i) { const struct vigs_plane *plane = planes[i]; GLfloat src_w, src_h; GLfloat tmp_x, tmp_y; if (!vigs_plane_enabled(plane) || ((plane->z_pos >= 0) ^ above_root)) { continue; } VIGS_LOG_DEBUG("plane[%u]: %ux%u format = %d, z_pos = %d, hflip = %d," " vflip = %d, rotation = %d ", i, plane->width, plane->height, plane->format, plane->z_pos, plane->hflip, plane->vflip, plane->rotation); src_w = plane->width; src_h = plane->height; vert_coords[6] = vert_coords[0] = plane->dst_x; vert_coords[7] = vert_coords[1] = plane->dst_y; vert_coords[2] = plane->dst_x + (int)plane->dst_size.w; vert_coords[3] = plane->dst_y; vert_coords[8] = vert_coords[4] = plane->dst_x + (int)plane->dst_size.w; vert_coords[9] = vert_coords[5] = plane->dst_y + (int)plane->dst_size.h; vert_coords[10] = plane->dst_x; 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[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[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[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; if (plane->hflip) { tmp_x = tex_coords[0]; tmp_y = tex_coords[1]; tex_coords[6] = tex_coords[0] = tex_coords[2]; tex_coords[7] = tex_coords[1] = tex_coords[3]; tex_coords[2] = tmp_x; tex_coords[3] = tmp_y; tmp_x = tex_coords[4]; tmp_y = tex_coords[5]; tex_coords[8] = tex_coords[4] = tex_coords[10]; tex_coords[9] = tex_coords[5] = tex_coords[11]; tex_coords[10] = tmp_x; tex_coords[11] = tmp_y; } if (plane->vflip) { tmp_x = tex_coords[0]; tmp_y = tex_coords[1]; tex_coords[6] = tex_coords[0] = tex_coords[10]; tex_coords[7] = tex_coords[1] = tex_coords[11]; tex_coords[10] = tmp_x; tex_coords[11] = tmp_y; tmp_x = tex_coords[4]; tmp_y = tex_coords[5]; tex_coords[8] = tex_coords[4] = tex_coords[2]; tex_coords[9] = tex_coords[5] = tex_coords[3]; tex_coords[2] = tmp_x; tex_coords[3] = tmp_y; } switch (plane->rotation) { case vigsp_rotation90: tmp_x = tex_coords[0]; tmp_y = tex_coords[1]; tex_coords[6] = tex_coords[0] = tex_coords[10]; tex_coords[7] = tex_coords[1] = tex_coords[11]; tex_coords[10] = tex_coords[4]; tex_coords[11] = tex_coords[5]; tex_coords[8] = tex_coords[4] = tex_coords[2]; tex_coords[9] = tex_coords[5] = tex_coords[3]; tex_coords[2] = tmp_x; tex_coords[3] = tmp_y; break; case vigsp_rotation180: tmp_x = tex_coords[0]; tmp_y = tex_coords[1]; tex_coords[6] = tex_coords[0] = tex_coords[4]; tex_coords[7] = tex_coords[1] = tex_coords[5]; tex_coords[8] = tex_coords[4] = tmp_x; tex_coords[9] = tex_coords[5] = tmp_y; tmp_x = tex_coords[2]; tmp_y = tex_coords[3]; tex_coords[2] = tex_coords[10]; tex_coords[3] = tex_coords[11]; tex_coords[10] = tmp_x; tex_coords[11] = tmp_y; break; case vigsp_rotation270: tmp_x = tex_coords[0]; tmp_y = tex_coords[1]; tex_coords[6] = tex_coords[0] = tex_coords[2]; tex_coords[7] = tex_coords[1] = tex_coords[3]; tex_coords[2] = tex_coords[4]; tex_coords[3] = tex_coords[5]; tex_coords[8] = tex_coords[4] = tex_coords[10]; tex_coords[9] = tex_coords[5] = tex_coords[11]; tex_coords[10] = tmp_x; tex_coords[11] = tmp_y; break; case vigsp_rotation0: default: break; } if (!bottom && (plane->format == vigsp_plane_bgra8888)) { /* * This is not bottom plane and it has alpha, turn on blending. */ gl_backend->Enable(GL_BLEND); gl_backend->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { gl_backend->Disable(GL_BLEND); } if (plane->format == vigsp_plane_nv21) { struct vigs_gl_surface *gl_sfc; struct vigs_winsys_gl_surface *ws_sfc; gl_backend->UseProgram(gl_backend->nv21_prog_id); gl_backend->UniformMatrix4fv(gl_backend->nv21_prog_proj_loc, 1, GL_FALSE, ortho); gl_sfc = (struct vigs_gl_surface*)plane->surfaces[1]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->ActiveTexture(GL_TEXTURE1); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); gl_backend->Uniform2f(gl_backend->nv21_prog_ctexSize_loc, ws_sfc->base.base.width, ws_sfc->base.base.height); gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->ActiveTexture(GL_TEXTURE0); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); gl_backend->Uniform2f(gl_backend->nv21_prog_ytexSize_loc, ws_sfc->base.base.width, ws_sfc->base.base.height); gl_backend->Uniform2f(gl_backend->nv21_prog_size_loc, src_w, src_h); vigs_gl_draw_nv21_prog(gl_backend, 6); gl_backend->UseProgram(gl_backend->tex_prog_id); } else if (plane->format == vigsp_plane_yuv420) { struct vigs_gl_surface *gl_sfc; struct vigs_winsys_gl_surface *ws_sfc; gl_backend->UseProgram(gl_backend->yuv420_prog_id); gl_backend->UniformMatrix4fv(gl_backend->yuv420_prog_proj_loc, 1, GL_FALSE, ortho); gl_sfc = (struct vigs_gl_surface*)plane->surfaces[2]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->ActiveTexture(GL_TEXTURE2); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); gl_backend->Uniform2f(gl_backend->yuv420_prog_vtexSize_loc, ws_sfc->base.base.width, ws_sfc->base.base.height); gl_sfc = (struct vigs_gl_surface*)plane->surfaces[1]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->ActiveTexture(GL_TEXTURE1); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); gl_backend->Uniform2f(gl_backend->yuv420_prog_utexSize_loc, ws_sfc->base.base.width, ws_sfc->base.base.height); gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->ActiveTexture(GL_TEXTURE0); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); gl_backend->Uniform2f(gl_backend->yuv420_prog_ytexSize_loc, ws_sfc->base.base.width, ws_sfc->base.base.height); gl_backend->Uniform2f(gl_backend->yuv420_prog_size_loc, src_w, src_h); vigs_gl_draw_yuv420_prog(gl_backend, 6); gl_backend->UseProgram(gl_backend->tex_prog_id); } else { struct vigs_gl_surface *gl_sfc; struct vigs_winsys_gl_surface *ws_sfc; gl_sfc = (struct vigs_gl_surface*)plane->surfaces[0]; ws_sfc = get_ws_sfc(gl_sfc); gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex); vigs_gl_draw_tex_prog(gl_backend, 6); } bottom = false; } return bottom; } static bool vigs_gl_backend_composite(struct vigs_surface *surface, const struct vigs_plane *planes, bool planes_dirty, 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; struct vigs_winsys_gl_surface *ws_root_sfc = get_ws_sfc(gl_root_sfc); uint32_t i; int j; GLfloat *vert_coords; GLfloat *tex_coords; const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES]; bool bottom = true; VIGS_LOG_TRACE("enter"); if (surface->ptr) { if (!vigs_qt5_onscreen_enabled() && !planes_dirty) { memcpy(display_data, surface->ptr, surface->stride * surface->ws_sfc->height); return true; } } else if (!ws_root_sfc->tex) { VIGS_LOG_WARN("compositing garbage (root surface) ???"); } if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc)) { goto out; } if (!vigs_gl_update_dpy_texture(gl_backend, surface->ws_sfc->width, surface->ws_sfc->height)) { goto out; } for (i = 0; i < VIGS_MAX_PLANES; ++i) { struct vigs_gl_surface *gl_sfc; struct vigs_winsys_gl_surface *ws_sfc; if (!vigs_plane_enabled(&planes[i])) { continue; } for (j = 0; j < 4; ++j) { gl_sfc = (struct vigs_gl_surface*)planes[i].surfaces[j]; if (!gl_sfc) { continue; } ws_sfc = get_ws_sfc(gl_sfc); if (!ws_sfc->tex) { VIGS_LOG_WARN("compositing garbage (plane %u, sfc %d) ???", i, j); } if (!vigs_winsys_gl_surface_create_texture(ws_sfc)) { goto out; } } } if (!vigs_gl_surface_setup_framebuffer(gl_root_sfc, gl_backend->tex_prog_id, gl_backend->tex_prog_proj_loc)) { goto out; } vigs_gl_backend_sort_planes(planes, sorted_planes); vigs_vector_resize(&gl_backend->v1, 0); vigs_vector_resize(&gl_backend->v2, 0); vert_coords = vigs_vector_append(&gl_backend->v1, (12 * sizeof(GLfloat))); tex_coords = vigs_vector_append(&gl_backend->v2, (12 * sizeof(GLfloat))); if (surface->ptr) { /* * Root surface is scanout, upload it to texture. * Slow path. */ gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex); gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ws_root_sfc->base.base.width, ws_root_sfc->base.base.height, ws_root_sfc->tex_format, ws_root_sfc->tex_type, surface->ptr); } gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0); gl_backend->Clear(GL_COLOR_BUFFER_BIT); bottom = vigs_gl_backend_composite_planes(gl_backend, sorted_planes, false, bottom, gl_root_sfc->ortho); /* * Render root surface. */ 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[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; } 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; } if (!bottom) { /* * Root surface has planes beneath it, turn on blending. * * Note that we DON'T check for alpha on root surface, i.e.: * (surface->format == vigsp_surface_bgra8888) * The reasons are: * + X.Org doesn't allow having 32 depths, i.e. only bpp can * be 32, depth must be <= 24, i.e. X.Org is not underlay-aware, * but that doesn't mean we can't have them with X.Org * + Since we DO have something beneath the root surface that means * root surface just got to have alpha, otherwise user won't be * able to see that "something", i.e. specifying alpha in root * surface format is not that necessary in this case */ gl_backend->Enable(GL_BLEND); gl_backend->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { gl_backend->Disable(GL_BLEND); } gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex); vigs_gl_draw_tex_prog(gl_backend, 6); bottom = false; vigs_gl_backend_composite_planes(gl_backend, sorted_planes, true, bottom, gl_root_sfc->ortho); out: gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); return false; } static bool vigs_gl_backend_capture(struct vigs_surface *surface, void *pixels) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend; if (gl_backend->read_pixels_make_current(gl_backend, true)) { if (!gl_backend->dpy_fb) { gl_backend->GenFramebuffers(1, &gl_backend->dpy_fb); if (!gl_backend->dpy_fb) { VIGS_LOG_ERROR("cannot create capture FB"); gl_backend->read_pixels_make_current(gl_backend, false); return false; } } gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_backend->dpy_fb); gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_backend->current_dpy->tex, 0); gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width, gl_backend->current_dpy->height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0); gl_backend->read_pixels_make_current(gl_backend, false); return true; } return false; } static void vigs_gl_backend_batch_end(struct vigs_backend *backend) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend; gl_backend->Finish(); gl_backend->make_current(gl_backend, false); } static bool vigs_gl_backend_display(struct vigs_backend *backend, uint8_t *display_data) { struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)backend; VIGS_LOG_TRACE("enter"); if (vigs_qt5_onscreen_enabled()) { if (gl_backend->current_dpy && gl_backend->current_dpy->tex) { vigs_qt5_dpy_render_texture(gl_backend->current_dpy); } return true; } 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->current_dpy->tex, 0); gl_backend->ReadPixels(0, 0, gl_backend->current_dpy->width, gl_backend->current_dpy->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; } } bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend) { if (!gl_backend->make_current(gl_backend, true)) { return false; } gl_backend->tex_pool = vigs_gl_pool_create("tmp_tex", &vigs_gl_backend_alloc_tmp_texture, &vigs_gl_backend_release_tmp_texture, gl_backend); gl_backend->fb_pool = vigs_gl_pool_create("fb", &vigs_gl_backend_alloc_framebuffer, &vigs_gl_backend_release_framebuffer, gl_backend); if (gl_backend->is_gl_2) { const char *tmp = (const char*)gl_backend->GetString(GL_EXTENSIONS); if (!tmp || (strstr(tmp, "GL_ARB_map_buffer_range ") == NULL)) { VIGS_LOG_WARN("glMapBufferRange not supported, using glBufferSubData"); } gl_backend->MapBufferRange = NULL; } else { gl_backend->GenVertexArrays(1, &gl_backend->vao); if (!gl_backend->vao) { VIGS_LOG_CRITICAL("cannot create VAO"); goto fail; } gl_backend->BindVertexArray(gl_backend->vao); } VIGS_LOG_INFO("Current GL_VENDOR = %s", (const char *)gl_backend->GetString(GL_VENDOR)); VIGS_LOG_INFO("Current GL_RENDERER = %s", (const char *)gl_backend->GetString(GL_RENDERER)); VIGS_LOG_INFO("Current GL_VERSION = %s", (const char *)gl_backend->GetString(GL_VERSION)); gl_backend->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->tex_prog_vs_id) { goto fail; } gl_backend->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->tex_prog_fs_id) { goto fail; } gl_backend->tex_prog_id = vigs_gl_create_program(gl_backend, gl_backend->tex_prog_vs_id, gl_backend->tex_prog_fs_id); if (!gl_backend->tex_prog_id) { goto fail; } gl_backend->tex_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->tex_prog_id, "proj"); gl_backend->tex_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->tex_prog_id, "vertCoord"); gl_backend->tex_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->tex_prog_id, "texCoord"); gl_backend->color_prog_vs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_vs_color_source_gl2 : g_vs_color_source_gl3), GL_VERTEX_SHADER); if (!gl_backend->color_prog_vs_id) { goto fail; } gl_backend->color_prog_fs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_fs_color_source_gl2 : g_fs_color_source_gl3), GL_FRAGMENT_SHADER); if (!gl_backend->color_prog_fs_id) { goto fail; } gl_backend->color_prog_id = vigs_gl_create_program(gl_backend, gl_backend->color_prog_vs_id, gl_backend->color_prog_fs_id); if (!gl_backend->color_prog_id) { goto fail; } gl_backend->color_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "proj"); gl_backend->color_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->color_prog_id, "vertCoord"); gl_backend->color_prog_color_loc = gl_backend->GetUniformLocation(gl_backend->color_prog_id, "color"); gl_backend->nv21_prog_vs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_vs_nv21_source_gl2 : g_vs_nv21_source_gl3), GL_VERTEX_SHADER); if (!gl_backend->nv21_prog_vs_id) { goto fail; } gl_backend->nv21_prog_fs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_fs_nv21_source_gl2 : g_fs_nv21_source_gl3), GL_FRAGMENT_SHADER); if (!gl_backend->nv21_prog_fs_id) { goto fail; } gl_backend->nv21_prog_id = vigs_gl_create_program(gl_backend, gl_backend->nv21_prog_vs_id, gl_backend->nv21_prog_fs_id); if (!gl_backend->nv21_prog_id) { goto fail; } gl_backend->nv21_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "proj"); gl_backend->nv21_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "vertCoord"); gl_backend->nv21_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->nv21_prog_id, "texCoord"); gl_backend->nv21_prog_size_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "size"); gl_backend->nv21_prog_ytexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytexSize"); gl_backend->nv21_prog_ctexSize_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctexSize"); gl_backend->nv21_prog_ytex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ytex"); gl_backend->nv21_prog_ctex_loc = gl_backend->GetUniformLocation(gl_backend->nv21_prog_id, "ctex"); gl_backend->yuv420_prog_vs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_vs_yuv420_source_gl2 : g_vs_yuv420_source_gl3), GL_VERTEX_SHADER); if (!gl_backend->yuv420_prog_vs_id) { goto fail; } gl_backend->yuv420_prog_fs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_fs_yuv420_source_gl2 : g_fs_yuv420_source_gl3), GL_FRAGMENT_SHADER); if (!gl_backend->yuv420_prog_fs_id) { goto fail; } gl_backend->yuv420_prog_id = vigs_gl_create_program(gl_backend, gl_backend->yuv420_prog_vs_id, gl_backend->yuv420_prog_fs_id); if (!gl_backend->yuv420_prog_id) { goto fail; } gl_backend->yuv420_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "proj"); gl_backend->yuv420_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->yuv420_prog_id, "vertCoord"); gl_backend->yuv420_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->yuv420_prog_id, "texCoord"); gl_backend->yuv420_prog_size_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "size"); gl_backend->yuv420_prog_ytexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "ytexSize"); gl_backend->yuv420_prog_utexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "utexSize"); gl_backend->yuv420_prog_vtexSize_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtexSize"); gl_backend->yuv420_prog_ytex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "ytex"); gl_backend->yuv420_prog_utex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "utex"); gl_backend->yuv420_prog_vtex_loc = gl_backend->GetUniformLocation(gl_backend->yuv420_prog_id, "vtex"); gl_backend->xbgr_prog_fs_id = vigs_gl_create_shader(gl_backend, (gl_backend->is_gl_2 ? g_fs_xbgr_source_gl2 : g_fs_xbgr_source_gl3), GL_FRAGMENT_SHADER); if (!gl_backend->xbgr_prog_fs_id) { goto fail; } /* * Let's borrow compiled vertex shader from tex program */ gl_backend->xbgr_prog_id = vigs_gl_create_program(gl_backend, gl_backend->tex_prog_vs_id, gl_backend->xbgr_prog_fs_id); if (!gl_backend->xbgr_prog_id) { goto fail; } gl_backend->xbgr_prog_proj_loc = gl_backend->GetUniformLocation(gl_backend->xbgr_prog_id, "proj"); gl_backend->xbgr_prog_vertCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "vertCoord"); gl_backend->xbgr_prog_texCoord_loc = gl_backend->GetAttribLocation(gl_backend->xbgr_prog_id, "texCoord"); gl_backend->GenBuffers(1, &gl_backend->vbo); if (!gl_backend->vbo) { VIGS_LOG_CRITICAL("cannot create VBOs"); goto fail; } gl_backend->BindBuffer(GL_ARRAY_BUFFER, gl_backend->vbo); gl_backend->UseProgram(gl_backend->nv21_prog_id); gl_backend->Uniform1i(gl_backend->nv21_prog_ytex_loc, 0); gl_backend->Uniform1i(gl_backend->nv21_prog_ctex_loc, 1); gl_backend->UseProgram(gl_backend->yuv420_prog_id); gl_backend->Uniform1i(gl_backend->yuv420_prog_ytex_loc, 0); gl_backend->Uniform1i(gl_backend->yuv420_prog_utex_loc, 1); gl_backend->Uniform1i(gl_backend->yuv420_prog_vtex_loc, 2); gl_backend->UseProgram(gl_backend->tex_prog_id); gl_backend->cur_prog_id = gl_backend->tex_prog_id; gl_backend->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl_backend->Disable(GL_DEPTH_TEST); gl_backend->Disable(GL_BLEND); gl_backend->base.batch_start = &vigs_gl_backend_batch_start; gl_backend->base.create_surface = &vigs_gl_backend_create_surface; gl_backend->base.composite = &vigs_gl_backend_composite; gl_backend->base.capture = &vigs_gl_backend_capture; gl_backend->base.batch_end = &vigs_gl_backend_batch_end; gl_backend->base.display = &vigs_gl_backend_display; gl_backend->make_current(gl_backend, false); vigs_vector_init(&gl_backend->v1, 0); vigs_vector_init(&gl_backend->v2, 0); int i; for (i = 0; i < TEXTURE_NUM; ++i) { gl_backend->dpy_items[i].available = true; qemu_mutex_init(&gl_backend->dpy_items[i].mutex); } return true; fail: gl_backend->make_current(gl_backend, false); return false; } void vigs_gl_backend_cleanup(struct vigs_gl_backend *gl_backend) { if (gl_backend->make_current(gl_backend, true)) { int i; for (i = 0; i < TEXTURE_NUM; i++) { if (gl_backend->dpy_items[i].tex) { gl_backend->DeleteTextures(1, &gl_backend->dpy_items[i].tex); } qemu_mutex_destroy(&gl_backend->dpy_items[i].mutex); } if (gl_backend->dpy_fb) { gl_backend->DeleteFramebuffers(1, &gl_backend->dpy_fb); } gl_backend->DeleteBuffers(1, &gl_backend->vbo); gl_backend->DetachShader(gl_backend->yuv420_prog_id, gl_backend->yuv420_prog_vs_id); gl_backend->DetachShader(gl_backend->yuv420_prog_id, gl_backend->yuv420_prog_fs_id); gl_backend->DeleteShader(gl_backend->yuv420_prog_vs_id); gl_backend->DeleteShader(gl_backend->yuv420_prog_fs_id); gl_backend->DeleteProgram(gl_backend->yuv420_prog_id); gl_backend->DetachShader(gl_backend->nv21_prog_id, gl_backend->nv21_prog_vs_id); gl_backend->DetachShader(gl_backend->nv21_prog_id, gl_backend->nv21_prog_fs_id); gl_backend->DeleteShader(gl_backend->nv21_prog_vs_id); gl_backend->DeleteShader(gl_backend->nv21_prog_fs_id); gl_backend->DeleteProgram(gl_backend->nv21_prog_id); gl_backend->DetachShader(gl_backend->color_prog_id, gl_backend->color_prog_vs_id); gl_backend->DetachShader(gl_backend->color_prog_id, gl_backend->color_prog_fs_id); gl_backend->DeleteShader(gl_backend->color_prog_vs_id); gl_backend->DeleteShader(gl_backend->color_prog_fs_id); gl_backend->DeleteProgram(gl_backend->color_prog_id); gl_backend->DetachShader(gl_backend->tex_prog_id, gl_backend->tex_prog_vs_id); gl_backend->DetachShader(gl_backend->tex_prog_id, gl_backend->tex_prog_fs_id); gl_backend->DeleteShader(gl_backend->tex_prog_vs_id); gl_backend->DeleteShader(gl_backend->tex_prog_fs_id); gl_backend->DeleteProgram(gl_backend->tex_prog_id); if (!gl_backend->is_gl_2) { gl_backend->DeleteVertexArrays(1, &gl_backend->vao); } vigs_gl_pool_destroy(gl_backend->fb_pool); vigs_gl_pool_destroy(gl_backend->tex_pool); gl_backend->make_current(gl_backend, false); } vigs_vector_cleanup(&gl_backend->v2); vigs_vector_cleanup(&gl_backend->v1); }