[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