texgetimage.c revision d6ee86c77a8e1543557fd64c1f1c354baa0a8ad8
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.5 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (c) 2009 VMware, Inc. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * Code for glGetTexImage() and glGetCompressedTexImage(). 29 */ 30 31 32#include "glheader.h" 33#include "bufferobj.h" 34#include "context.h" 35#include "formats.h" 36#include "image.h" 37#include "texcompress.h" 38#include "texgetimage.h" 39#include "teximage.h" 40#include "texstate.h" 41 42 43 44#if FEATURE_EXT_texture_sRGB 45 46/** 47 * Test if given texture image is an sRGB format. 48 */ 49static GLboolean 50is_srgb_teximage(const struct gl_texture_image *texImage) 51{ 52 switch (texImage->TexFormat) { 53 case MESA_FORMAT_SRGB8: 54 case MESA_FORMAT_SRGBA8: 55 case MESA_FORMAT_SARGB8: 56 case MESA_FORMAT_SL8: 57 case MESA_FORMAT_SLA8: 58 case MESA_FORMAT_SRGB_DXT1: 59 case MESA_FORMAT_SRGBA_DXT1: 60 case MESA_FORMAT_SRGBA_DXT3: 61 case MESA_FORMAT_SRGBA_DXT5: 62 return GL_TRUE; 63 default: 64 return GL_FALSE; 65 } 66} 67 68 69/** 70 * Convert a float value from linear space to a 71 * non-linear sRGB value in [0, 255]. 72 * Not terribly efficient. 73 */ 74static INLINE GLfloat 75linear_to_nonlinear(GLfloat cl) 76{ 77 /* can't have values outside [0, 1] */ 78 GLfloat cs; 79 if (cl < 0.0031308f) { 80 cs = 12.92f * cl; 81 } 82 else { 83 cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055); 84 } 85 return cs; 86} 87 88#endif /* FEATURE_EXT_texture_sRGB */ 89 90 91/** 92 * Can the given type represent negative values? 93 */ 94static INLINE GLboolean 95type_with_negative_values(GLenum type) 96{ 97 switch (type) { 98 case GL_BYTE: 99 case GL_SHORT: 100 case GL_INT: 101 case GL_FLOAT: 102 case GL_HALF_FLOAT_ARB: 103 return GL_TRUE; 104 default: 105 return GL_FALSE; 106 } 107} 108 109 110/** 111 * This is the software fallback for Driver.GetTexImage(). 112 * All error checking will have been done before this routine is called. 113 */ 114void 115_mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level, 116 GLenum format, GLenum type, GLvoid *pixels, 117 struct gl_texture_object *texObj, 118 struct gl_texture_image *texImage) 119{ 120 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 121 122 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 123 /* Packing texture image into a PBO. 124 * Map the (potentially) VRAM-based buffer into our process space so 125 * we can write into it with the code below. 126 * A hardware driver might use a sophisticated blit to move the 127 * texture data to the PBO if the PBO is in VRAM along with the texture. 128 */ 129 GLubyte *buf = (GLubyte *) 130 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 131 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); 132 if (!buf) { 133 /* buffer is already mapped - that's an error */ 134 _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)"); 135 return; 136 } 137 /* <pixels> was an offset into the PBO. 138 * Now make it a real, client-side pointer inside the mapped region. 139 */ 140 pixels = ADD_POINTERS(buf, pixels); 141 } 142 else if (!pixels) { 143 /* not an error */ 144 return; 145 } 146 147 { 148 const GLint width = texImage->Width; 149 const GLint height = texImage->Height; 150 const GLint depth = texImage->Depth; 151 GLint img, row; 152 for (img = 0; img < depth; img++) { 153 for (row = 0; row < height; row++) { 154 /* compute destination address in client memory */ 155 GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels, 156 width, height, format, type, 157 img, row, 0); 158 assert(dest); 159 160 if (format == GL_COLOR_INDEX) { 161 GLuint indexRow[MAX_WIDTH]; 162 GLint col; 163 GLuint indexBits = _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT); 164 /* Can't use FetchTexel here because that returns RGBA */ 165 if (indexBits == 8) { 166 const GLubyte *src = (const GLubyte *) texImage->Data; 167 src += width * (img * texImage->Height + row); 168 for (col = 0; col < width; col++) { 169 indexRow[col] = src[col]; 170 } 171 } 172 else if (indexBits == 16) { 173 const GLushort *src = (const GLushort *) texImage->Data; 174 src += width * (img * texImage->Height + row); 175 for (col = 0; col < width; col++) { 176 indexRow[col] = src[col]; 177 } 178 } 179 else { 180 _mesa_problem(ctx, 181 "Color index problem in _mesa_GetTexImage"); 182 } 183 _mesa_pack_index_span(ctx, width, type, dest, 184 indexRow, &ctx->Pack, 185 0 /* no image transfer */); 186 } 187 else if (format == GL_DEPTH_COMPONENT) { 188 GLfloat depthRow[MAX_WIDTH]; 189 GLint col; 190 for (col = 0; col < width; col++) { 191 (*texImage->FetchTexelf)(texImage, col, row, img, 192 depthRow + col); 193 } 194 _mesa_pack_depth_span(ctx, width, dest, type, 195 depthRow, &ctx->Pack); 196 } 197 else if (format == GL_DEPTH_STENCIL_EXT) { 198 /* XXX Note: we're bypassing texImage->FetchTexel()! */ 199 const GLuint *src = (const GLuint *) texImage->Data; 200 src += width * row + width * height * img; 201 _mesa_memcpy(dest, src, width * sizeof(GLuint)); 202 if (ctx->Pack.SwapBytes) { 203 _mesa_swap4((GLuint *) dest, width); 204 } 205 } 206 else if (format == GL_YCBCR_MESA) { 207 /* No pixel transfer */ 208 const GLint rowstride = texImage->RowStride; 209 MEMCPY(dest, 210 (const GLushort *) texImage->Data + row * rowstride, 211 width * sizeof(GLushort)); 212 /* check for byte swapping */ 213 if ((texImage->TexFormat == MESA_FORMAT_YCBCR 214 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || 215 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV 216 && type == GL_UNSIGNED_SHORT_8_8_MESA)) { 217 if (!ctx->Pack.SwapBytes) 218 _mesa_swap2((GLushort *) dest, width); 219 } 220 else if (ctx->Pack.SwapBytes) { 221 _mesa_swap2((GLushort *) dest, width); 222 } 223 } 224#if FEATURE_EXT_texture_sRGB 225 else if (is_srgb_teximage(texImage)) { 226 /* special case this since need to backconvert values */ 227 /* convert row to RGBA format */ 228 GLfloat rgba[MAX_WIDTH][4]; 229 GLint col; 230 GLbitfield transferOps = 0x0; 231 232 for (col = 0; col < width; col++) { 233 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); 234 if (texImage->_BaseFormat == GL_LUMINANCE) { 235 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); 236 rgba[col][GCOMP] = 0.0; 237 rgba[col][BCOMP] = 0.0; 238 } 239 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { 240 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); 241 rgba[col][GCOMP] = 0.0; 242 rgba[col][BCOMP] = 0.0; 243 } 244 else if (texImage->_BaseFormat == GL_RGB || 245 texImage->_BaseFormat == GL_RGBA) { 246 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); 247 rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); 248 rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); 249 } 250 } 251 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, 252 format, type, dest, 253 &ctx->Pack, transferOps); 254 } 255#endif /* FEATURE_EXT_texture_sRGB */ 256 else { 257 /* general case: convert row to RGBA format */ 258 GLfloat rgba[MAX_WIDTH][4]; 259 GLint col; 260 GLbitfield transferOps = 0x0; 261 GLenum dataType = 262 _mesa_get_format_datatype(texImage->TexFormat); 263 264 /* clamp does not apply to GetTexImage (final conversion)? 265 * Looks like we need clamp though when going from format 266 * containing negative values to unsigned format. 267 */ 268 if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) 269 transferOps |= IMAGE_CLAMP_BIT; 270 else if (!type_with_negative_values(type) && 271 (dataType == GL_FLOAT || 272 dataType == GL_SIGNED_NORMALIZED)) 273 transferOps |= IMAGE_CLAMP_BIT; 274 275 for (col = 0; col < width; col++) { 276 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); 277 if (texImage->_BaseFormat == GL_ALPHA) { 278 rgba[col][RCOMP] = 0.0; 279 rgba[col][GCOMP] = 0.0; 280 rgba[col][BCOMP] = 0.0; 281 } 282 else if (texImage->_BaseFormat == GL_LUMINANCE) { 283 rgba[col][GCOMP] = 0.0; 284 rgba[col][BCOMP] = 0.0; 285 rgba[col][ACOMP] = 1.0; 286 } 287 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { 288 rgba[col][GCOMP] = 0.0; 289 rgba[col][BCOMP] = 0.0; 290 } 291 else if (texImage->_BaseFormat == GL_INTENSITY) { 292 rgba[col][GCOMP] = 0.0; 293 rgba[col][BCOMP] = 0.0; 294 rgba[col][ACOMP] = 1.0; 295 } 296 } 297 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, 298 format, type, dest, 299 &ctx->Pack, transferOps); 300 } /* format */ 301 } /* row */ 302 } /* img */ 303 } 304 305 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 306 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 307 ctx->Pack.BufferObj); 308 } 309} 310 311 312 313/** 314 * This is the software fallback for Driver.GetCompressedTexImage(). 315 * All error checking will have been done before this routine is called. 316 */ 317void 318_mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level, 319 GLvoid *img, 320 struct gl_texture_object *texObj, 321 struct gl_texture_image *texImage) 322{ 323 const GLuint size = _mesa_format_image_size(texImage->TexFormat, 324 texImage->Width, 325 texImage->Height, 326 texImage->Depth); 327 328 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 329 /* pack texture image into a PBO */ 330 GLubyte *buf; 331 if ((const GLubyte *) img + size > 332 (const GLubyte *) ctx->Pack.BufferObj->Size) { 333 _mesa_error(ctx, GL_INVALID_OPERATION, 334 "glGetCompressedTexImage(invalid PBO access)"); 335 return; 336 } 337 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 338 GL_WRITE_ONLY_ARB, 339 ctx->Pack.BufferObj); 340 if (!buf) { 341 /* buffer is already mapped - that's an error */ 342 _mesa_error(ctx, GL_INVALID_OPERATION, 343 "glGetCompressedTexImage(PBO is mapped)"); 344 return; 345 } 346 img = ADD_POINTERS(buf, img); 347 } 348 else if (!img) { 349 /* not an error */ 350 return; 351 } 352 353 /* just memcpy, no pixelstore or pixel transfer */ 354 _mesa_memcpy(img, texImage->Data, size); 355 356 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 357 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 358 ctx->Pack.BufferObj); 359 } 360} 361 362 363 364/** 365 * Do error checking for a glGetTexImage() call. 366 * \return GL_TRUE if any error, GL_FALSE if no errors. 367 */ 368static GLboolean 369getteximage_error_check(GLcontext *ctx, GLenum target, GLint level, 370 GLenum format, GLenum type, GLvoid *pixels ) 371{ 372 const struct gl_texture_unit *texUnit; 373 struct gl_texture_object *texObj; 374 struct gl_texture_image *texImage; 375 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); 376 GLenum baseFormat; 377 378 if (maxLevels == 0) { 379 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); 380 return GL_TRUE; 381 } 382 383 if (level < 0 || level >= maxLevels) { 384 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); 385 return GL_TRUE; 386 } 387 388 if (_mesa_sizeof_packed_type(type) <= 0) { 389 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); 390 return GL_TRUE; 391 } 392 393 if (_mesa_components_in_format(format) <= 0 || 394 format == GL_STENCIL_INDEX) { 395 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); 396 return GL_TRUE; 397 } 398 399 if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { 400 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 401 return GL_TRUE; 402 } 403 404 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { 405 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 406 return GL_TRUE; 407 } 408 409 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { 410 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 411 return GL_TRUE; 412 } 413 414 if (!ctx->Extensions.EXT_packed_depth_stencil 415 && _mesa_is_depthstencil_format(format)) { 416 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 417 return GL_TRUE; 418 } 419 420 if (!ctx->Extensions.ATI_envmap_bumpmap 421 && _mesa_is_dudv_format(format)) { 422 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); 423 return GL_TRUE; 424 } 425 426 texUnit = _mesa_get_current_tex_unit(ctx); 427 texObj = _mesa_select_tex_object(ctx, texUnit, target); 428 429 if (!texObj || _mesa_is_proxy_texture(target)) { 430 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); 431 return GL_TRUE; 432 } 433 434 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 435 if (!texImage) { 436 /* out of memory */ 437 return GL_TRUE; 438 } 439 440 baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 441 442 /* Make sure the requested image format is compatible with the 443 * texture's format. Note that a color index texture can be converted 444 * to RGBA so that combo is allowed. 445 */ 446 if (_mesa_is_color_format(format) 447 && !_mesa_is_color_format(baseFormat) 448 && !_mesa_is_index_format(baseFormat)) { 449 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 450 return GL_TRUE; 451 } 452 else if (_mesa_is_index_format(format) 453 && !_mesa_is_index_format(baseFormat)) { 454 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 455 return GL_TRUE; 456 } 457 else if (_mesa_is_depth_format(format) 458 && !_mesa_is_depth_format(baseFormat) 459 && !_mesa_is_depthstencil_format(baseFormat)) { 460 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 461 return GL_TRUE; 462 } 463 else if (_mesa_is_ycbcr_format(format) 464 && !_mesa_is_ycbcr_format(baseFormat)) { 465 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 466 return GL_TRUE; 467 } 468 else if (_mesa_is_depthstencil_format(format) 469 && !_mesa_is_depthstencil_format(baseFormat)) { 470 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 471 return GL_TRUE; 472 } 473 else if (_mesa_is_dudv_format(format) 474 && !_mesa_is_dudv_format(baseFormat)) { 475 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); 476 return GL_TRUE; 477 } 478 479 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 480 /* packing texture image into a PBO */ 481 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 482 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, 483 texImage->Height, texImage->Depth, 484 format, type, pixels)) { 485 _mesa_error(ctx, GL_INVALID_OPERATION, 486 "glGetTexImage(invalid PBO access)"); 487 return GL_TRUE; 488 } 489 } 490 491 return GL_FALSE; 492} 493 494 495 496/** 497 * Get texture image. Called by glGetTexImage. 498 * 499 * \param target texture target. 500 * \param level image level. 501 * \param format pixel data format for returned image. 502 * \param type pixel data type for returned image. 503 * \param pixels returned pixel data. 504 */ 505void GLAPIENTRY 506_mesa_GetTexImage( GLenum target, GLint level, GLenum format, 507 GLenum type, GLvoid *pixels ) 508{ 509 const struct gl_texture_unit *texUnit; 510 struct gl_texture_object *texObj; 511 GET_CURRENT_CONTEXT(ctx); 512 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 513 514 if (getteximage_error_check(ctx, target, level, format, type, pixels)) { 515 return; 516 } 517 518 texUnit = _mesa_get_current_tex_unit(ctx); 519 texObj = _mesa_select_tex_object(ctx, texUnit, target); 520 521 _mesa_lock_texture(ctx, texObj); 522 { 523 struct gl_texture_image *texImage = 524 _mesa_select_tex_image(ctx, texObj, target, level); 525 526 /* typically, this will call _mesa_get_teximage() */ 527 ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels, 528 texObj, texImage); 529 } 530 _mesa_unlock_texture(ctx, texObj); 531} 532 533 534void GLAPIENTRY 535_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img) 536{ 537 const struct gl_texture_unit *texUnit; 538 struct gl_texture_object *texObj; 539 struct gl_texture_image *texImage; 540 GLint maxLevels; 541 GET_CURRENT_CONTEXT(ctx); 542 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); 543 544 texUnit = _mesa_get_current_tex_unit(ctx); 545 texObj = _mesa_select_tex_object(ctx, texUnit, target); 546 if (!texObj) { 547 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB"); 548 return; 549 } 550 551 maxLevels = _mesa_max_texture_levels(ctx, target); 552 ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */ 553 554 if (level < 0 || level >= maxLevels) { 555 _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); 556 return; 557 } 558 559 if (_mesa_is_proxy_texture(target)) { 560 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); 561 return; 562 } 563 564 _mesa_lock_texture(ctx, texObj); 565 { 566 texImage = _mesa_select_tex_image(ctx, texObj, target, level); 567 if (texImage) { 568 if (_mesa_is_format_compressed(texImage->TexFormat)) { 569 /* this typically calls _mesa_get_compressed_teximage() */ 570 ctx->Driver.GetCompressedTexImage(ctx, target, level, img, 571 texObj, texImage); 572 } 573 else { 574 _mesa_error(ctx, GL_INVALID_OPERATION, 575 "glGetCompressedTexImageARB"); 576 } 577 } 578 else { 579 /* probably invalid mipmap level */ 580 _mesa_error(ctx, GL_INVALID_VALUE, 581 "glGetCompressedTexImageARB(level)"); 582 } 583 } 584 _mesa_unlock_texture(ctx, texObj); 585} 586