X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fteximage.c;h=4a6258e89b22aed92439fdc7e48dd0d987a386ee;hb=a96308c37db0bc0086a017d318bc3504aa5f0b1a;hp=e643bfd60a3d86183c045b24aef94634f044de6a;hpb=f93b3dd69e744cf1dd6b102a11cdb07c2df4a967;p=mesa.git diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index e643bfd60a3..4a6258e89b2 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -1,8 +1,8 @@ -/* $Id: teximage.c,v 1.42 2000/08/30 18:22:28 brianp Exp $ */ +/* $Id: teximage.c,v 1.56 2000/10/30 13:32:01 keithw Exp $ */ /* * Mesa 3-D graphics library - * Version: 3.4 + * Version: 3.5 * * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. * @@ -32,6 +32,7 @@ #include "context.h" #include "convolve.h" #include "image.h" +#include "macros.h" #include "mem.h" #include "mmath.h" #include "span.h" @@ -45,7 +46,7 @@ /* * NOTES: * - * Mesa's native texture datatype is GLubyte. Native formats are + * Mesa's native texture datatype is GLchan. Native formats are * GL_ALPHA, GL_LUMINANCE, GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, GL_RGBA, * and GL_COLOR_INDEX. * Device drivers are free to implement any internal format they want. @@ -56,7 +57,7 @@ static void PrintTexture(const struct gl_texture_image *img) { int i, j, c; - GLubyte *data = img->Data; + GLchan *data = img->Data; if (!data) { printf("No texture data\n"); @@ -538,7 +539,7 @@ _mesa_compressed_image_size(GLcontext *ctx, * texture object. */ struct gl_texture_object * -_mesa_select_tex_object(GLcontext *ctx, struct gl_texture_unit *texUnit, +_mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit, GLenum target) { switch (target) { @@ -560,10 +561,10 @@ _mesa_select_tex_object(GLcontext *ctx, struct gl_texture_unit *texUnit, case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - return ctx->Extensions.HaveTextureCubeMap + return ctx->Extensions.ARB_texture_cube_map ? texUnit->CurrentCubeMap : NULL; case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - return ctx->Extensions.HaveTextureCubeMap + return ctx->Extensions.ARB_texture_cube_map ? ctx->Texture.ProxyCubeMap : NULL; default: gl_problem(NULL, "bad target in _mesa_select_tex_object()"); @@ -595,37 +596,37 @@ _mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_unit *texUnit, case GL_PROXY_TEXTURE_3D: return ctx->Texture.Proxy3D->Image[level]; case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - if (ctx->Extensions.HaveTextureCubeMap) + 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.HaveTextureCubeMap) + 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.HaveTextureCubeMap) + 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.HaveTextureCubeMap) + 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.HaveTextureCubeMap) + 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.HaveTextureCubeMap) + if (ctx->Extensions.ARB_texture_cube_map) return texUnit->CurrentCubeMap->NegZ[level]; else return NULL; case GL_PROXY_TEXTURE_CUBE_MAP_ARB: - if (ctx->Extensions.HaveTextureCubeMap) + if (ctx->Extensions.ARB_texture_cube_map) return ctx->Texture.ProxyCubeMap->Image[level]; else return NULL; @@ -670,208 +671,189 @@ adjust_texture_size_for_convolution(const GLcontext *ctx, GLuint dimensions, -/* Need this to prevent an out-of-bounds memory access when using - * X86 optimized code. - */ -#ifdef USE_X86_ASM -# define EXTRA_BYTE 1 -#else -# define EXTRA_BYTE 0 -#endif - - - /* - * Called by glTexImage[123]D. Fill in a texture image with data given - * by the client. All pixel transfer and unpack modes are handled here. - * NOTE: All texture image parameters should have already been error checked. + * This function is used to move user image data into a texture image. + * We handle full texture images and subtexture images. We also take + * care of all image transfer operations here, including convolution. + * Input: + * dstXoffset, dstYoffset, dstZoffset - offsets in pixels + * dstRowStride, dstImageStride - strides in GLchan's */ static void -make_texture_image( GLcontext *ctx, GLuint dimensions, - struct gl_texture_image *texImage, - GLenum srcFormat, GLenum srcType, const GLvoid *pixels, +fill_texture_image( GLcontext *ctx, GLuint dimensions, + GLenum texFormat, GLchan *texAddr, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLenum srcFormat, GLenum srcType, const GLvoid *srcAddr, const struct gl_pixelstore_attrib *srcPacking) { - GLint components, numPixels; - GLint internalFormat, width, height, depth, border; + GLint texComponents; ASSERT(ctx); - ASSERT(texImage); - ASSERT(!texImage->Data); - ASSERT(pixels); + ASSERT(dimensions >= 1 && dimensions <= 3); + ASSERT(texAddr); + ASSERT(srcWidth >= 1); + ASSERT(srcHeight >= 1); + ASSERT(srcDepth >= 1); + ASSERT(dstXoffset >= 0); + ASSERT(dstYoffset >= 0); + ASSERT(dstZoffset >= 0); + ASSERT(dstRowStride >= 0); + ASSERT(dstImageStride >= 0); + ASSERT(srcAddr); ASSERT(srcPacking); - internalFormat = texImage->IntFormat; - width = texImage->Width; - height = texImage->Height; - depth = texImage->Depth; - border = texImage->Border; - components = components_in_intformat(internalFormat); - - ASSERT(width > 0); - ASSERT(height > 0); - ASSERT(depth > 0); - ASSERT(border == 0 || border == 1); - ASSERT(components); - - numPixels = width * height * depth; - - texImage->Data = (GLubyte *) MALLOC(numPixels * components + EXTRA_BYTE); - if (!texImage->Data) - return; /* out of memory */ - - /* - * OK, the texture image struct has been initialized and the texture - * image memory has been allocated. - * Now fill in the texture image from the source data. - * This includes applying the pixel transfer operations. - */ - - if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) - _mesa_update_image_transfer_state(ctx); + texComponents = components_in_intformat(texFormat); /* try common 2D texture cases first */ - if (!ctx->ImageTransferState && srcType == GL_UNSIGNED_BYTE && depth == 1) { + if (!ctx->ImageTransferState && dimensions == 2 + && srcType == GL_UNSIGNED_BYTE) { - if (srcFormat == internalFormat || - (srcFormat == GL_LUMINANCE && internalFormat == 1) || - (srcFormat == GL_LUMINANCE_ALPHA && internalFormat == 2) || - (srcFormat == GL_RGB && internalFormat == 3) || - (srcFormat == GL_RGBA && internalFormat == 4)) { + if (srcFormat == texFormat) { /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA, - * GL_LUMINANCE_ALPHA, etc. texture formats. + * GL_LUMINANCE_ALPHA, etc. texture formats. Use memcpy(). */ - const GLubyte *src = (const GLubyte *) _mesa_image_address( - srcPacking, pixels, width, height, srcFormat, srcType, 0, 0, 0); - const GLint srcStride = _mesa_image_row_stride(srcPacking, width, - srcFormat, srcType); - GLubyte *dst = texImage->Data; - GLint dstBytesPerRow = width * components * sizeof(GLubyte); - if (srcStride == dstBytesPerRow) { - MEMCPY(dst, src, height * dstBytesPerRow); + const GLchan *src = (const GLchan *) _mesa_image_address( + srcPacking, srcAddr, srcWidth, srcHeight, + srcFormat, srcType, 0, 0, 0); + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + const GLint widthInBytes = srcWidth * texComponents * sizeof(GLchan); + GLchan *dst = texAddr + dstYoffset * dstRowStride + + dstXoffset * texComponents; + if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) { + MEMCPY(dst, src, srcHeight * widthInBytes); } else { GLint i; - for (i = 0; i < height; i++) { - MEMCPY(dst, src, dstBytesPerRow); - src += srcStride; - dst += dstBytesPerRow; + for (i = 0; i < srcHeight; i++) { + MEMCPY(dst, src, widthInBytes); + src += srcRowStride; + dst += dstRowStride; } } return; /* all done */ } - else if (srcFormat == GL_RGBA && internalFormat == GL_RGB) { + else if (srcFormat == GL_RGBA && texFormat == GL_RGB) { /* commonly used by Quake */ - const GLubyte *src = (const GLubyte *) _mesa_image_address( - srcPacking, pixels, width, height, srcFormat, srcType, 0, 0, 0); - const GLint srcStride = _mesa_image_row_stride(srcPacking, width, - srcFormat, srcType); - GLubyte *dst = texImage->Data; + const GLchan *src = (const GLchan *) _mesa_image_address( + srcPacking, srcAddr, srcWidth, srcHeight, + srcFormat, srcType, 0, 0, 0); + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLchan *dst = texAddr + dstYoffset * dstRowStride + + dstXoffset * texComponents; GLint i, j; - for (i = 0; i < height; i++) { - const GLubyte *s = src; - for (j = 0; j < width; j++) { - *dst++ = *s++; /*red*/ - *dst++ = *s++; /*green*/ - *dst++ = *s++; /*blue*/ - s++; /*alpha*/ + for (i = 0; i < srcHeight; i++) { + const GLchan *s = src; + GLchan *d = dst; + for (j = 0; j < srcWidth; j++) { + *d++ = *s++; /*red*/ + *d++ = *s++; /*green*/ + *d++ = *s++; /*blue*/ + s++; /*alpha*/ } - src += srcStride; + src += srcRowStride; + dst += dstRowStride; } return; /* all done */ } } - /* * General case solutions */ - if (texImage->Format == GL_COLOR_INDEX) { + if (texFormat == GL_COLOR_INDEX) { /* color index texture */ - const GLint destBytesPerRow = width * components * sizeof(GLubyte); - const GLenum dstType = GL_UNSIGNED_BYTE; - GLubyte *dest = texImage->Data; + const GLenum texType = GL_UNSIGNED_BYTE; GLint img, row; - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - const GLvoid *srcAddr = _mesa_image_address(srcPacking, - pixels, width, height, srcFormat, srcType, img, row, 0); - _mesa_unpack_index_span(ctx, width, dstType, dest, - srcType, srcAddr, srcPacking, + GLchan *dest = texAddr + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * texComponents; + for (img = 0; img < srcDepth; img++) { + GLchan *destRow = dest; + for (row = 0; row < srcHeight; row++) { + const GLvoid *src = _mesa_image_address(srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0); + _mesa_unpack_index_span(ctx, srcWidth, texType, destRow, + srcType, src, srcPacking, ctx->ImageTransferState); - dest += destBytesPerRow; + destRow += dstRowStride; } + dest += dstImageStride; } } else { /* regular, color texture */ - const GLint destBytesPerRow = width * components * sizeof(GLubyte); - const GLenum dstFormat = texImage->Format; - GLubyte *dest = texImage->Data; - GLint img, row; - GLint w = width, h = height; - if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) || - (dimensions >= 2 && - (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) - )) { + (dimensions >= 2 && ctx->Pixel.Convolution2DEnabled) || + (dimensions >= 2 && ctx->Pixel.Separable2DEnabled)) { + /* + * Fill texture image with convolution + */ + GLint img, row; + GLint convWidth = srcWidth, convHeight = srcHeight; GLfloat *tmpImage, *convImage; - tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); + tmpImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat)); if (!tmpImage) { gl_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return; } - convImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); + convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat)); if (!convImage) { gl_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); FREE(tmpImage); return; } - for (img = 0; img < depth; img++) { + for (img = 0; img < srcDepth; img++) { const GLfloat *srcf; GLfloat *dstf = tmpImage; + GLchan *dest; + /* unpack and do transfer ops up to convolution */ - for (row = 0; row < height; row++) { - const GLvoid *srcAddr = _mesa_image_address(srcPacking, - pixels, width, height, srcFormat, srcType, img, row, 0); - _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dstf, - srcFormat, srcType, srcAddr, srcPacking, - ctx->ImageTransferState & IMAGE_PRE_CONVOLUTION_BITS, - GL_TRUE); - dstf += width * 4; + for (row = 0; row < srcHeight; row++) { + const GLvoid *src = _mesa_image_address(srcPacking, + srcAddr, srcWidth, srcHeight, + srcFormat, srcType, img, row, 0); + _mesa_unpack_float_color_span(ctx, srcWidth, GL_RGBA, dstf, + srcFormat, srcType, src, srcPacking, + ctx->ImageTransferState & IMAGE_PRE_CONVOLUTION_BITS, + GL_TRUE); + dstf += srcWidth * 4; } /* convolve */ if (dimensions == 1) { - if (ctx->Pixel.Convolution1DEnabled) { - _mesa_convolve_1d_image(ctx, &w, tmpImage, convImage); - } + ASSERT(ctx->Pixel.Convolution1DEnabled); + _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage); } else { if (ctx->Pixel.Convolution2DEnabled) { - _mesa_convolve_2d_image(ctx, &w, &h, tmpImage, convImage); + _mesa_convolve_2d_image(ctx, &convWidth, &convHeight, + tmpImage, convImage); } else { ASSERT(ctx->Pixel.Separable2DEnabled); - _mesa_convolve_sep_image(ctx, &w, &h, tmpImage, convImage); + _mesa_convolve_sep_image(ctx, &convWidth, &convHeight, + tmpImage, convImage); } } - /* transfer ops after convolution */ + /* packing and transfer ops after convolution */ srcf = convImage; - for (row = 0; row < h; row++) { - GLvoid *dest; - dest = _mesa_image_address(&_mesa_native_packing, pixels, - w, h, GL_RGBA, GL_UNSIGNED_BYTE, - 0, row, 0); - _mesa_pack_float_rgba_span(ctx, w, + dest = texAddr + (dstZoffset + img) * dstImageStride + + dstYoffset * dstRowStride; + for (row = 0; row < convHeight; row++) { + _mesa_pack_float_rgba_span(ctx, convWidth, (const GLfloat (*)[4]) srcf, - dstFormat, GL_UNSIGNED_BYTE, + texFormat, GL_UNSIGNED_BYTE, dest, &_mesa_native_packing, ctx->ImageTransferState & IMAGE_POST_CONVOLUTION_BITS); - srcf += w * 4; + srcf += convWidth * 4; + dest += dstRowStride; } } @@ -879,16 +861,25 @@ make_texture_image( GLcontext *ctx, GLuint dimensions, FREE(tmpImage); } else { - /* no convolution */ - for (img = 0; img < depth; img++) { - for (row = 0; row < height; row++) { - const GLvoid *srcAddr = _mesa_image_address(srcPacking, - pixels, width, height, srcFormat, srcType, img, row, 0); - _mesa_unpack_ubyte_color_span(ctx, width, dstFormat, dest, - srcFormat, srcType, srcAddr, srcPacking, - ctx->ImageTransferState); - dest += destBytesPerRow; + /* + * no convolution + */ + GLint img, row; + GLchan *dest = texAddr + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * texComponents; + for (img = 0; img < srcDepth; img++) { + GLchan *destRow = dest; + for (row = 0; row < srcHeight; row++) { + const GLvoid *srcRow = _mesa_image_address(srcPacking, + srcAddr, srcWidth, srcHeight, + srcFormat, srcType, img, row, 0); + _mesa_unpack_chan_color_span(ctx, srcWidth, texFormat, destRow, + srcFormat, srcType, srcRow, srcPacking, + ctx->ImageTransferState); + destRow += dstRowStride; } + dest += dstImageStride; } } } @@ -896,6 +887,66 @@ make_texture_image( GLcontext *ctx, GLuint dimensions, +/* Need this to prevent an out-of-bounds memory access when using + * X86 optimized code. + */ +#ifdef USE_X86_ASM +# define EXTRA_BYTE sizeof(GLchan) +#else +# define EXTRA_BYTE 0 +#endif + + + +/* + * Called by glTexImage[123]D. Fill in a texture image with data given + * by the client. All pixel transfer and unpack modes are handled here. + * Input: dimensions (1, 2, or 3) + * texImage - destination texture image (we'll malloc the memory) + * width, height, depth - size of source image + * srcFormat, srcType - source image format and type + * pixels - source image data + * srcPacking - source image packing parameters + * + * NOTE: All texture image parameters should have already been error checked. + * + * NOTE: the texImage dimensions and source image dimensions must be correct + * with respect to convolution with border mode = reduce. + */ +static void +make_texture_image( GLcontext *ctx, GLuint dimensions, + struct gl_texture_image *texImage, + GLint width, GLint height, GLint depth, + GLenum srcFormat, GLenum srcType, const GLvoid *pixels, + const struct gl_pixelstore_attrib *srcPacking) +{ + const GLint internalFormat = texImage->IntFormat; + const GLint components = components_in_intformat(internalFormat); + GLint convWidth = width, convHeight = height; + + if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) { + _mesa_update_image_transfer_state(ctx); + } + + if (ctx->ImageTransferState & IMAGE_CONVOLUTION_BIT) { + adjust_texture_size_for_convolution(ctx, dimensions, + &convWidth, &convHeight); + } + + texImage->Data = (GLchan *) MALLOC(convWidth * convHeight * depth + * components * sizeof(GLchan) + EXTRA_BYTE); + if (!texImage->Data) + return; /* out of memory */ + + fill_texture_image(ctx, dimensions, texImage->Format, texImage->Data, + width, height, depth, 0, 0, 0, + convWidth * components * sizeof(GLchan), + convWidth * convHeight * components * sizeof(GLchan), + srcFormat, srcType, pixels, srcPacking); +} + + + /* * glTexImage[123]D can accept a NULL image pointer. In this case we * create a texture image with unspecified image contents per the OpenGL @@ -913,7 +964,8 @@ make_null_texture( struct gl_texture_image *texImage ) components = components_in_intformat(texImage->IntFormat); numPixels = texImage->Width * texImage->Height * texImage->Depth; - texImage->Data = (GLubyte *) MALLOC( numPixels * components + EXTRA_BYTE ); + texImage->Data = (GLchan *) MALLOC( numPixels * components * sizeof(GLchan) + + EXTRA_BYTE ); /* * Let's see if anyone finds this. If glTexImage2D() is called with @@ -932,15 +984,15 @@ make_null_texture( struct gl_texture_image *texImage ) " " }; - GLubyte *imgPtr = texImage->Data; + GLchan *imgPtr = texImage->Data; GLint i, j, k; for (i = 0; i < texImage->Height; i++) { GLint srcRow = 7 - i % 8; for (j = 0; j < texImage->Width; j++) { GLint srcCol = j % 32; - GLint texel = (message[srcRow][srcCol]=='X') ? 255 : 70; + GLint texel = (message[srcRow][srcCol]=='X') ? CHAN_MAX : 70; for (k=0;kFormat = 0; + img->IntFormat = 0; + img->RedBits = 0; + img->GreenBits = 0; + img->BlueBits = 0; + img->AlphaBits = 0; + img->IntensityBits = 0; + img->LuminanceBits = 0; + img->IndexBits = 0; + img->Border = 0; + img->Width = 0; + img->Height = 0; + img->Depth = 0; + img->Width2 = 0; + img->Height2 = 0; + img->Depth2 = 0; + img->WidthLog2 = 0; + img->HeightLog2 = 0; + img->DepthLog2 = 0; + img->Data = NULL; + img->IsCompressed = 0; + img->CompressedSize = 0; +} + + + /* * Test glTexImage[123]D() parameters for errors. * Input: @@ -976,7 +1062,7 @@ texture_error_check( GLcontext *ctx, GLenum target, else if (dimensions == 2) { isProxy = (GLboolean) (target == GL_PROXY_TEXTURE_2D); if (target != GL_TEXTURE_2D && !isProxy && - !(ctx->Extensions.HaveTextureCubeMap && + !(ctx->Extensions.ARB_texture_cube_map && target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { gl_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" ); @@ -1114,7 +1200,7 @@ subtexture_error_check( GLcontext *ctx, GLuint dimensions, } } else if (dimensions == 2) { - if (ctx->Extensions.HaveTextureCubeMap) { + if (ctx->Extensions.ARB_texture_cube_map) { if ((target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) && target != GL_TEXTURE_2D) { @@ -1229,7 +1315,7 @@ copytexture_error_check( GLcontext *ctx, GLuint dimensions, } } else if (dimensions == 2) { - if (ctx->Extensions.HaveTextureCubeMap) { + if (ctx->Extensions.ARB_texture_cube_map) { if ((target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) && target != GL_TEXTURE_2D) { @@ -1317,7 +1403,7 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, } } else if (dimensions == 2) { - if (ctx->Extensions.HaveTextureCubeMap) { + if (ctx->Extensions.ARB_texture_cube_map) { if ((target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) && target != GL_TEXTURE_2D) { @@ -1423,31 +1509,30 @@ copytexsubimage_error_check( GLcontext *ctx, GLuint dimensions, */ static GLint get_specific_compressed_tex_format(GLcontext *ctx, - GLint ifmt, GLint numDimensions) + GLint ifmt, GLint numDimensions, + GLint *levelp, + GLsizei *widthp, + GLsizei *heightp, + GLsizei *depthp, + GLint *borderp, + GLenum *formatp, + GLenum *typep) { char message[100]; GLint internalFormat = ifmt; - if (ctx->Extensions.HaveTextureCompression + if (ctx->Extensions.ARB_texture_compression && ctx->Driver.SpecificCompressedTexFormat) { /* * First, ask the driver for the specific format. + * We do this for all formats, since we may want to + * fake one compressed format for another. */ - switch (internalFormat) { - case GL_COMPRESSED_ALPHA_ARB: - case GL_COMPRESSED_LUMINANCE_ARB: - case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: - case GL_COMPRESSED_INTENSITY_ARB: - case GL_COMPRESSED_RGB_ARB: - case GL_COMPRESSED_RGBA_ARB: - internalFormat = (*ctx->Driver.SpecificCompressedTexFormat) - (ctx, internalFormat, numDimensions); - /* XXX shouldn't we return now? */ - break; - default: - /* silence compiler warnings */ - ; - } + internalFormat = (*ctx->Driver.SpecificCompressedTexFormat) + (ctx, internalFormat, numDimensions, + levelp, + widthp, heightp, depthp, + borderp, formatp, typep); } /* @@ -1458,7 +1543,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, */ switch (internalFormat) { case GL_COMPRESSED_ALPHA_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1466,7 +1551,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, internalFormat = GL_ALPHA; break; case GL_COMPRESSED_LUMINANCE_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1474,7 +1559,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, internalFormat = GL_LUMINANCE; break; case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1482,7 +1567,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, internalFormat = GL_LUMINANCE_ALPHA; break; case GL_COMPRESSED_INTENSITY_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1490,7 +1575,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, internalFormat = GL_INTENSITY; break; case GL_COMPRESSED_RGB_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1498,7 +1583,7 @@ get_specific_compressed_tex_format(GLcontext *ctx, internalFormat = GL_RGB; break; case GL_COMPRESSED_RGBA_ARB: - if (ctx && !ctx->Extensions.HaveTextureCompression) { + if (ctx && !ctx->Extensions.ARB_texture_compression) { sprintf(message, "glTexImage%dD(internalFormat)", numDimensions); gl_error(ctx, GL_INVALID_VALUE, message); return -1; @@ -1513,7 +1598,6 @@ get_specific_compressed_tex_format(GLcontext *ctx, } - /* * Called from the API. Note that width includes the border. */ @@ -1535,7 +1619,10 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_image *texImage; GLint ifmt; - ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 1); + ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 1, + &level, + &width, 0, 0, + &border, &format, &type); if (ifmt < 0) { /* * The error here is that we were sent a generic compressed @@ -1587,8 +1674,8 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, } if (retain || !success) { /* make internal copy of the texture image */ - make_texture_image(ctx, 1, texImage, format, type, - pixels, &ctx->Unpack); + make_texture_image(ctx, 1, texImage, width, 1, 1, + format, type, pixels, &ctx->Unpack); if (!success && ctx->Driver.TexImage1D) { /* let device driver try to use unpacked image */ (*ctx->Driver.TexImage1D)( ctx, target, level, texImage->Format, @@ -1615,16 +1702,21 @@ _mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } - else if (target==GL_PROXY_TEXTURE_1D) { + else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - format, type, 1, postConvWidth, 1, 1, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + format, type, 1, width, 1, 1, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, format, type, + width, 1, 1, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy1D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy1D->Image[level]); } } else { @@ -1655,7 +1747,7 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, adjust_texture_size_for_convolution(ctx, 2, &postConvWidth,&postConvHeight); if (target==GL_TEXTURE_2D || - (ctx->Extensions.HaveTextureCubeMap && + (ctx->Extensions.ARB_texture_cube_map && target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { struct gl_texture_unit *texUnit; @@ -1663,7 +1755,10 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_image *texImage; GLint ifmt; - ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 2); + ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 2, + &level, + &width, &height, 0, + &border, &format, &type); if (ifmt < 0) { /* * The error here is that we were sent a generic compressed @@ -1718,8 +1813,8 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, } if (retain || !success) { /* make internal copy of the texture image */ - make_texture_image(ctx, 2, texImage, format, type, - pixels, &ctx->Unpack); + make_texture_image(ctx, 2, texImage, width, height, 1, + format, type, pixels, &ctx->Unpack); if (!success && ctx->Driver.TexImage2D) { /* let device driver try to use unpacked image */ (*ctx->Driver.TexImage2D)( ctx, target, level, texImage->Format, @@ -1755,16 +1850,21 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } - else if (target==GL_PROXY_TEXTURE_2D) { + else if (target == GL_PROXY_TEXTURE_2D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - format, type, 2, postConvWidth, height, 1, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + format, type, 2, width, height, 1, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, format, type, + width, height, 1, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy2D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy2D->Image[level]); } } else { @@ -1781,7 +1881,6 @@ _mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat, } - /* * Called by the API or display list executor. * Note that width and height include the border. @@ -1801,7 +1900,10 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, struct gl_texture_image *texImage; GLint ifmt; - ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 3); + ifmt = get_specific_compressed_tex_format(ctx, internalFormat, 3, + &level, + &width, &height, &depth, + &border, &format, &type); if (ifmt < 0) { /* * The error here is that we were sent a generic compressed @@ -1854,8 +1956,8 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, } if (retain || !success) { /* make internal copy of the texture image */ - make_texture_image(ctx, 3, texImage, format, type, - pixels, &ctx->Unpack); + make_texture_image(ctx, 3, texImage, width, height, depth, + format, type, pixels, &ctx->Unpack); if (!success && ctx->Driver.TexImage3D) { /* let device driver try to use unpacked image */ (*ctx->Driver.TexImage3D)( ctx, target, level, texImage->Format, @@ -1882,16 +1984,21 @@ _mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } - else if (target==GL_PROXY_TEXTURE_3D) { + else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - format, type, 3, width, height, depth, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + format, type, 3, width, height, depth, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, format, type, + width, height, depth, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy3D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy3D->Image[level]); } } else { @@ -1954,7 +2061,8 @@ _mesa_get_teximage_from_driver( GLcontext *ctx, GLenum target, GLint level, if (!texImage->Data) { /* Allocate memory for the texture image data */ - texImage->Data = (GLubyte *) MALLOC(numPixels * destComponents + EXTRA_BYTE); + texImage->Data = (GLchan *) MALLOC(numPixels * destComponents + * sizeof(GLchan) + EXTRA_BYTE); } if (imgFormat == texImage->Format && imgType == GL_UNSIGNED_BYTE) { @@ -1974,8 +2082,8 @@ _mesa_get_teximage_from_driver( GLcontext *ctx, GLenum target, GLint level, const GLint srcBytesPerRow = width * srcBytesPerTexel; const GLenum dstType = GL_UNSIGNED_BYTE; const GLenum dstFormat = texImage->Format; - const GLubyte *srcPtr = (const GLubyte *) image; - GLubyte *destPtr = texImage->Data; + const GLchan *srcPtr = (const GLchan *) image; + GLchan *destPtr = texImage->Data; if (texImage->Format == GL_COLOR_INDEX) { /* color index texture */ @@ -1995,7 +2103,7 @@ _mesa_get_teximage_from_driver( GLcontext *ctx, GLenum target, GLint level, GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { - _mesa_unpack_ubyte_color_span(ctx, width, dstFormat, destPtr, + _mesa_unpack_chan_color_span(ctx, width, dstFormat, destPtr, imgFormat, imgType, srcPtr, &_mesa_native_packing, GL_FALSE); destPtr += destBytesPerRow; srcPtr += srcBytesPerRow; @@ -2009,11 +2117,62 @@ _mesa_get_teximage_from_driver( GLcontext *ctx, GLenum target, GLint level, } +/* + * Get all the mipmap images for a texture object from the device driver. + * Actually, only get mipmap images if we're using a mipmap filter. + */ +GLboolean +_mesa_get_teximages_from_driver(GLcontext *ctx, + struct gl_texture_object *texObj) +{ + if (ctx->Driver.GetTexImage) { + static const GLenum targets[] = { + GL_TEXTURE_1D, + GL_TEXTURE_2D, + GL_TEXTURE_3D, + GL_TEXTURE_CUBE_MAP_ARB, + GL_TEXTURE_CUBE_MAP_ARB, + GL_TEXTURE_CUBE_MAP_ARB + }; + GLboolean needLambda = (texObj->MinFilter != texObj->MagFilter); + GLenum target = targets[texObj->Dimensions - 1]; + if (needLambda) { + GLint level; + /* Get images for all mipmap levels. We might not need them + * all but this is easier. We're on a (slow) software path + * anyway. + */ + for (level = 0; level <= texObj->P; level++) { + struct gl_texture_image *texImg = texObj->Image[level]; + if (texImg && !texImg->Data) { + _mesa_get_teximage_from_driver(ctx, target, level, texObj); + if (!texImg->Data) + return GL_FALSE; /* out of memory */ + } + } + } + else { + GLint level = texObj->BaseLevel; + struct gl_texture_image *texImg = texObj->Image[level]; + if (texImg && !texImg->Data) { + _mesa_get_teximage_from_driver(ctx, target, level, texObj); + if (!texImg->Data) + return GL_FALSE; /* out of memory */ + } + } + return GL_TRUE; + } + return GL_FALSE; +} + + + void _mesa_GetTexImage( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { GET_CURRENT_CONTEXT(ctx); + const struct gl_texture_unit *texUnit; const struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLboolean discardImage; @@ -2038,46 +2197,15 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, if (!pixels) return; - switch (target) { - case GL_TEXTURE_1D: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[1]; - texImage = texObj->Image[level]; - break; - case GL_TEXTURE_2D: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[2]; - texImage = texObj->Image[level]; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->Image[level]; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->NegX[level]; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->PosY[level]; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->NegY[level]; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->PosZ[level]; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentCubeMap; - texImage = texObj->NegZ[level]; - break; - case GL_TEXTURE_3D: - texObj = ctx->Texture.Unit[ctx->Texture.CurrentUnit].CurrentD[3]; - texImage = texObj->Image[level]; - break; - default: - gl_error( ctx, GL_INVALID_ENUM, "glGetTexImage(target)" ); - 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); + if (!texObj || !texImage || + target == GL_PROXY_TEXTURE_1D || + target == GL_PROXY_TEXTURE_2D || + target == GL_PROXY_TEXTURE_3D) { + gl_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); + return; } if (!texImage) { @@ -2097,92 +2225,161 @@ _mesa_GetTexImage( GLenum target, GLint level, GLenum format, if (texImage->Data) { GLint width = texImage->Width; GLint height = texImage->Height; - GLint row; + GLint depth = texImage->Depth; + GLint img, row; if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) _mesa_update_image_transfer_state(ctx); - for (row = 0; row < height; row++) { - /* compute destination address in client memory */ - GLvoid *dest = _mesa_image_address( &ctx->Unpack, pixels, - width, height, - format, type, 0, row, 0); + if (ctx->ImageTransferState & IMAGE_CONVOLUTION_BIT) { + /* convert texture image to GL_RGBA, GL_FLOAT */ + GLfloat *tmpImage, *convImage; + const GLint comps = components_in_intformat(texImage->Format); - assert(dest); - if (texImage->Format == GL_RGBA) { - const GLubyte *src = texImage->Data + row * width * 4 * sizeof(GLubyte); - /* XXX convolution */ - _mesa_pack_rgba_span( ctx, width, (CONST GLubyte (*)[4]) src, - format, type, dest, &ctx->Pack, - ctx->ImageTransferState ); + tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); + if (!tmpImage) { + gl_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; } - else { - /* fetch RGBA row from texture image then pack it in client mem */ - GLubyte rgba[MAX_WIDTH][4]; - GLint i; - const GLubyte *src; - switch (texImage->Format) { - case GL_ALPHA: - src = texImage->Data + row * width * sizeof(GLubyte); - for (i = 0; i < width; i++) { - rgba[i][RCOMP] = 255; - rgba[i][GCOMP] = 255; - rgba[i][BCOMP] = 255; - rgba[i][ACOMP] = src[i]; - } - break; - case GL_LUMINANCE: - src = texImage->Data + row * width * sizeof(GLubyte); - for (i = 0; i < width; i++) { - rgba[i][RCOMP] = src[i]; - rgba[i][GCOMP] = src[i]; - rgba[i][BCOMP] = src[i]; - rgba[i][ACOMP] = 255; - } - break; - case GL_LUMINANCE_ALPHA: - src = texImage->Data + row * 2 * width * sizeof(GLubyte); - for (i = 0; i < width; i++) { - rgba[i][RCOMP] = src[i*2+0]; - rgba[i][GCOMP] = src[i*2+0]; - rgba[i][BCOMP] = src[i*2+0]; - rgba[i][ACOMP] = src[i*2+1]; - } - break; - case GL_INTENSITY: - src = texImage->Data + row * width * sizeof(GLubyte); - for (i = 0; i < width; i++) { - rgba[i][RCOMP] = src[i]; - rgba[i][GCOMP] = src[i]; - rgba[i][BCOMP] = src[i]; - rgba[i][ACOMP] = 255; - } - break; - case GL_RGB: - src = texImage->Data + row * 3 * width * sizeof(GLubyte); - for (i = 0; i < width; i++) { - rgba[i][RCOMP] = src[i*3+0]; - rgba[i][GCOMP] = src[i*3+1]; - rgba[i][BCOMP] = src[i*3+2]; - rgba[i][ACOMP] = 255; - } - break; - case GL_RGBA: - /* this special case should have been handled above! */ - gl_problem( ctx, "error 1 in gl_GetTexImage" ); - break; - case GL_COLOR_INDEX: - gl_problem( ctx, "GL_COLOR_INDEX not implemented in gl_GetTexImage" ); - break; - default: - gl_problem( ctx, "bad format in gl_GetTexImage" ); + convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); + if (!convImage) { + FREE(tmpImage); + gl_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + return; + } + + for (img = 0; img < depth; img++) { + GLint convWidth, convHeight; + + /* convert to GL_RGBA */ + for (row = 0; row < height; row++) { + const GLchan *src = texImage->Data + + (img * height + row ) * width * comps; + GLfloat *dst = tmpImage + row * width * 4; + _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst, + texImage->Format, GL_UNSIGNED_BYTE, + src, &_mesa_native_packing, + ctx->ImageTransferState & IMAGE_PRE_CONVOLUTION_BITS, + GL_FALSE); + } + + convWidth = width; + convHeight = height; + + /* convolve */ + if (target == GL_TEXTURE_1D) { + if (ctx->Pixel.Convolution1DEnabled) { + _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage); + } + } + else { + if (ctx->Pixel.Convolution2DEnabled) { + _mesa_convolve_2d_image(ctx, &convWidth, &convHeight, + tmpImage, convImage); + } + else if (ctx->Pixel.Separable2DEnabled) { + _mesa_convolve_sep_image(ctx, &convWidth, &convHeight, + tmpImage, convImage); + } + } + + /* pack convolved image */ + for (row = 0; row < convHeight; row++) { + const GLfloat *src = convImage + row * convWidth * 4; + GLvoid *dest = _mesa_image_address(&ctx->Pack, pixels, + convWidth, convHeight, + format, type, img, row, 0); + _mesa_pack_float_rgba_span(ctx, convWidth, + (const GLfloat(*)[4]) src, + format, type, dest, &ctx->Pack, + ctx->ImageTransferState & IMAGE_POST_CONVOLUTION_BITS); } - /* XXX convolution */ - _mesa_pack_rgba_span( ctx, width, (const GLubyte (*)[4])rgba, - format, type, dest, &ctx->Pack, - ctx->ImageTransferState ); } + + FREE(tmpImage); + FREE(convImage); } + else { + /* no convolution */ + for (img = 0; img < depth; img++) { + for (row = 0; row < height; row++) { + /* compute destination address in client memory */ + GLvoid *dest = _mesa_image_address( &ctx->Unpack, pixels, + width, height, format, type, img, row, 0); + assert(dest); + if (texImage->Format == GL_RGBA) { + /* simple case */ + const GLchan *src = texImage->Data + + (img * height + row ) * width * 4; + _mesa_pack_rgba_span( ctx, width, (CONST GLchan (*)[4]) src, + format, type, dest, &ctx->Pack, + ctx->ImageTransferState ); + } + else { + /* general case: convert row to RGBA format */ + GLchan rgba[MAX_WIDTH][4]; + GLint i; + const GLchan *src; + switch (texImage->Format) { + case GL_ALPHA: + src = texImage->Data + row * width; + for (i = 0; i < width; i++) { + rgba[i][RCOMP] = CHAN_MAX; + rgba[i][GCOMP] = CHAN_MAX; + rgba[i][BCOMP] = CHAN_MAX; + rgba[i][ACOMP] = src[i]; + } + break; + case GL_LUMINANCE: + src = texImage->Data + row * width; + for (i = 0; i < width; i++) { + rgba[i][RCOMP] = src[i]; + rgba[i][GCOMP] = src[i]; + rgba[i][BCOMP] = src[i]; + rgba[i][ACOMP] = CHAN_MAX; + } + break; + case GL_LUMINANCE_ALPHA: + src = texImage->Data + row * 2 * width; + for (i = 0; i < width; i++) { + rgba[i][RCOMP] = src[i*2+0]; + rgba[i][GCOMP] = src[i*2+0]; + rgba[i][BCOMP] = src[i*2+0]; + rgba[i][ACOMP] = src[i*2+1]; + } + break; + case GL_INTENSITY: + src = texImage->Data + row * width; + for (i = 0; i < width; i++) { + rgba[i][RCOMP] = src[i]; + rgba[i][GCOMP] = src[i]; + rgba[i][BCOMP] = src[i]; + rgba[i][ACOMP] = CHAN_MAX; + } + break; + case GL_RGB: + src = texImage->Data + row * 3 * width; + for (i = 0; i < width; i++) { + rgba[i][RCOMP] = src[i*3+0]; + rgba[i][GCOMP] = src[i*3+1]; + rgba[i][BCOMP] = src[i*3+2]; + rgba[i][ACOMP] = CHAN_MAX; + } + break; + case GL_COLOR_INDEX: + gl_problem( ctx, "GL_COLOR_INDEX not implemented in gl_GetTexImage" ); + break; + case GL_RGBA: + default: + gl_problem( ctx, "bad format in gl_GetTexImage" ); + } + _mesa_pack_rgba_span( ctx, width, (const GLchan (*)[4])rgba, + format, type, dest, &ctx->Pack, + ctx->ImageTransferState ); + } /* format */ + } /* row */ + } /* img */ + } /* convolution */ /* if we got the teximage from the device driver we'll discard it now */ if (discardImage) { @@ -2205,9 +2402,13 @@ _mesa_TexSubImage1D( GLenum target, GLint level, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLboolean success = GL_FALSE; + GLsizei postConvWidth; + + postConvWidth = width; + adjust_texture_size_for_convolution(ctx, 1, &postConvWidth, NULL); if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0, - width, 1, 1, format, type)) { + postConvWidth, 1, 1, format, type)) { return; /* error was detected */ } @@ -2229,10 +2430,6 @@ _mesa_TexSubImage1D( GLenum target, GLint level, } if (!success) { /* XXX if Driver.TexSubImage1D, unpack image and try again? */ - - const GLint texComponents = components_in_intformat(texImage->Format); - const GLenum texFormat = texImage->Format; - const GLint xoffsetb = xoffset + texImage->Border; GLboolean retain = GL_TRUE; if (!texImage->Data) { _mesa_get_teximage_from_driver( ctx, target, level, texObj ); @@ -2243,25 +2440,10 @@ _mesa_TexSubImage1D( GLenum target, GLint level, return; /* we're really out of luck! */ } - if (texFormat == GL_COLOR_INDEX) { - /* color index texture */ - GLubyte *dst = texImage->Data + xoffsetb * texComponents; - const GLvoid *src = _mesa_image_address(&ctx->Unpack, pixels, width, - 1, format, type, 0, 0, 0); - _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst, - type, src, &ctx->Unpack, - ctx->ImageTransferState); - } - else { - /* color texture */ - GLubyte *dst = texImage->Data + xoffsetb * texComponents; - const GLvoid *src = _mesa_image_address(&ctx->Unpack, pixels, width, - 1, format, type, 0, 0, 0); - /* XXX change for convolution */ - _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst, format, - type, src, &ctx->Unpack, - ctx->ImageTransferState); - } + fill_texture_image(ctx, 1, texImage->Format, texImage->Data, + width, 1, 1, xoffset, 0, 0, /* size and offsets */ + 0, 0, /* strides */ + format, type, pixels, &ctx->Unpack); if (ctx->Driver.TexImage1D) { (*ctx->Driver.TexImage1D)( ctx, target, level, texImage->Format, @@ -2275,8 +2457,6 @@ _mesa_TexSubImage1D( GLenum target, GLint level, texImage->Data = NULL; } } - - /*gl_put_texobj_on_dirty_list( ctx, texUnit->CurrentD[1] );*/ } @@ -2292,9 +2472,14 @@ _mesa_TexSubImage2D( GLenum target, GLint level, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GLboolean success = GL_FALSE; + GLsizei postConvWidth, postConvHeight; + + postConvWidth = width; + postConvHeight = height; + adjust_texture_size_for_convolution(ctx, 2, &postConvWidth,&postConvHeight); if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0, - width, height, 1, format, type)) { + postConvWidth, postConvHeight, 1, format, type)) { return; /* error was detected */ } @@ -2316,14 +2501,8 @@ _mesa_TexSubImage2D( GLenum target, GLint level, } if (!success) { /* XXX if Driver.TexSubImage2D, unpack image and try again? */ - - const GLint texComponents = components_in_intformat(texImage->Format); - const GLenum texFormat = texImage->Format; - const GLint xoffsetb = xoffset + texImage->Border; - const GLint yoffsetb = yoffset + texImage->Border; - const GLint srcStride = _mesa_image_row_stride(&ctx->Unpack, width, - format, type); - const GLint dstStride = texImage->Width * texComponents *sizeof(GLubyte); + const GLint texComps = components_in_intformat(texImage->Format); + const GLint texRowStride = texImage->Width * texComps; GLboolean retain = GL_TRUE; if (!texImage->Data) { @@ -2335,38 +2514,10 @@ _mesa_TexSubImage2D( GLenum target, GLint level, return; /* we're really out of luck! */ } - if (texFormat == GL_COLOR_INDEX) { - /* color index texture */ - GLubyte *dst = texImage->Data - + (yoffsetb * texImage->Width + xoffsetb) * texComponents; - const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels, - width, height, format, type, 0, 0, 0); - GLint row; - for (row = 0; row < height; row++) { - _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst, type, - (const GLvoid *) src, &ctx->Unpack, - ctx->ImageTransferState); - src += srcStride; - dst += dstStride; - } - } - else { - /* color texture */ - GLubyte *dst = texImage->Data - + (yoffsetb * texImage->Width + xoffsetb) * texComponents; - const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels, - width, height, format, type, 0, 0, 0); - GLint row; - /* XXX change for convolution */ - for (row = 0; row < height; row++) { - _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst, format, - type, (const GLvoid *) src, - &ctx->Unpack, - ctx->ImageTransferState); - src += srcStride; - dst += dstStride; - } - } + fill_texture_image(ctx, 2, texImage->Format, texImage->Data, + width, height, 1, xoffset, yoffset, 0, + texRowStride, 0, + format, type, pixels, &ctx->Unpack); if (ctx->Driver.TexImage2D) { (*ctx->Driver.TexImage2D)(ctx, target, level, texImage->Format, @@ -2433,57 +2584,25 @@ _mesa_TexSubImage3D( GLenum target, GLint level, } if (!success) { /* XXX if Driver.TexSubImage3D, unpack image and try again? */ - - const GLint texComponents = components_in_intformat(texImage->Format); - const GLenum texFormat = texImage->Format; - const GLint xoffsetb = xoffset + texImage->Border; - const GLint yoffsetb = yoffset + texImage->Border; - const GLint zoffsetb = zoffset + texImage->Border; - const GLint texWidth = texImage->Width; - const GLint dstRectArea = texWidth * texImage->Height; - const GLint srcStride = _mesa_image_row_stride(&ctx->Unpack, - width, format, type); - const GLint dstStride = texWidth * texComponents * sizeof(GLubyte); + const GLint texComps = components_in_intformat(texImage->Format); + const GLint texRowStride = texImage->Width * texComps; + const GLint texImgStride = texRowStride * texImage->Height; GLboolean retain = GL_TRUE; - if (texFormat == GL_COLOR_INDEX) { - /* color index texture */ - GLint img, row; - for (img = 0; img < depth; img++) { - const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels, - width, height, format, type, img, 0, 0); - GLubyte *dst = texImage->Data + ((zoffsetb + img) * dstRectArea - + yoffsetb * texWidth + xoffsetb) * texComponents; - for (row = 0; row < height; row++) { - _mesa_unpack_index_span(ctx, width, GL_UNSIGNED_BYTE, dst, - type, (const GLvoid *) src, - &ctx->Unpack, ctx->ImageTransferState); - src += srcStride; - dst += dstStride; - } - } - } - else { - /* color texture */ - GLint img, row; - /* XXX convolution */ - for (img = 0; img < depth; img++) { - const GLubyte *src = _mesa_image_address(&ctx->Unpack, pixels, - width, height, format, type, img, 0, 0); - GLubyte *dst = texImage->Data + ((zoffsetb + img) * dstRectArea - + yoffsetb * texWidth + xoffsetb) * texComponents; - for (row = 0; row < height; row++) { - _mesa_unpack_ubyte_color_span(ctx, width, texFormat, dst, - format, type, - (const GLvoid *) src, - &ctx->Unpack, - ctx->ImageTransferState); - src += srcStride; - dst += dstStride; - } + if (!texImage->Data) { + _mesa_get_teximage_from_driver( ctx, target, level, texObj ); + if (!texImage->Data) { + make_null_texture(texImage); } + if (!texImage->Data) + return; /* we're really out of luck! */ } + fill_texture_image(ctx, 3, texImage->Format, texImage->Data, + width, height, depth, xoffset, yoffset, zoffset, + texRowStride, texImgStride, + format, type, pixels, &ctx->Unpack); + if (ctx->Driver.TexImage3D) { (*ctx->Driver.TexImage3D)(ctx, target, level, texImage->Format, GL_UNSIGNED_BYTE, texImage->Data, @@ -2502,20 +2621,20 @@ _mesa_TexSubImage3D( GLenum target, GLint level, /* * Read an RGBA image from the frame buffer. - * This is used by glCopyTexSubImage[12]D(). + * This is used by glCopyTex[Sub]Image[12]D(). * Input: ctx - the context * x, y - lower left corner * width, height - size of region to read - * Return: pointer to block of GL_RGBA, GLubyte data. + * Return: pointer to block of GL_RGBA, GLchan data. */ -static GLubyte * +static GLchan * read_color_image( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height ) { GLint stride, i; - GLubyte *image, *dst; + GLchan *image, *dst; - image = (GLubyte *) MALLOC(width * height * 4 * sizeof(GLubyte)); + image = (GLchan *) MALLOC(width * height * 4 * sizeof(GLchan)); if (!image) return NULL; @@ -2523,13 +2642,11 @@ read_color_image( GLcontext *ctx, GLint x, GLint y, (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer ); - /* XXX TODO we have to apply pixel transfer ops here! */ - dst = image; - stride = width * 4 * sizeof(GLubyte); + stride = width * 4; for (i = 0; i < height; i++) { gl_read_rgba_span( ctx, ctx->ReadBuffer, width, x, y + i, - (GLubyte (*)[4]) dst ); + (GLchan (*)[4]) dst ); dst += stride; } @@ -2560,12 +2677,11 @@ _mesa_CopyTexImage1D( GLenum target, GLint level, if (ctx->ImageTransferState || !ctx->Driver.CopyTexImage1D || !(*ctx->Driver.CopyTexImage1D)(ctx, target, level, - internalFormat, x, y, width, border)) - { + internalFormat, x, y, width, border)) { struct gl_pixelstore_attrib unpackSave; /* get image from framebuffer */ - GLubyte *image = read_color_image( ctx, x, y, width, 1 ); + GLchan *image = read_color_image( ctx, x, y, width, 1 ); if (!image) { gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D" ); return; @@ -2601,12 +2717,11 @@ _mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat, if (ctx->ImageTransferState || !ctx->Driver.CopyTexImage2D || !(*ctx->Driver.CopyTexImage2D)(ctx, target, level, - internalFormat, x, y, width, height, border)) - { + internalFormat, x, y, width, height, border)) { struct gl_pixelstore_attrib unpackSave; /* get image from framebuffer */ - GLubyte *image = read_color_image( ctx, x, y, width, height ); + GLchan *image = read_color_image( ctx, x, y, width, height ); if (!image) { gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D" ); return; @@ -2645,7 +2760,7 @@ _mesa_CopyTexSubImage1D( GLenum target, GLint level, struct gl_texture_unit *texUnit; struct gl_texture_image *teximage; struct gl_pixelstore_attrib unpackSave; - GLubyte *image; + GLchan *image; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; teximage = texUnit->CurrentD[1]->Image[level]; @@ -2692,7 +2807,7 @@ _mesa_CopyTexSubImage2D( GLenum target, GLint level, struct gl_texture_unit *texUnit; struct gl_texture_image *teximage; struct gl_pixelstore_attrib unpackSave; - GLubyte *image; + GLchan *image; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; teximage = texUnit->CurrentD[2]->Image[level]; @@ -2739,7 +2854,7 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, struct gl_texture_unit *texUnit; struct gl_texture_image *teximage; struct gl_pixelstore_attrib unpackSave; - GLubyte *image; + GLchan *image; texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; teximage = texUnit->CurrentD[3]->Image[level]; @@ -2862,16 +2977,21 @@ _mesa_CompressedTexImage1DARB(GLenum target, GLint level, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } else if (target == GL_PROXY_TEXTURE_1D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 1, width, 1, 1, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + GL_NONE, GL_NONE, 1, width, 1, 1, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, GL_NONE, GL_NONE, + width, 1, 1, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy1D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy1D->Image[level]); } } else { @@ -2911,7 +3031,7 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, } if (target==GL_TEXTURE_2D || - (ctx->Extensions.HaveTextureCubeMap && + (ctx->Extensions.ARB_texture_cube_map && target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) { struct gl_texture_unit *texUnit; @@ -2992,16 +3112,21 @@ _mesa_CompressedTexImage2DARB(GLenum target, GLint level, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } else if (target == GL_PROXY_TEXTURE_2D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 1, width, 1, 1, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + GL_NONE, GL_NONE, 2, width, height, 1, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, GL_NONE, GL_NONE, + width, height, 1, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy2D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy2D->Image[level]); } } else { @@ -3116,16 +3241,21 @@ _mesa_CompressedTexImage3DARB(GLenum target, GLint level, /* state update */ gl_put_texobj_on_dirty_list( ctx, texObj ); - ctx->NewState |= NEW_TEXTURING; + ctx->NewState |= _NEW_TEXTURE; } else if (target == GL_PROXY_TEXTURE_3D) { /* Proxy texture: check for errors and update proxy state */ - if (texture_error_check(ctx, target, level, internalFormat, - GL_NONE, GL_NONE, 1, width, height, depth, border)) { + GLenum error = texture_error_check(ctx, target, level, internalFormat, + GL_NONE, GL_NONE, 1, width, height, depth, border); + if (!error && ctx->Driver.TestProxyTexImage) { + error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level, + internalFormat, GL_NONE, GL_NONE, + width, height, depth, border); + } + if (error) { /* if error, clear all proxy texture image parameters */ if (level>=0 && levelConst.MaxTextureLevels) { - MEMSET( ctx->Texture.Proxy3D->Image[level], 0, - sizeof(struct gl_texture_image) ); + clear_proxy_teximage(ctx->Texture.Proxy3D->Image[level]); } } else {