X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftexstore.c;h=5f30e03d06a7cfc266841c4e78901ac479f2d89b;hb=c1f2f9090bcca309b9aeef7ae57acc280704db81;hp=315cd6ca2d34168d28cd8535972321a4cb3b4dca;hpb=4923e1926ad7b7eb7de017eda8e7db64d357e5c8;p=mesa.git diff --git a/src/mesa/main/texstore.c b/src/mesa/main/texstore.c index 315cd6ca2d3..5f30e03d06a 100644 --- a/src/mesa/main/texstore.c +++ b/src/mesa/main/texstore.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.1 + * Version: 6.3 * * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. * @@ -52,6 +52,7 @@ #include "glheader.h" +#include "bufferobj.h" #include "colormac.h" #include "context.h" #include "convolve.h" @@ -62,691 +63,2095 @@ #include "texformat.h" #include "teximage.h" #include "texstore.h" -#include "texutil.h" -/* - * Given an internal texture format enum or 1, 2, 3, 4 return the - * corresponding _base_ internal format: GL_ALPHA, GL_LUMINANCE, - * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA. Return the - * number of components for the format. Return -1 if invalid enum. +static const GLint ZERO = 4, ONE = 5; + +static GLboolean can_swizzle(GLenum logicalBaseFormat) +{ + switch (logicalBaseFormat) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + case GL_ALPHA: + case GL_LUMINANCE: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * When promoting texture formats (see below) we need to compute the + * mapping of dest components back to source components. + * This function does that. + * \param logicalBaseFormat the logical format of the texture + * \param textureBaseFormat the final texture format + * \return map[4] the four mapping values */ -static GLint -components_in_intformat( GLint format ) +static void +compute_component_mapping(GLenum logicalBaseFormat, GLenum textureBaseFormat, + GLubyte map[6]) { - switch (format) { - case GL_ALPHA: - case GL_ALPHA4: - case GL_ALPHA8: - case GL_ALPHA12: - case GL_ALPHA16: - return 1; - case 1: + map[ZERO] = ZERO; + map[ONE] = ONE; + + /* compute mapping from dest components back to src components */ + switch (textureBaseFormat) { + case GL_RGB: + case GL_RGBA: + switch (logicalBaseFormat) { case GL_LUMINANCE: - case GL_LUMINANCE4: - case GL_LUMINANCE8: - case GL_LUMINANCE12: - case GL_LUMINANCE16: - return 1; - case 2: - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE4_ALPHA4: - case GL_LUMINANCE6_ALPHA2: - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE12_ALPHA4: - case GL_LUMINANCE12_ALPHA12: - case GL_LUMINANCE16_ALPHA16: - return 2; + map[0] = map[1] = map[2] = 0; + if (textureBaseFormat == GL_RGBA) + map[3] = ONE; + break; + case GL_ALPHA: + ASSERT(textureBaseFormat == GL_RGBA); + map[0] = map[1] = map[2] = ZERO; + map[3] = 0; + break; case GL_INTENSITY: - case GL_INTENSITY4: - case GL_INTENSITY8: - case GL_INTENSITY12: - case GL_INTENSITY16: - return 1; - case 3: + map[0] = map[1] = map[2] = 0; + if (textureBaseFormat == GL_RGBA) + map[3] = 0; + break; + case GL_LUMINANCE_ALPHA: + ASSERT(textureBaseFormat == GL_RGBA); + map[0] = map[1] = map[2] = 0; + map[3] = 1; + break; case GL_RGB: - case GL_R3_G3_B2: - case GL_RGB4: - case GL_RGB5: - case GL_RGB8: - case GL_RGB10: - case GL_RGB12: - case GL_RGB16: - return 3; - case 4: + ASSERT(textureBaseFormat == GL_RGBA); + map[0] = 0; + map[1] = 1; + map[2] = 2; + map[3] = ONE; + break; case GL_RGBA: - case GL_RGBA2: - case GL_RGBA4: - case GL_RGB5_A1: - case GL_RGBA8: - case GL_RGB10_A2: - case GL_RGBA12: - case GL_RGBA16: - return 4; - 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 1; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_SGIX: - case GL_DEPTH_COMPONENT24_SGIX: - case GL_DEPTH_COMPONENT32_SGIX: - return 1; - case GL_YCBCR_MESA: - return 2; /* Y + (Cb or Cr) */ + ASSERT(textureBaseFormat == GL_RGBA); + map[0] = 0; + map[1] = 1; + map[2] = 2; + map[3] = 3; + break; default: - return -1; /* error */ - } + _mesa_problem(NULL, "Unexpected logicalBaseFormat"); + map[0] = map[1] = map[2] = map[3] = 0; + } + break; + case GL_LUMINANCE_ALPHA: + switch (logicalBaseFormat) { + case GL_LUMINANCE: + map[0] = 0; + map[1] = ONE; + break; + case GL_ALPHA: + map[0] = ZERO; + map[1] = 0; + break; + case GL_INTENSITY: + map[0] = 0; + map[1] = 0; + break; + default: + _mesa_problem(NULL, "Unexpected logicalBaseFormat"); + map[0] = map[1] = 0; + } + break; + default: + _mesa_problem(NULL, "Unexpected logicalBaseFormat"); + map[0] = map[1] = 0; + break; + } } -/* - * This function is used to transfer the user's image data into a texture - * image buffer. We handle both full texture images and subtexture images. - * We also take care of all image transfer operations here, including - * convolution, scale/bias, colortables, etc. - * - * The destination texel type is always GLchan. - * The destination texel format is one of the 6 basic types. +/** + * Make a temporary (color) texture image with GLfloat components. + * Apply all needed pixel unpacking and pixel transfer operations. + * Note that there are both logicalBaseFormat and textureBaseFormat parameters. + * Suppose the user specifies GL_LUMINANCE as the internal texture format + * but the graphics hardware doesn't support luminance textures. So, might + * use an RGB hardware format instead. + * If logicalBaseFormat != textureBaseFormat we have some extra work to do. * - * A hardware driver may use this as a helper routine to unpack and - * apply pixel transfer ops into a temporary image buffer. Then, - * convert the temporary image into the special hardware format. + * \param ctx the rendering context + * \param dims image dimensions: 1, 2 or 3 + * \param logicalBaseFormat basic texture derived from the user's + * internal texture format value + * \param textureBaseFormat the actual basic format of the texture + * \param srcWidth source image width + * \param srcHeight source image height + * \param srcDepth source image depth + * \param srcFormat source image format + * \param srcType source image type + * \param srcAddr source image address + * \param srcPacking source image pixel packing + * \return resulting image with format = textureBaseFormat and type = GLfloat. + */ +static GLfloat * +make_temp_float_image(GLcontext *ctx, GLuint dims, + GLenum logicalBaseFormat, + GLenum textureBaseFormat, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + GLuint transferOps = ctx->_ImageTransferState; + GLfloat *tempImage; + + ASSERT(dims >= 1 && dims <= 3); + + ASSERT(logicalBaseFormat == GL_RGBA || + logicalBaseFormat == GL_RGB || + logicalBaseFormat == GL_LUMINANCE_ALPHA || + logicalBaseFormat == GL_LUMINANCE || + logicalBaseFormat == GL_ALPHA || + logicalBaseFormat == GL_INTENSITY || + logicalBaseFormat == GL_COLOR_INDEX || + logicalBaseFormat == GL_DEPTH_COMPONENT); + + ASSERT(textureBaseFormat == GL_RGBA || + textureBaseFormat == GL_RGB || + textureBaseFormat == GL_LUMINANCE_ALPHA || + textureBaseFormat == GL_LUMINANCE || + textureBaseFormat == GL_ALPHA || + textureBaseFormat == GL_INTENSITY || + textureBaseFormat == GL_COLOR_INDEX || + textureBaseFormat == GL_DEPTH_COMPONENT); + + /* conventional color image */ + + if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) || + (dims >= 2 && ctx->Pixel.Convolution2DEnabled) || + (dims >= 2 && ctx->Pixel.Separable2DEnabled)) { + /* need image convolution */ + const GLuint preConvTransferOps + = (transferOps & IMAGE_PRE_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT; + const GLuint postConvTransferOps + = (transferOps & IMAGE_POST_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT; + GLint img, row; + GLint convWidth, convHeight; + GLfloat *convImage; + + /* pre-convolution image buffer (3D) */ + tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth + * 4 * sizeof(GLfloat)); + if (!tempImage) + return NULL; + + /* post-convolution image buffer (2D) */ + convImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight + * 4 * sizeof(GLfloat)); + if (!convImage) { + _mesa_free(tempImage); + return NULL; + } + + /* loop over 3D image slices */ + for (img = 0; img < srcDepth; img++) { + GLfloat *dst = tempImage + img * (srcWidth * srcHeight * 4); + + /* unpack and do transfer ops up to convolution */ + for (row = 0; row < srcHeight; row++) { + const GLvoid *src = _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, + srcFormat, srcType, img, row, 0); + _mesa_unpack_color_span_float(ctx, srcWidth, GL_RGBA, dst, + srcFormat, srcType, src, + srcPacking, + preConvTransferOps); + dst += srcWidth * 4; + } + + /* do convolution */ + { + GLfloat *src = tempImage + img * (srcWidth * srcHeight * 4); + convWidth = srcWidth; + convHeight = srcHeight; + if (dims == 1) { + ASSERT(ctx->Pixel.Convolution1DEnabled); + _mesa_convolve_1d_image(ctx, &convWidth, src, convImage); + } + else { + if (ctx->Pixel.Convolution2DEnabled) { + _mesa_convolve_2d_image(ctx, &convWidth, &convHeight, + src, convImage); + } + else { + ASSERT(ctx->Pixel.Separable2DEnabled); + _mesa_convolve_sep_image(ctx, &convWidth, &convHeight, + src, convImage); + } + } + } + + /* do post-convolution transfer and pack into tempImage */ + { + const GLint logComponents + = _mesa_components_in_format(logicalBaseFormat); + const GLfloat *src = convImage; + GLfloat *dst = tempImage + img * (convWidth * convHeight * 4); + for (row = 0; row < convHeight; row++) { + _mesa_pack_rgba_span_float(ctx, convWidth, + (const GLfloat (*)[4]) src, + logicalBaseFormat, GL_FLOAT, + dst, &ctx->DefaultPacking, + postConvTransferOps); + src += convWidth * 4; + dst += convWidth * logComponents; + } + } + } /* loop over 3D image slices */ + + _mesa_free(convImage); + + /* might need these below */ + srcWidth = convWidth; + srcHeight = convHeight; + } + else { + /* no convolution */ + const GLint components = _mesa_components_in_format(logicalBaseFormat); + const GLint srcStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLfloat *dst; + GLint img, row; + + tempImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth + * components * sizeof(GLfloat)); + if (!tempImage) + return NULL; + + dst = tempImage; + for (img = 0; img < srcDepth; img++) { + const GLubyte *src + = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, + srcWidth, srcHeight, + srcFormat, srcType, + img, 0, 0); + for (row = 0; row < srcHeight; row++) { + _mesa_unpack_color_span_float(ctx, srcWidth, logicalBaseFormat, + dst, srcFormat, srcType, src, + srcPacking, transferOps); + dst += srcWidth * components; + src += srcStride; + } + } + } + + if (logicalBaseFormat != textureBaseFormat) { + /* more work */ + GLint texComponents = _mesa_components_in_format(textureBaseFormat); + GLint logComponents = _mesa_components_in_format(logicalBaseFormat); + GLfloat *newImage; + GLint i, n; + GLubyte map[6]; + + /* we only promote up to RGB, RGBA and LUMINANCE_ALPHA formats for now */ + ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA || + textureBaseFormat == GL_LUMINANCE_ALPHA); + + /* The actual texture format should have at least as many components + * as the logical texture format. + */ + ASSERT(texComponents >= logComponents); + + newImage = (GLfloat *) _mesa_malloc(srcWidth * srcHeight * srcDepth + * texComponents * sizeof(GLfloat)); + if (!newImage) { + _mesa_free(tempImage); + return NULL; + } + + compute_component_mapping(logicalBaseFormat, textureBaseFormat, map); + + n = srcWidth * srcHeight * srcDepth; + for (i = 0; i < n; i++) { + GLint k; + for (k = 0; k < texComponents; k++) { + GLint j = map[k]; + if (j == ZERO) + newImage[i * texComponents + k] = 0.0F; + else if (j == ONE) + newImage[i * texComponents + k] = 1.0F; + else + newImage[i * texComponents + k] = tempImage[i * logComponents + j]; + } + } + + _mesa_free(tempImage); + tempImage = newImage; + } + + return tempImage; +} + + +/** + * Make a temporary (color) texture image with GLchan components. + * Apply all needed pixel unpacking and pixel transfer operations. + * Note that there are both logicalBaseFormat and textureBaseFormat parameters. + * Suppose the user specifies GL_LUMINANCE as the internal texture format + * but the graphics hardware doesn't support luminance textures. So, might + * use an RGB hardware format instead. + * If logicalBaseFormat != textureBaseFormat we have some extra work to do. * - * \param - * dimensions - 1, 2, or 3 - * texDestFormat - GL_LUMINANCE, GL_INTENSITY, GL_LUMINANCE_ALPHA, GL_ALPHA, - * GL_RGB or GL_RGBA (the destination format) - * texDestAddr - destination image address - * srcWidth, srcHeight, srcDepth - size (in pixels) of src and dest images - * dstXoffset, dstYoffset, dstZoffset - position to store the image within - * the destination 3D texture - * dstRowStride, dstImageStride - dest image strides in bytes - * srcFormat - source image format (GL_ALPHA, GL_RED, GL_RGB, etc) - * srcType - GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_FLOAT, etc - * srcPacking - describes packing of incoming image. - * transferOps - mask of pixel transfer operations + * \param ctx the rendering context + * \param dims image dimensions: 1, 2 or 3 + * \param logicalBaseFormat basic texture derived from the user's + * internal texture format value + * \param textureBaseFormat the actual basic format of the texture + * \param srcWidth source image width + * \param srcHeight source image height + * \param srcDepth source image depth + * \param srcFormat source image format + * \param srcType source image type + * \param srcAddr source image address + * \param srcPacking source image pixel packing + * \return resulting image with format = textureBaseFormat and type = GLchan. */ +GLchan * +_mesa_make_temp_chan_image(GLcontext *ctx, GLuint dims, + GLenum logicalBaseFormat, + GLenum textureBaseFormat, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + GLuint transferOps = ctx->_ImageTransferState; + const GLint components = _mesa_components_in_format(logicalBaseFormat); + GLboolean freeSrcImage = GL_FALSE; + GLint img, row; + GLchan *tempImage, *dst; + + ASSERT(dims >= 1 && dims <= 3); + + ASSERT(logicalBaseFormat == GL_RGBA || + logicalBaseFormat == GL_RGB || + logicalBaseFormat == GL_LUMINANCE_ALPHA || + logicalBaseFormat == GL_LUMINANCE || + logicalBaseFormat == GL_ALPHA || + logicalBaseFormat == GL_INTENSITY); + + ASSERT(textureBaseFormat == GL_RGBA || + textureBaseFormat == GL_RGB || + textureBaseFormat == GL_LUMINANCE_ALPHA || + textureBaseFormat == GL_LUMINANCE || + textureBaseFormat == GL_ALPHA || + textureBaseFormat == GL_INTENSITY); + + if ((dims == 1 && ctx->Pixel.Convolution1DEnabled) || + (dims >= 2 && ctx->Pixel.Convolution2DEnabled) || + (dims >= 2 && ctx->Pixel.Separable2DEnabled)) { + /* get convolved image */ + GLfloat *convImage = make_temp_float_image(ctx, dims, + logicalBaseFormat, + logicalBaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, + srcAddr, srcPacking); + if (!convImage) + return NULL; + /* the convolved image is our new source image */ + srcAddr = convImage; + srcFormat = logicalBaseFormat; + srcType = GL_FLOAT; + srcPacking = &ctx->DefaultPacking; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + transferOps = 0; + freeSrcImage = GL_TRUE; + } + + /* unpack and transfer the source image */ + tempImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth + * components * sizeof(GLchan)); + if (!tempImage) + return NULL; + + dst = tempImage; + for (img = 0; img < srcDepth; img++) { + const GLint srcStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, + srcType); + const GLubyte *src + = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr, + srcWidth, srcHeight, + srcFormat, srcType, + img, 0, 0); + for (row = 0; row < srcHeight; row++) { + _mesa_unpack_color_span_chan(ctx, srcWidth, logicalBaseFormat, dst, + srcFormat, srcType, src, srcPacking, + transferOps); + dst += srcWidth * components; + src += srcStride; + } + } + + /* If we made a temporary image for convolution, free it here */ + if (freeSrcImage) { + _mesa_free((void *) srcAddr); + } + + if (logicalBaseFormat != textureBaseFormat) { + /* one more conversion step */ + GLint texComponents = _mesa_components_in_format(textureBaseFormat); + GLint logComponents = _mesa_components_in_format(logicalBaseFormat); + GLchan *newImage; + GLint i, n; + GLubyte map[6]; + + /* we only promote up to RGB, RGBA and LUMINANCE_ALPHA formats for now */ + ASSERT(textureBaseFormat == GL_RGB || textureBaseFormat == GL_RGBA || + textureBaseFormat == GL_LUMINANCE_ALPHA); + + /* The actual texture format should have at least as many components + * as the logical texture format. + */ + ASSERT(texComponents >= logComponents); + + newImage = (GLchan *) _mesa_malloc(srcWidth * srcHeight * srcDepth + * texComponents * sizeof(GLchan)); + if (!newImage) { + _mesa_free(tempImage); + return NULL; + } + + compute_component_mapping(logicalBaseFormat, textureBaseFormat, map); + + n = srcWidth * srcHeight * srcDepth; + for (i = 0; i < n; i++) { + GLint k; + for (k = 0; k < texComponents; k++) { + GLint j = map[k]; + if (j == ZERO) + newImage[i * texComponents + k] = 0; + else if (j == ONE) + newImage[i * texComponents + k] = CHAN_MAX; + else + newImage[i * texComponents + k] = tempImage[i * logComponents + j]; + } + } + + _mesa_free(tempImage); + tempImage = newImage; + } + + return tempImage; +} + + +static void swizzle_copy(GLubyte *dst, + GLuint dstComponents, + const GLubyte *src, + GLuint srcComponents, + GLubyte *map, + GLuint count) +{ + GLubyte tmp[8]; + GLint i; + + tmp[ZERO] = 0x0; + tmp[ONE] = 0xff; + + switch (dstComponents) { + case 4: + for (i = 0; i < count; i++) { + COPY_4UBV(tmp, src); + src += srcComponents; + dst[0] = tmp[map[0]]; + dst[1] = tmp[map[1]]; + dst[2] = tmp[map[2]]; + dst[3] = tmp[map[3]]; + dst += 4; + } + break; + case 3: + for (i = 0; i < count; i++) { + COPY_4UBV(tmp, src); + src += srcComponents; + dst[0] = tmp[map[0]]; + dst[1] = tmp[map[1]]; + dst[2] = tmp[map[2]]; + dst += 3; + } + break; + case 2: + for (i = 0; i < count; i++) { + COPY_4UBV(tmp, src); + src += srcComponents; + dst[0] = tmp[map[0]]; + dst[1] = tmp[map[1]]; + dst += 2; + } + break; + } +} + + static void -transfer_teximage(GLcontext *ctx, GLuint dimensions, - GLenum texDestFormat, GLvoid *texDestAddr, - 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, - GLuint transferOps) +_mesa_swizzle_ubyte_image(GLcontext *ctx, + GLuint dimensions, + GLenum srcFormat, + const GLubyte *dstmap, GLint dstComponents, + + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + + GLint srcWidth, GLint srcHeight, GLint srcDepth, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking ) { - GLint texComponents; - - ASSERT(ctx); - ASSERT(dimensions >= 1 && dimensions <= 3); - ASSERT(texDestFormat == GL_LUMINANCE || - texDestFormat == GL_INTENSITY || - texDestFormat == GL_LUMINANCE_ALPHA || - texDestFormat == GL_ALPHA || - texDestFormat == GL_RGB || - texDestFormat == GL_RGBA || - texDestFormat == GL_COLOR_INDEX || - texDestFormat == GL_DEPTH_COMPONENT); - ASSERT(texDestAddr); - ASSERT(srcWidth >= 0); - ASSERT(srcHeight >= 0); - ASSERT(srcDepth >= 0); - ASSERT(dstXoffset >= 0); - ASSERT(dstYoffset >= 0); - ASSERT(dstZoffset >= 0); - ASSERT(dstRowStride >= 0); - ASSERT(dstImageStride >= 0); - ASSERT(srcAddr); - ASSERT(srcPacking); - - texComponents = components_in_intformat(texDestFormat); - - /* try common 2D texture cases first */ - if (!transferOps && dimensions == 2 && srcType == CHAN_TYPE) { - - if (srcFormat == texDestFormat) { - /* This will cover the common GL_RGB, GL_RGBA, GL_ALPHA, - * GL_LUMINANCE_ALPHA, etc. texture formats. Use memcpy(). - */ - 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 = (GLchan *) texDestAddr - + dstYoffset * (dstRowStride / sizeof(GLchan)) - + dstXoffset * texComponents; - if (srcRowStride == widthInBytes && dstRowStride == widthInBytes) { - MEMCPY(dst, src, srcHeight * widthInBytes); + GLint srcComponents = _mesa_components_in_format(srcFormat); + GLubyte srcmap[6], map[4]; + GLint i; + + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, + srcFormat, GL_UNSIGNED_BYTE); + const GLint srcImageStride = _mesa_image_image_stride(srcPacking, + srcWidth, srcHeight, srcFormat, GL_UNSIGNED_BYTE); + const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dimensions, + srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, GL_UNSIGNED_BYTE, 0, 0, 0); + + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstComponents; + + compute_component_mapping(srcFormat, GL_RGBA, srcmap); + + for (i = 0; i < 4; i++) + map[i] = srcmap[dstmap[i]]; + + if (srcRowStride == srcWidth * srcComponents && + (srcImageStride == srcWidth * srcHeight * srcComponents || + srcDepth == 1)) { + swizzle_copy(dstImage, dstComponents, srcImage, srcComponents, map, + srcWidth * srcHeight * srcDepth); + } + else { + GLint img, row; + for (img = 0; img < srcDepth; img++) { + const GLubyte *srcRow = srcImage; + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + swizzle_copy(dstRow, dstComponents, srcRow, srcComponents, map, srcWidth); + dstRow += dstRowStride; + srcRow += srcRowStride; } - else { - GLint i; - for (i = 0; i < srcHeight; i++) { - MEMCPY(dst, src, widthInBytes); - src += (srcRowStride / sizeof(GLchan)); - dst += (dstRowStride / sizeof(GLchan)); - } + srcImage += srcImageStride; + dstImage += dstImageStride; + } + } +} + + + + + +/** + * Teximage storage routine for when a simple memcpy will do. + * No pixel transfer operations or special texel encodings allowed. + * 1D, 2D and 3D images supported. + */ +static void +memcpy_texture(GLuint dimensions, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, + srcFormat, srcType); + const GLint srcImageStride = _mesa_image_image_stride(srcPacking, + srcWidth, srcHeight, srcFormat, srcType); + const GLubyte *srcImage = (const GLubyte *) _mesa_image_address(dimensions, + srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, 0, 0, 0); + const GLint bytesPerRow = srcWidth * dstFormat->TexelBytes; + const GLint bytesPerImage = srcHeight * bytesPerRow; + const GLint bytesPerTexture = srcDepth * bytesPerImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + + if (dstRowStride == srcRowStride && + dstRowStride == bytesPerRow && + ((dstImageStride == srcImageStride && + dstImageStride == bytesPerImage) || + (srcDepth == 1))) { + /* one big memcpy */ + _mesa_memcpy(dstImage, srcImage, bytesPerTexture); + } + else { + GLint img, row; + for (img = 0; img < srcDepth; img++) { + const GLubyte *srcRow = srcImage; + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + _mesa_memcpy(dstRow, srcRow, bytesPerRow); + dstRow += dstRowStride; + srcRow += srcRowStride; } - return; /* all done */ + srcImage += srcImageStride; + dstImage += dstImageStride; } - else if (srcFormat == GL_RGBA && texDestFormat == GL_RGB) { - /* commonly used by Quake */ - const GLchan *src = (const GLchan *) _mesa_image_address( - srcPacking, srcAddr, srcWidth, srcHeight, - srcFormat, srcType, 0, 0, 0); + } +} + + + +/** + * Store an image in any of the formats: + * _mesa_texformat_rgba + * _mesa_texformat_rgb + * _mesa_texformat_alpha + * _mesa_texformat_luminance + * _mesa_texformat_luminance_alpha + * _mesa_texformat_intensity + * + * \param dims either 1 or 2 or 3 + * \param baseInternalFormat user-specified base internal format + * \param dstFormat destination Mesa texture format + * \param dstAddr destination image address + * \param dstX/Y/Zoffset destination x/y/z offset (ala TexSubImage), in texels + * \param dstRowStride destination image row stride, in bytes + * \param dstImageStride destination image layer stride, in bytes + * \param srcWidth/Height/Depth source image size, in pixels + * \param srcFormat incoming image format + * \param srcType incoming image data type + * \param srcAddr source image address + * \param srcPacking source image packing parameters + */ +GLboolean +_mesa_texstore_rgba(GLcontext *ctx, GLuint dims, + GLenum baseInternalFormat, + const struct gl_texture_format *dstFormat, + GLvoid *dstAddr, + GLint dstXoffset, GLint dstYoffset, GLint dstZoffset, + GLint dstRowStride, GLint dstImageStride, + GLint srcWidth, GLint srcHeight, GLint srcDepth, + GLenum srcFormat, GLenum srcType, + const GLvoid *srcAddr, + const struct gl_pixelstore_attrib *srcPacking) +{ + const GLint components = _mesa_components_in_format(baseInternalFormat); + + ASSERT(dstFormat == &_mesa_texformat_rgba || + dstFormat == &_mesa_texformat_rgb || + dstFormat == &_mesa_texformat_alpha || + dstFormat == &_mesa_texformat_luminance || + dstFormat == &_mesa_texformat_luminance_alpha || + dstFormat == &_mesa_texformat_intensity); + ASSERT(baseInternalFormat == GL_RGBA || + baseInternalFormat == GL_RGB || + baseInternalFormat == GL_ALPHA || + baseInternalFormat == GL_LUMINANCE || + baseInternalFormat == GL_LUMINANCE_ALPHA || + baseInternalFormat == GL_INTENSITY); + ASSERT(dstFormat->TexelBytes == components * sizeof(GLchan)); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == srcFormat && + srcType == CHAN_TYPE) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_rgb && + srcFormat == GL_RGBA && + srcType == CHAN_TYPE) { + /* extract RGB from RGBA */ + int img, row, col; + GLchan *dstImage = (GLchan *) (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + for (img = 0; img < srcDepth; img++) { const GLint srcRowStride = _mesa_image_row_stride(srcPacking, - srcWidth, srcFormat, srcType); - GLchan *dst = (GLchan *) texDestAddr - + dstYoffset * (dstRowStride / sizeof(GLchan)) - + dstXoffset * texComponents; - GLint i, j; - 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*/ + srcWidth, srcFormat, srcType); + GLchan *srcRow = (GLchan *) _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); + GLchan *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + RCOMP] = srcRow[col * 4 + RCOMP]; + dstRow[col * 3 + GCOMP] = srcRow[col * 4 + GCOMP]; + dstRow[col * 3 + BCOMP] = srcRow[col * 4 + BCOMP]; } - src += (srcRowStride / sizeof(GLchan)); - dst += (dstRowStride / sizeof(GLchan)); + dstRow += dstRowStride; + srcRow = (GLchan *) ((GLubyte *) srcRow + srcRowStride); } - return; /* all done */ + dstImage += dstImageStride; } } - - /* - * General case solutions - */ - if (texDestFormat == GL_COLOR_INDEX) { - /* color index texture */ - const GLenum texType = CHAN_TYPE; + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLint bytesPerRow; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; GLint img, row; - GLchan *dest = (GLchan *) texDestAddr - + dstZoffset * (dstImageStride / sizeof(GLchan)) - + dstYoffset * (dstRowStride / sizeof(GLchan)) - + dstXoffset * texComponents; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + bytesPerRow = srcWidth * components * sizeof(GLchan); for (img = 0; img < srcDepth; img++) { - GLchan *destRow = dest; + GLubyte *dstRow = dstImage; 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, transferOps); - destRow += (dstRowStride / sizeof(GLchan)); + _mesa_memcpy(dstRow, src, bytesPerRow); + dstRow += dstRowStride; + src += srcWidth * components; } - dest += dstImageStride; + dstImage += dstImageStride; } + + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +/** + * Store a floating point depth component texture image. + */ +GLboolean +_mesa_texstore_depth_component_float32(STORE_PARAMS) +{ + (void) dims; + ASSERT(dstFormat == &_mesa_texformat_depth_component_float32); + ASSERT(dstFormat->TexelBytes == sizeof(GLfloat)); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_DEPTH_COMPONENT && + srcFormat == GL_DEPTH_COMPONENT && + srcType == GL_FLOAT) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); } - else if (texDestFormat == GL_YCBCR_MESA) { - /* YCbCr texture */ + else { + /* general path */ + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; GLint img, row; - GLushort *dest = (GLushort *) texDestAddr - + dstZoffset * (dstImageStride / sizeof(GLushort)) - + dstYoffset * (dstRowStride / sizeof(GLushort)) - + dstXoffset * texComponents; - ASSERT(ctx->Extensions.MESA_ycbcr_texture); for (img = 0; img < srcDepth; img++) { - GLushort *destRow = dest; + GLubyte *dstRow = dstImage; for (row = 0; row < srcHeight; row++) { - const GLvoid *srcRow = _mesa_image_address(srcPacking, - srcAddr, srcWidth, srcHeight, - srcFormat, srcType, img, row, 0); - MEMCPY(destRow, srcRow, srcWidth * sizeof(GLushort)); - destRow += (dstRowStride / sizeof(GLushort)); + const GLvoid *src = _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0); + _mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) dstRow, + srcType, src, srcPacking); + dstRow += dstRowStride; } - dest += dstImageStride / sizeof(GLushort); + dstImage += dstImageStride; } } - else if (texDestFormat == GL_DEPTH_COMPONENT) { - /* Depth texture (shadow maps) */ - GLint img, row; - GLubyte *dest = (GLubyte *) texDestAddr - + dstZoffset * dstImageStride - + dstYoffset * (dstRowStride / sizeof(GLchan)) - + dstXoffset * texComponents; + return GL_TRUE; +} + + +/** + * Store a 16-bit integer depth component texture image. + */ +GLboolean +_mesa_texstore_depth_component16(STORE_PARAMS) +{ + (void) dims; + ASSERT(dstFormat == &_mesa_texformat_depth_component16); + ASSERT(dstFormat->TexelBytes == sizeof(GLushort)); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_DEPTH_COMPONENT && + srcFormat == GL_DEPTH_COMPONENT && + srcType == GL_UNSIGNED_SHORT) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; for (img = 0; img < srcDepth; img++) { - GLubyte *destRow = dest; + GLubyte *dstRow = dstImage; for (row = 0; row < srcHeight; row++) { - const GLvoid *src = _mesa_image_address(srcPacking, + GLfloat depthTemp[MAX_WIDTH]; + const GLvoid *src = _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0); - _mesa_unpack_depth_span(ctx, srcWidth, (GLfloat *) destRow, + GLushort *dst16 = (GLushort *) dstRow; + _mesa_unpack_depth_span(ctx, srcWidth, depthTemp, srcType, src, srcPacking); - destRow += (dstRowStride / sizeof(GLchan)); + for (col = 0; col < srcWidth; col++) { + dst16[col] = (GLushort) (depthTemp[col] * 65535.0F); + } + dstRow += dstRowStride; } - dest += dstImageStride; + dstImage += dstImageStride; + } + } + return GL_TRUE; +} + + +/** + * Store an rgb565 or rgb565_rev texture image. + */ +GLboolean +_mesa_texstore_rgb565(STORE_PARAMS) +{ + ASSERT(dstFormat == &_mesa_texformat_rgb565 || + dstFormat == &_mesa_texformat_rgb565_rev); + ASSERT(dstFormat->TexelBytes == 2); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_rgb565 && + baseInternalFormat == GL_RGB && + srcFormat == GL_RGB && + srcType == GL_UNSIGNED_SHORT_5_6_5) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_RGB && + srcFormat == GL_RGB && + srcType == GL_UNSIGNED_BYTE && + dims == 2) { + /* do optimized tex store */ + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, srcWidth, + srcFormat, srcType); + const GLubyte *src = (const GLubyte *) + _mesa_image_address(dims, srcPacking, srcAddr, srcWidth, srcHeight, + srcFormat, srcType, 0, 0, 0); + GLubyte *dst = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint row, col; + for (row = 0; row < srcHeight; row++) { + const GLubyte *srcUB = (const GLubyte *) src; + GLushort *dstUS = (GLushort *) dst; + /* check for byteswapped format */ + if (dstFormat == &_mesa_texformat_rgb565) { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_565( srcUB[0], srcUB[1], srcUB[2] ); + srcUB += 3; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_565_REV( srcUB[0], srcUB[1], srcUB[2] ); + srcUB += 3; + } + } + dst += dstRowStride; + src += srcRowStride; } } else { - /* regular, color texture */ - if ((dimensions == 1 && ctx->Pixel.Convolution1DEnabled) || - (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(srcWidth * srcHeight * 4 * sizeof(GLfloat)); - if (!tmpImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); - return; + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLushort *dstUS = (GLushort *) dstRow; + /* check for byteswapped format */ + if (dstFormat == &_mesa_texformat_rgb565) { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_565( CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 3; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_565_REV( CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 3; + } + } + dstRow += dstRowStride; } - convImage = (GLfloat *) MALLOC(srcWidth * srcHeight * 4 * sizeof(GLfloat)); - if (!convImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); - FREE(tmpImage); - return; + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +GLboolean +_mesa_texstore_rgba8888(STORE_PARAMS) +{ + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + + (void)littleEndian; + ASSERT(dstFormat == &_mesa_texformat_rgba8888 || + dstFormat == &_mesa_texformat_rgba8888_rev); + ASSERT(dstFormat->TexelBytes == 4); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_rgba8888 && + baseInternalFormat == GL_RGBA && + ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8) || + (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8_REV))) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } +#if 0 + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + srcType == GL_UNSIGNED_BYTE && + dstFormat == &_mesa_texformat_rgba8888 && + littleEndian && + can_swizzle(srcFormat)) { + GLubyte dstmap[4]; + + /* dstmap - how to swizzle from GL_RGBA to dst format: + * + * FIXME - add !litteEndian and _rev varients: + */ + dstmap[3] = 0; + dstmap[2] = 1; + dstmap[1] = 2; + dstmap[0] = 3; + + _mesa_swizzle_ubyte_image(ctx, dims, + srcFormat, + dstmap, 4, + dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcAddr, + srcPacking); + } +#endif + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLuint *dstUI = (GLuint *) dstRow; + if (dstFormat == &_mesa_texformat_rgba8888) { + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]), + CHAN_TO_UBYTE(src[ACOMP]) ); + src += 4; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_8888_REV( CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]), + CHAN_TO_UBYTE(src[ACOMP]) ); + src += 4; + } + } + dstRow += dstRowStride; } + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} - 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 < srcHeight; row++) { - const GLvoid *src = _mesa_image_address(srcPacking, - srcAddr, srcWidth, srcHeight, - srcFormat, srcType, img, row, 0); - _mesa_unpack_color_span_float(ctx, srcWidth, GL_RGBA, dstf, - srcFormat, srcType, src, srcPacking, - (transferOps & IMAGE_PRE_CONVOLUTION_BITS) | IMAGE_CLAMP_BIT); - dstf += srcWidth * 4; +GLboolean +_mesa_texstore_argb8888(STORE_PARAMS) +{ + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + + ASSERT(dstFormat == &_mesa_texformat_argb8888 || + dstFormat == &_mesa_texformat_argb8888_rev); + ASSERT(dstFormat->TexelBytes == 4); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb8888 && + baseInternalFormat == GL_RGBA && + srcFormat == GL_BGRA && + ((srcType == GL_UNSIGNED_BYTE && littleEndian) || + srcType == GL_UNSIGNED_INT_8_8_8_8_REV)) { + /* simple memcpy path (little endian) */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb8888_rev && + baseInternalFormat == GL_RGBA && + srcFormat == GL_BGRA && + ((srcType == GL_UNSIGNED_BYTE && !littleEndian) || + srcType == GL_UNSIGNED_INT_8_8_8_8)) { + /* simple memcpy path (big endian) */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb8888 && + srcFormat == GL_RGB && + srcType == GL_UNSIGNED_BYTE) { + + int img, row, col; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + for (img = 0; img < srcDepth; img++) { + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 4 + 0] = srcRow[col * 3 + BCOMP]; + dstRow[col * 4 + 1] = srcRow[col * 3 + GCOMP]; + dstRow[col * 4 + 2] = srcRow[col * 3 + RCOMP]; + dstRow[col * 4 + 3] = 0xff; } + dstRow += dstRowStride; + srcRow += srcRowStride; + } + dstImage += dstImageStride; + } + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb8888 && + srcFormat == GL_RGBA && + srcType == GL_UNSIGNED_BYTE) { + + int img, row, col; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + for (img = 0; img < srcDepth; img++) { + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 4 + 0] = srcRow[col * 4 + BCOMP]; + dstRow[col * 4 + 1] = srcRow[col * 4 + GCOMP]; + dstRow[col * 4 + 2] = srcRow[col * 4 + RCOMP]; + dstRow[col * 4 + 3] = srcRow[col * 4 + ACOMP]; + } + dstRow += dstRowStride; + srcRow += srcRowStride; + } + dstImage += dstImageStride; + } + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb8888 && + srcType == GL_UNSIGNED_BYTE && + littleEndian && + can_swizzle(srcFormat)) { - /* convolve */ - if (dimensions == 1) { - ASSERT(ctx->Pixel.Convolution1DEnabled); - _mesa_convolve_1d_image(ctx, &convWidth, tmpImage, convImage); + GLubyte dstmap[4]; + + /* dstmap - how to swizzle from GL_RGBA to dst format: + */ + dstmap[3] = 3; /* alpha */ + dstmap[2] = 0; /* red */ + dstmap[1] = 1; /* green */ + dstmap[0] = 2; /* blue */ + + _mesa_swizzle_ubyte_image(ctx, dims, + srcFormat, + dstmap, 4, + dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcAddr, + srcPacking); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLuint *dstUI = (GLuint *) dstRow; + if (dstFormat == &_mesa_texformat_argb8888) { + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; + } } else { - if (ctx->Pixel.Convolution2DEnabled) { - _mesa_convolve_2d_image(ctx, &convWidth, &convHeight, - tmpImage, convImage); - } - else { - ASSERT(ctx->Pixel.Separable2DEnabled); - _mesa_convolve_sep_image(ctx, &convWidth, &convHeight, - tmpImage, convImage); + for (col = 0; col < srcWidth; col++) { + dstUI[col] = PACK_COLOR_8888_REV( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; } } + dstRow += dstRowStride; + } + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} - /* packing and transfer ops after convolution */ - srcf = convImage; - dest = (GLchan *) texDestAddr - + (dstZoffset + img) * (dstImageStride / sizeof(GLchan)) - + dstYoffset * (dstRowStride / sizeof(GLchan)); - for (row = 0; row < convHeight; row++) { - _mesa_pack_rgba_span_float(ctx, convWidth, - (const GLfloat (*)[4]) srcf, - texDestFormat, CHAN_TYPE, - dest, &_mesa_native_packing, - transferOps - & IMAGE_POST_CONVOLUTION_BITS); - srcf += convWidth * 4; - dest += (dstRowStride / sizeof(GLchan)); + +GLboolean +_mesa_texstore_rgb888(STORE_PARAMS) +{ + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + + ASSERT(dstFormat == &_mesa_texformat_rgb888); + ASSERT(dstFormat->TexelBytes == 3); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_RGB && + srcFormat == GL_BGR && + srcType == GL_UNSIGNED_BYTE && + littleEndian) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + srcFormat == GL_RGBA && + srcType == GL_UNSIGNED_BYTE) { + /* extract RGB from RGBA */ + int img, row, col; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + for (img = 0; img < srcDepth; img++) { + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = srcRow[col * 4 + BCOMP]; + dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP]; + dstRow[col * 3 + 2] = srcRow[col * 4 + RCOMP]; } + dstRow += dstRowStride; + srcRow += srcRowStride; } - - FREE(convImage); - FREE(tmpImage); + dstImage += dstImageStride; } - else { - /* - * no convolution - */ - GLint img, row; - GLchan *dest = (GLchan *) texDestAddr - + dstZoffset * (dstImageStride / sizeof(GLchan)) - + dstYoffset * (dstRowStride / sizeof(GLchan)) - + 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_color_span_chan(ctx, srcWidth, texDestFormat, - destRow, srcFormat, srcType, srcRow, - srcPacking, transferOps); - destRow += (dstRowStride / sizeof(GLchan)); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = (const GLchan *) tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { +#if 0 + if (littleEndian) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]); + dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]); + dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]); + srcUB += 3; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = srcUB[BCOMP]; + dstRow[col * 3 + 1] = srcUB[GCOMP]; + dstRow[col * 3 + 2] = srcUB[RCOMP]; + srcUB += 3; + } } - dest += dstImageStride / sizeof(GLchan); +#else + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[BCOMP]); + dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]); + dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[RCOMP]); + src += 3; + } +#endif + dstRow += dstRowStride; } + dstImage += dstImageStride; } + _mesa_free((void *) tempImage); } + return GL_TRUE; } - -/* - * Transfer a texture image from user space to applying all - * needed image transfer operations and storing the result in the format - * specified by . may be any format from texformat.h. - * \param - * dimensions - 1, 2 or 3 - * baseInternalFormat - base format of the internal texture format - * specified by the user. This is very important, see below. - * dstFormat - destination image format - * dstAddr - destination address - * srcWidth, srcHeight, srcDepth - size of source iamge - * dstX/Y/Zoffset - as specified by glTexSubImage - * dstRowStride - stride between dest rows in bytes - * dstImageStride - stride between dest images in bytes - * srcFormat, srcType - incoming image format and data type - * srcAddr - source image address - * srcPacking - packing params of source image - * - * XXX this function is a bit more complicated than it should be. If - * _mesa_convert_texsubimage[123]d could handle any dest/source formats - * or if transfer_teximage() could store in any MESA_FORMAT_* format, we - * could simplify things here. - */ -void -_mesa_transfer_teximage(GLcontext *ctx, GLuint dimensions, - GLenum baseInternalFormat, - const struct gl_texture_format *dstFormat, - GLvoid *dstAddr, - 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) +GLboolean +_mesa_texstore_bgr888(STORE_PARAMS) { - const GLint dstRowStridePixels = dstRowStride / dstFormat->TexelBytes; - const GLint dstImageStridePixels = dstImageStride / dstFormat->TexelBytes; - GLboolean makeTemp; - GLuint transferOps = ctx->_ImageTransferState; - GLboolean freeSourceData = GL_FALSE; - GLint postConvWidth = srcWidth, postConvHeight = srcHeight; + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + + ASSERT(dstFormat == &_mesa_texformat_bgr888); + ASSERT(dstFormat->TexelBytes == 3); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_RGB && + srcFormat == GL_RGB && + srcType == GL_UNSIGNED_BYTE && + littleEndian) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + srcFormat == GL_RGBA && + srcType == GL_UNSIGNED_BYTE) { + /* extract BGR from RGBA */ + int img, row, col; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + for (img = 0; img < srcDepth; img++) { + const GLint srcRowStride = _mesa_image_row_stride(srcPacking, + srcWidth, srcFormat, srcType); + GLubyte *srcRow = (GLubyte *) _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, 0, 0); + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = srcRow[col * 4 + RCOMP]; + dstRow[col * 3 + 1] = srcRow[col * 4 + GCOMP]; + dstRow[col * 3 + 2] = srcRow[col * 4 + BCOMP]; + } + dstRow += dstRowStride; + srcRow += srcRowStride; + } + dstImage += dstImageStride; + } + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = (const GLchan *) tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col * 3 + 0] = CHAN_TO_UBYTE(src[RCOMP]); + dstRow[col * 3 + 1] = CHAN_TO_UBYTE(src[GCOMP]); + dstRow[col * 3 + 2] = CHAN_TO_UBYTE(src[BCOMP]); + src += 3; + } + dstRow += dstRowStride; + } + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} - assert(baseInternalFormat > 0); - ASSERT(baseInternalFormat == GL_LUMINANCE || - baseInternalFormat == GL_INTENSITY || - baseInternalFormat == GL_LUMINANCE_ALPHA || - baseInternalFormat == GL_ALPHA || - baseInternalFormat == GL_RGB || - baseInternalFormat == GL_RGBA || - baseInternalFormat == GL_YCBCR_MESA || - baseInternalFormat == GL_COLOR_INDEX || - baseInternalFormat == GL_DEPTH_COMPONENT); - if (transferOps & IMAGE_CONVOLUTION_BIT) { - _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth, - &postConvHeight); +GLboolean +_mesa_texstore_argb4444(STORE_PARAMS) +{ + ASSERT(dstFormat == &_mesa_texformat_argb4444 || + dstFormat == &_mesa_texformat_argb4444_rev); + ASSERT(dstFormat->TexelBytes == 2); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb4444 && + baseInternalFormat == GL_RGBA && + srcFormat == GL_BGRA && + srcType == GL_UNSIGNED_SHORT_4_4_4_4_REV) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); } - - /* - * Consider this scenario: The user's source image is GL_RGB and the - * requested internal format is GL_LUMINANCE. Now suppose the device - * driver doesn't support GL_LUMINANCE and instead uses RGB16 as the - * texture format. In that case we still need to do an intermediate - * conversion to luminance format so that the incoming red channel gets - * replicated into the dest red, green and blue channels. The following - * code takes care of that. - */ - if (dstFormat->BaseFormat != baseInternalFormat) { - /* Allocate storage for temporary image in the baseInternalFormat */ - const GLint texelSize = _mesa_components_in_format(baseInternalFormat) - * sizeof(GLchan); - const GLint bytes = texelSize * postConvWidth * postConvHeight *srcDepth; - const GLint tmpRowStride = texelSize * postConvWidth; - const GLint tmpImgStride = texelSize * postConvWidth * postConvHeight; - GLvoid *tmpImage = MALLOC(bytes); - if (!tmpImage) - return; - transfer_teximage(ctx, dimensions, baseInternalFormat, tmpImage, - srcWidth, srcHeight, srcDepth, - 0, 0, 0, /* x/y/zoffset */ - tmpRowStride, tmpImgStride, - srcFormat, srcType, srcAddr, srcPacking, transferOps); - - /* this is our new source image */ - srcWidth = postConvWidth; - srcHeight = postConvHeight; - srcFormat = baseInternalFormat; - srcType = CHAN_TYPE; - srcAddr = tmpImage; - srcPacking = &_mesa_native_packing; - freeSourceData = GL_TRUE; - transferOps = 0; /* image transfer ops were completed */ - } - - /* Let the optimized tex conversion functions take a crack at the - * image conversion if the dest format is a h/w format. - */ - if (_mesa_is_hardware_tex_format(dstFormat)) { - if (transferOps) { - makeTemp = GL_TRUE; + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLushort *dstUS = (GLushort *) dstRow; + if (dstFormat == &_mesa_texformat_argb4444) { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_4444( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_4444_REV( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; + } + } + dstRow += dstRowStride; + } + dstImage += dstImageStride; } - else { - if (dimensions == 1) { - makeTemp = !_mesa_convert_texsubimage1d(dstFormat->MesaFormat, - dstXoffset, - srcWidth, - srcFormat, srcType, - srcPacking, srcAddr, - dstAddr); + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + + +GLboolean +_mesa_texstore_argb1555(STORE_PARAMS) +{ + ASSERT(dstFormat == &_mesa_texformat_argb1555 || + dstFormat == &_mesa_texformat_argb1555_rev); + ASSERT(dstFormat->TexelBytes == 2); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_argb1555 && + baseInternalFormat == GL_RGBA && + srcFormat == GL_BGRA && + srcType == GL_UNSIGNED_SHORT_1_5_5_5_REV) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src =tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLushort *dstUS = (GLushort *) dstRow; + if (dstFormat == &_mesa_texformat_argb1555) { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_1555( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; + } + } + else { + for (col = 0; col < srcWidth; col++) { + dstUS[col] = PACK_COLOR_1555_REV( CHAN_TO_UBYTE(src[ACOMP]), + CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 4; + } + } + dstRow += dstRowStride; } - else if (dimensions == 2) { - makeTemp = !_mesa_convert_texsubimage2d(dstFormat->MesaFormat, - dstXoffset, dstYoffset, - srcWidth, srcHeight, - dstRowStridePixels, - srcFormat, srcType, - srcPacking, srcAddr, - dstAddr); + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +GLboolean +_mesa_texstore_al88(STORE_PARAMS) +{ + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + + ASSERT(dstFormat == &_mesa_texformat_al88 || + dstFormat == &_mesa_texformat_al88_rev); + ASSERT(dstFormat->TexelBytes == 2); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + dstFormat == &_mesa_texformat_al88 && + baseInternalFormat == GL_LUMINANCE_ALPHA && + srcFormat == GL_LUMINANCE_ALPHA && + srcType == GL_UNSIGNED_BYTE && + littleEndian) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLushort *dstUS = (GLushort *) dstRow; + if (dstFormat == &_mesa_texformat_al88) { + for (col = 0; col < srcWidth; col++) { + /* src[0] is luminance, src[1] is alpha */ + dstUS[col] = PACK_COLOR_88( CHAN_TO_UBYTE(src[1]), + CHAN_TO_UBYTE(src[0]) ); + src += 2; + } + } + else { + for (col = 0; col < srcWidth; col++) { + /* src[0] is luminance, src[1] is alpha */ + dstUS[col] = PACK_COLOR_88_REV( CHAN_TO_UBYTE(src[1]), + CHAN_TO_UBYTE(src[0]) ); + src += 2; + } + } + dstRow += dstRowStride; } - else { - assert(dimensions == 3); - makeTemp = !_mesa_convert_texsubimage3d(dstFormat->MesaFormat, - dstXoffset, dstYoffset, dstZoffset, - srcWidth, srcHeight, srcDepth, - dstRowStridePixels, dstImageStridePixels, - srcFormat, srcType, - srcPacking, srcAddr, dstAddr); + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +GLboolean +_mesa_texstore_rgb332(STORE_PARAMS) +{ + ASSERT(dstFormat == &_mesa_texformat_rgb332); + ASSERT(dstFormat->TexelBytes == 1); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == GL_RGB && + srcFormat == GL_RGB && srcType == GL_UNSIGNED_BYTE_3_3_2) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col] = PACK_COLOR_332( CHAN_TO_UBYTE(src[RCOMP]), + CHAN_TO_UBYTE(src[GCOMP]), + CHAN_TO_UBYTE(src[BCOMP]) ); + src += 3; + } + dstRow += dstRowStride; } - if (!makeTemp) { - /* all done! */ - if (freeSourceData) - FREE((void *) srcAddr); - return; + dstImage += dstImageStride; + } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +/** + * Texstore for _mesa_texformat_a8, _mesa_texformat_l8, _mesa_texformat_i8. + */ +GLboolean +_mesa_texstore_a8(STORE_PARAMS) +{ + ASSERT(dstFormat == &_mesa_texformat_a8 || + dstFormat == &_mesa_texformat_l8 || + dstFormat == &_mesa_texformat_i8); + ASSERT(dstFormat->TexelBytes == 1); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == srcFormat && + srcType == GL_UNSIGNED_BYTE) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLchan *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row, col; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + for (col = 0; col < srcWidth; col++) { + dstRow[col] = CHAN_TO_UBYTE(src[col]); + } + dstRow += dstRowStride; + src += srcWidth; } + dstImage += dstImageStride; } + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + + +GLboolean +_mesa_texstore_ci8(STORE_PARAMS) +{ + (void) dims; (void) baseInternalFormat; + ASSERT(dstFormat == &_mesa_texformat_ci8); + ASSERT(dstFormat->TexelBytes == 1); + ASSERT(baseInternalFormat == GL_COLOR_INDEX); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + srcFormat == GL_COLOR_INDEX && + srcType == GL_UNSIGNED_BYTE) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); } else { - /* software texture format */ - makeTemp = GL_FALSE; - } - - if (makeTemp) { - GLint postConvWidth = srcWidth, postConvHeight = srcHeight; - GLenum tmpFormat; - GLuint tmpComps, tmpTexelSize; - GLint tmpRowStride, tmpImageStride; - GLubyte *tmpImage; - - if (transferOps & IMAGE_CONVOLUTION_BIT) { - _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth, - &postConvHeight); - } - - tmpFormat = dstFormat->BaseFormat; - tmpComps = _mesa_components_in_format(tmpFormat); - tmpTexelSize = tmpComps * sizeof(GLchan); - tmpRowStride = postConvWidth * tmpTexelSize; - tmpImageStride = postConvWidth * postConvHeight * tmpTexelSize; - tmpImage = (GLubyte *) MALLOC(postConvWidth * postConvHeight * - srcDepth * tmpTexelSize); - if (!tmpImage) { - if (freeSourceData) - FREE((void *) srcAddr); - return; + /* general path */ + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row; + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + const GLvoid *src = _mesa_image_address(dims, srcPacking, + srcAddr, srcWidth, srcHeight, srcFormat, srcType, img, row, 0); + _mesa_unpack_index_span(ctx, srcWidth, GL_UNSIGNED_BYTE, dstRow, + srcType, src, srcPacking, + ctx->_ImageTransferState); + dstRow += dstRowStride; + } + dstImage += dstImageStride; } + } + return GL_TRUE; +} + - transfer_teximage(ctx, dimensions, tmpFormat, tmpImage, - srcWidth, srcHeight, srcDepth, - 0, 0, 0, /* x/y/zoffset */ - tmpRowStride, tmpImageStride, - srcFormat, srcType, srcAddr, srcPacking, transferOps); - - if (freeSourceData) - FREE((void *) srcAddr); - - /* the temp image is our new source image */ - srcWidth = postConvWidth; - srcHeight = postConvHeight; - srcFormat = tmpFormat; - srcType = CHAN_TYPE; - srcAddr = tmpImage; - srcPacking = &_mesa_native_packing; - freeSourceData = GL_TRUE; - } - - if (_mesa_is_hardware_tex_format(dstFormat)) { - assert(makeTemp); - if (dimensions == 1) { - GLboolean b; - b = _mesa_convert_texsubimage1d(dstFormat->MesaFormat, - dstXoffset, - srcWidth, - srcFormat, srcType, - srcPacking, srcAddr, - dstAddr); - assert(b); - (void) b; - } - else if (dimensions == 2) { - GLboolean b; - b = _mesa_convert_texsubimage2d(dstFormat->MesaFormat, - dstXoffset, dstYoffset, - srcWidth, srcHeight, - dstRowStridePixels, - srcFormat, srcType, - srcPacking, srcAddr, - dstAddr); - assert(b); - (void) b; +/** + * Texstore for _mesa_texformat_ycbcr or _mesa_texformat_ycbcr_rev. + */ +GLboolean +_mesa_texstore_ycbcr(STORE_PARAMS) +{ + const GLuint ui = 1; + const GLubyte littleEndian = *((const GLubyte *) &ui); + (void) ctx; (void) dims; (void) baseInternalFormat; + + ASSERT((dstFormat == &_mesa_texformat_ycbcr) || + (dstFormat == &_mesa_texformat_ycbcr_rev)); + ASSERT(dstFormat->TexelBytes == 2); + ASSERT(ctx->Extensions.MESA_ycbcr_texture); + ASSERT(srcFormat == GL_YCBCR_MESA); + ASSERT((srcType == GL_UNSIGNED_SHORT_8_8_MESA) || + (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA)); + ASSERT(baseInternalFormat == GL_YCBCR_MESA); + + /* always just memcpy since no pixel transfer ops apply */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + + /* Check if we need byte swapping */ + /* XXX the logic here _might_ be wrong */ + if (srcPacking->SwapBytes ^ + (srcType == GL_UNSIGNED_SHORT_8_8_REV_MESA) ^ + (dstFormat == &_mesa_texformat_ycbcr_rev) ^ + !littleEndian) { + GLushort *pImage = (GLushort *) ((GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes); + GLint img, row; + for (img = 0; img < srcDepth; img++) { + GLushort *pRow = pImage; + for (row = 0; row < srcHeight; row++) { + _mesa_swap2(pRow, srcWidth); + pRow += dstRowStride; + } + pImage += dstImageStride; } - else { - GLboolean b; - b = _mesa_convert_texsubimage3d(dstFormat->MesaFormat, - dstXoffset, dstYoffset, dstZoffset, - srcWidth, srcHeight, srcDepth, - dstRowStridePixels, dstImageStridePixels, - srcFormat, srcType, - srcPacking, srcAddr, dstAddr); - assert(b); - (void) b; + } + return GL_TRUE; +} + + + + +/** + * Store an image in any of the formats: + * _mesa_texformat_rgba_float32 + * _mesa_texformat_rgb_float32 + * _mesa_texformat_alpha_float32 + * _mesa_texformat_luminance_float32 + * _mesa_texformat_luminance_alpha_float32 + * _mesa_texformat_intensity_float32 + */ +GLboolean +_mesa_texstore_rgba_float32(STORE_PARAMS) +{ + const GLint components = _mesa_components_in_format(baseInternalFormat); + + ASSERT(dstFormat == &_mesa_texformat_rgba_float32 || + dstFormat == &_mesa_texformat_rgb_float32 || + dstFormat == &_mesa_texformat_alpha_float32 || + dstFormat == &_mesa_texformat_luminance_float32 || + dstFormat == &_mesa_texformat_luminance_alpha_float32 || + dstFormat == &_mesa_texformat_intensity_float32); + ASSERT(baseInternalFormat == GL_RGBA || + baseInternalFormat == GL_RGB || + baseInternalFormat == GL_ALPHA || + baseInternalFormat == GL_LUMINANCE || + baseInternalFormat == GL_LUMINANCE_ALPHA || + baseInternalFormat == GL_INTENSITY); + ASSERT(dstFormat->TexelBytes == components * sizeof(GLfloat)); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == srcFormat && + srcType == GL_FLOAT) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); + } + else { + /* general path */ + const GLfloat *tempImage = make_temp_float_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLfloat *src = tempImage; + GLint bytesPerRow; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + bytesPerRow = srcWidth * components * sizeof(GLfloat); + for (img = 0; img < srcDepth; img++) { + GLubyte *dst = dstImage; + for (row = 0; row < srcHeight; row++) { + _mesa_memcpy(dst, src, bytesPerRow); + dst += dstRowStride; + src += srcWidth * components; + } + dstImage += dstImageStride; } + + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + +/** + * As above, but store 16-bit floats. + */ +GLboolean +_mesa_texstore_rgba_float16(STORE_PARAMS) +{ + const GLint components = _mesa_components_in_format(baseInternalFormat); + + ASSERT(dstFormat == &_mesa_texformat_rgba_float16 || + dstFormat == &_mesa_texformat_rgb_float16 || + dstFormat == &_mesa_texformat_alpha_float16 || + dstFormat == &_mesa_texformat_luminance_float16 || + dstFormat == &_mesa_texformat_luminance_alpha_float16 || + dstFormat == &_mesa_texformat_intensity_float16); + ASSERT(baseInternalFormat == GL_RGBA || + baseInternalFormat == GL_RGB || + baseInternalFormat == GL_ALPHA || + baseInternalFormat == GL_LUMINANCE || + baseInternalFormat == GL_LUMINANCE_ALPHA || + baseInternalFormat == GL_INTENSITY); + ASSERT(dstFormat->TexelBytes == components * sizeof(GLhalfARB)); + + if (!ctx->_ImageTransferState && + !srcPacking->SwapBytes && + baseInternalFormat == srcFormat && + srcType == GL_HALF_FLOAT_ARB) { + /* simple memcpy path */ + memcpy_texture(dims, + dstFormat, dstAddr, dstXoffset, dstYoffset, dstZoffset, + dstRowStride, dstImageStride, + srcWidth, srcHeight, srcDepth, srcFormat, srcType, + srcAddr, srcPacking); } else { - /* software format */ - assert(!makeTemp); - transfer_teximage(ctx, dimensions, dstFormat->BaseFormat, dstAddr, - srcWidth, srcHeight, srcDepth, - dstXoffset, dstYoffset, dstZoffset, - dstRowStride, dstImageStride, - srcFormat, srcType, srcAddr, srcPacking, transferOps); + /* general path */ + const GLfloat *tempImage = make_temp_float_image(ctx, dims, + baseInternalFormat, + dstFormat->BaseFormat, + srcWidth, srcHeight, srcDepth, + srcFormat, srcType, srcAddr, + srcPacking); + const GLfloat *src = tempImage; + GLubyte *dstImage = (GLubyte *) dstAddr + + dstZoffset * dstImageStride + + dstYoffset * dstRowStride + + dstXoffset * dstFormat->TexelBytes; + GLint img, row; + if (!tempImage) + return GL_FALSE; + _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight); + for (img = 0; img < srcDepth; img++) { + GLubyte *dstRow = dstImage; + for (row = 0; row < srcHeight; row++) { + GLhalfARB *dstTexel = (GLhalfARB *) dstRow; + GLint i; + for (i = 0; i < srcWidth * components; i++) { + dstTexel[i] = _mesa_float_to_half(src[i]); + } + dstRow += dstRowStride; + src += srcWidth * components; + } + dstImage += dstImageStride; + } + + _mesa_free((void *) tempImage); + } + return GL_TRUE; +} + + + +/** + * Check if an unpack PBO is active prior to fetching a texture image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! + */ +const GLvoid * +_mesa_validate_pbo_teximage(GLcontext *ctx, GLuint dimensions, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *unpack, + const char *funcName) +{ + GLubyte *buf; + + if (unpack->BufferObj->Name == 0) { + /* no PBO */ + return pixels; + } + if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, + format, type, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access"); + return NULL; + } + + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, unpack->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); + return NULL; } - if (freeSourceData) - FREE((void *) srcAddr); /* the temp image */ + return ADD_POINTERS(buf, pixels); } - /** - * Given a user's uncompressed texture image, this function takes care of - * pixel unpacking, pixel transfer, format conversion and compression. + * Check if an unpack PBO is active prior to fetching a compressed texture + * image. + * If so, do bounds checking and map the buffer into main memory. + * Any errors detected will be recorded. + * The caller _must_ call _mesa_unmap_teximage_pbo() too! */ -static void -transfer_compressed_teximage(GLcontext *ctx, GLuint dimensions, - GLsizei width, GLsizei height, GLsizei depth, - GLenum srcFormat, GLenum srcType, - const struct gl_pixelstore_attrib *unpacking, - const GLvoid *source, - const struct gl_texture_format *dstFormat, - GLubyte *dest, - GLint dstRowStride) +const GLvoid * +_mesa_validate_pbo_compressed_teximage(GLcontext *ctx, + GLsizei imageSize, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + const char *funcName) { - GLchan *tempImage = NULL; - GLint srcRowStride; - GLenum baseFormat; - - ASSERT(dimensions == 2); - /* TexelBytes is zero if and only if it's a compressed format */ - ASSERT(dstFormat->TexelBytes == 0); - - baseFormat = dstFormat->BaseFormat; + GLubyte *buf; - if (srcFormat != baseFormat || srcType != CHAN_TYPE || - ctx->_ImageTransferState != 0 || unpacking->SwapBytes) { - /* need to convert user's image to texImage->Format, GLchan */ - GLint comps = components_in_intformat(baseFormat); - GLint postConvWidth = width, postConvHeight = height; - - /* XXX convolution untested */ - if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { - _mesa_adjust_image_for_convolution(ctx, dimensions, &postConvWidth, - &postConvHeight); - } - - tempImage = (GLchan*) MALLOC(width * height * comps * sizeof(GLchan)); - if (!tempImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); - return; - } - transfer_teximage(ctx, dimensions, - baseFormat, /* dest format */ - tempImage, /* dst address */ - width, height, depth, /* src size */ - 0, 0, 0, /* x/y/zoffset */ - comps * width, /* dst row stride */ - comps * width * height, /* dst image stride */ - srcFormat, srcType, /* src format, type */ - source, unpacking, /* src and src packing */ - ctx->_ImageTransferState); - source = tempImage; - width = postConvWidth; - height = postConvHeight; - srcRowStride = width; + if (packing->BufferObj->Name == 0) { + /* not using a PBO - return pointer unchanged */ + return pixels; } - else { - if (unpacking->RowLength) - srcRowStride = unpacking->RowLength; - else - srcRowStride = width; + if ((const GLubyte *) pixels + imageSize > + (const GLubyte *) packing->BufferObj->Size) { + /* out of bounds read! */ + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(invalid PBO access"); + return NULL; } - _mesa_compress_teximage(ctx, width, height, baseFormat, - (const GLchan *) source, srcRowStride, - dstFormat, dest, dstRowStride); - if (tempImage) { - FREE(tempImage); + buf = (GLubyte*) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + GL_READ_ONLY_ARB, packing->BufferObj); + if (!buf) { + _mesa_error(ctx, GL_INVALID_OPERATION, funcName, "(PBO is mapped"); + return NULL; } + + return ADD_POINTERS(buf, pixels); } +/** + * This function must be called after either of the validate_pbo_*_teximage() + * functions. It unmaps the PBO buffer if it was mapped earlier. + */ +void +_mesa_unmap_teximage_pbo(GLcontext *ctx, const struct gl_pixelstore_attrib *unpack) +{ + if (unpack->BufferObj->Name) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } +} + /* * This is the software fallback for Driver.TexImage1D() - * and Driver.CopyTexImage2D(). - * The texture image type will be GLchan. - * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY, - * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA. + * and Driver.CopyTexImage1D(). + * \sa _mesa_store_teximage2d() */ void _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level, @@ -758,7 +2163,8 @@ _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_image *texImage) { GLint postConvWidth = width; - GLint texelBytes, sizeInBytes; + GLint sizeInBytes; + (void) border; if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL); @@ -766,46 +2172,45 @@ _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level, /* choose the texture format */ assert(ctx->Driver.ChooseTextureFormat); - texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx, - internalFormat, format, type); + texImage->TexFormat = ctx->Driver.ChooseTextureFormat(ctx, internalFormat, + format, type); assert(texImage->TexFormat); texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D; texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df; - texelBytes = texImage->TexFormat->TexelBytes; - /* allocate memory */ if (texImage->IsCompressed) sizeInBytes = texImage->CompressedSize; else - sizeInBytes = postConvWidth * texelBytes; + sizeInBytes = postConvWidth * texImage->TexFormat->TexelBytes; texImage->Data = MESA_PBUFFER_ALLOC(sizeInBytes); if (!texImage->Data) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); return; } - if (!pixels) + pixels = _mesa_validate_pbo_teximage(ctx, 1, width, 1, 1, format, type, pixels, + packing, "glTexImage1D"); + if (!pixels) { + /* Note: we check for a NULL image pointer here, _after_ we allocated + * memory for the texture. That's what the GL spec calls for. + */ return; - - /* unpack image, apply transfer ops and store in texImage->Data */ - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - width); - transfer_compressed_teximage(ctx, 1, width, 1, 1, - format, type, packing, - pixels, texImage->TexFormat, - (GLubyte *) texImage->Data, dstRowStride); } else { - _mesa_transfer_teximage(ctx, 1, - texImage->Format, /* base format */ - texImage->TexFormat, texImage->Data, - width, 1, 1, /* src size */ - 0, 0, 0, /* dstX/Y/Zoffset */ - 0, /* dstRowStride */ - 0, /* dstImageStride */ - format, type, pixels, packing); + const GLint dstRowStride = 0, dstImageStride = 0; + GLboolean success; + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 1, texImage->Format, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, dstImageStride, + width, 1, 1, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + } } /* GL_SGIS_generate_mipmap */ @@ -814,15 +2219,24 @@ _mesa_store_teximage1d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } + + _mesa_unmap_teximage_pbo(ctx, packing); } -/* +/** * This is the software fallback for Driver.TexImage2D() * and Driver.CopyTexImage2D(). - * The texture image type will be GLchan. - * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY, - * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA. + * We store the image in heap memory. We know nothing about on-board + * VRAM here. But since most DRI drivers rely on keeping a copy of all + * textures in main memory, this routine will typically be used by + * hardware drivers too. + * + * Reasons why a driver might override this function: + * - Special memory allocation needs (VRAM, AGP, etc) + * - Unusual row/image strides or padding + * - Special housekeeping + * - Using VRAM-based Pixel Buffer Objects */ void _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level, @@ -835,6 +2249,7 @@ _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level, { GLint postConvWidth = width, postConvHeight = height; GLint texelBytes, sizeInBytes; + (void) border; if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth, @@ -862,27 +2277,34 @@ _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level, return; } - if (!pixels) + pixels = _mesa_validate_pbo_teximage(ctx, 2, width, height, 1, format, type, + pixels, packing, "glTexImage2D"); + if (!pixels) { + /* Note: we check for a NULL image pointer here, _after_ we allocated + * memory for the texture. That's what the GL spec calls for. + */ return; - - /* unpack image, apply transfer ops and store in texImage->Data */ - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - width); - transfer_compressed_teximage(ctx, 2, width, height, 1, - format, type, packing, - pixels, texImage->TexFormat, - (GLubyte *) texImage->Data, dstRowStride); } else { - _mesa_transfer_teximage(ctx, 2, - texImage->Format, - texImage->TexFormat, texImage->Data, - width, height, 1, /* src size */ - 0, 0, 0, /* dstX/Y/Zoffset */ - texImage->Width * texelBytes, /* dstRowStride */ - 0, /* dstImageStride */ - format, type, pixels, packing); + GLint dstRowStride, dstImageStride = 0; + GLboolean success; + if (texImage->IsCompressed) { + dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,width); + } + else { + dstRowStride = postConvWidth * texImage->TexFormat->TexelBytes; + } + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 2, texImage->Format, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, dstImageStride, + width, height, 1, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + } } /* GL_SGIS_generate_mipmap */ @@ -891,16 +2313,16 @@ _mesa_store_teximage2d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } + + _mesa_unmap_teximage_pbo(ctx, packing); } -/* +/** * This is the software fallback for Driver.TexImage3D() * and Driver.CopyTexImage3D(). - * The texture image type will be GLchan. - * The texture image format will be GL_COLOR_INDEX, GL_INTENSITY, - * GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_RGB or GL_RGBA. + * \sa _mesa_store_teximage2d() */ void _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level, @@ -912,6 +2334,7 @@ _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_image *texImage) { GLint texelBytes, sizeInBytes; + (void) border; /* choose the texture format */ assert(ctx->Driver.ChooseTextureFormat); @@ -934,27 +2357,36 @@ _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level, return; } - if (!pixels) + pixels = _mesa_validate_pbo_teximage(ctx, 3, width, height, depth, format, type, + pixels, packing, "glTexImage3D"); + if (!pixels) { + /* Note: we check for a NULL image pointer here, _after_ we allocated + * memory for the texture. That's what the GL spec calls for. + */ return; - - /* unpack image, apply transfer ops and store in texImage->Data */ - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - width); - transfer_compressed_teximage(ctx, 3, width, height, depth, - format, type, packing, - pixels, texImage->TexFormat, - (GLubyte *) texImage->Data, dstRowStride); } else { - _mesa_transfer_teximage(ctx, 3, - texImage->Format, - texImage->TexFormat, texImage->Data, - width, height, depth, /* src size */ - 0, 0, 0, /* dstX/Y/Zoffset */ - texImage->Width * texelBytes, /* dstRowStride */ - texImage->Width * texImage->Height * texelBytes, - format, type, pixels, packing); + GLint dstRowStride, dstImageStride; + GLboolean success; + if (texImage->IsCompressed) { + dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat,width); + dstImageStride = 0; + } + else { + dstRowStride = width * texImage->TexFormat->TexelBytes; + dstImageStride = dstRowStride * height; + } + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 3, texImage->Format, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, dstImageStride, + width, height, depth, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D"); + } } /* GL_SGIS_generate_mipmap */ @@ -963,6 +2395,8 @@ _mesa_store_teximage3d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } + + _mesa_unmap_teximage_pbo(ctx, packing); } @@ -980,30 +2414,25 @@ _mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - texImage->Width); - GLubyte *dest = _mesa_compressed_image_address(xoffset, 0, 0, - texImage->IntFormat, - texImage->Width, - (GLubyte*) texImage->Data); - transfer_compressed_teximage(ctx, 1, /* dimensions */ - width, 1, 1, /* size to replace */ - format, type, /* source format/type */ - packing, /* source packing */ - pixels, /* source data */ - texImage->TexFormat,/* dest format */ - dest, dstRowStride); - } - else { - _mesa_transfer_teximage(ctx, 1, - texImage->Format, - texImage->TexFormat, texImage->Data, - width, 1, 1, /* src size */ - xoffset, 0, 0, /* dest offsets */ - 0, /* dstRowStride */ - 0, /* dstImageStride */ - format, type, pixels, packing); + pixels = _mesa_validate_pbo_teximage(ctx, 1, width, 1, 1, format, type, pixels, + packing, "glTexSubImage1D"); + if (!pixels) + return; + + { + const GLint dstRowStride = 0, dstImageStride = 0; + GLboolean success; + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 1, texImage->Format, + texImage->TexFormat, + texImage->Data, + xoffset, 0, 0, /* offsets */ + dstRowStride, dstImageStride, + width, 1, 1, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); + } } /* GL_SGIS_generate_mipmap */ @@ -1012,11 +2441,13 @@ _mesa_store_texsubimage1d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } + + _mesa_unmap_teximage_pbo(ctx, packing); } -/* +/** * This is the software fallback for Driver.TexSubImage2D() * and Driver.CopyTexSubImage2D(). */ @@ -1029,30 +2460,32 @@ _mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - texImage->Width); - GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, 0, - texImage->IntFormat, - texImage->Width, - (GLubyte*) texImage->Data); - transfer_compressed_teximage(ctx, 2, /* dimensions */ - width, height, 1, /* size to replace */ - format, type, /* source format/type */ - packing, /* source packing */ - pixels, /* source data */ - texImage->TexFormat,/* dest format */ - dest, dstRowStride); - } - else { - _mesa_transfer_teximage(ctx, 2, - texImage->Format, - texImage->TexFormat, texImage->Data, - width, height, 1, /* src size */ - xoffset, yoffset, 0, /* dest offsets */ - texImage->Width *texImage->TexFormat->TexelBytes, - 0, /* dstImageStride */ - format, type, pixels, packing); + pixels = _mesa_validate_pbo_teximage(ctx, 2, width, height, 1, format, type, + pixels, packing, "glTexSubImage2D"); + if (!pixels) + return; + + { + GLint dstRowStride = 0, dstImageStride = 0; + GLboolean success; + if (texImage->IsCompressed) { + dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, + texImage->Width); + } + else { + dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes; + } + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 2, texImage->Format, + texImage->TexFormat, + texImage->Data, + xoffset, yoffset, 0, + dstRowStride, dstImageStride, + width, height, 1, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); + } } /* GL_SGIS_generate_mipmap */ @@ -1061,6 +2494,8 @@ _mesa_store_texsubimage2d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } + + _mesa_unmap_teximage_pbo(ctx, packing); } @@ -1077,31 +2512,34 @@ _mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { - if (texImage->IsCompressed) { - GLint dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, - texImage->Width); - GLubyte *dest = _mesa_compressed_image_address(xoffset, yoffset, zoffset, - texImage->IntFormat, - texImage->Width, - (GLubyte*) texImage->Data); - transfer_compressed_teximage(ctx, 3, /* dimensions */ - width, height, depth,/* size to replace */ - format, type, /* source format/type */ - packing, /* source packing */ - pixels, /* source data */ - texImage->TexFormat,/* dest format */ - dest, dstRowStride); - } - else { - const GLint texelBytes = texImage->TexFormat->TexelBytes; - _mesa_transfer_teximage(ctx, 3, - texImage->Format, - texImage->TexFormat, texImage->Data, - width, height, depth, /* src size */ - xoffset, yoffset, zoffset, /* dest offsets */ - texImage->Width * texelBytes, /* dst row stride */ - texImage->Width * texImage->Height * texelBytes, - format, type, pixels, packing); + pixels = _mesa_validate_pbo_teximage(ctx, 3, width, height, depth, format, type, + pixels, packing, "glTexSubImage3D"); + if (!pixels) + return; + + { + GLint dstRowStride, dstImageStride; + GLboolean success; + if (texImage->IsCompressed) { + dstRowStride = _mesa_compressed_row_stride(texImage->IntFormat, + texImage->Width); + dstImageStride = 0; /* XXX fix */ + } + else { + dstRowStride = texImage->Width * texImage->TexFormat->TexelBytes; + dstImageStride = dstRowStride * texImage->Height; + } + ASSERT(texImage->TexFormat->StoreImage); + success = texImage->TexFormat->StoreImage(ctx, 3, texImage->Format, + texImage->TexFormat, + texImage->Data, + xoffset, yoffset, zoffset, + dstRowStride, dstImageStride, + width, height, depth, + format, type, pixels, packing); + if (!success) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage3D"); + } } /* GL_SGIS_generate_mipmap */ @@ -1110,9 +2548,9 @@ _mesa_store_texsubimage3d(GLcontext *ctx, GLenum target, GLint level, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } -} - + _mesa_unmap_teximage_pbo(ctx, packing); +} /* @@ -1127,6 +2565,13 @@ _mesa_store_compressed_teximage1d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_image *texImage) { /* this space intentionally left blank */ + (void) ctx; + (void) target; (void) level; + (void) internalFormat; + (void) width; (void) border; + (void) imageSize; (void) data; + (void) texObj; + (void) texImage; } @@ -1142,6 +2587,8 @@ _mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { + (void) width; (void) height; (void) border; + /* This is pretty simple, basically just do a memcpy without worrying * about the usual image unpacking or image transfer operations. */ @@ -1167,9 +2614,23 @@ _mesa_store_compressed_teximage2d(GLcontext *ctx, GLenum target, GLint level, return; } + data = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, data, &ctx->Unpack, + "glCompressedTexImage2D"); + if (!data) + return; + /* copy the data */ ASSERT(texImage->CompressedSize == (GLuint) imageSize); MEMCPY(texImage->Data, data, imageSize); + + /* GL_SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + _mesa_generate_mipmap(ctx, target, + &ctx->Texture.Unit[ctx->Texture.CurrentUnit], + texObj); + } + + _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack); } @@ -1187,6 +2648,14 @@ _mesa_store_compressed_teximage3d(GLcontext *ctx, GLenum target, GLint level, struct gl_texture_image *texImage) { /* this space intentionally left blank */ + (void) ctx; + (void) target; (void) level; + (void) internalFormat; + (void) width; (void) height; (void) depth; + (void) border; + (void) imageSize; (void) data; + (void) texObj; + (void) texImage; } @@ -1204,6 +2673,13 @@ _mesa_store_compressed_texsubimage1d(GLcontext *ctx, GLenum target, struct gl_texture_image *texImage) { /* this space intentionally left blank */ + (void) ctx; + (void) target; (void) level; + (void) xoffset; (void) width; + (void) format; + (void) imageSize; (void) data; + (void) texObj; + (void) texImage; } @@ -1224,6 +2700,7 @@ _mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target, GLint i, rows; GLubyte *dest; const GLubyte *src; + (void) format; /* these should have been caught sooner */ ASSERT((width & 3) == 0 || width == 2 || width == 1); @@ -1231,6 +2708,11 @@ _mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target, ASSERT((xoffset & 3) == 0); ASSERT((yoffset & 3) == 0); + data = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, data, &ctx->Unpack, + "glCompressedTexSubImage2D"); + if (!data) + return; + srcRowStride = _mesa_compressed_row_stride(texImage->IntFormat, width); src = (const GLubyte *) data; @@ -1249,6 +2731,15 @@ _mesa_store_compressed_texsubimage2d(GLcontext *ctx, GLenum target, dest += destRowStride; src += srcRowStride; } + + /* GL_SGIS_generate_mipmap */ + if (level == texObj->BaseLevel && texObj->GenerateMipmap) { + _mesa_generate_mipmap(ctx, target, + &ctx->Texture.Unit[ctx->Texture.CurrentUnit], + texObj); + } + + _mesa_unmap_teximage_pbo(ctx, &ctx->Unpack); } @@ -1266,6 +2757,14 @@ _mesa_store_compressed_texsubimage3d(GLcontext *ctx, GLenum target, struct gl_texture_image *texImage) { /* this space intentionally left blank */ + (void) ctx; + (void) target; (void) level; + (void) xoffset; (void) yoffset; (void) zoffset; + (void) width; (void) height; (void) depth; + (void) format; + (void) imageSize; (void) data; + (void) texObj; + (void) texImage; } @@ -1327,7 +2826,6 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, case MESA_FORMAT_ALPHA: case MESA_FORMAT_LUMINANCE: case MESA_FORMAT_INTENSITY: - case MESA_FORMAT_COLOR_INDEX: { GLuint i, j, k; const GLchan *rowA = (const GLchan *) srcRowA; @@ -1354,7 +2852,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } } return; - case MESA_FORMAT_DEPTH_COMPONENT: + case MESA_FORMAT_DEPTH_COMPONENT_FLOAT32: { GLuint i, j, k; const GLfloat *rowA = (const GLfloat *) srcRowA; @@ -1366,9 +2864,23 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } } return; + case MESA_FORMAT_DEPTH_COMPONENT16: + { + GLuint i, j, k; + const GLushort *rowA = (const GLushort *) srcRowA; + const GLushort *rowB = (const GLushort *) srcRowB; + GLushort *dst = (GLushort *) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4; + } + } + return; /* Begin hardware formats */ case MESA_FORMAT_RGBA8888: + case MESA_FORMAT_RGBA8888_REV: case MESA_FORMAT_ARGB8888: + case MESA_FORMAT_ARGB8888_REV: { GLuint i, j, k; const GLubyte (*rowA)[4] = (const GLubyte (*)[4]) srcRowA; @@ -1388,6 +2900,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } return; case MESA_FORMAT_RGB888: + case MESA_FORMAT_BGR888: { GLuint i, j, k; const GLubyte (*rowA)[3] = (const GLubyte (*)[3]) srcRowA; @@ -1405,6 +2918,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } return; case MESA_FORMAT_RGB565: + case MESA_FORMAT_RGB565_REV: { GLuint i, j, k; const GLushort *rowA = (const GLushort *) srcRowA; @@ -1432,6 +2946,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } return; case MESA_FORMAT_ARGB4444: + case MESA_FORMAT_ARGB4444_REV: { GLuint i, j, k; const GLushort *rowA = (const GLushort *) srcRowA; @@ -1464,6 +2979,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } return; case MESA_FORMAT_ARGB1555: + case MESA_FORMAT_ARGB1555_REV: /* XXX broken? */ { GLuint i, j, k; const GLushort *rowA = (const GLushort *) srcRowA; @@ -1496,6 +3012,7 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } return; case MESA_FORMAT_AL88: + case MESA_FORMAT_AL88_REV: { GLuint i, j, k; const GLubyte (*rowA)[2] = (const GLubyte (*)[2]) srcRowA; @@ -1552,6 +3069,148 @@ do_row(const struct gl_texture_format *format, GLint srcWidth, } } return; + case MESA_FORMAT_RGBA_FLOAT32: + { + GLuint i, j, k; + const GLfloat (*rowA)[4] = (const GLfloat (*)[4]) srcRowA; + const GLfloat (*rowB)[4] = (const GLfloat (*)[4]) srcRowB; + GLfloat (*dst)[4] = (GLfloat (*)[4]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + dst[i][2] = (rowA[j][2] + rowA[k][2] + + rowB[j][2] + rowB[k][2]) * 0.25F; + dst[i][3] = (rowA[j][3] + rowA[k][3] + + rowB[j][3] + rowB[k][3]) * 0.25F; + } + } + return; + case MESA_FORMAT_RGBA_FLOAT16: + { + GLuint i, j, k, comp; + const GLhalfARB (*rowA)[4] = (const GLhalfARB (*)[4]) srcRowA; + const GLhalfARB (*rowB)[4] = (const GLhalfARB (*)[4]) srcRowB; + GLhalfARB (*dst)[4] = (GLhalfARB (*)[4]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 4; comp++) { + GLfloat aj, ak, bj, bk; + aj = _mesa_half_to_float(rowA[j][comp]); + ak = _mesa_half_to_float(rowA[k][comp]); + bj = _mesa_half_to_float(rowB[j][comp]); + bk = _mesa_half_to_float(rowB[k][comp]); + dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + return; + case MESA_FORMAT_RGB_FLOAT32: + { + GLuint i, j, k; + const GLfloat (*rowA)[3] = (const GLfloat (*)[3]) srcRowA; + const GLfloat (*rowB)[3] = (const GLfloat (*)[3]) srcRowB; + GLfloat (*dst)[3] = (GLfloat (*)[3]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + dst[i][2] = (rowA[j][2] + rowA[k][2] + + rowB[j][2] + rowB[k][2]) * 0.25F; + } + } + return; + case MESA_FORMAT_RGB_FLOAT16: + { + GLuint i, j, k, comp; + const GLhalfARB (*rowA)[3] = (const GLhalfARB (*)[3]) srcRowA; + const GLhalfARB (*rowB)[3] = (const GLhalfARB (*)[3]) srcRowB; + GLhalfARB (*dst)[3] = (GLhalfARB (*)[3]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 3; comp++) { + GLfloat aj, ak, bj, bk; + aj = _mesa_half_to_float(rowA[j][comp]); + ak = _mesa_half_to_float(rowA[k][comp]); + bj = _mesa_half_to_float(rowB[j][comp]); + bk = _mesa_half_to_float(rowB[k][comp]); + dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + return; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32: + { + GLuint i, j, k; + const GLfloat (*rowA)[2] = (const GLfloat (*)[2]) srcRowA; + const GLfloat (*rowB)[2] = (const GLfloat (*)[2]) srcRowB; + GLfloat (*dst)[2] = (GLfloat (*)[2]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + } + } + return; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16: + { + GLuint i, j, k, comp; + const GLhalfARB (*rowA)[2] = (const GLhalfARB (*)[2]) srcRowA; + const GLhalfARB (*rowB)[2] = (const GLhalfARB (*)[2]) srcRowB; + GLhalfARB (*dst)[2] = (GLhalfARB (*)[2]) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 2; comp++) { + GLfloat aj, ak, bj, bk; + aj = _mesa_half_to_float(rowA[j][comp]); + ak = _mesa_half_to_float(rowA[k][comp]); + bj = _mesa_half_to_float(rowB[j][comp]); + bk = _mesa_half_to_float(rowB[k][comp]); + dst[i][comp] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + return; + case MESA_FORMAT_ALPHA_FLOAT32: + case MESA_FORMAT_LUMINANCE_FLOAT32: + case MESA_FORMAT_INTENSITY_FLOAT32: + { + GLuint i, j, k; + const GLfloat *rowA = (const GLfloat *) srcRowA; + const GLfloat *rowB = (const GLfloat *) srcRowB; + GLfloat *dst = (GLfloat *) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F; + } + } + return; + case MESA_FORMAT_ALPHA_FLOAT16: + case MESA_FORMAT_LUMINANCE_FLOAT16: + case MESA_FORMAT_INTENSITY_FLOAT16: + { + GLuint i, j, k; + const GLhalfARB *rowA = (const GLhalfARB *) srcRowA; + const GLhalfARB *rowB = (const GLhalfARB *) srcRowB; + GLhalfARB *dst = (GLhalfARB *) dstRow; + for (i = j = 0, k = k0; i < (GLuint) dstWidth; + i++, j += colStride, k += colStride) { + GLfloat aj, ak, bj, bk; + aj = _mesa_half_to_float(rowA[j]); + ak = _mesa_half_to_float(rowA[k]); + bj = _mesa_half_to_float(rowB[j]); + bk = _mesa_half_to_float(rowB[k]); + dst[i] = _mesa_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + return; + default: _mesa_problem(NULL, "bad format in do_row()"); } @@ -1605,9 +3264,7 @@ make_2d_mipmap(const struct gl_texture_format *format, GLint border, const GLint dstRowStride = bpt * dstWidth; const GLubyte *srcA, *srcB; GLubyte *dst; - GLint row, colStride; - - colStride = (srcWidth == dstWidth) ? 1 : 2; + GLint row; /* Compute src and dst pointers, skipping any border */ srcA = srcPtr + border * ((srcWidth + 1) * bpt); @@ -2069,15 +3726,15 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target, GLint dstRowStride = _mesa_compressed_row_stride(srcImage->IntFormat, dstWidth); ASSERT(srcFormat == GL_RGB || srcFormat == GL_RGBA); - _mesa_compress_teximage(ctx, - dstWidth, dstHeight, /* size */ - srcFormat, /* source format */ - (const GLchan *) dstData, /* source buffer */ - dstWidth, /* source row stride */ - dstImage->TexFormat, /* dest format */ - (GLubyte*) dstImage->Data, /* dest buffer */ - dstRowStride ); /* dest row stride */ - + dstImage->TexFormat->StoreImage(ctx, 2, dstImage->Format, + dstImage->TexFormat, + dstImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, 0, /* strides */ + dstWidth, dstHeight, 1, /* size */ + srcFormat, CHAN_TYPE, + dstData, /* src data, actually */ + &ctx->DefaultPacking); /* swap src and dest pointers */ temp = (GLubyte *) srcData; srcData = dstData; @@ -2086,3 +3743,285 @@ _mesa_generate_mipmap(GLcontext *ctx, GLenum target, } /* loop over mipmap levels */ } + + +/** + * Helper function for drivers which need to rescale texture images to + * certain aspect ratios. + * Nearest filtering only (for broken hardware that can't support + * all aspect ratios). This can be made a lot faster, but I don't + * really care enough... + */ +void +_mesa_rescale_teximage2d (GLuint bytesPerPixel, + GLuint srcStrideInPixels, + GLuint dstRowStride, + GLint srcWidth, GLint srcHeight, + GLint dstWidth, GLint dstHeight, + const GLvoid *srcImage, GLvoid *dstImage) +{ + GLint row, col; + +#define INNER_LOOP( TYPE, HOP, WOP ) \ + for ( row = 0 ; row < dstHeight ; row++ ) { \ + GLint srcRow = row HOP hScale; \ + for ( col = 0 ; col < dstWidth ; col++ ) { \ + GLint srcCol = col WOP wScale; \ + dst[col] = src[srcRow * srcStrideInPixels + srcCol]; \ + } \ + dst = (TYPE *) ((GLubyte *) dst + dstRowStride); \ + } \ + +#define RESCALE_IMAGE( TYPE ) \ +do { \ + const TYPE *src = (const TYPE *)srcImage; \ + TYPE *dst = (TYPE *)dstImage; \ + \ + if ( srcHeight < dstHeight ) { \ + const GLint hScale = dstHeight / srcHeight; \ + if ( srcWidth < dstWidth ) { \ + const GLint wScale = dstWidth / srcWidth; \ + INNER_LOOP( TYPE, /, / ); \ + } \ + else { \ + const GLint wScale = srcWidth / dstWidth; \ + INNER_LOOP( TYPE, /, * ); \ + } \ + } \ + else { \ + const GLint hScale = srcHeight / dstHeight; \ + if ( srcWidth < dstWidth ) { \ + const GLint wScale = dstWidth / srcWidth; \ + INNER_LOOP( TYPE, *, / ); \ + } \ + else { \ + const GLint wScale = srcWidth / dstWidth; \ + INNER_LOOP( TYPE, *, * ); \ + } \ + } \ +} while (0) + + switch ( bytesPerPixel ) { + case 4: + RESCALE_IMAGE( GLuint ); + break; + + case 2: + RESCALE_IMAGE( GLushort ); + break; + + case 1: + RESCALE_IMAGE( GLubyte ); + break; + default: + _mesa_problem(NULL,"unexpected bytes/pixel in _mesa_rescale_teximage2d"); + } +} + + +/** + * Upscale an image by replication, not (typical) stretching. + * We use this when the image width or height is less than a + * certain size (4, 8) and we need to upscale an image. + */ +void +_mesa_upscale_teximage2d (GLsizei inWidth, GLsizei inHeight, + GLsizei outWidth, GLsizei outHeight, + GLint comps, const GLchan *src, GLint srcRowStride, + GLchan *dest ) +{ + GLint i, j, k; + + ASSERT(outWidth >= inWidth); + ASSERT(outHeight >= inHeight); +#if 0 + ASSERT(inWidth == 1 || inWidth == 2 || inHeight == 1 || inHeight == 2); + ASSERT((outWidth & 3) == 0); + ASSERT((outHeight & 3) == 0); +#endif + + for (i = 0; i < outHeight; i++) { + const GLint ii = i % inHeight; + for (j = 0; j < outWidth; j++) { + const GLint jj = j % inWidth; + for (k = 0; k < comps; k++) { + dest[(i * outWidth + j) * comps + k] + = src[ii * srcRowStride + jj * comps + k]; + } + } + } +} + + + +/** + * This is the software fallback for Driver.GetTexImage(). + * All error checking will have been done before this routine is called. + */ +void +_mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_texture_object *texObj, + const struct gl_texture_image *texImage) +{ + GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; + + if (ctx->Pack.BufferObj->Name) { + /* pack texture image into a PBO */ + GLubyte *buf; + 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)"); + return; + } + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, + ctx->Pack.BufferObj); + if (!buf) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)"); + return; + } + pixels = ADD_POINTERS(buf, pixels); + } + else if (!pixels) { + /* not an error */ + return; + } + + { + 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( dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + assert(dest); + + if (format == GL_COLOR_INDEX) { + GLuint indexRow[MAX_WIDTH]; + GLint col; + /* Can't use FetchTexel here because that returns RGBA */ + if (texImage->TexFormat->IndexBits == 8) { + const GLubyte *src = (const GLubyte *) texImage->Data; + for (col = 0; col < width; col++) { + indexRow[col] = src[texImage->Width * + (img * texImage->Height + row) + col]; + } + } + else if (texImage->TexFormat->IndexBits == 16) { + const GLushort *src = (const GLushort *) texImage->Data; + for (col = 0; col < width; col++) { + indexRow[col] = src[texImage->Width * + (img * texImage->Height + row) + col]; + } + } + else { + _mesa_problem(ctx, + "Color index problem in _mesa_GetTexImage"); + } + _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->FetchTexelf)(texImage, col, row, img, + 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 */ + GLfloat rgba[MAX_WIDTH][4]; + GLint col; + for (col = 0; col < width; col++) { + (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); + } + _mesa_pack_rgba_span_float(ctx, width, + (const GLfloat (*)[4]) rgba, + format, type, dest, &ctx->Pack, + 0 /* no image transfer */); + } /* format */ + } /* row */ + } /* img */ + } + + if (ctx->Pack.BufferObj->Name) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +} + + + +/** + * This is the software fallback for Driver.GetCompressedTexImage(). + * All error checking will have been done before this routine is called. + */ +void +_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level, + GLvoid *img, + const struct gl_texture_object *texObj, + const struct gl_texture_image *texImage) +{ + if (ctx->Pack.BufferObj->Name) { + /* pack texture image into a PBO */ + GLubyte *buf; + if ((const GLubyte *) img + texImage->CompressedSize > + (const GLubyte *) ctx->Pack.BufferObj->Size) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(invalid PBO access)"); + return; + } + buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + GL_WRITE_ONLY_ARB, + ctx->Pack.BufferObj); + if (!buf) { + /* buffer is already mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTexImage(PBO is mapped)"); + return; + } + img = ADD_POINTERS(buf, img); + } + else if (!img) { + /* not an error */ + return; + } + + /* just memcpy, no pixelstore or pixel transfer */ + MEMCPY(img, texImage->Data, texImage->CompressedSize); + + if (ctx->Pack.BufferObj->Name) { + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, + ctx->Pack.BufferObj); + } +}