[Cogl] [PATCH 1/2] Use GL_ARB_texture_swizzle to emulate GL_ALPHA textures

Robert Bragg robert at sixbynine.org
Fri Nov 23 06:37:22 PST 2012


This looks good to me:

Reviewed-by: Robert Bragg <robert at linux.intel.com>

thanks,
- Robert


On Mon, Nov 19, 2012 at 5:28 PM, Neil Roberts <neil at linux.intel.com> wrote:

> The core profile of GL3 has removed support for component-alpha
> textures. Previously the GL3 driver would just ignore this and try to
> create them anyway. This would generate a GL error on Mesa.
>
> To fix this the GL texture driver will now create a GL_RED texture
> when GL_ALPHA textures are not supported natively. It will then set a
> texture swizzle using the GL_ARB_texture_swizzle extension so that the
> alpha component will be taken from the red component of the texture.
> The swizzle is part of the texture object state so it only needs to be
> set once when the texture is created.
>
> The ‘gen’ virtual function of the texture driver has been changed to
> also take the internal format as a parameter. The GL driver will now
> set the swizzle as appropriate here.
>
> The GL3 driver now reports an error if the texture swizzle extension
> is not available because Cogl can't really work properly without out
> it. The extension is part of GL 3.3 so it is quite likely that it has
> wide support from drivers. Eventually we could get rid of this
> requirement if we have our own GLSL front-end and we could generate
> the swizzle ourselves.
>
> When uploading or downloading texture data to or from a
> component-alpha texture, we can no longer rely on GL to do the
> conversion. The swizzle doesn't have any effect on the texture data
> functions. In these cases Cogl will now force an intermediate buffer
> to be used and it will manually do the conversion as it does for the
> GLES drivers.
> ---
>  cogl/cogl-internal.h                           |  4 +-
>  cogl/cogl-texture-3d.c                         |  6 ++-
>  cogl/cogl-texture-driver.h                     |  5 +-
>  cogl/cogl-texture-rectangle.c                  | 16 +++---
>  cogl/cogl-texture.c                            | 38 +++++++++++++-
>  cogl/driver/gl/cogl-texture-2d-gl.c            |  9 ++--
>  cogl/driver/gl/gl/cogl-driver-gl.c             | 39 ++++++++++++--
>  cogl/driver/gl/gl/cogl-texture-driver-gl.c     | 70
> +++++++++++++++-----------
>  cogl/driver/gl/gles/cogl-driver-gles.c         |  3 +-
>  cogl/driver/gl/gles/cogl-texture-driver-gles.c | 40 +++++++--------
>  10 files changed, 159 insertions(+), 71 deletions(-)
>
> diff --git a/cogl/cogl-internal.h b/cogl/cogl-internal.h
> index 97f10d8..fa921a6 100644
> --- a/cogl/cogl-internal.h
> +++ b/cogl/cogl-internal.h
> @@ -114,7 +114,9 @@ typedef enum
>    COGL_PRIVATE_FEATURE_BLEND_CONSTANT = 1L<<18,
>    COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS = 1L<<19,
>    COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM = 1L<<20,
> -  COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS = 1L<<21
> +  COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS = 1L<<21,
> +  COGL_PRIVATE_FEATURE_ALPHA_TEXTURES = 1L<<22,
> +  COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE = 1L<<23
>  } CoglPrivateFeatureFlags;
>
>  /* Sometimes when evaluating pipelines, either during comparisons or
> diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
> index 6000b37..de00cb1 100644
> --- a/cogl/cogl-texture-3d.c
> +++ b/cogl/cogl-texture-3d.c
> @@ -234,7 +234,8 @@ cogl_texture_3d_new_with_size (CoglContext *ctx,
>                                           width, height, depth,
>                                           internal_format);
>
> -  ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, 1, &tex_3d->gl_texture);
> +  tex_3d->gl_texture =
> +    ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
>    _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
>                                     tex_3d->gl_texture,
>                                     FALSE);
> @@ -308,7 +309,8 @@ cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
>        _cogl_bitmap_unmap (dst_bmp);
>      }
>
> -  ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, 1, &tex_3d->gl_texture);
> +  tex_3d->gl_texture =
> +    ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
>
>    ctx->texture_driver->upload_to_gl_3d (ctx,
>                                          GL_TEXTURE_3D,
> diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl-texture-driver.h
> index d4b2b0d..7a186ba 100644
> --- a/cogl/cogl-texture-driver.h
> +++ b/cogl/cogl-texture-driver.h
> @@ -33,11 +33,10 @@ struct _CoglTextureDriver
>     * non-mipmap filters when creating textures. This is to save some
> memory as
>     * the driver will not allocate room for the mipmap tree.
>     */
> -  void
> +  GLuint
>    (* gen) (CoglContext *ctx,
>             GLenum gl_target,
> -           GLsizei n,
> -           GLuint *textures);
> +           CoglPixelFormat internal_format);
>
>    /*
>     * This sets up the glPixelStore state for an upload to a destination
> with
> diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
> index 3dca1ed..1ffeb83 100644
> --- a/cogl/cogl-texture-rectangle.c
> +++ b/cogl/cogl-texture-rectangle.c
> @@ -219,10 +219,10 @@ cogl_texture_rectangle_new_with_size (CoglContext
> *ctx,
>                                                    width, height,
>                                                    internal_format);
>
> -  ctx->texture_driver->gen (ctx,
> -                            GL_TEXTURE_RECTANGLE_ARB,
> -                            1, /* num textures */
> -                            &tex_rect->gl_texture);
> +  tex_rect->gl_texture =
> +    ctx->texture_driver->gen (ctx,
> +                              GL_TEXTURE_RECTANGLE_ARB,
> +                              internal_format);
>    _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
>                                     tex_rect->gl_texture,
>                                     tex_rect->is_foreign);
> @@ -274,10 +274,10 @@ cogl_texture_rectangle_new_from_bitmap (CoglBitmap
> *bmp,
>                                                    cogl_bitmap_get_height
> (bmp),
>                                                    internal_format);
>
> -  ctx->texture_driver->gen (ctx,
> -                            GL_TEXTURE_RECTANGLE_ARB,
> -                            1, /* num textures */
> -                            &tex_rect->gl_texture);
> +  tex_rect->gl_texture =
> +    ctx->texture_driver->gen (ctx,
> +                              GL_TEXTURE_RECTANGLE_ARB,
> +                              internal_format);
>    ctx->texture_driver->upload_to_gl (ctx,
>                                       GL_TEXTURE_RECTANGLE_ARB,
>                                       tex_rect->gl_texture,
> diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
> index 12be86e..7fc796c 100644
> --- a/cogl/cogl-texture.c
> +++ b/cogl/cogl-texture.c
> @@ -176,7 +176,15 @@ _cogl_texture_prepare_for_upload (CoglBitmap
>  *src_bmp,
>       limited number of formats so we must convert using the Cogl
>       bitmap code instead */
>
> -  if ((ctx->private_feature_flags &
> COGL_PRIVATE_FEATURE_FORMAT_CONVERSION))
> +  /* If the driver doesn't natively support alpha textures then it
> +   * won't work correctly to convert to/from component-alpha
> +   * textures */
> +
> +  if ((ctx->private_feature_flags &
> COGL_PRIVATE_FEATURE_FORMAT_CONVERSION) &&
> +      ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEXTURES)
> ||
> +       (src_format != COGL_PIXEL_FORMAT_A_8 &&
> +        dst_format != COGL_PIXEL_FORMAT_A_8) ||
> +       src_format == dst_format))
>      {
>        /* If the source format does not have the same premult flag as the
>           dst format then we need to copy and convert it */
> @@ -1146,6 +1154,34 @@ cogl_texture_get_data (CoglTexture *texture,
>      closest_format = ((closest_format & ~COGL_PREMULT_BIT) |
>                        (texture_format & COGL_PREMULT_BIT));
>
> +  /* If the application is requesting a conversion from a
> +   * component-alpha texture and the driver doesn't support them
> +   * natively then we can only read into an alpha-format buffer. In
> +   * this case the driver will be faking the alpha textures with a
> +   * red-component texture and it won't swizzle to the correct format
> +   * while reading */
> +  if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_ALPHA_TEXTURES)
> == 0)
> +    {
> +      if (texture_format == COGL_PIXEL_FORMAT_A_8)
> +        {
> +          closest_format = COGL_PIXEL_FORMAT_A_8;
> +          closest_gl_format = GL_RED;
> +          closest_gl_type = GL_UNSIGNED_BYTE;
> +        }
> +      else if (format == COGL_PIXEL_FORMAT_A_8)
> +        {
> +          /* If we are converting to a component-alpha texture then we
> +           * need to read all of the components to a temporary buffer
> +           * because there is no way to get just the 4th component.
> +           * Note: it doesn't matter whether the texture is
> +           * pre-multiplied here because we're only going to look at
> +           * the alpha component */
> +          closest_format = COGL_PIXEL_FORMAT_RGBA_8888;
> +          closest_gl_format = GL_RGBA;
> +          closest_gl_type = GL_UNSIGNED_BYTE;
> +        }
> +    }
> +
>    /* Is the requested format supported? */
>    if (closest_format == format)
>      /* Target user data directly */
> diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c
> b/cogl/driver/gl/cogl-texture-2d-gl.c
> index ecb3d1e..8e07017 100644
> --- a/cogl/driver/gl/cogl-texture-2d-gl.c
> +++ b/cogl/driver/gl/cogl-texture-2d-gl.c
> @@ -108,7 +108,8 @@ _cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
>                                           width, height,
>                                           internal_format);
>
> -  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
> +  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,
>                                     tex_2d->is_foreign);
> @@ -164,7 +165,8 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
>        _cogl_bitmap_unmap (dst_bmp);
>      }
>
> -  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
> +  tex_2d->gl_texture =
> +    ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
>    ctx->texture_driver->upload_to_gl (ctx,
>                                       GL_TEXTURE_2D,
>                                       tex_2d->gl_texture,
> @@ -198,7 +200,8 @@ _cogl_egl_texture_2d_gl_new_from_image (CoglContext
> *ctx,
>                                           width, height,
>                                           format);
>
> -  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
> +  tex_2d->gl_texture =
> +    ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, format);
>    _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
>                                     tex_2d->gl_texture,
>                                     FALSE);
> diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c
> b/cogl/driver/gl/gl/cogl-driver-gl.c
> index 142260f..c944718 100644
> --- a/cogl/driver/gl/gl/cogl-driver-gl.c
> +++ b/cogl/driver/gl/gl/cogl-driver-gl.c
> @@ -54,6 +54,10 @@ _cogl_driver_pixel_format_from_gl_internal (CoglContext
> *context,
>      {
>      case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8:
>      case GL_ALPHA12: case GL_ALPHA16:
> +      /* Cogl only supports one single-component texture so if we have
> +       * ended up with a red texture then it is probably being used as
> +       * a component-alpha texture */
> +    case GL_RED:
>
>        *out_format = COGL_PIXEL_FORMAT_A_8;
>        return TRUE;
> @@ -98,8 +102,20 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
>    switch (format)
>      {
>      case COGL_PIXEL_FORMAT_A_8:
> -      glintformat = GL_ALPHA;
> -      glformat = GL_ALPHA;
> +      /* If the driver doesn't natively support alpha textures then we
> +       * will use a red component texture with a swizzle to implement
> +       * the texture */
> +      if ((context->private_feature_flags &
> +           COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) == 0)
> +        {
> +          glintformat = GL_RED;
> +          glformat = GL_RED;
> +        }
> +      else
> +        {
> +          glintformat = GL_ALPHA;
> +          glformat = GL_ALPHA;
> +        }
>        gltype = GL_UNSIGNED_BYTE;
>        break;
>      case COGL_PIXEL_FORMAT_G_8:
> @@ -532,11 +548,17 @@ _cogl_driver_update_features (CoglContext *ctx,
>    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;
> +
>    if (ctx->driver == COGL_DRIVER_GL)
>      /* Features which are not available in GL 3 */
>      private_flags |= (COGL_PRIVATE_FEATURE_FIXED_FUNCTION |
>                        COGL_PRIVATE_FEATURE_ALPHA_TEST |
> -                      COGL_PRIVATE_FEATURE_QUADS);
> +                      COGL_PRIVATE_FEATURE_QUADS |
> +                      COGL_PRIVATE_FEATURE_ALPHA_TEXTURES);
>
>    private_flags |= (COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT |
>                      COGL_PRIVATE_FEATURE_ANY_GL |
> @@ -550,6 +572,17 @@ _cogl_driver_update_features (CoglContext *ctx,
>
>    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;
>  }
>
> diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c
> b/cogl/driver/gl/gl/cogl-texture-driver-gl.c
> index 3c681c3..87c33ba 100644
> --- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c
> +++ b/cogl/driver/gl/gl/cogl-texture-driver-gl.c
> @@ -44,41 +44,55 @@
>  #include <stdlib.h>
>  #include <math.h>
>
> -static void
> +#ifndef GL_TEXTURE_SWIZZLE_RGBA
> +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
> +#endif
> +
> +static GLuint
>  _cogl_texture_driver_gen (CoglContext *ctx,
>                            GLenum gl_target,
> -                          GLsizei n,
> -                          GLuint *textures)
> +                          CoglPixelFormat internal_format)
>  {
> -  unsigned int i;
> +  GLuint tex;
>
> -  GE (ctx, glGenTextures (n, textures));
> +  GE (ctx, glGenTextures (1, &tex));
>
> -  for (i = 0; i < n; i++)
> +  _cogl_bind_gl_texture_transient (gl_target, tex, FALSE);
> +
> +  switch (gl_target)
>      {
> -      _cogl_bind_gl_texture_transient (gl_target,
> -                                       textures[i],
> -                                       FALSE);
> -
> -      switch (gl_target)
> -        {
> -        case GL_TEXTURE_2D:
> -        case GL_TEXTURE_3D:
> -          /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set
> it */
> -          GE( ctx, glTexParameteri (gl_target,
> -                                    GL_TEXTURE_MIN_FILTER,
> -                                    GL_LINEAR) );
> -          break;
> -
> -        case GL_TEXTURE_RECTANGLE_ARB:
> -          /* Texture rectangles already default to GL_LINEAR so nothing
> -             needs to be done */
> -          break;
> -
> -        default:
> -          g_assert_not_reached();
> -        }
> +    case GL_TEXTURE_2D:
> +    case GL_TEXTURE_3D:
> +      /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
> +      GE( ctx, glTexParameteri (gl_target,
> +                                GL_TEXTURE_MIN_FILTER,
> +                                GL_LINEAR) );
> +      break;
> +
> +    case GL_TEXTURE_RECTANGLE_ARB:
> +      /* Texture rectangles already default to GL_LINEAR so nothing
> +         needs to be done */
> +      break;
> +
> +    default:
> +      g_assert_not_reached();
>      }
> +
> +  /* If the driver doesn't support alpha textures directly then we'll
> +   * fake them by setting the swizzle parameters */
> +  if (internal_format == COGL_PIXEL_FORMAT_A_8 &&
> +      (ctx->private_feature_flags & (COGL_PRIVATE_FEATURE_ALPHA_TEXTURES |
> +
> COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) ==
> +      COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)
> +    {
> +      static const GLint red_swizzle[] = { GL_ZERO, GL_ZERO, GL_ZERO,
> GL_RED };
> +
> +      GE( ctx, glTexParameteriv (gl_target,
> +                                 GL_TEXTURE_SWIZZLE_RGBA,
> +                                 red_swizzle) );
> +    }
> +
> +  return tex;
>  }
>
>  /* OpenGL - unlike GLES - can upload a sub region of pixel data from a
> larger
> diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c
> b/cogl/driver/gl/gles/cogl-driver-gles.c
> index 0e2b465..5630c66 100644
> --- a/cogl/driver/gl/gles/cogl-driver-gles.c
> +++ b/cogl/driver/gl/gles/cogl-driver-gles.c
> @@ -266,7 +266,8 @@ _cogl_driver_update_features (CoglContext *context,
>                        COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM);
>
>    private_flags |= (COGL_PRIVATE_FEATURE_VBOS |
> -                    COGL_PRIVATE_FEATURE_ANY_GL);
> +                    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);
> diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c
> b/cogl/driver/gl/gles/cogl-texture-driver-gles.c
> index 65407b6..1e45a53 100644
> --- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c
> +++ b/cogl/driver/gl/gles/cogl-texture-driver-gles.c
> @@ -63,34 +63,32 @@
>  #define GL_UNPACK_SKIP_PIXELS 0x0CF4
>  #endif
>
> -static void
> +static GLuint
>  _cogl_texture_driver_gen (CoglContext *ctx,
>                            GLenum gl_target,
> -                          GLsizei n,
> -                          GLuint *textures)
> +                          CoglPixelFormat internal_format)
>  {
> -  unsigned int i;
> +  GLuint tex;
>
> -  GE (ctx, glGenTextures (n, textures));
> +  GE (ctx, glGenTextures (1, &tex));
>
> -  for (i = 0; i < n; i++)
> -    {
> -      _cogl_bind_gl_texture_transient (gl_target, textures[i], FALSE);
> +  _cogl_bind_gl_texture_transient (gl_target, tex, FALSE);
>
> -      switch (gl_target)
> -        {
> -        case GL_TEXTURE_2D:
> -        case GL_TEXTURE_3D:
> -          /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set
> it */
> -          GE( ctx, glTexParameteri (gl_target,
> -                                    GL_TEXTURE_MIN_FILTER,
> -                                    GL_LINEAR) );
> -          break;
> -
> -        default:
> -          g_assert_not_reached();
> -        }
> +  switch (gl_target)
> +    {
> +    case GL_TEXTURE_2D:
> +    case GL_TEXTURE_3D:
> +      /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
> +      GE( ctx, glTexParameteri (gl_target,
> +                                GL_TEXTURE_MIN_FILTER,
> +                                GL_LINEAR) );
> +      break;
> +
> +    default:
> +      g_assert_not_reached();
>      }
> +
> +  return tex;
>  }
>
>  static void
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/cogl/attachments/20121123/a171d254/attachment-0001.html>


More information about the Cogl mailing list