| /* |
| * GStreamer |
| * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com> |
| * Copyright (C) 2014 Julien Isorce <julien.isorce@collabora.co.uk> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library 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 |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "gl.h" |
| #include "gstglshader.h" |
| |
| /* FIXME: separate into separate shader stage objects that can be added/removed |
| * independently of the shader program */ |
| |
| static const gchar *es2_version_header = "#version 100\n"; |
| |
| /* *INDENT-OFF* */ |
| static const gchar *simple_vertex_shader_str_gles2 = |
| "attribute vec4 a_position;\n" |
| "attribute vec2 a_texcoord;\n" |
| "varying vec2 v_texcoord;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_texcoord = a_texcoord;\n" |
| "}\n"; |
| |
| static const gchar *simple_fragment_shader_str_gles2 = |
| "#ifdef GL_ES\n" |
| "precision mediump float;\n" |
| "#endif\n" |
| "varying vec2 v_texcoord;\n" |
| "uniform sampler2D tex;\n" |
| "void main()\n" |
| "{\n" |
| " gl_FragColor = texture2D(tex, v_texcoord);\n" |
| "}"; |
| /* *INDENT-ON* */ |
| |
| #ifndef GL_COMPILE_STATUS |
| #define GL_COMPILE_STATUS 0x8B81 |
| #endif |
| #ifndef GLhandleARB |
| #define GLhandleARB GLuint |
| #endif |
| |
| #define GST_GL_SHADER_GET_PRIVATE(o) \ |
| (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_SHADER, GstGLShaderPrivate)) |
| |
| #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)) |
| #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1)) |
| #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0)) |
| #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)) |
| #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0)) |
| |
| typedef struct _GstGLShaderVTable |
| { |
| GLuint GSTGLAPI (*CreateProgram) (void); |
| void GSTGLAPI (*DeleteProgram) (GLuint program); |
| void GSTGLAPI (*UseProgram) (GLuint program); |
| void GSTGLAPI (*GetAttachedShaders) (GLuint program, GLsizei maxcount, |
| GLsizei * count, GLuint * shaders); |
| |
| GLuint GSTGLAPI (*CreateShader) (GLenum shaderType); |
| void GSTGLAPI (*DeleteShader) (GLuint shader); |
| void GSTGLAPI (*AttachShader) (GLuint program, GLuint shader); |
| void GSTGLAPI (*DetachShader) (GLuint program, GLuint shader); |
| |
| void GSTGLAPI (*GetShaderiv) (GLuint program, GLenum pname, GLint * params); |
| void GSTGLAPI (*GetProgramiv) (GLuint program, GLenum pname, GLint * params); |
| void GSTGLAPI (*GetShaderInfoLog) (GLuint shader, GLsizei maxLength, |
| GLsizei * length, char *log); |
| void GSTGLAPI (*GetProgramInfoLog) (GLuint shader, GLsizei maxLength, |
| GLsizei * length, char *log); |
| } GstGLShaderVTable; |
| |
| enum |
| { |
| PROP_0, |
| PROP_VERTEX_SRC, |
| PROP_FRAGMENT_SRC, |
| PROP_COMPILED, |
| PROP_ACTIVE /* unused */ |
| }; |
| |
| struct _GstGLShaderPrivate |
| { |
| gchar *vertex_src; |
| gchar *fragment_src; |
| |
| GLhandleARB vertex_handle; |
| GLhandleARB fragment_handle; |
| GLhandleARB program_handle; |
| |
| gboolean compiled; |
| gboolean active; |
| |
| GstGLAPI gl_api; |
| |
| GstGLShaderVTable vtable; |
| }; |
| |
| GST_DEBUG_CATEGORY_STATIC (gst_gl_shader_debug); |
| #define GST_CAT_DEFAULT gst_gl_shader_debug |
| |
| #define DEBUG_INIT \ |
| GST_DEBUG_CATEGORY_INIT (gst_gl_shader_debug, "glshader", 0, "shader"); |
| G_DEFINE_TYPE_WITH_CODE (GstGLShader, gst_gl_shader, GST_TYPE_OBJECT, |
| DEBUG_INIT); |
| |
| static void |
| _cleanup_shader (GstGLContext * context, GstGLShader * shader) |
| { |
| GstGLShaderPrivate *priv = shader->priv; |
| |
| /* release shader objects */ |
| gst_gl_shader_release (shader); |
| |
| /* delete program */ |
| if (priv->program_handle) { |
| GST_TRACE ("finalizing program shader %u", priv->program_handle); |
| |
| priv->vtable.DeleteProgram (priv->program_handle); |
| /* err = glGetError (); */ |
| /* GST_WARNING ("error: 0x%x", err); */ |
| /* glGetObjectParameteriv(priv->program_handle, GL_OBJECT_DELETE_STATUS_, &status); */ |
| /* GST_INFO ("program deletion status:%s", status == GL_TRUE ? "true" : "false" ); */ |
| } |
| |
| GST_DEBUG ("shader deleted %u", priv->program_handle); |
| } |
| |
| static void |
| gst_gl_shader_finalize (GObject * object) |
| { |
| GstGLShader *shader; |
| GstGLShaderPrivate *priv; |
| |
| shader = GST_GL_SHADER (object); |
| priv = shader->priv; |
| |
| GST_TRACE_OBJECT (shader, "finalizing shader %u", priv->program_handle); |
| |
| g_free (priv->vertex_src); |
| g_free (priv->fragment_src); |
| |
| gst_gl_context_thread_add (shader->context, |
| (GstGLContextThreadFunc) _cleanup_shader, shader); |
| |
| priv->fragment_handle = 0; |
| priv->vertex_handle = 0; |
| priv->program_handle = 0; |
| |
| if (shader->context) { |
| gst_object_unref (shader->context); |
| shader->context = NULL; |
| } |
| |
| G_OBJECT_CLASS (gst_gl_shader_parent_class)->finalize (object); |
| } |
| |
| static void |
| gst_gl_shader_set_property (GObject * object, |
| guint prop_id, const GValue * value, GParamSpec * pspec) |
| { |
| GstGLShader *shader = GST_GL_SHADER (object); |
| |
| switch (prop_id) { |
| case PROP_VERTEX_SRC: |
| gst_gl_shader_set_vertex_source (shader, g_value_get_string (value)); |
| break; |
| case PROP_FRAGMENT_SRC: |
| gst_gl_shader_set_fragment_source (shader, g_value_get_string (value)); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| } |
| |
| static void |
| gst_gl_shader_get_property (GObject * object, |
| guint prop_id, GValue * value, GParamSpec * pspec) |
| { |
| GstGLShader *shader = GST_GL_SHADER (object); |
| GstGLShaderPrivate *priv = shader->priv; |
| |
| switch (prop_id) { |
| case PROP_VERTEX_SRC: |
| g_value_set_string (value, priv->vertex_src); |
| break; |
| case PROP_FRAGMENT_SRC: |
| g_value_set_string (value, priv->fragment_src); |
| break; |
| case PROP_COMPILED: |
| g_value_set_boolean (value, priv->compiled); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| break; |
| } |
| |
| } |
| |
| int |
| gst_gl_shader_get_program_handle (GstGLShader * shader) |
| { |
| GstGLShaderPrivate *priv = shader->priv; |
| return (int) priv->program_handle; |
| } |
| |
| static void |
| gst_gl_shader_class_init (GstGLShaderClass * klass) |
| { |
| /* bind class methods .. */ |
| GObjectClass *obj_class = G_OBJECT_CLASS (klass); |
| |
| g_type_class_add_private (klass, sizeof (GstGLShaderPrivate)); |
| |
| obj_class->finalize = gst_gl_shader_finalize; |
| obj_class->set_property = gst_gl_shader_set_property; |
| obj_class->get_property = gst_gl_shader_get_property; |
| |
| /* .. and install properties */ |
| |
| g_object_class_install_property (obj_class, |
| PROP_VERTEX_SRC, |
| g_param_spec_string ("vertex-src", |
| "Vertex Source", |
| "GLSL Vertex Shader source code", NULL, |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (obj_class, |
| PROP_FRAGMENT_SRC, |
| g_param_spec_string ("fragment-src", |
| "Fragment Source", |
| "GLSL Fragment Shader source code", NULL, |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (obj_class, |
| PROP_ACTIVE, |
| g_param_spec_string ("active", |
| "Active", "Enable/Disable the shader", NULL, |
| G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| g_object_class_install_property (obj_class, |
| PROP_COMPILED, |
| g_param_spec_boolean ("compiled", |
| "Compiled", |
| "Shader compile and link status", FALSE, |
| G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
| } |
| |
| void |
| gst_gl_shader_set_vertex_source (GstGLShader * shader, const gchar * src) |
| { |
| GstGLShaderPrivate *priv; |
| |
| g_return_if_fail (GST_GL_IS_SHADER (shader)); |
| g_return_if_fail (src != NULL); |
| |
| priv = shader->priv; |
| |
| if (gst_gl_shader_is_compiled (shader)) |
| gst_gl_shader_release (shader); |
| |
| g_free (priv->vertex_src); |
| |
| priv->vertex_src = g_strdup (src); |
| } |
| |
| void |
| gst_gl_shader_set_fragment_source (GstGLShader * shader, const gchar * src) |
| { |
| GstGLShaderPrivate *priv; |
| |
| g_return_if_fail (GST_GL_IS_SHADER (shader)); |
| g_return_if_fail (src != NULL); |
| |
| priv = shader->priv; |
| |
| if (gst_gl_shader_is_compiled (shader)) |
| gst_gl_shader_release (shader); |
| |
| g_free (priv->fragment_src); |
| |
| priv->fragment_src = g_strdup (src); |
| } |
| |
| const gchar * |
| gst_gl_shader_get_vertex_source (GstGLShader * shader) |
| { |
| g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL); |
| return shader->priv->vertex_src; |
| } |
| |
| const gchar * |
| gst_gl_shader_get_fragment_source (GstGLShader * shader) |
| { |
| g_return_val_if_fail (GST_GL_IS_SHADER (shader), NULL); |
| return shader->priv->fragment_src; |
| } |
| |
| static void |
| gst_gl_shader_init (GstGLShader * self) |
| { |
| /* initialize sources and create program object */ |
| GstGLShaderPrivate *priv; |
| |
| priv = self->priv = GST_GL_SHADER_GET_PRIVATE (self); |
| |
| priv->vertex_src = NULL; |
| priv->fragment_src = NULL; |
| |
| priv->fragment_handle = 0; |
| priv->vertex_handle = 0; |
| |
| priv->compiled = FALSE; |
| priv->active = FALSE; /* unused at the moment */ |
| |
| /* FIXME: add API to get/set this for each shader */ |
| priv->gl_api = GST_GL_API_ANY; |
| } |
| |
| static gboolean |
| _fill_vtable (GstGLShader * shader, GstGLContext * context) |
| { |
| GstGLFuncs *gl = context->gl_vtable; |
| GstGLShaderVTable *vtable = &shader->priv->vtable; |
| |
| if (gl->CreateProgram) { |
| vtable->CreateProgram = gl->CreateProgram; |
| vtable->DeleteProgram = gl->DeleteProgram; |
| vtable->UseProgram = gl->UseProgram; |
| |
| vtable->CreateShader = gl->CreateShader; |
| vtable->DeleteShader = gl->DeleteShader; |
| vtable->AttachShader = gl->AttachShader; |
| vtable->DetachShader = gl->DetachShader; |
| |
| vtable->GetAttachedShaders = gl->GetAttachedShaders; |
| |
| vtable->GetShaderInfoLog = gl->GetShaderInfoLog; |
| vtable->GetShaderiv = gl->GetShaderiv; |
| vtable->GetProgramInfoLog = gl->GetProgramInfoLog; |
| vtable->GetProgramiv = gl->GetProgramiv; |
| } else if (gl->CreateProgramObject) { |
| vtable->CreateProgram = gl->CreateProgramObject; |
| vtable->DeleteProgram = gl->DeleteObject; |
| vtable->UseProgram = gl->UseProgramObject; |
| |
| vtable->CreateShader = gl->CreateShaderObject; |
| vtable->DeleteShader = gl->DeleteObject; |
| vtable->AttachShader = gl->AttachObject; |
| vtable->DetachShader = gl->DetachObject; |
| |
| vtable->GetAttachedShaders = gl->GetAttachedObjects; |
| |
| vtable->GetShaderInfoLog = gl->GetInfoLog; |
| vtable->GetShaderiv = gl->GetObjectParameteriv; |
| vtable->GetProgramInfoLog = gl->GetInfoLog; |
| vtable->GetProgramiv = gl->GetObjectParameteriv; |
| } else { |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| GstGLShader * |
| gst_gl_shader_new (GstGLContext * context) |
| { |
| GstGLShader *shader; |
| |
| g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL); |
| |
| shader = g_object_new (GST_GL_TYPE_SHADER, NULL); |
| shader->context = gst_object_ref (context); |
| |
| GST_DEBUG_OBJECT (shader, "Created new GLShader for context %" GST_PTR_FORMAT, |
| context); |
| |
| return shader; |
| } |
| |
| gboolean |
| gst_gl_shader_is_compiled (GstGLShader * shader) |
| { |
| g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE); |
| |
| return shader->priv->compiled; |
| } |
| |
| static gboolean |
| _shader_string_has_version (const gchar * str) |
| { |
| gboolean sl_comment = FALSE; |
| gboolean ml_comment = FALSE; |
| gboolean has_version = FALSE; |
| gint i = 0; |
| |
| /* search for #version to allow for preceeding comments as allowed by the |
| * GLSL specification */ |
| while (str && str[i] != '\0' && i < 1024) { |
| if (sl_comment) { |
| if (str[i] != '\n') |
| sl_comment = FALSE; |
| i++; |
| continue; |
| } |
| |
| if (ml_comment) { |
| if (g_strstr_len (&str[i], 2, "*/")) { |
| ml_comment = FALSE; |
| i += 2; |
| } else { |
| i++; |
| } |
| continue; |
| } |
| |
| if (g_strstr_len (&str[i], 2, "//")) { |
| sl_comment = TRUE; |
| i += 2; |
| continue; |
| } |
| |
| if (g_strstr_len (&str[i], 2, "/*")) { |
| ml_comment = TRUE; |
| i += 2; |
| continue; |
| } |
| |
| if (g_strstr_len (&str[i], 1, "#")) { |
| if (g_strstr_len (&str[i], 8, "#version")) |
| has_version = TRUE; |
| break; |
| } |
| |
| i++; |
| } |
| |
| return has_version; |
| } |
| |
| static void |
| _maybe_prepend_version (GstGLShader * shader, const gchar * shader_str, |
| gint * n_vertex_sources, const gchar *** vertex_sources) |
| { |
| gint n = 1; |
| |
| /* FIXME: this all an educated guess */ |
| if (gst_gl_context_check_gl_version (shader->context, GST_GL_API_OPENGL3, 3, |
| 0) |
| && (shader->priv->gl_api & GST_GL_API_GLES2) != 0 |
| && !_shader_string_has_version (shader_str)) |
| n = 2; |
| |
| *vertex_sources = g_malloc0 (n * sizeof (gchar *)); |
| |
| if (n > 1) |
| *vertex_sources[0] = es2_version_header; |
| |
| (*vertex_sources)[n - 1] = shader_str; |
| *n_vertex_sources = n; |
| } |
| |
| gboolean |
| gst_gl_shader_compile (GstGLShader * shader, GError ** error) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| |
| gchar info_buffer[2048]; |
| gint len = 0; |
| GLint status = GL_FALSE; |
| |
| g_return_val_if_fail (GST_GL_IS_SHADER (shader), FALSE); |
| |
| priv = shader->priv; |
| gl = shader->context->gl_vtable; |
| |
| if (priv->compiled) |
| return priv->compiled; |
| |
| if (!_fill_vtable (shader, shader->context)) |
| return FALSE; |
| |
| shader->priv->program_handle = shader->priv->vtable.CreateProgram (); |
| |
| GST_TRACE ("shader created %u", shader->priv->program_handle); |
| |
| g_return_val_if_fail (priv->program_handle, FALSE); |
| |
| if (priv->vertex_src) { |
| gint n_vertex_sources; |
| const gchar **vertex_sources; |
| |
| _maybe_prepend_version (shader, priv->vertex_src, &n_vertex_sources, |
| &vertex_sources); |
| |
| /* create vertex object */ |
| priv->vertex_handle = priv->vtable.CreateShader (GL_VERTEX_SHADER); |
| gl->ShaderSource (priv->vertex_handle, n_vertex_sources, vertex_sources, |
| NULL); |
| g_free (vertex_sources); |
| |
| /* compile */ |
| gl->CompileShader (priv->vertex_handle); |
| /* check everything is ok */ |
| status = GL_FALSE; |
| gl->GetShaderiv (priv->vertex_handle, GL_COMPILE_STATUS, &status); |
| |
| priv->vtable.GetShaderInfoLog (priv->vertex_handle, |
| sizeof (info_buffer) - 1, &len, info_buffer); |
| info_buffer[len] = '\0'; |
| |
| if (status != GL_TRUE) { |
| GST_ERROR ("Vertex Shader compilation failed:\n%s", info_buffer); |
| |
| g_set_error (error, GST_GL_SHADER_ERROR, |
| GST_GL_SHADER_ERROR_COMPILE, |
| "Vertex Shader compilation failed:\n%s", info_buffer); |
| |
| priv->vtable.DeleteShader (priv->vertex_handle); |
| priv->compiled = FALSE; |
| return priv->compiled; |
| } else if (len > 1) { |
| GST_FIXME ("vertex shader info log:\n%s\n", info_buffer); |
| } |
| priv->vtable.AttachShader (priv->program_handle, priv->vertex_handle); |
| |
| GST_LOG ("vertex shader attached %u", priv->vertex_handle); |
| } |
| |
| if (priv->fragment_src) { |
| gint n_fragment_sources; |
| const gchar **fragment_sources; |
| |
| _maybe_prepend_version (shader, priv->fragment_src, &n_fragment_sources, |
| &fragment_sources); |
| |
| /* create fragment object */ |
| priv->fragment_handle = priv->vtable.CreateShader (GL_FRAGMENT_SHADER); |
| gl->ShaderSource (priv->fragment_handle, n_fragment_sources, |
| fragment_sources, NULL); |
| g_free (fragment_sources); |
| /* compile */ |
| gl->CompileShader (priv->fragment_handle); |
| /* check everything is ok */ |
| status = GL_FALSE; |
| priv->vtable.GetShaderiv (priv->fragment_handle, |
| GL_COMPILE_STATUS, &status); |
| |
| priv->vtable.GetShaderInfoLog (priv->fragment_handle, |
| sizeof (info_buffer) - 1, &len, info_buffer); |
| info_buffer[len] = '\0'; |
| if (status != GL_TRUE) { |
| GST_ERROR ("Fragment Shader compilation failed:\n%s", info_buffer); |
| |
| g_set_error (error, GST_GL_SHADER_ERROR, |
| GST_GL_SHADER_ERROR_COMPILE, |
| "Fragment Shader compilation failed:\n%s", info_buffer); |
| |
| priv->vtable.DeleteShader (priv->fragment_handle); |
| priv->compiled = FALSE; |
| return priv->compiled; |
| } else if (len > 1) { |
| GST_FIXME ("vertex shader info log:\n%s\n", info_buffer); |
| } |
| priv->vtable.AttachShader (priv->program_handle, priv->fragment_handle); |
| |
| GST_LOG ("fragment shader attached %u", priv->fragment_handle); |
| } |
| |
| /* if nothing failed link shaders */ |
| gl->LinkProgram (priv->program_handle); |
| status = GL_FALSE; |
| priv->vtable.GetProgramiv (priv->program_handle, GL_LINK_STATUS, &status); |
| |
| priv->vtable.GetProgramInfoLog (priv->program_handle, |
| sizeof (info_buffer) - 1, &len, info_buffer); |
| info_buffer[len] = '\0'; |
| |
| if (status != GL_TRUE) { |
| GST_ERROR ("Shader linking failed:\n%s", info_buffer); |
| |
| g_set_error (error, GST_GL_SHADER_ERROR, |
| GST_GL_SHADER_ERROR_LINK, "Shader Linking failed:\n%s", info_buffer); |
| priv->compiled = FALSE; |
| return priv->compiled; |
| } else if (len > 1) { |
| GST_FIXME ("shader link log:\n%s\n", info_buffer); |
| } |
| /* success! */ |
| priv->compiled = TRUE; |
| g_object_notify (G_OBJECT (shader), "compiled"); |
| |
| return priv->compiled; |
| } |
| |
| void |
| gst_gl_shader_release (GstGLShader * shader) |
| { |
| GstGLShaderPrivate *priv; |
| |
| g_return_if_fail (GST_GL_IS_SHADER (shader)); |
| |
| priv = shader->priv; |
| |
| if (!priv->compiled || !priv->program_handle) |
| return; |
| |
| if (priv->vertex_handle) { /* not needed but nvidia doesn't care to respect the spec */ |
| GST_TRACE ("finalizing vertex shader %u", priv->vertex_handle); |
| |
| priv->vtable.DeleteShader (priv->vertex_handle); |
| } |
| |
| if (priv->fragment_handle) { |
| GST_TRACE ("finalizing fragment shader %u", priv->fragment_handle); |
| |
| priv->vtable.DeleteShader (priv->fragment_handle); |
| } |
| |
| if (priv->vertex_handle) |
| priv->vtable.DetachShader (priv->program_handle, priv->vertex_handle); |
| if (priv->fragment_handle) |
| priv->vtable.DetachShader (priv->program_handle, priv->fragment_handle); |
| |
| priv->compiled = FALSE; |
| g_object_notify (G_OBJECT (shader), "compiled"); |
| } |
| |
| void |
| gst_gl_shader_use (GstGLShader * shader) |
| { |
| GstGLShaderPrivate *priv; |
| |
| g_return_if_fail (GST_GL_IS_SHADER (shader)); |
| |
| priv = shader->priv; |
| |
| g_return_if_fail (priv->program_handle); |
| |
| priv->vtable.UseProgram (priv->program_handle); |
| |
| return; |
| } |
| |
| void |
| gst_gl_context_clear_shader (GstGLContext * context) |
| { |
| GstGLFuncs *gl; |
| |
| g_return_if_fail (GST_GL_IS_CONTEXT (context)); |
| |
| gl = context->gl_vtable; |
| |
| if (gl->CreateProgram) |
| gl->UseProgram (0); |
| else if (gl->CreateProgramObject) |
| gl->UseProgramObject (0); |
| } |
| |
| gboolean |
| gst_gl_shader_compile_and_check (GstGLShader * shader, |
| const gchar * source, GstGLShaderSourceType type) |
| { |
| gboolean is_compiled = FALSE; |
| |
| g_object_get (G_OBJECT (shader), "compiled", &is_compiled, NULL); |
| |
| if (!is_compiled) { |
| GError *error = NULL; |
| |
| switch (type) { |
| case GST_GL_SHADER_FRAGMENT_SOURCE: |
| gst_gl_shader_set_fragment_source (shader, source); |
| break; |
| case GST_GL_SHADER_VERTEX_SOURCE: |
| gst_gl_shader_set_vertex_source (shader, source); |
| break; |
| default: |
| g_assert_not_reached (); |
| break; |
| } |
| |
| gst_gl_shader_compile (shader, &error); |
| if (error) { |
| gst_gl_context_set_error (shader->context, "%s", error->message); |
| g_error_free (error); |
| gst_gl_context_clear_shader (shader->context); |
| |
| return FALSE; |
| } |
| } |
| return TRUE; |
| } |
| |
| gboolean |
| gst_gl_shader_compile_all_with_attribs_and_check (GstGLShader * shader, |
| const gchar * v_src, const gchar * f_src, const gint n_attribs, |
| const gchar * attrib_names[], GLint attrib_locs[]) |
| { |
| gint i = 0; |
| GError *error = NULL; |
| |
| gst_gl_shader_set_vertex_source (shader, v_src); |
| gst_gl_shader_set_fragment_source (shader, f_src); |
| |
| gst_gl_shader_compile (shader, &error); |
| if (error) { |
| gst_gl_context_set_error (shader->context, "%s", error->message); |
| g_error_free (error); |
| gst_gl_context_clear_shader (shader->context); |
| |
| return FALSE; |
| } |
| |
| for (i = 0; i < n_attribs; i++) |
| attrib_locs[i] = |
| gst_gl_shader_get_attribute_location (shader, attrib_names[i]); |
| |
| return TRUE; |
| } |
| |
| gboolean |
| gst_gl_shader_compile_with_default_f_and_check (GstGLShader * shader, |
| const gchar * v_src, const gint n_attribs, const gchar * attrib_names[], |
| GLint attrib_locs[]) |
| { |
| return gst_gl_shader_compile_all_with_attribs_and_check (shader, v_src, |
| simple_fragment_shader_str_gles2, n_attribs, attrib_names, attrib_locs); |
| } |
| |
| gboolean |
| gst_gl_shader_compile_with_default_v_and_check (GstGLShader * shader, |
| const gchar * f_src, GLint * pos_loc, GLint * tex_loc) |
| { |
| const gchar *attrib_names[2] = { "a_position", "a_texcoord" }; |
| GLint attrib_locs[2] = { 0 }; |
| gboolean ret = TRUE; |
| |
| ret = gst_gl_shader_compile_all_with_attribs_and_check (shader, |
| simple_vertex_shader_str_gles2, f_src, 2, attrib_names, attrib_locs); |
| |
| if (ret) { |
| *pos_loc = attrib_locs[0]; |
| *tex_loc = attrib_locs[1]; |
| } |
| |
| return ret; |
| } |
| |
| gboolean |
| gst_gl_shader_compile_with_default_vf_and_check (GstGLShader * shader, |
| GLint * pos_loc, GLint * tex_loc) |
| { |
| return gst_gl_shader_compile_with_default_v_and_check (shader, |
| simple_fragment_shader_str_gles2, pos_loc, tex_loc); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_1f (GstGLShader * shader, const gchar * name, |
| gfloat value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform1f (location, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_1fv (GstGLShader * shader, const gchar * name, |
| guint count, gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform1fv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_1i (GstGLShader * shader, const gchar * name, |
| gint value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform1i (location, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_1iv (GstGLShader * shader, const gchar * name, |
| guint count, gint * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform1iv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_2f (GstGLShader * shader, const gchar * name, |
| gfloat value0, gfloat value1) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform2f (location, value0, value1); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_2fv (GstGLShader * shader, const gchar * name, |
| guint count, gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform2fv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_2i (GstGLShader * shader, const gchar * name, |
| gint v0, gint v1) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform2i (location, v0, v1); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_2iv (GstGLShader * shader, const gchar * name, |
| guint count, gint * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform2iv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_3f (GstGLShader * shader, const gchar * name, |
| gfloat v0, gfloat v1, gfloat v2) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform3f (location, v0, v1, v2); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_3fv (GstGLShader * shader, const gchar * name, |
| guint count, gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform3fv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_3i (GstGLShader * shader, const gchar * name, |
| gint v0, gint v1, gint v2) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform3i (location, v0, v1, v2); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_3iv (GstGLShader * shader, const gchar * name, |
| guint count, gint * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform3iv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_4f (GstGLShader * shader, const gchar * name, |
| gfloat v0, gfloat v1, gfloat v2, gfloat v3) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform4f (location, v0, v1, v2, v3); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_4fv (GstGLShader * shader, const gchar * name, |
| guint count, gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform4fv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_4i (GstGLShader * shader, const gchar * name, |
| gint v0, gint v1, gint v2, gint v3) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform4i (location, v0, v1, v2, v3); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_4iv (GstGLShader * shader, const gchar * name, |
| guint count, gint * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->Uniform4iv (location, count, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_2fv (GstGLShader * shader, const gchar * name, |
| gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix2fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_3fv (GstGLShader * shader, const gchar * name, |
| gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix3fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_4fv (GstGLShader * shader, const gchar * name, |
| gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix4fv (location, count, transpose, value); |
| } |
| |
| #if GST_GL_HAVE_OPENGL |
| void |
| gst_gl_shader_set_uniform_matrix_2x3fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix2x3fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_2x4fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix2x4fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_3x2fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix3x2fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_3x4fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix3x4fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_4x2fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix4x2fv (location, count, transpose, value); |
| } |
| |
| void |
| gst_gl_shader_set_uniform_matrix_4x3fv (GstGLShader * shader, |
| const gchar * name, gint count, gboolean transpose, const gfloat * value) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| GLint location = -1; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| location = gl->GetUniformLocation (priv->program_handle, name); |
| |
| gl->UniformMatrix4x3fv (location, count, transpose, value); |
| } |
| #endif /* GST_GL_HAVE_OPENGL */ |
| |
| GLint |
| gst_gl_shader_get_attribute_location (GstGLShader * shader, const gchar * name) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| |
| g_return_val_if_fail (shader != NULL, -1); |
| priv = shader->priv; |
| g_return_val_if_fail (priv->program_handle != 0, -1); |
| if (0 == priv->vertex_handle) |
| return -1; |
| |
| gl = shader->context->gl_vtable; |
| |
| return gl->GetAttribLocation (priv->program_handle, name); |
| } |
| |
| void |
| gst_gl_shader_bind_attribute_location (GstGLShader * shader, GLuint index, |
| const gchar * name) |
| { |
| GstGLShaderPrivate *priv; |
| GstGLFuncs *gl; |
| |
| g_return_if_fail (shader != NULL); |
| priv = shader->priv; |
| g_return_if_fail (priv->program_handle != 0); |
| gl = shader->context->gl_vtable; |
| |
| gl->BindAttribLocation (priv->program_handle, index, name); |
| } |
| |
| GQuark |
| gst_gl_shader_error_quark (void) |
| { |
| return g_quark_from_static_string ("gst-gl-shader-error"); |
| } |