diff --git a/clutter/cogl/cogl/cogl-texture-2d-private.h b/clutter/cogl/cogl/cogl-texture-2d-private.h index 33c71efe0..705ed3968 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-private.h +++ b/clutter/cogl/cogl/cogl-texture-2d-private.h @@ -51,6 +51,8 @@ struct _CoglTexture2D GLint wrap_mode_t; gboolean auto_mipmap; gboolean mipmaps_dirty; + + CoglTexturePixel first_pixel; }; GQuark diff --git a/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h b/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h index 1560c1ffd..09a70e23d 100644 --- a/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h +++ b/clutter/cogl/cogl/cogl-texture-2d-sliced-private.h @@ -32,19 +32,6 @@ #define COGL_TEXTURE_2D_SLICED(tex) ((CoglTexture2DSliced *)tex) typedef struct _CoglTexture2DSliced CoglTexture2DSliced; -typedef struct _CoglTexturePixel CoglTexturePixel; - -/* This is used to store the first pixel of each slice. This is only - used when glGenerateMipmap is not available */ -struct _CoglTexturePixel -{ - /* We need to store the format of the pixel because we store the - data in the source format which might end up being different for - each slice if a subregion is updated with a different format */ - GLenum gl_format; - GLenum gl_type; - guint8 data[4]; -}; struct _CoglTexture2DSliced { diff --git a/clutter/cogl/cogl/cogl-texture-2d.c b/clutter/cogl/cogl/cogl-texture-2d.c index b5e4ed7ec..c67f5dfe6 100644 --- a/clutter/cogl/cogl/cogl-texture-2d.c +++ b/clutter/cogl/cogl/cogl-texture-2d.c @@ -166,13 +166,6 @@ _cogl_texture_2d_can_create (unsigned int width, GLenum gl_intformat; GLenum gl_type; - /* If the driver doesn't support glGenerateMipmap then we need to - store a copy of the first pixels to cause an update. Instead of - duplicating the code here we'll just make it fallback to - CoglTexture2DSliced */ - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) - return FALSE; - /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && @@ -296,6 +289,13 @@ _cogl_texture_2d_new_from_bitmap (CoglHandle bmp_handle, flags, internal_format); + /* Keep a copy of the first pixel so that if glGenerateMipmap isn't + supported we can fallback to using GL_GENERATE_MIPMAP */ + tex_2d->first_pixel.gl_format = gl_format; + tex_2d->first_pixel.gl_type = gl_type; + memcpy (tex_2d->first_pixel.data, dst_bmp.data, + _cogl_get_format_bpp (dst_bmp.format)); + _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture); _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D, tex_2d->gl_texture, @@ -420,10 +420,25 @@ _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, tex_2d->gl_texture, FALSE); - /* glGenerateMipmap is defined in the FBO extension. We only allow - CoglTexture2D instances to be created if this feature is - available so we don't need to check for the extension */ - _cogl_texture_driver_gl_generate_mipmaps (GL_TEXTURE_2D); + + /* glGenerateMipmap is defined in the FBO extension. If it's not + available we'll fallback to temporarily enabling + GL_GENERATE_MIPMAP and reuploading the first pixel */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + _cogl_texture_driver_gl_generate_mipmaps (GL_TEXTURE_2D); + else + { + GE( glTexParameteri (GL_TEXTURE_2D, + GL_GENERATE_MIPMAP, + GL_TRUE) ); + GE( glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1, + tex_2d->first_pixel.gl_format, + tex_2d->first_pixel.gl_type, + tex_2d->first_pixel.data) ); + GE( glTexParameteri (GL_TEXTURE_2D, + GL_GENERATE_MIPMAP, + GL_FALSE) ); + } tex_2d->mipmaps_dirty = FALSE; } @@ -454,6 +469,17 @@ _cogl_texture_2d_set_region (CoglTexture *tex, &gl_format, &gl_type); + /* If this touches the first pixel then we'll update our copy */ + if (dst_x == 0 && dst_y == 0) + { + CoglPixelFormat bpp = _cogl_get_format_bpp (bmp->format); + tex_2d->first_pixel.gl_format = gl_format; + tex_2d->first_pixel.gl_type = gl_type; + memcpy (tex_2d->first_pixel.data, + bmp->data + bmp->rowstride * src_y + bpp * src_x, + bpp); + } + /* Send data to GL */ _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D, tex_2d->gl_texture, diff --git a/clutter/cogl/cogl/cogl-texture-3d-private.h b/clutter/cogl/cogl/cogl-texture-3d-private.h index b3bbb26b0..bb9e5ba62 100644 --- a/clutter/cogl/cogl/cogl-texture-3d-private.h +++ b/clutter/cogl/cogl/cogl-texture-3d-private.h @@ -54,6 +54,8 @@ struct _CoglTexture3D GLint wrap_mode_p; gboolean auto_mipmap; gboolean mipmaps_dirty; + + CoglTexturePixel first_pixel; }; GQuark diff --git a/clutter/cogl/cogl/cogl-texture-3d.c b/clutter/cogl/cogl/cogl-texture-3d.c index f58e3a51b..170342ffc 100644 --- a/clutter/cogl/cogl/cogl-texture-3d.c +++ b/clutter/cogl/cogl/cogl-texture-3d.c @@ -222,20 +222,6 @@ _cogl_texture_3d_can_create (unsigned int width, return FALSE; } - /* If the driver doesn't support glGenerateMipmap then we need to - store a copy of the first pixels to cause an update. Instead of - duplicating the code here we'll just make it throw an error */ - if ((flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0 && - !cogl_features_available (COGL_FEATURE_OFFSCREEN)) - { - g_set_error (error, - COGL_ERROR, - COGL_ERROR_UNSUPPORTED, - "Auto mipmapping was requested but this is not supported " - "by Cogl with this driver"); - return FALSE; - } - /* If NPOT textures aren't supported then the size must be a power of two */ if (!cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && @@ -359,6 +345,13 @@ _cogl_texture_3d_new_from_bitmap (CoglHandle bmp_handle, tex_3d = _cogl_texture_3d_create_base (dst_bmp.width, height, depth, flags, internal_format); + /* Keep a copy of the first pixel so that if glGenerateMipmap isn't + supported we can fallback to using GL_GENERATE_MIPMAP */ + tex_3d->first_pixel.gl_format = gl_format; + tex_3d->first_pixel.gl_type = gl_type; + memcpy (tex_3d->first_pixel.data, dst_bmp.data, + _cogl_get_format_bpp (dst_bmp.format)); + _cogl_texture_driver_gen (GL_TEXTURE_3D, 1, &tex_3d->gl_texture); _cogl_texture_driver_upload_to_gl_3d (GL_TEXTURE_3D, @@ -565,10 +558,31 @@ _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags) _cogl_bind_gl_texture_transient (GL_TEXTURE_3D, tex_3d->gl_texture, FALSE); - /* glGenerateMipmap is defined in the FBO extension. We only allow - CoglTexture3D instances to be created if this feature is - available so we don't need to check for the extension */ - _cogl_texture_driver_gl_generate_mipmaps (GL_TEXTURE_3D); + /* glGenerateMipmap is defined in the FBO extension. If it's not + available we'll fallback to temporarily enabling + GL_GENERATE_MIPMAP and reuploading the first pixel */ + if (cogl_features_available (COGL_FEATURE_OFFSCREEN)) + _cogl_texture_driver_gl_generate_mipmaps (GL_TEXTURE_3D); + else + { + GE( glTexParameteri (GL_TEXTURE_3D, + GL_GENERATE_MIPMAP, + GL_TRUE) ); + GE( glTexSubImage3D (GL_TEXTURE_3D, + 0, /* level */ + 0, /* xoffset */ + 0, /* yoffset */ + 0, /* zoffset */ + 1, /* width */ + 1, /* height */ + 1, /* depth */ + tex_3d->first_pixel.gl_format, + tex_3d->first_pixel.gl_type, + tex_3d->first_pixel.data) ); + GE( glTexParameteri (GL_TEXTURE_3D, + GL_GENERATE_MIPMAP, + GL_FALSE) ); + } tex_3d->mipmaps_dirty = FALSE; } diff --git a/clutter/cogl/cogl/cogl-texture-private.h b/clutter/cogl/cogl/cogl-texture-private.h index 592ea06f0..454cb8485 100644 --- a/clutter/cogl/cogl/cogl-texture-private.h +++ b/clutter/cogl/cogl/cogl-texture-private.h @@ -151,6 +151,22 @@ typedef enum _CoglTextureChangeFlags } CoglTextureChangeFlags; +typedef struct _CoglTexturePixel CoglTexturePixel; + +/* This is used by the texture backends to store the first pixel of + each GL texture. This is only used when glGenerateMipmap is not + available so that we can temporarily set GL_GENERATE_MIPMAP and + reupload a pixel */ +struct _CoglTexturePixel +{ + /* We need to store the format of the pixel because we store the + data in the source format which might end up being different for + each slice if a subregion is updated with a different format */ + GLenum gl_format; + GLenum gl_type; + guint8 data[4]; +}; + void _cogl_texture_free (CoglTexture *texture);