Blame gst-libs/gst/gl/gstglsl.c

Packit 971217
/*
Packit 971217
 * GStreamer
Packit 971217
 * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
#include <gst/gl/gl.h>
Packit 971217
Packit 971217
#include "gstglsl.h"
Packit 971217
#include "gstglsl_private.h"
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:gstglsl
Packit 971217
 * @title: GstGLSL
Packit 971217
 * @short_description: helpers for dealing with OpenGL shaders
Packit 971217
 * @see_also: #GstGLSLStage, #GstGLShader
Packit 971217
 */
Packit 971217
Packit 971217
#define GST_CAT_DEFAULT gst_glsl_debug
Packit 971217
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
Packit 971217
Packit 971217
static void
Packit 971217
_init_debug (void)
Packit 971217
{
Packit 971217
  static volatile gsize _init = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter (&_init)) {
Packit 971217
    GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glsl", 0,
Packit 971217
        "OpenGL Shading Language");
Packit 971217
    g_once_init_leave (&_init, 1);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
GQuark
Packit 971217
gst_glsl_error_quark (void)
Packit 971217
{
Packit 971217
  return g_quark_from_static_string ("gst-glsl-error");
Packit 971217
}
Packit 971217
Packit 971217
struct glsl_version_string
Packit 971217
{
Packit 971217
  GstGLSLVersion version;
Packit 971217
  const gchar *name;
Packit 971217
};
Packit 971217
Packit 971217
static const struct glsl_version_string glsl_versions[] = {
Packit 971217
  /* keep in sync with definition in the header */
Packit 971217
  {GST_GLSL_VERSION_100, "100"},
Packit 971217
  {GST_GLSL_VERSION_110, "110"},
Packit 971217
  {GST_GLSL_VERSION_120, "120"},
Packit 971217
  {GST_GLSL_VERSION_130, "130"},
Packit 971217
  {GST_GLSL_VERSION_140, "140"},
Packit 971217
  {GST_GLSL_VERSION_150, "150"},
Packit 971217
  {GST_GLSL_VERSION_300, "300"},
Packit 971217
  {GST_GLSL_VERSION_310, "310"},
Packit 971217
  {GST_GLSL_VERSION_320, "320"},
Packit 971217
  {GST_GLSL_VERSION_330, "330"},
Packit 971217
  {GST_GLSL_VERSION_400, "400"},
Packit 971217
  {GST_GLSL_VERSION_410, "410"},
Packit 971217
  {GST_GLSL_VERSION_420, "420"},
Packit 971217
  {GST_GLSL_VERSION_430, "430"},
Packit 971217
  {GST_GLSL_VERSION_440, "440"},
Packit 971217
  {GST_GLSL_VERSION_450, "450"},
Packit 971217
};
Packit 971217
Packit 971217
struct glsl_profile_string
Packit 971217
{
Packit 971217
  GstGLSLProfile profile;
Packit 971217
  const gchar *name;
Packit 971217
};
Packit 971217
Packit 971217
static const struct glsl_profile_string glsl_profiles[] = {
Packit 971217
  /* keep in sync with definition in the header */
Packit 971217
  {GST_GLSL_PROFILE_ES, "es"},
Packit 971217
  {GST_GLSL_PROFILE_CORE, "core"},
Packit 971217
  {GST_GLSL_PROFILE_COMPATIBILITY, "compatibility"},
Packit 971217
};
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_version_to_string:
Packit 971217
 * @version: a #GstGLSLVersion
Packit 971217
 *
Packit 971217
 * Returns: (nullable): the name of @version or %NULL on error
Packit 971217
 */
Packit 971217
const gchar *
Packit 971217
gst_glsl_version_to_string (GstGLSLVersion version)
Packit 971217
{
Packit 971217
  int i;
Packit 971217
Packit 971217
  if (version == GST_GLSL_VERSION_NONE)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  for (i = 0; i < G_N_ELEMENTS (glsl_versions); i++) {
Packit 971217
    if (version == glsl_versions[i].version)
Packit 971217
      return glsl_versions[i].name;
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_version_from_string:
Packit 971217
 * @string: a GLSL version string
Packit 971217
 *
Packit 971217
 * Returns: the #GstGLSLVersion of @string or %GST_GLSL_VERSION_NONE on error
Packit 971217
 */
Packit 971217
GstGLSLVersion
Packit 971217
gst_glsl_version_from_string (const gchar * string)
Packit 971217
{
Packit 971217
  gchar *str;
Packit 971217
  int i;
Packit 971217
Packit 971217
  if (string == NULL)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  str = g_strdup (string);
Packit 971217
  str = g_strstrip (str);
Packit 971217
Packit 971217
  for (i = 0; i < G_N_ELEMENTS (glsl_versions); i++) {
Packit 971217
    if (g_strcmp0 (str, glsl_versions[i].name) == 0) {
Packit 971217
      g_free (str);
Packit 971217
      return glsl_versions[i].version;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  g_free (str);
Packit 971217
  return 0;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_profile_to_string:
Packit 971217
 * @profile: a #GstGLSLProfile
Packit 971217
 *
Packit 971217
 * Returns: (nullable): the name for @profile or %NULL on error
Packit 971217
 */
Packit 971217
const gchar *
Packit 971217
gst_glsl_profile_to_string (GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  int i;
Packit 971217
Packit 971217
  if (profile == GST_GLSL_PROFILE_NONE)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  /* multiple profiles are not allowed */
Packit 971217
  if ((profile & (profile - 1)) != 0)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  for (i = 0; i < G_N_ELEMENTS (glsl_profiles); i++) {
Packit 971217
    if (profile == glsl_profiles[i].profile)
Packit 971217
      return glsl_profiles[i].name;
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_profile_from_string:
Packit 971217
 * @string: a GLSL version string
Packit 971217
 *
Packit 971217
 * Returns: the #GstGLSLProfile of @string or %GST_GLSL_PROFILE_NONE on error
Packit 971217
 */
Packit 971217
GstGLSLProfile
Packit 971217
gst_glsl_profile_from_string (const gchar * string)
Packit 971217
{
Packit 971217
  gchar *str;
Packit 971217
  int i;
Packit 971217
Packit 971217
  if (string == NULL)
Packit 971217
    return GST_GLSL_PROFILE_NONE;
Packit 971217
Packit 971217
  str = g_strdup (string);
Packit 971217
  str = g_strstrip (str);
Packit 971217
Packit 971217
  for (i = 0; i < G_N_ELEMENTS (glsl_profiles); i++) {
Packit 971217
    if (g_strcmp0 (str, glsl_profiles[i].name) == 0) {
Packit 971217
      g_free (str);
Packit 971217
      return glsl_profiles[i].profile;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  g_free (str);
Packit 971217
  return GST_GLSL_PROFILE_NONE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_is_valid_version_profile (GstGLSLVersion version, GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  if (version == GST_GLSL_VERSION_NONE)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  /* versions that may not need an explicit profile */
Packit 971217
  if (version <= GST_GLSL_VERSION_150 && profile == GST_GLSL_PROFILE_NONE)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  /* ES versions require an ES profile */
Packit 971217
  if (version == GST_GLSL_VERSION_100 || version == GST_GLSL_VERSION_300
Packit 971217
      || version == GST_GLSL_VERSION_310 || version == GST_GLSL_VERSION_320)
Packit 971217
    return profile == GST_GLSL_PROFILE_ES;
Packit 971217
Packit 971217
  /* required profile and no ES profile for normal GL contexts */
Packit 971217
  if (version == GST_GLSL_VERSION_150 || version >= GST_GLSL_VERSION_330)
Packit 971217
    return profile == GST_GLSL_PROFILE_NONE || profile == GST_GLSL_PROFILE_CORE
Packit 971217
        || profile == GST_GLSL_PROFILE_COMPATIBILITY;
Packit 971217
Packit 971217
  if (version <= GST_GLSL_VERSION_140)
Packit 971217
    return profile == GST_GLSL_PROFILE_NONE
Packit 971217
        || profile == GST_GLSL_PROFILE_COMPATIBILITY;
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_version_profile_to_string:
Packit 971217
 * @version: a #GstGLSLVersion
Packit 971217
 * @profile: a #GstGLSLVersion
Packit 971217
 *
Packit 971217
 * Returns: the combined GLSL #version string for @version and @profile
Packit 971217
 */
Packit 971217
gchar *
Packit 971217
gst_glsl_version_profile_to_string (GstGLSLVersion version,
Packit 971217
    GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  const gchar *version_s, *profile_s;
Packit 971217
Packit 971217
  if (!_is_valid_version_profile (version, profile))
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  version_s = gst_glsl_version_to_string (version);
Packit 971217
  /* no profiles in GL/ES <= 150 */
Packit 971217
  if (version <= GST_GLSL_VERSION_140)
Packit 971217
    profile_s = NULL;
Packit 971217
  else
Packit 971217
    profile_s = gst_glsl_profile_to_string (profile);
Packit 971217
Packit 971217
  if (!version_s)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  if (profile_s)
Packit 971217
    return g_strdup_printf ("%s %s", version_s, profile_s);
Packit 971217
Packit 971217
  return g_strdup (version_s);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_fixup_version_profile (GstGLSLVersion * version, GstGLSLProfile * profile)
Packit 971217
{
Packit 971217
  if (*version == GST_GLSL_VERSION_100 || *version == GST_GLSL_VERSION_300
Packit 971217
      || *version == GST_GLSL_VERSION_310 || *version == GST_GLSL_VERSION_320)
Packit 971217
    *profile = GST_GLSL_PROFILE_ES;
Packit 971217
  else if (*version <= GST_GLSL_VERSION_140)
Packit 971217
    *profile = GST_GLSL_PROFILE_COMPATIBILITY;
Packit 971217
  else if (*profile == GST_GLSL_PROFILE_NONE
Packit 971217
      && (*version >= GST_GLSL_VERSION_150 || *version >= GST_GLSL_VERSION_330))
Packit 971217
    *profile = GST_GLSL_PROFILE_CORE;
Packit 971217
}
Packit 971217
Packit 971217
/* @str points to the start of "#version", "#    version" or "#\tversion", etc */
Packit 971217
static const gchar *
Packit 971217
_check_valid_version_preprocessor_string (const gchar * str)
Packit 971217
{
Packit 971217
  gint i = 0;
Packit 971217
Packit 971217
  if (!str || !str[i])
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  /* there can be whitespace between the '#' and 'version' */
Packit 971217
  do {
Packit 971217
    i++;
Packit 971217
    if (str[i] == '\0' || str[i] == '\n' || str[i] == '\r')
Packit 971217
      return NULL;
Packit 971217
  } while (g_ascii_isspace (str[i]));
Packit 971217
  if (g_strstr_len (&str[i], 7, "version"))
Packit 971217
    return &str[i + 7];
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_version_profile_from_string:
Packit 971217
 * @string: a valid GLSL #version string
Packit 971217
 * @version_ret: (out): resulting #GstGLSLVersion
Packit 971217
 * @profile_ret: (out): resulting #GstGLSLVersion
Packit 971217
 *
Packit 971217
 * Note: this function expects either a #version GLSL preprocesser directive
Packit 971217
 * or a valid GLSL version and/or profile.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if a valid #version string was found, FALSE otherwise
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_glsl_version_profile_from_string (const gchar * string,
Packit 971217
    GstGLSLVersion * version_ret, GstGLSLProfile * profile_ret)
Packit 971217
{
Packit 971217
  gchar *str, *version_s, *profile_s;
Packit 971217
  GstGLSLVersion version = GST_GLSL_VERSION_NONE;
Packit 971217
  GstGLSLProfile profile = GST_GLSL_PROFILE_NONE;
Packit 971217
  gint i;
Packit 971217
Packit 971217
  _init_debug ();
Packit 971217
Packit 971217
  if (!string)
Packit 971217
    goto error;
Packit 971217
Packit 971217
  str = g_strdup (string);
Packit 971217
  version_s = g_strstrip (str);
Packit 971217
Packit 971217
  /* skip possible #version prefix */
Packit 971217
  if (str[0] == '#') {
Packit 971217
    if (!(version_s =
Packit 971217
            (gchar *) _check_valid_version_preprocessor_string (version_s))) {
Packit 971217
      GST_WARNING ("Invalid preprocesser directive detected: %s", version_s);
Packit 971217
      g_free (str);
Packit 971217
      goto error;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  version_s = g_strstrip (version_s);
Packit 971217
Packit 971217
  i = 0;
Packit 971217
  while (version_s && version_s[i] != '\0' && g_ascii_isdigit (version_s[i]))
Packit 971217
    i++;
Packit 971217
  /* wrong version length */
Packit 971217
  if (i != 3) {
Packit 971217
    GST_WARNING ("version number has the wrong number of digits: %s",
Packit 971217
        version_s);
Packit 971217
    g_free (str);
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
Packit 971217
  if (version_s[i] != 0) {
Packit 971217
    version_s[i] = '\0';
Packit 971217
    i++;
Packit 971217
    profile_s = &version_s[i];
Packit 971217
    profile_s = g_strstrip (profile_s);
Packit 971217
Packit 971217
    profile = gst_glsl_profile_from_string (profile_s);
Packit 971217
  }
Packit 971217
  version = gst_glsl_version_from_string (version_s);
Packit 971217
  g_free (str);
Packit 971217
Packit 971217
  /* check whether the parsed data is valid */
Packit 971217
  if (!version) {
Packit 971217
    GST_WARNING ("Could not map the version number to a valid GLSL version:");
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
  if (!_is_valid_version_profile (version, profile)) {
Packit 971217
    GST_WARNING ("Invalid version/profile combination specified: %s %s",
Packit 971217
        gst_glsl_version_to_string (version),
Packit 971217
        gst_glsl_profile_to_string (profile));
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
  /* got a profile when none was expected */
Packit 971217
  if (version <= GST_GLSL_VERSION_140 && profile != GST_GLSL_PROFILE_NONE) {
Packit 971217
    GST_WARNING
Packit 971217
        ("Found a profile (%s) with a version (%s) that does not support "
Packit 971217
        "profiles", gst_glsl_version_to_string (version),
Packit 971217
        gst_glsl_profile_to_string (profile));
Packit 971217
    goto error;
Packit 971217
  }
Packit 971217
Packit 971217
  _fixup_version_profile (&version, &profile);
Packit 971217
Packit 971217
  if (profile_ret)
Packit 971217
    *profile_ret = profile;
Packit 971217
  if (version_ret)
Packit 971217
    *version_ret = version;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
error:
Packit 971217
  {
Packit 971217
    if (profile_ret)
Packit 971217
      *profile_ret = GST_GLSL_PROFILE_NONE;
Packit 971217
    if (version_ret)
Packit 971217
      *version_ret = GST_GLSL_VERSION_NONE;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* returns the pointer in @str to the #version declaration */
Packit 971217
const gchar *
Packit 971217
_gst_glsl_shader_string_find_version (const gchar * str)
Packit 971217
{
Packit 971217
  gboolean sl_comment = FALSE;
Packit 971217
  gboolean ml_comment = FALSE;
Packit 971217
  gboolean newline = TRUE;
Packit 971217
  gint i = 0;
Packit 971217
Packit 971217
  _init_debug ();
Packit 971217
Packit 971217
  /* search for #version while allowing for preceeding comments/whitespace as
Packit 971217
   * permitted by the GLSL specification */
Packit 971217
  while (str && str[i] != '\0' && i < 1024) {
Packit 971217
    if (str[i] == '\n' || str[i] == '\r') {
Packit 971217
      newline = TRUE;
Packit 971217
      sl_comment = FALSE;
Packit 971217
      i++;
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
Packit 971217
    if (g_ascii_isspace (str[i]))
Packit 971217
      goto next;
Packit 971217
Packit 971217
    if (sl_comment)
Packit 971217
      goto next;
Packit 971217
Packit 971217
    if (ml_comment) {
Packit 971217
      if (g_strstr_len (&str[i], 2, "*/")) {
Packit 971217
        ml_comment = FALSE;
Packit 971217
        i++;
Packit 971217
      }
Packit 971217
      goto next;
Packit 971217
    }
Packit 971217
Packit 971217
    if (g_strstr_len (&str[i], 2, "//")) {
Packit 971217
      sl_comment = TRUE;
Packit 971217
      i++;
Packit 971217
      goto next;
Packit 971217
    }
Packit 971217
Packit 971217
    if (g_strstr_len (&str[i], 2, "/*")) {
Packit 971217
      ml_comment = TRUE;
Packit 971217
      i++;
Packit 971217
      goto next;
Packit 971217
    }
Packit 971217
Packit 971217
    if (str[i] == '#') {
Packit 971217
      if (newline && _check_valid_version_preprocessor_string (&str[i])) {
Packit 971217
        GST_DEBUG ("found #version declaration at index %i", i);
Packit 971217
        return &str[i];
Packit 971217
      }
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
  next:
Packit 971217
    newline = FALSE;
Packit 971217
    i++;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG ("no #version declaration found in the first 1K");
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_glsl_string_get_version_profile:
Packit 971217
 * @s: string to search for a valid #version string
Packit 971217
 * @version: (out): resulting #GstGLSLVersion
Packit 971217
 * @profile: (out): resulting #GstGLSLProfile
Packit 971217
 *
Packit 971217
 * Note: this function first searches the first 1 kilobytes for a #version
Packit 971217
 * preprocessor directive and then executes gst_glsl_version_profile_from_string().
Packit 971217
 *
Packit 971217
 * Returns: TRUE if a valid #version string was found, FALSE otherwise
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_glsl_string_get_version_profile (const gchar * s, GstGLSLVersion * version,
Packit 971217
    GstGLSLProfile * profile)
Packit 971217
{
Packit 971217
  const gchar *version_profile_s;
Packit 971217
Packit 971217
  version_profile_s = _gst_glsl_shader_string_find_version (s);
Packit 971217
  if (!version_profile_s)
Packit 971217
    goto error;
Packit 971217
Packit 971217
  if (!gst_glsl_version_profile_from_string (version_profile_s, version,
Packit 971217
          profile))
Packit 971217
    goto error;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
error:
Packit 971217
  {
Packit 971217
    if (version)
Packit 971217
      *version = GST_GLSL_VERSION_NONE;
Packit 971217
    if (profile)
Packit 971217
      *profile = GST_GLSL_PROFILE_NONE;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_version_to_glsl_version:
Packit 971217
 * @gl_api: the #GstGLAPI
Packit 971217
 * @maj: the major GL version
Packit 971217
 * @min: the minor GL version
Packit 971217
 *
Packit 971217
 * Returns: The minimum supported #GstGLSLVersion available for @gl_api, @maj and @min
Packit 971217
 */
Packit 971217
GstGLSLVersion
Packit 971217
gst_gl_version_to_glsl_version (GstGLAPI gl_api, gint maj, gint min)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (gl_api != GST_GL_API_NONE, 0);
Packit 971217
Packit 971217
  _init_debug ();
Packit 971217
Packit 971217
  if (gl_api & GST_GL_API_GLES2) {
Packit 971217
    if (maj == 2 && min == 0)
Packit 971217
      return 100;
Packit 971217
Packit 971217
    if (maj == 3 && min >= 0 && min <= 2)
Packit 971217
      return maj * 100 + min * 10;
Packit 971217
Packit 971217
    GST_WARNING ("unknown GLES version");
Packit 971217
    return 0;
Packit 971217
  }
Packit 971217
Packit 971217
  /* versions match for >= 3.3 */
Packit 971217
  if (gl_api & (GST_GL_API_OPENGL3 | GST_GL_API_OPENGL)) {
Packit 971217
    if (maj > 3 || (maj == 3 && min >= 3))
Packit 971217
      return maj * 100 + min * 10;
Packit 971217
Packit 971217
    if (maj == 3 && min == 2)
Packit 971217
      return 150;
Packit 971217
    if (maj == 3 && min == 1)
Packit 971217
      return 140;
Packit 971217
    if (maj == 3 && min == 0)
Packit 971217
      return 130;
Packit 971217
    if (maj == 2 && min == 1)
Packit 971217
      return 120;
Packit 971217
    if (maj == 2 && min == 0)
Packit 971217
      return 110;
Packit 971217
Packit 971217
    GST_WARNING ("unknown GL version");
Packit 971217
    return 0;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_WARNING ("unknown GL API");
Packit 971217
  return 0;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_gl_context_supports_glsl_profile_version:
Packit 971217
 * @context: a #GstGLContext
Packit 971217
 * @version: a #GstGLSLVersion
Packit 971217
 * @profile: a #GstGLSLProfile
Packit 971217
 *
Packit 971217
 * Returns: Whether @context supports the combination of @version with @profile
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_gl_context_supports_glsl_profile_version (GstGLContext * context,
Packit 971217
    GstGLSLVersion version, GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
Packit 971217
Packit 971217
  if (!_is_valid_version_profile (version, profile))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (profile != GST_GLSL_PROFILE_NONE) {
Packit 971217
    if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0)) {
Packit 971217
      if ((profile & GST_GLSL_PROFILE_ES) == 0)
Packit 971217
        return FALSE;
Packit 971217
    } else if ((gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) != 0) {
Packit 971217
      if ((profile & GST_GLSL_PROFILE_COMPATIBILITY) == 0)
Packit 971217
        return FALSE;
Packit 971217
    } else if ((gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3) != 0) {
Packit 971217
      /* GL_ARB_es2_compatibility is requried for GL3 contexts */
Packit 971217
      if ((profile & (GST_GLSL_PROFILE_CORE | GST_GLSL_PROFILE_ES)) == 0)
Packit 971217
        return FALSE;
Packit 971217
    } else {
Packit 971217
      g_assert_not_reached ();
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (version != GST_GLSL_VERSION_NONE) {
Packit 971217
    GstGLAPI gl_api;
Packit 971217
    gint maj, min, glsl_version;
Packit 971217
Packit 971217
    if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 1)) {
Packit 971217
      if (version > GST_GLSL_VERSION_310)
Packit 971217
        return FALSE;
Packit 971217
    } else if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3,
Packit 971217
            0)) {
Packit 971217
      if (version > GST_GLSL_VERSION_300)
Packit 971217
        return FALSE;
Packit 971217
    } else if (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2,
Packit 971217
            0)) {
Packit 971217
      if (version > GST_GLSL_VERSION_100)
Packit 971217
        return FALSE;
Packit 971217
    }
Packit 971217
Packit 971217
    gl_api = gst_gl_context_get_gl_api (context);
Packit 971217
    gst_gl_context_get_gl_version (context, &maj, &min);
Packit 971217
    glsl_version = gst_gl_version_to_glsl_version (gl_api, maj, min);
Packit 971217
    if (version > glsl_version)
Packit 971217
      return FALSE;
Packit 971217
Packit 971217
    if (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 1, 0))
Packit 971217
      /* GL_ARB_es2_compatibility is requried for GL3 contexts */
Packit 971217
      if (version < GST_GLSL_VERSION_150 && version != GST_GLSL_VERSION_100)
Packit 971217
        return FALSE;
Packit 971217
Packit 971217
    if (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0)
Packit 971217
        && version < GST_GLSL_VERSION_110)
Packit 971217
      return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
gboolean
Packit 971217
_gst_glsl_funcs_fill (GstGLSLFuncs * vtable, GstGLContext * context)
Packit 971217
{
Packit 971217
  GstGLFuncs *gl = context->gl_vtable;
Packit 971217
Packit 971217
  if (vtable->initialized)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  if (gl->CreateProgram) {
Packit 971217
    vtable->CreateProgram = gl->CreateProgram;
Packit 971217
    vtable->DeleteProgram = gl->DeleteProgram;
Packit 971217
    vtable->UseProgram = gl->UseProgram;
Packit 971217
Packit 971217
    vtable->CreateShader = gl->CreateShader;
Packit 971217
    vtable->DeleteShader = gl->DeleteShader;
Packit 971217
    vtable->AttachShader = gl->AttachShader;
Packit 971217
    vtable->DetachShader = gl->DetachShader;
Packit 971217
Packit 971217
    vtable->GetAttachedShaders = gl->GetAttachedShaders;
Packit 971217
Packit 971217
    vtable->GetShaderInfoLog = gl->GetShaderInfoLog;
Packit 971217
    vtable->GetShaderiv = gl->GetShaderiv;
Packit 971217
    vtable->GetProgramInfoLog = gl->GetProgramInfoLog;
Packit 971217
    vtable->GetProgramiv = gl->GetProgramiv;
Packit 971217
  } else if (gl->CreateProgramObject) {
Packit 971217
    vtable->CreateProgram = gl->CreateProgramObject;
Packit 971217
    vtable->DeleteProgram = gl->DeleteObject;
Packit 971217
    vtable->UseProgram = gl->UseProgramObject;
Packit 971217
Packit 971217
    vtable->CreateShader = gl->CreateShaderObject;
Packit 971217
    vtable->DeleteShader = gl->DeleteObject;
Packit 971217
    vtable->AttachShader = gl->AttachObject;
Packit 971217
    vtable->DetachShader = gl->DetachObject;
Packit 971217
Packit 971217
    vtable->GetAttachedShaders = gl->GetAttachedObjects;
Packit 971217
Packit 971217
    vtable->GetShaderInfoLog = gl->GetInfoLog;
Packit 971217
    vtable->GetShaderiv = gl->GetObjectParameteriv;
Packit 971217
    vtable->GetProgramInfoLog = gl->GetInfoLog;
Packit 971217
    vtable->GetProgramiv = gl->GetObjectParameteriv;
Packit 971217
  } else {
Packit 971217
    vtable->initialized = FALSE;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  vtable->initialized = TRUE;
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
_mangle_external_image_extension (const gchar * str, GstGLContext * context,
Packit 971217
    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
Packit 971217
    GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  GST_DEBUG ("is oes? %d, profile == ES? %d, version >= 300? %d, "
Packit 971217
      "have essl3? %d", to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES,
Packit 971217
      profile == GST_GLSL_PROFILE_ES, version >= GST_GLSL_VERSION_300,
Packit 971217
      gst_gl_context_check_feature (context,
Packit 971217
          "GL_OES_EGL_image_external_essl3"));
Packit 971217
Packit 971217
  /* replace GL_OES_EGL_image_external with GL_OES_EGL_image_external_essl3 where supported */
Packit 971217
  if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES && profile == GST_GLSL_PROFILE_ES
Packit 971217
      && version >= GST_GLSL_VERSION_300) {
Packit 971217
    if (gst_gl_context_check_feature (context,
Packit 971217
            "GL_OES_EGL_image_external_essl3")) {
Packit 971217
      GRegex *regex = g_regex_new (
Packit 971217
          /* '#extension ' with optional spacing */
Packit 971217
          "(#[ \\t]*extension[ \\t]+)"
Packit 971217
          /* what we're looking to replace */
Packit 971217
          "GL_OES_EGL_image_external"
Packit 971217
          /* ':' with optional spacing */
Packit 971217
          "([ \\t]*:[ \\t]*"
Packit 971217
          /* some word like require, disable, etc followed by spacing and a newline */
Packit 971217
          "\\S+[ \\t]*\\R)",
Packit 971217
          0, 0, NULL);
Packit 971217
      gchar *tmp = g_regex_replace (regex, str, -1, 0,
Packit 971217
          "\\1GL_OES_EGL_image_external_essl3\\2", 0, NULL);
Packit 971217
      g_regex_unref (regex);
Packit 971217
      return tmp;
Packit 971217
    } else {
Packit 971217
      GST_FIXME ("Undefined situation detected. GLES3 supported but "
Packit 971217
          "GL_OES_EGL_image_external_essl3 not supported.  Falling back to the "
Packit 971217
          "older GL_OES_EGL_image_external extension");
Packit 971217
      return g_strdup (str);
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    return g_strdup (str);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
_mangle_texture_access (const gchar * str, GstGLContext * context,
Packit 971217
    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion version,
Packit 971217
    GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  const gchar *from_str = NULL, *to_str = NULL;
Packit 971217
  gchar *ret, *tmp;
Packit 971217
  gchar *regex_find;
Packit 971217
  GRegex *regex;
Packit 971217
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_2D)
Packit 971217
    from_str = "texture2D";
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_RECTANGLE)
Packit 971217
    from_str = "texture2DRect";
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
Packit 971217
    from_str = "texture2D";
Packit 971217
Packit 971217
  /* GL3 || gles3 but not when external-oes unless the image_external_essl3 extension is supported */
Packit 971217
  if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
Packit 971217
          && version >= GST_GLSL_VERSION_300
Packit 971217
          && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
Packit 971217
              || gst_gl_context_check_feature (context,
Packit 971217
                  "GL_OES_EGL_image_external_essl3")))) {
Packit 971217
    to_str = "texture";
Packit 971217
  } else {
Packit 971217
    if (to == GST_GL_TEXTURE_TARGET_2D)
Packit 971217
      to_str = "texture2D";
Packit 971217
    if (to == GST_GL_TEXTURE_TARGET_RECTANGLE)
Packit 971217
      to_str = "texture2DRect";
Packit 971217
    if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
Packit 971217
      to_str = "texture2D";
Packit 971217
  }
Packit 971217
Packit 971217
  /* followed by any amount of whitespace then a bracket */
Packit 971217
  regex_find = g_strdup_printf ("%s(?=\\s*\\()", from_str);
Packit 971217
  regex = g_regex_new (regex_find, 0, 0, NULL);
Packit 971217
  tmp = g_regex_replace_literal (regex, str, -1, 0, to_str, 0, NULL);
Packit 971217
  g_free (regex_find);
Packit 971217
  g_regex_unref (regex);
Packit 971217
Packit 971217
  if (tmp) {
Packit 971217
    ret = tmp;
Packit 971217
  } else {
Packit 971217
    GST_FIXME ("Couldn't mangle texture access successfully from %s to %s",
Packit 971217
        from_str, to_str);
Packit 971217
    ret = g_strdup (str);
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
_mangle_sampler_type (const gchar * str, GstGLTextureTarget from,
Packit 971217
    GstGLTextureTarget to)
Packit 971217
{
Packit 971217
  const gchar *from_str = NULL, *to_str = NULL;
Packit 971217
  gchar *ret, *tmp;
Packit 971217
  gchar *regex_find;
Packit 971217
  GRegex *regex;
Packit 971217
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_2D)
Packit 971217
    from_str = "sampler2D";
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_RECTANGLE)
Packit 971217
    from_str = "sampler2DRect";
Packit 971217
  if (from == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
Packit 971217
    from_str = "samplerExternalOES";
Packit 971217
Packit 971217
  if (to == GST_GL_TEXTURE_TARGET_2D)
Packit 971217
    to_str = "sampler2D";
Packit 971217
  if (to == GST_GL_TEXTURE_TARGET_RECTANGLE)
Packit 971217
    to_str = "sampler2DRect";
Packit 971217
  if (to == GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
Packit 971217
    to_str = "samplerExternalOES";
Packit 971217
Packit 971217
  /* followed by some whitespace  */
Packit 971217
  regex_find = g_strdup_printf ("%s(?=\\s)", from_str);
Packit 971217
  regex = g_regex_new (regex_find, 0, 0, NULL);
Packit 971217
  tmp = g_regex_replace_literal (regex, str, -1, 0, to_str, 0, NULL);
Packit 971217
  g_free (regex_find);
Packit 971217
  g_regex_unref (regex);
Packit 971217
Packit 971217
  if (tmp) {
Packit 971217
    ret = tmp;
Packit 971217
  } else {
Packit 971217
    GST_FIXME ("Couldn't mangle sampler type successfully from %s to %s",
Packit 971217
        from_str, to_str);
Packit 971217
    ret = g_strdup (str);
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
_mangle_varying_attribute (const gchar * str, guint shader_type,
Packit 971217
    GstGLSLVersion version, GstGLSLProfile profile)
Packit 971217
{
Packit 971217
  if (shader_type == GL_VERTEX_SHADER) {
Packit 971217
    if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
Packit 971217
            && version >= GST_GLSL_VERSION_300)) {
Packit 971217
      gchar *tmp, *tmp2;
Packit 971217
      GRegex *regex;
Packit 971217
Packit 971217
      /* followed by some whitespace  */
Packit 971217
      regex = g_regex_new ("varying(?=\\s)", 0, 0, NULL);
Packit 971217
      tmp = g_regex_replace_literal (regex, str, -1, 0, "out", 0, NULL);
Packit 971217
      g_regex_unref (regex);
Packit 971217
Packit 971217
      /* followed by some whitespace  */
Packit 971217
      regex = g_regex_new ("attribute(?=\\s)", 0, 0, NULL);
Packit 971217
      tmp2 = g_regex_replace_literal (regex, tmp, -1, 0, "in", 0, NULL);
Packit 971217
      g_regex_unref (regex);
Packit 971217
Packit 971217
      g_free (tmp);
Packit 971217
      return tmp2;
Packit 971217
    }
Packit 971217
  } else if (shader_type == GL_FRAGMENT_SHADER) {
Packit 971217
    if (profile == GST_GLSL_PROFILE_CORE || (profile == GST_GLSL_PROFILE_ES
Packit 971217
            && version >= GST_GLSL_VERSION_300)) {
Packit 971217
      gchar *tmp;
Packit 971217
      GRegex *regex;
Packit 971217
Packit 971217
      /* followed by some whitespace  */
Packit 971217
      regex = g_regex_new ("varying(?=\\s)", 0, 0, NULL);
Packit 971217
      tmp = g_regex_replace_literal (regex, str, -1, 0, "in", 0, NULL);
Packit 971217
      g_regex_unref (regex);
Packit 971217
Packit 971217
      return tmp;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  return g_strdup (str);
Packit 971217
}
Packit 971217
Packit 971217
static gchar *
Packit 971217
_mangle_frag_color_data (const gchar * str)
Packit 971217
{
Packit 971217
  GRegex *regex;
Packit 971217
  gchar *ret, *tmp;
Packit 971217
Packit 971217
  regex = g_regex_new ("gl_FragColor", 0, 0, NULL);
Packit 971217
  ret = g_regex_replace_literal (regex, str, -1, 0, "fragColor", 0, NULL);
Packit 971217
  g_regex_unref (regex);
Packit 971217
Packit 971217
  tmp = ret;
Packit 971217
  /* search and replace 'gl_FragData[NUM]' into fragColor_NUM */
Packit 971217
  regex = g_regex_new ("gl_FragData\\[(\\d+)\\]", 0, 0, NULL);
Packit 971217
  ret = g_regex_replace (regex, tmp, -1, 0, "fragColor_\\1", 0, NULL);
Packit 971217
  g_regex_unref (regex);
Packit 971217
  g_free (tmp);
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_mangle_version_profile_from_gl_api (GstGLContext * context,
Packit 971217
    GstGLTextureTarget from, GstGLTextureTarget to, GstGLSLVersion * version,
Packit 971217
    GstGLSLProfile * profile)
Packit 971217
{
Packit 971217
  GstGLAPI gl_api;
Packit 971217
  gint gl_major, gl_minor;
Packit 971217
Packit 971217
  gl_api = gst_gl_context_get_gl_api (context);
Packit 971217
  gst_gl_context_get_gl_version (context, &gl_major, &gl_minor);
Packit 971217
Packit 971217
  *version = GST_GLSL_VERSION_NONE;
Packit 971217
  *profile = GST_GLSL_PROFILE_NONE;
Packit 971217
Packit 971217
  if (gl_api & GST_GL_API_OPENGL3) {
Packit 971217
    if (gl_major > 3 || gl_minor >= 3) {
Packit 971217
      *version = GST_GLSL_VERSION_330;
Packit 971217
      *profile = GST_GLSL_PROFILE_CORE;
Packit 971217
    } else {
Packit 971217
      *version = GST_GLSL_VERSION_150;
Packit 971217
      *profile = GST_GLSL_PROFILE_NONE;
Packit 971217
    }
Packit 971217
  } else if (gl_api & GST_GL_API_GLES2) {
Packit 971217
    /* We don't know which texture function to use if we have GLES3 and
Packit 971217
     * don't have the essl3 extension */
Packit 971217
    if (gl_major >= 3 && (to != GST_GL_TEXTURE_TARGET_EXTERNAL_OES
Packit 971217
            || gst_gl_context_check_feature (context,
Packit 971217
                "GL_OES_EGL_image_external_essl3"))) {
Packit 971217
      *version = GST_GLSL_VERSION_300;
Packit 971217
      *profile = GST_GLSL_PROFILE_ES;
Packit 971217
    } else if (gl_major >= 2) {
Packit 971217
      *version = GST_GLSL_VERSION_100;
Packit 971217
      *profile = GST_GLSL_PROFILE_ES;
Packit 971217
    }
Packit 971217
  } else if (gl_api & GST_GL_API_OPENGL) {
Packit 971217
    *version = GST_GLSL_VERSION_110;
Packit 971217
    *profile = GST_GLSL_PROFILE_COMPATIBILITY;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
gchar *
Packit 971217
_gst_glsl_mangle_shader (const gchar * str, guint shader_type,
Packit 971217
    GstGLTextureTarget from, GstGLTextureTarget to, GstGLContext * context,
Packit 971217
    GstGLSLVersion * version, GstGLSLProfile * profile)
Packit 971217
{
Packit 971217
  gchar *tmp, *tmp2;
Packit 971217
Packit 971217
  _init_debug ();
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
Packit 971217
Packit 971217
  _mangle_version_profile_from_gl_api (context, from, to, version, profile);
Packit 971217
  tmp2 =
Packit 971217
      _mangle_external_image_extension (str, context, from, to, *version,
Packit 971217
      *profile);
Packit 971217
  tmp = _mangle_texture_access (tmp2, context, from, to, *version, *profile);
Packit 971217
  g_free (tmp2);
Packit 971217
  tmp2 = _mangle_sampler_type (tmp, from, to);
Packit 971217
  g_free (tmp);
Packit 971217
  tmp = _mangle_varying_attribute (tmp2, shader_type, *version, *profile);
Packit 971217
  g_free (tmp2);
Packit 971217
  if (shader_type == GL_FRAGMENT_SHADER) {
Packit 971217
    if ((*profile == GST_GLSL_PROFILE_ES && *version >= GST_GLSL_VERSION_300)
Packit 971217
        || (*profile == GST_GLSL_PROFILE_CORE
Packit 971217
            && *version >= GST_GLSL_VERSION_150)) {
Packit 971217
      tmp2 = _mangle_frag_color_data (tmp);
Packit 971217
      g_free (tmp);
Packit 971217
      tmp = tmp2;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  return tmp;
Packit 971217
}