| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2022 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / OpenGL tools used by compositor filter, vout filter and WebGL bindings | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC 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 Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include <gpac/tools.h> | |
| #include <gpac/filters.h> | |
| #ifndef GPAC_DISABLE_3D | |
| #include "../compositor/gl_inc.h" | |
| #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__) | |
| # if defined(GPAC_USE_TINYGL) | |
| # pragma comment(lib, "TinyGL") | |
| # elif defined(GPAC_USE_GLES1X) | |
| # if 0 | |
| # pragma message("Using OpenGL-ES Common Lite Profile") | |
| # pragma comment(lib, "libGLES_CL") | |
| # define GL_ES_CL_PROFILE | |
| # else | |
| # pragma message("Using OpenGL-ES Common Profile") | |
| # pragma comment(lib, "libGLES_CM") | |
| # endif | |
| # elif defined(GPAC_USE_GLES2) | |
| # pragma comment(lib, "libGLESv2") | |
| # else | |
| # pragma comment(lib, "opengl32") | |
| # endif | |
| #ifdef GPAC_HAS_GLU | |
| # pragma comment(lib, "glu32") | |
| #endif | |
| #endif | |
| /*!! HORRIBLE HACK, but on my test devices, it seems that glClipPlanex is missing on the device but not in the SDK lib !!*/ | |
| #if defined(GL_MAX_CLIP_PLANES) && defined(__SYMBIAN32__) | |
| #undef GL_MAX_CLIP_PLANES | |
| #endif | |
| #ifdef LOAD_GL_1_3 | |
| GLDECL_FUNC(glActiveTexture); | |
| GLDECL_FUNC(glClientActiveTexture); | |
| GLDECL_FUNC(glBlendEquation); | |
| #endif //LOAD_GL_1_3 | |
| #ifdef LOAD_GL_1_4 | |
| GLDECL_FUNC(glPointParameterf); | |
| GLDECL_FUNC(glPointParameterfv); | |
| #endif //LOAD_GL_1_4 | |
| #ifdef LOAD_GL_1_5 | |
| GLDECL_FUNC(glGenBuffers); | |
| GLDECL_FUNC(glDeleteBuffers); | |
| GLDECL_FUNC(glBindBuffer); | |
| GLDECL_FUNC(glBufferData); | |
| GLDECL_FUNC(glBufferSubData); | |
| GLDECL_FUNC(glMapBuffer); | |
| GLDECL_FUNC(glUnmapBuffer); | |
| #endif //LOAD_GL_1_5 | |
| #ifdef LOAD_GL_2_0 | |
| GLDECL_FUNC(glCreateProgram); | |
| GLDECL_FUNC(glDeleteProgram); | |
| GLDECL_FUNC(glLinkProgram); | |
| GLDECL_FUNC(glUseProgram); | |
| GLDECL_FUNC(glCreateShader); | |
| GLDECL_FUNC(glDeleteShader); | |
| GLDECL_FUNC(glShaderSource); | |
| GLDECL_FUNC(glCompileShader); | |
| GLDECL_FUNC(glAttachShader); | |
| GLDECL_FUNC(glDetachShader); | |
| GLDECL_FUNC(glGetShaderiv); | |
| GLDECL_FUNC(glGetInfoLogARB); | |
| GLDECL_FUNC(glGetUniformLocation); | |
| GLDECL_FUNC(glGetUniformfv); | |
| GLDECL_FUNC(glGetUniformiv); | |
| GLDECL_FUNC(glUniform1f); | |
| GLDECL_FUNC(glUniform2f); | |
| GLDECL_FUNC(glUniform3f); | |
| GLDECL_FUNC(glUniform4f); | |
| GLDECL_FUNC(glUniform1i); | |
| GLDECL_FUNC(glUniform2i); | |
| GLDECL_FUNC(glUniform3i); | |
| GLDECL_FUNC(glUniform4i); | |
| GLDECL_FUNC(glUniform1fv); | |
| GLDECL_FUNC(glUniform2fv); | |
| GLDECL_FUNC(glUniform3fv); | |
| GLDECL_FUNC(glUniform4fv); | |
| GLDECL_FUNC(glUniform1iv); | |
| GLDECL_FUNC(glUniform2iv); | |
| GLDECL_FUNC(glUniform3iv); | |
| GLDECL_FUNC(glUniform4iv); | |
| GLDECL_FUNC(glUniformMatrix2fv); | |
| GLDECL_FUNC(glUniformMatrix3fv); | |
| GLDECL_FUNC(glUniformMatrix4fv); | |
| GLDECL_FUNC(glUniformMatrix2x3fv); | |
| GLDECL_FUNC(glUniformMatrix3x2fv); | |
| GLDECL_FUNC(glUniformMatrix2x4fv); | |
| GLDECL_FUNC(glUniformMatrix4x2fv); | |
| GLDECL_FUNC(glUniformMatrix3x4fv); | |
| GLDECL_FUNC(glUniformMatrix4x3fv); | |
| GLDECL_FUNC(glGetProgramiv); | |
| GLDECL_FUNC(glGetProgramInfoLog); | |
| GLDECL_FUNC(glGetAttribLocation); | |
| GLDECL_FUNC(glBindFramebuffer); | |
| GLDECL_FUNC(glFramebufferTexture2D); | |
| GLDECL_FUNC(glGenFramebuffers); | |
| GLDECL_FUNC(glGenRenderbuffers); | |
| GLDECL_FUNC(glBindRenderbuffer); | |
| GLDECL_FUNC(glRenderbufferStorage); | |
| GLDECL_FUNC(glFramebufferRenderbuffer); | |
| GLDECL_FUNC(glDeleteFramebuffers); | |
| GLDECL_FUNC(glDeleteRenderbuffers); | |
| GLDECL_FUNC(glCheckFramebufferStatus); | |
| GLDECL_FUNC(glBlendColor); | |
| GLDECL_FUNC(glBlendEquationSeparate); | |
| GLDECL_FUNC(glBlendFuncSeparate); | |
| GLDECL_FUNC(glCompressedTexImage2D); | |
| GLDECL_FUNC(glCompressedTexSubImage2D); | |
| GLDECL_FUNC(glGenerateMipmap); | |
| GLDECL_FUNC(glGetShaderInfoLog); | |
| GLDECL_FUNC(glGetShaderSource); | |
| GLDECL_FUNC(glGetActiveAttrib); | |
| GLDECL_FUNC(glGetActiveUniform); | |
| GLDECL_FUNC(glGetAttachedShaders); | |
| GLDECL_FUNC(glBindAttribLocation); | |
| GLDECL_FUNC(glIsBuffer); | |
| GLDECL_FUNC(glIsFramebuffer); | |
| GLDECL_FUNC(glIsProgram); | |
| GLDECL_FUNC(glIsRenderbuffer); | |
| GLDECL_FUNC(glIsShader); | |
| GLDECL_FUNC(glSampleCoverage); | |
| GLDECL_FUNC(glStencilFuncSeparate); | |
| GLDECL_FUNC(glStencilOpSeparate); | |
| GLDECL_FUNC(glStencilMaskSeparate); | |
| GLDECL_FUNC(glValidateProgram); | |
| GLDECL_FUNC(glVertexAttrib1fv); | |
| GLDECL_FUNC(glVertexAttrib1f); | |
| GLDECL_FUNC(glVertexAttrib2f); | |
| GLDECL_FUNC(glVertexAttrib2fv); | |
| GLDECL_FUNC(glVertexAttrib3f); | |
| GLDECL_FUNC(glVertexAttrib3fv); | |
| GLDECL_FUNC(glVertexAttrib4f); | |
| GLDECL_FUNC(glVertexAttrib4fv); | |
| GLDECL_FUNC(glGetBufferParameteriv); | |
| GLDECL_FUNC(glGetFramebufferAttachmentParameteriv); | |
| GLDECL_FUNC(glGetVertexAttribiv); | |
| GLDECL_FUNC(glGetVertexAttribfv); | |
| GLDECL_FUNC(glGetVertexAttribPointerv); | |
| GLDECL_FUNC(glGetRenderbufferParameteriv); | |
| #ifndef GPAC_CONFIG_ANDROID | |
| GLDECL_FUNC(glEnableVertexAttribArray); | |
| GLDECL_FUNC(glDisableVertexAttribArray); | |
| GLDECL_FUNC(glVertexAttribPointer); | |
| GLDECL_FUNC(glVertexAttribIPointer); | |
| #endif | |
| #endif //LOAD_GL_2_0 | |
| static Bool gl_fun_loaded = GF_FALSE; | |
| void gf_opengl_init() | |
| { | |
| if (gl_fun_loaded) return; | |
| gl_fun_loaded = GF_TRUE; | |
| #ifndef GPAC_USE_TINYGL | |
| #ifdef LOAD_GL_1_3 | |
| GET_GLFUN(glActiveTexture); | |
| GET_GLFUN(glClientActiveTexture); | |
| GET_GLFUN(glBlendEquation); | |
| #endif | |
| #ifdef LOAD_GL_1_4 | |
| GET_GLFUN(glPointParameterf); | |
| GET_GLFUN(glPointParameterfv); | |
| #endif | |
| #ifdef LOAD_GL_1_5 | |
| GET_GLFUN(glGenBuffers); | |
| GET_GLFUN(glDeleteBuffers); | |
| GET_GLFUN(glBindBuffer); | |
| GET_GLFUN(glBufferData); | |
| GET_GLFUN(glBufferSubData); | |
| GET_GLFUN(glMapBuffer); | |
| GET_GLFUN(glUnmapBuffer); | |
| #endif | |
| #ifdef LOAD_GL_2_0 | |
| GET_GLFUN(glCreateProgram); | |
| GET_GLFUN(glDeleteProgram); | |
| GET_GLFUN(glLinkProgram); | |
| GET_GLFUN(glUseProgram); | |
| GET_GLFUN(glCreateShader); | |
| GET_GLFUN(glDeleteShader); | |
| GET_GLFUN(glShaderSource); | |
| GET_GLFUN(glCompileShader); | |
| GET_GLFUN(glAttachShader); | |
| GET_GLFUN(glDetachShader); | |
| GET_GLFUN(glGetShaderiv); | |
| GET_GLFUN(glGetInfoLogARB); | |
| GET_GLFUN(glGetUniformLocation); | |
| GET_GLFUN(glGetUniformfv); | |
| GET_GLFUN(glGetUniformiv); | |
| GET_GLFUN(glUniform1f); | |
| GET_GLFUN(glUniform2f); | |
| GET_GLFUN(glUniform3f); | |
| GET_GLFUN(glUniform4f); | |
| GET_GLFUN(glUniform1i); | |
| GET_GLFUN(glUniform2i); | |
| GET_GLFUN(glUniform3i); | |
| GET_GLFUN(glUniform4i); | |
| GET_GLFUN(glUniform1fv); | |
| GET_GLFUN(glUniform2fv); | |
| GET_GLFUN(glUniform3fv); | |
| GET_GLFUN(glUniform4fv); | |
| GET_GLFUN(glUniform1iv); | |
| GET_GLFUN(glUniform2iv); | |
| GET_GLFUN(glUniform3iv); | |
| GET_GLFUN(glUniform4iv); | |
| GET_GLFUN(glUniformMatrix2fv); | |
| GET_GLFUN(glUniformMatrix3fv); | |
| GET_GLFUN(glUniformMatrix4fv); | |
| GET_GLFUN(glUniformMatrix2x3fv); | |
| GET_GLFUN(glUniformMatrix3x2fv); | |
| GET_GLFUN(glUniformMatrix2x4fv); | |
| GET_GLFUN(glUniformMatrix4x2fv); | |
| GET_GLFUN(glUniformMatrix3x4fv); | |
| GET_GLFUN(glUniformMatrix4x3fv); | |
| GET_GLFUN(glGetProgramiv); | |
| GET_GLFUN(glGetProgramInfoLog); | |
| GET_GLFUN(glBlendColor); | |
| GET_GLFUN(glBlendEquationSeparate); | |
| GET_GLFUN(glBlendFuncSeparate); | |
| GET_GLFUN(glCompressedTexImage2D); | |
| GET_GLFUN(glCompressedTexSubImage2D); | |
| GET_GLFUN(glGenerateMipmap); | |
| GET_GLFUN(glGetShaderInfoLog); | |
| GET_GLFUN(glGetShaderSource); | |
| GET_GLFUN(glGetActiveAttrib); | |
| GET_GLFUN(glGetActiveUniform); | |
| GET_GLFUN(glGetAttachedShaders); | |
| GET_GLFUN(glBindAttribLocation); | |
| GET_GLFUN(glIsBuffer); | |
| GET_GLFUN(glIsFramebuffer); | |
| GET_GLFUN(glIsProgram); | |
| GET_GLFUN(glIsRenderbuffer); | |
| GET_GLFUN(glIsShader); | |
| GET_GLFUN(glSampleCoverage); | |
| GET_GLFUN(glStencilFuncSeparate); | |
| GET_GLFUN(glStencilOpSeparate); | |
| GET_GLFUN(glStencilMaskSeparate); | |
| GET_GLFUN(glValidateProgram); | |
| GET_GLFUN(glVertexAttrib1fv); | |
| GET_GLFUN(glVertexAttrib1f); | |
| GET_GLFUN(glVertexAttrib2f); | |
| GET_GLFUN(glVertexAttrib2fv); | |
| GET_GLFUN(glVertexAttrib3f); | |
| GET_GLFUN(glVertexAttrib3fv); | |
| GET_GLFUN(glVertexAttrib4f); | |
| GET_GLFUN(glVertexAttrib4fv); | |
| GET_GLFUN(glGetBufferParameteriv); | |
| GET_GLFUN(glGetFramebufferAttachmentParameteriv); | |
| GET_GLFUN(glGetVertexAttribiv); | |
| GET_GLFUN(glGetVertexAttribfv); | |
| GET_GLFUN(glGetVertexAttribPointerv); | |
| GET_GLFUN(glGetRenderbufferParameteriv); | |
| #ifndef GPAC_CONFIG_ANDROID | |
| GET_GLFUN(glEnableVertexAttribArray); | |
| GET_GLFUN(glDisableVertexAttribArray); | |
| GET_GLFUN(glVertexAttribPointer); | |
| GET_GLFUN(glVertexAttribIPointer); | |
| GET_GLFUN(glGetAttribLocation); | |
| GET_GLFUN(glBindFramebuffer); | |
| GET_GLFUN(glFramebufferTexture2D); | |
| GET_GLFUN(glGenFramebuffers); | |
| GET_GLFUN(glGenRenderbuffers); | |
| GET_GLFUN(glBindRenderbuffer); | |
| GET_GLFUN(glRenderbufferStorage); | |
| GET_GLFUN(glFramebufferRenderbuffer); | |
| GET_GLFUN(glDeleteFramebuffers); | |
| GET_GLFUN(glDeleteRenderbuffers); | |
| GET_GLFUN(glCheckFramebufferStatus); | |
| #endif | |
| #endif //LOAD_GL_2_0 | |
| #endif //GPAC_USE_TINYGL | |
| } | |
| static char *gl_shader_yuv_matrix = \ | |
| "uniform mat4 _gf_%s_mx;\n\ | |
| "; | |
| #if 0 //old code | |
| static char *gl_shader_yuv_coefs = \ | |
| "const vec3 offset = vec3(-0.0625, -0.5, -0.5);\n\ | |
| const vec3 R_mul = vec3(1.164, 0.000, 1.596);\n\ | |
| const vec3 G_mul = vec3(1.164, -0.391, -0.813);\n\ | |
| const vec3 B_mul = vec3(1.164, 2.018, 0.000);\n\ | |
| "; | |
| static char *gl_shader_yuv_coefs_jpeg = \ | |
| "const vec3 offset = vec3(0.0, -0.5, -0.5);\n\ | |
| const vec3 R_mul = vec3(1, 0.000, 1.40200);\n\ | |
| const vec3 G_mul = vec3(1, -0.34414, -0.71414);\n\ | |
| const vec3 B_mul = vec3(1, 1.77200, 0.000);\n\ | |
| "; | |
| #endif | |
| static char *gl_shader_vars_yuv = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| uniform sampler2D _gf_%s_2;\n\ | |
| uniform sampler2D _gf_%s_3;\n\ | |
| "; | |
| #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2) | |
| static char *gl_shader_fun_yuv_gles10 = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv, col;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| col = texture2D(_gf_%s_1, texc);\n\ | |
| yuv.x = (col.a*65280.0 + col.r*255.0)/1023.0;\n\ | |
| col = texture2D(_gf_%s_2, texc);\n\ | |
| yuv.y = (col.a*65280.0 + col.r*255.0)/1023.0;\n\ | |
| col = texture2D(_gf_%s_3, texc);\n\ | |
| yuv.z = (col.a*65280.0 + col.r*255.0)/1023.0;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| #endif | |
| static char *gl_shader_fun_yuv = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.x = texture2D(_gf_%s_1, texc).r;\n\ | |
| yuv.y = texture2D(_gf_%s_2, texc).r;\n\ | |
| yuv.z = texture2D(_gf_%s_3, texc).r;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_yvu = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.x = texture2D(_gf_%s_1, texc).r;\n\ | |
| yuv.y = texture2D(_gf_%s_3, texc).r;\n\ | |
| yuv.z = texture2D(_gf_%s_2, texc).r;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_yuva = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| uniform sampler2D _gf_%s_2;\n\ | |
| uniform sampler2D _gf_%s_3;\n\ | |
| uniform sampler2D _gf_%s_4;\n\ | |
| "; | |
| static char *gl_shader_fun_yuva = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.x = texture2D(_gf_%s_1, texc).r;\n\ | |
| yuv.y = texture2D(_gf_%s_2, texc).r;\n\ | |
| yuv.z = texture2D(_gf_%s_3, texc).r;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = texture2D(_gf_%s_4, texc).r;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_nv12 = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| uniform sampler2D _gf_%s_2;\n\ | |
| "; | |
| static char *gl_shader_fun_nv12 = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.x = texture2D(_gf_%s_1, texc).r;\n\ | |
| yuv.yz = texture2D(_gf_%s_2, texc).ra;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_nv21 = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| uniform sampler2D _gf_%s_2;\n\ | |
| "; | |
| static char *gl_shader_fun_nv21 = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.x = texture2D(_gf_%s_1, texc).r;\n\ | |
| yuv.yz = texture2D(_gf_%s_2, texc).ar;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_uyvu = \ | |
| "uniform sampler2D _gf_%s_1;\ | |
| uniform float _gf_%s_width;\ | |
| "; | |
| static char *gl_shader_fun_uyvy = \ | |
| "vec2 texc, t_texc;\ | |
| vec4 yuv;\ | |
| vec4 uyvy;\ | |
| float tex_s;\ | |
| texc = _gpacTexCoord.st;\ | |
| t_texc = texc * vec2(1, 1);\ | |
| uyvy = texture2D(_gf_%s_1, t_texc); \ | |
| tex_s = texc.x*_gf_%s_width;\ | |
| if (tex_s - (2.0 * floor(tex_s/2.0)) == 1.0) {\ | |
| uyvy.g = uyvy.a; \ | |
| }\ | |
| yuv.r = uyvy.g;\ | |
| yuv.g = uyvy.r;\ | |
| yuv.b = uyvy.b;\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_vyuy = \ | |
| "vec2 texc, t_texc;\ | |
| vec4 yuv;\ | |
| vec4 vyuy;\ | |
| float tex_s;\ | |
| texc = _gpacTexCoord.st;\ | |
| t_texc = texc * vec2(1, 1);\ | |
| vyuy = texture2D(_gf_%s_1, t_texc); \ | |
| tex_s = texc.x*_gf_%s_width;\ | |
| if (tex_s - (2.0 * floor(tex_s/2.0)) == 1.0) {\ | |
| vyuy.g = vyuy.a; \ | |
| }\ | |
| yuv.r = vyuy.g;\ | |
| yuv.g = vyuy.b;\ | |
| yuv.b = vyuy.r;\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_yuyv = \ | |
| "vec2 texc, t_texc;\ | |
| vec4 yuv;\ | |
| vec4 yvyu;\ | |
| float tex_s;\ | |
| texc = _gpacTexCoord.st;\ | |
| t_texc = texc * vec2(1, 1);\ | |
| yvyu = texture2D(_gf_%s_1, t_texc); \ | |
| tex_s = texc.x*_gf_%s_width;\ | |
| if (tex_s - (2.0 * floor(tex_s/2.0)) == 1.0) {\ | |
| yvyu.r = yvyu.b; \ | |
| }\ | |
| yuv.r = yvyu.r;\ | |
| yuv.g = yvyu.g;\ | |
| yuv.b = yvyu.a;\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_yvyu = \ | |
| "vec2 texc, t_texc;\ | |
| vec4 yuv;\ | |
| vec4 yuyv;\ | |
| float tex_s;\ | |
| texc = _gpacTexCoord.st;\ | |
| t_texc = texc * vec2(1, 1);\ | |
| yuyv = texture2D(_gf_%s_1, t_texc); \ | |
| tex_s = texc.x*_gf_%s_width;\ | |
| if (tex_s - (2.0 * floor(tex_s/2.0)) == 1.0) {\ | |
| yuyv.r = yuyv.b; \ | |
| }\ | |
| yuv.r = yuyv.r;\ | |
| yuv.g = yuyv.a;\ | |
| yuv.b = yuyv.g;\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_yuv4_pack = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| "; | |
| static char *gl_shader_fun_yuv4_pack = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv = texture2D(_gf_%s_1, texc);\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_vyu4_pack = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| yuv.rgb = texture2D(_gf_%s_1, texc).gbr;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_yuv4a_pack = \ | |
| "vec2 texc;\n\ | |
| vec4 tex;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| tex = texture2D(_gf_%s_1, texc);\n\ | |
| yuv.rgb = tex.rgb;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = tex.a;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_fun_uyv4a_pack = \ | |
| "vec2 texc;\n\ | |
| vec4 tex;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| tex = texture2D(_gf_%s_1, texc);\n\ | |
| yuv.rgb = tex.grb;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = tex.a;\n\ | |
| return yuv;\n\ | |
| "; | |
| //uploaded as RGBA describing 10 bit V + 10 bit Y + 10 bit U + 2 bits lost, lost bits in R (first byte) | |
| //V: 8 bit A + 2 bits B | |
| //Y: 6 bit B + 4 bits G | |
| //U: 4 bit G + 6 bits R | |
| // | |
| //we do the maths for bit reading, we should add support for GLES3 shift operators as well (but no support in WebGL1) | |
| static char *gl_shader_fun_yuv4_10_pack = \ | |
| "vec2 texc;\n\ | |
| vec4 val;\n\ | |
| int valr, valg, valb, vala, interm1, interm2;\n\ | |
| vec4 yuv;\n\ | |
| texc = _gpacTexCoord.st;\n\ | |
| val = texture2D(_gf_%s_1, texc).rgba;\n\ | |
| vala = int(val.a*255.0);\n\ | |
| valb = int(val.b*255.0);\n\ | |
| valg = int(val.g*255.0);\n\ | |
| valr = int(val.r*255.0 / 64.0);\n\ | |
| interm1 = valb / 64;\n\ | |
| yuv.b = float( (vala * 4) + (interm1) ) / 1023.0;\n\ | |
| interm1 *= 64;\n\ | |
| interm2 = valg / 16;\n\ | |
| yuv.r = float( ((valb - interm1) * 16) + (interm2) ) / 1023.0;\n\ | |
| interm2 *= 16;\n\ | |
| yuv.g = float( ((valg - interm2) * 64) + valr ) / 1023.0;\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_v210 = \ | |
| "uniform sampler2D _gf_%s_1;\ | |
| uniform float _gf_%s_width;\ | |
| uniform float _gf_%s_gpu_width;\ | |
| "; | |
| //uploaded as RGBA describing 2 bits lost (in A, last byte) + 3 * 10 bit {U,Y,V} , pattern repeating 6 times | |
| //first pattern (x%6==0) is {00b, Cr, Y, Cb} in {A, B, G, R} bytes | |
| //we decompose RGBA pixel x and x+1 as follows | |
| //.R: 8 bit R + 2 bits G | |
| //.G: 6 bit G + 4 bits B | |
| //.B: 4 bit G + 6 bits A | |
| // | |
| //s coordinate is remapped to line pos x in source width pixels | |
| //the GPU sees the texture as a {stride/4, height} texture | |
| //so when we fetch from sampler2D we need to convert 6 pixels v210 to 4 pixels RGBA for x | |
| //but the next pixel we need is 1/gpu_width after x | |
| // | |
| //we do the maths for bit reading, we should add support for GLES3 shift operators as well (but no support in WebGL1) | |
| static char *gl_shader_fun_v210 = \ | |
| "vec2 texc;\n\ | |
| vec4 yuv, yuv1, yuv2, val;\n\ | |
| int x, off_x, dec_x, valr, valg, valb, vala, interm1, interm2;\n\ | |
| float tx_width = _gf_%s_width;\n\ | |
| float tx_gpu_width = _gf_%s_gpu_width;\n\ | |
| x = int(_gpacTexCoord.s * tx_width);\n\ | |
| interm1 = x/6;\n\ | |
| off_x = x - (interm1 * 6);\n\ | |
| x-=off_x;\n\ | |
| if (off_x>=4) dec_x = 2;\n\ | |
| else if (off_x>=2) dec_x = 1;\n\ | |
| else dec_x = 0;\n\ | |
| texc.t = _gpacTexCoord.t;\n\ | |
| texc.s = float(x * 4 / 6 + dec_x) / tx_gpu_width;\n\ | |
| val = texture2D(_gf_%s_1, texc);\n\ | |
| vala = int(val.a*255.0);\n\ | |
| valb = int(val.b*255.0);\n\ | |
| valg = int(val.g*255.0);\n\ | |
| valr = int(val.r*255.0);\n\ | |
| vala = vala - ((vala/64) * 64);\n\ | |
| interm1 = valg / 4;\n\ | |
| yuv1.r = float( valr + (valg - interm1*4)*256 ) / 1023.0;\n\ | |
| interm2 = valb / 16;\n\ | |
| yuv1.g = float( (valb - interm2*16) * 64 + interm1 ) / 1023.0;\n\ | |
| yuv1.b = float( interm2 + vala*16 ) / 1023.0;\n\ | |
| if (off_x==0) {\n\ | |
| yuv.g = yuv1.r;\n\ | |
| yuv.r = yuv1.g;\n\ | |
| yuv.b = yuv1.b;\n\ | |
| } else {\n\ | |
| texc.s = float(x * 4 / 6 + dec_x + 1) / tx_gpu_width;\n\ | |
| val = texture2D(_gf_%s_1, texc);\n\ | |
| vala = int(val.a*255.0);\n\ | |
| valb = int(val.b*255.0);\n\ | |
| valg = int(val.g*255.0);\n\ | |
| valr = int(val.r*255.0);\n\ | |
| vala = vala - ((vala/64) * 64);\n\ | |
| interm1 = valg / 4;\n\ | |
| yuv2.r = float( valr + (valg - interm1*4)*256 ) / 1023.0;\n\ | |
| interm2 = valb / 16;\n\ | |
| yuv2.g = float( (valb - interm2*16) * 64 + interm1 ) / 1023.0;\n\ | |
| yuv2.b = float( interm2 + vala*16 ) / 1023.0;\n\ | |
| if (off_x==1) {\n\ | |
| yuv.g = yuv1.r;\n\ | |
| yuv.r = yuv2.r;\n\ | |
| yuv.b = yuv1.b;\n\ | |
| } else if (off_x==2) {\n\ | |
| yuv.g = yuv1.g;\n\ | |
| yuv.r = yuv1.b;\n\ | |
| yuv.b = yuv2.r;\n\ | |
| } else if (off_x==3) {\n\ | |
| yuv.g = yuv1.g;\n\ | |
| yuv.r = yuv2.g;\n\ | |
| yuv.b = yuv2.r;\n\ | |
| } else if (off_x==4) {\n\ | |
| yuv.g = yuv1.b;\n\ | |
| yuv.r = yuv2.r;\n\ | |
| yuv.b = yuv2.g;\n\ | |
| } else {\n\ | |
| yuv.g = yuv1.b;\n\ | |
| yuv.r = yuv2.b;\n\ | |
| yuv.b = yuv2.g;\n\ | |
| }\n\ | |
| }\n\ | |
| yuv.w = 1.0;\n\ | |
| yuv = _gf_%s_mx * yuv;\n\ | |
| yuv.w = 1.0;\n\ | |
| return yuv;\n\ | |
| "; | |
| static char *gl_shader_vars_rgb = \ | |
| "uniform sampler2D _gf_%s_1;\n\ | |
| "; | |
| static char *gl_shader_fun_alphagrey = \ | |
| "vec4 col, ocol;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| ocol.r = ocol.g = ocol.b = col.a;\n\ | |
| ocol.a = col.r;\n\ | |
| return ocol;\n\ | |
| "; | |
| static char *gl_shader_fun_rgb332 = \ | |
| "vec4 col, ocol;\n\ | |
| float res, col_r, col_g, col_b;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| res = floor( 255.0 * col.r );\n\ | |
| col_r = floor(res / 32.0);\n\ | |
| col_g = floor((res - col_r*32.0)/4.0);\n\ | |
| col_b = floor(res - col_r*128.0 - col_g*4.0);\n\ | |
| ocol.r = col_r / 7.0;\n\ | |
| ocol.g = col_g / 7.0;\n\ | |
| ocol.b = col_b / 3.0;\n\ | |
| ocol.a = 1.0;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_rgb444 = \ | |
| "vec4 col, ocol;\n\ | |
| float res, col_g, col_b;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| res = floor( 255.0 * col.a );\n\ | |
| col_g = floor(res / 16.0);\n\ | |
| col_b = floor(res - col_g*16.0);\n\ | |
| ocol.r = col.r * 17.0;\n\ | |
| ocol.g = col_g / 15.0;\n\ | |
| ocol.b = col_b / 15.0;\n\ | |
| ocol.a = 1.0;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_rgb555 = \ | |
| "vec4 col, ocol;\n\ | |
| float res, col_r, col_g1, col_g, col_b;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| res = floor(255.0 * col.r);\n\ | |
| col_r = floor(res / 4.0);\n\ | |
| col_g1 = floor(res - col_r*4.0);\n\ | |
| res = floor(255.0 * col.a);\n\ | |
| col_g = floor(res / 32);\n\ | |
| col_b = floor(res - col_g*32.0);\n\ | |
| col_g += col_g1 * 8;\n\ | |
| ocol.r = col_r / 31.0;\n\ | |
| ocol.g = col_g / 31.0;\n\ | |
| ocol.b = col_b / 31.0;\n\ | |
| ocol.a = 1.0;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_rgb565 = \ | |
| "vec4 col, ocol;\n\ | |
| float res, col_r, col_g1, col_g, col_b;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| res = floor(255.0 * col.r);\n\ | |
| col_r = floor(res / 8.0);\n\ | |
| col_g1 = floor(res - col_r*8.0);\n\ | |
| res = floor(255.0 * col.a);\n\ | |
| col_g = floor(res / 32);\n\ | |
| col_b = floor(res - col_g*32.0);\n\ | |
| col_g += col_g1 * 8;\n\ | |
| ocol.r = col_r / 31.0;\n\ | |
| ocol.g = col_g / 63.0;\n\ | |
| ocol.b = col_b / 31.0;\n\ | |
| ocol.a = 1.0;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_argb = \ | |
| "vec4 col, ocol;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| ocol.r = col.g;\n\ | |
| ocol.g = col.b;\n\ | |
| ocol.b = col.a;\n\ | |
| ocol.a = col.r;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_abgr = \ | |
| "vec4 col, ocol;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| ocol.r = col.a;\n\ | |
| ocol.g = col.b;\n\ | |
| ocol.b = col.g;\n\ | |
| ocol.a = col.r;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_bgra = \ | |
| "vec4 col, ocol;\n\ | |
| col = texture2D(_gf_%s_1, _gpacTexCoord.st);\n\ | |
| ocol.r = col.b;\n\ | |
| ocol.g = col.g;\n\ | |
| ocol.b = col.r;\n\ | |
| ocol.a = col.a;\n\ | |
| return ocol;\ | |
| "; | |
| static char *gl_shader_fun_rgb = \ | |
| "return texture2D(_gf_%s_1, _gpacTexCoord.st);\ | |
| "; | |
| static char *gl_shader_vars_externalOES = \ | |
| "uniform samplerExternalOES _gf_%s_1;\n\ | |
| "; | |
| Bool gf_gl_txw_insert_fragment_shader(u32 pix_fmt, const char *tx_name, char **f_source, Bool y_flip) | |
| { | |
| char szCode[4000]; | |
| const char *shader_vars = NULL; | |
| const char *shader_fun = NULL; | |
| switch (pix_fmt) { | |
| case GF_PIXEL_NV21: | |
| case GF_PIXEL_NV21_10: | |
| shader_vars = gl_shader_vars_nv21; | |
| shader_fun = gl_shader_fun_nv21; | |
| break; | |
| case GF_PIXEL_NV12: | |
| case GF_PIXEL_NV12_10: | |
| shader_vars = gl_shader_vars_nv12; | |
| shader_fun = gl_shader_fun_nv12; | |
| break; | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_UYVY_10: | |
| shader_vars = gl_shader_vars_uyvu; | |
| shader_fun = gl_shader_fun_uyvy; | |
| break; | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_YUYV_10: | |
| shader_vars = gl_shader_vars_uyvu; //same as uyvy | |
| shader_fun = gl_shader_fun_yuyv; | |
| break; | |
| case GF_PIXEL_VYUY: | |
| case GF_PIXEL_VYUY_10: | |
| shader_vars = gl_shader_vars_uyvu; //same as uyvy | |
| shader_fun = gl_shader_fun_vyuy; | |
| break; | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_YVYU_10: | |
| shader_vars = gl_shader_vars_uyvu; //same as uyvy | |
| shader_fun = gl_shader_fun_yvyu; | |
| break; | |
| case GF_PIXEL_YUV444_PACK: | |
| shader_vars = gl_shader_vars_yuv4_pack; | |
| shader_fun = gl_shader_fun_yuv4_pack; | |
| break; | |
| case GF_PIXEL_VYU444_PACK: | |
| shader_vars = gl_shader_vars_yuv4_pack; | |
| shader_fun = gl_shader_fun_vyu4_pack; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| shader_vars = gl_shader_vars_yuv4_pack; | |
| shader_fun = gl_shader_fun_yuv4a_pack; | |
| break; | |
| case GF_PIXEL_UYVA444_PACK: | |
| shader_vars = gl_shader_vars_yuv4_pack; | |
| shader_fun = gl_shader_fun_uyv4a_pack; | |
| break; | |
| case GF_PIXEL_YUV444_10_PACK: | |
| shader_vars = gl_shader_vars_yuv4_pack; | |
| shader_fun = gl_shader_fun_yuv4_10_pack; | |
| break; | |
| case GF_PIXEL_V210: | |
| shader_vars = gl_shader_vars_v210; | |
| shader_fun = gl_shader_fun_v210; | |
| break; | |
| case GF_PIXEL_ALPHAGREY: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_alphagrey; | |
| break; | |
| case GF_PIXEL_RGB_332: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_rgb332; | |
| break; | |
| case GF_PIXEL_RGB_444: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_rgb444; | |
| break; | |
| case GF_PIXEL_RGB_555: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_rgb555; | |
| break; | |
| case GF_PIXEL_RGB_565: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_rgb565; | |
| break; | |
| case GF_PIXEL_ARGB: | |
| case GF_PIXEL_XRGB: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_argb; | |
| break; | |
| case GF_PIXEL_ABGR: | |
| case GF_PIXEL_XBGR: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_abgr; | |
| break; | |
| case GF_PIXEL_BGR: | |
| case GF_PIXEL_BGRA: | |
| case GF_PIXEL_BGRX: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_bgra; | |
| break; | |
| case GF_PIXEL_YUV_10: | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV444_10: | |
| #if defined(GPAC_USE_GLES1X) || defined(GPAC_USE_GLES2) | |
| shader_vars = gl_shader_vars_yuv; | |
| shader_fun = gl_shader_fun_yuv_gles10; | |
| break; | |
| #endif | |
| case GF_PIXEL_YUVD: | |
| case GF_PIXEL_YUV422: | |
| case GF_PIXEL_YUV444: | |
| case GF_PIXEL_YUV: | |
| shader_vars = gl_shader_vars_yuv; | |
| shader_fun = gl_shader_fun_yuv; | |
| break; | |
| case GF_PIXEL_YVU: | |
| shader_vars = gl_shader_vars_yuv; | |
| shader_fun = gl_shader_fun_yvu; | |
| break; | |
| case GF_PIXEL_YUVA: | |
| case GF_PIXEL_YUVA444: | |
| shader_vars = gl_shader_vars_yuva; | |
| shader_fun = gl_shader_fun_yuva; | |
| break; | |
| case GF_PIXEL_GL_EXTERNAL: | |
| shader_vars = gl_shader_vars_externalOES; | |
| shader_fun = gl_shader_fun_rgb; | |
| break; | |
| default: | |
| shader_vars = gl_shader_vars_rgb; | |
| shader_fun = gl_shader_fun_rgb; | |
| break; | |
| } | |
| if (!shader_vars || !shader_fun) return GF_FALSE; | |
| /*format with max 4 tx_name (for yuva)*/ | |
| sprintf(szCode, shader_vars, tx_name, tx_name, tx_name, tx_name); | |
| gf_dynstrcat(f_source, szCode, NULL); | |
| if (gf_pixel_fmt_is_yuv(pix_fmt)) { | |
| // gf_dynstrcat(f_source, gl_shader_yuv_matrix, NULL); | |
| sprintf(szCode, gl_shader_yuv_matrix, tx_name); | |
| gf_dynstrcat(f_source, szCode, NULL); | |
| } | |
| gf_dynstrcat(f_source, "\nvec4 ", NULL); | |
| gf_dynstrcat(f_source, tx_name, NULL); | |
| gf_dynstrcat(f_source, "_sample(vec2 _gpacTexCoord) {\n", NULL); | |
| if (y_flip) { | |
| gf_dynstrcat(f_source, "_gpacTexCoord.t = 1.0 - _gpacTexCoord.t;\n", NULL); | |
| } | |
| /*format with max 4 tx_name (for yuva) + matrix for yuv*/ | |
| sprintf(szCode, shader_fun, tx_name, tx_name, tx_name, tx_name, tx_name); | |
| gf_dynstrcat(f_source, szCode, NULL); | |
| gf_dynstrcat(f_source, "\n}\n", NULL); | |
| return GF_TRUE; | |
| } | |
| Bool gf_gl_txw_setup(GF_GLTextureWrapper *tx, u32 pix_fmt, u32 width, u32 height, u32 stride, u32 uv_stride, Bool linear_interp, GF_FilterFrameInterface *frame_ifce, Bool full_range, s32 matrix_coef_or_neg) | |
| { | |
| u32 i; | |
| tx->width = width; | |
| tx->height = height; | |
| tx->pix_fmt = pix_fmt; | |
| tx->stride = stride; | |
| tx->uv_stride = uv_stride; | |
| tx->internal_textures = GF_TRUE; | |
| tx->nb_textures = 1; | |
| tx->is_yuv = GF_FALSE; | |
| tx->bit_depth = 8; | |
| tx->gl_format = GL_LUMINANCE; | |
| tx->bytes_per_pix = 1; | |
| tx->fullrange = full_range; | |
| if (matrix_coef_or_neg==GF_CICP_MX_UNSPECIFIED) | |
| tx->mx_cicp = -1; | |
| else | |
| tx->mx_cicp = matrix_coef_or_neg; | |
| if (!tx->stride) | |
| gf_pixel_get_size_info(tx->pix_fmt, tx->width, tx->height, NULL, &tx->stride, &tx->uv_stride, NULL, &tx->uv_h); | |
| switch (tx->pix_fmt) { | |
| case GF_PIXEL_YUV444_10: | |
| tx->bit_depth = 10; | |
| case GF_PIXEL_YUV444: | |
| case GF_PIXEL_YUVA444: | |
| tx->uv_w = tx->width; | |
| tx->uv_h = tx->height; | |
| if (!tx->uv_stride) | |
| tx->uv_stride = tx->stride; | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 3; | |
| if (tx->pix_fmt==GF_PIXEL_YUVA444) { | |
| tx->nb_textures = 4; | |
| tx->has_alpha = GF_TRUE; | |
| } | |
| break; | |
| case GF_PIXEL_YUV422_10: | |
| tx->bit_depth = 10; | |
| case GF_PIXEL_YUV422: | |
| tx->uv_w = tx->width/2; | |
| tx->uv_h = tx->height; | |
| if (!tx->uv_stride) | |
| tx->uv_stride = tx->stride/2; | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 3; | |
| break; | |
| case GF_PIXEL_YUV_10: | |
| tx->bit_depth = 10; | |
| case GF_PIXEL_YUV: | |
| case GF_PIXEL_YVU: | |
| case GF_PIXEL_YUVA: | |
| tx->uv_w = tx->width/2; | |
| if (tx->width % 2) tx->uv_w++; | |
| tx->uv_h = tx->height/2; | |
| if (tx->height % 2) tx->uv_h++; | |
| if (!tx->uv_stride) { | |
| tx->uv_stride = tx->stride/2; | |
| if (tx->stride%2) tx->uv_stride ++; | |
| } | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 3; | |
| if (tx->pix_fmt==GF_PIXEL_YUVA) { | |
| tx->nb_textures = 4; | |
| tx->has_alpha = GF_TRUE; | |
| } | |
| break; | |
| case GF_PIXEL_NV12_10: | |
| case GF_PIXEL_NV21_10: | |
| tx->bit_depth = 10; | |
| case GF_PIXEL_NV12: | |
| case GF_PIXEL_NV21: | |
| tx->uv_w = tx->width/2; | |
| tx->uv_h = tx->height/2; | |
| if (!tx->uv_stride) | |
| tx->uv_stride = tx->stride; | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 2; | |
| break; | |
| case GF_PIXEL_UYVY_10: | |
| case GF_PIXEL_YUYV_10: | |
| case GF_PIXEL_YVYU_10: | |
| case GF_PIXEL_VYUY_10: | |
| tx->bit_depth = 16; | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_VYUY: | |
| tx->uv_w = tx->width/2; | |
| tx->uv_h = tx->height; | |
| if (!tx->uv_stride) { | |
| tx->uv_stride = tx->stride/2; | |
| if (tx->stride%2) tx->uv_stride ++; | |
| } | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 1; | |
| break; | |
| case GF_PIXEL_V210: | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 1; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| tx->has_alpha = GF_TRUE; | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| case GF_PIXEL_YUV444_10_PACK: | |
| tx->uv_w = tx->width; | |
| tx->uv_h = tx->height; | |
| if (!tx->uv_stride) { | |
| tx->uv_stride = tx->stride; | |
| } | |
| tx->is_yuv = GF_TRUE; | |
| tx->nb_textures = 1; | |
| break; | |
| case GF_PIXEL_GREYSCALE: | |
| tx->gl_format = GL_LUMINANCE; | |
| tx->bytes_per_pix = 1; | |
| break; | |
| case GF_PIXEL_ALPHAGREY: | |
| case GF_PIXEL_GREYALPHA: | |
| tx->gl_format = GL_LUMINANCE_ALPHA; | |
| tx->bytes_per_pix = 2; | |
| break; | |
| case GF_PIXEL_RGB: | |
| tx->gl_format = GL_RGB; | |
| tx->bytes_per_pix = 3; | |
| break; | |
| case GF_PIXEL_BGR: | |
| tx->gl_format = GL_RGB; | |
| tx->bytes_per_pix = 3; | |
| break; | |
| case GF_PIXEL_BGRA: | |
| tx->has_alpha = GF_TRUE; | |
| case GF_PIXEL_BGRX: | |
| tx->gl_format = GL_RGBA; | |
| tx->bytes_per_pix = 4; | |
| break; | |
| case GF_PIXEL_ARGB: | |
| tx->has_alpha = GF_TRUE; | |
| case GF_PIXEL_XRGB: | |
| tx->gl_format = GL_RGBA; | |
| tx->bytes_per_pix = 4; | |
| break; | |
| case GF_PIXEL_ABGR: | |
| tx->has_alpha = GF_TRUE; | |
| case GF_PIXEL_XBGR: | |
| tx->gl_format = GL_RGBA; | |
| tx->bytes_per_pix = 4; | |
| break; | |
| case GF_PIXEL_RGBA: | |
| tx->has_alpha = GF_TRUE; | |
| case GF_PIXEL_RGBX: | |
| tx->gl_format = GL_RGBA; | |
| tx->bytes_per_pix = 4; | |
| break; | |
| case GF_PIXEL_RGB_332: | |
| tx->gl_format = GL_LUMINANCE; | |
| tx->bytes_per_pix = 1; | |
| break; | |
| case GF_PIXEL_RGB_444: | |
| tx->gl_format = GL_LUMINANCE_ALPHA; | |
| tx->bytes_per_pix = 2; | |
| break; | |
| case GF_PIXEL_RGB_555: | |
| tx->gl_format = GL_LUMINANCE_ALPHA; | |
| tx->bytes_per_pix = 2; | |
| break; | |
| case GF_PIXEL_RGB_565: | |
| tx->gl_format = GL_LUMINANCE_ALPHA; | |
| tx->bytes_per_pix = 2; | |
| break; | |
| case GF_PIXEL_GL_EXTERNAL: | |
| tx->internal_textures = GF_FALSE; | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Pixel format %s unsupported, cannot setup texture wrapper\n", gf_4cc_to_str(tx->pix_fmt))); | |
| return GF_FALSE; | |
| } | |
| if (tx->bit_depth>8) | |
| tx->bytes_per_pix = 2; | |
| if (frame_ifce && frame_ifce->get_gl_texture) { | |
| tx->internal_textures = GF_FALSE; | |
| } | |
| /*create textures*/ | |
| if (tx->internal_textures) { | |
| #if !defined(GPAC_USE_GLES1X) | |
| u32 glmode = GL_NEAREST; | |
| if ((tx->nb_textures==1) && linear_interp && !tx->is_yuv) | |
| glmode = GL_LINEAR; | |
| #endif | |
| tx->first_tx_load = GF_TRUE; | |
| tx->scale_10bit = 0; | |
| tx->memory_format = GL_UNSIGNED_BYTE; | |
| if (tx->is_yuv && tx->bit_depth>8) { | |
| #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| //we use x bits but GL will normalise using 16 bits, so we need to multiply the normalized result by 2^(16-x) | |
| u32 nb_bits = (16 - tx->bit_depth); | |
| u32 scale = 1; | |
| while (nb_bits) { | |
| scale*=2; | |
| nb_bits--; | |
| } | |
| tx->scale_10bit = scale; | |
| tx->memory_format = GL_UNSIGNED_SHORT; | |
| #else | |
| switch (tx->pix_fmt) { | |
| case GF_PIXEL_YUV_10: | |
| case GF_PIXEL_YUV422_10: | |
| case GF_PIXEL_YUV444_10: | |
| tx->gl_format = GL_LUMINANCE_ALPHA; | |
| tx->memory_format = GL_UNSIGNED_BYTE; | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Pixel format %s unsupported, cannot setup texture wrapper\n", gf_4cc_to_str(tx->pix_fmt))); | |
| return GF_FALSE; | |
| } | |
| #endif | |
| } | |
| GL_CHECK_ERR() | |
| glGenTextures(tx->nb_textures, tx->textures); | |
| GL_CHECK_ERR() | |
| #ifndef GPAC_USE_GLES2 | |
| glEnable(GL_TEXTURE_2D); | |
| GL_CHECK_ERR() | |
| #endif | |
| for (i=0; i<tx->nb_textures; i++) { | |
| #if !defined(GPAC_USE_GLES1X) | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[i] ); | |
| GL_CHECK_ERR() | |
| #if defined(GPAC_USE_GLES2) | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| #else | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |
| #endif | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmode); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode); | |
| #endif | |
| GL_CHECK_ERR() | |
| } | |
| #if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| if (tx->is_yuv && tx->pbo_state) { | |
| tx->first_tx_load = GF_FALSE; | |
| glGenBuffers(1, &tx->PBOs[0]); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[0]); | |
| if (tx->nb_textures>1) { | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, tx->bytes_per_pix * tx->width*tx->height, NULL, GL_DYNAMIC_DRAW_ARB); | |
| glGenBuffers(1, &tx->PBOs[1]); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[1]); | |
| } else { | |
| //packed YUV | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, tx->bytes_per_pix * 4*tx->width/2*tx->height, NULL, GL_DYNAMIC_DRAW_ARB); | |
| } | |
| if (tx->nb_textures==3) { | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, tx->bytes_per_pix * tx->uv_w*tx->uv_h, NULL, GL_DYNAMIC_DRAW_ARB); | |
| glGenBuffers(1, &tx->PBOs[2]); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[2]); | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, tx->bytes_per_pix * tx->uv_w*tx->uv_h, NULL, GL_DYNAMIC_DRAW_ARB); | |
| } | |
| //nv12/21 | |
| else { | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, tx->bytes_per_pix * 2*tx->uv_w*tx->uv_h, NULL, GL_DYNAMIC_DRAW_ARB); | |
| } | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); | |
| } | |
| #endif | |
| #ifndef GPAC_USE_GLES2 | |
| glDisable(GL_TEXTURE_2D); | |
| GL_CHECK_ERR() | |
| #endif | |
| } | |
| return GF_TRUE; | |
| } | |
| Bool gf_gl_txw_upload(GF_GLTextureWrapper *tx, const u8 *data, GF_FilterFrameInterface *frame_ifce) | |
| { | |
| Bool use_stride = GF_FALSE; | |
| u32 stride_luma, stride_chroma; | |
| const u8 *pY=NULL, *pU=NULL, *pV=NULL, *pA=NULL; | |
| tx->frame_ifce = NULL; | |
| if (!frame_ifce && !data) return GF_FALSE; | |
| if (!tx->internal_textures) { | |
| if (frame_ifce && frame_ifce->get_gl_texture) { | |
| tx->frame_ifce = frame_ifce; | |
| return GF_TRUE; | |
| } | |
| return GF_FALSE; | |
| } | |
| stride_luma = tx->stride; | |
| stride_chroma = tx->uv_stride; | |
| if (!frame_ifce) { | |
| if (tx->is_yuv) { | |
| if (tx->nb_textures==2) { | |
| if (tx->has_alpha) { | |
| pA = data + tx->stride * tx->height; | |
| } else { | |
| pU = data + tx->stride * tx->height; | |
| } | |
| } else if (tx->nb_textures>=3) { | |
| pU = data + tx->stride * tx->height; | |
| pV = pU + tx->uv_stride * tx->uv_h; | |
| if (tx->nb_textures==4) { | |
| pA = pV + tx->uv_stride * tx->uv_h; | |
| } | |
| } | |
| } | |
| } else { | |
| u32 st_o; | |
| if (!frame_ifce->get_plane) | |
| return GF_FALSE; | |
| if (tx->nb_textures) | |
| frame_ifce->get_plane(frame_ifce, 0, &data, &stride_luma); | |
| if (tx->nb_textures>1) | |
| frame_ifce->get_plane(frame_ifce, 1, &pU, &stride_chroma); | |
| //todo we need to cleanup alpha frame fetch, how do we differentiate between NV12+alpha (3 planes) and YUV420 ? | |
| if (tx->nb_textures>2) | |
| frame_ifce->get_plane(frame_ifce, 2, &pV, &st_o); | |
| if (tx->nb_textures>3) | |
| frame_ifce->get_plane(frame_ifce, 3, &pA, &st_o); | |
| } | |
| pY = data; | |
| if (tx->is_yuv && (stride_luma != tx->width)) { | |
| use_stride = GF_TRUE; //whether >8bits or real stride | |
| } | |
| GL_CHECK_ERR() | |
| //push data | |
| #ifndef GPAC_USE_GLES2 | |
| glEnable(GL_TEXTURE_2D); | |
| GL_CHECK_ERR() | |
| #endif | |
| if (tx->scale_10bit) { | |
| #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| glPixelTransferi(GL_RED_SCALE, tx->scale_10bit); | |
| if (tx->nb_textures==2) | |
| glPixelTransferi(GL_ALPHA_SCALE, tx->scale_10bit); | |
| glPixelStorei(GL_UNPACK_ALIGNMENT, 2); | |
| #endif | |
| } else { | |
| #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| glPixelTransferi(GL_RED_SCALE, 1); | |
| glPixelTransferi(GL_ALPHA_SCALE, 1); | |
| glPixelStorei(GL_UNPACK_LSB_FIRST, 0); | |
| #endif | |
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
| } | |
| GL_CHECK_ERR() | |
| if (!tx->is_yuv) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| GL_CHECK_ERR() | |
| if (use_stride) { | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| glPixelStorei(GL_UNPACK_ROW_LENGTH, tx->stride / tx->bytes_per_pix); | |
| #endif | |
| } | |
| if (tx->first_tx_load) { | |
| glTexImage2D(GL_TEXTURE_2D, 0, tx->gl_format, tx->width, tx->height, 0, tx->gl_format, GL_UNSIGNED_BYTE, data); | |
| tx->first_tx_load = GF_FALSE; | |
| } else { | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->width, tx->height, tx->gl_format, tx->memory_format, data); | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| #endif | |
| GL_CHECK_ERR() | |
| } | |
| #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| else if (tx->pbo_state && tx->PBOs[0]) { | |
| u32 i, linesize, count, p_stride; | |
| u8 *ptr; | |
| //packed YUV | |
| if (tx->nb_textures==1) { | |
| if (tx->pbo_state!=GF_GL_PBO_TEXIMG) { | |
| glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[0]); | |
| ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
| switch (tx->pix_fmt) { | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| linesize = 3 * tx->width; | |
| break; | |
| case GF_PIXEL_YUVA444_PACK: | |
| case GF_PIXEL_UYVA444_PACK: | |
| linesize = 4 * tx->width; | |
| break; | |
| case GF_PIXEL_YUV444_10_PACK: | |
| linesize = 4 * tx->width; | |
| break; | |
| case GF_PIXEL_V210: | |
| linesize = tx->width * 16 / 6; | |
| break; | |
| default: | |
| linesize = tx->width/2 * tx->bytes_per_pix * 4; | |
| } | |
| p_stride = stride_luma; | |
| count = tx->height; | |
| for (i=0; i<count; i++) { | |
| memcpy(ptr, pY, linesize); | |
| pY += p_stride; | |
| ptr += linesize; | |
| } | |
| glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); | |
| } | |
| if (tx->pbo_state!=GF_GL_PBO_PUSH) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[0]); | |
| if ((tx->pix_fmt==GF_PIXEL_YUV444_PACK) || (tx->pix_fmt==GF_PIXEL_VYU444_PACK)) | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tx->width, tx->height, 0, GL_RGB, tx->memory_format, NULL); | |
| else if ((tx->pix_fmt==GF_PIXEL_YUVA444_PACK) || (tx->pix_fmt==GF_PIXEL_UYVA444_PACK)) | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx->width, tx->height, 0, GL_RGBA, tx->memory_format, NULL); | |
| else if (tx->pix_fmt==GF_PIXEL_YUV444_10_PACK) | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx->width, tx->height, 0, GL_RGBA, tx->memory_format, NULL); | |
| else if (tx->pix_fmt==GF_PIXEL_V210) | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx->width, tx->height, 0, GL_RGBA, tx->memory_format, NULL); | |
| else | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx->width/2, tx->height, 0, GL_RGBA, tx->memory_format, NULL); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); | |
| } | |
| } else { | |
| if (tx->pbo_state!=GF_GL_PBO_TEXIMG) { | |
| glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[0]); | |
| ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
| linesize = tx->width*tx->bytes_per_pix; | |
| p_stride = stride_luma; | |
| count = tx->height; | |
| for (i=0; i<count; i++) { | |
| memcpy(ptr, pY, linesize); | |
| pY += p_stride; | |
| ptr += linesize; | |
| } | |
| glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); | |
| if (pU) { | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[1]); | |
| ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
| linesize = tx->uv_w * tx->bytes_per_pix; | |
| p_stride = stride_chroma; | |
| count = tx->uv_h; | |
| //NV12 and NV21 | |
| if (!pV) { | |
| linesize *= 2; | |
| } | |
| for (i=0; i<count; i++) { | |
| memcpy(ptr, pU, linesize); | |
| pU += p_stride; | |
| ptr += linesize; | |
| } | |
| glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); | |
| } | |
| if (pV) { | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[2]); | |
| ptr =(u8 *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); | |
| for (i=0; i<count; i++) { | |
| memcpy(ptr, pV, linesize); | |
| pV += p_stride; | |
| ptr += linesize; | |
| } | |
| glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB); | |
| } | |
| } | |
| if (tx->pbo_state!=GF_GL_PBO_PUSH) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[0]); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tx->width, tx->height, 0, tx->gl_format, tx->memory_format, NULL); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[1] ); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[1]); | |
| glTexImage2D(GL_TEXTURE_2D, 0, pV ? GL_LUMINANCE : GL_LUMINANCE_ALPHA, tx->uv_w, tx->uv_h, 0, pV ? GL_LUMINANCE : GL_LUMINANCE_ALPHA, tx->memory_format, NULL); | |
| if (pV) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[2] ); | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, tx->PBOs[2]); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tx->uv_w, tx->uv_h, 0, tx->gl_format, tx->memory_format, NULL); | |
| } | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); | |
| } | |
| } | |
| } | |
| #endif | |
| else if ((tx->nb_textures==1) || ((tx->nb_textures==2) && tx->has_alpha)) { | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| u32 uv_stride = 0; | |
| #endif | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| use_stride = GF_FALSE; | |
| if ((tx->pix_fmt==GF_PIXEL_YUV444_PACK) | |
| || (tx->pix_fmt==GF_PIXEL_VYU444_PACK) | |
| || (tx->pix_fmt==GF_PIXEL_YUVA444_PACK) | |
| || (tx->pix_fmt==GF_PIXEL_UYVA444_PACK) | |
| || (tx->pix_fmt==GF_PIXEL_YUV444_10_PACK) | |
| || (tx->pix_fmt==GF_PIXEL_V210) | |
| ) { | |
| u32 tx_width = tx->width; | |
| u32 nb_bytes = 3; | |
| GLuint fmt = GL_RGB; | |
| switch (tx->pix_fmt) { | |
| case GF_PIXEL_YUV444_PACK: | |
| case GF_PIXEL_VYU444_PACK: | |
| break; | |
| default: | |
| nb_bytes = 4; | |
| fmt = GL_RGBA; | |
| } | |
| if (tx->pix_fmt==GF_PIXEL_V210) { | |
| //inverse stride to get number of pixels - this is less than out actual width, we'll undo while repacking | |
| tx_width = tx->stride / 4; | |
| use_stride = GF_FALSE; | |
| } | |
| else if (stride_luma > nb_bytes*tx->width) { | |
| use_stride = GF_TRUE; | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_luma/tx->bytes_per_pix); | |
| #endif | |
| if (tx->first_tx_load) { | |
| glTexImage2D(GL_TEXTURE_2D, 0, fmt, tx_width, tx->height, 0, fmt, tx->memory_format, pY); | |
| tx->first_tx_load = GF_FALSE; | |
| } else { | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx_width, tx->height, fmt, tx->memory_format, pY); | |
| } | |
| } else { | |
| u32 scaler = tx->scale_10bit ? 4 : 2; | |
| if (stride_luma > scaler*tx->width) { | |
| //stride is given in bytes for packed formats, so divide by 2 to get the number of pixels | |
| //for YUYV, and we upload as a texture with half the wsize so redivide again by two | |
| //since GL_UNPACK_ROW_LENGTH counts in component and we moved the set 2 bytes per comp on 10 bits | |
| //no need to further divide | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| uv_stride = stride_luma/scaler/2; | |
| #endif | |
| use_stride = GF_TRUE; | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, uv_stride); | |
| #endif | |
| if (tx->first_tx_load) { | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx->width/2, tx->height, 0, GL_RGBA, tx->memory_format, pY); | |
| tx->first_tx_load = GF_FALSE; | |
| } else { | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->width/2, tx->height, GL_RGBA, tx->memory_format, pY); | |
| } | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| #endif | |
| } | |
| else if (tx->first_tx_load) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_luma/tx->bytes_per_pix); | |
| #endif | |
| glTexImage2D(GL_TEXTURE_2D, 0, tx->gl_format, tx->width, tx->height, 0, tx->gl_format, tx->memory_format, pY); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[1] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, pV ? stride_chroma/tx->bytes_per_pix : stride_chroma/tx->bytes_per_pix/2); | |
| #endif | |
| glTexImage2D(GL_TEXTURE_2D, 0, pV ? tx->gl_format : GL_LUMINANCE_ALPHA, tx->uv_w, tx->uv_h, 0, pV ? tx->gl_format : GL_LUMINANCE_ALPHA, tx->memory_format, pU); | |
| if (pV) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[2] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_chroma/tx->bytes_per_pix); | |
| #endif | |
| glTexImage2D(GL_TEXTURE_2D, 0, tx->gl_format, tx->uv_w, tx->uv_h, 0, tx->gl_format, tx->memory_format, pV); | |
| } | |
| if (pA) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[3] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_luma/tx->bytes_per_pix); | |
| #endif | |
| glTexImage2D(GL_TEXTURE_2D, 0, tx->gl_format, tx->width, tx->height, 0, tx->gl_format, tx->memory_format, pA); | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| #endif | |
| tx->first_tx_load = GF_FALSE; | |
| } | |
| else { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_luma/tx->bytes_per_pix); | |
| #endif | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->width, tx->height, tx->gl_format, tx->memory_format, pY); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[1] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, pV ? stride_chroma/tx->bytes_per_pix : stride_chroma/tx->bytes_per_pix/2); | |
| #endif | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->uv_w, tx->uv_h, pV ? tx->gl_format : GL_LUMINANCE_ALPHA, tx->memory_format, pU); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| if (pV) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[2] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_chroma/tx->bytes_per_pix); | |
| #endif | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->uv_w, tx->uv_h, tx->gl_format, tx->memory_format, pV); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| } | |
| if (pA) { | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[3] ); | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_luma/tx->bytes_per_pix); | |
| #endif | |
| glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tx->width, tx->height, tx->gl_format, tx->memory_format, pA); | |
| glBindTexture(GL_TEXTURE_2D, 0); | |
| } | |
| #if !defined(GPAC_GL_NO_STRIDE) | |
| if (use_stride) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
| #endif | |
| } | |
| //restore red/alpha scale | |
| if (tx->scale_10bit) { | |
| #if !defined(GPAC_USE_GLES1X) && !defined(GPAC_USE_GLES2) | |
| glPixelTransferi(GL_RED_SCALE, 1); | |
| glPixelTransferi(GL_ALPHA_SCALE, 1); | |
| glPixelStorei(GL_UNPACK_LSB_FIRST, 0); | |
| #endif | |
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
| } | |
| return GF_TRUE; | |
| } | |
| struct yuv_coefs { | |
| u32 cicp; | |
| Double Kr, Kb; | |
| } YUVMatrices[] = { | |
| {GF_CICP_MX_BT709, 0.2126, 0.0722}, | |
| {GF_CICP_MX_FCC47, 0.3, 0.11}, | |
| {GF_CICP_MX_BT601_625, 0.299, 0.114}, | |
| {GF_CICP_MX_SMPTE170, 0.299, 0.114}, | |
| {GF_CICP_MX_SMPTE240, 0.212, 0.087}, | |
| {GF_CICP_MX_BT2020, 0.2627, 0.0593}, | |
| {GF_CICP_MX_BT2020_CL, 0.2627, 0.0593} | |
| }; | |
| static void get_yuv_color_matrix(GF_GLTextureWrapper *tx, GF_Matrix *mx) | |
| { | |
| Double Kg; | |
| struct yuv_coefs *yc = NULL; | |
| //setup YUV->RGB matrix, in row-major | |
| gf_mx_init(*mx); | |
| if (tx->mx_cicp>=0) { | |
| u32 i, count=GF_ARRAY_LENGTH(YUVMatrices); | |
| u32 mx_code = (u32) tx->mx_cicp; | |
| if (mx_code==GF_CICP_MX_IDENTITY) { | |
| return; | |
| } | |
| if (mx_code==GF_CICP_MX_YCgCo) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[GL] YCgCo matrix not supported, will use BT709\n")); | |
| yc = &YUVMatrices[1]; | |
| } | |
| else if (mx_code==GF_CICP_MX_YDzDx) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[GL] YDxDy matrix not supported, will use BT709\n")); | |
| yc = &YUVMatrices[1]; | |
| } else { | |
| for (i=0; i<count; i++) { | |
| if (YUVMatrices[i].cicp == mx_code) { | |
| yc = &YUVMatrices[i]; | |
| break; | |
| } | |
| } | |
| if (!yc) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[GL] Unrecognized matrix coefficient value %d, will use BT709\n", mx_code)); | |
| yc = &YUVMatrices[1]; | |
| } | |
| } | |
| } else { | |
| yc = &YUVMatrices[1]; | |
| } | |
| Kg = 1.0 - yc->Kr - yc->Kb; | |
| mx->m[0] = 1.0f; | |
| mx->m[2] = (Float) (2.0 * (1.0 - yc->Kr) ); | |
| mx->m[4] = 1.0; | |
| mx->m[5] = (Float) ( - 2.0 * (1.0 - yc->Kb) * yc->Kb / Kg ); | |
| mx->m[6] = (Float) ( - 2.0 * (1.0 - yc->Kr) * yc->Kr / Kg ); | |
| mx->m[8] = 1.0f; | |
| mx->m[9] = (Float) (2.0 * (1.0 - yc->Kb) ); | |
| mx->m[10] = 0.0; | |
| //move to column major | |
| gf_mx_transpose(mx); | |
| if (tx->fullrange) { | |
| gf_mx_add_translation(mx, 0, FLT2FIX(-0.5), FLT2FIX(-0.5)); | |
| } else { | |
| gf_mx_add_scale(mx, FLT2FIX(255.0/216.0), FLT2FIX(255.0/224.0), FLT2FIX(255.0/224.0) ); | |
| gf_mx_add_translation(mx, FLT2FIX(-0.0625), FLT2FIX(-0.5), FLT2FIX(-0.5)); | |
| } | |
| GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[GL] YUV2RGB matrix is (column-major):\n" | |
| "\t%.4f\t%.4f\t%.4f\t%.4f\n" | |
| "\t%.4f\t%.4f\t%.4f\t%.4f\n" | |
| "\t%.4f\t%.4f\t%.4f\t%.4f\n" | |
| "\t%.4f\t%.4f\t%.4f\t%.4f\n", | |
| mx->m[0], mx->m[1], mx->m[2], mx->m[3], | |
| mx->m[4], mx->m[5], mx->m[6], mx->m[7], | |
| mx->m[8], mx->m[9], mx->m[10], mx->m[11], | |
| mx->m[12], mx->m[13], mx->m[14], mx->m[15] | |
| )); | |
| } | |
| Bool gf_gl_txw_bind(GF_GLTextureWrapper *tx, const char *tx_name, u32 gl_program, u32 texture_unit) | |
| { | |
| if (!texture_unit) | |
| texture_unit = GL_TEXTURE0; | |
| if (gl_program && (gl_program != tx->last_program)) { | |
| tx->last_program = gl_program; | |
| tx->uniform_setup = GF_FALSE; | |
| } | |
| #if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) | |
| if ((!tx->uniform_setup || (tx->init_active_texture != texture_unit)) && gl_program) { | |
| char szName[100]; | |
| u32 i; | |
| u32 start_idx = texture_unit - GL_TEXTURE0; | |
| s32 loc; | |
| tx->init_active_texture = texture_unit; | |
| for (i=0; i<tx->nb_textures; i++) { | |
| sprintf(szName, "_gf_%s_%d", tx_name, i+1); | |
| loc = glGetUniformLocation(gl_program, szName); | |
| if (!i && (loc == -1)) | |
| loc = glGetUniformLocation(gl_program, tx_name); | |
| GL_CHECK_ERR() | |
| if (loc == -1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[GL] Failed to locate texture %s in shader\n", szName)); | |
| return GF_FALSE; | |
| } | |
| glUniform1i(loc, start_idx + i); | |
| GL_CHECK_ERR() | |
| } | |
| GL_CHECK_ERR() | |
| } | |
| if (!tx->uniform_setup && gl_program) { | |
| s32 loc; | |
| Bool needs_gpu_width = GF_FALSE; | |
| char szName[100]; | |
| if (tx->is_yuv) { | |
| GF_Matrix mx; | |
| get_yuv_color_matrix(tx, &mx); | |
| sprintf(szName, "_gf_%s_mx", tx_name); | |
| loc = glGetUniformLocation(gl_program, szName); | |
| if (loc == -1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[GL] Failed to locate matrix coefficients %s in shader\n", szName)); | |
| return GF_FALSE; | |
| } | |
| glUniformMatrix4fv(loc, 1, GL_FALSE, mx.m); | |
| } | |
| switch (tx->pix_fmt) { | |
| case GF_PIXEL_V210: | |
| needs_gpu_width = GF_TRUE; | |
| case GF_PIXEL_UYVY: | |
| case GF_PIXEL_YUYV: | |
| case GF_PIXEL_VYUY: | |
| case GF_PIXEL_YVYU: | |
| case GF_PIXEL_UYVY_10: | |
| case GF_PIXEL_YUYV_10: | |
| case GF_PIXEL_VYUY_10: | |
| case GF_PIXEL_YVYU_10: | |
| sprintf(szName, "_gf_%s_width", tx_name); | |
| loc = glGetUniformLocation(gl_program, szName); | |
| if (loc == -1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[GL] Failed to locate uniform %s in shader\n", szName)); | |
| return GF_FALSE; | |
| } | |
| glUniform1f(loc, (GLfloat) tx->width); | |
| if (needs_gpu_width) { | |
| u32 gpu_width = tx->stride / 4; | |
| sprintf(szName, "_gf_%s_gpu_width", tx_name); | |
| loc = glGetUniformLocation(gl_program, szName); | |
| if (loc == -1) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[GL] Failed to locate uniform %s in shader\n", szName)); | |
| return GF_FALSE; | |
| } | |
| glUniform1f(loc, (GLfloat) gpu_width); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| tx->uniform_setup = GF_TRUE; | |
| } | |
| #endif // !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X) | |
| GL_CHECK_ERR() | |
| if (!tx->internal_textures) { | |
| u32 i; | |
| GF_Matrix txmx; | |
| gf_mx_init(txmx); | |
| for (i=0; i<tx->nb_textures; i++) { | |
| u32 gl_format = GL_TEXTURE_2D; | |
| //everything we do is on this texture unit, including what the parent filter does when fetching the gl texture | |
| glActiveTexture(texture_unit + i); | |
| if (tx->frame_ifce && tx->frame_ifce->get_gl_texture(tx->frame_ifce, i, &gl_format, &tx->textures[i], &txmx) != GF_OK) { | |
| if (!i) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[GL] Failed to get frame interface OpenGL texture ID for plane %d\n", i)); | |
| return GF_FALSE; | |
| } | |
| break; | |
| } | |
| #ifndef GPAC_USE_GLES2 | |
| if (!gl_program) | |
| glEnable(gl_format); | |
| #endif | |
| if (!tx->textures[i]) | |
| break; | |
| glBindTexture(gl_format, tx->textures[i]); | |
| glTexParameteri(gl_format, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(gl_format, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(gl_format, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| glTexParameteri(gl_format, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| /*todo pass matrix to shader !!*/ | |
| } | |
| tx->flip = (txmx.m[5]<0) ? GF_TRUE : GF_FALSE; | |
| if (tx->nb_textures) { | |
| #ifndef GPAC_USE_GLES2 | |
| glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
| glClientActiveTexture(texture_unit); | |
| #endif | |
| } | |
| return GF_TRUE; | |
| } | |
| if (tx->nb_textures>3) { | |
| glActiveTexture(texture_unit + 3); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[3]); | |
| } | |
| if (tx->nb_textures>2) { | |
| glActiveTexture(texture_unit + 2); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[2]); | |
| } | |
| if (tx->nb_textures>1) { | |
| glActiveTexture(texture_unit + 1); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[1]); | |
| } | |
| if (tx->nb_textures) { | |
| glActiveTexture(texture_unit); | |
| glBindTexture(GL_TEXTURE_2D, tx->textures[0]); | |
| #ifndef GPAC_USE_GLES2 | |
| glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
| glClientActiveTexture(texture_unit); | |
| #endif | |
| } | |
| #ifndef GPAC_USE_GLES2 | |
| glEnable(GL_TEXTURE_2D); | |
| #endif | |
| GL_CHECK_ERR() | |
| return GF_TRUE; | |
| } | |
| void gf_gl_txw_reset(GF_GLTextureWrapper *tx) | |
| { | |
| if (tx->nb_textures) { | |
| if (tx->internal_textures) { | |
| glDeleteTextures(tx->nb_textures, tx->textures); | |
| if (tx->pbo_state && tx->PBOs[0]) { | |
| glDeleteBuffers(tx->nb_textures, tx->PBOs); | |
| } | |
| } | |
| tx->nb_textures = 0; | |
| } | |
| tx->width = 0; | |
| tx->height = 0; | |
| tx->pix_fmt = 0; | |
| tx->stride = 0; | |
| tx->uv_stride = 0; | |
| tx->internal_textures = GF_FALSE; | |
| tx->uniform_setup = GF_FALSE; | |
| } | |
| #else | |
| void gf_opengl_init() | |
| { | |
| } | |
| Bool gf_gl_txw_insert_fragment_shader(u32 pix_fmt, const char *tx_name, char **f_source, Bool y_flip) | |
| { | |
| return GF_FALSE; | |
| } | |
| Bool gf_gl_txw_setup(GF_GLTextureWrapper *tx, u32 pix_fmt, u32 width, u32 height, u32 stride, u32 uv_stride, Bool linear_interp, GF_FilterFrameInterface *frame_ifce, Bool full_range, s32 matrix_coef_or_neg) | |
| { | |
| return GF_FALSE; | |
| } | |
| Bool gf_gl_txw_upload(GF_GLTextureWrapper *tx, const u8 *data, GF_FilterFrameInterface *frame_ifce) | |
| { | |
| return GF_FALSE; | |
| } | |
| Bool gf_gl_txw_bind(GF_GLTextureWrapper *tx, const char *tx_name, u32 gl_program, u32 texture_unit) | |
| { | |
| return GF_FALSE; | |
| } | |
| void gf_gl_txw_reset(GF_GLTextureWrapper *tx) | |
| { | |
| } | |
| #endif //GPAC_DISABLE_3D |