X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fteximage.c;h=384e1455203c3185d79a7c3ec0c869ca9bbcdcc5;hb=ff938bf059a41a9bdf4c2c93cebe4a3b8a89c201;hp=90f03322373d240a8a783d66cc2ea38015906886;hpb=6dc85575000127630489b407c50a4b3ea87c9acb;p=mesa.git diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 90f03322373..384e1455203 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1,19 +1,8 @@ -/** - * \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. - */ - /* * Mesa 3-D graphics library - * Version: 5.1 + * Version: 7.1 * - * Copyright (C) 1999-2003 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"), @@ -34,9 +23,18 @@ */ +/** + * \file teximage.c + * Texture image-related functions. + */ + + #include "glheader.h" +#include "bufferobj.h" #include "context.h" #include "convolve.h" +#include "fbobject.h" +#include "framebuffer.h" #include "image.h" #include "imports.h" #include "macros.h" @@ -49,14 +47,37 @@ #include "mtypes.h" +/** + * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE + * elsewhere. + */ +void * +_mesa_alloc_texmemory(GLsizei bytes) +{ + return _mesa_align_malloc(bytes, 512); +} + + +/** + * Free texture memory allocated with _mesa_alloc_texmemory() + */ +void +_mesa_free_texmemory(void *m) +{ + _mesa_align_free(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"); @@ -96,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 @@ -105,7 +127,7 @@ static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img) /* * Compute floor(log_base_2(n)). - * If n <= 0 return -1. + * If n < 0 return -1. */ static int logbase2( int n ) @@ -113,9 +135,11 @@ logbase2( int n ) GLint i = 1; GLint log2 = 0; - if (n <= 0) { + if (n < 0) return -1; - } + + if (n == 0) + return 0; while ( n > i ) { i *= 2; @@ -132,10 +156,11 @@ logbase2( int n ) /** - * Get base internal format. + * Return the simple base format for a given internal texture format. + * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA. * * \param ctx GL context. - * \param format internal texture format enum or 1, 2, 3, 4. + * \param internalFormat the internal texture format token or 1, 2, 3, or 4. * * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE, * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum. @@ -144,13 +169,9 @@ logbase2( int n ) * texture format and env mode determine the arithmetic used. */ GLint -_mesa_base_tex_format( GLcontext *ctx, GLint format ) +_mesa_base_tex_format( GLcontext *ctx, GLint internalFormat ) { - /* - * Ask the driver for the base format, if it doesn't - * know, it will return -1; - */ - switch (format) { + switch (internalFormat) { case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: @@ -199,88 +220,181 @@ _mesa_base_tex_format( GLcontext *ctx, GLint format ) case GL_RGBA12: case GL_RGBA16: return GL_RGBA; - case GL_COLOR_INDEX: - case GL_COLOR_INDEX1_EXT: - case GL_COLOR_INDEX2_EXT: - case GL_COLOR_INDEX4_EXT: - case GL_COLOR_INDEX8_EXT: - case GL_COLOR_INDEX12_EXT: - case GL_COLOR_INDEX16_EXT: - if (ctx->Extensions.EXT_paletted_texture) + default: + ; /* fallthrough */ + } + + if (ctx->Extensions.EXT_paletted_texture) { + switch (internalFormat) { + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: return GL_COLOR_INDEX; - else - return -1; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_SGIX: - case GL_DEPTH_COMPONENT24_SGIX: - case GL_DEPTH_COMPONENT32_SGIX: - if (ctx->Extensions.SGIX_depth_texture) + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.SGIX_depth_texture || + ctx->Extensions.ARB_depth_texture) { + switch (internalFormat) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16_SGIX: + case GL_DEPTH_COMPONENT24_SGIX: + case GL_DEPTH_COMPONENT32_SGIX: return GL_DEPTH_COMPONENT; - else - return -1; + default: + ; /* fallthrough */ + } + } - /* GL_ARB_texture_compression */ - case GL_COMPRESSED_ALPHA: - if (ctx->Extensions.ARB_texture_compression) + if (ctx->Extensions.ARB_texture_compression) { + switch (internalFormat) { + case GL_COMPRESSED_ALPHA: return GL_ALPHA; - else - return -1; - case GL_COMPRESSED_LUMINANCE: - if (ctx->Extensions.ARB_texture_compression) + case GL_COMPRESSED_LUMINANCE: return GL_LUMINANCE; - else - return -1; - case GL_COMPRESSED_LUMINANCE_ALPHA: - if (ctx->Extensions.ARB_texture_compression) + case GL_COMPRESSED_LUMINANCE_ALPHA: return GL_LUMINANCE_ALPHA; - else - return -1; - case GL_COMPRESSED_INTENSITY: - if (ctx->Extensions.ARB_texture_compression) + case GL_COMPRESSED_INTENSITY: return GL_INTENSITY; - else - return -1; - case GL_COMPRESSED_RGB: - if (ctx->Extensions.ARB_texture_compression) + case GL_COMPRESSED_RGB: return GL_RGB; - else - return -1; - case GL_COMPRESSED_RGBA: - if (ctx->Extensions.ARB_texture_compression) + case GL_COMPRESSED_RGBA: return GL_RGBA; - else - return -1; - case GL_COMPRESSED_RGB_FXT1_3DFX: - if (ctx->Extensions.TDFX_texture_compression_FXT1) + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.TDFX_texture_compression_FXT1) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_FXT1_3DFX: return GL_RGB; - else - return -1; - case GL_COMPRESSED_RGBA_FXT1_3DFX: - if (ctx->Extensions.TDFX_texture_compression_FXT1) + case GL_COMPRESSED_RGBA_FXT1_3DFX: return GL_RGBA; - else - return -1; + default: + ; /* fallthrough */ + } + } - case GL_YCBCR_MESA: - if (ctx->Extensions.MESA_ycbcr_texture) - return GL_YCBCR_MESA; - else - return -1; + if (ctx->Extensions.EXT_texture_compression_s3tc) { + switch (internalFormat) { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.S3_s3tc) { + switch (internalFormat) { + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + return GL_RGB; + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + return GL_RGBA; + default: + ; /* fallthrough */ + } + } + + if (ctx->Extensions.MESA_ycbcr_texture) { + if (internalFormat == GL_YCBCR_MESA) + return GL_YCBCR_MESA; + } + + if (ctx->Extensions.ARB_texture_float) { + switch (internalFormat) { + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + return GL_ALPHA; + case GL_RGBA16F_ARB: + case GL_RGBA32F_ARB: + return GL_RGBA; + case GL_RGB16F_ARB: + case GL_RGB32F_ARB: + return GL_RGB; + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + return GL_INTENSITY; + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + return GL_LUMINANCE_ALPHA; + default: + ; /* fallthrough */ + } + } + + 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: - return -1; /* error */ + ; /* fallthrough */ + } } + +#endif /* FEATURE_EXT_texture_sRGB */ + + return -1; /* error */ } /** - * Test if the given image format is a color/RGBA format, i.e., not - * color index, depth, stencil, etc. + * Test if the given image format is a color/RGBA format (i.e., not color + * index, depth, stencil, etc). + * \param format the image format value (may by an internal texture format) + * \return GL_TRUE if its a color/RGBA format, GL_FALSE otherwise. */ static GLboolean is_color_format(GLenum format) { switch (format) { + case GL_RED: + case GL_GREEN: + case GL_BLUE: case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: @@ -307,6 +421,7 @@ is_color_format(GLenum format) case GL_INTENSITY16: case 3: case GL_RGB: + case GL_BGR: case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: @@ -315,7 +430,9 @@ is_color_format(GLenum format) case GL_RGB12: case GL_RGB16: case 4: + case GL_ABGR_EXT: case GL_RGBA: + case GL_BGRA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: @@ -323,6 +440,54 @@ is_color_format(GLenum format) case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: + /* float texture formats */ + case GL_ALPHA16F_ARB: + case GL_ALPHA32F_ARB: + case GL_LUMINANCE16F_ARB: + case GL_LUMINANCE32F_ARB: + case GL_LUMINANCE_ALPHA16F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + case GL_INTENSITY16F_ARB: + case GL_INTENSITY32F_ARB: + case GL_RGB16F_ARB: + case GL_RGB32F_ARB: + case GL_RGBA16F_ARB: + case GL_RGBA32F_ARB: + /* compressed formats */ + case GL_COMPRESSED_ALPHA: + case GL_COMPRESSED_LUMINANCE: + case GL_COMPRESSED_LUMINANCE_ALPHA: + case GL_COMPRESSED_INTENSITY: + case GL_COMPRESSED_RGB: + case GL_COMPRESSED_RGBA: + case GL_RGB_S3TC: + case GL_RGB4_S3TC: + case GL_RGBA_S3TC: + case GL_RGBA4_S3TC: + 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_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: @@ -352,6 +517,56 @@ is_index_format(GLenum format) } +/** + * Test if the given image format is a depth component format. + */ +static GLboolean +is_depth_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT16_ARB: + case GL_DEPTH_COMPONENT24_ARB: + case GL_DEPTH_COMPONENT32_ARB: + case GL_DEPTH_COMPONENT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Test if the given image format is a YCbCr format. + */ +static GLboolean +is_ycbcr_format(GLenum format) +{ + switch (format) { + case GL_YCBCR_MESA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * 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. * @@ -364,18 +579,38 @@ is_index_format(GLenum format) * are supported. */ static GLboolean -is_compressed_format(GLenum internalFormat) +is_compressed_format(GLcontext *ctx, GLenum internalFormat) { - switch (internalFormat) { - case GL_COMPRESSED_RGB_FXT1_3DFX: - case GL_COMPRESSED_RGBA_FXT1_3DFX: + 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. @@ -394,38 +629,37 @@ _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: - tObj->Image[level] = texImage; - return; + 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: - tObj->Image[level] = texImage; - return; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - tObj->NegX[level] = texImage; - return; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - tObj->PosY[level] = texImage; - return; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - tObj->NegY[level] = texImage; - return; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - tObj->PosZ[level] = texImage; - return; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - tObj->NegZ[level] = texImage; - return; + { + GLuint face = ((GLuint) target - + (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X); + tObj->Image[face][level] = texImage; + } + break; case GL_TEXTURE_RECTANGLE_NV: ASSERT(level == 0); - tObj->Image[level] = texImage; - return; + tObj->Image[0][level] = texImage; + break; default: _mesa_problem(NULL, "bad target in _mesa_set_tex_image()"); return; } + /* Set the 'back' pointer */ + texImage->TexObject = tObj; } @@ -447,21 +681,48 @@ _mesa_new_texture_image( GLcontext *ctx ) /** - * Free texture image. + * Free texture image data. + * This function is a fallback called via ctx->Driver.FreeTexImageData(). * * \param teximage texture image. * - * Free the texture image structure and the associated image data if it's not - * marked as client data. + * Free the texture image data if it's not marked as client data. */ void -_mesa_delete_texture_image( struct gl_texture_image *teximage ) +_mesa_free_texture_image_data(GLcontext *ctx, + struct gl_texture_image *texImage) { - if (teximage->Data && !teximage->IsClientData) { - MESA_PBUFFER_FREE( teximage->Data ); - teximage->Data = NULL; + (void) ctx; + + if (texImage->Data && !texImage->IsClientData) { + /* free the old texture data */ + _mesa_free_texmemory(texImage->Data); } - FREE( teximage ); + + texImage->Data = NULL; +} + + +/** + * Free texture image. + * + * \param teximage texture image. + * + * Free the texture image structure and the associated image data. + */ +void +_mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *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); + if (texImage->ImageOffsets) + _mesa_free(texImage->ImageOffsets); + _mesa_free(texImage); } @@ -472,14 +733,16 @@ _mesa_delete_texture_image( 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); } @@ -529,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; @@ -550,77 +825,59 @@ _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[level]; case GL_PROXY_TEXTURE_1D: - return ctx->Texture.Proxy1D->Image[level]; case GL_TEXTURE_2D: - return texUnit->Current2D->Image[level]; case GL_PROXY_TEXTURE_2D: - return ctx->Texture.Proxy2D->Image[level]; case GL_TEXTURE_3D: - return texUnit->Current3D->Image[level]; case GL_PROXY_TEXTURE_3D: - return ctx->Texture.Proxy3D->Image[level]; + return texObj->Image[0][level]; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->Image[level]; - else - return NULL; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->NegX[level]; - else - return NULL; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->PosY[level]; - else - return NULL; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->NegY[level]; - else - return NULL; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->PosZ[level]; - else - return NULL; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - if (ctx->Extensions.ARB_texture_cube_map) - return texUnit->CurrentCubeMap->NegZ[level]; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + if (ctx->Extensions.ARB_texture_cube_map) { + GLuint face = ((GLuint) target - + (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X); + 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[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[level]; - } - else { - return NULL; - } case GL_PROXY_TEXTURE_RECTANGLE_NV: - if (ctx->Extensions.NV_texture_rectangle) { - ASSERT(level == 0); - return ctx->Texture.ProxyRect->Image[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; } } @@ -632,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; } @@ -670,66 +930,106 @@ _mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level) case GL_PROXY_TEXTURE_1D: if (level >= ctx->Const.MaxTextureLevels) return NULL; - texImage = ctx->Texture.Proxy1D->Image[level]; + texImage = ctx->Texture.Proxy1D->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.Proxy1D->Image[level] = texImage; + ctx->Texture.Proxy1D->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.Proxy1D; } return texImage; case GL_PROXY_TEXTURE_2D: if (level >= ctx->Const.MaxTextureLevels) return NULL; - texImage = ctx->Texture.Proxy2D->Image[level]; + texImage = ctx->Texture.Proxy2D->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.Proxy2D->Image[level] = texImage; + ctx->Texture.Proxy2D->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.Proxy2D; } return texImage; case GL_PROXY_TEXTURE_3D: if (level >= ctx->Const.Max3DTextureLevels) return NULL; - texImage = ctx->Texture.Proxy3D->Image[level]; + texImage = ctx->Texture.Proxy3D->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.Proxy3D->Image[level] = texImage; + ctx->Texture.Proxy3D->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.Proxy3D; } return texImage; case GL_PROXY_TEXTURE_CUBE_MAP: if (level >= ctx->Const.MaxCubeTextureLevels) return NULL; - texImage = ctx->Texture.ProxyCubeMap->Image[level]; + texImage = ctx->Texture.ProxyCubeMap->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.ProxyCubeMap->Image[level] = texImage; + ctx->Texture.ProxyCubeMap->Image[0][level] = texImage; + /* Set the 'back' pointer */ + texImage->TexObject = ctx->Texture.ProxyCubeMap; } return texImage; case GL_PROXY_TEXTURE_RECTANGLE_NV: if (level > 0) return NULL; - texImage = ctx->Texture.ProxyRect->Image[level]; + texImage = ctx->Texture.ProxyRect->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.ProxyRect->Image[0][level] = texImage; + /* Set the 'back' pointer */ + 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.ProxyRect->Image[level] = texImage; + 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: @@ -757,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: @@ -767,13 +1071,12 @@ _mesa_max_texture_levels(GLcontext *ctx, GLenum target) case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_ARB: case GL_PROXY_TEXTURE_CUBE_MAP_ARB: return ctx->Const.MaxCubeTextureLevels; - break; case GL_TEXTURE_RECTANGLE_NV: case GL_PROXY_TEXTURE_RECTANGLE_NV: return 1; - break; default: return 0; /* bad target */ } @@ -850,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; @@ -865,7 +1172,8 @@ clear_teximage_fields(struct gl_texture_image *img) img->DepthLog2 = 0; img->Data = NULL; img->TexFormat = &_mesa_null_texformat; - img->FetchTexel = NULL; + img->FetchTexelc = NULL; + img->FetchTexelf = NULL; img->IsCompressed = 0; img->CompressedSize = 0; } @@ -875,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. @@ -892,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(internalFormat); - if (img->IsCompressed) - img->CompressedSize = _mesa_compressed_texture_size(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 */ @@ -950,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. @@ -979,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; @@ -989,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; @@ -1002,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; @@ -1026,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; @@ -1042,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. * @@ -1071,8 +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) { @@ -1094,10 +1478,10 @@ texture_error_check( GLcontext *ctx, GLenum target, return GL_TRUE; } - if (width < 1 || height < 1 || depth < 1) { + if (width < 0 || height < 0 || depth < 0) { if (!isProxy) { _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage%dD(width, height or depth < 1)", dimensions); + "glTexImage%dD(width, height or depth < 0)", dimensions); } return GL_TRUE; } @@ -1107,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)" ); @@ -1118,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 && @@ -1131,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) { @@ -1142,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)"); @@ -1155,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)" ); @@ -1170,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, @@ -1190,7 +1574,7 @@ texture_error_check( GLcontext *ctx, GLenum target, } /* Check incoming image format and type */ - if (!_mesa_is_legal_format_and_type(format, type)) { + if (!_mesa_is_legal_format_and_type(ctx, 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. */ @@ -1201,16 +1585,28 @@ texture_error_check( GLcontext *ctx, GLenum target, return GL_TRUE; } - if (format == GL_YCBCR_MESA || internalFormat == GL_YCBCR_MESA) { + /* make sure internal format and format basically agree */ + colorFormat = is_color_format(format); + indexFormat = is_index_format(format); + 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_depthstencil_format(internalFormat) != is_depthstencil_format(format))) { + if (!isProxy) + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTexImage(internalFormat/format)"); + return GL_TRUE; + } + + /* additional checks for ycbcr textures */ + if (internalFormat == GL_YCBCR_MESA) { ASSERT(ctx->Extensions.MESA_ycbcr_texture); - if (format != GL_YCBCR_MESA || - internalFormat != GL_YCBCR_MESA || - (type != GL_UNSIGNED_SHORT_8_8_MESA && - type != GL_UNSIGNED_SHORT_8_8_REV_MESA)) { + if (type != GL_UNSIGNED_SHORT_8_8_MESA && + type != GL_UNSIGNED_SHORT_8_8_REV_MESA) { char message[100]; _mesa_sprintf(message, - "glTexImage%d(format/type/internalFormat YCBCR mismatch", - dimensions); + "glTexImage%d(format/type YCBCR mismatch", dimensions); _mesa_error(ctx, GL_INVALID_ENUM, message); return GL_TRUE; /* error */ } @@ -1234,22 +1630,28 @@ 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) { + /* additional checks for depth textures */ + if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) { + /* 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_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB) { + if (!isProxy) _mesa_error(ctx, GL_INVALID_ENUM, - "glTexImage%d(target)", dimensions); - return GL_TRUE; - } + "glTexImage(target/internalFormat)"); + return GL_TRUE; + } + } + + /* additional checks for compressed textures */ + if (is_compressed_format(ctx, internalFormat)) { + 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) { @@ -1294,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) { @@ -1306,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; } @@ -1357,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); @@ -1398,28 +1823,22 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } } - if (!_mesa_is_legal_format_and_type(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; @@ -1431,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; @@ -1471,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) { @@ -1481,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 || @@ -1488,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 @@ -1538,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; @@ -1561,13 +2014,7 @@ 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(internalFormat)) { + if (is_compressed_format(ctx, internalFormat)) { if (target != GL_TEXTURE_2D) { _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%d(target)", dimensions); @@ -1579,6 +2026,22 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, return GL_TRUE; } } + 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; @@ -1586,7 +2049,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, /** - * 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). @@ -1608,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)" ); @@ -1634,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; } } @@ -1665,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)", @@ -1735,39 +2222,62 @@ 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; } /** - * Get texture image. + * Get texture image. Called by glGetTexImage. * * \param target texture target. * \param level image level. - * \param format pixel data format. - * \param type pixel data type. - * \param pixels pixel data. + * \param format pixel data format for returned image. + * \param type pixel data type for returned image. + * \param pixels returned pixel data. */ -void +void GLAPIENTRY _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; } @@ -1793,98 +2303,115 @@ _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 && format == GL_DEPTH_COMPONENT) { + 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 && format == GL_YCBCR_MESA) { + if (!ctx->Extensions.MESA_ycbcr_texture && is_ycbcr_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - } - - /* XXX what if format/type doesn't match texture format/type? */ - - if (!pixels) - return; - - texImage = _mesa_select_tex_image(ctx, texUnit, target, level); - if (!texImage) { - /* invalid mipmap level, not an error */ return; } - if (!texImage->Data) { - /* no image data, not an error */ + if (!ctx->Extensions.EXT_packed_depth_stencil + && is_depthstencil_format(format)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return; } + _mesa_lock_texture(ctx, texObj); { - const GLint width = texImage->Width; - const GLint height = texImage->Height; - const GLint depth = texImage->Depth; - GLint img, row; - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - /* compute destination address in client memory */ - GLvoid *dest = _mesa_image_address( &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - assert(dest); - - if (format == GL_COLOR_INDEX) { - GLuint indexRow[MAX_WIDTH]; - GLint col; - for (col = 0; col < width; col++) { - (*texImage->FetchTexel)(texImage, col, row, img, - (GLvoid *) &indexRow[col]); - } - _mesa_pack_index_span(ctx, width, type, dest, - indexRow, &ctx->Pack, - 0 /* no image transfer */); - } - else if (format == GL_DEPTH_COMPONENT) { - GLfloat depthRow[MAX_WIDTH]; - GLint col; - for (col = 0; col < width; col++) { - (*texImage->FetchTexel)(texImage, col, row, img, - (GLvoid *) &depthRow[col]); - } - _mesa_pack_depth_span(ctx, width, dest, type, - depthRow, &ctx->Pack); - } - else if (format == GL_YCBCR_MESA) { - /* No pixel transfer */ - const GLint rowstride = texImage->RowStride; - MEMCPY(dest, - (const GLushort *) texImage->Data + row * rowstride, - width * sizeof(GLushort)); - /* check for byte swapping */ - if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR - && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || - (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV - && type == GL_UNSIGNED_SHORT_8_8_MESA)) { - if (!ctx->Pack.SwapBytes) - _mesa_swap2((GLushort *) dest, width); - } - else if (ctx->Pack.SwapBytes) { - _mesa_swap2((GLushort *) dest, width); - } - } - else { - /* general case: convert row to RGBA format */ - GLchan rgba[MAX_WIDTH][4]; - GLint col; - for (col = 0; col < width; col++) { - (*texImage->FetchTexel)(texImage, col, row, img, - (GLvoid *) rgba[col]); - } - _mesa_pack_rgba_span(ctx, width, (const GLchan (*)[4])rgba, - format, type, dest, &ctx->Pack, - 0 /* no image transfer */); - } /* format */ - } /* row */ - } /* img */ + 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); +} + + + +/** + * 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); + } + } } } @@ -1893,7 +2420,7 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, /* * Called from the API. Note that width includes the border. */ -void +void GLAPIENTRY _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ) @@ -1907,53 +2434,58 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, } if (target == GL_TEXTURE_1D) { + /* 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, 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 && !texImage->IsClientData) { - /* free the old texture data */ - MESA_PBUFFER_FREE(texImage->Data); + if (texture_error_check(ctx, target, level, internalFormat, + format, type, 1, postConvWidth, 1, 1, border)) { + return; /* error was recorded */ } - 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); - - /* 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); - if (!texImage->FetchTexel) { - /* If driver didn't explicitly set this, use the default */ - texImage->FetchTexel = texImage->TexFormat->FetchTexel1D; - } - ASSERT(texImage->FetchTexel); - - /* 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, "glTexImage1D"); + 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); + + ASSERT(ctx->Driver.TexImage1D); + + /* 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); + + 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 */ @@ -1982,7 +2514,7 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, } -void +void GLAPIENTRY _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, @@ -2002,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, @@ -2014,49 +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 && !texImage->IsClientData) { - /* free the old texture data */ - MESA_PBUFFER_FREE(texImage->Data); - } - 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); - - 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 (!texImage->FetchTexel) { - /* If driver didn't explicitly set this, use the default */ - texImage->FetchTexel = texImage->TexFormat->FetchTexel2D; - } - ASSERT(texImage->FetchTexel); + _mesa_update_state(ctx); - /* 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); @@ -2065,7 +2605,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, 1, border)) { /* when error, clear all proxy texture image parameters */ if (texImage) - clear_teximage_fields(ctx->Texture.Proxy2D->Image[level]); + clear_teximage_fields(ctx->Texture.Proxy2D->Image[0][level]); } else { /* no error, set the tex image parameters */ @@ -2087,7 +2627,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, * Called by the API or display list executor. * Note that width and height include the border. */ -void +void GLAPIENTRY _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, @@ -2096,54 +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; + 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 */ } - 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 && !texImage->IsClientData) { - MESA_PBUFFER_FREE(texImage->Data); - } - 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); - - 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); - - ASSERT(texImage->TexFormat); - if (!texImage->FetchTexel) { - /* If driver didn't explicitly set this, use the default */ - texImage->FetchTexel = texImage->TexFormat->FetchTexel3D; - } - ASSERT(texImage->FetchTexel); + _mesa_update_state(ctx); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; - } - else if (target == GL_PROXY_TEXTURE_3D) { + 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, "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); + + /* 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); + + 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_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); @@ -2168,7 +2718,7 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, } -void +void GLAPIENTRY _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, @@ -2180,7 +2730,7 @@ _mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat, -void +void GLAPIENTRY _mesa_TexSubImage1D( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, @@ -2189,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); @@ -2202,30 +2752,42 @@ _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 || !pixels) - return; /* no-op, not an error */ + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + 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; + /* 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); } -void +void GLAPIENTRY _mesa_TexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, @@ -2249,32 +2811,42 @@ _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 || !pixels) - 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); } -void +void GLAPIENTRY _mesa_TexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, @@ -2297,29 +2869,39 @@ _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 || !pixels) - 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); } -void +void GLAPIENTRY _mesa_CopyTexImage1D( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, @@ -2329,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); @@ -2345,41 +2928,44 @@ _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 && !texImage->IsClientData) { - /* free the old texture data */ - MESA_PBUFFER_FREE(texImage->Data); - } - 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; + } - clear_teximage_fields(texImage); /* not really needed, but helpful */ - _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1, - border, internalFormat); + 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); - ASSERT(ctx->Driver.CopyTexImage1D); - (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, - x, y, width, border); - ASSERT(texImage->TexFormat); - if (!texImage->FetchTexel) { - /* If driver didn't explicitly set this, use the default */ - texImage->FetchTexel = texImage->TexFormat->FetchTexel1D; - } - ASSERT(texImage->FetchTexel); + ASSERT(ctx->Driver.CopyTexImage1D); + (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat, + x, y, width, border); - /* state update */ - texObj->Complete = GL_FALSE; - ctx->NewState |= _NEW_TEXTURE; + 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); } -void +void GLAPIENTRY _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) @@ -2388,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); @@ -2405,41 +2992,45 @@ _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 && !texImage->IsClientData) { - /* free the old texture data */ - MESA_PBUFFER_FREE(texImage->Data); - } - 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); - if (!texImage->FetchTexel) { - /* If driver didn't explicitly set this, use the default */ - texImage->FetchTexel = texImage->TexFormat->FetchTexel2D; - } - ASSERT(texImage->FetchTexel); + 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); - /* 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); +} -void +void GLAPIENTRY _mesa_CopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) { @@ -2447,6 +3038,9 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, 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); @@ -2462,20 +3056,36 @@ _mesa_CopyTexSubImage1D( 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 we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + 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; + + 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); + } - ASSERT(ctx->Driver.CopyTexSubImage1D); - (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width); - ctx->NewState |= _NEW_TEXTURE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } -void +void GLAPIENTRY _mesa_CopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) @@ -2499,22 +3109,35 @@ _mesa_CopyTexSubImage2D( 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 we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; + _mesa_lock_texture(ctx, texObj); + { + texImage = _mesa_select_tex_image(ctx, texObj, target, level); + + if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0, + postConvWidth, postConvHeight, texImage)) + goto out; + + /* 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); + } - ASSERT(ctx->Driver.CopyTexSubImage2D); - (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level, - xoffset, yoffset, x, y, width, height); - ctx->NewState |= _NEW_TEXTURE; + ctx->NewState |= _NEW_TEXTURE; + } + out: + _mesa_unlock_texture(ctx, texObj); } -void +void GLAPIENTRY _mesa_CopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) @@ -2538,19 +3161,33 @@ _mesa_CopyTexSubImage3D( 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 we have a border, xoffset=-1 is legal. Bias by border width */ - xoffset += texImage->Border; - yoffset += texImage->Border; - zoffset += texImage->Border; + _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 (_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); } @@ -2572,7 +3209,6 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize) { - GLboolean isProxy = GL_FALSE; GLint expectedSize, maxLevels = 0, maxTextureSize; if (dimensions == 1) { @@ -2582,7 +3218,6 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, 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; @@ -2591,7 +3226,6 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, 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) { @@ -2610,7 +3244,12 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, maxTextureSize = 1 << (maxLevels - 1); - if (!is_compressed_format(internalFormat)) + /* 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; if (border != 0) @@ -2620,16 +3259,16 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, * XXX We should probably use the proxy texture error check function here. */ if (width < 1 || width > maxTextureSize || - (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(width) < 0)) + (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(width) != 1)) return GL_INVALID_VALUE; if ((height < 1 || height > maxTextureSize || - (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(height) < 0)) + (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(height) != 1)) && dimensions > 1) return GL_INVALID_VALUE; if ((depth < 1 || depth > maxTextureSize || - (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(depth) < 0)) + (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(depth) != 1)) && dimensions > 2) return GL_INVALID_VALUE; @@ -2641,17 +3280,30 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions, if (level < 0 || level >= maxLevels) return GL_INVALID_VALUE; - expectedSize = _mesa_compressed_texture_size(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; } /** * Error checking for glCompressedTexSubImage[123]D(). + * \warning There are some bad assumptions here about the size of compressed + * texture tiles (multiple of 4) used to test the validity of the + * offset and size parameters. * \return error code or GL_NO_ERROR. */ static GLenum @@ -2661,8 +3313,8 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize) { - GLboolean isProxy = GL_FALSE; GLint expectedSize, maxLevels = 0, maxTextureSize; + (void) zoffset; if (dimensions == 1) { /* 1D compressed textures not allowed */ @@ -2671,7 +3323,6 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, 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; @@ -2680,7 +3331,6 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, 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) { @@ -2699,7 +3349,8 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, maxTextureSize = 1 << (maxLevels - 1); - if (!is_compressed_format(format)) + /* this will catch any invalid compressed format token */ + if (!is_compressed_format(ctx, format)) return GL_INVALID_ENUM; if (width < 1 || width > maxTextureSize) @@ -2712,6 +3363,9 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, if (level < 0 || level >= maxLevels) return GL_INVALID_VALUE; + /* XXX these tests are specific to the compressed format. + * this code should be generalized in some way. + */ if ((xoffset & 3) != 0 || (yoffset & 3) != 0) return GL_INVALID_VALUE; @@ -2721,8 +3375,8 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, if ((height & 3) != 0 && height != 2 && height != 1) return GL_INVALID_VALUE; - expectedSize = _mesa_compressed_texture_size(ctx, width, height, depth, - format); + expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height, + depth, format); if (expectedSize != imageSize) return GL_INVALID_VALUE; @@ -2731,7 +3385,7 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions, -void +void GLAPIENTRY _mesa_CompressedTexImage1DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, @@ -2741,6 +3395,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (target == GL_TEXTURE_1D) { + /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; @@ -2753,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 && !texImage->IsClientData) { - MESA_PBUFFER_FREE(texImage->Data); - } - texImage->Data = NULL; - _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, - border, internalFormat); - - 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; + _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); + + _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1, + border, internalFormat); + + 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 */ @@ -2796,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 { @@ -2810,7 +3479,7 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, } -void +void GLAPIENTRY _mesa_CompressedTexImage2DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, @@ -2823,6 +3492,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, (ctx->Extensions.ARB_texture_cube_map && target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { + /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; @@ -2835,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 && !texImage->IsClientData) { - MESA_PBUFFER_FREE(texImage->Data); - } - texImage->Data = NULL; - _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, - border, internalFormat); - - 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; + _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); + + _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1, + border, internalFormat); + + 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 && @@ -2880,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 { @@ -2894,7 +3578,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, } -void +void GLAPIENTRY _mesa_CompressedTexImage3DARB(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, @@ -2904,6 +3588,7 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (target == GL_TEXTURE_3D) { + /* non-proxy target */ struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; @@ -2916,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 && !texImage->IsClientData) { - MESA_PBUFFER_FREE(texImage->Data); - } - texImage->Data = NULL; - - _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, - border, internalFormat); - - 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; + _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); + + _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth, + border, internalFormat); + + 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 */ @@ -2960,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 { @@ -2974,7 +3671,7 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, } -void +void GLAPIENTRY _mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data) @@ -2987,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; @@ -2995,34 +3694,39 @@ _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 || !data) - 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); } -void +void GLAPIENTRY _mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, @@ -3036,43 +3740,51 @@ _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"); 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, - "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 || !data) - 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); } -void +void GLAPIENTRY _mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, @@ -3086,49 +3798,56 @@ _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 || !data) - 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); } -void +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); @@ -3149,26 +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)"); + } } - - if (!img) - return; - - /* just memcpy, no pixelstore or pixel transfer */ - MEMCPY(img, texImage->Data, texImage->CompressedSize); + _mesa_unlock_texture(ctx, texObj); }