diff options
Diffstat (limited to 'src/mesa/main/teximage.c')
-rw-r--r-- | src/mesa/main/teximage.c | 784 |
1 files changed, 500 insertions, 284 deletions
diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 769f74eda74..6ec00c07402 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1,4 +1,4 @@ -/* $Id: teximage.c,v 1.116 2002/09/23 16:37:14 brianp Exp $ */ +/* $Id: teximage.c,v 1.117 2002/09/27 02:45:38 brianp Exp $ */ /* * Mesa 3-D graphics library @@ -36,6 +36,7 @@ #include "mem.h" #include "mmath.h" #include "state.h" +#include "texcompress.h" #include "texformat.h" #include "teximage.h" #include "texstate.h" @@ -142,6 +143,10 @@ logbase2( int n ) * Given an internal texture format enum or 1, 2, 3, 4 return the * corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE, * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. + * + * This is the format which is used during texture application (i.e. the + * texture format and env mode determine the arithmetic used. + * * Return -1 if invalid enum. */ GLint @@ -151,12 +156,6 @@ _mesa_base_tex_format( GLcontext *ctx, GLint format ) * Ask the driver for the base format, if it doesn't * know, it will return -1; */ - if (ctx->Driver.BaseCompressedTexFormat) { - GLint ifmt = (*ctx->Driver.BaseCompressedTexFormat)(ctx, format); - if (ifmt >= 0) { - return ifmt; - } - } switch (format) { case GL_ALPHA: case GL_ALPHA4: @@ -222,11 +221,55 @@ _mesa_base_tex_format( GLcontext *ctx, GLint format ) return GL_DEPTH_COMPONENT; else return -1; + + /* GL_ARB_texture_compression */ + case GL_COMPRESSED_ALPHA: + if (ctx->Extensions.ARB_texture_compression) + return GL_ALPHA; + else + return -1; + case GL_COMPRESSED_LUMINANCE: + if (ctx->Extensions.ARB_texture_compression) + return GL_LUMINANCE; + else + return -1; + case GL_COMPRESSED_LUMINANCE_ALPHA: + if (ctx->Extensions.ARB_texture_compression) + return GL_LUMINANCE_ALPHA; + else + return -1; + case GL_COMPRESSED_INTENSITY: + if (ctx->Extensions.ARB_texture_compression) + return GL_INTENSITY; + else + return -1; + case GL_COMPRESSED_RGB: + if (ctx->Extensions.ARB_texture_compression) + return GL_RGB; + else + return -1; + case GL_COMPRESSED_RGBA: + if (ctx->Extensions.ARB_texture_compression) + return GL_RGBA; + else + return -1; + case GL_COMPRESSED_RGB_FXT1_3DFX: + if (ctx->Extensions.TDFX_texture_compression_FXT1) + return GL_RGB; + else + return -1; + case GL_COMPRESSED_RGBA_FXT1_3DFX: + if (ctx->Extensions.TDFX_texture_compression_FXT1) + return GL_RGBA; + else + return -1; + case GL_YCBCR_MESA: if (ctx->Extensions.MESA_ycbcr_texture) return GL_YCBCR_MESA; else return -1; + default: return -1; /* error */ } @@ -309,25 +352,24 @@ is_index_format(GLenum format) } -/* - * Return GL_TRUE if internalFormat is a compressed format, return GL_FALSE - * otherwise. +/** + * Return GL_TRUE if internalFormat is a supported compressed format, + * return GL_FALSE otherwise. + * \param - internalFormat - the internal format token provided by the user */ static GLboolean -is_compressed_format(GLcontext *ctx, GLenum internalFormat) +is_compressed_format(GLenum internalFormat) { - if (ctx->Driver.BaseCompressedTexFormat) { - GLint b = (*ctx->Driver.BaseCompressedTexFormat)(ctx, internalFormat); - if (b > 0) + switch (internalFormat) { + case GL_COMPRESSED_RGB_FXT1_3DFX: + case GL_COMPRESSED_RGBA_FXT1_3DFX: return GL_TRUE; - else + default: return GL_FALSE; } - return GL_FALSE; } - /* * Store a gl_texture_image pointer in a gl_texture_object structure * according to the target and level parameters. @@ -657,7 +699,13 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target, img->Height2 = 1 << img->HeightLog2; img->Depth2 = 1 << img->DepthLog2; img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); - img->IsCompressed = is_compressed_format(ctx, internalFormat); + img->IsCompressed = is_compressed_format(internalFormat); + if (img->IsCompressed) + img->CompressedSize = _mesa_compressed_texture_size(ctx, width, height, + depth, internalFormat); + else + img->CompressedSize = 0; + /* Compute Width/Height/DepthScale for mipmap lod computation */ if (target == GL_TEXTURE_RECTANGLE_NV) { /* scale = 1.0 since texture coords directly map to texels */ @@ -689,7 +737,6 @@ texture_error_check( GLcontext *ctx, GLenum target, GLint depth, GLint border ) { GLboolean isProxy; - GLint iformat; GLint maxLevels = 0, maxTextureSize; if (dimensions == 1) { @@ -879,8 +926,7 @@ texture_error_check( GLcontext *ctx, GLenum target, } } - iformat = _mesa_base_tex_format( ctx, internalFormat ); - if (iformat < 0) { + if (_mesa_base_tex_format(ctx, internalFormat) < 0) { if (!isProxy) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexImage%dD(internalFormat=0x%x)", @@ -889,24 +935,21 @@ texture_error_check( GLcontext *ctx, GLenum target, return GL_TRUE; } - ASSERT(iformat > 0); - - if (!is_compressed_format( ctx, internalFormat ) && - !_mesa_is_legal_format_and_type( format, type )) { + if (!_mesa_is_legal_format_and_type(format, type)) { /* Yes, generate GL_INVALID_OPERATION, not GL_INVALID_ENUM, if there * is a type/format mismatch. See 1.2 spec page 94, sec 3.6.4. */ if (!isProxy) { - _mesa_error(ctx, GL_INVALID_OPERATION, + _mesa_error(ctx, GL_INVALID_OPERATION, "glTexImage%dD(format or type)", dimensions); } return GL_TRUE; } - if (format == GL_YCBCR_MESA || iformat == GL_YCBCR_MESA) { + if (format == GL_YCBCR_MESA || internalFormat == GL_YCBCR_MESA) { ASSERT(ctx->Extensions.MESA_ycbcr_texture); if (format != GL_YCBCR_MESA || - iformat != GL_YCBCR_MESA || + internalFormat != GL_YCBCR_MESA || (type != GL_UNSIGNED_SHORT_8_8_MESA && type != GL_UNSIGNED_SHORT_8_8_REV_MESA)) { char message[100]; @@ -918,6 +961,32 @@ texture_error_check( GLcontext *ctx, GLenum target, } } + if (is_compressed_format(internalFormat)) { + if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) { + /* OK */ + } + else if (ctx->Extensions.ARB_texture_cube_map && + (target == GL_PROXY_TEXTURE_CUBE_MAP || + (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { + /* OK */ + } + else { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage%d(target)", dimensions); + return GL_TRUE; + } + } + if (border != 0) { + if (!isProxy) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage%D(border!=0)", dimensions); + } + return GL_TRUE; + } + } + /* if we get here, the parameters are OK */ return GL_FALSE; } @@ -940,7 +1009,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; struct gl_texture_image *destTex; GLint maxLevels = 0; - GLboolean compressed; if (dimensions == 1) { if (target != GL_TEXTURE_1D) { @@ -1037,30 +1105,51 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } } - compressed = is_compressed_format(ctx, destTex->IntFormat); - - if (!compressed && !_mesa_is_legal_format_and_type(format, type)) { + if (!_mesa_is_legal_format_and_type(format, type)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%dD(format or type)", dimensions); return GL_TRUE; } - if (compressed) { - if (xoffset != -((GLint)destTex->Border)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage1/2/3D(xoffset != -border"); + if (destTex->IsCompressed) { + const struct gl_texture_unit *texUnit; + const struct gl_texture_object *texObj; + const struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(ctx, texUnit, target); + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + + if (target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D) { + /* OK */ + } + else if (ctx->Extensions.ARB_texture_cube_map && + (target == GL_PROXY_TEXTURE_CUBE_MAP || + (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { + /* OK */ + } + else { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexSubImage%D(target)", dimensions); return GL_TRUE; } - if (dimensions > 1 && yoffset != -((GLint)destTex->Border)) { + /* offset must be multiple of 4 */ + if ((xoffset & 3) || (yoffset & 3)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage2/3D(yoffset != -border"); + "glTexSubImage%D(xoffset or yoffset)", dimensions); return GL_TRUE; } - if (dimensions > 2 && zoffset != -((GLint)destTex->Border)) { + /* size must be multiple of 4 or equal to whole texture size */ + if ((width & 3) && width != texImage->Width) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexSubImage3D(zoffset != -border"); + "glTexSubImage%D(width)", dimensions); return GL_TRUE; - } + } + if ((height & 3) && height != texImage->Height) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%D(width)", dimensions); + return GL_TRUE; + } } return GL_FALSE; @@ -1077,7 +1166,6 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, GLenum target, GLint level, GLint internalFormat, GLint width, GLint height, GLint border ) { - GLint iformat; GLint maxLevels = 0, maxTextureSize; if (dimensions == 1) { @@ -1157,13 +1245,25 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - iformat = _mesa_base_tex_format(ctx, internalFormat); - if (iformat < 0) { + if (_mesa_base_tex_format(ctx, internalFormat) < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyTexImage%dD(internalFormat)", dimensions); return GL_TRUE; } + if (is_compressed_format(internalFormat)) { + if (target != GL_TEXTURE_2D) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyTexImage%d(target)", dimensions); + return GL_TRUE; + } + if (border != 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%D(border!=0)", dimensions); + return GL_TRUE; + } + } + /* if we get here, the parameters are OK */ return GL_FALSE; } @@ -1178,7 +1278,6 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; struct gl_texture_image *teximage; GLint maxLevels = 0; - GLboolean compressed; if (dimensions == 1) { if (target != GL_TEXTURE_1D) { @@ -1277,23 +1376,29 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, } } - compressed = is_compressed_format(ctx, teximage->IntFormat); - if (compressed) { - if (xoffset != -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage1/2/3D(xoffset != -border"); + if (teximage->IsCompressed) { + if (target != GL_TEXTURE_2D) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCopyTexSubImage%d(target)", dimensions); return GL_TRUE; } - if (dimensions > 1 && yoffset != -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage2/3D(yoffset != -border"); + /* offset must be multiple of 4 */ + if ((xoffset & 3) || (yoffset & 3)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%D(xoffset or yoffset)", dimensions); return GL_TRUE; } - if (dimensions > 2 && zoffset != -((GLint)teximage->Border)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexSubImage3D(zoffset != -border"); + /* size must be multiple of 4 */ + if ((width & 3) != 0 && width != teximage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%D(width)", dimensions); return GL_TRUE; - } + } + if ((height & 3) != 0 && height != teximage->Height) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexSubImage%D(height)", dimensions); + return GL_TRUE; + } } /* if we get here, the parameters are OK */ @@ -1503,28 +1608,10 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, ASSERT(ctx->Driver.TexImage1D); -#if 0 /* don't make default teximage anymore */ - if (pixels) { - (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, - width, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); - } - else { - GLubyte *dummy = make_null_texture(width, 1, 1, format); - if (dummy) { - (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, - width, border, - format, GL_UNSIGNED_BYTE, dummy, - &_mesa_native_packing, texObj, texImage); - FREE(dummy); - } - } -#else - /* <pixels> may be null! */ + /* Give the texture to the driver! <pixels> may be null! */ (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, width, border, format, type, pixels, &ctx->Unpack, texObj, texImage); -#endif ASSERT(texImage->TexFormat); if (!texImage->FetchTexel) { @@ -1533,27 +1620,15 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, } ASSERT(texImage->FetchTexel); - if (texImage->IsCompressed) { - ASSERT(texImage->CompressedSize > 0); - } - /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, - format, type, 1, - postConvWidth, 1, 1, border); + GLboolean error = texture_error_check(ctx, target, level, internalFormat, + format, type, 1, postConvWidth, 1, 1, border); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, 1, 1, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, format, type, @@ -1565,6 +1640,16 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, clear_teximage_fields(ctx->Texture.Proxy1D->Image[level]); } } + else { + /* no error, set the tex image parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, 1, 1, + border, internalFormat); + } } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" ); @@ -1632,28 +1717,10 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, ASSERT(ctx->Driver.TexImage2D); -#if 0 /* don't make default teximage anymore */ - if (pixels) { - (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, - width, height, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); - } - else { - GLubyte *dummy = make_null_texture(width, height, 1, format); - if (dummy) { - (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, - width, height, border, - format, GL_UNSIGNED_BYTE, dummy, - &_mesa_native_packing, texObj, texImage); - FREE(dummy); - } - } -#else - /* <pixels> may be null! */ + /* Give the texture to the driver! <pixels> may be null! */ (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, width, height, border, format, type, pixels, &ctx->Unpack, texObj, texImage); -#endif ASSERT(texImage->TexFormat); if (!texImage->FetchTexel) { @@ -1662,10 +1729,6 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, } ASSERT(texImage->FetchTexel); - if (texImage->IsCompressed) { - ASSERT(texImage->CompressedSize > 0); - } - /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; @@ -1676,17 +1739,9 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, (target == GL_PROXY_TEXTURE_RECTANGLE_NV && ctx->Extensions.NV_texture_rectangle)) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, - format, type, 2, - postConvWidth, postConvHeight, 1, border); + GLboolean error = texture_error_check(ctx, target, level, internalFormat, + format, type, 2, postConvWidth, postConvHeight, 1, border); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, postConvHeight, 1, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, format, type, @@ -1700,6 +1755,16 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, clear_teximage_fields(ctx->Texture.Proxy2D->Image[level]); } } + else { + /* no error, set the tex image parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, postConvHeight, 1, + border, internalFormat); + } } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" ); @@ -1757,30 +1822,10 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, ASSERT(ctx->Driver.TexImage3D); -#if 0 /* don't make default teximage anymore */ - if (pixels) { - (*ctx->Driver.TexImage3D)(ctx, target, level, (GLint) internalFormat, - width, height, depth, border, - format, type, pixels, - &ctx->Unpack, texObj, texImage); - } - else { - GLubyte *dummy = make_null_texture(width, height, depth, format); - if (dummy) { - (*ctx->Driver.TexImage3D)(ctx, target, level, - (GLint) internalFormat, - width, height, depth, border, - format, GL_UNSIGNED_BYTE, dummy, - &_mesa_native_packing, texObj, texImage); - FREE(dummy); - } - } -#else - /* <pixels> may be null! */ + /* Give the texture to the driver! <pixels> may be null! */ (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat, width, height, depth, border, format, type, pixels, &ctx->Unpack, texObj, texImage); -#endif ASSERT(texImage->TexFormat); if (!texImage->FetchTexel) { @@ -1789,25 +1834,15 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, } ASSERT(texImage->FetchTexel); - if (texImage->IsCompressed) { - ASSERT(texImage->CompressedSize > 0); - } - /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, + GLboolean error = texture_error_check(ctx, target, level, internalFormat, format, type, 3, width, height, depth, border); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, format, type, @@ -1819,6 +1854,15 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, clear_teximage_fields(ctx->Texture.Proxy3D->Image[level]); } } + else { + /* no error, set the tex image parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); + } } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" ); @@ -1833,7 +1877,7 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) { - _mesa_TexImage3D(target, level, internalFormat, width, height, + _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height, depth, border, format, type, pixels); } @@ -2219,6 +2263,176 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, + +/**********************************************************************/ +/****** Compressed Textures ******/ +/**********************************************************************/ + + +/** + * Error checking for glCompressedTexImage[123]D(). + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_texture_error_check(GLcontext *ctx, GLint dimensions, + GLenum target, GLint level, + GLenum internalFormat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, + GLsizei imageSize) +{ + GLboolean isProxy = GL_FALSE; + GLint expectedSize, maxLevels = 0, maxTextureSize; + + if (dimensions == 1) { + /* 1D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + else if (dimensions == 2) { + if (target == GL_PROXY_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + isProxy = GL_TRUE; + } + else if (target == GL_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + isProxy = GL_TRUE; + } + else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else { + return GL_INVALID_ENUM; /*target*/ + } + } + else if (dimensions == 3) { + /* 3D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + + maxTextureSize = 1 << (maxLevels - 1); + + if (!is_compressed_format(internalFormat)) + return GL_INVALID_ENUM; + + if (border != 0) + return GL_INVALID_VALUE; + + if (width < 1 || width > maxTextureSize || logbase2(width) < 0) + return GL_INVALID_VALUE; + + if ((height < 1 || height > maxTextureSize || logbase2(height) < 0) + && dimensions > 1) + return GL_INVALID_VALUE; + + if ((depth < 1 || depth > maxTextureSize || logbase2(depth) < 0) + && dimensions > 2) + return GL_INVALID_VALUE; + + /* For cube map, width must equal height */ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height) + return GL_INVALID_VALUE; + + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + expectedSize = _mesa_compressed_texture_size(ctx, width, height, depth, + internalFormat); + if (expectedSize != imageSize) + return GL_INVALID_VALUE; + + return GL_NO_ERROR; +} + + +/** + * Error checking for glCompressedTexSubImage[123]D(). + * \return error code or GL_NO_ERROR. + */ +static GLenum +compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize) +{ + GLboolean isProxy = GL_FALSE; + GLint expectedSize, maxLevels = 0, maxTextureSize; + + if (dimensions == 1) { + /* 1D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + else if (dimensions == 2) { + if (target == GL_PROXY_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + isProxy = GL_TRUE; + } + else if (target == GL_TEXTURE_2D) { + maxLevels = ctx->Const.MaxTextureLevels; + } + else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + isProxy = GL_TRUE; + } + else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { + if (!ctx->Extensions.ARB_texture_cube_map) + return GL_INVALID_ENUM; /*target*/ + maxLevels = ctx->Const.MaxCubeTextureLevels; + } + else { + return GL_INVALID_ENUM; /*target*/ + } + } + else if (dimensions == 3) { + /* 3D compressed textures not allowed */ + return GL_INVALID_ENUM; + } + + maxTextureSize = 1 << (maxLevels - 1); + + if (!is_compressed_format(format)) + return GL_INVALID_ENUM; + + if (width < 1 || width > maxTextureSize || logbase2(width) < 0) + return GL_INVALID_VALUE; + + if ((height < 1 || height > maxTextureSize || logbase2(height) < 0) + && dimensions > 1) + return GL_INVALID_VALUE; + + if (level < 0 || level >= maxLevels) + return GL_INVALID_VALUE; + + if ((xoffset & 3) != 0 || (yoffset & 3) != 0) + return GL_INVALID_VALUE; + + if ((width & 3) != 0 && width != 2 && width != 1) + return GL_INVALID_VALUE; + + if ((height & 3) != 0 && height != 2 && height != 1) + return GL_INVALID_VALUE; + + expectedSize = _mesa_compressed_texture_size(ctx, width, height, depth, + format); + if (expectedSize != imageSize) + return GL_INVALID_VALUE; + + return GL_NO_ERROR; +} + + + void _mesa_CompressedTexImage1DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, @@ -2228,28 +2442,15 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - switch (internalFormat) { - case GL_COMPRESSED_ALPHA_ARB: - case GL_COMPRESSED_LUMINANCE_ARB: - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: - case GL_COMPRESSED_INTENSITY_ARB: - case GL_COMPRESSED_RGB_ARB: - case GL_COMPRESSED_RGBA_ARB: - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage1DARB"); - return; - default: - /* silence compiler warning */ - ; - } - if (target == GL_TEXTURE_1D) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 1, width, 1, 1, border)) { - return; /* error in texture image was detected */ + GLenum error = compressed_texture_error_check(ctx, 1, target, level, + internalFormat, width, 1, 1, border, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexImage1D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2260,7 +2461,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, texImage = _mesa_alloc_texture_image(); texObj->Image[level] = texImage; if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1DARB"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D"); return; } } @@ -2272,14 +2473,11 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, border, internalFormat); - if (ctx->Extensions.ARB_texture_compression) { - ASSERT(ctx->Driver.CompressedTexImage1D); - (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, - internalFormat, width, border, - imageSize, data, - texObj, texImage); - ASSERT(texImage->CompressedSize > 0); /* sanity */ - } + ASSERT(ctx->Driver.CompressedTexImage1D); + (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, + internalFormat, width, border, + imageSize, data, + texObj, texImage); /* state update */ texObj->Complete = GL_FALSE; @@ -2287,15 +2485,9 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 1, width, 1, 1, border); + GLenum error = compressed_texture_error_check(ctx, 1, target, level, + internalFormat, width, 1, 1, border, imageSize); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, GL_NONE, GL_NONE, @@ -2307,9 +2499,18 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, clear_teximage_fields(ctx->Texture.Proxy1D->Image[level]); } } + else { + /* store the teximage parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); + } } else { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage1DARB(target)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage1D(target)"); return; } } @@ -2324,33 +2525,18 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - switch (internalFormat) { - case GL_COMPRESSED_ALPHA_ARB: - case GL_COMPRESSED_LUMINANCE_ARB: - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: - case GL_COMPRESSED_INTENSITY_ARB: - case GL_COMPRESSED_RGB_ARB: - case GL_COMPRESSED_RGBA_ARB: - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2DARB"); - return; - default: - /* silence compiler warning */ - ; - } - if (target == GL_TEXTURE_2D || (ctx->Extensions.ARB_texture_cube_map && target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) || - (ctx->Extensions.NV_texture_rectangle && - target == GL_TEXTURE_RECTANGLE_NV)) { + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 2, width, height, 1, border)) { - return; /* error in texture image was detected */ + GLenum error = compressed_texture_error_check(ctx, 2, target, level, + internalFormat, width, height, 1, border, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexImage2D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2361,7 +2547,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, texImage = _mesa_alloc_texture_image(); texObj->Image[level] = texImage; if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2DARB"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); return; } } @@ -2373,30 +2559,23 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, border, internalFormat); - if (ctx->Extensions.ARB_texture_compression) { - ASSERT(ctx->Driver.CompressedTexImage2D); - (*ctx->Driver.CompressedTexImage2D)(ctx, target, level, - internalFormat, width, height, - border, imageSize, data, - texObj, texImage); - ASSERT(texImage->CompressedSize > 0); /* sanity */ - } + ASSERT(ctx->Driver.CompressedTexImage2D); + (*ctx->Driver.CompressedTexImage2D)(ctx, target, level, + internalFormat, width, height, + border, imageSize, data, + texObj, texImage); /* state update */ texObj->Complete = GL_FALSE; ctx->NewState |= _NEW_TEXTURE; } - else if (target == GL_PROXY_TEXTURE_2D) { + else if (target == GL_PROXY_TEXTURE_2D || + (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB && + ctx->Extensions.ARB_texture_cube_map)) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 2, width, height, 1, border); + GLenum error = compressed_texture_error_check(ctx, 2, target, level, + internalFormat, width, height, 1, border, imageSize); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, GL_NONE, GL_NONE, @@ -2410,9 +2589,18 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, clear_teximage_fields(ctx->Texture.Proxy2D->Image[level]); } } + else { + /* store the teximage parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); + } } else { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2DARB(target)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2D(target)"); return; } } @@ -2427,28 +2615,15 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - switch (internalFormat) { - case GL_COMPRESSED_ALPHA_ARB: - case GL_COMPRESSED_LUMINANCE_ARB: - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: - case GL_COMPRESSED_INTENSITY_ARB: - case GL_COMPRESSED_RGB_ARB: - case GL_COMPRESSED_RGBA_ARB: - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage3DARB"); - return; - default: - /* silence compiler warning */ - ; - } - if (target == GL_TEXTURE_3D) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 3, width, height, depth, border)) { - return; /* error in texture image was detected */ + GLenum error = compressed_texture_error_check(ctx, 3, target, level, + internalFormat, width, height, depth, border, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexImage3D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2459,7 +2634,7 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, texImage = _mesa_alloc_texture_image(); texObj->Image[level] = texImage; if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3DARB"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D"); return; } } @@ -2471,15 +2646,12 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, border, internalFormat); - if (ctx->Extensions.ARB_texture_compression) { - ASSERT(ctx->Driver.CompressedTexImage3D); - (*ctx->Driver.CompressedTexImage3D)(ctx, target, level, - internalFormat, - width, height, depth, - border, imageSize, data, - texObj, texImage); - ASSERT(texImage->CompressedSize > 0); /* sanity */ - } + ASSERT(ctx->Driver.CompressedTexImage3D); + (*ctx->Driver.CompressedTexImage3D)(ctx, target, level, + internalFormat, + width, height, depth, + border, imageSize, data, + texObj, texImage); /* state update */ texObj->Complete = GL_FALSE; @@ -2487,16 +2659,9 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ - GLenum error = texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 3, width, height, depth, border); + GLenum error = compressed_texture_error_check(ctx, 3, target, level, + internalFormat, width, height, depth, border, imageSize); if (!error) { - struct gl_texture_unit *texUnit; - struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - _mesa_init_teximage_fields(ctx, target, texImage, - width, height, depth, - border, internalFormat); ASSERT(ctx->Driver.TestProxyTexImage); error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, internalFormat, GL_NONE, GL_NONE, @@ -2508,9 +2673,18 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, clear_teximage_fields(ctx->Texture.Proxy3D->Image[level]); } } + else { + /* store the teximage parameters */ + struct gl_texture_unit *texUnit; + struct gl_texture_image *texImage; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat); + } } else { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage3DARB(target)"); + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage3D(target)"); return; } } @@ -2524,12 +2698,15 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + GLenum error; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0, - width, 1, 1, format, GL_NONE)) { - return; /* error was detected */ + error = compressed_subtexture_error_check(ctx, 1, target, level, + xoffset, 0, 0, width, 1, 1, format, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexSubImage1D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2537,6 +2714,17 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, texImage = _mesa_select_tex_image(ctx, texUnit, target, level); assert(texImage); + if (format != texImage->IntFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage1D(format)"); + return; + } + + if ((width == 1 || width == 2) && width != texImage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)"); + return; + } + if (width == 0 || !data) return; /* no-op, not an error */ @@ -2559,12 +2747,15 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + GLenum error; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0, - width, height, 1, format, GL_NONE)) { - return; /* error was detected */ + error = compressed_subtexture_error_check(ctx, 2, target, level, + xoffset, yoffset, 0, width, height, 1, format, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexSubImage2D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2572,6 +2763,18 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, texImage = _mesa_select_tex_image(ctx, texUnit, target, level); assert(texImage); + if (format != texImage->IntFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage2D(format)"); + return; + } + + if (((width == 1 || width == 2) && width != texImage->Width) || + ((height == 1 || height == 2) && height != texImage->Height)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)"); + return; + } + if (width == 0 || height == 0 || !data) return; /* no-op, not an error */ @@ -2594,12 +2797,15 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + GLenum error; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (subtexture_error_check(ctx, 3, target, level, xoffset, yoffset, zoffset, - width, height, depth, format, GL_NONE)) { - return; /* error was detected */ + error = compressed_subtexture_error_check(ctx, 3, target, level, + xoffset, yoffset, zoffset, width, height, depth, format, imageSize); + if (error) { + _mesa_error(ctx, error, "glCompressedTexSubImage2D"); + return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; @@ -2607,6 +2813,19 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, texImage = _mesa_select_tex_image(ctx, texUnit, target, level); assert(texImage); + if (format != texImage->IntFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage3D(format)"); + return; + } + + if (((width == 1 || width == 2) && width != texImage->Width) || + ((height == 1 || height == 2) && height != texImage->Height) || + ((depth == 1 || depth == 2) && depth != texImage->Depth)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)"); + return; + } + if (width == 0 || height == 0 || depth == 0 || !data) return; /* no-op, not an error */ @@ -2675,9 +2894,6 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) if (!img) return; - if (ctx->Extensions.ARB_texture_compression) { - ASSERT(ctx->Driver.GetCompressedTexImage); - (*ctx->Driver.GetCompressedTexImage)(ctx, target, level, img, texObj, - texImage); - } + /* just memcpy, no pixelstore or pixel transfer */ + MEMCPY(img, texImage->Data, texImage->CompressedSize); } |