X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fteximage.c;h=384e1455203c3185d79a7c3ec0c869ca9bbcdcc5;hb=ff938bf059a41a9bdf4c2c93cebe4a3b8a89c201;hp=b5d2d266b002d8c691b24ea6351723af6ad6f07b;hpb=4cf6718725c7cf3bfb728118a8b14f8cf206c701;p=mesa.git diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index b5d2d266b00..384e1455203 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1,8 +1,8 @@ /* * Mesa 3-D graphics library - * Version: 6.3 + * Version: 7.1 * - * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -25,13 +25,7 @@ /** * \file teximage.c - * Texture images manipulation functions. - * - * \note Mesa's native texture data type is GLchan. Native formats are - * GL_ALPHA, GL_LUMINANCE, GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, GL_RGBA, and - * GL_COLOR_INDEX. - * - * \note Device drivers are free to implement any internal format they want. + * Texture image-related functions. */ @@ -39,6 +33,8 @@ #include "bufferobj.h" #include "context.h" #include "convolve.h" +#include "fbobject.h" +#include "framebuffer.h" #include "image.h" #include "imports.h" #include "macros.h" @@ -77,11 +73,11 @@ _mesa_free_texmemory(void *m) #if 0 static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img) { -#if CHAN_TYPE == GL_FLOAT - _mesa_problem(NULL, "PrintTexture doesn't support float channels"); +#if CHAN_TYPE != GL_UNSIGNED_BYTE + _mesa_problem(NULL, "PrintTexture not supported"); #else GLuint i, j, c; - const GLchan *data = (const GLchan *) img->Data; + const GLubyte *data = (const GLubyte *) img->Data; if (!data) { _mesa_printf("No texture data\n"); @@ -121,6 +117,7 @@ static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img) _mesa_printf("%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]); data += (img->RowStride - img->Width) * c; } + /* XXX use img->ImageStride here */ _mesa_printf("\n"); } #endif @@ -242,7 +239,8 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat ) } } - if (ctx->Extensions.SGIX_depth_texture) { + if (ctx->Extensions.SGIX_depth_texture || + ctx->Extensions.ARB_depth_texture) { switch (internalFormat) { case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16_SGIX: @@ -340,6 +338,46 @@ _mesa_base_tex_format( GLcontext *ctx, GLint internalFormat ) } } + if (ctx->Extensions.EXT_packed_depth_stencil) { + switch (internalFormat) { + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_DEPTH_STENCIL_EXT; + default: + ; /* fallthrough */ + } + } + +#if FEATURE_EXT_texture_sRGB + if (ctx->Extensions.EXT_texture_sRGB) { + switch (internalFormat) { + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + case GL_COMPRESSED_SRGB_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + case GL_COMPRESSED_SRGB_ALPHA_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return GL_RGBA; + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + case GL_COMPRESSED_SLUMINANCE_EXT: + case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: + return GL_LUMINANCE_ALPHA; + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + return GL_LUMINANCE; + default: + ; /* fallthrough */ + } + } + +#endif /* FEATURE_EXT_texture_sRGB */ + return -1; /* error */ } @@ -432,6 +470,24 @@ is_color_format(GLenum format) case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: case GL_COMPRESSED_RGB_FXT1_3DFX: case GL_COMPRESSED_RGBA_FXT1_3DFX: +#if FEATURE_EXT_texture_sRGB + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + case GL_COMPRESSED_SRGB_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SLUMINANCE_EXT: + case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: +#endif /* FEATURE_EXT_texture_sRGB */ return GL_TRUE; case GL_YCBCR_MESA: /* not considered to be RGB */ default: @@ -494,6 +550,23 @@ is_ycbcr_format(GLenum format) } +/** + * Test if the given image format is a Depth/Stencil format. + */ +static GLboolean +is_depthstencil_format(GLenum format) +{ + switch (format) { + case GL_DEPTH24_STENCIL8_EXT: + case GL_DEPTH_STENCIL_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + + /** * Test if it is a supported compressed format. * @@ -508,25 +581,36 @@ is_ycbcr_format(GLenum format) static GLboolean is_compressed_format(GLcontext *ctx, GLenum internalFormat) { - (void) ctx; - switch (internalFormat) { - case GL_COMPRESSED_RGB_FXT1_3DFX: - case GL_COMPRESSED_RGBA_FXT1_3DFX: - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - case GL_RGB_S3TC: - case GL_RGB4_S3TC: - case GL_RGBA_S3TC: - case GL_RGBA4_S3TC: + GLint supported[100]; /* 100 should be plenty */ + GLuint i, n; + + n = _mesa_get_compressed_formats(ctx, supported, GL_TRUE); + ASSERT(n < 100); + for (i = 0; i < n; i++) { + if ((GLint) internalFormat == supported[i]) { return GL_TRUE; - default: - return GL_FALSE; + } } + return GL_FALSE; +} + + +/** + * For cube map faces, return a face index in [0,5]. + * For other targets return 0; + */ +GLuint +_mesa_tex_target_to_face(GLenum target) +{ + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) + return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + else + return 0; } + /** * Store a gl_texture_image pointer in a gl_texture_object structure * according to the target and level parameters. @@ -545,10 +629,13 @@ _mesa_set_tex_image(struct gl_texture_object *tObj, { ASSERT(tObj); ASSERT(texImage); + /* XXX simplify this with _mesa_tex_target_to_face() */ switch (target) { case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: tObj->Image[0][level] = texImage; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: @@ -605,6 +692,8 @@ void _mesa_free_texture_image_data(GLcontext *ctx, struct gl_texture_image *texImage) { + (void) ctx; + if (texImage->Data && !texImage->IsClientData) { /* free the old texture data */ _mesa_free_texmemory(texImage->Data); @@ -624,11 +713,16 @@ _mesa_free_texture_image_data(GLcontext *ctx, void _mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage ) { - if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } + /* Free texImage->Data and/or any other driver-specific texture + * image storage. + */ + ASSERT(ctx->Driver.FreeTexImageData); + ctx->Driver.FreeTexImageData( ctx, texImage ); + ASSERT(texImage->Data == NULL); - FREE( texImage ); + if (texImage->ImageOffsets) + _mesa_free(texImage->ImageOffsets); + _mesa_free(texImage); } @@ -639,14 +733,16 @@ _mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage ) * * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise. */ -static GLboolean -is_proxy_target(GLenum target) +GLboolean +_mesa_is_proxy_texture(GLenum target) { return (target == GL_PROXY_TEXTURE_1D || target == GL_PROXY_TEXTURE_2D || target == GL_PROXY_TEXTURE_3D || target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - target == GL_PROXY_TEXTURE_RECTANGLE_NV); + target == GL_PROXY_TEXTURE_RECTANGLE_NV || + target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || + target == GL_PROXY_TEXTURE_2D_ARRAY_EXT); } @@ -696,6 +792,18 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit, case GL_PROXY_TEXTURE_RECTANGLE_NV: return ctx->Extensions.NV_texture_rectangle ? ctx->Texture.ProxyRect : NULL; + case GL_TEXTURE_1D_ARRAY_EXT: + return ctx->Extensions.MESA_texture_array + ? texUnit->Current1DArray : NULL; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + return ctx->Extensions.MESA_texture_array + ? ctx->Texture.Proxy1DArray : NULL; + case GL_TEXTURE_2D_ARRAY_EXT: + return ctx->Extensions.MESA_texture_array + ? texUnit->Current2DArray : NULL; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return ctx->Extensions.MESA_texture_array + ? ctx->Texture.Proxy2DArray : NULL; default: _mesa_problem(NULL, "bad target in _mesa_select_tex_object()"); return NULL; @@ -717,24 +825,24 @@ _mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit, * \sa gl_texture_unit. */ struct gl_texture_image * -_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, - GLenum target, GLint level) +_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj, + GLenum target, GLint level) { - ASSERT(texUnit); - ASSERT(level < MAX_TEXTURE_LEVELS); + ASSERT(texObj); + + if (level < 0 || level >= MAX_TEXTURE_LEVELS) + return NULL; + + /* XXX simplify this with _mesa_tex_target_to_face() */ switch (target) { case GL_TEXTURE_1D: - return texUnit->Current1D->Image[0][level]; case GL_PROXY_TEXTURE_1D: - return ctx->Texture.Proxy1D->Image[0][level]; case GL_TEXTURE_2D: - return texUnit->Current2D->Image[0][level]; case GL_PROXY_TEXTURE_2D: - return ctx->Texture.Proxy2D->Image[0][level]; case GL_TEXTURE_3D: - return texUnit->Current3D->Image[0][level]; case GL_PROXY_TEXTURE_3D: - return ctx->Texture.Proxy3D->Image[0][level]; + return texObj->Image[0][level]; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: @@ -744,33 +852,32 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, if (ctx->Extensions.ARB_texture_cube_map) { GLuint face = ((GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X); - return texUnit->CurrentCubeMap->Image[face][level]; + return texObj->Image[face][level]; } else return NULL; + case GL_PROXY_TEXTURE_CUBE_MAP_ARB: if (ctx->Extensions.ARB_texture_cube_map) - return ctx->Texture.ProxyCubeMap->Image[0][level]; + return texObj->Image[0][level]; else return NULL; + case GL_TEXTURE_RECTANGLE_NV: - if (ctx->Extensions.NV_texture_rectangle) { - ASSERT(level == 0); - return texUnit->CurrentRect->Image[0][level]; - } - else { - return NULL; - } case GL_PROXY_TEXTURE_RECTANGLE_NV: - if (ctx->Extensions.NV_texture_rectangle) { - ASSERT(level == 0); - return ctx->Texture.ProxyRect->Image[0][level]; - } - else { + if (ctx->Extensions.NV_texture_rectangle && level == 0) + return texObj->Image[0][level]; + else return NULL; - } + + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + return (ctx->Extensions.MESA_texture_array) + ? texObj->Image[0][level] : NULL; + default: - _mesa_problem(ctx, "bad target in _mesa_select_tex_image()"); return NULL; } } @@ -782,22 +889,25 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, * out of memory. */ struct gl_texture_image * -_mesa_get_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, +_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj, GLenum target, GLint level) { struct gl_texture_image *texImage; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); + + if (!texObj) + return NULL; + + texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { - struct gl_texture_object *texObj; texImage = ctx->Driver.NewTextureImage(ctx); if (!texImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation"); return NULL; } - texObj = _mesa_select_tex_object(ctx, texUnit, target); - ASSERT(texObj); + _mesa_set_tex_image(texObj, target, level, texImage); } + return texImage; } @@ -892,6 +1002,36 @@ _mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level) texImage->TexObject = ctx->Texture.ProxyRect; } return texImage; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texImage = ctx->Texture.Proxy1DArray->Image[0][level]; + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation"); + return NULL; + } + ctx->Texture.Proxy1DArray->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.Proxy1DArray; + } + return texImage; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + if (level >= ctx->Const.MaxTextureLevels) + return NULL; + texImage = ctx->Texture.Proxy2DArray->Image[0][level]; + if (!texImage) { + texImage = ctx->Driver.NewTextureImage(ctx); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation"); + return NULL; + } + ctx->Texture.Proxy2DArray->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.Proxy2DArray; + } + return texImage; default: return NULL; } @@ -917,6 +1057,10 @@ _mesa_max_texture_levels(GLcontext *ctx, GLenum target) case GL_PROXY_TEXTURE_1D: case GL_TEXTURE_2D: case GL_PROXY_TEXTURE_2D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: return ctx->Const.MaxTextureLevels; case GL_TEXTURE_3D: case GL_PROXY_TEXTURE_3D: @@ -1009,13 +1153,17 @@ static void clear_teximage_fields(struct gl_texture_image *img) { ASSERT(img); - img->Format = 0; - img->IntFormat = 0; + img->_BaseFormat = 0; + img->InternalFormat = 0; img->Border = 0; img->Width = 0; img->Height = 0; img->Depth = 0; img->RowStride = 0; + if (img->ImageOffsets) { + _mesa_free(img->ImageOffsets); + img->ImageOffsets = NULL; + } img->Width2 = 0; img->Height2 = 0; img->Depth2 = 0; @@ -1035,7 +1183,7 @@ clear_teximage_fields(struct gl_texture_image *img) * Initialize basic fields of the gl_texture_image struct. * * \param ctx GL context. - * \param target texture target. + * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc). * \param img texture image structure to be initialized. * \param width image width. * \param height image height. @@ -1052,42 +1200,65 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum internalFormat) { + GLint i; + ASSERT(img); - img->Format = _mesa_base_tex_format( ctx, internalFormat ); - ASSERT(img->Format > 0); - img->IntFormat = internalFormat; + ASSERT(width >= 0); + ASSERT(height >= 0); + ASSERT(depth >= 0); + + img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat ); + ASSERT(img->_BaseFormat > 0); + img->InternalFormat = internalFormat; img->Border = border; img->Width = width; img->Height = height; img->Depth = depth; - img->RowStride = width; - img->WidthLog2 = logbase2(width - 2 * border); - if (height == 1) /* 1-D texture */ + + img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */ + img->WidthLog2 = logbase2(img->Width2); + + if (height == 1) { /* 1-D texture */ + img->Height2 = 1; img->HeightLog2 = 0; - else - img->HeightLog2 = logbase2(height - 2 * border); - if (depth == 1) /* 2-D texture */ + } + else { + img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */ + img->HeightLog2 = logbase2(img->Height2); + } + + if (depth == 1) { /* 2-D texture */ + img->Depth2 = 1; img->DepthLog2 = 0; - else - img->DepthLog2 = logbase2(depth - 2 * border); - img->Width2 = width - 2 * border; /*1 << img->WidthLog2;*/ - img->Height2 = height - 2 * border; /*1 << img->HeightLog2;*/ - img->Depth2 = depth - 2 * border; /*1 << img->DepthLog2;*/ + } + else { + img->Depth2 = depth - 2 * border; /* == 1 << img->DepthLog2; */ + img->DepthLog2 = logbase2(img->Depth2); + } + img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2); - img->IsCompressed = is_compressed_format(ctx, internalFormat); - if (img->IsCompressed) - img->CompressedSize = ctx->Driver.CompressedTextureSize(ctx, width, - height, depth, internalFormat); - else - img->CompressedSize = 0; - if ((width == 1 || _mesa_bitcount(width - 2 * border) == 1) && - (height == 1 || _mesa_bitcount(height - 2 * border) == 1) && - (depth == 1 || _mesa_bitcount(depth - 2 * border) == 1)) + img->IsCompressed = GL_FALSE; + img->CompressedSize = 0; + + if ((width == 1 || _mesa_bitcount(img->Width2) == 1) && + (height == 1 || _mesa_bitcount(img->Height2) == 1) && + (depth == 1 || _mesa_bitcount(img->Depth2) == 1)) img->_IsPowerOfTwo = GL_TRUE; else img->_IsPowerOfTwo = GL_FALSE; + /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */ + img->RowStride = width; + /* Allocate the ImageOffsets array and initialize to typical values. + * We allocate the array for 1D/2D textures too in order to avoid special- + * case code in the texstore routines. + */ + img->ImageOffsets = (GLuint *) _mesa_malloc(depth * sizeof(GLuint)); + for (i = 0; i < depth; i++) { + img->ImageOffsets[i] = i * width * height; + } + /* Compute Width/Height/DepthScale for mipmap lod computation */ if (target == GL_TEXTURE_RECTANGLE_NV) { /* scale = 1.0 since texture coords directly map to texels */ @@ -1110,6 +1281,10 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target, * A hardware driver might override this function if, for example, the * max 3D texture size is 512x512x64 (i.e. not a cube). * + * Note that width, height, depth == 0 is not an error. However, a + * texture with zero width/height/depth will be considered "incomplete" + * and texturing will effectively be disabled. + * * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D, * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV, * GL_PROXY_TEXTURE_CUBE_MAP_ARB. @@ -1139,7 +1314,7 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); if (width < 2 * border || width > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(width - 2 * border) != 1) || + width >0 && _mesa_bitcount(width - 2 * border) != 1) || level >= ctx->Const.MaxTextureLevels) { /* bad width or level */ return GL_FALSE; @@ -1149,10 +1324,10 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); if (width < 2 * border || width > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(width - 2 * border) != 1) || + width > 0 && _mesa_bitcount(width - 2 * border) != 1) || height < 2 * border || height > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(height - 2 * border) != 1) || + height > 0 && _mesa_bitcount(height - 2 * border) != 1) || level >= ctx->Const.MaxTextureLevels) { /* bad width or height or level */ return GL_FALSE; @@ -1162,21 +1337,21 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); if (width < 2 * border || width > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(width - 2 * border) != 1) || + width > 0 && _mesa_bitcount(width - 2 * border) != 1) || height < 2 * border || height > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(height - 2 * border) != 1) || + height > 0 && _mesa_bitcount(height - 2 * border) != 1) || depth < 2 * border || depth > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(depth - 2 * border) != 1) || + depth > 0 && _mesa_bitcount(depth - 2 * border) != 1) || level >= ctx->Const.Max3DTextureLevels) { /* bad width or height or depth or level */ return GL_FALSE; } return GL_TRUE; case GL_PROXY_TEXTURE_RECTANGLE_NV: - if (width < 1 || width > ctx->Const.MaxTextureRectSize || - height < 1 || height > ctx->Const.MaxTextureRectSize || + if (width < 0 || width > ctx->Const.MaxTextureRectSize || + height < 0 || height > ctx->Const.MaxTextureRectSize || level != 0) { /* bad width or height or level */ return GL_FALSE; @@ -1186,15 +1361,45 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1); if (width < 2 * border || width > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(width - 2 * border) != 1) || + width > 0 && _mesa_bitcount(width - 2 * border) != 1) || height < 2 * border || height > 2 + maxSize || (!ctx->Extensions.ARB_texture_non_power_of_two && - _mesa_bitcount(height - 2 * border) != 1) || + height > 0 && _mesa_bitcount(height - 2 * border) != 1) || level >= ctx->Const.MaxCubeTextureLevels) { /* bad width or height */ return GL_FALSE; } return GL_TRUE; + case GL_PROXY_TEXTURE_1D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize || + (!ctx->Extensions.ARB_texture_non_power_of_two && + width > 0 && _mesa_bitcount(width - 2 * border) != 1) || + level >= ctx->Const.MaxTextureLevels) { + /* bad width or level */ + return GL_FALSE; + } + + if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) { + return GL_FALSE; + } + return GL_TRUE; + case GL_PROXY_TEXTURE_2D_ARRAY_EXT: + maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + if (width < 2 * border || width > 2 + maxSize || + (!ctx->Extensions.ARB_texture_non_power_of_two && + width > 0 && _mesa_bitcount(width - 2 * border) != 1) || + height < 2 * border || height > 2 + maxSize || + (!ctx->Extensions.ARB_texture_non_power_of_two && + height > 0 && _mesa_bitcount(height - 2 * border) != 1) || + level >= ctx->Const.MaxTextureLevels) { + /* bad width or height or level */ + return GL_FALSE; + } + if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) { + return GL_FALSE; + } + return GL_TRUE; default: _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage"); return GL_FALSE; @@ -1202,6 +1407,23 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level, } +/** + * Helper function to determine whether a target supports compressed textures + */ +static GLboolean +target_can_be_compressed(GLcontext *ctx, GLenum target) +{ + return (((target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D)) + || ((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)))) + || ((ctx->Extensions.MESA_texture_array && + ((target == GL_PROXY_TEXTURE_2D_ARRAY_EXT) || + (target == GL_TEXTURE_2D_ARRAY_EXT))))); +} + + /** * Test the glTexImage[123]D() parameters for errors. * @@ -1231,9 +1453,10 @@ texture_error_check( GLcontext *ctx, GLenum target, GLint width, GLint height, GLint depth, GLint border ) { - const GLboolean isProxy = is_proxy_target(target); - GLboolean sizeOK; + const GLboolean isProxy = _mesa_is_proxy_texture(target); + GLboolean sizeOK = GL_TRUE; GLboolean colorFormat, indexFormat; + GLenum proxy_target; /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ if (level < 0 || level >= MAX_TEXTURE_LEVELS) { @@ -1268,10 +1491,9 @@ texture_error_check( GLcontext *ctx, GLenum target, */ if (dimensions == 1) { if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) { - sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_1D, - level, internalFormat, - format, type, - width, 1, 1, border); + proxy_target = GL_PROXY_TEXTURE_1D; + height = 1; + depth = 1; } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" ); @@ -1279,11 +1501,9 @@ texture_error_check( GLcontext *ctx, GLenum target, } } else if (dimensions == 2) { + depth = 1; if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) { - sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_2D, - level, internalFormat, - format, type, - width, height, 1, border); + proxy_target = GL_PROXY_TEXTURE_2D; } else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && @@ -1292,10 +1512,8 @@ texture_error_check( GLcontext *ctx, GLenum target, _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)"); return GL_TRUE; } - sizeOK = (width == height) && - ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_CUBE_MAP_ARB, - level, internalFormat, format, type, - width, height, 1, border); + proxy_target = GL_PROXY_TEXTURE_CUBE_MAP_ARB; + sizeOK = (width == height); } else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV || target == GL_TEXTURE_RECTANGLE_NV) { @@ -1303,11 +1521,11 @@ texture_error_check( GLcontext *ctx, GLenum target, _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)"); return GL_TRUE; } - sizeOK = ctx->Driver.TestProxyTexImage(ctx, - GL_PROXY_TEXTURE_RECTANGLE_NV, - level, internalFormat, - format, type, - width, height, 1, border); + proxy_target = GL_PROXY_TEXTURE_RECTANGLE_NV; + } + else if (target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || + target == GL_TEXTURE_1D_ARRAY_EXT) { + proxy_target = GL_PROXY_TEXTURE_1D_ARRAY_EXT; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)"); @@ -1316,10 +1534,11 @@ texture_error_check( GLcontext *ctx, GLenum target, } else if (dimensions == 3) { if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) { - sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_3D, - level, internalFormat, - format, type, - width, height, depth, border); + proxy_target = GL_PROXY_TEXTURE_3D; + } + else if (target == GL_PROXY_TEXTURE_2D_ARRAY_EXT || + target == GL_TEXTURE_2D_ARRAY_EXT) { + proxy_target = GL_PROXY_TEXTURE_2D_ARRAY_EXT; } else { _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" ); @@ -1331,6 +1550,10 @@ texture_error_check( GLcontext *ctx, GLenum target, return GL_TRUE; } + sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxy_target, level, + internalFormat, format, + type, width, height, + depth, border); if (!sizeOK) { if (!isProxy) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -1368,7 +1591,8 @@ texture_error_check( GLcontext *ctx, GLenum target, if ((is_color_format(internalFormat) && !colorFormat && !indexFormat) || (is_index_format(internalFormat) && !indexFormat) || (is_depth_format(internalFormat) != is_depth_format(format)) || - (is_ycbcr_format(internalFormat) != is_ycbcr_format(format))) { + (is_ycbcr_format(internalFormat) != is_ycbcr_format(format)) || + (is_depthstencil_format(internalFormat) != is_depthstencil_format(format))) { if (!isProxy) _mesa_error(ctx, GL_INVALID_OPERATION, "glTexImage(internalFormat/format)"); @@ -1408,11 +1632,13 @@ texture_error_check( GLcontext *ctx, GLenum target, /* additional checks for depth textures */ if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) { - /* Only 1D and 2D textures supported */ + /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */ if (target != GL_TEXTURE_1D && target != GL_PROXY_TEXTURE_1D && target != GL_TEXTURE_2D && - target != GL_PROXY_TEXTURE_2D) { + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB) { if (!isProxy) _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target/internalFormat)"); @@ -1422,21 +1648,10 @@ texture_error_check( GLcontext *ctx, GLenum target, /* additional checks for compressed textures */ if (is_compressed_format(ctx, 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 (!target_can_be_compressed(ctx, target) && !isProxy) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexImage%d(target)", dimensions); + return GL_TRUE; } if (border != 0) { if (!isProxy) { @@ -1481,9 +1696,6 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, GLint width, GLint height, GLint depth, GLenum format, GLenum type ) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - struct gl_texture_image *destTex; - /* Check target */ if (dimensions == 1) { if (target != GL_TEXTURE_1D) { @@ -1493,26 +1705,37 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } else if (dimensions == 2) { if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && - target <=GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { if (!ctx->Extensions.ARB_texture_cube_map) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" ); return GL_TRUE; } } - else if (ctx->Extensions.NV_texture_rectangle && - target == GL_TEXTURE_RECTANGLE_NV) { + else if (target == GL_TEXTURE_RECTANGLE_NV) { if (!ctx->Extensions.NV_texture_rectangle) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" ); return GL_TRUE; } } + else if (target == GL_TEXTURE_1D_ARRAY_EXT) { + if (!ctx->Extensions.MESA_texture_array) { + _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" ); + return GL_TRUE; + } + } else if (target != GL_TEXTURE_2D) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" ); return GL_TRUE; } } else if (dimensions == 3) { - if (target != GL_TEXTURE_3D) { + if (target == GL_TEXTURE_2D_ARRAY_EXT) { + if (!ctx->Extensions.MESA_texture_array) { + _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" ); + return GL_TRUE; + } + } + else if (target != GL_TEXTURE_3D) { _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" ); return GL_TRUE; } @@ -1544,8 +1767,23 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - destTex = _mesa_select_tex_image(ctx, texUnit, target, level); + if (!_mesa_is_legal_format_and_type(ctx, format, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexSubImage%dD(format or type)", dimensions); + return GL_TRUE; + } + + return GL_FALSE; +} +static GLboolean +subtexture_error_check2( GLcontext *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, + const struct gl_texture_image *destTex ) +{ if (!destTex) { /* undefined image level */ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions); @@ -1585,28 +1823,22 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } } - if (!_mesa_is_legal_format_and_type(ctx, format, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexSubImage%dD(format or type)", dimensions); +#if FEATURE_EXT_texture_sRGB + if (destTex->InternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT || + destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT || + destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT || + destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) { + if ((width & 0x3) || (height & 0x3) || + (xoffset & 0x3) || (yoffset & 0x3)) + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexSubImage%dD(size or offset not multiple of 4)", + dimensions); return GL_TRUE; } +#endif if (destTex->IsCompressed) { - const struct gl_texture_unit *texUnit; - const struct gl_texture_image *texImage; - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - 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 { + if (!target_can_be_compressed(ctx, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%D(target)", dimensions); return GL_TRUE; @@ -1618,12 +1850,12 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } /* size must be multiple of 4 or equal to whole texture size */ - if ((width & 3) && (GLuint) width != texImage->Width) { + if ((width & 3) && (GLuint) width != destTex->Width) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%D(width)", dimensions); return GL_TRUE; } - if ((height & 3) && (GLuint) height != texImage->Height) { + if ((height & 3) && (GLuint) height != destTex->Height) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%D(width)", dimensions); return GL_TRUE; @@ -1658,8 +1890,9 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, GLenum target, GLint level, GLint internalFormat, GLint width, GLint height, GLint border ) { - GLenum format, type; + GLenum type; GLboolean sizeOK; + GLint format; /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */ if (level < 0 || level >= MAX_TEXTURE_LEVELS) { @@ -1668,6 +1901,16 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + /* Check border */ if (border < 0 || border > 1 || ((target == GL_TEXTURE_RECTANGLE_NV || @@ -1675,10 +1918,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - /* The format and type aren't really significant here, but we need to pass - * something to TestProxyTexImage(). - */ format = _mesa_base_tex_format(ctx, internalFormat); + if (format < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glCopyTexImage%dD(internalFormat)", dimensions); + return GL_TRUE; + } + + /* NOTE: the format and type aren't really significant for + * TestProxyTexImage(). Only the internalformat really matters. + if (!_mesa_source_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(missing readbuffer)", dimensions); + return GL_TRUE; + } + + */ type = GL_FLOAT; /* Check target and call ctx->Driver.TestProxyTexImage() to check the @@ -1725,6 +1980,17 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, format, type, width, height, 1, border); } + else if (target == GL_TEXTURE_1D_ARRAY_EXT) { + if (!ctx->Extensions.MESA_texture_array) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)"); + return GL_TRUE; + } + sizeOK = ctx->Driver.TestProxyTexImage(ctx, + GL_PROXY_TEXTURE_1D_ARRAY_EXT, + level, internalFormat, + format, type, + width, height, 1, border); + } else { _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" ); return GL_TRUE; @@ -1748,12 +2014,6 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - 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(ctx, internalFormat)) { if (target != GL_TEXTURE_2D) { _mesa_error(ctx, GL_INVALID_ENUM, @@ -1766,14 +2026,30 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } } - - /* if we get here, the parameters are OK */ - return GL_FALSE; + else if (is_depth_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%D(no depth)", dimensions); + return GL_TRUE; + } + } + else if (is_depthstencil_format(internalFormat)) { + /* make sure we have depth/stencil buffers */ + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%D(no depth/stencil buffer)", dimensions); + return GL_TRUE; + } + } + + /* if we get here, the parameters are OK */ + return GL_FALSE; } /** - * Test glCopyTexImage[12]D() parameters for errors. + * Test glCopyTexSubImage[12]D() parameters for errors. * * \param ctx GL context. * \param dimensions texture image dimensions (must be 1, 2 or 3). @@ -1795,12 +2071,19 @@ static GLboolean copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height ) + GLsizei width, GLsizei height) { - struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - struct gl_texture_image *teximage; - /* Check target */ + /* Check that the source buffer is complete */ + if (ctx->ReadBuffer->Name) { + _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer); + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "glCopyTexImage%dD(invalid readbuffer)", dimensions); + return GL_TRUE; + } + } + if (dimensions == 1) { if (target != GL_TEXTURE_1D) { _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" ); @@ -1821,15 +2104,23 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } } + else if (target == GL_TEXTURE_1D_ARRAY_EXT) { + if (!ctx->Extensions.MESA_texture_array) { + _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" ); + return GL_TRUE; + } + } else if (target != GL_TEXTURE_2D) { _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" ); return GL_TRUE; } } else if (dimensions == 3) { - if (target != GL_TEXTURE_3D) { - _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" ); - return GL_TRUE; + if (((target != GL_TEXTURE_2D_ARRAY_EXT) || + (!ctx->Extensions.MESA_texture_array)) + && (target != GL_TEXTURE_3D)) { + _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" ); + return GL_TRUE; } } @@ -1852,7 +2143,16 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } - teximage = _mesa_select_tex_image(ctx, texUnit, target, level); + return GL_FALSE; +} + +static GLboolean +copytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions, + GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, + const struct gl_texture_image *teximage ) +{ if (!teximage) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage%dD(undefined texture level: %d)", @@ -1922,11 +2222,34 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, } } - if (teximage->IntFormat == GL_YCBCR_MESA) { + if (teximage->InternalFormat == GL_YCBCR_MESA) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D"); return GL_TRUE; } + if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%dD(missing readbuffer)", dimensions); + return GL_TRUE; + } + + if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) { + if (!ctx->ReadBuffer->_DepthBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%D(no depth buffer)", + dimensions); + return GL_TRUE; + } + } + else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) { + if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexSubImage%D(no depth/stencil buffer)", + dimensions); + return GL_TRUE; + } + } + /* if we get here, the parameters are OK */ return GL_FALSE; } @@ -1946,15 +2269,15 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { const struct gl_texture_unit *texUnit; - const struct gl_texture_object *texObj; - const struct gl_texture_image *texImage; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; GLint maxLevels = 0; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); texUnit = &(ctx->Texture.Unit[ctx->Texture.CurrentUnit]); texObj = _mesa_select_tex_object(ctx, texUnit, target); - if (!texObj || is_proxy_target(target)) { + if (!texObj || _mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return; } @@ -1980,54 +2303,116 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, if (!ctx->Extensions.EXT_paletted_texture && is_index_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return; } - if (!ctx->Extensions.SGIX_depth_texture && is_depth_format(format)) { + if (!ctx->Extensions.SGIX_depth_texture && + !ctx->Extensions.ARB_depth_texture && is_depth_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + return; } if (!ctx->Extensions.MESA_ycbcr_texture && is_ycbcr_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - } - - if (!pixels) - return; - - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (!texImage) { - /* invalid mipmap level, not an error */ return; } - /* Make sure the requested image format is compatible with the - * texture's format. We let the colorformat-indexformat go through, - * because the texelfetcher will dequantize to full rgba. - */ - if (is_color_format(format) - && !is_color_format(texImage->TexFormat->BaseFormat) - && !is_index_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_index_format(format) - && !is_index_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; - } - else if (is_depth_format(format) - && !is_depth_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + if (!ctx->Extensions.EXT_packed_depth_stencil + && is_depthstencil_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return; } - else if (is_ycbcr_format(format) - && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); - return; + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (!texImage) { + /* invalid mipmap level, not an error */ + goto out; + } + + + /* Make sure the requested image format is compatible with the + * texture's format. Note that a color index texture can be converted + * to RGBA so that combo is allowed. + */ + if (is_color_format(format) + && !is_color_format(texImage->TexFormat->BaseFormat) + && !is_index_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_index_format(format) + && !is_index_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_depth_format(format) + && !is_depth_format(texImage->TexFormat->BaseFormat) + && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_ycbcr_format(format) + && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + else if (is_depthstencil_format(format) + && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); + goto out; + } + + if (ctx->Pack.BufferObj->Name) { + /* packing texture image into a PBO */ + const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; + if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, + texImage->Height, texImage->Depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTexImage(invalid PBO access)"); + goto out; + } + } + + /* typically, this will call _mesa_get_teximage() */ + ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, + texObj, texImage); + } + out: + _mesa_unlock_texture(ctx, texObj); +} + - /* typically, this will call _mesa_get_teximage() */ - ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, - texObj, texImage); + +/** + * Check if the given texture image is bound to any framebuffer objects + * and update/invalidate them. + * XXX We're only checking the currently bound framebuffer object for now. + * In the future, perhaps struct gl_texture_image should have a pointer (or + * list of pointers (yikes)) to the gl_framebuffer(s) which it's bound to. + */ +static void +update_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj, + GLuint face, GLuint level) +{ + if (ctx->DrawBuffer->Name) { + GLuint i; + for (i = 0; i < BUFFER_COUNT; i++) { + struct gl_renderbuffer_attachment *att = + ctx->DrawBuffer->Attachment + i; + if (att->Type == GL_TEXTURE && + att->Texture == texObj && + att->TextureLevel == level && + att->CubeMapFace == face) { + ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]); + /* Tell driver about the new renderbuffer texture */ + ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att); + } + } + } } @@ -2053,52 +2438,54 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + const GLuint face = _mesa_tex_target_to_face(target); if (texture_error_check(ctx, target, level, internalFormat, format, type, 1, postConvWidth, 1, 1, border)) { return; /* error was recorded */ } - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, 1, 1, - border, internalFormat); - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_update_state(ctx); - ASSERT(ctx->Driver.TexImage1D); + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, - width, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); + ASSERT(texImage->Data == NULL); - ASSERT(texImage->TexFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, 1, 1, + border, internalFormat); + + ASSERT(ctx->Driver.TexImage1D); - /* If driver didn't explicitly set this, use the defaults */ - if (!texImage->FetchTexelc) - texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D; - if (!texImage->FetchTexelf) - texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df; - ASSERT(texImage->FetchTexelc); - ASSERT(texImage->FetchTexelf); + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat, + width, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + ASSERT(texImage->TexFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ @@ -2147,11 +2534,14 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, 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_RECTANGLE_NV) || + (ctx->Extensions.MESA_texture_array && + target == GL_TEXTURE_1D_ARRAY_EXT)) { /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; + const GLuint face = _mesa_tex_target_to_face(target); if (texture_error_check(ctx, target, level, internalFormat, format, type, 2, postConvWidth, postConvHeight, @@ -2159,51 +2549,54 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, return; /* error was recorded */ } - texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, postConvHeight, 1, - border, internalFormat); - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_update_state(ctx); - ASSERT(ctx->Driver.TexImage2D); - - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, - width, height, border, format, type, pixels, - &ctx->Unpack, texObj, texImage); - - ASSERT(texImage->TexFormat); - - /* If driver didn't explicitly set these, use the defaults */ - if (!texImage->FetchTexelc) - texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D; - if (!texImage->FetchTexelf) - texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df; - ASSERT(texImage->FetchTexelc); - ASSERT(texImage->FetchTexelf); - - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, postConvHeight, 1, + border, internalFormat); + + ASSERT(ctx->Driver.TexImage2D); + + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + ASSERT(texImage->TexFormat); + + update_fbo_texture(ctx, texObj, face, level); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_2D || (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB && ctx->Extensions.ARB_texture_cube_map) || (target == GL_PROXY_TEXTURE_RECTANGLE_NV && - ctx->Extensions.NV_texture_rectangle)) { + ctx->Extensions.NV_texture_rectangle) || + (ctx->Extensions.MESA_texture_array && + target == GL_PROXY_TEXTURE_1D_ARRAY_EXT)) { /* Proxy texture: check for errors and update proxy state */ struct gl_texture_image *texImage; texImage = _mesa_get_proxy_tex_image(ctx, target, level); @@ -2243,58 +2636,64 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (target == GL_TEXTURE_3D) { + if (target == GL_TEXTURE_3D || + (ctx->Extensions.MESA_texture_array && + target == GL_TEXTURE_2D_ARRAY_EXT)) { + /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; - /* non-proxy target */ + const GLuint face = _mesa_tex_target_to_face(target); if (texture_error_check(ctx, target, level, (GLint) internalFormat, format, type, 3, width, height, depth, border)) { return; /* error was recorded */ } + if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) + _mesa_update_state(ctx); + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - width, height, depth, - border, internalFormat); - - if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE) - _mesa_update_state(ctx); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, + border, internalFormat); - ASSERT(ctx->Driver.TexImage3D); + ASSERT(ctx->Driver.TexImage3D); - /* Give the texture to the driver! may be null! */ - (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat, - width, height, depth, border, format, type, - pixels, &ctx->Unpack, texObj, texImage); + /* Give the texture to the driver! may be null! */ + (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat, + width, height, depth, border, format, type, + pixels, &ctx->Unpack, texObj, texImage); - ASSERT(texImage->TexFormat); + ASSERT(texImage->TexFormat); - /* If driver didn't explicitly set these, use the defaults */ - if (!texImage->FetchTexelc) - texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D; - if (!texImage->FetchTexelf) - texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df; - ASSERT(texImage->FetchTexelc); - ASSERT(texImage->FetchTexelf); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } - else if (target == GL_PROXY_TEXTURE_3D) { + else if (target == GL_PROXY_TEXTURE_3D || + (ctx->Extensions.MESA_texture_array && + target == GL_PROXY_TEXTURE_2D_ARRAY_EXT)) { /* Proxy texture: check for errors and update proxy state */ struct gl_texture_image *texImage; texImage = _mesa_get_proxy_tex_image(ctx, target, level); @@ -2340,7 +2739,7 @@ _mesa_TexSubImage1D( GLenum target, GLint level, GLsizei postConvWidth = width; struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; - struct gl_texture_image *texImage; + struct gl_texture_image *texImage = NULL; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2353,26 +2752,38 @@ _mesa_TexSubImage1D( GLenum target, GLint level, } if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0, - postConvWidth, 1, 1, format, type)) { + postConvWidth, 1, 1, format, type)) { return; /* error was detected */ } + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + assert(texObj); - if (width == 0) - return; /* no-op, not an error */ + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; + if (subtexture_error_check2(ctx, 1, target, level, xoffset, 0, 0, + postConvWidth, 1, 1, format, type, texImage)) { + goto out; /* error was detected */ + } + + if (width == 0) + goto out; /* no-op, not an error */ + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; - ASSERT(ctx->Driver.TexSubImage1D); - (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width, - format, type, pixels, &ctx->Unpack, - texObj, texImage); - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.TexSubImage1D); + (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width, + format, type, pixels, &ctx->Unpack, + texObj, texImage); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2400,27 +2811,37 @@ _mesa_TexSubImage2D( GLenum target, GLint level, } if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0, - postConvWidth, postConvHeight, 1, format, type)) { + postConvWidth, postConvHeight, 1, format, type)) { return; /* error was detected */ } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - if (width == 0 || height == 0) - return; /* no-op, not an error */ + if (subtexture_error_check2(ctx, 2, target, level, xoffset, yoffset, 0, + postConvWidth, postConvHeight, 1, format, type, + texImage)) { + goto out; /* error was detected */ + } - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; + if (width == 0 || height == 0) + goto out; /* no-op, not an error */ - ASSERT(ctx->Driver.TexSubImage2D); - (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset, - width, height, format, type, pixels, - &ctx->Unpack, texObj, texImage); - ctx->NewState |= _NEW_TEXTURE; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + + ASSERT(ctx->Driver.TexSubImage2D); + (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset, + width, height, format, type, pixels, + &ctx->Unpack, texObj, texImage); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2448,24 +2869,34 @@ _mesa_TexSubImage3D( GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); - - if (width == 0 || height == 0 || height == 0) - return; /* no-op, not an error */ - - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; - zoffset += texImage->Border; - - ASSERT(ctx->Driver.TexSubImage3D); - (*ctx->Driver.TexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, type, pixels, - &ctx->Unpack, texObj, texImage ); - ctx->NewState |= _NEW_TEXTURE; + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (subtexture_error_check2(ctx, 3, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, texImage)) { + goto out; /* error was detected */ + } + + if (width == 0 || height == 0 || height == 0) + goto out; /* no-op, not an error */ + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + zoffset += texImage->Border; + + ASSERT(ctx->Driver.TexSubImage3D); + (*ctx->Driver.TexSubImage3D)(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, + &ctx->Unpack, texObj, texImage ); + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2480,6 +2911,7 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width; + const GLuint face = _mesa_tex_target_to_face(target); GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2496,38 +2928,39 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1, - border, internalFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1, + border, internalFormat); - ASSERT(ctx->Driver.CopyTexImage1D); - (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, - x, y, width, border); + ASSERT(ctx->Driver.CopyTexImage1D); + (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, + x, y, width, border); - ASSERT(texImage->TexFormat); + ASSERT(texImage->TexFormat); - /* If driver didn't explicitly set these, use the defaults */ - if (!texImage->FetchTexelc) - texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D; - if (!texImage->FetchTexelf) - texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df; - ASSERT(texImage->FetchTexelc); - ASSERT(texImage->FetchTexelf); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2541,6 +2974,7 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; + const GLuint face = _mesa_tex_target_to_face(target); GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2558,49 +2992,55 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, - postConvWidth, postConvHeight, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); - ASSERT(ctx->Driver.CopyTexImage2D); - (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat, - x, y, width, height, border); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + + ASSERT(texImage->Data == NULL); - ASSERT(texImage->TexFormat); + clear_teximage_fields(texImage); /* not really needed, but helpful */ + _mesa_init_teximage_fields(ctx, target, texImage, + postConvWidth, postConvHeight, 1, + border, internalFormat); + + ASSERT(ctx->Driver.CopyTexImage2D); + (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat, + x, y, width, height, border); + + ASSERT(texImage->TexFormat); - /* If driver didn't explicitly set these, use the defaults */ - if (!texImage->FetchTexelc) - texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D; - if (!texImage->FetchTexelf) - texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df; - ASSERT(texImage->FetchTexelc); - ASSERT(texImage->FetchTexelf); + update_fbo_texture(ctx, texObj, face, level); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } - void GLAPIENTRY _mesa_CopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width; + GLint yoffset = 0; + GLsizei height = 1; + GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -2615,15 +3055,32 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; + if (copytexsubimage_error_check2(ctx, 1, target, level, + xoffset, 0, 0, postConvWidth, 1, + texImage)) + goto out; + + + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; - ASSERT(ctx->Driver.CopyTexSubImage1D); - (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width); - ctx->NewState |= _NEW_TEXTURE; + if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, + &width, &height)) { + ASSERT(ctx->Driver.CopyTexSubImage1D); + ctx->Driver.CopyTexSubImage1D(ctx, target, level, + xoffset, x, y, width); + } + + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2634,6 +3091,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; GET_CURRENT_CONTEXT(ctx); @@ -2650,17 +3108,31 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; + if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0, + postConvWidth, postConvHeight, texImage)) + goto out; - ASSERT(ctx->Driver.CopyTexSubImage2D); - (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level, - xoffset, yoffset, x, y, width, height); - ctx->NewState |= _NEW_TEXTURE; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + + if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, + &width, &height)) { + ASSERT(ctx->Driver.CopyTexSubImage2D); + ctx->Driver.CopyTexSubImage2D(ctx, target, level, + xoffset, yoffset, x, y, width, height); + } + + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2671,6 +3143,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, GLint x, GLint y, GLsizei width, GLsizei height ) { struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLsizei postConvWidth = width, postConvHeight = height; GET_CURRENT_CONTEXT(ctx); @@ -2687,19 +3160,34 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, return; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - ASSERT(texImage); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset, + zoffset, postConvWidth, postConvHeight, + texImage)) + goto out; - /* If we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; - zoffset += texImage->Border; + /* If we have a border, xoffset=-1 is legal. Bias by border width */ + xoffset += texImage->Border; + yoffset += texImage->Border; + zoffset += texImage->Border; + + if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y, + &width, &height)) { + ASSERT(ctx->Driver.CopyTexSubImage3D); + ctx->Driver.CopyTexSubImage3D(ctx, target, level, + xoffset, yoffset, zoffset, + x, y, width, height); + } - ASSERT(ctx->Driver.CopyTexSubImage3D); - (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - x, y, width, height); - ctx->NewState |= _NEW_TEXTURE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } @@ -2756,9 +3244,11 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, maxTextureSize = 1 << (maxLevels - 1); + /* This will detect any invalid internalFormat value */ if (!is_compressed_format(ctx, internalFormat)) return GL_INVALID_ENUM; + /* This should really never fail */ if (_mesa_base_tex_format(ctx, internalFormat) < 0) return GL_INVALID_ENUM; @@ -2790,11 +3280,21 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, if (level < 0 || level >= maxLevels) return GL_INVALID_VALUE; - expectedSize = ctx->Driver.CompressedTextureSize(ctx, width, height, depth, - internalFormat); + expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height, + depth, internalFormat); if (expectedSize != imageSize) return GL_INVALID_VALUE; +#if FEATURE_EXT_texture_sRGB + if ((internalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT || + internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT || + internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT || + internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) + && border != 0) { + return GL_INVALID_OPERATION; + } +#endif + return GL_NO_ERROR; } @@ -2849,6 +3349,7 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, maxTextureSize = 1 << (maxLevels - 1); + /* this will catch any invalid compressed format token */ if (!is_compressed_format(ctx, format)) return GL_INVALID_ENUM; @@ -2874,8 +3375,8 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, if ((height & 3) != 0 && height != 2 && height != 1) return GL_INVALID_VALUE; - expectedSize = ctx->Driver.CompressedTextureSize(ctx, width, height, depth, - format); + expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height, + depth, format); if (expectedSize != imageSize) return GL_INVALID_VALUE; @@ -2907,28 +3408,35 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); - ASSERT(ctx->Driver.CompressedTexImage1D); - (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, - internalFormat, width, border, - imageSize, data, - texObj, texImage); + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + ASSERT(ctx->Driver.CompressedTexImage1D); + (*ctx->Driver.CompressedTexImage1D)(ctx, target, level, + internalFormat, width, border, + imageSize, data, + texObj, texImage); + + /* state update */ + texObj->_Complete = GL_FALSE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ @@ -2950,11 +3458,18 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; 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); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -2990,28 +3505,35 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); - ASSERT(ctx->Driver.CompressedTexImage2D); - (*ctx->Driver.CompressedTexImage2D)(ctx, target, level, - internalFormat, width, height, - border, imageSize, data, - texObj, texImage); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + 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; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_2D || (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB && @@ -3035,11 +3557,18 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; 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); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -3072,29 +3601,35 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_get_tex_image(ctx, texUnit, target, level); - if (!texImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D"); - return; - } - else if (texImage->Data) { - ctx->Driver.FreeTexImageData( ctx, texImage ); - } - ASSERT(texImage->Data == NULL); - - _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, - border, internalFormat); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_get_tex_image(ctx, texObj, target, level); + if (!texImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D"); + goto out; + } + + if (texImage->Data) { + ctx->Driver.FreeTexImageData( ctx, texImage ); + } + ASSERT(texImage->Data == NULL); - ASSERT(ctx->Driver.CompressedTexImage3D); - (*ctx->Driver.CompressedTexImage3D)(ctx, target, level, - internalFormat, - width, height, depth, - border, imageSize, data, - texObj, texImage); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, + border, internalFormat); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + 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; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ @@ -3116,11 +3651,17 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, else { /* store the teximage parameters */ struct gl_texture_unit *texUnit; + struct gl_texture_object *texObj; 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); + texObj = _mesa_select_tex_object(ctx, texUnit, target); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + _mesa_init_teximage_fields(ctx, target, texImage, width, height, + depth, border, internalFormat); + } + _mesa_unlock_texture(ctx, texObj); } } else { @@ -3143,7 +3684,9 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); error = compressed_subtexture_error_check(ctx, 1, target, level, - xoffset, 0, 0, width, 1, 1, format, imageSize); + xoffset, 0, 0, /* pos */ + width, 1, 1, /* size */ + format, imageSize); if (error) { _mesa_error(ctx, error, "glCompressedTexSubImage1D"); return; @@ -3151,30 +3694,35 @@ _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->IntFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage1D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage1D(format)"); + goto out; + } - if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)"); - return; - } + if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)"); + goto out; + } - if (width == 0) - return; /* no-op, not an error */ + if (width == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage1D) { - (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level, - xoffset, width, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage1D) { + (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level, + xoffset, width, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3192,7 +3740,9 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); error = compressed_subtexture_error_check(ctx, 2, target, level, - xoffset, yoffset, 0, width, height, 1, format, imageSize); + xoffset, yoffset, 0, /* pos */ + width, height, 1, /* size */ + format, imageSize); if (error) { /* XXX proxy target? */ _mesa_error(ctx, error, "glCompressedTexSubImage2D"); @@ -3201,31 +3751,36 @@ _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->IntFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage2D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage2D(format)"); + goto out; + } - if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || - ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)"); - return; - } + if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || + ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)"); + goto out; + } - if (width == 0 || height == 0) - return; /* no-op, not an error */ + if (width == 0 || height == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage2D) { - (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level, - xoffset, yoffset, width, height, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage2D) { + (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level, + xoffset, yoffset, width, height, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3243,41 +3798,48 @@ _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); error = compressed_subtexture_error_check(ctx, 3, target, level, - xoffset, yoffset, zoffset, width, height, depth, format, imageSize); + xoffset, yoffset, zoffset,/*pos*/ + width, height, depth, /*size*/ + format, imageSize); if (error) { - _mesa_error(ctx, error, "glCompressedTexSubImage2D"); + _mesa_error(ctx, error, "glCompressedTexSubImage3D"); return; } texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(ctx, texUnit, target); - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - assert(texImage); + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + assert(texImage); - if ((GLint) format != texImage->IntFormat) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCompressedTexSubImage3D(format)"); - return; - } + if ((GLint) format != texImage->InternalFormat) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTexSubImage3D(format)"); + goto out; + } - if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || - ((height == 1 || height == 2) && (GLuint) height != texImage->Height) || - ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)"); - return; - } + if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) || + ((height == 1 || height == 2) && (GLuint) height != texImage->Height) || + ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)"); + goto out; + } - if (width == 0 || height == 0 || depth == 0) - return; /* no-op, not an error */ + if (width == 0 || height == 0 || depth == 0) + goto out; /* no-op, not an error */ - if (ctx->Driver.CompressedTexSubImage3D) { - (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level, - xoffset, yoffset, zoffset, - width, height, depth, - format, imageSize, data, - texObj, texImage); + if (ctx->Driver.CompressedTexSubImage3D) { + (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level, + xoffset, yoffset, zoffset, + width, height, depth, + format, imageSize, data, + texObj, texImage); + } + ctx->NewState |= _NEW_TEXTURE; } - ctx->NewState |= _NEW_TEXTURE; + out: + _mesa_unlock_texture(ctx, texObj); } @@ -3285,7 +3847,7 @@ void GLAPIENTRY _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) { const struct gl_texture_unit *texUnit; - const struct gl_texture_object *texObj; + struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLint maxLevels; GET_CURRENT_CONTEXT(ctx); @@ -3306,23 +3868,30 @@ _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) return; } - if (is_proxy_target(target)) { + if (_mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); return; } - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (!texImage) { - /* probably invalid mipmap level */ - _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); - return; - } - - if (!texImage->IsCompressed) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB"); - return; + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (texImage) { + if (texImage->IsCompressed) { + /* this typically calls _mesa_get_compressed_teximage() */ + ctx->Driver.GetCompressedTexImage(ctx, target, level, img, + texObj, texImage); + } + else { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImageARB"); + } + } + else { + /* probably invalid mipmap level */ + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetCompressedTexImageARB(level)"); + } } - - /* this typically calls _mesa_get_compressed_teximage() */ - ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage); + _mesa_unlock_texture(ctx, texObj); }