texgetimage.c revision 01e04c3f
14a49301eSmrg/* 24a49301eSmrg * Mesa 3-D graphics library 34a49301eSmrg * 44a49301eSmrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 54a49301eSmrg * Copyright (c) 2009 VMware, Inc. 64a49301eSmrg * 74a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a 84a49301eSmrg * copy of this software and associated documentation files (the "Software"), 94a49301eSmrg * to deal in the Software without restriction, including without limitation 104a49301eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 114a49301eSmrg * and/or sell copies of the Software, and to permit persons to whom the 124a49301eSmrg * Software is furnished to do so, subject to the following conditions: 134a49301eSmrg * 144a49301eSmrg * The above copyright notice and this permission notice shall be included 154a49301eSmrg * in all copies or substantial portions of the Software. 164a49301eSmrg * 174a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 184a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 194a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 244a49301eSmrg */ 254a49301eSmrg 264a49301eSmrg 274a49301eSmrg/** 284a49301eSmrg * Code for glGetTexImage() and glGetCompressedTexImage(). 294a49301eSmrg */ 304a49301eSmrg 314a49301eSmrg 324a49301eSmrg#include "glheader.h" 334a49301eSmrg#include "bufferobj.h" 344a49301eSmrg#include "enums.h" 354a49301eSmrg#include "context.h" 364a49301eSmrg#include "formats.h" 37af69d88dSmrg#include "format_unpack.h" 38af69d88dSmrg#include "glformats.h" 394a49301eSmrg#include "image.h" 403464ebd5Sriastradh#include "mtypes.h" 413464ebd5Sriastradh#include "pack.h" 423464ebd5Sriastradh#include "pbo.h" 43af69d88dSmrg#include "pixelstore.h" 44af69d88dSmrg#include "texcompress.h" 454a49301eSmrg#include "texgetimage.h" 464a49301eSmrg#include "teximage.h" 4701e04c3fSmrg#include "texobj.h" 48af69d88dSmrg#include "texstore.h" 4901e04c3fSmrg#include "format_utils.h" 5001e04c3fSmrg#include "pixeltransfer.h" 514a49301eSmrg 524a49301eSmrg/** 534a49301eSmrg * Can the given type represent negative values? 544a49301eSmrg */ 55af69d88dSmrgstatic inline GLboolean 56af69d88dSmrgtype_needs_clamping(GLenum type) 574a49301eSmrg{ 584a49301eSmrg switch (type) { 594a49301eSmrg case GL_BYTE: 604a49301eSmrg case GL_SHORT: 614a49301eSmrg case GL_INT: 624a49301eSmrg case GL_FLOAT: 634a49301eSmrg case GL_HALF_FLOAT_ARB: 64af69d88dSmrg case GL_UNSIGNED_INT_10F_11F_11F_REV: 65af69d88dSmrg case GL_UNSIGNED_INT_5_9_9_9_REV: 664a49301eSmrg return GL_FALSE; 67af69d88dSmrg default: 68af69d88dSmrg return GL_TRUE; 694a49301eSmrg } 704a49301eSmrg} 714a49301eSmrg 724a49301eSmrg 734a49301eSmrg/** 744a49301eSmrg * glGetTexImage for depth/Z pixels. 754a49301eSmrg */ 764a49301eSmrgstatic void 773464ebd5Sriastradhget_tex_depth(struct gl_context *ctx, GLuint dimensions, 7801e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 7901e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 804a49301eSmrg GLenum format, GLenum type, GLvoid *pixels, 81af69d88dSmrg struct gl_texture_image *texImage) 824a49301eSmrg{ 83af69d88dSmrg GLint img, row; 84af69d88dSmrg GLfloat *depthRow = malloc(width * sizeof(GLfloat)); 853464ebd5Sriastradh 863464ebd5Sriastradh if (!depthRow) { 873464ebd5Sriastradh _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 883464ebd5Sriastradh return; 893464ebd5Sriastradh } 904a49301eSmrg 91af69d88dSmrg for (img = 0; img < depth; img++) { 92af69d88dSmrg GLubyte *srcMap; 93af69d88dSmrg GLint srcRowStride; 94af69d88dSmrg 95af69d88dSmrg /* map src texture buffer */ 9601e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 9701e04c3fSmrg xoffset, yoffset, width, height, 9801e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &srcRowStride); 99af69d88dSmrg 100af69d88dSmrg if (srcMap) { 101af69d88dSmrg for (row = 0; row < height; row++) { 102af69d88dSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 103af69d88dSmrg width, height, format, type, 104af69d88dSmrg img, row, 0); 105af69d88dSmrg const GLubyte *src = srcMap + row * srcRowStride; 106af69d88dSmrg _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow); 107af69d88dSmrg _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); 1084a49301eSmrg } 109af69d88dSmrg 11001e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 111af69d88dSmrg } 112af69d88dSmrg else { 113af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 114af69d88dSmrg break; 1154a49301eSmrg } 1164a49301eSmrg } 1173464ebd5Sriastradh 1183464ebd5Sriastradh free(depthRow); 1194a49301eSmrg} 1204a49301eSmrg 1214a49301eSmrg 1224a49301eSmrg/** 1234a49301eSmrg * glGetTexImage for depth/stencil pixels. 1244a49301eSmrg */ 1254a49301eSmrgstatic void 1263464ebd5Sriastradhget_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions, 12701e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 12801e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 1294a49301eSmrg GLenum format, GLenum type, GLvoid *pixels, 130af69d88dSmrg struct gl_texture_image *texImage) 1314a49301eSmrg{ 1324a49301eSmrg GLint img, row; 1334a49301eSmrg 134af69d88dSmrg assert(format == GL_DEPTH_STENCIL); 135af69d88dSmrg assert(type == GL_UNSIGNED_INT_24_8 || 136af69d88dSmrg type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV); 137af69d88dSmrg 1384a49301eSmrg for (img = 0; img < depth; img++) { 139af69d88dSmrg GLubyte *srcMap; 140af69d88dSmrg GLint rowstride; 141af69d88dSmrg 142af69d88dSmrg /* map src texture buffer */ 14301e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 14401e04c3fSmrg xoffset, yoffset, width, height, 14501e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &rowstride); 146af69d88dSmrg 147af69d88dSmrg if (srcMap) { 148af69d88dSmrg for (row = 0; row < height; row++) { 149af69d88dSmrg const GLubyte *src = srcMap + row * rowstride; 150af69d88dSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 151af69d88dSmrg width, height, format, type, 152af69d88dSmrg img, row, 0); 153af69d88dSmrg _mesa_unpack_depth_stencil_row(texImage->TexFormat, 154af69d88dSmrg width, 155af69d88dSmrg (const GLuint *) src, 156af69d88dSmrg type, dest); 157af69d88dSmrg if (ctx->Pack.SwapBytes) { 158af69d88dSmrg _mesa_swap4((GLuint *) dest, width); 159af69d88dSmrg } 1604a49301eSmrg } 1614a49301eSmrg 16201e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 16301e04c3fSmrg } 16401e04c3fSmrg else { 16501e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 16601e04c3fSmrg break; 16701e04c3fSmrg } 16801e04c3fSmrg } 16901e04c3fSmrg} 17001e04c3fSmrg 17101e04c3fSmrg/** 17201e04c3fSmrg * glGetTexImage for stencil pixels. 17301e04c3fSmrg */ 17401e04c3fSmrgstatic void 17501e04c3fSmrgget_tex_stencil(struct gl_context *ctx, GLuint dimensions, 17601e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 17701e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 17801e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 17901e04c3fSmrg struct gl_texture_image *texImage) 18001e04c3fSmrg{ 18101e04c3fSmrg GLint img, row; 18201e04c3fSmrg 18301e04c3fSmrg assert(format == GL_STENCIL_INDEX); 18401e04c3fSmrg 18501e04c3fSmrg for (img = 0; img < depth; img++) { 18601e04c3fSmrg GLubyte *srcMap; 18701e04c3fSmrg GLint rowstride; 18801e04c3fSmrg 18901e04c3fSmrg /* map src texture buffer */ 19001e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 19101e04c3fSmrg xoffset, yoffset, width, height, 19201e04c3fSmrg GL_MAP_READ_BIT, 19301e04c3fSmrg &srcMap, &rowstride); 19401e04c3fSmrg 19501e04c3fSmrg if (srcMap) { 19601e04c3fSmrg for (row = 0; row < height; row++) { 19701e04c3fSmrg const GLubyte *src = srcMap + row * rowstride; 19801e04c3fSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 19901e04c3fSmrg width, height, format, type, 20001e04c3fSmrg img, row, 0); 20101e04c3fSmrg _mesa_unpack_ubyte_stencil_row(texImage->TexFormat, 20201e04c3fSmrg width, 20301e04c3fSmrg (const GLuint *) src, 20401e04c3fSmrg dest); 20501e04c3fSmrg } 20601e04c3fSmrg 20701e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 208af69d88dSmrg } 209af69d88dSmrg else { 210af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 211af69d88dSmrg break; 2124a49301eSmrg } 2134a49301eSmrg } 2144a49301eSmrg} 2154a49301eSmrg 2164a49301eSmrg 2174a49301eSmrg/** 2184a49301eSmrg * glGetTexImage for YCbCr pixels. 2194a49301eSmrg */ 2204a49301eSmrgstatic void 2213464ebd5Sriastradhget_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, 22201e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 22301e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 2244a49301eSmrg GLenum format, GLenum type, GLvoid *pixels, 225af69d88dSmrg struct gl_texture_image *texImage) 2264a49301eSmrg{ 2274a49301eSmrg GLint img, row; 2284a49301eSmrg 2294a49301eSmrg for (img = 0; img < depth; img++) { 230af69d88dSmrg GLubyte *srcMap; 231af69d88dSmrg GLint rowstride; 232af69d88dSmrg 233af69d88dSmrg /* map src texture buffer */ 23401e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 23501e04c3fSmrg xoffset, yoffset, width, height, 23601e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &rowstride); 237af69d88dSmrg 238af69d88dSmrg if (srcMap) { 239af69d88dSmrg for (row = 0; row < height; row++) { 240af69d88dSmrg const GLubyte *src = srcMap + row * rowstride; 241af69d88dSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 242af69d88dSmrg width, height, format, type, 243af69d88dSmrg img, row, 0); 244af69d88dSmrg memcpy(dest, src, width * sizeof(GLushort)); 245af69d88dSmrg 246af69d88dSmrg /* check for byte swapping */ 247af69d88dSmrg if ((texImage->TexFormat == MESA_FORMAT_YCBCR 248af69d88dSmrg && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || 249af69d88dSmrg (texImage->TexFormat == MESA_FORMAT_YCBCR_REV 250af69d88dSmrg && type == GL_UNSIGNED_SHORT_8_8_MESA)) { 251af69d88dSmrg if (!ctx->Pack.SwapBytes) 252af69d88dSmrg _mesa_swap2((GLushort *) dest, width); 253af69d88dSmrg } 254af69d88dSmrg else if (ctx->Pack.SwapBytes) { 2554a49301eSmrg _mesa_swap2((GLushort *) dest, width); 256af69d88dSmrg } 2574a49301eSmrg } 2584a49301eSmrg 25901e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 260af69d88dSmrg } 261af69d88dSmrg else { 262af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 263af69d88dSmrg break; 2644a49301eSmrg } 2654a49301eSmrg } 2664a49301eSmrg} 2674a49301eSmrg 26801e04c3fSmrg/** 26901e04c3fSmrg * Depending on the base format involved we may need to apply a rebase 27001e04c3fSmrg * transform (for example: if we download to a Luminance format we want 27101e04c3fSmrg * G=0 and B=0). 27201e04c3fSmrg */ 27301e04c3fSmrgstatic bool 27401e04c3fSmrgteximage_needs_rebase(mesa_format texFormat, GLenum baseFormat, 27501e04c3fSmrg bool is_compressed, uint8_t *rebaseSwizzle) 27601e04c3fSmrg{ 27701e04c3fSmrg bool needsRebase = false; 27801e04c3fSmrg 27901e04c3fSmrg if (baseFormat == GL_LUMINANCE || 28001e04c3fSmrg baseFormat == GL_INTENSITY) { 28101e04c3fSmrg needsRebase = true; 28201e04c3fSmrg rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; 28301e04c3fSmrg rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; 28401e04c3fSmrg rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; 28501e04c3fSmrg rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; 28601e04c3fSmrg } else if (baseFormat == GL_LUMINANCE_ALPHA) { 28701e04c3fSmrg needsRebase = true; 28801e04c3fSmrg rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; 28901e04c3fSmrg rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; 29001e04c3fSmrg rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; 29101e04c3fSmrg rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; 29201e04c3fSmrg } else if (!is_compressed && 29301e04c3fSmrg (baseFormat != _mesa_get_format_base_format(texFormat))) { 29401e04c3fSmrg needsRebase = 29501e04c3fSmrg _mesa_compute_rgba2base2rgba_component_mapping(baseFormat, 29601e04c3fSmrg rebaseSwizzle); 29701e04c3fSmrg } 29801e04c3fSmrg 29901e04c3fSmrg return needsRebase; 30001e04c3fSmrg} 30101e04c3fSmrg 3024a49301eSmrg 3034a49301eSmrg/** 304af69d88dSmrg * Get a color texture image with decompression. 3054a49301eSmrg */ 3064a49301eSmrgstatic void 307af69d88dSmrgget_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, 30801e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 30901e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 310af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 311af69d88dSmrg struct gl_texture_image *texImage, 312af69d88dSmrg GLbitfield transferOps) 3134a49301eSmrg{ 314af69d88dSmrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 315af69d88dSmrg const mesa_format texFormat = 316af69d88dSmrg _mesa_get_srgb_format_linear(texImage->TexFormat); 317af69d88dSmrg const GLenum baseFormat = _mesa_get_format_base_format(texFormat); 31801e04c3fSmrg GLfloat *tempImage, *tempSlice; 31901e04c3fSmrg GLuint slice; 32001e04c3fSmrg int srcStride, dstStride; 32101e04c3fSmrg uint32_t dstFormat; 32201e04c3fSmrg bool needsRebase; 32301e04c3fSmrg uint8_t rebaseSwizzle[4]; 324af69d88dSmrg 325af69d88dSmrg /* Decompress into temp float buffer, then pack into user buffer */ 32601e04c3fSmrg tempImage = malloc(width * height * depth * 4 * sizeof(GLfloat)); 327af69d88dSmrg if (!tempImage) { 328af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 3293464ebd5Sriastradh return; 3303464ebd5Sriastradh } 3313464ebd5Sriastradh 332af69d88dSmrg /* Decompress the texture image slices - results in 'tempImage' */ 333af69d88dSmrg for (slice = 0; slice < depth; slice++) { 334af69d88dSmrg GLubyte *srcMap; 335af69d88dSmrg GLint srcRowStride; 336af69d88dSmrg 337af69d88dSmrg tempSlice = tempImage + slice * 4 * width * height; 338af69d88dSmrg 33901e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice, 34001e04c3fSmrg xoffset, yoffset, width, height, 341af69d88dSmrg GL_MAP_READ_BIT, 342af69d88dSmrg &srcMap, &srcRowStride); 343af69d88dSmrg if (srcMap) { 344af69d88dSmrg _mesa_decompress_image(texFormat, width, height, 345af69d88dSmrg srcMap, srcRowStride, tempSlice); 346af69d88dSmrg 34701e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice); 348af69d88dSmrg } 349af69d88dSmrg else { 350af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 351af69d88dSmrg free(tempImage); 352af69d88dSmrg return; 353af69d88dSmrg } 3543464ebd5Sriastradh } 355af69d88dSmrg 35601e04c3fSmrg needsRebase = teximage_needs_rebase(texFormat, baseFormat, true, 35701e04c3fSmrg rebaseSwizzle); 3584a49301eSmrg 35901e04c3fSmrg srcStride = 4 * width * sizeof(GLfloat); 36001e04c3fSmrg dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type); 36101e04c3fSmrg dstFormat = _mesa_format_from_format_and_type(format, type); 362af69d88dSmrg tempSlice = tempImage; 363af69d88dSmrg for (slice = 0; slice < depth; slice++) { 36401e04c3fSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 36501e04c3fSmrg width, height, format, type, 36601e04c3fSmrg slice, 0, 0); 36701e04c3fSmrg _mesa_format_convert(dest, dstFormat, dstStride, 36801e04c3fSmrg tempSlice, RGBA32_FLOAT, srcStride, 36901e04c3fSmrg width, height, 37001e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 37101e04c3fSmrg 37201e04c3fSmrg /* Handle byte swapping if required */ 37301e04c3fSmrg if (ctx->Pack.SwapBytes) { 37401e04c3fSmrg _mesa_swap_bytes_2d_image(format, type, &ctx->Pack, 37501e04c3fSmrg width, height, dest, dest); 376af69d88dSmrg } 37701e04c3fSmrg 378af69d88dSmrg tempSlice += 4 * width * height; 379af69d88dSmrg } 380af69d88dSmrg 381af69d88dSmrg free(tempImage); 382af69d88dSmrg} 383af69d88dSmrg 384af69d88dSmrg 385af69d88dSmrg/** 386af69d88dSmrg * Return a base GL format given the user-requested format 387af69d88dSmrg * for glGetTexImage(). 388af69d88dSmrg */ 389af69d88dSmrgGLenum 390af69d88dSmrg_mesa_base_pack_format(GLenum format) 391af69d88dSmrg{ 392af69d88dSmrg switch (format) { 393af69d88dSmrg case GL_ABGR_EXT: 394af69d88dSmrg case GL_BGRA: 395af69d88dSmrg case GL_BGRA_INTEGER: 396af69d88dSmrg case GL_RGBA_INTEGER: 397af69d88dSmrg return GL_RGBA; 398af69d88dSmrg case GL_BGR: 399af69d88dSmrg case GL_BGR_INTEGER: 400af69d88dSmrg case GL_RGB_INTEGER: 401af69d88dSmrg return GL_RGB; 402af69d88dSmrg case GL_RED_INTEGER: 403af69d88dSmrg return GL_RED; 404af69d88dSmrg case GL_GREEN_INTEGER: 405af69d88dSmrg return GL_GREEN; 406af69d88dSmrg case GL_BLUE_INTEGER: 407af69d88dSmrg return GL_BLUE; 408af69d88dSmrg case GL_ALPHA_INTEGER: 409af69d88dSmrg return GL_ALPHA; 410af69d88dSmrg case GL_LUMINANCE_INTEGER_EXT: 411af69d88dSmrg return GL_LUMINANCE; 412af69d88dSmrg case GL_LUMINANCE_ALPHA_INTEGER_EXT: 413af69d88dSmrg return GL_LUMINANCE_ALPHA; 414af69d88dSmrg default: 415af69d88dSmrg return format; 416af69d88dSmrg } 417af69d88dSmrg} 418af69d88dSmrg 419af69d88dSmrg 420af69d88dSmrg/** 421af69d88dSmrg * Get an uncompressed color texture image. 422af69d88dSmrg */ 423af69d88dSmrgstatic void 424af69d88dSmrgget_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, 42501e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 42601e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 427af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 428af69d88dSmrg struct gl_texture_image *texImage, 429af69d88dSmrg GLbitfield transferOps) 430af69d88dSmrg{ 431af69d88dSmrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 432af69d88dSmrg const mesa_format texFormat = 433af69d88dSmrg _mesa_get_srgb_format_linear(texImage->TexFormat); 43401e04c3fSmrg GLuint img; 43501e04c3fSmrg GLboolean dst_is_integer; 43601e04c3fSmrg uint32_t dst_format; 43701e04c3fSmrg int dst_stride; 43801e04c3fSmrg uint8_t rebaseSwizzle[4]; 43901e04c3fSmrg bool needsRebase; 44001e04c3fSmrg void *rgba = NULL; 44101e04c3fSmrg 44201e04c3fSmrg needsRebase = teximage_needs_rebase(texFormat, texImage->_BaseFormat, false, 44301e04c3fSmrg rebaseSwizzle); 44401e04c3fSmrg 44501e04c3fSmrg /* Describe the dst format */ 44601e04c3fSmrg dst_is_integer = _mesa_is_enum_format_integer(format); 44701e04c3fSmrg dst_format = _mesa_format_from_format_and_type(format, type); 44801e04c3fSmrg dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type); 44901e04c3fSmrg 45001e04c3fSmrg /* Since _mesa_format_convert does not handle transferOps we need to handle 45101e04c3fSmrg * them before we call the function. This requires to convert to RGBA float 45201e04c3fSmrg * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is 45301e04c3fSmrg * integer then transferOps do not apply. 45401e04c3fSmrg */ 45501e04c3fSmrg assert(!transferOps || (transferOps && !dst_is_integer)); 45601e04c3fSmrg (void) dst_is_integer; /* silence unused var warning */ 4573464ebd5Sriastradh 458af69d88dSmrg for (img = 0; img < depth; img++) { 459af69d88dSmrg GLubyte *srcMap; 460af69d88dSmrg GLint rowstride; 46101e04c3fSmrg GLubyte *img_src; 46201e04c3fSmrg void *dest; 46301e04c3fSmrg void *src; 46401e04c3fSmrg int src_stride; 46501e04c3fSmrg uint32_t src_format; 466af69d88dSmrg 467af69d88dSmrg /* map src texture buffer */ 46801e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 46901e04c3fSmrg xoffset, yoffset, width, height, 47001e04c3fSmrg GL_MAP_READ_BIT, 471af69d88dSmrg &srcMap, &rowstride); 47201e04c3fSmrg if (!srcMap) { 47301e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 47401e04c3fSmrg goto done; 47501e04c3fSmrg } 476af69d88dSmrg 47701e04c3fSmrg img_src = srcMap; 47801e04c3fSmrg dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 47901e04c3fSmrg width, height, format, type, 48001e04c3fSmrg img, 0, 0); 48101e04c3fSmrg 48201e04c3fSmrg if (transferOps) { 48301e04c3fSmrg uint32_t rgba_format; 48401e04c3fSmrg int rgba_stride; 48501e04c3fSmrg bool need_convert = false; 48601e04c3fSmrg 48701e04c3fSmrg /* We will convert to RGBA float */ 48801e04c3fSmrg rgba_format = RGBA32_FLOAT; 48901e04c3fSmrg rgba_stride = width * 4 * sizeof(GLfloat); 49001e04c3fSmrg 49101e04c3fSmrg /* If we are lucky and the dst format matches the RGBA format we need 49201e04c3fSmrg * to convert to, then we can convert directly into the dst buffer 49301e04c3fSmrg * and avoid the final conversion/copy from the rgba buffer to the dst 49401e04c3fSmrg * buffer. 49501e04c3fSmrg */ 49601e04c3fSmrg if (format == rgba_format) { 49701e04c3fSmrg rgba = dest; 49801e04c3fSmrg } else { 49901e04c3fSmrg need_convert = true; 50001e04c3fSmrg if (rgba == NULL) { /* Allocate the RGBA buffer only once */ 50101e04c3fSmrg rgba = malloc(height * rgba_stride); 50201e04c3fSmrg if (!rgba) { 50301e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 50401e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 50501e04c3fSmrg return; 506af69d88dSmrg } 50701e04c3fSmrg } 50801e04c3fSmrg } 50901e04c3fSmrg 51001e04c3fSmrg _mesa_format_convert(rgba, rgba_format, rgba_stride, 51101e04c3fSmrg img_src, texFormat, rowstride, 51201e04c3fSmrg width, height, 51301e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 51401e04c3fSmrg 51501e04c3fSmrg /* Handle transfer ops now */ 51601e04c3fSmrg _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); 51701e04c3fSmrg 51801e04c3fSmrg /* If we had to rebase, we have already handled that */ 51901e04c3fSmrg needsRebase = false; 52001e04c3fSmrg 52101e04c3fSmrg /* If we were lucky and our RGBA conversion matches the dst format, 52201e04c3fSmrg * then we are done. 52301e04c3fSmrg */ 52401e04c3fSmrg if (!need_convert) 52501e04c3fSmrg goto do_swap; 52601e04c3fSmrg 52701e04c3fSmrg /* Otherwise, we need to convert from RGBA to dst next */ 52801e04c3fSmrg src = rgba; 52901e04c3fSmrg src_format = rgba_format; 53001e04c3fSmrg src_stride = rgba_stride; 53101e04c3fSmrg } else { 53201e04c3fSmrg /* No RGBA conversion needed, convert directly to dst */ 53301e04c3fSmrg src = img_src; 53401e04c3fSmrg src_format = texFormat; 53501e04c3fSmrg src_stride = rowstride; 536af69d88dSmrg } 53701e04c3fSmrg 53801e04c3fSmrg /* Do the conversion to destination format */ 53901e04c3fSmrg _mesa_format_convert(dest, dst_format, dst_stride, 54001e04c3fSmrg src, src_format, src_stride, 54101e04c3fSmrg width, height, 54201e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 54301e04c3fSmrg 54401e04c3fSmrg do_swap: 54501e04c3fSmrg /* Handle byte swapping if required */ 54601e04c3fSmrg if (ctx->Pack.SwapBytes) 54701e04c3fSmrg _mesa_swap_bytes_2d_image(format, type, &ctx->Pack, 54801e04c3fSmrg width, height, dest, dest); 54901e04c3fSmrg 55001e04c3fSmrg /* Unmap the src texture buffer */ 55101e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 5523464ebd5Sriastradh } 5533464ebd5Sriastradh 55401e04c3fSmrgdone: 5553464ebd5Sriastradh free(rgba); 5564a49301eSmrg} 5574a49301eSmrg 5584a49301eSmrg 559af69d88dSmrg/** 560af69d88dSmrg * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). 561af69d88dSmrg * Compressed textures are handled here as well. 562af69d88dSmrg */ 563af69d88dSmrgstatic void 564af69d88dSmrgget_tex_rgba(struct gl_context *ctx, GLuint dimensions, 56501e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 56601e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 567af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 568af69d88dSmrg struct gl_texture_image *texImage) 569af69d88dSmrg{ 570af69d88dSmrg const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); 571af69d88dSmrg GLbitfield transferOps = 0x0; 572af69d88dSmrg 573af69d88dSmrg /* In general, clamping does not apply to glGetTexImage, except when 574af69d88dSmrg * the returned type of the image can't hold negative values. 575af69d88dSmrg */ 576af69d88dSmrg if (type_needs_clamping(type)) { 577af69d88dSmrg /* the returned image type can't have negative values */ 578af69d88dSmrg if (dataType == GL_FLOAT || 579af69d88dSmrg dataType == GL_HALF_FLOAT || 580af69d88dSmrg dataType == GL_SIGNED_NORMALIZED || 581af69d88dSmrg format == GL_LUMINANCE || 582af69d88dSmrg format == GL_LUMINANCE_ALPHA) { 583af69d88dSmrg transferOps |= IMAGE_CLAMP_BIT; 584af69d88dSmrg } 585af69d88dSmrg } 586af69d88dSmrg 587af69d88dSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 58801e04c3fSmrg get_tex_rgba_compressed(ctx, dimensions, 58901e04c3fSmrg xoffset, yoffset, zoffset, 59001e04c3fSmrg width, height, depth, 59101e04c3fSmrg format, type, 592af69d88dSmrg pixels, texImage, transferOps); 593af69d88dSmrg } 594af69d88dSmrg else { 59501e04c3fSmrg get_tex_rgba_uncompressed(ctx, dimensions, 59601e04c3fSmrg xoffset, yoffset, zoffset, 59701e04c3fSmrg width, height, depth, 59801e04c3fSmrg format, type, 599af69d88dSmrg pixels, texImage, transferOps); 600af69d88dSmrg } 601af69d88dSmrg} 602af69d88dSmrg 603af69d88dSmrg 6044a49301eSmrg/** 6054a49301eSmrg * Try to do glGetTexImage() with simple memcpy(). 6064a49301eSmrg * \return GL_TRUE if done, GL_FALSE otherwise 6074a49301eSmrg */ 6084a49301eSmrgstatic GLboolean 60901e04c3fSmrgget_tex_memcpy(struct gl_context *ctx, 61001e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 61101e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 61201e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 613af69d88dSmrg struct gl_texture_image *texImage) 6144a49301eSmrg{ 615af69d88dSmrg const GLenum target = texImage->TexObject->Target; 6164a49301eSmrg GLboolean memCopy = GL_FALSE; 617af69d88dSmrg GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); 6184a49301eSmrg 6194a49301eSmrg /* 620af69d88dSmrg * Check if we can use memcpy to copy from the hardware texture 621af69d88dSmrg * format to the user's format/type. 622af69d88dSmrg * Note that GL's pixel transfer ops don't apply to glGetTexImage() 6234a49301eSmrg */ 624af69d88dSmrg if ((target == GL_TEXTURE_1D || 625af69d88dSmrg target == GL_TEXTURE_2D || 626af69d88dSmrg target == GL_TEXTURE_RECTANGLE || 627af69d88dSmrg _mesa_is_cube_face(target)) && 628af69d88dSmrg texBaseFormat == texImage->_BaseFormat) { 629af69d88dSmrg memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, 630af69d88dSmrg format, type, 63101e04c3fSmrg ctx->Pack.SwapBytes, NULL); 63201e04c3fSmrg } 63301e04c3fSmrg 63401e04c3fSmrg if (depth > 1) { 63501e04c3fSmrg /* only a single slice is supported at this time */ 63601e04c3fSmrg memCopy = FALSE; 6374a49301eSmrg } 6384a49301eSmrg 6394a49301eSmrg if (memCopy) { 6404a49301eSmrg const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); 64101e04c3fSmrg const GLint bytesPerRow = width * bpp; 6424a49301eSmrg GLubyte *dst = 64301e04c3fSmrg _mesa_image_address2d(&ctx->Pack, pixels, width, height, 64401e04c3fSmrg format, type, 0, 0); 6454a49301eSmrg const GLint dstRowStride = 64601e04c3fSmrg _mesa_image_row_stride(&ctx->Pack, width, format, type); 647af69d88dSmrg GLubyte *src; 648af69d88dSmrg GLint srcRowStride; 6494a49301eSmrg 650af69d88dSmrg /* map src texture buffer */ 65101e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset, 65201e04c3fSmrg xoffset, yoffset, width, height, 653af69d88dSmrg GL_MAP_READ_BIT, &src, &srcRowStride); 654af69d88dSmrg 655af69d88dSmrg if (src) { 656af69d88dSmrg if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { 65701e04c3fSmrg memcpy(dst, src, bytesPerRow * height); 658af69d88dSmrg } 659af69d88dSmrg else { 660af69d88dSmrg GLuint row; 66101e04c3fSmrg for (row = 0; row < height; row++) { 662af69d88dSmrg memcpy(dst, src, bytesPerRow); 663af69d88dSmrg dst += dstRowStride; 664af69d88dSmrg src += srcRowStride; 665af69d88dSmrg } 666af69d88dSmrg } 667af69d88dSmrg 668af69d88dSmrg /* unmap src texture buffer */ 66901e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset); 6704a49301eSmrg } 6714a49301eSmrg else { 672af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 6734a49301eSmrg } 6744a49301eSmrg } 6754a49301eSmrg 6764a49301eSmrg return memCopy; 6774a49301eSmrg} 6784a49301eSmrg 6794a49301eSmrg 6804a49301eSmrg/** 68101e04c3fSmrg * This is the software fallback for Driver.GetTexSubImage(). 6824a49301eSmrg * All error checking will have been done before this routine is called. 683af69d88dSmrg * We'll call ctx->Driver.MapTextureImage() to access the data, then 684af69d88dSmrg * unmap with ctx->Driver.UnmapTextureImage(). 6854a49301eSmrg */ 6864a49301eSmrgvoid 68701e04c3fSmrg_mesa_GetTexSubImage_sw(struct gl_context *ctx, 68801e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 68901e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 69001e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 69101e04c3fSmrg struct gl_texture_image *texImage) 6924a49301eSmrg{ 693af69d88dSmrg const GLuint dimensions = 694af69d88dSmrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 6954a49301eSmrg 696af69d88dSmrg /* map dest buffer, if PBO */ 6974a49301eSmrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 6984a49301eSmrg /* Packing texture image into a PBO. 6994a49301eSmrg * Map the (potentially) VRAM-based buffer into our process space so 7004a49301eSmrg * we can write into it with the code below. 7014a49301eSmrg * A hardware driver might use a sophisticated blit to move the 7024a49301eSmrg * texture data to the PBO if the PBO is in VRAM along with the texture. 7034a49301eSmrg */ 7044a49301eSmrg GLubyte *buf = (GLubyte *) 705af69d88dSmrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 706af69d88dSmrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 707af69d88dSmrg MAP_INTERNAL); 7084a49301eSmrg if (!buf) { 7094a49301eSmrg /* out of memory or other unexpected error */ 7104a49301eSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 7114a49301eSmrg return; 7124a49301eSmrg } 7134a49301eSmrg /* <pixels> was an offset into the PBO. 7144a49301eSmrg * Now make it a real, client-side pointer inside the mapped region. 7154a49301eSmrg */ 7164a49301eSmrg pixels = ADD_POINTERS(buf, pixels); 7174a49301eSmrg } 7184a49301eSmrg 71901e04c3fSmrg /* for all array textures, the Z axis selects the layer */ 72001e04c3fSmrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 72101e04c3fSmrg depth = height; 72201e04c3fSmrg height = 1; 72301e04c3fSmrg zoffset = yoffset; 72401e04c3fSmrg yoffset = 0; 72501e04c3fSmrg assert(zoffset + depth <= texImage->Height); 72601e04c3fSmrg } else { 72701e04c3fSmrg assert(zoffset + depth <= texImage->Depth); 72801e04c3fSmrg } 72901e04c3fSmrg 73001e04c3fSmrg if (get_tex_memcpy(ctx, xoffset, yoffset, zoffset, width, height, depth, 73101e04c3fSmrg format, type, pixels, texImage)) { 7324a49301eSmrg /* all done */ 7334a49301eSmrg } 7344a49301eSmrg else if (format == GL_DEPTH_COMPONENT) { 73501e04c3fSmrg get_tex_depth(ctx, dimensions, xoffset, yoffset, zoffset, 73601e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7374a49301eSmrg } 7384a49301eSmrg else if (format == GL_DEPTH_STENCIL_EXT) { 73901e04c3fSmrg get_tex_depth_stencil(ctx, dimensions, xoffset, yoffset, zoffset, 74001e04c3fSmrg width, height, depth, format, type, pixels, 74101e04c3fSmrg texImage); 74201e04c3fSmrg } 74301e04c3fSmrg else if (format == GL_STENCIL_INDEX) { 74401e04c3fSmrg get_tex_stencil(ctx, dimensions, xoffset, yoffset, zoffset, 74501e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7464a49301eSmrg } 7474a49301eSmrg else if (format == GL_YCBCR_MESA) { 74801e04c3fSmrg get_tex_ycbcr(ctx, dimensions, xoffset, yoffset, zoffset, 74901e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7504a49301eSmrg } 7514a49301eSmrg else { 75201e04c3fSmrg get_tex_rgba(ctx, dimensions, xoffset, yoffset, zoffset, 75301e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7544a49301eSmrg } 7554a49301eSmrg 7564a49301eSmrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 757af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 7584a49301eSmrg } 7594a49301eSmrg} 7604a49301eSmrg 7614a49301eSmrg 7624a49301eSmrg 7634a49301eSmrg/** 76401e04c3fSmrg * This function assumes that all error checking has been done. 7654a49301eSmrg */ 76601e04c3fSmrgstatic void 76701e04c3fSmrgget_compressed_texsubimage_sw(struct gl_context *ctx, 768af69d88dSmrg struct gl_texture_image *texImage, 76901e04c3fSmrg GLint xoffset, GLint yoffset, 77001e04c3fSmrg GLint zoffset, GLsizei width, 77101e04c3fSmrg GLint height, GLint depth, 772af69d88dSmrg GLvoid *img) 7734a49301eSmrg{ 774af69d88dSmrg const GLuint dimensions = 775af69d88dSmrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 776af69d88dSmrg struct compressed_pixelstore store; 77701e04c3fSmrg GLint slice; 778af69d88dSmrg GLubyte *dest; 779af69d88dSmrg 780af69d88dSmrg _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat, 78101e04c3fSmrg width, height, depth, 78201e04c3fSmrg &ctx->Pack, &store); 7834a49301eSmrg 7844a49301eSmrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 7854a49301eSmrg /* pack texture image into a PBO */ 786af69d88dSmrg dest = (GLubyte *) 787af69d88dSmrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 788af69d88dSmrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 789af69d88dSmrg MAP_INTERNAL); 790af69d88dSmrg if (!dest) { 7914a49301eSmrg /* out of memory or other unexpected error */ 7924a49301eSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 7934a49301eSmrg "glGetCompresssedTexImage(map PBO failed)"); 7944a49301eSmrg return; 7954a49301eSmrg } 796af69d88dSmrg dest = ADD_POINTERS(dest, img); 797af69d88dSmrg } else { 798af69d88dSmrg dest = img; 7994a49301eSmrg } 8004a49301eSmrg 801af69d88dSmrg dest += store.SkipBytes; 8024a49301eSmrg 803af69d88dSmrg for (slice = 0; slice < store.CopySlices; slice++) { 804af69d88dSmrg GLint srcRowStride; 805af69d88dSmrg GLubyte *src; 806af69d88dSmrg 807af69d88dSmrg /* map src texture buffer */ 80801e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice, 80901e04c3fSmrg xoffset, yoffset, width, height, 810af69d88dSmrg GL_MAP_READ_BIT, &src, &srcRowStride); 811af69d88dSmrg 812af69d88dSmrg if (src) { 81301e04c3fSmrg GLint i; 814af69d88dSmrg for (i = 0; i < store.CopyRowsPerSlice; i++) { 815af69d88dSmrg memcpy(dest, src, store.CopyBytesPerRow); 816af69d88dSmrg dest += store.TotalBytesPerRow; 817af69d88dSmrg src += srcRowStride; 818af69d88dSmrg } 819af69d88dSmrg 82001e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice); 821af69d88dSmrg 822af69d88dSmrg /* Advance to next slice */ 82301e04c3fSmrg dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - 82401e04c3fSmrg store.CopyRowsPerSlice); 825af69d88dSmrg 826af69d88dSmrg } else { 827af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); 8284a49301eSmrg } 8294a49301eSmrg } 8304a49301eSmrg 8314a49301eSmrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 832af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 8334a49301eSmrg } 8344a49301eSmrg} 8354a49301eSmrg 8364a49301eSmrg 837af69d88dSmrg/** 83801e04c3fSmrg * Validate the texture target enum supplied to glGetTex(ture)Image or 83901e04c3fSmrg * glGetCompressedTex(ture)Image. 840af69d88dSmrg */ 841af69d88dSmrgstatic GLboolean 84201e04c3fSmrglegal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa) 843af69d88dSmrg{ 844af69d88dSmrg switch (target) { 845af69d88dSmrg case GL_TEXTURE_1D: 846af69d88dSmrg case GL_TEXTURE_2D: 847af69d88dSmrg case GL_TEXTURE_3D: 848af69d88dSmrg return GL_TRUE; 849af69d88dSmrg case GL_TEXTURE_RECTANGLE_NV: 850af69d88dSmrg return ctx->Extensions.NV_texture_rectangle; 851af69d88dSmrg case GL_TEXTURE_1D_ARRAY_EXT: 852af69d88dSmrg case GL_TEXTURE_2D_ARRAY_EXT: 853af69d88dSmrg return ctx->Extensions.EXT_texture_array; 854af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 855af69d88dSmrg return ctx->Extensions.ARB_texture_cube_map_array; 85601e04c3fSmrg 85701e04c3fSmrg /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec 85801e04c3fSmrg * (30.10.2014) says: 85901e04c3fSmrg * "An INVALID_ENUM error is generated if the effective target is not 86001e04c3fSmrg * one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY, 86101e04c3fSmrg * TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of 86201e04c3fSmrg * the targets from table 8.19 (for GetTexImage and GetnTexImage *only*), 86301e04c3fSmrg * or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.) 86401e04c3fSmrg */ 86501e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 86601e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 86701e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 86801e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 86901e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 87001e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 87101e04c3fSmrg return dsa ? GL_FALSE : ctx->Extensions.ARB_texture_cube_map; 87201e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 87301e04c3fSmrg return dsa ? GL_TRUE : GL_FALSE; 874af69d88dSmrg default: 875af69d88dSmrg return GL_FALSE; 876af69d88dSmrg } 877af69d88dSmrg} 878af69d88dSmrg 8794a49301eSmrg 8804a49301eSmrg/** 88101e04c3fSmrg * Wrapper for _mesa_select_tex_image() which can handle target being 88201e04c3fSmrg * GL_TEXTURE_CUBE_MAP in which case we use zoffset to select a cube face. 88301e04c3fSmrg * This can happen for glGetTextureImage and glGetTextureSubImage (DSA 88401e04c3fSmrg * functions). 8854a49301eSmrg */ 88601e04c3fSmrgstatic struct gl_texture_image * 88701e04c3fSmrgselect_tex_image(const struct gl_texture_object *texObj, GLenum target, 88801e04c3fSmrg GLint level, GLint zoffset) 8894a49301eSmrg{ 89001e04c3fSmrg assert(level >= 0); 89101e04c3fSmrg assert(level < MAX_TEXTURE_LEVELS); 89201e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 89301e04c3fSmrg assert(zoffset >= 0); 89401e04c3fSmrg assert(zoffset < 6); 89501e04c3fSmrg target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset; 89601e04c3fSmrg } 89701e04c3fSmrg return _mesa_select_tex_image(texObj, target, level); 89801e04c3fSmrg} 8994a49301eSmrg 90001e04c3fSmrg 90101e04c3fSmrg/** 90201e04c3fSmrg * Error-check the offset and size arguments to 90301e04c3fSmrg * glGet[Compressed]TextureSubImage(). 90401e04c3fSmrg * \return true if error, false if no error. 90501e04c3fSmrg */ 90601e04c3fSmrgstatic bool 90701e04c3fSmrgdimensions_error_check(struct gl_context *ctx, 90801e04c3fSmrg struct gl_texture_object *texObj, 90901e04c3fSmrg GLenum target, GLint level, 91001e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 91101e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 91201e04c3fSmrg const char *caller) 91301e04c3fSmrg{ 91401e04c3fSmrg const struct gl_texture_image *texImage; 91501e04c3fSmrg GLuint imageWidth = 0, imageHeight = 0, imageDepth = 0; 91601e04c3fSmrg 91701e04c3fSmrg if (xoffset < 0) { 91801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset = %d)", caller, xoffset); 91901e04c3fSmrg return true; 9204a49301eSmrg } 9214a49301eSmrg 92201e04c3fSmrg if (yoffset < 0) { 92301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset = %d)", caller, yoffset); 92401e04c3fSmrg return true; 9254a49301eSmrg } 9264a49301eSmrg 92701e04c3fSmrg if (zoffset < 0) { 92801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset = %d)", caller, zoffset); 92901e04c3fSmrg return true; 9304a49301eSmrg } 9314a49301eSmrg 93201e04c3fSmrg if (width < 0) { 93301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(width = %d)", caller, width); 93401e04c3fSmrg return true; 93501e04c3fSmrg } 9364a49301eSmrg 93701e04c3fSmrg if (height < 0) { 93801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(height = %d)", caller, height); 93901e04c3fSmrg return true; 9404a49301eSmrg } 9414a49301eSmrg 94201e04c3fSmrg if (depth < 0) { 94301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(depth = %d)", caller, depth); 94401e04c3fSmrg return true; 9454a49301eSmrg } 9464a49301eSmrg 94701e04c3fSmrg /* do special per-target checks */ 94801e04c3fSmrg switch (target) { 94901e04c3fSmrg case GL_TEXTURE_1D: 95001e04c3fSmrg if (yoffset != 0) { 95101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 95201e04c3fSmrg "%s(1D, yoffset = %d)", caller, yoffset); 95301e04c3fSmrg return true; 95401e04c3fSmrg } 95501e04c3fSmrg if (height != 1) { 95601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 95701e04c3fSmrg "%s(1D, height = %d)", caller, height); 95801e04c3fSmrg return true; 95901e04c3fSmrg } 96001e04c3fSmrg /* fall-through */ 96101e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 96201e04c3fSmrg case GL_TEXTURE_2D: 96301e04c3fSmrg case GL_TEXTURE_RECTANGLE: 96401e04c3fSmrg if (zoffset != 0) { 96501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 96601e04c3fSmrg "%s(zoffset = %d)", caller, zoffset); 96701e04c3fSmrg return true; 96801e04c3fSmrg } 96901e04c3fSmrg if (depth != 1) { 97001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 97101e04c3fSmrg "%s(depth = %d)", caller, depth); 97201e04c3fSmrg return true; 97301e04c3fSmrg } 97401e04c3fSmrg break; 97501e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 97601e04c3fSmrg /* Non-array cube maps are special because we have a gl_texture_image 97701e04c3fSmrg * per face. 97801e04c3fSmrg */ 97901e04c3fSmrg if (zoffset + depth > 6) { 98001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 98101e04c3fSmrg "%s(zoffset + depth = %d)", caller, zoffset + depth); 98201e04c3fSmrg return true; 98301e04c3fSmrg } 98401e04c3fSmrg break; 98501e04c3fSmrg default: 98601e04c3fSmrg ; /* nothing */ 9874a49301eSmrg } 98801e04c3fSmrg 98901e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 99001e04c3fSmrg if (texImage) { 99101e04c3fSmrg imageWidth = texImage->Width; 99201e04c3fSmrg imageHeight = texImage->Height; 99301e04c3fSmrg imageDepth = texImage->Depth; 9944a49301eSmrg } 99501e04c3fSmrg 99601e04c3fSmrg if (xoffset + width > imageWidth) { 99701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 99801e04c3fSmrg "%s(xoffset %d + width %d > %u)", 99901e04c3fSmrg caller, xoffset, width, imageWidth); 100001e04c3fSmrg return true; 1001af69d88dSmrg } 100201e04c3fSmrg 100301e04c3fSmrg if (yoffset + height > imageHeight) { 100401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 100501e04c3fSmrg "%s(yoffset %d + height %d > %u)", 100601e04c3fSmrg caller, yoffset, height, imageHeight); 100701e04c3fSmrg return true; 10084a49301eSmrg } 100901e04c3fSmrg 101001e04c3fSmrg if (target != GL_TEXTURE_CUBE_MAP) { 101101e04c3fSmrg /* Cube map error checking was done above */ 101201e04c3fSmrg if (zoffset + depth > imageDepth) { 101301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 101401e04c3fSmrg "%s(zoffset %d + depth %d > %u)", 101501e04c3fSmrg caller, zoffset, depth, imageDepth); 101601e04c3fSmrg return true; 101701e04c3fSmrg } 10184a49301eSmrg } 101901e04c3fSmrg 102001e04c3fSmrg /* Extra checks for compressed textures */ 102101e04c3fSmrg if (texImage) { 102201e04c3fSmrg GLuint bw, bh, bd; 102301e04c3fSmrg _mesa_get_format_block_size_3d(texImage->TexFormat, &bw, &bh, &bd); 102401e04c3fSmrg if (bw > 1 || bh > 1 || bd > 1) { 102501e04c3fSmrg /* offset must be multiple of block size */ 102601e04c3fSmrg if (xoffset % bw != 0) { 102701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 102801e04c3fSmrg "%s(xoffset = %d)", caller, xoffset); 102901e04c3fSmrg return true; 103001e04c3fSmrg } 103101e04c3fSmrg if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) { 103201e04c3fSmrg if (yoffset % bh != 0) { 103301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 103401e04c3fSmrg "%s(yoffset = %d)", caller, yoffset); 103501e04c3fSmrg return true; 103601e04c3fSmrg } 103701e04c3fSmrg } 103801e04c3fSmrg 103901e04c3fSmrg if (zoffset % bd != 0) { 104001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 104101e04c3fSmrg "%s(zoffset = %d)", caller, zoffset); 104201e04c3fSmrg return true; 104301e04c3fSmrg } 104401e04c3fSmrg 104501e04c3fSmrg /* The size must be a multiple of bw x bh x bd, or we must be using a 104601e04c3fSmrg * offset+size that exactly hits the edge of the image. 104701e04c3fSmrg */ 104801e04c3fSmrg if ((width % bw != 0) && 104901e04c3fSmrg (xoffset + width != (GLint) texImage->Width)) { 105001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 105101e04c3fSmrg "%s(width = %d)", caller, width); 105201e04c3fSmrg return true; 105301e04c3fSmrg } 105401e04c3fSmrg 105501e04c3fSmrg if ((height % bh != 0) && 105601e04c3fSmrg (yoffset + height != (GLint) texImage->Height)) { 105701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 105801e04c3fSmrg "%s(height = %d)", caller, height); 105901e04c3fSmrg return true; 106001e04c3fSmrg } 106101e04c3fSmrg 106201e04c3fSmrg if ((depth % bd != 0) && 106301e04c3fSmrg (zoffset + depth != (GLint) texImage->Depth)) { 106401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 106501e04c3fSmrg "%s(depth = %d)", caller, depth); 106601e04c3fSmrg return true; 106701e04c3fSmrg } 106801e04c3fSmrg } 106901e04c3fSmrg } 107001e04c3fSmrg 107101e04c3fSmrg if (width == 0 || height == 0 || depth == 0) { 107201e04c3fSmrg /* Not an error, but nothing to do. Return 'true' so that the 107301e04c3fSmrg * caller simply returns. 107401e04c3fSmrg */ 107501e04c3fSmrg return true; 10764a49301eSmrg } 10774a49301eSmrg 107801e04c3fSmrg return false; 107901e04c3fSmrg} 108001e04c3fSmrg 108101e04c3fSmrg 108201e04c3fSmrg/** 108301e04c3fSmrg * Do PBO-related error checking for getting uncompressed images. 108401e04c3fSmrg * \return true if there was an error (or the GetTexImage is to be a no-op) 108501e04c3fSmrg */ 108601e04c3fSmrgstatic bool 108701e04c3fSmrgpbo_error_check(struct gl_context *ctx, GLenum target, 108801e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 108901e04c3fSmrg GLenum format, GLenum type, GLsizei clientMemSize, 109001e04c3fSmrg GLvoid *pixels, 109101e04c3fSmrg const char *caller) 109201e04c3fSmrg{ 109301e04c3fSmrg const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 109401e04c3fSmrg 109501e04c3fSmrg if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, width, height, depth, 10963464ebd5Sriastradh format, type, clientMemSize, pixels)) { 10973464ebd5Sriastradh if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 10984a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 109901e04c3fSmrg "%s(out of bounds PBO access)", caller); 11003464ebd5Sriastradh } else { 11013464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 110201e04c3fSmrg "%s(out of bounds access: bufSize (%d) is too small)", 110301e04c3fSmrg caller, clientMemSize); 11044a49301eSmrg } 110501e04c3fSmrg return true; 11063464ebd5Sriastradh } 11074a49301eSmrg 11083464ebd5Sriastradh if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 11094a49301eSmrg /* PBO should not be mapped */ 1110af69d88dSmrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 11114a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 111201e04c3fSmrg "%s(PBO is mapped)", caller); 111301e04c3fSmrg return true; 11144a49301eSmrg } 11154a49301eSmrg } 11164a49301eSmrg 111701e04c3fSmrg if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 111801e04c3fSmrg /* not an error, do nothing */ 111901e04c3fSmrg return true; 112001e04c3fSmrg } 11214a49301eSmrg 112201e04c3fSmrg return false; 112301e04c3fSmrg} 11244a49301eSmrg 11254a49301eSmrg 11264a49301eSmrg/** 112701e04c3fSmrg * Do teximage-related error checking for getting uncompressed images. 112801e04c3fSmrg * \return true if there was an error 11294a49301eSmrg */ 113001e04c3fSmrgstatic bool 113101e04c3fSmrgteximage_error_check(struct gl_context *ctx, 113201e04c3fSmrg struct gl_texture_image *texImage, 113301e04c3fSmrg GLenum format, const char *caller) 11344a49301eSmrg{ 113501e04c3fSmrg GLenum baseFormat; 113601e04c3fSmrg assert(texImage); 1137af69d88dSmrg 113801e04c3fSmrg /* 113901e04c3fSmrg * Format and type checking has been moved up to GetnTexImage and 114001e04c3fSmrg * GetTextureImage so that it happens before getting the texImage object. 114101e04c3fSmrg */ 11424a49301eSmrg 114301e04c3fSmrg baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 11444a49301eSmrg 114501e04c3fSmrg /* Make sure the requested image format is compatible with the 114601e04c3fSmrg * texture's format. 114701e04c3fSmrg */ 114801e04c3fSmrg if (_mesa_is_color_format(format) 114901e04c3fSmrg && !_mesa_is_color_format(baseFormat)) { 115001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 115101e04c3fSmrg "%s(format mismatch)", caller); 115201e04c3fSmrg return true; 11534a49301eSmrg } 115401e04c3fSmrg else if (_mesa_is_depth_format(format) 115501e04c3fSmrg && !_mesa_is_depth_format(baseFormat) 115601e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat)) { 115701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 115801e04c3fSmrg "%s(format mismatch)", caller); 115901e04c3fSmrg return true; 11604a49301eSmrg } 116101e04c3fSmrg else if (_mesa_is_stencil_format(format) 116201e04c3fSmrg && !ctx->Extensions.ARB_texture_stencil8) { 116301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 116401e04c3fSmrg "%s(format=GL_STENCIL_INDEX)", caller); 116501e04c3fSmrg return true; 11664a49301eSmrg } 116701e04c3fSmrg else if (_mesa_is_stencil_format(format) 116801e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat) 116901e04c3fSmrg && !_mesa_is_stencil_format(baseFormat)) { 117001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 117101e04c3fSmrg "%s(format mismatch)", caller); 117201e04c3fSmrg return true; 117301e04c3fSmrg } 117401e04c3fSmrg else if (_mesa_is_ycbcr_format(format) 117501e04c3fSmrg && !_mesa_is_ycbcr_format(baseFormat)) { 117601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 117701e04c3fSmrg "%s(format mismatch)", caller); 117801e04c3fSmrg return true; 117901e04c3fSmrg } 118001e04c3fSmrg else if (_mesa_is_depthstencil_format(format) 118101e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat)) { 118201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 118301e04c3fSmrg "%s(format mismatch)", caller); 118401e04c3fSmrg return true; 118501e04c3fSmrg } 118601e04c3fSmrg else if (!_mesa_is_stencil_format(format) && 118701e04c3fSmrg _mesa_is_enum_format_integer(format) != 118801e04c3fSmrg _mesa_is_format_integer(texImage->TexFormat)) { 118901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 119001e04c3fSmrg "%s(format mismatch)", caller); 119101e04c3fSmrg return true; 119201e04c3fSmrg } 119301e04c3fSmrg 119401e04c3fSmrg return false; 11954a49301eSmrg} 11964a49301eSmrg 11974a49301eSmrg 119801e04c3fSmrg/** 119901e04c3fSmrg * Do common teximage-related error checking for getting uncompressed images. 120001e04c3fSmrg * \return true if there was an error 120101e04c3fSmrg */ 120201e04c3fSmrgstatic bool 120301e04c3fSmrgcommon_error_check(struct gl_context *ctx, 120401e04c3fSmrg struct gl_texture_object *texObj, 120501e04c3fSmrg GLenum target, GLint level, 120601e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 120701e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 120801e04c3fSmrg GLvoid *pixels, const char *caller) 12093464ebd5Sriastradh{ 121001e04c3fSmrg GLenum err; 121101e04c3fSmrg GLint maxLevels; 121201e04c3fSmrg 121301e04c3fSmrg if (texObj->Target == 0) { 121401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); 121501e04c3fSmrg return true; 121601e04c3fSmrg } 121701e04c3fSmrg 121801e04c3fSmrg maxLevels = _mesa_max_texture_levels(ctx, target); 121901e04c3fSmrg if (level < 0 || level >= maxLevels) { 122001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level = %d)", caller, level); 122101e04c3fSmrg return true; 122201e04c3fSmrg } 122301e04c3fSmrg 122401e04c3fSmrg err = _mesa_error_check_format_and_type(ctx, format, type); 122501e04c3fSmrg if (err != GL_NO_ERROR) { 122601e04c3fSmrg _mesa_error(ctx, err, "%s(format/type)", caller); 122701e04c3fSmrg return true; 122801e04c3fSmrg } 122901e04c3fSmrg 123001e04c3fSmrg /* According to OpenGL 4.6 spec, section 8.11.4 ("Texture Image Queries"): 123101e04c3fSmrg * 123201e04c3fSmrg * "An INVALID_OPERATION error is generated by GetTextureImage if the 123301e04c3fSmrg * effective target is TEXTURE_CUBE_MAP or TEXTURE_CUBE_MAP_ARRAY , 123401e04c3fSmrg * and the texture object is not cube complete or cube array complete, 123501e04c3fSmrg * respectively." 123601e04c3fSmrg * 123701e04c3fSmrg * This applies also to GetTextureSubImage, GetCompressedTexImage, 123801e04c3fSmrg * GetCompressedTextureImage, and GetnCompressedTexImage. 123901e04c3fSmrg */ 124001e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP && !_mesa_cube_complete(texObj)) { 124101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 124201e04c3fSmrg "%s(cube incomplete)", caller); 124301e04c3fSmrg return true; 124401e04c3fSmrg } 124501e04c3fSmrg 124601e04c3fSmrg return false; 12473464ebd5Sriastradh} 12483464ebd5Sriastradh 12494a49301eSmrg 12504a49301eSmrg/** 125101e04c3fSmrg * Do error checking for all (non-compressed) get-texture-image functions. 125201e04c3fSmrg * \return true if any error, false if no errors. 12534a49301eSmrg */ 125401e04c3fSmrgstatic bool 125501e04c3fSmrggetteximage_error_check(struct gl_context *ctx, 125601e04c3fSmrg struct gl_texture_object *texObj, 125701e04c3fSmrg GLenum target, GLint level, 125801e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 125901e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 126001e04c3fSmrg GLvoid *pixels, const char *caller) 12614a49301eSmrg{ 12624a49301eSmrg struct gl_texture_image *texImage; 12634a49301eSmrg 126401e04c3fSmrg assert(texObj); 126501e04c3fSmrg 126601e04c3fSmrg if (common_error_check(ctx, texObj, target, level, width, height, depth, 126701e04c3fSmrg format, type, bufSize, pixels, caller)) { 126801e04c3fSmrg return true; 12694a49301eSmrg } 12704a49301eSmrg 127101e04c3fSmrg if (width == 0 || height == 0 || depth == 0) { 127201e04c3fSmrg /* Not an error, but nothing to do. Return 'true' so that the 127301e04c3fSmrg * caller simply returns. 127401e04c3fSmrg */ 127501e04c3fSmrg return true; 127601e04c3fSmrg } 127701e04c3fSmrg 127801e04c3fSmrg if (pbo_error_check(ctx, target, width, height, depth, 127901e04c3fSmrg format, type, bufSize, pixels, caller)) { 128001e04c3fSmrg return true; 128101e04c3fSmrg } 128201e04c3fSmrg 128301e04c3fSmrg texImage = select_tex_image(texObj, target, level, 0); 128401e04c3fSmrg if (teximage_error_check(ctx, texImage, format, caller)) { 128501e04c3fSmrg return true; 128601e04c3fSmrg } 128701e04c3fSmrg 128801e04c3fSmrg return false; 128901e04c3fSmrg} 129001e04c3fSmrg 129101e04c3fSmrg 129201e04c3fSmrg/** 129301e04c3fSmrg * Do error checking for all (non-compressed) get-texture-image functions. 129401e04c3fSmrg * \return true if any error, false if no errors. 129501e04c3fSmrg */ 129601e04c3fSmrgstatic bool 129701e04c3fSmrggettexsubimage_error_check(struct gl_context *ctx, 129801e04c3fSmrg struct gl_texture_object *texObj, 129901e04c3fSmrg GLenum target, GLint level, 130001e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 130101e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 130201e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 130301e04c3fSmrg GLvoid *pixels, const char *caller) 130401e04c3fSmrg{ 130501e04c3fSmrg struct gl_texture_image *texImage; 130601e04c3fSmrg 130701e04c3fSmrg assert(texObj); 130801e04c3fSmrg 130901e04c3fSmrg if (common_error_check(ctx, texObj, target, level, width, height, depth, 131001e04c3fSmrg format, type, bufSize, pixels, caller)) { 131101e04c3fSmrg return true; 131201e04c3fSmrg } 131301e04c3fSmrg 131401e04c3fSmrg if (dimensions_error_check(ctx, texObj, target, level, 131501e04c3fSmrg xoffset, yoffset, zoffset, 131601e04c3fSmrg width, height, depth, caller)) { 131701e04c3fSmrg return true; 131801e04c3fSmrg } 131901e04c3fSmrg 132001e04c3fSmrg if (pbo_error_check(ctx, target, width, height, depth, 132101e04c3fSmrg format, type, bufSize, pixels, caller)) { 132201e04c3fSmrg return true; 132301e04c3fSmrg } 132401e04c3fSmrg 132501e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 132601e04c3fSmrg if (teximage_error_check(ctx, texImage, format, caller)) { 132701e04c3fSmrg return true; 132801e04c3fSmrg } 132901e04c3fSmrg 133001e04c3fSmrg return false; 133101e04c3fSmrg} 133201e04c3fSmrg 133301e04c3fSmrg 133401e04c3fSmrg/** 133501e04c3fSmrg * Return the width, height and depth of a texture image. 133601e04c3fSmrg * This function must be resilient to bad parameter values since 133701e04c3fSmrg * this is called before full error checking. 133801e04c3fSmrg */ 133901e04c3fSmrgstatic void 134001e04c3fSmrgget_texture_image_dims(const struct gl_texture_object *texObj, 134101e04c3fSmrg GLenum target, GLint level, 134201e04c3fSmrg GLsizei *width, GLsizei *height, GLsizei *depth) 134301e04c3fSmrg{ 134401e04c3fSmrg const struct gl_texture_image *texImage = NULL; 134501e04c3fSmrg 134601e04c3fSmrg if (level >= 0 && level < MAX_TEXTURE_LEVELS) { 134701e04c3fSmrg texImage = _mesa_select_tex_image(texObj, target, level); 134801e04c3fSmrg } 134901e04c3fSmrg 135001e04c3fSmrg if (texImage) { 135101e04c3fSmrg *width = texImage->Width; 135201e04c3fSmrg *height = texImage->Height; 135301e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 135401e04c3fSmrg *depth = 6; 135501e04c3fSmrg } 135601e04c3fSmrg else { 135701e04c3fSmrg *depth = texImage->Depth; 135801e04c3fSmrg } 135901e04c3fSmrg } 136001e04c3fSmrg else { 136101e04c3fSmrg *width = *height = *depth = 0; 136201e04c3fSmrg } 136301e04c3fSmrg} 136401e04c3fSmrg 136501e04c3fSmrg 136601e04c3fSmrg/** 136701e04c3fSmrg * Common code for all (uncompressed) get-texture-image functions. 136801e04c3fSmrg * \param texObj the texture object (should not be null) 136901e04c3fSmrg * \param target user-provided target, or 0 for DSA 137001e04c3fSmrg * \param level image level. 137101e04c3fSmrg * \param format pixel data format for returned image. 137201e04c3fSmrg * \param type pixel data type for returned image. 137301e04c3fSmrg * \param bufSize size of the pixels data buffer. 137401e04c3fSmrg * \param pixels returned pixel data. 137501e04c3fSmrg * \param caller name of calling function 137601e04c3fSmrg */ 137701e04c3fSmrgstatic void 137801e04c3fSmrgget_texture_image(struct gl_context *ctx, 137901e04c3fSmrg struct gl_texture_object *texObj, 138001e04c3fSmrg GLenum target, GLint level, 138101e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 138201e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 138301e04c3fSmrg GLenum format, GLenum type, 138401e04c3fSmrg GLvoid *pixels, const char *caller) 138501e04c3fSmrg{ 138601e04c3fSmrg struct gl_texture_image *texImage; 138701e04c3fSmrg unsigned firstFace, numFaces, i; 138801e04c3fSmrg GLint imageStride; 138901e04c3fSmrg 139001e04c3fSmrg FLUSH_VERTICES(ctx, 0); 139101e04c3fSmrg 139201e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 139301e04c3fSmrg assert(texImage); /* should have been error checked already */ 139401e04c3fSmrg 139501e04c3fSmrg if (_mesa_is_zero_size_texture(texImage)) { 139601e04c3fSmrg /* no image data to return */ 139701e04c3fSmrg return; 139801e04c3fSmrg } 139901e04c3fSmrg 140001e04c3fSmrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 140101e04c3fSmrg _mesa_debug(ctx, "%s(tex %u) format = %s, w=%d, h=%d," 140201e04c3fSmrg " dstFmt=0x%x, dstType=0x%x\n", 140301e04c3fSmrg caller, texObj->Name, 140401e04c3fSmrg _mesa_get_format_name(texImage->TexFormat), 140501e04c3fSmrg texImage->Width, texImage->Height, 140601e04c3fSmrg format, type); 140701e04c3fSmrg } 140801e04c3fSmrg 140901e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 141001e04c3fSmrg /* Compute stride between cube faces */ 141101e04c3fSmrg imageStride = _mesa_image_image_stride(&ctx->Pack, width, height, 141201e04c3fSmrg format, type); 141301e04c3fSmrg firstFace = zoffset; 141401e04c3fSmrg numFaces = depth; 141501e04c3fSmrg zoffset = 0; 141601e04c3fSmrg depth = 1; 141701e04c3fSmrg } 141801e04c3fSmrg else { 141901e04c3fSmrg imageStride = 0; 142001e04c3fSmrg firstFace = _mesa_tex_target_to_face(target); 142101e04c3fSmrg numFaces = 1; 142201e04c3fSmrg } 142301e04c3fSmrg 142401e04c3fSmrg _mesa_lock_texture(ctx, texObj); 142501e04c3fSmrg 142601e04c3fSmrg for (i = 0; i < numFaces; i++) { 142701e04c3fSmrg texImage = texObj->Image[firstFace + i][level]; 142801e04c3fSmrg assert(texImage); 142901e04c3fSmrg 143001e04c3fSmrg ctx->Driver.GetTexSubImage(ctx, xoffset, yoffset, zoffset, 143101e04c3fSmrg width, height, depth, 143201e04c3fSmrg format, type, pixels, texImage); 143301e04c3fSmrg 143401e04c3fSmrg /* next cube face */ 143501e04c3fSmrg pixels = (GLubyte *) pixels + imageStride; 143601e04c3fSmrg } 143701e04c3fSmrg 143801e04c3fSmrg _mesa_unlock_texture(ctx, texObj); 143901e04c3fSmrg} 144001e04c3fSmrg 144101e04c3fSmrg 144201e04c3fSmrgvoid GLAPIENTRY 144301e04c3fSmrg_mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format, GLenum type, 144401e04c3fSmrg GLsizei bufSize, GLvoid *pixels) 144501e04c3fSmrg{ 144601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 144701e04c3fSmrg static const char *caller = "glGetnTexImageARB"; 144801e04c3fSmrg GLsizei width, height, depth; 144901e04c3fSmrg struct gl_texture_object *texObj; 145001e04c3fSmrg 145101e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 145201e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 145301e04c3fSmrg return; 145401e04c3fSmrg } 145501e04c3fSmrg 145601e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 145701e04c3fSmrg assert(texObj); 145801e04c3fSmrg 145901e04c3fSmrg get_texture_image_dims(texObj, target, level, &width, &height, &depth); 146001e04c3fSmrg 146101e04c3fSmrg if (getteximage_error_check(ctx, texObj, target, level, 146201e04c3fSmrg width, height, depth, 146301e04c3fSmrg format, type, bufSize, pixels, caller)) { 146401e04c3fSmrg return; 146501e04c3fSmrg } 146601e04c3fSmrg 146701e04c3fSmrg get_texture_image(ctx, texObj, target, level, 146801e04c3fSmrg 0, 0, 0, width, height, depth, 146901e04c3fSmrg format, type, pixels, caller); 147001e04c3fSmrg} 147101e04c3fSmrg 147201e04c3fSmrg 147301e04c3fSmrgvoid GLAPIENTRY 147401e04c3fSmrg_mesa_GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, 147501e04c3fSmrg GLvoid *pixels ) 147601e04c3fSmrg{ 147701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 147801e04c3fSmrg static const char *caller = "glGetTexImage"; 147901e04c3fSmrg GLsizei width, height, depth; 148001e04c3fSmrg struct gl_texture_object *texObj; 148101e04c3fSmrg 148201e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 148301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 148401e04c3fSmrg return; 14854a49301eSmrg } 14864a49301eSmrg 14874a49301eSmrg texObj = _mesa_get_current_tex_object(ctx, target); 148801e04c3fSmrg assert(texObj); 148901e04c3fSmrg 149001e04c3fSmrg get_texture_image_dims(texObj, target, level, &width, &height, &depth); 149101e04c3fSmrg 149201e04c3fSmrg if (getteximage_error_check(ctx, texObj, target, level, 149301e04c3fSmrg width, height, depth, 149401e04c3fSmrg format, type, INT_MAX, pixels, caller)) { 149501e04c3fSmrg return; 149601e04c3fSmrg } 149701e04c3fSmrg 149801e04c3fSmrg get_texture_image(ctx, texObj, target, level, 149901e04c3fSmrg 0, 0, 0, width, height, depth, 150001e04c3fSmrg format, type, pixels, caller); 150101e04c3fSmrg} 150201e04c3fSmrg 150301e04c3fSmrg 150401e04c3fSmrgvoid GLAPIENTRY 150501e04c3fSmrg_mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, 150601e04c3fSmrg GLsizei bufSize, GLvoid *pixels) 150701e04c3fSmrg{ 150801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 150901e04c3fSmrg GLsizei width, height, depth; 151001e04c3fSmrg static const char *caller = "glGetTextureImage"; 151101e04c3fSmrg struct gl_texture_object *texObj = 151201e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 151301e04c3fSmrg 15144a49301eSmrg if (!texObj) { 151501e04c3fSmrg return; 151601e04c3fSmrg } 151701e04c3fSmrg 151801e04c3fSmrg if (!legal_getteximage_target(ctx, texObj->Target, true)) { 151901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 152001e04c3fSmrg return; 15214a49301eSmrg } 15224a49301eSmrg 152301e04c3fSmrg get_texture_image_dims(texObj, texObj->Target, level, 152401e04c3fSmrg &width, &height, &depth); 152501e04c3fSmrg 152601e04c3fSmrg if (getteximage_error_check(ctx, texObj, texObj->Target, level, 152701e04c3fSmrg width, height, depth, 152801e04c3fSmrg format, type, bufSize, pixels, caller)) { 152901e04c3fSmrg return; 153001e04c3fSmrg } 153101e04c3fSmrg 153201e04c3fSmrg get_texture_image(ctx, texObj, texObj->Target, level, 153301e04c3fSmrg 0, 0, 0, width, height, depth, 153401e04c3fSmrg format, type, pixels, caller); 153501e04c3fSmrg} 153601e04c3fSmrg 153701e04c3fSmrg 153801e04c3fSmrgvoid GLAPIENTRY 153901e04c3fSmrg_mesa_GetTextureSubImage(GLuint texture, GLint level, 154001e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 154101e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 154201e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 154301e04c3fSmrg void *pixels) 154401e04c3fSmrg{ 154501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 154601e04c3fSmrg static const char *caller = "glGetTextureSubImage"; 154701e04c3fSmrg struct gl_texture_object *texObj = 154801e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 15494a49301eSmrg 155001e04c3fSmrg if (!texObj) { 155101e04c3fSmrg return; 155201e04c3fSmrg } 155301e04c3fSmrg 155401e04c3fSmrg if (!legal_getteximage_target(ctx, texObj->Target, true)) { 155501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 155601e04c3fSmrg "%s(buffer/multisample texture)", caller); 155701e04c3fSmrg return; 155801e04c3fSmrg } 155901e04c3fSmrg 156001e04c3fSmrg if (gettexsubimage_error_check(ctx, texObj, texObj->Target, level, 156101e04c3fSmrg xoffset, yoffset, zoffset, 156201e04c3fSmrg width, height, depth, 156301e04c3fSmrg format, type, bufSize, pixels, caller)) { 156401e04c3fSmrg return; 156501e04c3fSmrg } 156601e04c3fSmrg 156701e04c3fSmrg get_texture_image(ctx, texObj, texObj->Target, level, 156801e04c3fSmrg xoffset, yoffset, zoffset, width, height, depth, 156901e04c3fSmrg format, type, pixels, caller); 157001e04c3fSmrg} 157101e04c3fSmrg 157201e04c3fSmrg 157301e04c3fSmrg 157401e04c3fSmrg/** 157501e04c3fSmrg * Compute the number of bytes which will be written when retrieving 157601e04c3fSmrg * a sub-region of a compressed texture. 157701e04c3fSmrg */ 157801e04c3fSmrgstatic GLsizei 157901e04c3fSmrgpacked_compressed_size(GLuint dimensions, mesa_format format, 158001e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 158101e04c3fSmrg const struct gl_pixelstore_attrib *packing) 158201e04c3fSmrg{ 158301e04c3fSmrg struct compressed_pixelstore st; 158401e04c3fSmrg GLsizei totalBytes; 158501e04c3fSmrg 158601e04c3fSmrg _mesa_compute_compressed_pixelstore(dimensions, format, 158701e04c3fSmrg width, height, depth, 158801e04c3fSmrg packing, &st); 158901e04c3fSmrg totalBytes = 159001e04c3fSmrg (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow + 159101e04c3fSmrg st.SkipBytes + 159201e04c3fSmrg (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow + 159301e04c3fSmrg st.CopyBytesPerRow; 159401e04c3fSmrg 159501e04c3fSmrg return totalBytes; 159601e04c3fSmrg} 159701e04c3fSmrg 159801e04c3fSmrg 159901e04c3fSmrg/** 160001e04c3fSmrg * Do error checking for getting compressed texture images. 160101e04c3fSmrg * \return true if any error, false if no errors. 160201e04c3fSmrg */ 160301e04c3fSmrgstatic bool 160401e04c3fSmrggetcompressedteximage_error_check(struct gl_context *ctx, 160501e04c3fSmrg struct gl_texture_object *texObj, 160601e04c3fSmrg GLenum target, GLint level, 160701e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 160801e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 160901e04c3fSmrg GLsizei bufSize, GLvoid *pixels, 161001e04c3fSmrg const char *caller) 161101e04c3fSmrg{ 161201e04c3fSmrg struct gl_texture_image *texImage; 161301e04c3fSmrg GLint maxLevels; 161401e04c3fSmrg GLsizei totalBytes; 161501e04c3fSmrg GLuint dimensions; 161601e04c3fSmrg 161701e04c3fSmrg assert(texObj); 161801e04c3fSmrg 161901e04c3fSmrg if (texObj->Target == 0) { 162001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); 162101e04c3fSmrg return true; 162201e04c3fSmrg } 162301e04c3fSmrg 162401e04c3fSmrg maxLevels = _mesa_max_texture_levels(ctx, target); 162501e04c3fSmrg if (level < 0 || level >= maxLevels) { 16264a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 162701e04c3fSmrg "%s(bad level = %d)", caller, level); 162801e04c3fSmrg return true; 16294a49301eSmrg } 16304a49301eSmrg 163101e04c3fSmrg if (dimensions_error_check(ctx, texObj, target, level, 163201e04c3fSmrg xoffset, yoffset, zoffset, 163301e04c3fSmrg width, height, depth, caller)) { 163401e04c3fSmrg return true; 163501e04c3fSmrg } 163601e04c3fSmrg 163701e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 163801e04c3fSmrg assert(texImage); 163901e04c3fSmrg 16404a49301eSmrg if (!_mesa_is_format_compressed(texImage->TexFormat)) { 16414a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 164201e04c3fSmrg "%s(texture is not compressed)", caller); 164301e04c3fSmrg return true; 16444a49301eSmrg } 16454a49301eSmrg 1646af69d88dSmrg /* Check for invalid pixel storage modes */ 164701e04c3fSmrg dimensions = _mesa_get_texture_dimensions(texObj->Target); 1648af69d88dSmrg if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, 164901e04c3fSmrg &ctx->Pack, 165001e04c3fSmrg caller)) { 165101e04c3fSmrg return true; 1652af69d88dSmrg } 1653af69d88dSmrg 165401e04c3fSmrg /* Compute number of bytes that may be touched in the dest buffer */ 165501e04c3fSmrg totalBytes = packed_compressed_size(dimensions, texImage->TexFormat, 165601e04c3fSmrg width, height, depth, 165701e04c3fSmrg &ctx->Pack); 165801e04c3fSmrg 165901e04c3fSmrg /* Do dest buffer bounds checking */ 166001e04c3fSmrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 16614a49301eSmrg /* do bounds checking on PBO write */ 166201e04c3fSmrg if ((GLubyte *) pixels + totalBytes > 166301e04c3fSmrg (GLubyte *) ctx->Pack.BufferObj->Size) { 16644a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 166501e04c3fSmrg "%s(out of bounds PBO access)", caller); 166601e04c3fSmrg return true; 16673464ebd5Sriastradh } 16683464ebd5Sriastradh 16693464ebd5Sriastradh /* make sure PBO is not mapped */ 1670af69d88dSmrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 167101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller); 167201e04c3fSmrg return true; 167301e04c3fSmrg } 167401e04c3fSmrg } 167501e04c3fSmrg else { 167601e04c3fSmrg /* do bounds checking on writing to client memory */ 167701e04c3fSmrg if (totalBytes > bufSize) { 16783464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 167901e04c3fSmrg "%s(out of bounds access: bufSize (%d) is too small)", 168001e04c3fSmrg caller, bufSize); 168101e04c3fSmrg return true; 16824a49301eSmrg } 16834a49301eSmrg } 16844a49301eSmrg 168501e04c3fSmrg if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) { 168601e04c3fSmrg /* not an error, but do nothing */ 168701e04c3fSmrg return true; 168801e04c3fSmrg } 168901e04c3fSmrg 169001e04c3fSmrg return false; 16914a49301eSmrg} 16924a49301eSmrg 16934a49301eSmrg 169401e04c3fSmrg/** 169501e04c3fSmrg * Common helper for all glGetCompressed-teximage functions. 169601e04c3fSmrg */ 169701e04c3fSmrgstatic void 169801e04c3fSmrgget_compressed_texture_image(struct gl_context *ctx, 169901e04c3fSmrg struct gl_texture_object *texObj, 170001e04c3fSmrg GLenum target, GLint level, 170101e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 170201e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 170301e04c3fSmrg GLvoid *pixels, 170401e04c3fSmrg const char *caller) 17054a49301eSmrg{ 17064a49301eSmrg struct gl_texture_image *texImage; 170701e04c3fSmrg unsigned firstFace, numFaces, i, imageStride; 1708af69d88dSmrg 1709af69d88dSmrg FLUSH_VERTICES(ctx, 0); 17104a49301eSmrg 171101e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 171201e04c3fSmrg assert(texImage); /* should have been error checked already */ 17134a49301eSmrg 1714af69d88dSmrg if (_mesa_is_zero_size_texture(texImage)) 1715af69d88dSmrg return; 1716af69d88dSmrg 17174a49301eSmrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 17184a49301eSmrg _mesa_debug(ctx, 171901e04c3fSmrg "%s(tex %u) format = %s, w=%d, h=%d\n", 172001e04c3fSmrg caller, texObj->Name, 17214a49301eSmrg _mesa_get_format_name(texImage->TexFormat), 17224a49301eSmrg texImage->Width, texImage->Height); 17234a49301eSmrg } 17244a49301eSmrg 172501e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 172601e04c3fSmrg struct compressed_pixelstore store; 172701e04c3fSmrg 172801e04c3fSmrg /* Compute image stride between cube faces */ 172901e04c3fSmrg _mesa_compute_compressed_pixelstore(2, texImage->TexFormat, 173001e04c3fSmrg width, height, depth, 173101e04c3fSmrg &ctx->Pack, &store); 173201e04c3fSmrg imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice; 173301e04c3fSmrg 173401e04c3fSmrg firstFace = zoffset; 173501e04c3fSmrg numFaces = depth; 173601e04c3fSmrg zoffset = 0; 173701e04c3fSmrg depth = 1; 173801e04c3fSmrg } 173901e04c3fSmrg else { 174001e04c3fSmrg imageStride = 0; 174101e04c3fSmrg firstFace = _mesa_tex_target_to_face(target); 174201e04c3fSmrg numFaces = 1; 174301e04c3fSmrg } 174401e04c3fSmrg 17454a49301eSmrg _mesa_lock_texture(ctx, texObj); 174601e04c3fSmrg 174701e04c3fSmrg for (i = 0; i < numFaces; i++) { 174801e04c3fSmrg texImage = texObj->Image[firstFace + i][level]; 174901e04c3fSmrg assert(texImage); 175001e04c3fSmrg 175101e04c3fSmrg get_compressed_texsubimage_sw(ctx, texImage, 175201e04c3fSmrg xoffset, yoffset, zoffset, 175301e04c3fSmrg width, height, depth, pixels); 175401e04c3fSmrg 175501e04c3fSmrg /* next cube face */ 175601e04c3fSmrg pixels = (GLubyte *) pixels + imageStride; 17574a49301eSmrg } 175801e04c3fSmrg 17594a49301eSmrg _mesa_unlock_texture(ctx, texObj); 17604a49301eSmrg} 17613464ebd5Sriastradh 176201e04c3fSmrg 17633464ebd5Sriastradhvoid GLAPIENTRY 176401e04c3fSmrg_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 176501e04c3fSmrg GLvoid *pixels) 17663464ebd5Sriastradh{ 176701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 176801e04c3fSmrg static const char *caller = "glGetnCompressedTexImageARB"; 176901e04c3fSmrg GLsizei width, height, depth; 177001e04c3fSmrg struct gl_texture_object *texObj; 177101e04c3fSmrg 177201e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 177301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 177401e04c3fSmrg return; 177501e04c3fSmrg } 177601e04c3fSmrg 177701e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 177801e04c3fSmrg assert(texObj); 177901e04c3fSmrg 178001e04c3fSmrg get_texture_image_dims(texObj, target, level, &width, &height, &depth); 178101e04c3fSmrg 178201e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, target, level, 178301e04c3fSmrg 0, 0, 0, width, height, depth, 178401e04c3fSmrg INT_MAX, pixels, caller)) { 178501e04c3fSmrg return; 178601e04c3fSmrg } 178701e04c3fSmrg 178801e04c3fSmrg get_compressed_texture_image(ctx, texObj, target, level, 178901e04c3fSmrg 0, 0, 0, width, height, depth, 179001e04c3fSmrg pixels, caller); 179101e04c3fSmrg} 179201e04c3fSmrg 179301e04c3fSmrg 179401e04c3fSmrgvoid GLAPIENTRY 179501e04c3fSmrg_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels) 179601e04c3fSmrg{ 179701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 179801e04c3fSmrg static const char *caller = "glGetCompressedTexImage"; 179901e04c3fSmrg GLsizei width, height, depth; 180001e04c3fSmrg struct gl_texture_object *texObj; 180101e04c3fSmrg 180201e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 180301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 180401e04c3fSmrg return; 180501e04c3fSmrg } 180601e04c3fSmrg 180701e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 180801e04c3fSmrg assert(texObj); 180901e04c3fSmrg 181001e04c3fSmrg get_texture_image_dims(texObj, target, level, 181101e04c3fSmrg &width, &height, &depth); 181201e04c3fSmrg 181301e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, target, level, 181401e04c3fSmrg 0, 0, 0, width, height, depth, 181501e04c3fSmrg INT_MAX, pixels, caller)) { 181601e04c3fSmrg return; 181701e04c3fSmrg } 181801e04c3fSmrg 181901e04c3fSmrg get_compressed_texture_image(ctx, texObj, target, level, 182001e04c3fSmrg 0, 0, 0, width, height, depth, 182101e04c3fSmrg pixels, caller); 182201e04c3fSmrg} 182301e04c3fSmrg 182401e04c3fSmrg 182501e04c3fSmrgvoid GLAPIENTRY 182601e04c3fSmrg_mesa_GetCompressedTextureImage(GLuint texture, GLint level, 182701e04c3fSmrg GLsizei bufSize, GLvoid *pixels) 182801e04c3fSmrg{ 182901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 183001e04c3fSmrg static const char *caller = "glGetCompressedTextureImage"; 183101e04c3fSmrg GLsizei width, height, depth; 183201e04c3fSmrg struct gl_texture_object *texObj = 183301e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 183401e04c3fSmrg 183501e04c3fSmrg if (!texObj) { 183601e04c3fSmrg return; 183701e04c3fSmrg } 183801e04c3fSmrg 183901e04c3fSmrg get_texture_image_dims(texObj, texObj->Target, level, 184001e04c3fSmrg &width, &height, &depth); 184101e04c3fSmrg 184201e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 184301e04c3fSmrg 0, 0, 0, width, height, depth, 184401e04c3fSmrg bufSize, pixels, caller)) { 184501e04c3fSmrg return; 184601e04c3fSmrg } 184701e04c3fSmrg 184801e04c3fSmrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 184901e04c3fSmrg 0, 0, 0, width, height, depth, 185001e04c3fSmrg pixels, caller); 185101e04c3fSmrg} 185201e04c3fSmrg 185301e04c3fSmrg 185401e04c3fSmrgvoid APIENTRY 185501e04c3fSmrg_mesa_GetCompressedTextureSubImage(GLuint texture, GLint level, 185601e04c3fSmrg GLint xoffset, GLint yoffset, 185701e04c3fSmrg GLint zoffset, GLsizei width, 185801e04c3fSmrg GLsizei height, GLsizei depth, 185901e04c3fSmrg GLsizei bufSize, void *pixels) 186001e04c3fSmrg{ 186101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 186201e04c3fSmrg static const char *caller = "glGetCompressedTextureImage"; 186301e04c3fSmrg struct gl_texture_object *texObj = NULL; 186401e04c3fSmrg 186501e04c3fSmrg texObj = _mesa_lookup_texture_err(ctx, texture, caller); 186601e04c3fSmrg if (!texObj) { 186701e04c3fSmrg return; 186801e04c3fSmrg } 186901e04c3fSmrg 187001e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 187101e04c3fSmrg xoffset, yoffset, zoffset, 187201e04c3fSmrg width, height, depth, 187301e04c3fSmrg bufSize, pixels, caller)) { 187401e04c3fSmrg return; 187501e04c3fSmrg } 187601e04c3fSmrg 187701e04c3fSmrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 187801e04c3fSmrg xoffset, yoffset, zoffset, 187901e04c3fSmrg width, height, depth, 188001e04c3fSmrg pixels, caller); 18813464ebd5Sriastradh} 1882