Esempio n. 1
0
static void
_cogl_init_feature_overrides (CoglContext *ctx)
{
  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_VBOS)))
    COGL_FLAGS_SET (ctx->private_features, COGL_PRIVATE_FEATURE_VBOS, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PBOS)))
    COGL_FLAGS_SET (ctx->private_features, COGL_PRIVATE_FEATURE_PBOS, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_GLSL)))
    {
      ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL;
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, FALSE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
                      FALSE);
    }

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_NPOT_TEXTURES)))
    {
      ctx->feature_flags &= ~(COGL_FEATURE_TEXTURE_NPOT |
                              COGL_FEATURE_TEXTURE_NPOT_BASIC |
                              COGL_FEATURE_TEXTURE_NPOT_MIPMAP |
                              COGL_FEATURE_TEXTURE_NPOT_REPEAT);
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, FALSE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, FALSE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, FALSE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, FALSE);
    }
}
static CoglBool
_cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
{
  _COGL_GET_CONTEXT (ctx, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
    return FALSE;

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
    return FALSE;

  /* Vertex snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_vertex_snippets (pipeline))
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* If there is a user program then the appropriate backend for that
   * language should handle it. */
  if (cogl_pipeline_get_user_program (pipeline))
    return FALSE;

  /* The fixed progend can't handle the per-vertex point size
   * attribute */
  if (cogl_pipeline_get_per_vertex_point_size (pipeline))
    return FALSE;

  return TRUE;
}
static gboolean
_cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference,
                                    int n_tex_coord_attribs)
{
  CoglHandle user_program;

  _COGL_GET_CONTEXT (ctx, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
    return FALSE;

  if (ctx->driver == COGL_DRIVER_GLES2)
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* If there is a user program with a fragment shader then the
     appropriate backend for that language should handle it. We can
     still use the fixed fragment backend if the program only contains
     a vertex shader */
  user_program = cogl_pipeline_get_user_program (pipeline);
  if (user_program != COGL_INVALID_HANDLE &&
      _cogl_program_has_fragment_shader (user_program))
    return FALSE;

  _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
  return TRUE;
}
static CoglBool
_cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
{
  _COGL_GET_CONTEXT (ctx, FALSE);

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
    return FALSE;

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
    return FALSE;

  /* Vertex snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_vertex_snippets (pipeline))
    return FALSE;

  /* Validate that we can handle the fragment state using ARBfp
   */

  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ARBFP))
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* The ARBfp progend can't handle the per-vertex point size
   * attribute */
  if (cogl_pipeline_get_per_vertex_point_size (pipeline))
    return FALSE;

  return TRUE;
}
static void
setup_texture_source (CoglPipelineShaderState *shader_state,
                      int unit_index,
                      CoglTextureType texture_type)
{
  if (!shader_state->unit_state[unit_index].sampled)
    {
      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
        g_string_append_printf (shader_state->source,
                                "TEMP texel%d;\n"
                                "MOV texel%d, one;\n",
                                unit_index,
                                unit_index);
      else
        g_string_append_printf (shader_state->source,
                                "TEMP texel%d;\n"
                                "TEX texel%d,fragment.texcoord[%d],"
                                "texture[%d],%s;\n",
                                unit_index,
                                unit_index,
                                unit_index,
                                unit_index,
                                texture_type_to_arbfp_string (texture_type));
      shader_state->unit_state[unit_index].sampled = TRUE;
    }
}
Esempio n. 6
0
static gboolean
cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
                                            PangoFont *font,
                                            PangoGlyph glyph,
                                            CoglPangoGlyphCacheValue *value)
{
  CoglAtlasTexture *texture;
  CoglError *ignore_error = NULL;

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SHARED_ATLAS))
    return FALSE;

  /* If the cache is using mipmapping then we can't use the global
     atlas because it would just get migrated back out */
  if (cache->use_mipmapping)
    return FALSE;

  texture = cogl_atlas_texture_new_with_size (cache->ctx,
                                              value->draw_width,
                                              value->draw_height);
  if (!cogl_texture_allocate (COGL_TEXTURE (texture), &ignore_error))
    {
      cogl_error_free (ignore_error);
      return FALSE;
    }

  value->texture = COGL_TEXTURE (texture);
  value->tx1 = 0;
  value->ty1 = 0;
  value->tx2 = 1;
  value->ty2 = 1;
  value->tx_pixel = 0;
  value->ty_pixel = 0;

  /* The first time we store a texture in the global atlas we'll
     register for notifications when the global atlas is reorganized
     so we can forward the notification on as a glyph
     reorganization */
  if (!cache->using_global_atlas)
    {
      _cogl_atlas_texture_add_reorganize_callback
        (cache->ctx,
         cogl_pango_glyph_cache_reorganize_cb, cache);
      cache->using_global_atlas = TRUE;
    }

  return TRUE;
}
Esempio n. 7
0
static CoglBool
validate_statements_for_context (CoglBlendStringStatement *statements,
                                 int n_statements,
                                 CoglBlendStringContext context,
                                 CoglError **error)
{
  const char *error_string;

  if (n_statements == 1)
    {
      if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
        {
          error_string = "You need to also give a blend statement for the RGB"
                         "channels";
          goto error;
        }
      else if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
        {
          error_string = "You need to also give a blend statement for the "
                         "Alpha channel";
          goto error;
        }
    }

  if (context == COGL_BLEND_STRING_CONTEXT_BLENDING)
    return validate_blend_statements (statements, n_statements, error);
  else
    return validate_tex_combine_statements (statements, n_statements, error);

error:
  _cogl_set_error (error,
                   COGL_BLEND_STRING_ERROR,
                   COGL_BLEND_STRING_ERROR_INVALID_ERROR,
                   "Invalid %s string: %s",
                   context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
                   "blend" : "texture combine",
                   error_string);

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      g_debug ("Invalid %s string: %s",
               context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
               "blend" : "texture combine",
               error_string);
    }

  return FALSE;
}
Esempio n. 8
0
static CoglBool
validate_tex_combine_statements (CoglBlendStringStatement *statements,
                                 int n_statements,
                                 CoglError **error)
{
  int i, j;
  const char *error_string;
  CoglBlendStringError detail = COGL_BLEND_STRING_ERROR_INVALID_ERROR;

  for (i = 0; i < n_statements; i++)
    {
      for (j = 0; j < statements[i].function->argc; j++)
        {
          CoglBlendStringArgument *arg = &statements[i].args[j];
          if (arg->source.is_zero)
            {
              error_string = "You can't use the constant '0' as a texture "
                             "combine argument";
              goto error;
            }
          if (!arg->factor.is_one)
            {
              error_string = "Argument factors are only relevant to blending "
                             "not texture combining";
              goto error;
            }
        }
    }

  return TRUE;

error:
  _cogl_set_error (error,
                   COGL_BLEND_STRING_ERROR,
                   detail,
                   "Invalid texture combine string: %s",
                   error_string);

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      g_debug ("Invalid texture combine string: %s",
               error_string);
    }
  return FALSE;
}
Esempio n. 9
0
static CoglBool
cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
                                            PangoFont *font,
                                            PangoGlyph glyph,
                                            CoglPangoGlyphCacheValue *value)
{
  CoglAtlasTexture *texture;

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SHARED_ATLAS))
    return FALSE;

  /* If the cache is using mipmapping then we can't use the global
     atlas because it would just get migrated back out */
  if (cache->use_mipmapping)
    return FALSE;

  texture = _cogl_atlas_texture_new_with_size (value->draw_width,
                                               value->draw_height,
                                               COGL_TEXTURE_NONE,
                                               COGL_PIXEL_FORMAT_RGBA_8888_PRE);

  if (texture == NULL)
    return FALSE;

  value->texture = COGL_TEXTURE (texture);
  value->tx1 = 0;
  value->ty1 = 0;
  value->tx2 = 1;
  value->ty2 = 1;
  value->tx_pixel = 0;
  value->ty_pixel = 0;

  /* The first time we store a texture in the global atlas we'll
     register for notifications when the global atlas is reorganized
     so we can forward the notification on as a glyph
     reorganization */
  if (!cache->using_global_atlas)
    {
      _cogl_atlas_texture_add_reorganize_callback
        (cogl_pango_glyph_cache_reorganize_cb, cache);
      cache->using_global_atlas = TRUE;
    }

  return TRUE;
}
Esempio n. 10
0
void
_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx,
                                               const char *version_string,
                                               GLuint shader_gl_handle,
                                               GLenum shader_gl_type,
                                               GLsizei count_in,
                                               const char **strings_in,
                                               const GLint *lengths_in)
{
  const char *vertex_boilerplate;
  const char *fragment_boilerplate;

  const char **strings = g_alloca (sizeof (char *) * (count_in + 4));
  GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4));
  int count = 0;
  char *tex_coord_declarations = NULL;

  vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE;
  fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE;

  if (version_string)
    {
      strings[count] = version_string;
      lengths[count++] = -1;
    }

  if (ctx->driver == COGL_DRIVER_GLES2 &&
      cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
    {
      static const char texture_3d_extension[] =
        "#extension GL_OES_texture_3D : enable\n";
      strings[count] = texture_3d_extension;
      lengths[count++] = sizeof (texture_3d_extension) - 1;
    }

  if (shader_gl_type == GL_VERTEX_SHADER)
    {
      strings[count] = vertex_boilerplate;
      lengths[count++] = strlen (vertex_boilerplate);
    }
  else if (shader_gl_type == GL_FRAGMENT_SHADER)
    {
      strings[count] = fragment_boilerplate;
      lengths[count++] = strlen (fragment_boilerplate);
    }

  memcpy (strings + count, strings_in, sizeof (char *) * count_in);
  if (lengths_in)
    memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
  else
    {
      int i;

      for (i = 0; i < count_in; i++)
        lengths[count + i] = -1; /* null terminated */
    }
  count += count_in;

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
    {
      GString *buf = g_string_new (NULL);
      int i;

      g_string_append_printf (buf,
                              "%s shader:\n",
                              shader_gl_type == GL_VERTEX_SHADER ?
                              "vertex" : "fragment");
      for (i = 0; i < count; i++)
        if (lengths[i] != -1)
          g_string_append_len (buf, strings[i], lengths[i]);
        else
          g_string_append (buf, strings[i]);

      g_message ("%s", buf->str);

      g_string_free (buf, TRUE);
    }

  GE( ctx, glShaderSource (shader_gl_handle, count,
                           (const char **) strings, lengths) );

  g_free (tex_coord_declarations);
}
Esempio n. 11
0
int
_cogl_blend_string_compile (const char *string,
                            CoglBlendStringContext context,
                            CoglBlendStringStatement *statements,
                            CoglError **error)
{
  const char *p = string;
  const char *mark = NULL;
  const char *error_string;
  ParserState state = PARSER_STATE_EXPECT_DEST_CHANNELS;
  CoglBlendStringStatement *statement = statements;
  int current_statement = 0;
  int current_arg = 0;
  int remaining_argc = 0;

#if 0
  COGL_DEBUG_SET_FLAG (COGL_DEBUG_BLEND_STRINGS);
#endif

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n",
                 context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
                 "blend" : "texture combine",
                 string);
    }

  do
    {
      if (g_ascii_isspace (*p))
        continue;

      if (*p == '\0')
        {
          switch (state)
            {
            case PARSER_STATE_EXPECT_DEST_CHANNELS:
              if (current_statement != 0)
                goto finished;
              error_string = "Empty statement";
              goto error;
            case PARSER_STATE_SCRAPING_DEST_CHANNELS:
              error_string = "Expected an '=' following the destination "
                "channel mask";
              goto error;
            case PARSER_STATE_EXPECT_FUNCTION_NAME:
              error_string = "Expected a function name";
              goto error;
            case PARSER_STATE_SCRAPING_FUNCTION_NAME:
              error_string = "Expected parenthesis after the function name";
              goto error;
            case PARSER_STATE_EXPECT_ARG_START:
              error_string = "Expected to find the start of an argument";
              goto error;
            case PARSER_STATE_EXPECT_STATEMENT_END:
              error_string = "Expected closing parenthesis for statement";
              goto error;
            }
        }

      switch (state)
        {
        case PARSER_STATE_EXPECT_DEST_CHANNELS:
          mark = p;
          state = PARSER_STATE_SCRAPING_DEST_CHANNELS;

          /* fall through */
        case PARSER_STATE_SCRAPING_DEST_CHANNELS:
          if (*p != '=')
            continue;
          if (strncmp (mark, "RGBA", 4) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
          else if (strncmp (mark, "RGB", 3) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
          else if (strncmp (mark, "A", 1) == 0)
            statement->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
          else
            {
              error_string = "Unknown destination channel mask; "
                "expected RGBA=, RGB= or A=";
              goto error;
            }
          state = PARSER_STATE_EXPECT_FUNCTION_NAME;
          continue;

        case PARSER_STATE_EXPECT_FUNCTION_NAME:
          mark = p;
          state = PARSER_STATE_SCRAPING_FUNCTION_NAME;

          /* fall through */
        case PARSER_STATE_SCRAPING_FUNCTION_NAME:
          if (*p != '(')
            {
              if (!is_alphanum_char (*p))
                {
                  error_string = "non alpha numeric character in function"
                    "name";
                  goto error;
                }
              continue;
            }
          statement->function = get_function_info (mark, p, context);
          if (!statement->function)
            {
              error_string = "Unknown function name";
              goto error;
            }
          remaining_argc = statement->function->argc;
          current_arg = 0;
          state = PARSER_STATE_EXPECT_ARG_START;

          /* fall through */
        case PARSER_STATE_EXPECT_ARG_START:
          if (*p != '(' && *p != ',')
            continue;
          if (remaining_argc)
            {
              p++; /* parse_argument expects to see the first char of the arg */
              if (!parse_argument (string, &p, statement,
                                   current_arg, &statement->args[current_arg],
                                   context, error))
                return 0;
              current_arg++;
              remaining_argc--;
            }
          if (!remaining_argc)
            state = PARSER_STATE_EXPECT_STATEMENT_END;
          continue;

        case PARSER_STATE_EXPECT_STATEMENT_END:
          if (*p != ')')
            {
              error_string = "Expected end of statement";
              goto error;
            }
          state = PARSER_STATE_EXPECT_DEST_CHANNELS;
          if (current_statement++ == 1)
            goto finished;
          statement = &statements[current_statement];
        }
    }
  while (p++);

finished:

  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
    {
      if (current_statement > 0)
        print_statement (0, &statements[0]);
      if (current_statement > 1)
        print_statement (1, &statements[1]);
    }

  if (!validate_statements_for_context (statements,
                                        current_statement,
                                        context,
                                        error))
    return 0;

  return current_statement;

error:
    {
      int offset = p - string;
      _cogl_set_error (error,
                       COGL_BLEND_STRING_ERROR,
                       COGL_BLEND_STRING_ERROR_PARSE_ERROR,
                       "Syntax error at offset %d: %s",
                       offset,
                       error_string);

      if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
        {
          g_debug ("Syntax error at offset %d: %s",
                   offset, error_string);
        }
      return 0;
    }
}
Esempio n. 12
0
static CoglBool
parse_argument (const char *string, /* original user string */
                const char **ret_p, /* start of argument IN:OUT */
                const CoglBlendStringStatement *statement,
                int current_arg,
                CoglBlendStringArgument *arg, /* OUT */
                CoglBlendStringContext context,
                CoglError **error)
{
  const char *p = *ret_p;
  const char *mark = NULL;
  const char *error_string = NULL;
  ParserArgState state = PARSER_ARG_STATE_START;
  CoglBool parsing_factor = FALSE;
  CoglBool implicit_factor_brace = FALSE;

  arg->source.is_zero = FALSE;
  arg->source.info = NULL;
  arg->source.texture = 0;
  arg->source.one_minus = FALSE;
  arg->source.mask = statement->mask;

  arg->factor.is_one = FALSE;
  arg->factor.is_color = FALSE;
  arg->factor.is_src_alpha_saturate = FALSE;

  arg->factor.source.is_zero = FALSE;
  arg->factor.source.info = NULL;
  arg->factor.source.texture = 0;
  arg->factor.source.one_minus = FALSE;
  arg->factor.source.mask = statement->mask;

  do
    {
      if (g_ascii_isspace (*p))
        continue;

      if (*p == '\0')
        {
          error_string = "Unexpected end of string while parsing argument";
          goto error;
        }

      switch (state)
        {
        case PARSER_ARG_STATE_START:
          if (*p == '1')
            state = PARSER_ARG_STATE_EXPECT_MINUS;
          else if (*p == '0')
            {
              arg->source.is_zero = TRUE;
              state = PARSER_ARG_STATE_EXPECT_END;
            }
          else
            {
              p--; /* backtrack */
              state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_MINUS:
          if (*p != '-')
            {
              error_string = "expected a '-' following the 1";
              goto error;
            }
          arg->source.one_minus = TRUE;
          state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
          continue;

        case PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME:
          if (!is_symbol_char (*p))
            {
              error_string = "expected a color source name";
              goto error;
            }
          state = PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME;
          mark = p;
          if (parsing_factor)
            arg->factor.is_color = TRUE;

          /* fall through */
        case PARSER_ARG_STATE_SCRAPING_COLOR_SRC_NAME:
          if (!is_symbol_char (*p))
            {
              CoglBlendStringColorSource *source =
                parsing_factor ? &arg->factor.source : &arg->source;
              source->info = get_color_src_info (mark, p, context);
              if (!source->info)
                {
                  error_string = "Unknown color source name";
                  goto error;
                }
              if (source->info->type ==
                  COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N)
                {
                  char *endp;
                  source->texture =
                    strtoul (&mark[strlen ("TEXTURE_")], &endp, 10);
                  if (mark == endp)
                    {
                      error_string = "invalid texture number given with "
                                     "TEXTURE_N color source";
                      goto error;
                    }
                  p = endp;
                }
              state = PARSER_ARG_STATE_MAYBE_COLOR_MASK;
            }
          else
            continue;

          /* fall through */
        case PARSER_ARG_STATE_MAYBE_COLOR_MASK:
          if (*p != '[')
            {
              p--; /* backtrack */
              if (!parsing_factor)
                state = PARSER_ARG_STATE_MAYBE_MULT;
              else
                state = PARSER_ARG_STATE_EXPECT_END;
              continue;
            }
          state = PARSER_ARG_STATE_SCRAPING_MASK;
          mark = p;

          /* fall through */
        case PARSER_ARG_STATE_SCRAPING_MASK:
          if (*p == ']')
            {
              size_t len = p - mark;
              CoglBlendStringColorSource *source =
                parsing_factor ? &arg->factor.source : &arg->source;

              if (len == 5 && strncmp (mark, "[RGBA", len) == 0)
                {
                  if (statement->mask != COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
                    {
                      error_string = "You can't use an RGBA color mask if the "
                                     "statement hasn't also got an RGBA= mask";
                      goto error;
                    }
                  source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGBA;
                }
              else if (len == 4 && strncmp (mark, "[RGB", len) == 0)
                source->mask = COGL_BLEND_STRING_CHANNEL_MASK_RGB;
              else if (len == 2 && strncmp (mark, "[A", len) == 0)
                source->mask = COGL_BLEND_STRING_CHANNEL_MASK_ALPHA;
              else
                {
                  error_string = "Expected a channel mask of [RGBA]"
                                 "[RGB] or [A]";
                  goto error;
                }
              if (parsing_factor)
                state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
              else
                state = PARSER_ARG_STATE_MAYBE_MULT;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_OPEN_PAREN:
          if (*p != '(')
            {
              if (is_alphanum_char (*p))
                {
                  p--; /* compensate for implicit brace and ensure this
                        * char gets considered part of the blend factor */
                  implicit_factor_brace = TRUE;
                }
              else
                {
                  error_string = "Expected '(' around blend factor or alpha "
                                 "numeric character for blend factor name";
                  goto error;
                }
            }
          else
            implicit_factor_brace = FALSE;
          parsing_factor = TRUE;
          state = PARSER_ARG_STATE_EXPECT_FACTOR;
          continue;

        case PARSER_ARG_STATE_EXPECT_FACTOR:
          if (*p == '1')
            state = PARSER_ARG_STATE_MAYBE_MINUS;
          else if (*p == '0')
            {
              arg->source.is_zero = TRUE;
              state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            }
          else
            {
              state = PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE;
              mark = p;
            }
          continue;

        case PARSER_ARG_STATE_MAYBE_SRC_ALPHA_SATURATE:
          if (!is_symbol_char (*p))
            {
              size_t len = p - mark;
              if (len >= strlen ("SRC_ALPHA_SATURATE") &&
                  strncmp (mark, "SRC_ALPHA_SATURATE", len) == 0)
                {
                  arg->factor.is_src_alpha_saturate = TRUE;
                  state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
                }
              else
                {
                  state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
                  p = mark - 1; /* backtrack */
                }
            }
          continue;

        case PARSER_ARG_STATE_MAYBE_MINUS:
          if (*p == '-')
            {
              if (implicit_factor_brace)
                {
                  error_string = "Expected ( ) braces around blend factor with "
                                 "a subtraction";
                  goto error;
                }
              arg->factor.source.one_minus = TRUE;
              state = PARSER_ARG_STATE_EXPECT_COLOR_SRC_NAME;
            }
          else
            {
              arg->factor.is_one = TRUE;
              state = PARSER_ARG_STATE_EXPECT_CLOSE_PAREN;
            }
          continue;

        case PARSER_ARG_STATE_EXPECT_CLOSE_PAREN:
          if (implicit_factor_brace)
            {
              p--;
              state = PARSER_ARG_STATE_EXPECT_END;
              continue;
            }
          if (*p != ')')
            {
              error_string = "Expected closing parenthesis after blend factor";
              goto error;
            }
          state = PARSER_ARG_STATE_EXPECT_END;
          continue;

        case PARSER_ARG_STATE_MAYBE_MULT:
          if (*p == '*')
            {
              state = PARSER_ARG_STATE_EXPECT_OPEN_PAREN;
              continue;
            }
          arg->factor.is_one = TRUE;
          state = PARSER_ARG_STATE_EXPECT_END;

          /* fall through */
        case PARSER_ARG_STATE_EXPECT_END:
          if (*p != ',' && *p != ')')
            {
              error_string = "expected , or )";
              goto error;
            }

          *ret_p = p - 1;
          return TRUE;
        }
    }
  while (p++);

error:
  {
    int offset = p - string;
    _cogl_set_error (error,
                     COGL_BLEND_STRING_ERROR,
                     COGL_BLEND_STRING_ERROR_ARGUMENT_PARSE_ERROR,
                     "Syntax error for argument %d at offset %d: %s",
                     current_arg,
                     offset,
                     error_string);

    if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
      {
        g_debug ("Syntax error for argument %d at offset %d: %s",
                 current_arg, offset, error_string);
      }
    return FALSE;
  }
}
Esempio n. 13
0
void
_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx,
                                               GLuint shader_gl_handle,
                                               GLenum shader_gl_type,
                                               CoglPipeline *pipeline,
                                               GLsizei count_in,
                                               const char **strings_in,
                                               const GLint *lengths_in)
{
  const char *vertex_boilerplate;
  const char *fragment_boilerplate;

  const char **strings = g_alloca (sizeof (char *) * (count_in + 4));
  GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4));
  char *version_string;
  int count = 0;

  int n_layers;

  vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE;
  fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE;

  version_string = g_strdup_printf ("#version %i\n\n",
                                    ctx->glsl_version_to_use);
  strings[count] = version_string;
  lengths[count++] = -1;

  if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED) &&
      cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
    {
      static const char texture_3d_extension[] =
        "#extension GL_OES_texture_3D : enable\n";
      strings[count] = texture_3d_extension;
      lengths[count++] = sizeof (texture_3d_extension) - 1;
    }

  if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL))
    {
      static const char texture_3d_extension[] =
        "#extension GL_OES_EGL_image_external : require\n";
      strings[count] = texture_3d_extension;
      lengths[count++] = sizeof (texture_3d_extension) - 1;
    }

  if (shader_gl_type == GL_VERTEX_SHADER)
    {
      strings[count] = vertex_boilerplate;
      lengths[count++] = strlen (vertex_boilerplate);
    }
  else if (shader_gl_type == GL_FRAGMENT_SHADER)
    {
      strings[count] = fragment_boilerplate;
      lengths[count++] = strlen (fragment_boilerplate);
    }

  n_layers = cogl_pipeline_get_n_layers (pipeline);
  if (n_layers)
    {
      GString *layer_declarations = ctx->codegen_boilerplate_buffer;
      g_string_set_size (layer_declarations, 0);

      g_string_append_printf (layer_declarations,
                              "varying vec4 _cogl_tex_coord[%d];\n",
                              n_layers);

      if (shader_gl_type == GL_VERTEX_SHADER)
        {
          g_string_append_printf (layer_declarations,
                                  "uniform mat4 cogl_texture_matrix[%d];\n",
                                  n_layers);

          _cogl_pipeline_foreach_layer_internal (pipeline,
                                                 add_layer_vertex_boilerplate_cb,
                                                 layer_declarations);
        }
      else if (shader_gl_type == GL_FRAGMENT_SHADER)
        {
          _cogl_pipeline_foreach_layer_internal (pipeline,
                                                 add_layer_fragment_boilerplate_cb,
                                                 layer_declarations);
        }

      strings[count] = layer_declarations->str;
      lengths[count++] = -1; /* null terminated */
    }

  memcpy (strings + count, strings_in, sizeof (char *) * count_in);
  if (lengths_in)
    memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
  else
    {
      int i;

      for (i = 0; i < count_in; i++)
        lengths[count + i] = -1; /* null terminated */
    }
  count += count_in;

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
    {
      GString *buf = g_string_new (NULL);
      int i;

      g_string_append_printf (buf,
                              "%s shader:\n",
                              shader_gl_type == GL_VERTEX_SHADER ?
                              "vertex" : "fragment");
      for (i = 0; i < count; i++)
        if (lengths[i] != -1)
          g_string_append_len (buf, strings[i], lengths[i]);
        else
          g_string_append (buf, strings[i]);

      g_message ("%s", buf->str);

      g_string_free (buf, TRUE);
    }

  GE( ctx, glShaderSource (shader_gl_handle, count,
                           (const char **) strings, lengths) );

  g_free (version_string);
}
Esempio n. 14
0
static CoglTexture *
_cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
                               CoglTextureFlags flags,
                               CoglPixelFormat internal_format,
                               CoglBool can_convert_in_place,
                               CoglError **error)
{
  CoglContext *ctx = _cogl_bitmap_get_context (bitmap);
  CoglTexture *tex;
  CoglError *internal_error = NULL;

  if (!flags &&
      !COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ATLAS))
    {
      /* First try putting the texture in the atlas */
      CoglAtlasTexture *atlas_tex =
        _cogl_atlas_texture_new_from_bitmap (bitmap,
                                             can_convert_in_place);

      _cogl_texture_set_internal_format (COGL_TEXTURE (atlas_tex),
                                         internal_format);

      if (cogl_texture_allocate (COGL_TEXTURE (atlas_tex), &internal_error))
        return COGL_TEXTURE (atlas_tex);

      cogl_error_free (internal_error);
      internal_error = NULL;
      cogl_object_unref (atlas_tex);
    }

  /* If that doesn't work try a fast path 2D texture */
  if ((_cogl_util_is_pot (bitmap->width) &&
       _cogl_util_is_pot (bitmap->height)) ||
      (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
       cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP)))
    {
      tex = COGL_TEXTURE (_cogl_texture_2d_new_from_bitmap (bitmap,
                                                            can_convert_in_place));

      _cogl_texture_set_internal_format (tex, internal_format);

      if (!cogl_texture_allocate (tex, &internal_error))
        {
          cogl_error_free (internal_error);
          internal_error = NULL;
          cogl_object_unref (tex);
          tex = NULL;
        }
    }
  else
    tex = NULL;

  if (!tex)
    {
      /* Otherwise create a sliced texture */
      int max_waste = flags & COGL_TEXTURE_NO_SLICING ? -1 : COGL_TEXTURE_MAX_WASTE;
      tex = COGL_TEXTURE (_cogl_texture_2d_sliced_new_from_bitmap (bitmap,
                                                             max_waste,
                                                             can_convert_in_place));

      _cogl_texture_set_internal_format (tex, internal_format);

      if (!cogl_texture_allocate (tex, error))
        {
          cogl_object_unref (tex);
          tex = NULL;
        }
    }

  if (tex &&
      flags & COGL_TEXTURE_NO_AUTO_MIPMAP)
    {
      cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (tex),
                                           0, 0, 1, 1,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE,
                                           set_auto_mipmap_cb,
                                           NULL);
    }

  return tex;
}
Esempio n. 15
0
void
_cogl_shader_compile_real (CoglHandle handle,
                           CoglPipeline *pipeline)
{
  CoglShader *shader = handle;

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

#ifdef HAVE_COGL_GL
  if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
    {
#ifdef COGL_GL_DEBUG
      GLenum gl_error;
#endif

      if (shader->gl_handle)
        return;

      GE (ctx, glGenPrograms (1, &shader->gl_handle));

      GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle));

      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
        g_message ("user ARBfp program:\n%s", shader->source);

#ifdef COGL_GL_DEBUG
      _cogl_gl_util_clear_gl_errors (ctx);
#endif
      ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
                            GL_PROGRAM_FORMAT_ASCII_ARB,
                            strlen (shader->source),
                            shader->source);
#ifdef COGL_GL_DEBUG
      gl_error = _cogl_gl_util_get_error (ctx);
      if (gl_error != GL_NO_ERROR)
        {
          g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s",
                     G_STRLOC,
                     gl_error,
                     shader->source,
                     ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
        }
#endif
    }
  else
#endif
    {
      GLenum gl_type;
      GLint status;

      if (shader->gl_handle)
        {
          CoglPipeline *prev = shader->compilation_pipeline;

          /* XXX: currently the only things that will affect the
           * boilerplate for user shaders, apart from driver features,
           * are the pipeline layer-indices and texture-unit-indices
           */
          if (pipeline == prev ||
              _cogl_pipeline_layer_and_unit_numbers_equal (prev, pipeline))
            return;
        }

      if (shader->gl_handle)
        delete_shader (shader);

      switch (shader->type)
        {
        case COGL_SHADER_TYPE_VERTEX:
          gl_type = GL_VERTEX_SHADER;
          break;
        case COGL_SHADER_TYPE_FRAGMENT:
          gl_type = GL_FRAGMENT_SHADER;
          break;
        default:
          g_assert_not_reached ();
          break;
        }

      shader->gl_handle = ctx->glCreateShader (gl_type);

      _cogl_glsl_shader_set_source_with_boilerplate (ctx,
                                                     shader->gl_handle,
                                                     gl_type,
                                                     pipeline,
                                                     1,
                                                     (const char **)
                                                      &shader->source,
                                                     NULL);

      GE (ctx, glCompileShader (shader->gl_handle));

      shader->compilation_pipeline = cogl_object_ref (pipeline);

      GE (ctx, glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
      if (!status)
        {
          char buffer[512];
          int len = 0;

          ctx->glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
          buffer[len] = '\0';

          g_warning ("Failed to compile GLSL program:\n"
                     "src:\n%s\n"
                     "error:\n%s\n",
                     shader->source,
                     buffer);
        }
    }
}
static void
_cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference)
{
  CoglPipelineShaderState *shader_state;
  CoglPipeline *authority;
  CoglPipelineCacheEntry *cache_entry = NULL;
  CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

  /* Now lookup our ARBfp backend private state */
  shader_state = get_shader_state (pipeline);

  /* If we have a valid shader_state then we are all set and don't
   * need to generate a new program. */
  if (shader_state)
    return;

  /* If we don't have an associated arbfp program yet then find the
   * arbfp-authority (the oldest ancestor whose state will result in
   * the same program being generated as for this pipeline).
   *
   * We always make sure to associate new programs with the
   * arbfp-authority to maximize the chance that other pipelines can
   * share it.
   */
  authority = _cogl_pipeline_find_equivalent_parent
    (pipeline,
     _cogl_pipeline_get_state_for_fragment_codegen (ctx) &
     ~COGL_PIPELINE_STATE_LAYERS,
     _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
  shader_state = get_shader_state (authority);
  if (shader_state)
    {
      /* If we are going to share our program state with an arbfp-authority
       * then add a reference to the program state associated with that
       * arbfp-authority... */
      set_shader_state (pipeline, shader_state);
      return;
    }

  /* If we haven't yet found an existing program then before we resort to
   * generating a new arbfp program we see if we can find a suitable
   * program in the pipeline_cache. */
  if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
    {
      cache_entry =
        _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache,
                                                    authority);

      shader_state = get_shader_state (cache_entry->pipeline);

      if (shader_state)
        shader_state->ref_count++;
    }

  /* If we still haven't got a shader state then we'll have to create
     a new one */
  if (shader_state == NULL)
    {
      shader_state = shader_state_new (n_layers, cache_entry);

      shader_state->user_program = user_program;
      if (user_program == COGL_INVALID_HANDLE)
        {
          /* We reuse a single grow-only GString for code-gen */
          g_string_set_size (ctx->codegen_source_buffer, 0);
          shader_state->source = ctx->codegen_source_buffer;
          g_string_append (shader_state->source,
                           "!!ARBfp1.0\n"
                           "TEMP output;\n"
                           "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
                           "PARAM half = {.5, .5, .5, .5};\n"
                           "PARAM one = {1, 1, 1, 1};\n"
                           "PARAM two = {2, 2, 2, 2};\n"
                           "PARAM minus_one = {-1, -1, -1, -1};\n");
        }
    }

  set_shader_state (pipeline, shader_state);

  shader_state->ref_count--;

  /* Since we have already resolved the arbfp-authority at this point
   * we might as well also associate any program we find from the cache
   * with the authority too... */
  if (authority != pipeline)
    set_shader_state (authority, shader_state);

  /* If we found a template then we'll attach it to that too so that
     next time a similar pipeline is used it can use the same state */
  if (cache_entry)
    set_shader_state (cache_entry->pipeline, shader_state);
}
Esempio n. 17
0
static CoglBool
_cogl_driver_update_features (CoglContext *ctx,
                              CoglError **error)
{
  CoglPrivateFeatureFlags private_flags = 0;
  char **gl_extensions;
  int gl_major = 0, gl_minor = 0;

  /* We have to special case getting the pointer to the glGetString*
     functions because we need to use them to determine what functions
     we can expect */
  ctx->glGetString =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetString",
                                              TRUE);
  ctx->glGetStringi =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetStringi",
                                              TRUE);
  ctx->glGetIntegerv =
    (void *) _cogl_renderer_get_proc_address (ctx->display->renderer,
                                              "glGetIntegerv",
                                              TRUE);

  gl_extensions = _cogl_context_get_gl_extensions (ctx);

  if (!check_gl_version (ctx, gl_extensions, error))
    return FALSE;

  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
    {
      char *all_extensions = g_strjoinv (" ", gl_extensions);

      COGL_NOTE (WINSYS,
                 "Checking features\n"
                 "  GL_VENDOR: %s\n"
                 "  GL_RENDERER: %s\n"
                 "  GL_VERSION: %s\n"
                 "  GL_EXTENSIONS: %s",
                 ctx->glGetString (GL_VENDOR),
                 ctx->glGetString (GL_RENDERER),
                 _cogl_context_get_gl_version (ctx),
                 all_extensions);

      g_free (all_extensions);
    }

  _cogl_get_gl_version (ctx, &gl_major, &gl_minor);

  _cogl_gpu_info_init (ctx, &ctx->gpu);

  ctx->glsl_major = 1;
  ctx->glsl_minor = 1;

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
    {
      const char *glsl_version =
        (char *)ctx->glGetString (GL_SHADING_LANGUAGE_VERSION);
      parse_gl_version (glsl_version, &ctx->glsl_major, &ctx->glsl_minor);
    }

  COGL_FLAGS_SET (ctx->features,
                  COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE);
  COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4))
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);

  _cogl_feature_check_ext_functions (ctx,
                                     gl_major,
                                     gl_minor,
                                     gl_extensions);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) ||
      _cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions))
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NPOT, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE);
    }

  if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_MESA_PACK_INVERT;

  if (ctx->glGenRenderbuffers)
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
      private_flags |= COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS;
    }

  if (ctx->glBlitFramebuffer)
    private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;

  if (ctx->glRenderbufferStorageMultisampleIMG)
    COGL_FLAGS_SET (ctx->features,
                    COGL_FEATURE_ID_OFFSCREEN_MULTISAMPLE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) ||
      _cogl_check_extension ("GL_ARB_depth_texture", gl_extensions))
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE);

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 1) ||
      _cogl_check_extension ("GL_EXT_pixel_buffer_object", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_PBOS;

  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 1, 4) ||
      _cogl_check_extension ("GL_EXT_blend_color", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;

  if (ctx->glGenPrograms)
    private_flags |= COGL_PRIVATE_FEATURE_ARBFP;

  if (ctx->glCreateProgram)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE);
  else
    {
      /* If all of the old GLSL extensions are available then we can fake
       * the GL 2.0 GLSL support by diverting to the old function names */
      if (ctx->glCreateProgramObject && /* GL_ARB_shader_objects */
          ctx->glVertexAttribPointer && /* GL_ARB_vertex_shader */
          _cogl_check_extension ("GL_ARB_fragment_shader", gl_extensions))
        {
          ctx->glCreateShader = ctx->glCreateShaderObject;
          ctx->glCreateProgram = ctx->glCreateProgramObject;
          ctx->glDeleteShader = ctx->glDeleteObject;
          ctx->glDeleteProgram = ctx->glDeleteObject;
          ctx->glAttachShader = ctx->glAttachObject;
          ctx->glUseProgram = ctx->glUseProgramObject;
          ctx->glGetProgramInfoLog = ctx->glGetInfoLog;
          ctx->glGetShaderInfoLog = ctx->glGetInfoLog;
          ctx->glGetShaderiv = ctx->glGetObjectParameteriv;
          ctx->glGetProgramiv = ctx->glGetObjectParameteriv;
          ctx->glDetachShader = ctx->glDetachObject;
          ctx->glGetAttachedShaders = ctx->glGetAttachedObjects;
          /* FIXME: there doesn't seem to be an equivalent for glIsShader
           * and glIsProgram. This doesn't matter for now because Cogl
           * doesn't use these but if we add support for simulating a
           * GLES2 context on top of regular GL then we'll need to do
           * something here */

          COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GLSL, TRUE);
        }
    }

  if ((COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0) ||
       _cogl_check_extension ("GL_ARB_point_sprite", gl_extensions)) &&

      /* If GLSL is supported then we only enable point sprite support
       * too if we have glsl >= 1.2 otherwise we don't have the
       * gl_PointCoord builtin which we depend on in the glsl backend.
       */
      (!COGL_FLAGS_GET (ctx->features, COGL_FEATURE_ID_GLSL) ||
       COGL_CHECK_GL_VERSION (ctx->glsl_major, ctx->glsl_minor, 1, 2)))
    {
      COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);
    }

  if (ctx->glGenBuffers)
    {
      private_flags |= COGL_PRIVATE_FEATURE_VBOS;
      COGL_FLAGS_SET (ctx->features,
                         COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE);
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE);
    }

  if (_cogl_check_extension ("GL_ARB_texture_rectangle", gl_extensions))
    COGL_FLAGS_SET (ctx->features,
                    COGL_FEATURE_ID_TEXTURE_RECTANGLE, TRUE);

  if (ctx->glTexImage3D)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE);

  if (ctx->glEGLImageTargetTexture2D)
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE;

  if (_cogl_check_extension ("GL_EXT_packed_depth_stencil", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL;

  if (ctx->glGenSamplers)
    private_flags |= COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS;


  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 3) ||
      _cogl_check_extension ("GL_ARB_texture_swizzle", gl_extensions) ||
      _cogl_check_extension ("GL_EXT_texture_swizzle", gl_extensions))
    private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE;

  /* The per-vertex point size is only available via GLSL with the
   * gl_PointSize builtin. This is only available in GL 2.0 (not the
   * GLSL extensions) */
  if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0))
    {
      COGL_FLAGS_SET (ctx->features,
                      COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE,
                      TRUE);
      private_flags |= COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE;
    }

  if (ctx->driver == COGL_DRIVER_GL)
    {
      int max_clip_planes = 0;

      /* Features which are not available in GL 3 */
      private_flags |= (COGL_PRIVATE_FEATURE_GL_FIXED |
                        COGL_PRIVATE_FEATURE_ALPHA_TEST |
                        COGL_PRIVATE_FEATURE_QUADS |
                        COGL_PRIVATE_FEATURE_ALPHA_TEXTURES);

      GE( ctx, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
      if (max_clip_planes >= 4)
        private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
    }

  private_flags |= (COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT |
                    COGL_PRIVATE_FEATURE_ANY_GL |
                    COGL_PRIVATE_FEATURE_FORMAT_CONVERSION |
                    COGL_PRIVATE_FEATURE_BLEND_CONSTANT |
                    COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM |
                    COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS |
                    COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL);

  if (ctx->glFenceSync)
    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE);

  /* Cache features */
  ctx->private_feature_flags |= private_flags;

  g_strfreev (gl_extensions);

  if ((private_flags & (COGL_PRIVATE_FEATURE_ALPHA_TEXTURES |
                        COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) == 0)
    {
      _cogl_set_error (error,
                       COGL_DRIVER_ERROR,
                       COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND,
                       "The GL_ARB_texture_swizzle extension is required "
                       "to use the GL3 driver");
      return FALSE;
    }

  return TRUE;
}
static gboolean
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
                                   int n_layers,
                                   unsigned long pipelines_difference)
{
  CoglPipelineShaderState *shader_state;
  CoglPipeline *template_pipeline = NULL;
  CoglProgram *user_program;

  _COGL_GET_CONTEXT (ctx, FALSE);

  if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
    return FALSE;

  user_program = cogl_pipeline_get_user_program (pipeline);

  /* If the user program has a vertex shader that isn't GLSL then the
     appropriate vertend for that language should handle it */
  if (user_program &&
      _cogl_program_has_vertex_shader (user_program) &&
      _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
    return FALSE;

  /* Now lookup our glsl backend private state (allocating if
   * necessary) */
  shader_state = get_shader_state (pipeline);

  if (shader_state == NULL)
    {
      CoglPipeline *authority;

      /* Get the authority for anything affecting vertex shader
         state */
      authority = _cogl_pipeline_find_equivalent_parent
        (pipeline,
         COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN &
         ~COGL_PIPELINE_STATE_LAYERS,
         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);

      shader_state = get_shader_state (authority);

      if (shader_state == NULL)
        {
          /* Check if there is already a similar cached pipeline whose
             shader state we can share */
          if (G_LIKELY (!(COGL_DEBUG_ENABLED
                          (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
            {
              template_pipeline =
                _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache,
                                                          authority);

              shader_state = get_shader_state (template_pipeline);
            }

          if (shader_state)
            shader_state->ref_count++;
          else
            shader_state = shader_state_new ();

          set_shader_state (authority, shader_state);

          if (template_pipeline)
            {
              shader_state->ref_count++;
              set_shader_state (template_pipeline, shader_state);
            }
        }

      if (authority != pipeline)
        {
          shader_state->ref_count++;
          set_shader_state (pipeline, shader_state);
        }
    }

  if (shader_state->gl_shader)
    {
      /* If we already have a valid GLSL shader then we don't need to
         generate a new one. However if there's a user program and it
         has changed since the last link then we do need a new shader */
      if (user_program == NULL ||
          shader_state->user_program_age == user_program->age)
        return TRUE;

      /* We need to recreate the shader so destroy the existing one */
      GE( ctx, glDeleteShader (shader_state->gl_shader) );
      shader_state->gl_shader = 0;
    }

  /* If we make it here then we have a shader_state struct without a gl_shader
     either because this is the first time we've encountered it or
     because the user program has changed */

  if (user_program)
    shader_state->user_program_age = user_program->age;

  /* If the user program contains a vertex shader then we don't need
     to generate one */
  if (user_program &&
      _cogl_program_has_vertex_shader (user_program))
    return TRUE;

  /* We reuse two grow-only GStrings for code-gen. One string
     contains the uniform and attribute declarations while the
     other contains the main function. We need two strings
     because we need to dynamically declare attributes as the
     add_layer callback is invoked */
  g_string_set_size (ctx->codegen_header_buffer, 0);
  g_string_set_size (ctx->codegen_source_buffer, 0);
  shader_state->header = ctx->codegen_header_buffer;
  shader_state->source = ctx->codegen_source_buffer;

  g_string_append (shader_state->source,
                   "void\n"
                   "main ()\n"
                   "{\n");

  if (ctx->driver == COGL_DRIVER_GLES2)
    /* There is no builtin uniform for the pointsize on GLES2 so we need
       to copy it from the custom uniform in the vertex shader */
    g_string_append (shader_state->source,
                     "  cogl_point_size_out = cogl_point_size_in;\n");
  /* On regular OpenGL we'll just flush the point size builtin */
  else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)
    {
      CoglPipeline *authority =
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE);

      if (ctx->point_size_cache != authority->big_state->point_size)
        {
          GE( ctx, glPointSize (authority->big_state->point_size) );
          ctx->point_size_cache = authority->big_state->point_size;
        }
    }

  return TRUE;
}
static void
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
                                   int n_layers,
                                   unsigned long pipelines_difference)
{
  CoglPipelineShaderState *shader_state;
  CoglPipeline *template_pipeline = NULL;

  _COGL_GET_CONTEXT (ctx, NO_RETVAL);

  /* Now lookup our glsl backend private state (allocating if
   * necessary) */
  shader_state = get_shader_state (pipeline);

  if (shader_state == NULL)
    {
      CoglPipeline *authority;

      /* Get the authority for anything affecting vertex shader
         state */
      authority = _cogl_pipeline_find_equivalent_parent
        (pipeline,
         COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN &
         ~COGL_PIPELINE_STATE_LAYERS,
         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);

      shader_state = get_shader_state (authority);

      if (shader_state == NULL)
        {
          /* Check if there is already a similar cached pipeline whose
             shader state we can share */
          if (G_LIKELY (!(COGL_DEBUG_ENABLED
                          (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
            {
              template_pipeline =
                _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache,
                                                          authority);

              shader_state = get_shader_state (template_pipeline);
            }

          if (shader_state)
            shader_state->ref_count++;
          else
            shader_state = shader_state_new ();

          set_shader_state (authority, shader_state);

          if (template_pipeline)
            {
              shader_state->ref_count++;
              set_shader_state (template_pipeline, shader_state);
            }
        }

      if (authority != pipeline)
        {
          shader_state->ref_count++;
          set_shader_state (pipeline, shader_state);
        }
    }

  if (shader_state->gl_shader)
    return;

  /* If we make it here then we have a shader_state struct without a gl_shader
     because this is the first time we've encountered it */

  /* We reuse two grow-only GStrings for code-gen. One string
     contains the uniform and attribute declarations while the
     other contains the main function. We need two strings
     because we need to dynamically declare attributes as the
     add_layer callback is invoked */
  g_string_set_size (ctx->codegen_header_buffer, 0);
  g_string_set_size (ctx->codegen_source_buffer, 0);
  shader_state->header = ctx->codegen_header_buffer;
  shader_state->source = ctx->codegen_source_buffer;

  add_layer_declarations (pipeline, shader_state);
  add_global_declarations (pipeline, shader_state);

  g_string_append (shader_state->source,
                   "void\n"
                   "cogl_generated_source ()\n"
                   "{\n");

  if (!(ctx->private_feature_flags &
        COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM))
    /* There is no builtin uniform for the pointsize on GLES2 so we need
       to copy it from the custom uniform in the vertex shader */
    g_string_append (shader_state->source,
                     "  cogl_point_size_out = cogl_point_size_in;\n");
}
Esempio n. 20
0
static CoglBool
_cogl_driver_update_features (CoglContext *context,
                              CoglError **error)
{
    CoglPrivateFeatureFlags private_flags = 0;
    char **gl_extensions;

    /* We have to special case getting the pointer to the glGetString
       function because we need to use it to determine what functions we
       can expect */
    context->glGetString =
        (void *) _cogl_renderer_get_proc_address (context->display->renderer,
                "glGetString",
                TRUE);

    gl_extensions = _cogl_context_get_gl_extensions (context);

    if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS)))
    {
        char *all_extensions = g_strjoinv (" ", gl_extensions);

        COGL_NOTE (WINSYS,
                   "Checking features\n"
                   "  GL_VENDOR: %s\n"
                   "  GL_RENDERER: %s\n"
                   "  GL_VERSION: %s\n"
                   "  GL_EXTENSIONS: %s",
                   context->glGetString (GL_VENDOR),
                   context->glGetString (GL_RENDERER),
                   _cogl_context_get_gl_version (context),
                   all_extensions);

        g_free (all_extensions);
    }

    context->glsl_major = 1;
    context->glsl_minor = 0;

    _cogl_gpu_info_init (context, &context->gpu);

    _cogl_feature_check_ext_functions (context,
                                       -1 /* GL major version */,
                                       -1 /* GL minor version */,
                                       gl_extensions);

#ifdef HAVE_COGL_GLES
    if (context->driver == COGL_DRIVER_GLES1)
    {
        int max_clip_planes;
        GE( context, glGetIntegerv (GL_MAX_CLIP_PLANES, &max_clip_planes) );
        if (max_clip_planes >= 4)
            private_flags |= COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
    }
#endif

    if (context->driver == COGL_DRIVER_GLES2)
    {
        /* Note GLES 2 core doesn't support mipmaps for npot textures or
         * repeat modes other than CLAMP_TO_EDGE. */
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GLSL, TRUE);
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_RANGE, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_MIRRORED_REPEAT, TRUE);

        private_flags |= COGL_PRIVATE_FEATURE_BLEND_CONSTANT;
    }
    else if (context->driver == COGL_DRIVER_GLES1)
        private_flags |= (COGL_PRIVATE_FEATURE_FIXED_FUNCTION |
                          COGL_PRIVATE_FEATURE_ALPHA_TEST |
                          COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM);

    private_flags |= (COGL_PRIVATE_FEATURE_VBOS |
                      COGL_PRIVATE_FEATURE_ANY_GL |
                      COGL_PRIVATE_FEATURE_ALPHA_TEXTURES);

    /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
    COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_POINT_SPRITE, TRUE);

    if (context->glGenRenderbuffers)
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_OFFSCREEN, TRUE);

    if (context->glBlitFramebuffer)
        private_flags |= COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT;

    if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions))
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE);

    if (_cogl_check_extension ("GL_OES_depth_texture", gl_extensions))
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_DEPTH_TEXTURE, TRUE);

    if (_cogl_check_extension ("GL_OES_texture_npot", gl_extensions))
    {
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_REPEAT, TRUE);
    }
    else if (_cogl_check_extension ("GL_IMG_texture_npot", gl_extensions))
    {
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_BASIC, TRUE);
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_TEXTURE_NPOT_MIPMAP, TRUE);
    }

    if (context->glTexImage3D)
        COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TEXTURE_3D, TRUE);

    if (context->glMapBuffer)
        /* The GL_OES_mapbuffer extension doesn't support mapping for
           read */
        COGL_FLAGS_SET (context->features,
                        COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE);

    if (context->glEGLImageTargetTexture2D)
        private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE;

    if (_cogl_check_extension ("GL_OES_packed_depth_stencil", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL;

    if (_cogl_check_extension ("GL_EXT_texture_format_BGRA8888", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888;

    if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions))
        private_flags |= COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE;

    /* Cache features */
    context->private_feature_flags |= private_flags;

    g_strfreev (gl_extensions);

    return TRUE;
}
static CoglBool
_cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference)
{
  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
  GLuint gl_program;
  UpdateConstantsState state;

  _COGL_GET_CONTEXT (ctx, FALSE);

  if (shader_state->source)
    {
      GLenum gl_error;
      COGL_STATIC_COUNTER (fragend_arbfp_compile_counter,
                           "arbfp compile counter",
                           "Increments each time a new ARBfp "
                           "program is compiled",
                           0 /* no application private data */);

      COGL_COUNTER_INC (_cogl_uprof_context, fragend_arbfp_compile_counter);

      g_string_append (shader_state->source,
                       "MOV result.color,output;\n");
      g_string_append (shader_state->source, "END\n");

      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
        g_message ("pipeline program:\n%s", shader_state->source->str);

      GE (ctx, glGenPrograms (1, &shader_state->gl_program));

      GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB,
                              shader_state->gl_program));

      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
        ;
      ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
                            GL_PROGRAM_FORMAT_ASCII_ARB,
                            shader_state->source->len,
                            shader_state->source->str);
      if (ctx->glGetError () != GL_NO_ERROR)
        {
          g_warning ("\n%s\n%s",
                     shader_state->source->str,
                     ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
        }

      shader_state->source = NULL;
    }

  gl_program = shader_state->gl_program;

  GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
  _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_ARBFP);

  state.unit = 0;
  state.shader_state = shader_state;
  /* If this arbfp program was last used with a different pipeline
   * then we need to ensure we update all program.local params */
  state.update_all =
    pipeline != shader_state->last_used_for_pipeline;
  cogl_pipeline_foreach_layer (pipeline,
                               update_constants_cb,
                               &state);

  /* We need to track what pipeline used this arbfp program last since
   * we will need to update program.local params when switching
   * between different pipelines. */
  shader_state->last_used_for_pipeline = pipeline;

  return TRUE;
}
static CoglBool
_cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference,
                                    int n_tex_coord_attribs)
{
  CoglPipelineShaderState *shader_state;
  CoglPipeline *authority;
  CoglPipeline *template_pipeline = NULL;

  _COGL_GET_CONTEXT (ctx, FALSE);

  /* First validate that we can handle the current state using ARBfp
   */

  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
    return FALSE;

  /* TODO: support fog */
  if (_cogl_pipeline_get_fog_enabled (pipeline))
    return FALSE;

  /* Fragment snippets are only supported in the GLSL fragend */
  if (_cogl_pipeline_has_fragment_snippets (pipeline))
    return FALSE;

  /* Now lookup our ARBfp backend private state */
  shader_state = get_shader_state (pipeline);

  /* If we have a valid shader_state then we are all set and don't
   * need to generate a new program. */
  if (shader_state)
    return TRUE;

  /* If we don't have an associated arbfp program yet then find the
   * arbfp-authority (the oldest ancestor whose state will result in
   * the same program being generated as for this pipeline).
   *
   * We always make sure to associate new programs with the
   * arbfp-authority to maximize the chance that other pipelines can
   * share it.
   */
  authority = _cogl_pipeline_find_equivalent_parent
    (pipeline,
     _cogl_pipeline_get_state_for_fragment_codegen (ctx) &
     ~COGL_PIPELINE_STATE_LAYERS,
     _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
  shader_state = get_shader_state (authority);
  if (shader_state)
    {
      /* If we are going to share our program state with an arbfp-authority
       * then add a reference to the program state associated with that
       * arbfp-authority... */
      shader_state->ref_count++;
      set_shader_state (pipeline, shader_state);
      return TRUE;
    }

  /* If we haven't yet found an existing program then before we resort to
   * generating a new arbfp program we see if we can find a suitable
   * program in the pipeline_cache. */
  if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
    {
      template_pipeline =
        _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache,
                                                    authority);

      shader_state = get_shader_state (template_pipeline);

      if (shader_state)
        shader_state->ref_count++;
    }

  /* If we still haven't got a shader state then we'll have to create
     a new one */
  if (shader_state == NULL)
    {
      shader_state = shader_state_new (n_layers);

      /* We reuse a single grow-only GString for code-gen */
      g_string_set_size (ctx->codegen_source_buffer, 0);
      shader_state->source = ctx->codegen_source_buffer;
      g_string_append (shader_state->source,
                       "!!ARBfp1.0\n"
                       "TEMP output;\n"
                       "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
                       "PARAM half = {.5, .5, .5, .5};\n"
                       "PARAM one = {1, 1, 1, 1};\n"
                       "PARAM two = {2, 2, 2, 2};\n"
                       "PARAM minus_one = {-1, -1, -1, -1};\n");
    }

  set_shader_state (pipeline, shader_state);

  /* Since we have already resolved the arbfp-authority at this point
   * we might as well also associate any program we find from the cache
   * with the authority too... */
  if (authority != pipeline)
    {
      shader_state->ref_count++;
      set_shader_state (authority, shader_state);
    }

  /* If we found a template then we'll attach it to that too so that
     next time a similar pipeline is used it can use the same state */
  if (template_pipeline)
    {
      shader_state->ref_count++;
      set_shader_state (template_pipeline, shader_state);
    }

  return TRUE;
}
Esempio n. 23
0
static CoglBool
_cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
                                        CoglPipelineLayer *layer,
                                        unsigned long layers_difference)
{
  CoglTextureUnit *unit =
    _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer));
  int unit_index = unit->index;
  int n_rgb_func_args;
  int n_alpha_func_args;

  _COGL_GET_CONTEXT (ctx, FALSE);

  /* XXX: Beware that since we are changing the active texture unit we
   * must make sure we don't call into other Cogl components that may
   * temporarily bind texture objects to query/modify parameters since
   * they will end up binding texture unit 1. See
   * _cogl_bind_gl_texture_transient for more details.
   */
  _cogl_set_active_texture_unit (unit_index);

  if (G_UNLIKELY (unit_index >= get_max_texture_units ()))
    {
      _cogl_disable_texture_unit (unit_index);
      /* TODO: although this isn't considered an error that
       * warrants falling back to a different backend we
       * should print a warning here. */
      return TRUE;
    }

  /* Handle enabling or disabling the right texture type */
  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE)
    {
      CoglTextureType texture_type =
        _cogl_pipeline_layer_get_texture_type (layer);
      GLenum gl_target;

      switch (texture_type)
        {
        case COGL_TEXTURE_TYPE_2D:
          gl_target = GL_TEXTURE_2D;
          break;

        case COGL_TEXTURE_TYPE_3D:
          gl_target = GL_TEXTURE_3D;
          break;

        case COGL_TEXTURE_TYPE_RECTANGLE:
          gl_target = GL_TEXTURE_RECTANGLE_ARB;
          break;
        }

      _cogl_set_active_texture_unit (unit_index);

      /* The common GL code handles binding the right texture so we
         just need to handle enabling and disabling it */

      if (unit->enabled_gl_target != gl_target)
        {
          /* Disable the previous target if it's still enabled */
          if (unit->enabled_gl_target)
            GE (ctx, glDisable (unit->enabled_gl_target));

          /* Enable the new target */
          if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
            {
              GE (ctx, glEnable (gl_target));
              unit->enabled_gl_target = gl_target;
            }
        }
    }
  else
    {
      /* Even though there may be no difference between the last flushed
       * texture state and the current layers texture state it may be that the
       * texture unit has been disabled for some time so we need to assert that
       * it's enabled now.
       */
      if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)) &&
          unit->enabled_gl_target == 0)
        {
          _cogl_set_active_texture_unit (unit_index);
          GE (ctx, glEnable (unit->gl_target));
          unit->enabled_gl_target = unit->gl_target;
        }
    }

  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE)
    {
      CoglPipelineLayer *authority =
        _cogl_pipeline_layer_get_authority (layer,
                                            COGL_PIPELINE_LAYER_STATE_COMBINE);
      CoglPipelineLayerBigState *big_state = authority->big_state;
      GLenum sources[3];

      GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE));

      /* Set the combiner functions... */
      GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
                          GL_COMBINE_RGB,
                          big_state->texture_combine_rgb_func));
      GE (ctx, glTexEnvi (GL_TEXTURE_ENV,
                          GL_COMBINE_ALPHA,
                          big_state->texture_combine_alpha_func));

      /*
       * Setup the function arguments...
       */

      /* For the RGB components... */
      n_rgb_func_args =
        _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);

      translate_sources (pipeline,
                         n_rgb_func_args,
                         big_state->texture_combine_rgb_src,
                         sources);

      GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
                          sources[0]));
      GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
                          big_state->texture_combine_rgb_op[0]));
      if (n_rgb_func_args > 1)
        {
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
                              sources[1]));
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
                              big_state->texture_combine_rgb_op[1]));
        }
      if (n_rgb_func_args > 2)
        {
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_RGB,
                              sources[2]));
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_RGB,
                              big_state->texture_combine_rgb_op[2]));
        }

      /* For the Alpha component */
      n_alpha_func_args =
        _cogl_get_n_args_for_combine_func (big_state->texture_combine_alpha_func);

      translate_sources (pipeline,
                         n_alpha_func_args,
                         big_state->texture_combine_alpha_src,
                         sources);

      GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
                          sources[0]));
      GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
                          big_state->texture_combine_alpha_op[0]));
      if (n_alpha_func_args > 1)
        {
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
                              sources[1]));
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
                              big_state->texture_combine_alpha_op[1]));
        }
      if (n_alpha_func_args > 2)
        {
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_SRC2_ALPHA,
                              sources[2]));
          GE (ctx, glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
                              big_state->texture_combine_alpha_op[2]));
        }
    }

  if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
    {
      CoglPipelineLayer *authority =
        _cogl_pipeline_layer_get_authority
        (layer, COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT);
      CoglPipelineLayerBigState *big_state = authority->big_state;

      GE (ctx, glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,
                           big_state->texture_combine_constant));
    }

  return TRUE;
}
Esempio n. 24
0
/* In addition to writing the stack matrix into the give @matrix
 * argument this function *may* sometimes also return a pointer
 * to a matrix too so if we are querying the inverse matrix we
 * should query from the return matrix so that the result can
 * be cached within the stack. */
CoglMatrix *
cogl_matrix_entry_get (CoglMatrixEntry *entry,
                        CoglMatrix *matrix)
{
  int depth;
  CoglMatrixEntry *current;
  CoglMatrixEntry **children;
  int i;

  for (depth = 0, current = entry;
       current;
       current = current->parent, depth++)
    {
      switch (current->op)
        {
        case COGL_MATRIX_OP_LOAD_IDENTITY:
          cogl_matrix_init_identity (matrix);
          goto initialized;
        case COGL_MATRIX_OP_LOAD:
          {
            CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)current;
            *matrix = *load->matrix;
            goto initialized;
          }
        case COGL_MATRIX_OP_SAVE:
          {
            CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)current;
            if (!save->cache_valid)
              {
                CoglMagazine *matrices_magazine =
                  cogl_matrix_stack_matrices_magazine;
                save->cache = _cogl_magazine_chunk_alloc (matrices_magazine);
                cogl_matrix_entry_get (current->parent, save->cache);
                save->cache_valid = TRUE;
              }
            *matrix = *save->cache;
            goto initialized;
          }
        default:
          continue;
        }
    }

initialized:

  if (depth == 0)
    {
      switch (entry->op)
        {
        case COGL_MATRIX_OP_LOAD_IDENTITY:
        case COGL_MATRIX_OP_TRANSLATE:
        case COGL_MATRIX_OP_ROTATE:
        case COGL_MATRIX_OP_ROTATE_QUATERNION:
        case COGL_MATRIX_OP_ROTATE_EULER:
        case COGL_MATRIX_OP_SCALE:
        case COGL_MATRIX_OP_MULTIPLY:
          return NULL;

        case COGL_MATRIX_OP_LOAD:
          {
            CoglMatrixEntryLoad *load = (CoglMatrixEntryLoad *)entry;
            return load->matrix;
          }
        case COGL_MATRIX_OP_SAVE:
          {
            CoglMatrixEntrySave *save = (CoglMatrixEntrySave *)entry;
            return save->cache;
          }
        }
      g_warn_if_reached ();
      return NULL;
    }

#ifdef COGL_ENABLE_DEBUG
  if (!current)
    {
      g_warning ("Inconsistent matrix stack");
      return NULL;
    }

  entry->composite_gets++;
#endif

  children = g_alloca (sizeof (CoglMatrixEntry) * depth);

  /* We need walk the list of entries from the init/load/save entry
   * back towards the leaf node but the nodes don't link to their
   * children so we need to re-walk them here to add to a separate
   * array. */
  for (i = depth - 1, current = entry;
       i >= 0 && current;
       i--, current = current->parent)
    {
      children[i] = current;
    }

#ifdef COGL_ENABLE_DEBUG
  if (COGL_DEBUG_ENABLED (COGL_DEBUG_PERFORMANCE) &&
      entry->composite_gets >= 2)
    {
      COGL_NOTE (PERFORMANCE,
                 "Re-composing a matrix stack entry multiple times");
    }
#endif

  for (i = 0; i < depth; i++)
    {
      switch (children[i]->op)
        {
        case COGL_MATRIX_OP_TRANSLATE:
          {
            CoglMatrixEntryTranslate *translate =
              (CoglMatrixEntryTranslate *)children[i];
            cogl_matrix_translate (matrix,
                                   translate->x,
                                   translate->y,
                                   translate->z);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE:
          {
            CoglMatrixEntryRotate *rotate=
              (CoglMatrixEntryRotate *)children[i];
            cogl_matrix_rotate (matrix,
                                rotate->angle,
                                rotate->x,
                                rotate->y,
                                rotate->z);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE_EULER:
          {
            CoglMatrixEntryRotateEuler *rotate =
              (CoglMatrixEntryRotateEuler *)children[i];
            CoglEuler euler;
            cogl_euler_init (&euler,
                             rotate->heading,
                             rotate->pitch,
                             rotate->roll);
            cogl_matrix_rotate_euler (matrix,
                                      &euler);
            continue;
          }
        case COGL_MATRIX_OP_ROTATE_QUATERNION:
          {
            CoglMatrixEntryRotateQuaternion *rotate =
              (CoglMatrixEntryRotateQuaternion *)children[i];
            CoglQuaternion quaternion;
            cogl_quaternion_init_from_array (&quaternion, rotate->values);
            cogl_matrix_rotate_quaternion (matrix, &quaternion);
            continue;
          }
        case COGL_MATRIX_OP_SCALE:
          {
            CoglMatrixEntryScale *scale =
              (CoglMatrixEntryScale *)children[i];
            cogl_matrix_scale (matrix,
                               scale->x,
                               scale->y,
                               scale->z);
            continue;
          }
        case COGL_MATRIX_OP_MULTIPLY:
          {
            CoglMatrixEntryMultiply *multiply =
              (CoglMatrixEntryMultiply *)children[i];
            cogl_matrix_multiply (matrix, matrix, multiply->matrix);
            continue;
          }

        case COGL_MATRIX_OP_LOAD_IDENTITY:
        case COGL_MATRIX_OP_LOAD:
        case COGL_MATRIX_OP_SAVE:
          g_warn_if_reached ();
          continue;
        }
    }

  return NULL;
}