texgetimage.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (c) 2009 VMware, Inc. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * Code for glGetTexImage() and glGetCompressedTexImage(). 29848b8605Smrg */ 30848b8605Smrg 31848b8605Smrg 32848b8605Smrg#include "glheader.h" 33848b8605Smrg#include "bufferobj.h" 34848b8605Smrg#include "enums.h" 35848b8605Smrg#include "context.h" 36848b8605Smrg#include "formats.h" 37848b8605Smrg#include "format_unpack.h" 38848b8605Smrg#include "glformats.h" 39848b8605Smrg#include "image.h" 40848b8605Smrg#include "mtypes.h" 41848b8605Smrg#include "pack.h" 42848b8605Smrg#include "pbo.h" 43848b8605Smrg#include "pixelstore.h" 44848b8605Smrg#include "texcompress.h" 45848b8605Smrg#include "texgetimage.h" 46848b8605Smrg#include "teximage.h" 47848b8605Smrg#include "texstore.h" 48848b8605Smrg 49848b8605Smrg 50848b8605Smrg 51848b8605Smrg/** 52848b8605Smrg * Can the given type represent negative values? 53848b8605Smrg */ 54848b8605Smrgstatic inline GLboolean 55848b8605Smrgtype_needs_clamping(GLenum type) 56848b8605Smrg{ 57848b8605Smrg switch (type) { 58848b8605Smrg case GL_BYTE: 59848b8605Smrg case GL_SHORT: 60848b8605Smrg case GL_INT: 61848b8605Smrg case GL_FLOAT: 62848b8605Smrg case GL_HALF_FLOAT_ARB: 63848b8605Smrg case GL_UNSIGNED_INT_10F_11F_11F_REV: 64848b8605Smrg case GL_UNSIGNED_INT_5_9_9_9_REV: 65848b8605Smrg return GL_FALSE; 66848b8605Smrg default: 67848b8605Smrg return GL_TRUE; 68848b8605Smrg } 69848b8605Smrg} 70848b8605Smrg 71848b8605Smrg 72848b8605Smrg/** 73848b8605Smrg * glGetTexImage for depth/Z pixels. 74848b8605Smrg */ 75848b8605Smrgstatic void 76848b8605Smrgget_tex_depth(struct gl_context *ctx, GLuint dimensions, 77848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 78848b8605Smrg struct gl_texture_image *texImage) 79848b8605Smrg{ 80848b8605Smrg const GLint width = texImage->Width; 81848b8605Smrg GLint height = texImage->Height; 82848b8605Smrg GLint depth = texImage->Depth; 83848b8605Smrg GLint img, row; 84848b8605Smrg GLfloat *depthRow = malloc(width * sizeof(GLfloat)); 85848b8605Smrg 86848b8605Smrg if (!depthRow) { 87848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 88848b8605Smrg return; 89848b8605Smrg } 90848b8605Smrg 91848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 92848b8605Smrg depth = height; 93848b8605Smrg height = 1; 94848b8605Smrg } 95848b8605Smrg 96848b8605Smrg for (img = 0; img < depth; img++) { 97848b8605Smrg GLubyte *srcMap; 98848b8605Smrg GLint srcRowStride; 99848b8605Smrg 100848b8605Smrg /* map src texture buffer */ 101848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, img, 102848b8605Smrg 0, 0, width, height, GL_MAP_READ_BIT, 103848b8605Smrg &srcMap, &srcRowStride); 104848b8605Smrg 105848b8605Smrg if (srcMap) { 106848b8605Smrg for (row = 0; row < height; row++) { 107848b8605Smrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 108848b8605Smrg width, height, format, type, 109848b8605Smrg img, row, 0); 110848b8605Smrg const GLubyte *src = srcMap + row * srcRowStride; 111848b8605Smrg _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); 112848b8605Smrg _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); 113848b8605Smrg } 114848b8605Smrg 115848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 116848b8605Smrg } 117848b8605Smrg else { 118848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 119848b8605Smrg break; 120848b8605Smrg } 121848b8605Smrg } 122848b8605Smrg 123848b8605Smrg free(depthRow); 124848b8605Smrg} 125848b8605Smrg 126848b8605Smrg 127848b8605Smrg/** 128848b8605Smrg * glGetTexImage for depth/stencil pixels. 129848b8605Smrg */ 130848b8605Smrgstatic void 131848b8605Smrgget_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, 132848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 133848b8605Smrg struct gl_texture_image *texImage) 134848b8605Smrg{ 135848b8605Smrg const GLint width = texImage->Width; 136848b8605Smrg const GLint height = texImage->Height; 137848b8605Smrg const GLint depth = texImage->Depth; 138848b8605Smrg GLint img, row; 139848b8605Smrg 140848b8605Smrg assert(format == GL_DEPTH_STENCIL); 141848b8605Smrg assert(type == GL_UNSIGNED_INT_24_8 || 142848b8605Smrg type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); 143848b8605Smrg 144848b8605Smrg for (img = 0; img < depth; img++) { 145848b8605Smrg GLubyte *srcMap; 146848b8605Smrg GLint rowstride; 147848b8605Smrg 148848b8605Smrg /* map src texture buffer */ 149848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, img, 150848b8605Smrg 0, 0, width, height, GL_MAP_READ_BIT, 151848b8605Smrg &srcMap, &rowstride); 152848b8605Smrg 153848b8605Smrg if (srcMap) { 154848b8605Smrg for (row = 0; row < height; row++) { 155848b8605Smrg const GLubyte *src = srcMap + row * rowstride; 156848b8605Smrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 157848b8605Smrg width, height, format, type, 158848b8605Smrg img, row, 0); 159848b8605Smrg _mesa_unpack_depth_stencil_row(texImage->TexFormat, 160848b8605Smrg width, 161848b8605Smrg (const GLuint *) src, 162848b8605Smrg type, dest); 163848b8605Smrg if (ctx->Pack.SwapBytes) { 164848b8605Smrg _mesa_swap4((GLuint *) dest, width); 165848b8605Smrg } 166848b8605Smrg } 167848b8605Smrg 168848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 169848b8605Smrg } 170848b8605Smrg else { 171848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 172848b8605Smrg break; 173848b8605Smrg } 174848b8605Smrg } 175848b8605Smrg} 176848b8605Smrg 177848b8605Smrg 178848b8605Smrg/** 179848b8605Smrg * glGetTexImage for YCbCr pixels. 180848b8605Smrg */ 181848b8605Smrgstatic void 182848b8605Smrgget_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, 183848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 184848b8605Smrg struct gl_texture_image *texImage) 185848b8605Smrg{ 186848b8605Smrg const GLint width = texImage->Width; 187848b8605Smrg const GLint height = texImage->Height; 188848b8605Smrg const GLint depth = texImage->Depth; 189848b8605Smrg GLint img, row; 190848b8605Smrg 191848b8605Smrg for (img = 0; img < depth; img++) { 192848b8605Smrg GLubyte *srcMap; 193848b8605Smrg GLint rowstride; 194848b8605Smrg 195848b8605Smrg /* map src texture buffer */ 196848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, img, 197848b8605Smrg 0, 0, width, height, GL_MAP_READ_BIT, 198848b8605Smrg &srcMap, &rowstride); 199848b8605Smrg 200848b8605Smrg if (srcMap) { 201848b8605Smrg for (row = 0; row < height; row++) { 202848b8605Smrg const GLubyte *src = srcMap + row * rowstride; 203848b8605Smrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 204848b8605Smrg width, height, format, type, 205848b8605Smrg img, row, 0); 206848b8605Smrg memcpy(dest, src, width * sizeof(GLushort)); 207848b8605Smrg 208848b8605Smrg /* check for byte swapping */ 209848b8605Smrg if ((texImage->TexFormat == MESA_FORMAT_YCBCR 210848b8605Smrg && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || 211848b8605Smrg (texImage->TexFormat == MESA_FORMAT_YCBCR_REV 212848b8605Smrg && type == GL_UNSIGNED_SHORT_8_8_MESA)) { 213848b8605Smrg if (!ctx->Pack.SwapBytes) 214848b8605Smrg _mesa_swap2((GLushort *) dest, width); 215848b8605Smrg } 216848b8605Smrg else if (ctx->Pack.SwapBytes) { 217848b8605Smrg _mesa_swap2((GLushort *) dest, width); 218848b8605Smrg } 219848b8605Smrg } 220848b8605Smrg 221848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 222848b8605Smrg } 223848b8605Smrg else { 224848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 225848b8605Smrg break; 226848b8605Smrg } 227848b8605Smrg } 228848b8605Smrg} 229848b8605Smrg 230848b8605Smrg 231848b8605Smrg/** 232848b8605Smrg * Get a color texture image with decompression. 233848b8605Smrg */ 234848b8605Smrgstatic void 235848b8605Smrgget_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, 236848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 237848b8605Smrg struct gl_texture_image *texImage, 238848b8605Smrg GLbitfield transferOps) 239848b8605Smrg{ 240848b8605Smrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 241848b8605Smrg const mesa_format texFormat = 242848b8605Smrg _mesa_get_srgb_format_linear(texImage->TexFormat); 243848b8605Smrg const GLenum baseFormat = _mesa_get_format_base_format(texFormat); 244848b8605Smrg const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); 245848b8605Smrg GLenum rebaseFormat = GL_NONE; 246848b8605Smrg const GLuint width = texImage->Width; 247848b8605Smrg const GLuint height = texImage->Height; 248848b8605Smrg const GLuint depth = texImage->Depth; 249848b8605Smrg GLfloat *tempImage, *tempSlice, *srcRow; 250848b8605Smrg GLuint row, slice; 251848b8605Smrg 252848b8605Smrg /* Decompress into temp float buffer, then pack into user buffer */ 253848b8605Smrg tempImage = malloc(width * height * depth 254848b8605Smrg * 4 * sizeof(GLfloat)); 255848b8605Smrg if (!tempImage) { 256848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 257848b8605Smrg return; 258848b8605Smrg } 259848b8605Smrg 260848b8605Smrg /* Decompress the texture image slices - results in 'tempImage' */ 261848b8605Smrg for (slice = 0; slice < depth; slice++) { 262848b8605Smrg GLubyte *srcMap; 263848b8605Smrg GLint srcRowStride; 264848b8605Smrg 265848b8605Smrg tempSlice = tempImage + slice * 4 * width * height; 266848b8605Smrg 267848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, slice, 268848b8605Smrg 0, 0, width, height, 269848b8605Smrg GL_MAP_READ_BIT, 270848b8605Smrg &srcMap, &srcRowStride); 271848b8605Smrg if (srcMap) { 272848b8605Smrg _mesa_decompress_image(texFormat, width, height, 273848b8605Smrg srcMap, srcRowStride, tempSlice); 274848b8605Smrg 275848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, slice); 276848b8605Smrg } 277848b8605Smrg else { 278848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 279848b8605Smrg free(tempImage); 280848b8605Smrg return; 281848b8605Smrg } 282848b8605Smrg } 283848b8605Smrg 284848b8605Smrg if (baseFormat == GL_LUMINANCE || 285848b8605Smrg baseFormat == GL_INTENSITY || 286848b8605Smrg baseFormat == GL_LUMINANCE_ALPHA) { 287848b8605Smrg /* If a luminance (or intensity) texture is read back as RGB(A), the 288848b8605Smrg * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat 289848b8605Smrg * here to get G=B=0. 290848b8605Smrg */ 291848b8605Smrg rebaseFormat = texImage->_BaseFormat; 292848b8605Smrg } 293848b8605Smrg else if ((baseFormat == GL_RGBA || 294848b8605Smrg baseFormat == GL_RGB || 295848b8605Smrg baseFormat == GL_RG) && 296848b8605Smrg (destBaseFormat == GL_LUMINANCE || 297848b8605Smrg destBaseFormat == GL_LUMINANCE_ALPHA || 298848b8605Smrg destBaseFormat == GL_LUMINANCE_INTEGER_EXT || 299848b8605Smrg destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { 300848b8605Smrg /* If we're reading back an RGB(A) texture as luminance then we need 301848b8605Smrg * to return L=tex(R). Note, that's different from glReadPixels which 302848b8605Smrg * returns L=R+G+B. 303848b8605Smrg */ 304848b8605Smrg rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ 305848b8605Smrg } 306848b8605Smrg 307848b8605Smrg if (rebaseFormat) { 308848b8605Smrg _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, 309848b8605Smrg rebaseFormat); 310848b8605Smrg } 311848b8605Smrg 312848b8605Smrg tempSlice = tempImage; 313848b8605Smrg for (slice = 0; slice < depth; slice++) { 314848b8605Smrg srcRow = tempSlice; 315848b8605Smrg for (row = 0; row < height; row++) { 316848b8605Smrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 317848b8605Smrg width, height, format, type, 318848b8605Smrg slice, row, 0); 319848b8605Smrg 320848b8605Smrg _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, 321848b8605Smrg format, type, dest, &ctx->Pack, transferOps); 322848b8605Smrg srcRow += 4 * width; 323848b8605Smrg } 324848b8605Smrg tempSlice += 4 * width * height; 325848b8605Smrg } 326848b8605Smrg 327848b8605Smrg free(tempImage); 328848b8605Smrg} 329848b8605Smrg 330848b8605Smrg 331848b8605Smrg/** 332848b8605Smrg * Return a base GL format given the user-requested format 333848b8605Smrg * for glGetTexImage(). 334848b8605Smrg */ 335848b8605SmrgGLenum 336848b8605Smrg_mesa_base_pack_format(GLenum format) 337848b8605Smrg{ 338848b8605Smrg switch (format) { 339848b8605Smrg case GL_ABGR_EXT: 340848b8605Smrg case GL_BGRA: 341848b8605Smrg case GL_BGRA_INTEGER: 342848b8605Smrg case GL_RGBA_INTEGER: 343848b8605Smrg return GL_RGBA; 344848b8605Smrg case GL_BGR: 345848b8605Smrg case GL_BGR_INTEGER: 346848b8605Smrg case GL_RGB_INTEGER: 347848b8605Smrg return GL_RGB; 348848b8605Smrg case GL_RED_INTEGER: 349848b8605Smrg return GL_RED; 350848b8605Smrg case GL_GREEN_INTEGER: 351848b8605Smrg return GL_GREEN; 352848b8605Smrg case GL_BLUE_INTEGER: 353848b8605Smrg return GL_BLUE; 354848b8605Smrg case GL_ALPHA_INTEGER: 355848b8605Smrg return GL_ALPHA; 356848b8605Smrg case GL_LUMINANCE_INTEGER_EXT: 357848b8605Smrg return GL_LUMINANCE; 358848b8605Smrg case GL_LUMINANCE_ALPHA_INTEGER_EXT: 359848b8605Smrg return GL_LUMINANCE_ALPHA; 360848b8605Smrg default: 361848b8605Smrg return format; 362848b8605Smrg } 363848b8605Smrg} 364848b8605Smrg 365848b8605Smrg 366848b8605Smrg/** 367848b8605Smrg * Get an uncompressed color texture image. 368848b8605Smrg */ 369848b8605Smrgstatic void 370848b8605Smrgget_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, 371848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 372848b8605Smrg struct gl_texture_image *texImage, 373848b8605Smrg GLbitfield transferOps) 374848b8605Smrg{ 375848b8605Smrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 376848b8605Smrg const mesa_format texFormat = 377848b8605Smrg _mesa_get_srgb_format_linear(texImage->TexFormat); 378848b8605Smrg const GLuint width = texImage->Width; 379848b8605Smrg GLenum destBaseFormat = _mesa_base_pack_format(format); 380848b8605Smrg GLenum rebaseFormat = GL_NONE; 381848b8605Smrg GLuint height = texImage->Height; 382848b8605Smrg GLuint depth = texImage->Depth; 383848b8605Smrg GLuint img, row; 384848b8605Smrg GLfloat (*rgba)[4]; 385848b8605Smrg GLuint (*rgba_uint)[4]; 386848b8605Smrg GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); 387848b8605Smrg GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); 388848b8605Smrg GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); 389848b8605Smrg 390848b8605Smrg /* Allocate buffer for one row of texels */ 391848b8605Smrg rgba = malloc(4 * width * sizeof(GLfloat)); 392848b8605Smrg rgba_uint = (GLuint (*)[4]) rgba; 393848b8605Smrg if (!rgba) { 394848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 395848b8605Smrg return; 396848b8605Smrg } 397848b8605Smrg 398848b8605Smrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 399848b8605Smrg depth = height; 400848b8605Smrg height = 1; 401848b8605Smrg } 402848b8605Smrg 403848b8605Smrg if (texImage->_BaseFormat == GL_LUMINANCE || 404848b8605Smrg texImage->_BaseFormat == GL_INTENSITY || 405848b8605Smrg texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { 406848b8605Smrg /* If a luminance (or intensity) texture is read back as RGB(A), the 407848b8605Smrg * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat 408848b8605Smrg * here to get G=B=0. 409848b8605Smrg */ 410848b8605Smrg rebaseFormat = texImage->_BaseFormat; 411848b8605Smrg } 412848b8605Smrg else if ((texImage->_BaseFormat == GL_RGBA || 413848b8605Smrg texImage->_BaseFormat == GL_RGB || 414848b8605Smrg texImage->_BaseFormat == GL_RG) && 415848b8605Smrg (destBaseFormat == GL_LUMINANCE || 416848b8605Smrg destBaseFormat == GL_LUMINANCE_ALPHA || 417848b8605Smrg destBaseFormat == GL_LUMINANCE_INTEGER_EXT || 418848b8605Smrg destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { 419848b8605Smrg /* If we're reading back an RGB(A) texture as luminance then we need 420848b8605Smrg * to return L=tex(R). Note, that's different from glReadPixels which 421848b8605Smrg * returns L=R+G+B. 422848b8605Smrg */ 423848b8605Smrg rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ 424848b8605Smrg } 425848b8605Smrg else if (texImage->_BaseFormat != texBaseFormat) { 426848b8605Smrg /* The internal format and the real format differ, so we can't rely 427848b8605Smrg * on the unpack functions setting the correct constant values. 428848b8605Smrg * (e.g. reading back GL_RGB8 which is actually RGBA won't set alpha=1) 429848b8605Smrg */ 430848b8605Smrg switch (texImage->_BaseFormat) { 431848b8605Smrg case GL_RED: 432848b8605Smrg if ((texBaseFormat == GL_RGBA || 433848b8605Smrg texBaseFormat == GL_RGB || 434848b8605Smrg texBaseFormat == GL_RG) && 435848b8605Smrg (destBaseFormat == GL_RGBA || 436848b8605Smrg destBaseFormat == GL_RGB || 437848b8605Smrg destBaseFormat == GL_RG || 438848b8605Smrg destBaseFormat == GL_GREEN)) { 439848b8605Smrg rebaseFormat = texImage->_BaseFormat; 440848b8605Smrg break; 441848b8605Smrg } 442848b8605Smrg /* fall through */ 443848b8605Smrg case GL_RG: 444848b8605Smrg if ((texBaseFormat == GL_RGBA || 445848b8605Smrg texBaseFormat == GL_RGB) && 446848b8605Smrg (destBaseFormat == GL_RGBA || 447848b8605Smrg destBaseFormat == GL_RGB || 448848b8605Smrg destBaseFormat == GL_BLUE)) { 449848b8605Smrg rebaseFormat = texImage->_BaseFormat; 450848b8605Smrg break; 451848b8605Smrg } 452848b8605Smrg /* fall through */ 453848b8605Smrg case GL_RGB: 454848b8605Smrg if (texBaseFormat == GL_RGBA && 455848b8605Smrg (destBaseFormat == GL_RGBA || 456848b8605Smrg destBaseFormat == GL_ALPHA || 457848b8605Smrg destBaseFormat == GL_LUMINANCE_ALPHA)) { 458848b8605Smrg rebaseFormat = texImage->_BaseFormat; 459848b8605Smrg } 460848b8605Smrg break; 461848b8605Smrg 462848b8605Smrg case GL_ALPHA: 463848b8605Smrg if (destBaseFormat != GL_ALPHA) { 464848b8605Smrg rebaseFormat = texImage->_BaseFormat; 465848b8605Smrg } 466848b8605Smrg break; 467848b8605Smrg } 468848b8605Smrg } 469848b8605Smrg 470848b8605Smrg for (img = 0; img < depth; img++) { 471848b8605Smrg GLubyte *srcMap; 472848b8605Smrg GLint rowstride; 473848b8605Smrg 474848b8605Smrg /* map src texture buffer */ 475848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, img, 476848b8605Smrg 0, 0, width, height, GL_MAP_READ_BIT, 477848b8605Smrg &srcMap, &rowstride); 478848b8605Smrg if (srcMap) { 479848b8605Smrg for (row = 0; row < height; row++) { 480848b8605Smrg const GLubyte *src = srcMap + row * rowstride; 481848b8605Smrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 482848b8605Smrg width, height, format, type, 483848b8605Smrg img, row, 0); 484848b8605Smrg 485848b8605Smrg if (tex_is_integer) { 486848b8605Smrg _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); 487848b8605Smrg if (rebaseFormat) 488848b8605Smrg _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); 489848b8605Smrg if (tex_is_uint) { 490848b8605Smrg _mesa_pack_rgba_span_from_uints(ctx, width, 491848b8605Smrg (GLuint (*)[4]) rgba_uint, 492848b8605Smrg format, type, dest); 493848b8605Smrg } else { 494848b8605Smrg _mesa_pack_rgba_span_from_ints(ctx, width, 495848b8605Smrg (GLint (*)[4]) rgba_uint, 496848b8605Smrg format, type, dest); 497848b8605Smrg } 498848b8605Smrg } else { 499848b8605Smrg _mesa_unpack_rgba_row(texFormat, width, src, rgba); 500848b8605Smrg if (rebaseFormat) 501848b8605Smrg _mesa_rebase_rgba_float(width, rgba, rebaseFormat); 502848b8605Smrg _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, 503848b8605Smrg format, type, dest, 504848b8605Smrg &ctx->Pack, transferOps); 505848b8605Smrg } 506848b8605Smrg } 507848b8605Smrg 508848b8605Smrg /* Unmap the src texture buffer */ 509848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 510848b8605Smrg } 511848b8605Smrg else { 512848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 513848b8605Smrg break; 514848b8605Smrg } 515848b8605Smrg } 516848b8605Smrg 517848b8605Smrg free(rgba); 518848b8605Smrg} 519848b8605Smrg 520848b8605Smrg 521848b8605Smrg/** 522848b8605Smrg * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). 523848b8605Smrg * Compressed textures are handled here as well. 524848b8605Smrg */ 525848b8605Smrgstatic void 526848b8605Smrgget_tex_rgba(struct gl_context *ctx, GLuint dimensions, 527848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 528848b8605Smrg struct gl_texture_image *texImage) 529848b8605Smrg{ 530848b8605Smrg const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); 531848b8605Smrg GLbitfield transferOps = 0x0; 532848b8605Smrg 533848b8605Smrg /* In general, clamping does not apply to glGetTexImage, except when 534848b8605Smrg * the returned type of the image can't hold negative values. 535848b8605Smrg */ 536848b8605Smrg if (type_needs_clamping(type)) { 537848b8605Smrg /* the returned image type can't have negative values */ 538848b8605Smrg if (dataType == GL_FLOAT || 539848b8605Smrg dataType == GL_HALF_FLOAT || 540848b8605Smrg dataType == GL_SIGNED_NORMALIZED || 541848b8605Smrg format == GL_LUMINANCE || 542848b8605Smrg format == GL_LUMINANCE_ALPHA) { 543848b8605Smrg transferOps |= IMAGE_CLAMP_BIT; 544848b8605Smrg } 545848b8605Smrg } 546848b8605Smrg 547848b8605Smrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 548848b8605Smrg get_tex_rgba_compressed(ctx, dimensions, format, type, 549848b8605Smrg pixels, texImage, transferOps); 550848b8605Smrg } 551848b8605Smrg else { 552848b8605Smrg get_tex_rgba_uncompressed(ctx, dimensions, format, type, 553848b8605Smrg pixels, texImage, transferOps); 554848b8605Smrg } 555848b8605Smrg} 556848b8605Smrg 557848b8605Smrg 558848b8605Smrg/** 559848b8605Smrg * Try to do glGetTexImage() with simple memcpy(). 560848b8605Smrg * \return GL_TRUE if done, GL_FALSE otherwise 561848b8605Smrg */ 562848b8605Smrgstatic GLboolean 563848b8605Smrgget_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, 564848b8605Smrg GLvoid *pixels, 565848b8605Smrg struct gl_texture_image *texImage) 566848b8605Smrg{ 567848b8605Smrg const GLenum target = texImage->TexObject->Target; 568848b8605Smrg GLboolean memCopy = GL_FALSE; 569848b8605Smrg GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); 570848b8605Smrg 571848b8605Smrg /* 572848b8605Smrg * Check if we can use memcpy to copy from the hardware texture 573848b8605Smrg * format to the user's format/type. 574848b8605Smrg * Note that GL's pixel transfer ops don't apply to glGetTexImage() 575848b8605Smrg */ 576848b8605Smrg if ((target == GL_TEXTURE_1D || 577848b8605Smrg target == GL_TEXTURE_2D || 578848b8605Smrg target == GL_TEXTURE_RECTANGLE || 579848b8605Smrg _mesa_is_cube_face(target)) && 580848b8605Smrg texBaseFormat == texImage->_BaseFormat) { 581848b8605Smrg memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, 582848b8605Smrg format, type, 583848b8605Smrg ctx->Pack.SwapBytes); 584848b8605Smrg } 585848b8605Smrg 586848b8605Smrg if (memCopy) { 587848b8605Smrg const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); 588848b8605Smrg const GLuint bytesPerRow = texImage->Width * bpp; 589848b8605Smrg GLubyte *dst = 590848b8605Smrg _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width, 591848b8605Smrg texImage->Height, format, type, 0, 0); 592848b8605Smrg const GLint dstRowStride = 593848b8605Smrg _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type); 594848b8605Smrg GLubyte *src; 595848b8605Smrg GLint srcRowStride; 596848b8605Smrg 597848b8605Smrg /* map src texture buffer */ 598848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, 0, 599848b8605Smrg 0, 0, texImage->Width, texImage->Height, 600848b8605Smrg GL_MAP_READ_BIT, &src, &srcRowStride); 601848b8605Smrg 602848b8605Smrg if (src) { 603848b8605Smrg if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { 604848b8605Smrg memcpy(dst, src, bytesPerRow * texImage->Height); 605848b8605Smrg } 606848b8605Smrg else { 607848b8605Smrg GLuint row; 608848b8605Smrg for (row = 0; row < texImage->Height; row++) { 609848b8605Smrg memcpy(dst, src, bytesPerRow); 610848b8605Smrg dst += dstRowStride; 611848b8605Smrg src += srcRowStride; 612848b8605Smrg } 613848b8605Smrg } 614848b8605Smrg 615848b8605Smrg /* unmap src texture buffer */ 616848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 617848b8605Smrg } 618848b8605Smrg else { 619848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 620848b8605Smrg } 621848b8605Smrg } 622848b8605Smrg 623848b8605Smrg return memCopy; 624848b8605Smrg} 625848b8605Smrg 626848b8605Smrg 627848b8605Smrg/** 628848b8605Smrg * This is the software fallback for Driver.GetTexImage(). 629848b8605Smrg * All error checking will have been done before this routine is called. 630848b8605Smrg * We'll call ctx->Driver.MapTextureImage() to access the data, then 631848b8605Smrg * unmap with ctx->Driver.UnmapTextureImage(). 632848b8605Smrg */ 633848b8605Smrgvoid 634848b8605Smrg_mesa_get_teximage(struct gl_context *ctx, 635848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 636848b8605Smrg struct gl_texture_image *texImage) 637848b8605Smrg{ 638848b8605Smrg const GLuint dimensions = 639848b8605Smrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 640848b8605Smrg 641848b8605Smrg /* map dest buffer, if PBO */ 642848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 643848b8605Smrg /* Packing texture image into a PBO. 644848b8605Smrg * Map the (potentially) VRAM-based buffer into our process space so 645848b8605Smrg * we can write into it with the code below. 646848b8605Smrg * A hardware driver might use a sophisticated blit to move the 647848b8605Smrg * texture data to the PBO if the PBO is in VRAM along with the texture. 648848b8605Smrg */ 649848b8605Smrg GLubyte *buf = (GLubyte *) 650848b8605Smrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 651848b8605Smrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 652848b8605Smrg MAP_INTERNAL); 653848b8605Smrg if (!buf) { 654848b8605Smrg /* out of memory or other unexpected error */ 655848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 656848b8605Smrg return; 657848b8605Smrg } 658848b8605Smrg /* <pixels> was an offset into the PBO. 659848b8605Smrg * Now make it a real, client-side pointer inside the mapped region. 660848b8605Smrg */ 661848b8605Smrg pixels = ADD_POINTERS(buf, pixels); 662848b8605Smrg } 663848b8605Smrg 664848b8605Smrg if (get_tex_memcpy(ctx, format, type, pixels, texImage)) { 665848b8605Smrg /* all done */ 666848b8605Smrg } 667848b8605Smrg else if (format == GL_DEPTH_COMPONENT) { 668848b8605Smrg get_tex_depth(ctx, dimensions, format, type, pixels, texImage); 669848b8605Smrg } 670848b8605Smrg else if (format == GL_DEPTH_STENCIL_EXT) { 671848b8605Smrg get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage); 672848b8605Smrg } 673848b8605Smrg else if (format == GL_YCBCR_MESA) { 674848b8605Smrg get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage); 675848b8605Smrg } 676848b8605Smrg else { 677848b8605Smrg get_tex_rgba(ctx, dimensions, format, type, pixels, texImage); 678848b8605Smrg } 679848b8605Smrg 680848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 681848b8605Smrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 682848b8605Smrg } 683848b8605Smrg} 684848b8605Smrg 685848b8605Smrg 686848b8605Smrg 687848b8605Smrg/** 688848b8605Smrg * This is the software fallback for Driver.GetCompressedTexImage(). 689848b8605Smrg * All error checking will have been done before this routine is called. 690848b8605Smrg */ 691848b8605Smrgvoid 692848b8605Smrg_mesa_get_compressed_teximage(struct gl_context *ctx, 693848b8605Smrg struct gl_texture_image *texImage, 694848b8605Smrg GLvoid *img) 695848b8605Smrg{ 696848b8605Smrg const GLuint dimensions = 697848b8605Smrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 698848b8605Smrg struct compressed_pixelstore store; 699848b8605Smrg GLuint i, slice; 700848b8605Smrg GLubyte *dest; 701848b8605Smrg 702848b8605Smrg _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat, 703848b8605Smrg texImage->Width, texImage->Height, 704848b8605Smrg texImage->Depth, 705848b8605Smrg &ctx->Pack, 706848b8605Smrg &store); 707848b8605Smrg 708848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 709848b8605Smrg /* pack texture image into a PBO */ 710848b8605Smrg dest = (GLubyte *) 711848b8605Smrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 712848b8605Smrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 713848b8605Smrg MAP_INTERNAL); 714848b8605Smrg if (!dest) { 715848b8605Smrg /* out of memory or other unexpected error */ 716848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 717848b8605Smrg "glGetCompresssedTexImage(map PBO failed)"); 718848b8605Smrg return; 719848b8605Smrg } 720848b8605Smrg dest = ADD_POINTERS(dest, img); 721848b8605Smrg } else { 722848b8605Smrg dest = img; 723848b8605Smrg } 724848b8605Smrg 725848b8605Smrg dest += store.SkipBytes; 726848b8605Smrg 727848b8605Smrg for (slice = 0; slice < store.CopySlices; slice++) { 728848b8605Smrg GLint srcRowStride; 729848b8605Smrg GLubyte *src; 730848b8605Smrg 731848b8605Smrg /* map src texture buffer */ 732848b8605Smrg ctx->Driver.MapTextureImage(ctx, texImage, 0, 733848b8605Smrg 0, 0, texImage->Width, texImage->Height, 734848b8605Smrg GL_MAP_READ_BIT, &src, &srcRowStride); 735848b8605Smrg 736848b8605Smrg if (src) { 737848b8605Smrg 738848b8605Smrg for (i = 0; i < store.CopyRowsPerSlice; i++) { 739848b8605Smrg memcpy(dest, src, store.CopyBytesPerRow); 740848b8605Smrg dest += store.TotalBytesPerRow; 741848b8605Smrg src += srcRowStride; 742848b8605Smrg } 743848b8605Smrg 744848b8605Smrg ctx->Driver.UnmapTextureImage(ctx, texImage, 0); 745848b8605Smrg 746848b8605Smrg /* Advance to next slice */ 747848b8605Smrg dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice); 748848b8605Smrg 749848b8605Smrg } else { 750848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); 751848b8605Smrg } 752848b8605Smrg } 753848b8605Smrg 754848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 755848b8605Smrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 756848b8605Smrg } 757848b8605Smrg} 758848b8605Smrg 759848b8605Smrg 760848b8605Smrg/** 761848b8605Smrg * Validate the texture target enum supplied to glTexImage or 762848b8605Smrg * glCompressedTexImage. 763848b8605Smrg */ 764848b8605Smrgstatic GLboolean 765848b8605Smrglegal_getteximage_target(struct gl_context *ctx, GLenum target) 766848b8605Smrg{ 767848b8605Smrg switch (target) { 768848b8605Smrg case GL_TEXTURE_1D: 769848b8605Smrg case GL_TEXTURE_2D: 770848b8605Smrg case GL_TEXTURE_3D: 771848b8605Smrg return GL_TRUE; 772848b8605Smrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: 773848b8605Smrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: 774848b8605Smrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: 775848b8605Smrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: 776848b8605Smrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: 777848b8605Smrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: 778848b8605Smrg return ctx->Extensions.ARB_texture_cube_map; 779848b8605Smrg case GL_TEXTURE_RECTANGLE_NV: 780848b8605Smrg return ctx->Extensions.NV_texture_rectangle; 781848b8605Smrg case GL_TEXTURE_1D_ARRAY_EXT: 782848b8605Smrg case GL_TEXTURE_2D_ARRAY_EXT: 783848b8605Smrg return ctx->Extensions.EXT_texture_array; 784848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARRAY: 785848b8605Smrg return ctx->Extensions.ARB_texture_cube_map_array; 786848b8605Smrg default: 787848b8605Smrg return GL_FALSE; 788848b8605Smrg } 789848b8605Smrg} 790848b8605Smrg 791848b8605Smrg 792848b8605Smrg/** 793848b8605Smrg * Do error checking for a glGetTexImage() call. 794848b8605Smrg * \return GL_TRUE if any error, GL_FALSE if no errors. 795848b8605Smrg */ 796848b8605Smrgstatic GLboolean 797848b8605Smrggetteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, 798848b8605Smrg GLenum format, GLenum type, GLsizei clientMemSize, 799848b8605Smrg GLvoid *pixels ) 800848b8605Smrg{ 801848b8605Smrg struct gl_texture_object *texObj; 802848b8605Smrg struct gl_texture_image *texImage; 803848b8605Smrg const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 804848b8605Smrg const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 805848b8605Smrg GLenum baseFormat, err; 806848b8605Smrg 807848b8605Smrg if (!legal_getteximage_target(ctx, target)) { 808848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); 809848b8605Smrg return GL_TRUE; 810848b8605Smrg } 811848b8605Smrg 812848b8605Smrg assert(maxLevels != 0); 813848b8605Smrg if (level < 0 || level >= maxLevels) { 814848b8605Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); 815848b8605Smrg return GL_TRUE; 816848b8605Smrg } 817848b8605Smrg 818848b8605Smrg err = _mesa_error_check_format_and_type(ctx, format, type); 819848b8605Smrg if (err != GL_NO_ERROR) { 820848b8605Smrg _mesa_error(ctx, err, "glGetTexImage(format/type)"); 821848b8605Smrg return GL_TRUE; 822848b8605Smrg } 823848b8605Smrg 824848b8605Smrg texObj = _mesa_get_current_tex_object(ctx, target); 825848b8605Smrg 826848b8605Smrg if (!texObj) { 827848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); 828848b8605Smrg return GL_TRUE; 829848b8605Smrg } 830848b8605Smrg 831848b8605Smrg texImage = _mesa_select_tex_image(ctx, texObj, target, level); 832848b8605Smrg if (!texImage) { 833848b8605Smrg /* non-existant texture image */ 834848b8605Smrg return GL_TRUE; 835848b8605Smrg } 836848b8605Smrg 837848b8605Smrg baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 838848b8605Smrg 839848b8605Smrg /* Make sure the requested image format is compatible with the 840848b8605Smrg * texture's format. 841848b8605Smrg */ 842848b8605Smrg if (_mesa_is_color_format(format) 843848b8605Smrg && !_mesa_is_color_format(baseFormat)) { 844848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 845848b8605Smrg return GL_TRUE; 846848b8605Smrg } 847848b8605Smrg else if (_mesa_is_depth_format(format) 848848b8605Smrg && !_mesa_is_depth_format(baseFormat) 849848b8605Smrg && !_mesa_is_depthstencil_format(baseFormat)) { 850848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 851848b8605Smrg return GL_TRUE; 852848b8605Smrg } 853848b8605Smrg else if (_mesa_is_stencil_format(format) 854848b8605Smrg && !ctx->Extensions.ARB_texture_stencil8) { 855848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)"); 856848b8605Smrg return GL_TRUE; 857848b8605Smrg } 858848b8605Smrg else if (_mesa_is_ycbcr_format(format) 859848b8605Smrg && !_mesa_is_ycbcr_format(baseFormat)) { 860848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 861848b8605Smrg return GL_TRUE; 862848b8605Smrg } 863848b8605Smrg else if (_mesa_is_depthstencil_format(format) 864848b8605Smrg && !_mesa_is_depthstencil_format(baseFormat)) { 865848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 866848b8605Smrg return GL_TRUE; 867848b8605Smrg } 868848b8605Smrg else if (_mesa_is_enum_format_integer(format) != 869848b8605Smrg _mesa_is_format_integer(texImage->TexFormat)) { 870848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 871848b8605Smrg return GL_TRUE; 872848b8605Smrg } 873848b8605Smrg 874848b8605Smrg if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, 875848b8605Smrg texImage->Height, texImage->Depth, 876848b8605Smrg format, type, clientMemSize, pixels)) { 877848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 878848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 879848b8605Smrg "glGetTexImage(out of bounds PBO access)"); 880848b8605Smrg } else { 881848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 882848b8605Smrg "glGetnTexImageARB(out of bounds access:" 883848b8605Smrg " bufSize (%d) is too small)", clientMemSize); 884848b8605Smrg } 885848b8605Smrg return GL_TRUE; 886848b8605Smrg } 887848b8605Smrg 888848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 889848b8605Smrg /* PBO should not be mapped */ 890848b8605Smrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 891848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 892848b8605Smrg "glGetTexImage(PBO is mapped)"); 893848b8605Smrg return GL_TRUE; 894848b8605Smrg } 895848b8605Smrg } 896848b8605Smrg 897848b8605Smrg return GL_FALSE; 898848b8605Smrg} 899848b8605Smrg 900848b8605Smrg 901848b8605Smrg 902848b8605Smrg/** 903848b8605Smrg * Get texture image. Called by glGetTexImage. 904848b8605Smrg * 905848b8605Smrg * \param target texture target. 906848b8605Smrg * \param level image level. 907848b8605Smrg * \param format pixel data format for returned image. 908848b8605Smrg * \param type pixel data type for returned image. 909848b8605Smrg * \param bufSize size of the pixels data buffer. 910848b8605Smrg * \param pixels returned pixel data. 911848b8605Smrg */ 912848b8605Smrgvoid GLAPIENTRY 913848b8605Smrg_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format, 914848b8605Smrg GLenum type, GLsizei bufSize, GLvoid *pixels ) 915848b8605Smrg{ 916848b8605Smrg struct gl_texture_object *texObj; 917848b8605Smrg struct gl_texture_image *texImage; 918848b8605Smrg GET_CURRENT_CONTEXT(ctx); 919848b8605Smrg 920848b8605Smrg FLUSH_VERTICES(ctx, 0); 921848b8605Smrg 922848b8605Smrg if (getteximage_error_check(ctx, target, level, format, type, 923848b8605Smrg bufSize, pixels)) { 924848b8605Smrg return; 925848b8605Smrg } 926848b8605Smrg 927848b8605Smrg if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 928848b8605Smrg /* not an error, do nothing */ 929848b8605Smrg return; 930848b8605Smrg } 931848b8605Smrg 932848b8605Smrg texObj = _mesa_get_current_tex_object(ctx, target); 933848b8605Smrg texImage = _mesa_select_tex_image(ctx, texObj, target, level); 934848b8605Smrg 935848b8605Smrg if (_mesa_is_zero_size_texture(texImage)) 936848b8605Smrg return; 937848b8605Smrg 938848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 939848b8605Smrg _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d," 940848b8605Smrg " dstFmt=0x%x, dstType=0x%x\n", 941848b8605Smrg texObj->Name, 942848b8605Smrg _mesa_get_format_name(texImage->TexFormat), 943848b8605Smrg texImage->Width, texImage->Height, 944848b8605Smrg format, type); 945848b8605Smrg } 946848b8605Smrg 947848b8605Smrg _mesa_lock_texture(ctx, texObj); 948848b8605Smrg { 949848b8605Smrg ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage); 950848b8605Smrg } 951848b8605Smrg _mesa_unlock_texture(ctx, texObj); 952848b8605Smrg} 953848b8605Smrg 954848b8605Smrg 955848b8605Smrgvoid GLAPIENTRY 956848b8605Smrg_mesa_GetTexImage( GLenum target, GLint level, GLenum format, 957848b8605Smrg GLenum type, GLvoid *pixels ) 958848b8605Smrg{ 959848b8605Smrg _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels); 960848b8605Smrg} 961848b8605Smrg 962848b8605Smrg 963848b8605Smrg/** 964848b8605Smrg * Do error checking for a glGetCompressedTexImage() call. 965848b8605Smrg * \return GL_TRUE if any error, GL_FALSE if no errors. 966848b8605Smrg */ 967848b8605Smrgstatic GLboolean 968848b8605Smrggetcompressedteximage_error_check(struct gl_context *ctx, GLenum target, 969848b8605Smrg GLint level, GLsizei clientMemSize, GLvoid *img) 970848b8605Smrg{ 971848b8605Smrg struct gl_texture_object *texObj; 972848b8605Smrg struct gl_texture_image *texImage; 973848b8605Smrg const GLint maxLevels = _mesa_max_texture_levels(ctx, target); 974848b8605Smrg GLuint compressedSize, dimensions; 975848b8605Smrg 976848b8605Smrg if (!legal_getteximage_target(ctx, target)) { 977848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", 978848b8605Smrg target); 979848b8605Smrg return GL_TRUE; 980848b8605Smrg } 981848b8605Smrg 982848b8605Smrg assert(maxLevels != 0); 983848b8605Smrg if (level < 0 || level >= maxLevels) { 984848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 985848b8605Smrg "glGetCompressedTexImageARB(bad level = %d)", level); 986848b8605Smrg return GL_TRUE; 987848b8605Smrg } 988848b8605Smrg 989848b8605Smrg texObj = _mesa_get_current_tex_object(ctx, target); 990848b8605Smrg if (!texObj) { 991848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); 992848b8605Smrg return GL_TRUE; 993848b8605Smrg } 994848b8605Smrg 995848b8605Smrg texImage = _mesa_select_tex_image(ctx, texObj, target, level); 996848b8605Smrg 997848b8605Smrg if (!texImage) { 998848b8605Smrg /* probably invalid mipmap level */ 999848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1000848b8605Smrg "glGetCompressedTexImageARB(level)"); 1001848b8605Smrg return GL_TRUE; 1002848b8605Smrg } 1003848b8605Smrg 1004848b8605Smrg if (!_mesa_is_format_compressed(texImage->TexFormat)) { 1005848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1006848b8605Smrg "glGetCompressedTexImageARB(texture is not compressed)"); 1007848b8605Smrg return GL_TRUE; 1008848b8605Smrg } 1009848b8605Smrg 1010848b8605Smrg compressedSize = _mesa_format_image_size(texImage->TexFormat, 1011848b8605Smrg texImage->Width, 1012848b8605Smrg texImage->Height, 1013848b8605Smrg texImage->Depth); 1014848b8605Smrg 1015848b8605Smrg /* Check for invalid pixel storage modes */ 1016848b8605Smrg dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target); 1017848b8605Smrg if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, 1018848b8605Smrg &ctx->Pack, 1019848b8605Smrg "glGetCompressedTexImageARB")) { 1020848b8605Smrg return GL_TRUE; 1021848b8605Smrg } 1022848b8605Smrg 1023848b8605Smrg if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 1024848b8605Smrg /* do bounds checking on writing to client memory */ 1025848b8605Smrg if (clientMemSize < (GLsizei) compressedSize) { 1026848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1027848b8605Smrg "glGetnCompressedTexImageARB(out of bounds access:" 1028848b8605Smrg " bufSize (%d) is too small)", clientMemSize); 1029848b8605Smrg return GL_TRUE; 1030848b8605Smrg } 1031848b8605Smrg } else { 1032848b8605Smrg /* do bounds checking on PBO write */ 1033848b8605Smrg if ((const GLubyte *) img + compressedSize > 1034848b8605Smrg (const GLubyte *) ctx->Pack.BufferObj->Size) { 1035848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1036848b8605Smrg "glGetCompressedTexImage(out of bounds PBO access)"); 1037848b8605Smrg return GL_TRUE; 1038848b8605Smrg } 1039848b8605Smrg 1040848b8605Smrg /* make sure PBO is not mapped */ 1041848b8605Smrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 1042848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1043848b8605Smrg "glGetCompressedTexImage(PBO is mapped)"); 1044848b8605Smrg return GL_TRUE; 1045848b8605Smrg } 1046848b8605Smrg } 1047848b8605Smrg 1048848b8605Smrg return GL_FALSE; 1049848b8605Smrg} 1050848b8605Smrg 1051848b8605Smrg 1052848b8605Smrgvoid GLAPIENTRY 1053848b8605Smrg_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 1054848b8605Smrg GLvoid *img) 1055848b8605Smrg{ 1056848b8605Smrg struct gl_texture_object *texObj; 1057848b8605Smrg struct gl_texture_image *texImage; 1058848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1059848b8605Smrg 1060848b8605Smrg FLUSH_VERTICES(ctx, 0); 1061848b8605Smrg 1062848b8605Smrg if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) { 1063848b8605Smrg return; 1064848b8605Smrg } 1065848b8605Smrg 1066848b8605Smrg if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) { 1067848b8605Smrg /* not an error, do nothing */ 1068848b8605Smrg return; 1069848b8605Smrg } 1070848b8605Smrg 1071848b8605Smrg texObj = _mesa_get_current_tex_object(ctx, target); 1072848b8605Smrg texImage = _mesa_select_tex_image(ctx, texObj, target, level); 1073848b8605Smrg 1074848b8605Smrg if (_mesa_is_zero_size_texture(texImage)) 1075848b8605Smrg return; 1076848b8605Smrg 1077848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 1078848b8605Smrg _mesa_debug(ctx, 1079848b8605Smrg "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n", 1080848b8605Smrg texObj->Name, 1081848b8605Smrg _mesa_get_format_name(texImage->TexFormat), 1082848b8605Smrg texImage->Width, texImage->Height); 1083848b8605Smrg } 1084848b8605Smrg 1085848b8605Smrg _mesa_lock_texture(ctx, texObj); 1086848b8605Smrg { 1087848b8605Smrg ctx->Driver.GetCompressedTexImage(ctx, texImage, img); 1088848b8605Smrg } 1089848b8605Smrg _mesa_unlock_texture(ctx, texObj); 1090848b8605Smrg} 1091848b8605Smrg 1092848b8605Smrgvoid GLAPIENTRY 1093848b8605Smrg_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img) 1094848b8605Smrg{ 1095848b8605Smrg _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img); 1096848b8605Smrg} 1097