X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftexgetimage.c;h=daabf2e81380216e3dabc76dca6cc8d7a9f374d9;hb=f10f5b88224ba82310fc71f9a73ae118bf28be2d;hp=06e032396e4e5e49fd0e560bc41358a0c3137b28;hpb=403cf7c56fc6decb7636114dc1dadb7adf99a7a4;p=mesa.git diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c index 06e032396e4..daabf2e8138 100644 --- a/src/mesa/main/texgetimage.c +++ b/src/mesa/main/texgetimage.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 7.7 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * Copyright (c) 2009 VMware, Inc. @@ -18,9 +17,10 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ @@ -35,8 +35,8 @@ #include "context.h" #include "formats.h" #include "format_unpack.h" +#include "glformats.h" #include "image.h" -#include "mfeatures.h" #include "mtypes.h" #include "pack.h" #include "pbo.h" @@ -50,7 +50,7 @@ * Can the given type represent negative values? */ static inline GLboolean -type_with_negative_values(GLenum type) +type_needs_clamping(GLenum type) { switch (type) { case GL_BYTE: @@ -58,9 +58,11 @@ type_with_negative_values(GLenum type) case GL_INT: case GL_FLOAT: case GL_HALF_FLOAT_ARB: - return GL_TRUE; - default: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: return GL_FALSE; + default: + return GL_TRUE; } } @@ -77,7 +79,7 @@ get_tex_depth(struct gl_context *ctx, GLuint dimensions, const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; - GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat)); + GLfloat *depthRow = malloc(width * sizeof(GLfloat)); if (!depthRow) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); @@ -93,16 +95,22 @@ get_tex_depth(struct gl_context *ctx, GLuint dimensions, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); - for (row = 0; row < height; row++) { - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - const GLubyte *src = srcMap + row * srcRowStride; - _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); - _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); - } + if (srcMap) { + for (row = 0; row < height; row++) { + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + const GLubyte *src = srcMap + row * srcRowStride; + _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); + _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); + } - ctx->Driver.UnmapTextureImage(ctx, texImage, img); + ctx->Driver.UnmapTextureImage(ctx, texImage, img); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + break; + } } free(depthRow); @@ -122,6 +130,10 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, const GLint depth = texImage->Depth; GLint img, row; + assert(format == GL_DEPTH_STENCIL); + assert(type == GL_UNSIGNED_INT_24_8); + /* XXX type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV is not handled yet */ + for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; @@ -131,19 +143,28 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); - for (row = 0; row < height; row++) { - const GLubyte *src = srcMap + row * rowstride; - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - /* XXX Z24_S8 vs. S8_Z24??? */ - memcpy(dest, src, width * sizeof(GLuint)); - if (ctx->Pack.SwapBytes) { - _mesa_swap4((GLuint *) dest, width); + if (srcMap) { + for (row = 0; row < height; row++) { + const GLubyte *src = srcMap + row * rowstride; + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + /* Unpack from texture's format to GL's z24_s8 layout */ + _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat, + width, + (const GLuint *) src, + dest); + if (ctx->Pack.SwapBytes) { + _mesa_swap4((GLuint *) dest, width); + } } - } - ctx->Driver.UnmapTextureImage(ctx, texImage, img); + ctx->Driver.UnmapTextureImage(ctx, texImage, img); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + break; + } } } @@ -170,198 +191,360 @@ get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); - for (row = 0; row < height; row++) { - const GLubyte *src = srcMap + row * rowstride; - void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, - width, height, format, type, - img, row, 0); - memcpy(dest, src, width * sizeof(GLushort)); - - /* check for byte swapping */ - if ((texImage->TexFormat == MESA_FORMAT_YCBCR - && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || - (texImage->TexFormat == MESA_FORMAT_YCBCR_REV - && type == GL_UNSIGNED_SHORT_8_8_MESA)) { - if (!ctx->Pack.SwapBytes) + if (srcMap) { + for (row = 0; row < height; row++) { + const GLubyte *src = srcMap + row * rowstride; + void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, + width, height, format, type, + img, row, 0); + memcpy(dest, src, width * sizeof(GLushort)); + + /* check for byte swapping */ + if ((texImage->TexFormat == MESA_FORMAT_YCBCR + && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || + (texImage->TexFormat == 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 if (ctx->Pack.SwapBytes) { - _mesa_swap2((GLushort *) dest, width); - } - } - ctx->Driver.UnmapTextureImage(ctx, texImage, img); + ctx->Driver.UnmapTextureImage(ctx, texImage, img); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + break; + } } } /** - * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). - * Compressed textures are handled here as well. + * Get a color texture image with decompression. */ static void -get_tex_rgba(struct gl_context *ctx, GLuint dimensions, - GLenum format, GLenum type, GLvoid *pixels, - struct gl_texture_image *texImage) +get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_image *texImage, + GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ - const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); + const mesa_format texFormat = + _mesa_get_srgb_format_linear(texImage->TexFormat); + const GLenum baseFormat = _mesa_get_format_base_format(texFormat); + const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); + GLenum rebaseFormat = GL_NONE; const GLuint width = texImage->Width; const GLuint height = texImage->Height; const GLuint depth = texImage->Depth; - const GLenum dataType = _mesa_get_format_datatype(texFormat); - const GLenum baseFormat = _mesa_get_format_base_format(texFormat); - /* Normally, no pixel transfer ops are performed during glGetTexImage. - * The only possible exception is component clamping to [0,1]. - */ - GLbitfield transferOps = 0x0; - - /* In general, clamping does not apply to glGetTexImage, except when - * the returned type of the image can't hold negative values. - */ - if (!type_with_negative_values(type)) { - /* the returned image type can't have negative values */ - if (dataType == GL_FLOAT || - dataType == GL_SIGNED_NORMALIZED || - format == GL_LUMINANCE || - format == GL_LUMINANCE_ALPHA) { - transferOps |= IMAGE_CLAMP_BIT; - } + GLfloat *tempImage, *tempSlice, *srcRow; + GLuint row, slice; + + /* Decompress into temp float buffer, then pack into user buffer */ + tempImage = malloc(width * height * depth + * 4 * sizeof(GLfloat)); + if (!tempImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); + return; } - if (_mesa_is_format_compressed(texFormat)) { - /* Decompress into temp buffer, then pack into user buffer */ - GLfloat *tempImage, *srcRow; - GLuint row; - - tempImage = (GLfloat *) malloc(texImage->Width * texImage->Height * - texImage->Depth * 4 * sizeof(GLfloat)); - if (!tempImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); - return; - } - - /* Decompress the texture image - results in 'tempImage' */ - { - GLubyte *srcMap; - GLint srcRowStride; - GLuint bytes, bw, bh; - - bytes = _mesa_get_format_bytes(texImage->TexFormat); - _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); - - ctx->Driver.MapTextureImage(ctx, texImage, 0, - 0, 0, width, height, - GL_MAP_READ_BIT, - &srcMap, &srcRowStride); + /* Decompress the texture image slices - results in 'tempImage' */ + for (slice = 0; slice < depth; slice++) { + GLubyte *srcMap; + GLint srcRowStride; - /* XXX This line is a bit of a hack to work around the - * mismatch of compressed row strides as returned by - * MapTextureImage() vs. what the texture decompression code - * uses. This will be fixed in the future. - */ - srcRowStride = srcRowStride * bh / bytes; + tempSlice = tempImage + slice * 4 * width * height; + ctx->Driver.MapTextureImage(ctx, texImage, slice, + 0, 0, width, height, + GL_MAP_READ_BIT, + &srcMap, &srcRowStride); + if (srcMap) { _mesa_decompress_image(texFormat, width, height, - srcMap, srcRowStride, tempImage); + srcMap, srcRowStride, tempSlice); - ctx->Driver.UnmapTextureImage(ctx, texImage, 0); + ctx->Driver.UnmapTextureImage(ctx, texImage, slice); } - - if (baseFormat == GL_LUMINANCE || - baseFormat == GL_LUMINANCE_ALPHA) { - /* Set green and blue to zero since the pack function here will - * compute L=R+G+B. - */ - GLuint i; - for (i = 0; i < width * height; i++) { - tempImage[i * 4 + GCOMP] = tempImage[i * 4 + BCOMP] = 0.0f; - } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + free(tempImage); + return; } + } + + if (baseFormat == GL_LUMINANCE || + baseFormat == GL_INTENSITY || + baseFormat == GL_LUMINANCE_ALPHA) { + /* If a luminance (or intensity) texture is read back as RGB(A), the + * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat + * here to get G=B=0. + */ + rebaseFormat = texImage->_BaseFormat; + } + else if ((baseFormat == GL_RGBA || + baseFormat == GL_RGB || + baseFormat == GL_RG) && + (destBaseFormat == GL_LUMINANCE || + destBaseFormat == GL_LUMINANCE_ALPHA || + destBaseFormat == GL_LUMINANCE_INTEGER_EXT || + destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { + /* If we're reading back an RGB(A) texture as luminance then we need + * to return L=tex(R). Note, that's different from glReadPixels which + * returns L=R+G+B. + */ + rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ + } + + if (rebaseFormat) { + _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, + rebaseFormat); + } - srcRow = tempImage; + tempSlice = tempImage; + for (slice = 0; slice < depth; slice++) { + srcRow = tempSlice; for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, - 0, row, 0); + slice, row, 0); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, format, type, dest, &ctx->Pack, transferOps); - srcRow += width * 4; + srcRow += 4 * width; } + tempSlice += 4 * width * height; + } + + free(tempImage); +} + - free(tempImage); +/** + * Return a base GL format given the user-requested format + * for glGetTexImage(). + */ +GLenum +_mesa_base_pack_format(GLenum format) +{ + switch (format) { + case GL_ABGR_EXT: + case GL_BGRA: + case GL_BGRA_INTEGER: + case GL_RGBA_INTEGER: + return GL_RGBA; + case GL_BGR: + case GL_BGR_INTEGER: + case GL_RGB_INTEGER: + return GL_RGB; + case GL_RED_INTEGER: + return GL_RED; + case GL_GREEN_INTEGER: + return GL_GREEN; + case GL_BLUE_INTEGER: + return GL_BLUE; + case GL_ALPHA_INTEGER: + return GL_ALPHA; + case GL_LUMINANCE_INTEGER_EXT: + return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + return GL_LUMINANCE_ALPHA; + default: + return format; } - else { - /* No decompression needed */ - GLuint img, row; - GLfloat (*rgba)[4]; +} - rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); - if (!rgba) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); - return; - } - for (img = 0; img < depth; img++) { - GLubyte *srcMap; - GLint rowstride; +/** + * Get an uncompressed color texture image. + */ +static void +get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_image *texImage, + GLbitfield transferOps) +{ + /* don't want to apply sRGB -> RGB conversion here so override the format */ + const mesa_format texFormat = + _mesa_get_srgb_format_linear(texImage->TexFormat); + const GLuint width = texImage->Width; + GLenum destBaseFormat = _mesa_base_pack_format(format); + GLenum rebaseFormat = GL_NONE; + GLuint height = texImage->Height; + GLuint depth = texImage->Depth; + GLuint img, row; + GLfloat (*rgba)[4]; + GLuint (*rgba_uint)[4]; + GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); + GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); + GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); + + /* Allocate buffer for one row of texels */ + rgba = malloc(4 * width * sizeof(GLfloat)); + rgba_uint = (GLuint (*)[4]) rgba; + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); + return; + } + + if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { + depth = height; + height = 1; + } - /* map src texture buffer */ - ctx->Driver.MapTextureImage(ctx, texImage, img, - 0, 0, width, height, GL_MAP_READ_BIT, - &srcMap, &rowstride); + if (texImage->_BaseFormat == GL_LUMINANCE || + texImage->_BaseFormat == GL_INTENSITY || + texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { + /* If a luminance (or intensity) texture is read back as RGB(A), the + * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat + * here to get G=B=0. + */ + rebaseFormat = texImage->_BaseFormat; + } + else if ((texImage->_BaseFormat == GL_RGBA || + texImage->_BaseFormat == GL_RGB || + texImage->_BaseFormat == GL_RG) && + (destBaseFormat == GL_LUMINANCE || + destBaseFormat == GL_LUMINANCE_ALPHA || + destBaseFormat == GL_LUMINANCE_INTEGER_EXT || + destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { + /* If we're reading back an RGB(A) texture as luminance then we need + * to return L=tex(R). Note, that's different from glReadPixels which + * returns L=R+G+B. + */ + rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ + } + else if (texImage->_BaseFormat != texBaseFormat) { + /* The internal format and the real format differ, so we can't rely + * on the unpack functions setting the correct constant values. + * (e.g. reading back GL_RGB8 which is actually RGBA won't set alpha=1) + */ + switch (texImage->_BaseFormat) { + case GL_RED: + if ((texBaseFormat == GL_RGBA || + texBaseFormat == GL_RGB || + texBaseFormat == GL_RG) && + (destBaseFormat == GL_RGBA || + destBaseFormat == GL_RGB || + destBaseFormat == GL_RG || + destBaseFormat == GL_GREEN)) { + rebaseFormat = texImage->_BaseFormat; + break; + } + /* fall through */ + case GL_RG: + if ((texBaseFormat == GL_RGBA || + texBaseFormat == GL_RGB) && + (destBaseFormat == GL_RGBA || + destBaseFormat == GL_RGB || + destBaseFormat == GL_BLUE)) { + rebaseFormat = texImage->_BaseFormat; + break; + } + /* fall through */ + case GL_RGB: + if (texBaseFormat == GL_RGBA && + (destBaseFormat == GL_RGBA || + destBaseFormat == GL_ALPHA || + destBaseFormat == GL_LUMINANCE_ALPHA)) { + rebaseFormat = texImage->_BaseFormat; + } + break; + case GL_ALPHA: + if (destBaseFormat != GL_ALPHA) { + rebaseFormat = texImage->_BaseFormat; + } + break; + } + } + + for (img = 0; img < depth; img++) { + GLubyte *srcMap; + GLint rowstride; + + /* map src texture buffer */ + ctx->Driver.MapTextureImage(ctx, texImage, img, + 0, 0, width, height, GL_MAP_READ_BIT, + &srcMap, &rowstride); + if (srcMap) { for (row = 0; row < height; row++) { - const GLubyte *src = srcMap + row * rowstride; + const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); - _mesa_unpack_rgba_row(texFormat, width, src, rgba); - - if (texImage->_BaseFormat == GL_ALPHA) { - GLint col; - for (col = 0; col < width; col++) { - rgba[col][RCOMP] = 0.0F; - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - } - } - else if (texImage->_BaseFormat == GL_LUMINANCE) { - GLint col; - for (col = 0; col < width; col++) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - rgba[col][ACOMP] = 1.0F; + if (tex_is_integer) { + _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); + if (rebaseFormat) + _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); + if (tex_is_uint) { + _mesa_pack_rgba_span_from_uints(ctx, width, + (GLuint (*)[4]) rgba_uint, + format, type, dest); + } else { + _mesa_pack_rgba_span_from_ints(ctx, width, + (GLint (*)[4]) rgba_uint, + format, type, dest); } - } - else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { - GLint col; - for (col = 0; col < width; col++) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - } - } - else if (texImage->_BaseFormat == GL_INTENSITY) { - GLint col; - for (col = 0; col < width; col++) { - rgba[col][GCOMP] = 0.0F; - rgba[col][BCOMP] = 0.0F; - rgba[col][ACOMP] = 1.0F; - } - } - - _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, - format, type, dest, - &ctx->Pack, transferOps); - } + } else { + _mesa_unpack_rgba_row(texFormat, width, src, rgba); + if (rebaseFormat) + _mesa_rebase_rgba_float(width, rgba, rebaseFormat); + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, + format, type, dest, + &ctx->Pack, transferOps); + } + } /* Unmap the src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, img); } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); + break; + } + } + + free(rgba); +} + + +/** + * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). + * Compressed textures are handled here as well. + */ +static void +get_tex_rgba(struct gl_context *ctx, GLuint dimensions, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_image *texImage) +{ + const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); + GLbitfield transferOps = 0x0; + + /* In general, clamping does not apply to glGetTexImage, except when + * the returned type of the image can't hold negative values. + */ + if (type_needs_clamping(type)) { + /* the returned image type can't have negative values */ + if (dataType == GL_FLOAT || + dataType == GL_HALF_FLOAT || + dataType == GL_SIGNED_NORMALIZED || + format == GL_LUMINANCE || + format == GL_LUMINANCE_ALPHA) { + transferOps |= IMAGE_CLAMP_BIT; + } + } - free(rgba); + if (_mesa_is_format_compressed(texImage->TexFormat)) { + get_tex_rgba_compressed(ctx, dimensions, format, type, + pixels, texImage, transferOps); + } + else { + get_tex_rgba_uncompressed(ctx, dimensions, format, type, + pixels, texImage, transferOps); } } @@ -377,55 +560,21 @@ get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, { const GLenum target = texImage->TexObject->Target; GLboolean memCopy = GL_FALSE; + GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* - * Check if the src/dst formats are compatible. - * Also note that GL's pixel transfer ops don't apply to glGetTexImage() - * so we don't have to worry about those. - * XXX more format combinations could be supported here. + * Check if we can use memcpy to copy from the hardware texture + * format to the user's format/type. + * Note that GL's pixel transfer ops don't apply to glGetTexImage() */ if ((target == GL_TEXTURE_1D || target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE || - (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && - target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) { - if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 || - texImage->TexFormat == MESA_FORMAT_SARGB8) && - format == GL_BGRA && - (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) && - !ctx->Pack.SwapBytes && - _mesa_little_endian()) { - memCopy = GL_TRUE; - } - else if ((texImage->TexFormat == MESA_FORMAT_AL88 || - texImage->TexFormat == MESA_FORMAT_SLA8) && - format == GL_LUMINANCE_ALPHA && - type == GL_UNSIGNED_BYTE && - !ctx->Pack.SwapBytes && - _mesa_little_endian()) { - memCopy = GL_TRUE; - } - else if ((texImage->TexFormat == MESA_FORMAT_L8 || - texImage->TexFormat == MESA_FORMAT_SL8) && - format == GL_LUMINANCE && - type == GL_UNSIGNED_BYTE) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_L16 && - format == GL_LUMINANCE && - type == GL_UNSIGNED_SHORT) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_A8 && - format == GL_ALPHA && - type == GL_UNSIGNED_BYTE) { - memCopy = GL_TRUE; - } - else if (texImage->TexFormat == MESA_FORMAT_A16 && - format == GL_ALPHA && - type == GL_UNSIGNED_SHORT) { - memCopy = GL_TRUE; - } + _mesa_is_cube_face(target)) && + texBaseFormat == texImage->_BaseFormat) { + memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, + format, type, + ctx->Pack.SwapBytes); } if (memCopy) { @@ -444,20 +593,25 @@ get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, 0, 0, texImage->Width, texImage->Height, GL_MAP_READ_BIT, &src, &srcRowStride); - if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { - memcpy(dst, src, bytesPerRow * texImage->Height); + if (src) { + if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { + memcpy(dst, src, bytesPerRow * texImage->Height); + } + else { + GLuint row; + for (row = 0; row < texImage->Height; row++) { + memcpy(dst, src, bytesPerRow); + dst += dstRowStride; + src += srcRowStride; + } + } + + /* unmap src texture buffer */ + ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { - GLuint row; - for (row = 0; row < texImage->Height; row++) { - memcpy(dst, src, bytesPerRow); - dst += dstRowStride; - src += srcRowStride; - } + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); } - - /* unmap src texture buffer */ - ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } return memCopy; @@ -475,18 +629,8 @@ _mesa_get_teximage(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { - GLuint dimensions; - - switch (texImage->TexObject->Target) { - case GL_TEXTURE_1D: - dimensions = 1; - break; - case GL_TEXTURE_3D: - dimensions = 3; - break; - default: - dimensions = 2; - } + const GLuint dimensions = + _mesa_get_texture_dimensions(texImage->TexObject->Target); /* map dest buffer, if PBO */ if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { @@ -498,7 +642,8 @@ _mesa_get_teximage(struct gl_context *ctx, */ GLubyte *buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, - GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); + GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, + MAP_INTERNAL); if (!buf) { /* out of memory or other unexpected error */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); @@ -527,7 +672,7 @@ _mesa_get_teximage(struct gl_context *ctx, } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); + ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); } } @@ -538,10 +683,9 @@ _mesa_get_teximage(struct gl_context *ctx, * All error checking will have been done before this routine is called. */ void -_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level, - GLvoid *img, - struct gl_texture_object *texObj, - struct gl_texture_image *texImage) +_mesa_get_compressed_teximage(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLvoid *img) { const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width); @@ -553,7 +697,8 @@ _mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level /* pack texture image into a PBO */ GLubyte *buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, - GL_MAP_WRITE_BIT, ctx->Pack.BufferObj); + GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, + MAP_INTERNAL); if (!buf) { /* out of memory or other unexpected error */ _mesa_error(ctx, GL_OUT_OF_MEMORY, @@ -568,33 +713,69 @@ _mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level 0, 0, texImage->Width, texImage->Height, GL_MAP_READ_BIT, &src, &srcRowStride); - /* no pixelstore or pixel transfer, but respect stride */ + if (src) { + /* no pixelstore or pixel transfer, but respect stride */ + + if (row_stride == srcRowStride) { + const GLuint size = _mesa_format_image_size(texImage->TexFormat, + texImage->Width, + texImage->Height, + texImage->Depth); + memcpy(img, src, size); + } + else { + GLuint bw, bh; + _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); + for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { + memcpy((GLubyte *)img + i * row_stride, + (GLubyte *)src + i * srcRowStride, + row_stride); + } + } - if (row_stride == srcRowStride) { - const GLuint size = _mesa_format_image_size(texImage->TexFormat, - texImage->Width, - texImage->Height, - texImage->Depth); - memcpy(img, src, size); + ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { - GLuint bw, bh; - _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); - for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) { - memcpy((GLubyte *)img + i * row_stride, - (GLubyte *)src + i * srcRowStride, - row_stride); - } + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); } - ctx->Driver.UnmapTextureImage(ctx, texImage, 0); - if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj); + ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); } } +/** + * Validate the texture target enum supplied to glTexImage or + * glCompressedTexImage. + */ +static GLboolean +legal_getteximage_target(struct gl_context *ctx, GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + return GL_TRUE; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + return ctx->Extensions.ARB_texture_cube_map; + case GL_TEXTURE_RECTANGLE_NV: + return ctx->Extensions.NV_texture_rectangle; + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + return ctx->Extensions.EXT_texture_array; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return ctx->Extensions.ARB_texture_cube_map_array; + default: + return GL_FALSE; + } +} + /** * Do error checking for a glGetTexImage() call. @@ -609,62 +790,35 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, struct gl_texture_image *texImage; const GLint maxLevels = _mesa_max_texture_levels(ctx, target); const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; - GLenum baseFormat; + GLenum baseFormat, err; - if (maxLevels == 0) { + if (!legal_getteximage_target(ctx, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); return GL_TRUE; } + assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); return GL_TRUE; } - if (_mesa_sizeof_packed_type(type) <= 0) { - _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); - return GL_TRUE; - } - - if (_mesa_components_in_format(format) <= 0 || - format == GL_STENCIL_INDEX || - format == GL_COLOR_INDEX) { - _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); - return GL_TRUE; - } - - if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.EXT_packed_depth_stencil - && _mesa_is_depthstencil_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); - return GL_TRUE; - } - - if (!ctx->Extensions.ATI_envmap_bumpmap - && _mesa_is_dudv_format(format)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); + err = _mesa_error_check_format_and_type(ctx, format, type); + if (err != GL_NO_ERROR) { + _mesa_error(ctx, err, "glGetTexImage(format/type)"); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); - if (!texObj || _mesa_is_proxy_texture(target)) { + if (!texObj) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { - /* out of memory */ + /* non-existant texture image */ return GL_TRUE; } @@ -716,7 +870,7 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* PBO should not be mapped */ - if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(PBO is mapped)"); return GL_TRUE; @@ -745,7 +899,8 @@ _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + FLUSH_VERTICES(ctx, 0); if (getteximage_error_check(ctx, target, level, format, type, bufSize, pixels)) { @@ -760,6 +915,9 @@ _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, texObj = _mesa_get_current_tex_object(ctx, target); texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (_mesa_is_zero_size_texture(texImage)) + return; + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," " dstFmt=0x%x, dstType=0x%x\n", @@ -798,25 +956,19 @@ getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, const GLint maxLevels = _mesa_max_texture_levels(ctx, target); GLuint compressedSize; - if (maxLevels == 0) { + if (!legal_getteximage_target(ctx, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", target); return GL_TRUE; } + assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(bad level = %d)", level); return GL_TRUE; } - if (_mesa_is_proxy_texture(target)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetCompressedTexImageARB(bad target = %s)", - _mesa_lookup_enum_by_nr(target)); - return GL_TRUE; - } - texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); @@ -845,10 +997,11 @@ getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* do bounds checking on writing to client memory */ - if (clientMemSize < compressedSize) { + if (clientMemSize < (GLsizei) compressedSize) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetnCompressedTexImageARB(out of bounds access:" " bufSize (%d) is too small)", clientMemSize); + return GL_TRUE; } } else { /* do bounds checking on PBO write */ @@ -860,7 +1013,7 @@ getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, } /* make sure PBO is not mapped */ - if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImage(PBO is mapped)"); return GL_TRUE; @@ -878,7 +1031,8 @@ _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, struct gl_texture_object *texObj; struct gl_texture_image *texImage; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + FLUSH_VERTICES(ctx, 0); if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { return; @@ -892,6 +1046,9 @@ _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, texObj = _mesa_get_current_tex_object(ctx, target); texImage = _mesa_select_tex_image(ctx, texObj, target, level); + if (_mesa_is_zero_size_texture(texImage)) + return; + if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { _mesa_debug(ctx, "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", @@ -902,14 +1059,13 @@ _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, _mesa_lock_texture(ctx, texObj); { - ctx->Driver.GetCompressedTexImage(ctx, target, level, img, - texObj, texImage); + ctx->Driver.GetCompressedTexImage(ctx, texImage, img); } _mesa_unlock_texture(ctx, texObj); } void GLAPIENTRY -_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) +_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) { _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); }