コード例 #1
0
ファイル: cogl-texture-2d-gl.c プロジェクト: endlessm/mutter
static gboolean
allocate_custom_egl_image_external (CoglTexture2D *tex_2d,
                                    CoglTextureLoader *loader,
                                    CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_2d);
  CoglContext *ctx = tex->context;
  CoglPixelFormat external_format;
  CoglPixelFormat internal_format;

  external_format = loader->src.egl_image_external.format;
  internal_format = _cogl_texture_determine_internal_format (tex,
                                                             external_format);

  _cogl_gl_util_clear_gl_errors (ctx);

  GE (ctx, glActiveTexture (GL_TEXTURE0));
  GE (ctx, glGenTextures (1, &tex_2d->gl_texture));

  GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES,
                          tex_2d->gl_texture));

  if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR)
    {
      _cogl_set_error (error,
                       COGL_TEXTURE_ERROR,
                       COGL_TEXTURE_ERROR_BAD_PARAMETER,
                       "Could not create a CoglTexture2D from a given "
                       "EGLImage");
      GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) );
      return FALSE;
    }

  GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES,
                           GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
  GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES,
                           GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));

  if (!loader->src.egl_image_external.alloc (tex_2d,
                                             tex_2d->egl_image_external.user_data,
                                             error))
    {
      GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0));
      GE (ctx, glDeleteTextures (1, &tex_2d->gl_texture));
      return FALSE;
    }

  GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0));

  tex_2d->internal_format = internal_format;
  tex_2d->gl_target = GL_TEXTURE_EXTERNAL_OES;

  return TRUE;
}
コード例 #2
0
ファイル: cogl-texture-2d-gl.c プロジェクト: endlessm/mutter
static gboolean
allocate_from_egl_image (CoglTexture2D *tex_2d,
                         CoglTextureLoader *loader,
                         CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_2d);
  CoglContext *ctx = tex->context;
  CoglPixelFormat internal_format = loader->src.egl_image.format;

  tex_2d->gl_texture =
    ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                   tex_2d->gl_texture,
                                   FALSE);
  _cogl_gl_util_clear_gl_errors (ctx);

  ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image);
  if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR)
    {
      _cogl_set_error (error,
                       COGL_TEXTURE_ERROR,
                       COGL_TEXTURE_ERROR_BAD_PARAMETER,
                       "Could not create a CoglTexture2D from a given "
                       "EGLImage");
      GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) );
      return FALSE;
    }

  tex_2d->internal_format = internal_format;

  _cogl_texture_set_allocated (tex,
                               internal_format,
                               loader->src.egl_image.width,
                               loader->src.egl_image.height);

  return TRUE;
}
コード例 #3
0
ファイル: cogl-texture-3d.c プロジェクト: collinss/muffin
static CoglBool
allocate_with_size (CoglTexture3D *tex_3d,
                    CoglTextureLoader *loader,
                    CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_3d);
  CoglContext *ctx = tex->context;
  CoglPixelFormat internal_format;
  int width = loader->src.sized.width;
  int height = loader->src.sized.height;
  int depth = loader->src.sized.depth;
  GLenum gl_intformat;
  GLenum gl_format;
  GLenum gl_type;
  GLenum gl_texture;

  internal_format =
    _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);

  if (!_cogl_texture_3d_can_create (ctx,
                                    width,
                                    height,
                                    depth,
                                    internal_format,
                                    error))
    return FALSE;

  ctx->driver_vtable->pixel_format_to_gl (ctx,
                                          internal_format,
                                          &gl_intformat,
                                          &gl_format,
                                          &gl_type);

  gl_texture =
    ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
  _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
                                   gl_texture,
                                   FALSE);
  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
                     width, height, depth,
                     0, gl_format, gl_type, NULL);

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    {
      GE( ctx, glDeleteTextures (1, &gl_texture) );
      return FALSE;
    }

  tex_3d->gl_texture = gl_texture;
  tex_3d->gl_format = gl_intformat;

  tex_3d->depth = depth;

  tex_3d->internal_format = internal_format;

  _cogl_texture_set_allocated (tex, internal_format, width, height);

  return TRUE;
}
コード例 #4
0
ファイル: cogl-texture-2d-gl.c プロジェクト: endlessm/mutter
static gboolean
allocate_from_gl_foreign (CoglTexture2D *tex_2d,
                          CoglTextureLoader *loader,
                          CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_2d);
  CoglContext *ctx = tex->context;
  CoglPixelFormat format = loader->src.gl_foreign.format;
  GLint gl_compressed = GL_FALSE;
  GLenum gl_int_format = 0;

  if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Foreign GL_TEXTURE_2D textures are not "
                       "supported by your system");
      return FALSE;
    }

  /* Make sure binding succeeds */
  _cogl_gl_util_clear_gl_errors (ctx);

  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                   loader->src.gl_foreign.gl_handle, TRUE);
  if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Failed to bind foreign GL_TEXTURE_2D texture");
      return FALSE;
    }

  /* Obtain texture parameters
     (only level 0 we are interested in) */

#ifdef HAVE_COGL_GL
  if (_cogl_has_private_feature
      (ctx, COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS))
    {
      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
                                         GL_TEXTURE_COMPRESSED,
                                         &gl_compressed) );

      {
        GLint val;

        GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
                                           GL_TEXTURE_INTERNAL_FORMAT,
                                           &val) );

        gl_int_format = val;
      }

      /* If we can query GL for the actual pixel format then we'll ignore
         the passed in format and use that. */
      if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
                                                              gl_int_format,
                                                              &format))
        {
          _cogl_set_error (error,
                           COGL_SYSTEM_ERROR,
                           COGL_SYSTEM_ERROR_UNSUPPORTED,
                           "Unsupported internal format for foreign texture");
          return FALSE;
        }
    }
  else
#endif
    {
      /* Otherwise we'll assume we can derive the GL format from the
         passed in format */
      ctx->driver_vtable->pixel_format_to_gl (ctx,
                                              format,
                                              &gl_int_format,
                                              NULL,
                                              NULL);
    }

  /* Compressed texture images not supported */
  if (gl_compressed == GL_TRUE)
    {
      _cogl_set_error (error,
                       COGL_SYSTEM_ERROR,
                       COGL_SYSTEM_ERROR_UNSUPPORTED,
                       "Compressed foreign textures aren't currently supported");
      return FALSE;
    }

  /* Note: previously this code would query the texture object for
     whether it has GL_GENERATE_MIPMAP enabled to determine whether to
     auto-generate the mipmap. This doesn't make much sense any more
     since Cogl switch to using glGenerateMipmap. Ideally I think
     cogl_texture_2d_gl_new_from_foreign should take a flags parameter so
     that the application can decide whether it wants
     auto-mipmapping. To be compatible with existing code, Cogl now
     disables its own auto-mipmapping but leaves the value of
     GL_GENERATE_MIPMAP alone so that it would still work but without
     the dirtiness tracking that Cogl would do. */

  _cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE);

  /* Setup bitmap info */
  tex_2d->is_foreign = TRUE;
  tex_2d->mipmaps_dirty = TRUE;

  tex_2d->gl_texture = loader->src.gl_foreign.gl_handle;
  tex_2d->gl_internal_format = gl_int_format;

  /* Unknown filter */
  tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
  tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE;

  tex_2d->internal_format = format;

  _cogl_texture_set_allocated (tex,
                               format,
                               loader->src.gl_foreign.width,
                               loader->src.gl_foreign.height);
  return TRUE;
}
コード例 #5
0
ファイル: cogl-texture-2d-gl.c プロジェクト: endlessm/mutter
static gboolean
allocate_with_size (CoglTexture2D *tex_2d,
                    CoglTextureLoader *loader,
                    CoglError **error)
{
  CoglTexture *tex = COGL_TEXTURE (tex_2d);
  CoglPixelFormat internal_format;
  int width = loader->src.sized.width;
  int height = loader->src.sized.height;
  CoglContext *ctx = tex->context;
  GLenum gl_intformat;
  GLenum gl_format;
  GLenum gl_type;
  GLenum gl_texture;

  internal_format =
    _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);

  if (!_cogl_texture_2d_gl_can_create (ctx,
                                       width,
                                       height,
                                       internal_format))
    {
      _cogl_set_error (error, COGL_TEXTURE_ERROR,
                       COGL_TEXTURE_ERROR_SIZE,
                       "Failed to create texture 2d due to size/format"
                       " constraints");
      return FALSE;
    }

  ctx->driver_vtable->pixel_format_to_gl (ctx,
                                          internal_format,
                                          &gl_intformat,
                                          &gl_format,
                                          &gl_type);

  gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);

  tex_2d->gl_internal_format = gl_intformat;

  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                   gl_texture,
                                   tex_2d->is_foreign);

  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
                     width, height, 0, gl_format, gl_type, NULL);

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    {
      GE( ctx, glDeleteTextures (1, &gl_texture) );
      return FALSE;
    }

  tex_2d->gl_texture = gl_texture;
  tex_2d->gl_internal_format = gl_intformat;

  tex_2d->internal_format = internal_format;

  _cogl_texture_set_allocated (tex, internal_format, width, height);

  return TRUE;
}
コード例 #6
0
static CoglBool
_cogl_texture_driver_upload_to_gl_3d (CoglContext *ctx,
                                      GLenum gl_target,
                                      GLuint gl_handle,
                                      CoglBool is_foreign,
                                      GLint height,
                                      GLint depth,
                                      CoglBitmap *source_bmp,
                                      GLint internal_gl_format,
                                      GLuint source_gl_format,
                                      GLuint source_gl_type,
                                      CoglError **error)
{
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  int rowstride = cogl_bitmap_get_rowstride (source_bmp);
  int bmp_width = cogl_bitmap_get_width (source_bmp);
  int bmp_height = cogl_bitmap_get_height (source_bmp);
  uint8_t *data;

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* If the rowstride or image height can't be specified with just
     GL_ALIGNMENT alone then we need to copy the bitmap because there
     is no GL_ROW_LENGTH */
  if (rowstride / bpp != bmp_width ||
      height != bmp_height / depth)
    {
      CoglBitmap *bmp;
      int image_height = bmp_height / depth;
      CoglPixelFormat source_bmp_format = cogl_bitmap_get_format (source_bmp);
      int i;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, bmp_width * bpp, bpp);

      /* Initialize the texture with empty data and then upload each
         image with a sub-region update */

      /* Clear any GL errors */
      _cogl_gl_util_clear_gl_errors (ctx);

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         NULL);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        return FALSE;

      bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
                                                 bmp_width,
                                                 height,
                                                 source_bmp_format,
                                                 error);
      if (!bmp)
        return FALSE;

      for (i = 0; i < depth; i++)
        {
          if (!_cogl_bitmap_copy_subregion (source_bmp,
                                            bmp,
                                            0, image_height * i,
                                            0, 0,
                                            bmp_width,
                                            height,
                                            error))
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          data = _cogl_bitmap_gl_bind (bmp,
                                       COGL_BUFFER_ACCESS_READ, 0, error);
          if (!data)
            {
              cogl_object_unref (bmp);
              return FALSE;
            }

          /* Clear any GL errors */
          _cogl_gl_util_clear_gl_errors (ctx);

          ctx->glTexSubImage3D (gl_target,
                                0, /* level */
                                0, /* xoffset */
                                0, /* yoffset */
                                i, /* zoffset */
                                bmp_width, /* width */
                                height, /* height */
                                1, /* depth */
                                source_gl_format,
                                source_gl_type,
                                data);

          if (_cogl_gl_util_catch_out_of_memory (ctx, error))
            {
              cogl_object_unref (bmp);
              _cogl_bitmap_gl_unbind (bmp);
              return FALSE;
            }

          _cogl_bitmap_gl_unbind (bmp);
        }

      cogl_object_unref (bmp);
    }
  else
    {
      data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, error);
      if (!data)
        return FALSE;

      _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);

      /* Clear any GL errors */
      _cogl_gl_util_clear_gl_errors (ctx);

      ctx->glTexImage3D (gl_target,
                         0, /* level */
                         internal_gl_format,
                         bmp_width,
                         height,
                         depth,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);

      if (_cogl_gl_util_catch_out_of_memory (ctx, error))
        {
          _cogl_bitmap_gl_unbind (source_bmp);
          return FALSE;
        }

      _cogl_bitmap_gl_unbind (source_bmp);
    }

  return TRUE;
}
コード例 #7
0
static CoglBool
_cogl_texture_driver_upload_to_gl (CoglContext *ctx,
                                   GLenum gl_target,
                                   GLuint gl_handle,
                                   CoglBool is_foreign,
                                   CoglBitmap *source_bmp,
                                   GLint internal_gl_format,
                                   GLuint source_gl_format,
                                   GLuint source_gl_type,
                                   CoglError **error)
{
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  int rowstride;
  int bmp_width = cogl_bitmap_get_width (source_bmp);
  int bmp_height = cogl_bitmap_get_height (source_bmp);
  CoglBitmap *bmp;
  uint8_t *data;
  CoglError *internal_error = NULL;
  CoglBool status = TRUE;

  bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error);
  if (!bmp)
    return FALSE;

  rowstride = cogl_bitmap_get_rowstride (bmp);

  /* Setup gl alignment to match rowstride and top-left corner */
  _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp);

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  data = _cogl_bitmap_gl_bind (bmp,
                               COGL_BUFFER_ACCESS_READ,
                               0, /* hints */
                               &internal_error);

  /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we
   * have to explicitly check the cogl error pointer to catch
   * problems... */
  if (internal_error)
    {
      cogl_object_unref (bmp);
      _cogl_propagate_error (error, internal_error);
      return FALSE;
    }

  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  ctx->glTexImage2D (gl_target, 0,
                     internal_gl_format,
                     bmp_width, bmp_height,
                     0,
                     source_gl_format,
                     source_gl_type,
                     data);

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    status = FALSE;

  _cogl_bitmap_gl_unbind (bmp);

  cogl_object_unref (bmp);

  return status;
}
コード例 #8
0
static CoglBool
_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
                                             CoglTexture *texture,
                                             CoglBool is_foreign,
                                             int src_x,
                                             int src_y,
                                             int dst_x,
                                             int dst_y,
                                             int width,
                                             int height,
                                             int level,
                                             CoglBitmap *source_bmp,
				             GLuint source_gl_format,
				             GLuint source_gl_type,
                                             CoglError **error)
{
  GLenum gl_target;
  GLuint gl_handle;
  uint8_t *data;
  CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
  int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
  CoglBitmap *slice_bmp;
  int rowstride;
  CoglBool status = TRUE;
  CoglError *internal_error = NULL;
  int level_width;
  int level_height;

  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);

  /* If we have the GL_EXT_unpack_subimage extension then we can
     upload from subregions directly. Otherwise we may need to copy
     the bitmap */
  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) &&
      (src_x != 0 || src_y != 0 ||
       width != cogl_bitmap_get_width (source_bmp) ||
       height != cogl_bitmap_get_height (source_bmp)))
    {
      slice_bmp =
        _cogl_bitmap_new_with_malloc_buffer (ctx,
                                             width, height,
                                             source_format,
                                             error);
      if (!slice_bmp)
        return FALSE;

      if (!_cogl_bitmap_copy_subregion (source_bmp,
                                        slice_bmp,
                                        src_x, src_y,
                                        0, 0, /* dst_x/y */
                                        width, height,
                                        error))
        {
          cogl_object_unref (slice_bmp);
          return FALSE;
        }

      src_x = src_y = 0;
    }
  else
    {
      slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error);
      if (!slice_bmp)
        return FALSE;
    }

  rowstride = cogl_bitmap_get_rowstride (slice_bmp);

  /* Setup gl alignment to match rowstride and top-left corner */
  prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp);

  data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error);

  /* NB: _cogl_bitmap_gl_bind() may return NULL when successfull so we
   * have to explicitly check the cogl error pointer to catch
   * problems... */
  if (internal_error)
    {
      _cogl_propagate_error (error, internal_error);
      cogl_object_unref (slice_bmp);
      return FALSE;
    }

  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);

  /* Clear any GL errors */
  _cogl_gl_util_clear_gl_errors (ctx);

  _cogl_texture_get_level_size (texture,
                                level,
                                &level_width,
                                &level_height,
                                NULL);

  if (level_width == width && level_height == height)
    {
      /* GL gets upset if you use glTexSubImage2D to define the
       * contents of a mipmap level so we make sure to use
       * glTexImage2D if we are uploading a full mipmap level.
       */
      ctx->glTexImage2D (gl_target,
                         level,
                         _cogl_texture_gl_get_format (texture),
                         width,
                         height,
                         0,
                         source_gl_format,
                         source_gl_type,
                         data);
    }
  else
    {
      /* GL gets upset if you use glTexSubImage2D to initialize the
       * contents of a mipmap level so if this is the first time
       * we've seen a request to upload to this level we call
       * glTexImage2D first to assert that the storage for this
       * level exists.
       */
      if (texture->max_level < level)
        {
          ctx->glTexImage2D (gl_target,
                             level,
                             _cogl_texture_gl_get_format (texture),
                             level_width,
                             level_height,
                             0,
                             source_gl_format,
                             source_gl_type,
                             NULL);
        }

      ctx->glTexSubImage2D (gl_target,
                            level,
                            dst_x, dst_y,
                            width, height,
                            source_gl_format,
                            source_gl_type,
                            data);
    }

  if (_cogl_gl_util_catch_out_of_memory (ctx, error))
    status = FALSE;

  _cogl_bitmap_gl_unbind (slice_bmp);

  cogl_object_unref (slice_bmp);

  return status;
}
コード例 #9
0
ファイル: cogl-shader.c プロジェクト: collinss/muffin
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);
        }
    }
}