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 1364a49301eSmrg for (img = 0; img < depth; img++) { 137af69d88dSmrg GLubyte *srcMap; 138af69d88dSmrg GLint rowstride; 139af69d88dSmrg 140af69d88dSmrg /* map src texture buffer */ 14101e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 14201e04c3fSmrg xoffset, yoffset, width, height, 14301e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &rowstride); 144af69d88dSmrg 145af69d88dSmrg if (srcMap) { 146af69d88dSmrg for (row = 0; row < height; row++) { 147af69d88dSmrg const GLubyte *src = srcMap + row * rowstride; 148af69d88dSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 149af69d88dSmrg width, height, format, type, 150af69d88dSmrg img, row, 0); 1517ec681f3Smrg switch (type) { 1527ec681f3Smrg case GL_UNSIGNED_INT_24_8: 1537ec681f3Smrg _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat, 1547ec681f3Smrg width, src, dest); 1557ec681f3Smrg break; 1567ec681f3Smrg case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: 1577ec681f3Smrg _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat, 1587ec681f3Smrg width, 1597ec681f3Smrg src, dest); 1607ec681f3Smrg break; 1617ec681f3Smrg default: 1627ec681f3Smrg unreachable("bad type in get_tex_depth_stencil()"); 1637ec681f3Smrg } 164af69d88dSmrg if (ctx->Pack.SwapBytes) { 165af69d88dSmrg _mesa_swap4((GLuint *) dest, width); 166af69d88dSmrg } 1674a49301eSmrg } 1684a49301eSmrg 16901e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 17001e04c3fSmrg } 17101e04c3fSmrg else { 17201e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 17301e04c3fSmrg break; 17401e04c3fSmrg } 17501e04c3fSmrg } 17601e04c3fSmrg} 17701e04c3fSmrg 17801e04c3fSmrg/** 17901e04c3fSmrg * glGetTexImage for stencil pixels. 18001e04c3fSmrg */ 18101e04c3fSmrgstatic void 18201e04c3fSmrgget_tex_stencil(struct gl_context *ctx, GLuint dimensions, 18301e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 18401e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 18501e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 18601e04c3fSmrg struct gl_texture_image *texImage) 18701e04c3fSmrg{ 18801e04c3fSmrg GLint img, row; 18901e04c3fSmrg 19001e04c3fSmrg assert(format == GL_STENCIL_INDEX); 19101e04c3fSmrg 19201e04c3fSmrg for (img = 0; img < depth; img++) { 19301e04c3fSmrg GLubyte *srcMap; 19401e04c3fSmrg GLint rowstride; 19501e04c3fSmrg 19601e04c3fSmrg /* map src texture buffer */ 19701e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 19801e04c3fSmrg xoffset, yoffset, width, height, 19901e04c3fSmrg GL_MAP_READ_BIT, 20001e04c3fSmrg &srcMap, &rowstride); 20101e04c3fSmrg 20201e04c3fSmrg if (srcMap) { 20301e04c3fSmrg for (row = 0; row < height; row++) { 20401e04c3fSmrg const GLubyte *src = srcMap + row * rowstride; 20501e04c3fSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 20601e04c3fSmrg width, height, format, type, 20701e04c3fSmrg img, row, 0); 20801e04c3fSmrg _mesa_unpack_ubyte_stencil_row(texImage->TexFormat, 20901e04c3fSmrg width, 21001e04c3fSmrg (const GLuint *) src, 21101e04c3fSmrg dest); 21201e04c3fSmrg } 21301e04c3fSmrg 21401e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 215af69d88dSmrg } 216af69d88dSmrg else { 217af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 218af69d88dSmrg break; 2194a49301eSmrg } 2204a49301eSmrg } 2214a49301eSmrg} 2224a49301eSmrg 2234a49301eSmrg 2244a49301eSmrg/** 2254a49301eSmrg * glGetTexImage for YCbCr pixels. 2264a49301eSmrg */ 2274a49301eSmrgstatic void 2283464ebd5Sriastradhget_tex_ycbcr(struct gl_context *ctx, GLuint dimensions, 22901e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 23001e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 2314a49301eSmrg GLenum format, GLenum type, GLvoid *pixels, 232af69d88dSmrg struct gl_texture_image *texImage) 2334a49301eSmrg{ 2344a49301eSmrg GLint img, row; 2354a49301eSmrg 2364a49301eSmrg for (img = 0; img < depth; img++) { 237af69d88dSmrg GLubyte *srcMap; 238af69d88dSmrg GLint rowstride; 239af69d88dSmrg 240af69d88dSmrg /* map src texture buffer */ 24101e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 24201e04c3fSmrg xoffset, yoffset, width, height, 24301e04c3fSmrg GL_MAP_READ_BIT, &srcMap, &rowstride); 244af69d88dSmrg 245af69d88dSmrg if (srcMap) { 246af69d88dSmrg for (row = 0; row < height; row++) { 247af69d88dSmrg const GLubyte *src = srcMap + row * rowstride; 248af69d88dSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 249af69d88dSmrg width, height, format, type, 250af69d88dSmrg img, row, 0); 251af69d88dSmrg memcpy(dest, src, width * sizeof(GLushort)); 252af69d88dSmrg 253af69d88dSmrg /* check for byte swapping */ 254af69d88dSmrg if ((texImage->TexFormat == MESA_FORMAT_YCBCR 255af69d88dSmrg && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || 256af69d88dSmrg (texImage->TexFormat == MESA_FORMAT_YCBCR_REV 257af69d88dSmrg && type == GL_UNSIGNED_SHORT_8_8_MESA)) { 258af69d88dSmrg if (!ctx->Pack.SwapBytes) 259af69d88dSmrg _mesa_swap2((GLushort *) dest, width); 260af69d88dSmrg } 261af69d88dSmrg else if (ctx->Pack.SwapBytes) { 2624a49301eSmrg _mesa_swap2((GLushort *) dest, width); 263af69d88dSmrg } 2644a49301eSmrg } 2654a49301eSmrg 26601e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 267af69d88dSmrg } 268af69d88dSmrg else { 269af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 270af69d88dSmrg break; 2714a49301eSmrg } 2724a49301eSmrg } 2734a49301eSmrg} 2744a49301eSmrg 27501e04c3fSmrg/** 27601e04c3fSmrg * Depending on the base format involved we may need to apply a rebase 27701e04c3fSmrg * transform (for example: if we download to a Luminance format we want 27801e04c3fSmrg * G=0 and B=0). 27901e04c3fSmrg */ 28001e04c3fSmrgstatic bool 28101e04c3fSmrgteximage_needs_rebase(mesa_format texFormat, GLenum baseFormat, 28201e04c3fSmrg bool is_compressed, uint8_t *rebaseSwizzle) 28301e04c3fSmrg{ 28401e04c3fSmrg bool needsRebase = false; 28501e04c3fSmrg 28601e04c3fSmrg if (baseFormat == GL_LUMINANCE || 28701e04c3fSmrg baseFormat == GL_INTENSITY) { 28801e04c3fSmrg needsRebase = true; 28901e04c3fSmrg rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; 29001e04c3fSmrg rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; 29101e04c3fSmrg rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; 29201e04c3fSmrg rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE; 29301e04c3fSmrg } else if (baseFormat == GL_LUMINANCE_ALPHA) { 29401e04c3fSmrg needsRebase = true; 29501e04c3fSmrg rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X; 29601e04c3fSmrg rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; 29701e04c3fSmrg rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; 29801e04c3fSmrg rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W; 29901e04c3fSmrg } else if (!is_compressed && 30001e04c3fSmrg (baseFormat != _mesa_get_format_base_format(texFormat))) { 30101e04c3fSmrg needsRebase = 30201e04c3fSmrg _mesa_compute_rgba2base2rgba_component_mapping(baseFormat, 30301e04c3fSmrg rebaseSwizzle); 30401e04c3fSmrg } 30501e04c3fSmrg 30601e04c3fSmrg return needsRebase; 30701e04c3fSmrg} 30801e04c3fSmrg 3094a49301eSmrg 3104a49301eSmrg/** 311af69d88dSmrg * Get a color texture image with decompression. 3124a49301eSmrg */ 3134a49301eSmrgstatic void 314af69d88dSmrgget_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, 31501e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 31601e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 317af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 318af69d88dSmrg struct gl_texture_image *texImage, 319af69d88dSmrg GLbitfield transferOps) 3204a49301eSmrg{ 321af69d88dSmrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 322af69d88dSmrg const mesa_format texFormat = 323af69d88dSmrg _mesa_get_srgb_format_linear(texImage->TexFormat); 324af69d88dSmrg const GLenum baseFormat = _mesa_get_format_base_format(texFormat); 32501e04c3fSmrg GLfloat *tempImage, *tempSlice; 32601e04c3fSmrg GLuint slice; 32701e04c3fSmrg int srcStride, dstStride; 32801e04c3fSmrg uint32_t dstFormat; 32901e04c3fSmrg bool needsRebase; 33001e04c3fSmrg uint8_t rebaseSwizzle[4]; 331af69d88dSmrg 332af69d88dSmrg /* Decompress into temp float buffer, then pack into user buffer */ 33301e04c3fSmrg tempImage = malloc(width * height * depth * 4 * sizeof(GLfloat)); 334af69d88dSmrg if (!tempImage) { 335af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 3363464ebd5Sriastradh return; 3373464ebd5Sriastradh } 3383464ebd5Sriastradh 339af69d88dSmrg /* Decompress the texture image slices - results in 'tempImage' */ 340af69d88dSmrg for (slice = 0; slice < depth; slice++) { 341af69d88dSmrg GLubyte *srcMap; 342af69d88dSmrg GLint srcRowStride; 343af69d88dSmrg 344af69d88dSmrg tempSlice = tempImage + slice * 4 * width * height; 345af69d88dSmrg 34601e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice, 34701e04c3fSmrg xoffset, yoffset, width, height, 348af69d88dSmrg GL_MAP_READ_BIT, 349af69d88dSmrg &srcMap, &srcRowStride); 350af69d88dSmrg if (srcMap) { 351af69d88dSmrg _mesa_decompress_image(texFormat, width, height, 352af69d88dSmrg srcMap, srcRowStride, tempSlice); 353af69d88dSmrg 35401e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice); 355af69d88dSmrg } 356af69d88dSmrg else { 357af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 358af69d88dSmrg free(tempImage); 359af69d88dSmrg return; 360af69d88dSmrg } 3613464ebd5Sriastradh } 362af69d88dSmrg 36301e04c3fSmrg needsRebase = teximage_needs_rebase(texFormat, baseFormat, true, 36401e04c3fSmrg rebaseSwizzle); 3654a49301eSmrg 36601e04c3fSmrg srcStride = 4 * width * sizeof(GLfloat); 36701e04c3fSmrg dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type); 36801e04c3fSmrg dstFormat = _mesa_format_from_format_and_type(format, type); 369af69d88dSmrg tempSlice = tempImage; 370af69d88dSmrg for (slice = 0; slice < depth; slice++) { 37101e04c3fSmrg void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 37201e04c3fSmrg width, height, format, type, 37301e04c3fSmrg slice, 0, 0); 37401e04c3fSmrg _mesa_format_convert(dest, dstFormat, dstStride, 37501e04c3fSmrg tempSlice, RGBA32_FLOAT, srcStride, 37601e04c3fSmrg width, height, 37701e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 37801e04c3fSmrg 37901e04c3fSmrg /* Handle byte swapping if required */ 38001e04c3fSmrg if (ctx->Pack.SwapBytes) { 38101e04c3fSmrg _mesa_swap_bytes_2d_image(format, type, &ctx->Pack, 38201e04c3fSmrg width, height, dest, dest); 383af69d88dSmrg } 38401e04c3fSmrg 385af69d88dSmrg tempSlice += 4 * width * height; 386af69d88dSmrg } 387af69d88dSmrg 388af69d88dSmrg free(tempImage); 389af69d88dSmrg} 390af69d88dSmrg 391af69d88dSmrg 392af69d88dSmrg/** 393af69d88dSmrg * Return a base GL format given the user-requested format 394af69d88dSmrg * for glGetTexImage(). 395af69d88dSmrg */ 396af69d88dSmrgGLenum 397af69d88dSmrg_mesa_base_pack_format(GLenum format) 398af69d88dSmrg{ 399af69d88dSmrg switch (format) { 400af69d88dSmrg case GL_ABGR_EXT: 401af69d88dSmrg case GL_BGRA: 402af69d88dSmrg case GL_BGRA_INTEGER: 403af69d88dSmrg case GL_RGBA_INTEGER: 404af69d88dSmrg return GL_RGBA; 405af69d88dSmrg case GL_BGR: 406af69d88dSmrg case GL_BGR_INTEGER: 407af69d88dSmrg case GL_RGB_INTEGER: 408af69d88dSmrg return GL_RGB; 409af69d88dSmrg case GL_RED_INTEGER: 410af69d88dSmrg return GL_RED; 411af69d88dSmrg case GL_GREEN_INTEGER: 412af69d88dSmrg return GL_GREEN; 413af69d88dSmrg case GL_BLUE_INTEGER: 414af69d88dSmrg return GL_BLUE; 415af69d88dSmrg case GL_ALPHA_INTEGER: 416af69d88dSmrg return GL_ALPHA; 417af69d88dSmrg case GL_LUMINANCE_INTEGER_EXT: 418af69d88dSmrg return GL_LUMINANCE; 419af69d88dSmrg case GL_LUMINANCE_ALPHA_INTEGER_EXT: 420af69d88dSmrg return GL_LUMINANCE_ALPHA; 421af69d88dSmrg default: 422af69d88dSmrg return format; 423af69d88dSmrg } 424af69d88dSmrg} 425af69d88dSmrg 426af69d88dSmrg 427af69d88dSmrg/** 428af69d88dSmrg * Get an uncompressed color texture image. 429af69d88dSmrg */ 430af69d88dSmrgstatic void 431af69d88dSmrgget_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, 43201e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 43301e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 434af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 435af69d88dSmrg struct gl_texture_image *texImage, 436af69d88dSmrg GLbitfield transferOps) 437af69d88dSmrg{ 438af69d88dSmrg /* don't want to apply sRGB -> RGB conversion here so override the format */ 439af69d88dSmrg const mesa_format texFormat = 440af69d88dSmrg _mesa_get_srgb_format_linear(texImage->TexFormat); 44101e04c3fSmrg GLuint img; 44201e04c3fSmrg GLboolean dst_is_integer; 44301e04c3fSmrg uint32_t dst_format; 44401e04c3fSmrg int dst_stride; 44501e04c3fSmrg uint8_t rebaseSwizzle[4]; 44601e04c3fSmrg bool needsRebase; 44701e04c3fSmrg void *rgba = NULL; 44801e04c3fSmrg 44901e04c3fSmrg needsRebase = teximage_needs_rebase(texFormat, texImage->_BaseFormat, false, 45001e04c3fSmrg rebaseSwizzle); 45101e04c3fSmrg 45201e04c3fSmrg /* Describe the dst format */ 45301e04c3fSmrg dst_is_integer = _mesa_is_enum_format_integer(format); 45401e04c3fSmrg dst_format = _mesa_format_from_format_and_type(format, type); 45501e04c3fSmrg dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type); 45601e04c3fSmrg 45701e04c3fSmrg /* Since _mesa_format_convert does not handle transferOps we need to handle 45801e04c3fSmrg * them before we call the function. This requires to convert to RGBA float 45901e04c3fSmrg * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is 46001e04c3fSmrg * integer then transferOps do not apply. 46101e04c3fSmrg */ 46201e04c3fSmrg assert(!transferOps || (transferOps && !dst_is_integer)); 46301e04c3fSmrg (void) dst_is_integer; /* silence unused var warning */ 4643464ebd5Sriastradh 465af69d88dSmrg for (img = 0; img < depth; img++) { 466af69d88dSmrg GLubyte *srcMap; 467af69d88dSmrg GLint rowstride; 46801e04c3fSmrg GLubyte *img_src; 46901e04c3fSmrg void *dest; 47001e04c3fSmrg void *src; 47101e04c3fSmrg int src_stride; 47201e04c3fSmrg uint32_t src_format; 473af69d88dSmrg 474af69d88dSmrg /* map src texture buffer */ 47501e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + img, 47601e04c3fSmrg xoffset, yoffset, width, height, 47701e04c3fSmrg GL_MAP_READ_BIT, 478af69d88dSmrg &srcMap, &rowstride); 47901e04c3fSmrg if (!srcMap) { 48001e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 48101e04c3fSmrg goto done; 48201e04c3fSmrg } 483af69d88dSmrg 48401e04c3fSmrg img_src = srcMap; 48501e04c3fSmrg dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, 48601e04c3fSmrg width, height, format, type, 48701e04c3fSmrg img, 0, 0); 48801e04c3fSmrg 48901e04c3fSmrg if (transferOps) { 49001e04c3fSmrg uint32_t rgba_format; 49101e04c3fSmrg int rgba_stride; 49201e04c3fSmrg bool need_convert = false; 49301e04c3fSmrg 49401e04c3fSmrg /* We will convert to RGBA float */ 49501e04c3fSmrg rgba_format = RGBA32_FLOAT; 49601e04c3fSmrg rgba_stride = width * 4 * sizeof(GLfloat); 49701e04c3fSmrg 49801e04c3fSmrg /* If we are lucky and the dst format matches the RGBA format we need 49901e04c3fSmrg * to convert to, then we can convert directly into the dst buffer 50001e04c3fSmrg * and avoid the final conversion/copy from the rgba buffer to the dst 50101e04c3fSmrg * buffer. 50201e04c3fSmrg */ 50301e04c3fSmrg if (format == rgba_format) { 50401e04c3fSmrg rgba = dest; 50501e04c3fSmrg } else { 50601e04c3fSmrg need_convert = true; 50701e04c3fSmrg if (rgba == NULL) { /* Allocate the RGBA buffer only once */ 50801e04c3fSmrg rgba = malloc(height * rgba_stride); 50901e04c3fSmrg if (!rgba) { 51001e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); 51101e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, img); 51201e04c3fSmrg return; 513af69d88dSmrg } 51401e04c3fSmrg } 51501e04c3fSmrg } 51601e04c3fSmrg 51701e04c3fSmrg _mesa_format_convert(rgba, rgba_format, rgba_stride, 51801e04c3fSmrg img_src, texFormat, rowstride, 51901e04c3fSmrg width, height, 52001e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 52101e04c3fSmrg 52201e04c3fSmrg /* Handle transfer ops now */ 52301e04c3fSmrg _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); 52401e04c3fSmrg 52501e04c3fSmrg /* If we had to rebase, we have already handled that */ 52601e04c3fSmrg needsRebase = false; 52701e04c3fSmrg 52801e04c3fSmrg /* If we were lucky and our RGBA conversion matches the dst format, 52901e04c3fSmrg * then we are done. 53001e04c3fSmrg */ 53101e04c3fSmrg if (!need_convert) 53201e04c3fSmrg goto do_swap; 53301e04c3fSmrg 53401e04c3fSmrg /* Otherwise, we need to convert from RGBA to dst next */ 53501e04c3fSmrg src = rgba; 53601e04c3fSmrg src_format = rgba_format; 53701e04c3fSmrg src_stride = rgba_stride; 53801e04c3fSmrg } else { 53901e04c3fSmrg /* No RGBA conversion needed, convert directly to dst */ 54001e04c3fSmrg src = img_src; 54101e04c3fSmrg src_format = texFormat; 54201e04c3fSmrg src_stride = rowstride; 543af69d88dSmrg } 54401e04c3fSmrg 54501e04c3fSmrg /* Do the conversion to destination format */ 54601e04c3fSmrg _mesa_format_convert(dest, dst_format, dst_stride, 54701e04c3fSmrg src, src_format, src_stride, 54801e04c3fSmrg width, height, 54901e04c3fSmrg needsRebase ? rebaseSwizzle : NULL); 55001e04c3fSmrg 55101e04c3fSmrg do_swap: 55201e04c3fSmrg /* Handle byte swapping if required */ 55301e04c3fSmrg if (ctx->Pack.SwapBytes) 55401e04c3fSmrg _mesa_swap_bytes_2d_image(format, type, &ctx->Pack, 55501e04c3fSmrg width, height, dest, dest); 55601e04c3fSmrg 55701e04c3fSmrg /* Unmap the src texture buffer */ 55801e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + img); 5593464ebd5Sriastradh } 5603464ebd5Sriastradh 56101e04c3fSmrgdone: 5623464ebd5Sriastradh free(rgba); 5634a49301eSmrg} 5644a49301eSmrg 5654a49301eSmrg 566af69d88dSmrg/** 567af69d88dSmrg * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). 568af69d88dSmrg * Compressed textures are handled here as well. 569af69d88dSmrg */ 570af69d88dSmrgstatic void 571af69d88dSmrgget_tex_rgba(struct gl_context *ctx, GLuint dimensions, 57201e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 57301e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 574af69d88dSmrg GLenum format, GLenum type, GLvoid *pixels, 575af69d88dSmrg struct gl_texture_image *texImage) 576af69d88dSmrg{ 577af69d88dSmrg const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); 578af69d88dSmrg GLbitfield transferOps = 0x0; 579af69d88dSmrg 580af69d88dSmrg /* In general, clamping does not apply to glGetTexImage, except when 581af69d88dSmrg * the returned type of the image can't hold negative values. 582af69d88dSmrg */ 583af69d88dSmrg if (type_needs_clamping(type)) { 584af69d88dSmrg /* the returned image type can't have negative values */ 585af69d88dSmrg if (dataType == GL_FLOAT || 586af69d88dSmrg dataType == GL_HALF_FLOAT || 587af69d88dSmrg dataType == GL_SIGNED_NORMALIZED || 588af69d88dSmrg format == GL_LUMINANCE || 589af69d88dSmrg format == GL_LUMINANCE_ALPHA) { 590af69d88dSmrg transferOps |= IMAGE_CLAMP_BIT; 591af69d88dSmrg } 592af69d88dSmrg } 593af69d88dSmrg 594af69d88dSmrg if (_mesa_is_format_compressed(texImage->TexFormat)) { 59501e04c3fSmrg get_tex_rgba_compressed(ctx, dimensions, 59601e04c3fSmrg xoffset, yoffset, zoffset, 59701e04c3fSmrg width, height, depth, 59801e04c3fSmrg format, type, 599af69d88dSmrg pixels, texImage, transferOps); 600af69d88dSmrg } 601af69d88dSmrg else { 60201e04c3fSmrg get_tex_rgba_uncompressed(ctx, dimensions, 60301e04c3fSmrg xoffset, yoffset, zoffset, 60401e04c3fSmrg width, height, depth, 60501e04c3fSmrg format, type, 606af69d88dSmrg pixels, texImage, transferOps); 607af69d88dSmrg } 608af69d88dSmrg} 609af69d88dSmrg 610af69d88dSmrg 6114a49301eSmrg/** 6124a49301eSmrg * Try to do glGetTexImage() with simple memcpy(). 6134a49301eSmrg * \return GL_TRUE if done, GL_FALSE otherwise 6144a49301eSmrg */ 6154a49301eSmrgstatic GLboolean 61601e04c3fSmrgget_tex_memcpy(struct gl_context *ctx, 61701e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 61801e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 61901e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 620af69d88dSmrg struct gl_texture_image *texImage) 6214a49301eSmrg{ 622af69d88dSmrg const GLenum target = texImage->TexObject->Target; 6234a49301eSmrg GLboolean memCopy = GL_FALSE; 624af69d88dSmrg GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat); 6254a49301eSmrg 6264a49301eSmrg /* 627af69d88dSmrg * Check if we can use memcpy to copy from the hardware texture 628af69d88dSmrg * format to the user's format/type. 629af69d88dSmrg * Note that GL's pixel transfer ops don't apply to glGetTexImage() 6304a49301eSmrg */ 631af69d88dSmrg if ((target == GL_TEXTURE_1D || 632af69d88dSmrg target == GL_TEXTURE_2D || 633af69d88dSmrg target == GL_TEXTURE_RECTANGLE || 634af69d88dSmrg _mesa_is_cube_face(target)) && 635af69d88dSmrg texBaseFormat == texImage->_BaseFormat) { 636af69d88dSmrg memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat, 637af69d88dSmrg format, type, 63801e04c3fSmrg ctx->Pack.SwapBytes, NULL); 63901e04c3fSmrg } 64001e04c3fSmrg 64101e04c3fSmrg if (depth > 1) { 64201e04c3fSmrg /* only a single slice is supported at this time */ 6437ec681f3Smrg memCopy = GL_FALSE; 6444a49301eSmrg } 6454a49301eSmrg 6464a49301eSmrg if (memCopy) { 6474a49301eSmrg const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat); 64801e04c3fSmrg const GLint bytesPerRow = width * bpp; 6494a49301eSmrg GLubyte *dst = 65001e04c3fSmrg _mesa_image_address2d(&ctx->Pack, pixels, width, height, 65101e04c3fSmrg format, type, 0, 0); 6524a49301eSmrg const GLint dstRowStride = 65301e04c3fSmrg _mesa_image_row_stride(&ctx->Pack, width, format, type); 654af69d88dSmrg GLubyte *src; 655af69d88dSmrg GLint srcRowStride; 6564a49301eSmrg 657af69d88dSmrg /* map src texture buffer */ 65801e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset, 65901e04c3fSmrg xoffset, yoffset, width, height, 660af69d88dSmrg GL_MAP_READ_BIT, &src, &srcRowStride); 661af69d88dSmrg 662af69d88dSmrg if (src) { 663af69d88dSmrg if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) { 66401e04c3fSmrg memcpy(dst, src, bytesPerRow * height); 665af69d88dSmrg } 666af69d88dSmrg else { 667af69d88dSmrg GLuint row; 66801e04c3fSmrg for (row = 0; row < height; row++) { 669af69d88dSmrg memcpy(dst, src, bytesPerRow); 670af69d88dSmrg dst += dstRowStride; 671af69d88dSmrg src += srcRowStride; 672af69d88dSmrg } 673af69d88dSmrg } 674af69d88dSmrg 675af69d88dSmrg /* unmap src texture buffer */ 67601e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset); 6774a49301eSmrg } 6784a49301eSmrg else { 679af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); 6804a49301eSmrg } 6814a49301eSmrg } 6824a49301eSmrg 6834a49301eSmrg return memCopy; 6844a49301eSmrg} 6854a49301eSmrg 6864a49301eSmrg 6874a49301eSmrg/** 68801e04c3fSmrg * This is the software fallback for Driver.GetTexSubImage(). 6894a49301eSmrg * All error checking will have been done before this routine is called. 690af69d88dSmrg * We'll call ctx->Driver.MapTextureImage() to access the data, then 691af69d88dSmrg * unmap with ctx->Driver.UnmapTextureImage(). 6924a49301eSmrg */ 6934a49301eSmrgvoid 69401e04c3fSmrg_mesa_GetTexSubImage_sw(struct gl_context *ctx, 69501e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 69601e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 69701e04c3fSmrg GLenum format, GLenum type, GLvoid *pixels, 69801e04c3fSmrg struct gl_texture_image *texImage) 6994a49301eSmrg{ 700af69d88dSmrg const GLuint dimensions = 701af69d88dSmrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 7024a49301eSmrg 703af69d88dSmrg /* map dest buffer, if PBO */ 7047ec681f3Smrg if (ctx->Pack.BufferObj) { 7054a49301eSmrg /* Packing texture image into a PBO. 7064a49301eSmrg * Map the (potentially) VRAM-based buffer into our process space so 7074a49301eSmrg * we can write into it with the code below. 7084a49301eSmrg * A hardware driver might use a sophisticated blit to move the 7094a49301eSmrg * texture data to the PBO if the PBO is in VRAM along with the texture. 7104a49301eSmrg */ 7114a49301eSmrg GLubyte *buf = (GLubyte *) 712af69d88dSmrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 713af69d88dSmrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 714af69d88dSmrg MAP_INTERNAL); 7154a49301eSmrg if (!buf) { 7164a49301eSmrg /* out of memory or other unexpected error */ 7174a49301eSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)"); 7184a49301eSmrg return; 7194a49301eSmrg } 7204a49301eSmrg /* <pixels> was an offset into the PBO. 7214a49301eSmrg * Now make it a real, client-side pointer inside the mapped region. 7224a49301eSmrg */ 7234a49301eSmrg pixels = ADD_POINTERS(buf, pixels); 7244a49301eSmrg } 7254a49301eSmrg 72601e04c3fSmrg /* for all array textures, the Z axis selects the layer */ 72701e04c3fSmrg if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { 72801e04c3fSmrg depth = height; 72901e04c3fSmrg height = 1; 73001e04c3fSmrg zoffset = yoffset; 73101e04c3fSmrg yoffset = 0; 73201e04c3fSmrg assert(zoffset + depth <= texImage->Height); 73301e04c3fSmrg } else { 73401e04c3fSmrg assert(zoffset + depth <= texImage->Depth); 73501e04c3fSmrg } 73601e04c3fSmrg 73701e04c3fSmrg if (get_tex_memcpy(ctx, xoffset, yoffset, zoffset, width, height, depth, 73801e04c3fSmrg format, type, pixels, texImage)) { 7394a49301eSmrg /* all done */ 7404a49301eSmrg } 7414a49301eSmrg else if (format == GL_DEPTH_COMPONENT) { 74201e04c3fSmrg get_tex_depth(ctx, dimensions, xoffset, yoffset, zoffset, 74301e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7444a49301eSmrg } 7454a49301eSmrg else if (format == GL_DEPTH_STENCIL_EXT) { 74601e04c3fSmrg get_tex_depth_stencil(ctx, dimensions, xoffset, yoffset, zoffset, 74701e04c3fSmrg width, height, depth, format, type, pixels, 74801e04c3fSmrg texImage); 74901e04c3fSmrg } 75001e04c3fSmrg else if (format == GL_STENCIL_INDEX) { 75101e04c3fSmrg get_tex_stencil(ctx, dimensions, xoffset, yoffset, zoffset, 75201e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7534a49301eSmrg } 7544a49301eSmrg else if (format == GL_YCBCR_MESA) { 75501e04c3fSmrg get_tex_ycbcr(ctx, dimensions, xoffset, yoffset, zoffset, 75601e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7574a49301eSmrg } 7584a49301eSmrg else { 75901e04c3fSmrg get_tex_rgba(ctx, dimensions, xoffset, yoffset, zoffset, 76001e04c3fSmrg width, height, depth, format, type, pixels, texImage); 7614a49301eSmrg } 7624a49301eSmrg 7637ec681f3Smrg if (ctx->Pack.BufferObj) { 764af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 7654a49301eSmrg } 7664a49301eSmrg} 7674a49301eSmrg 7684a49301eSmrg 7694a49301eSmrg 7704a49301eSmrg/** 77101e04c3fSmrg * This function assumes that all error checking has been done. 7724a49301eSmrg */ 77301e04c3fSmrgstatic void 77401e04c3fSmrgget_compressed_texsubimage_sw(struct gl_context *ctx, 775af69d88dSmrg struct gl_texture_image *texImage, 77601e04c3fSmrg GLint xoffset, GLint yoffset, 77701e04c3fSmrg GLint zoffset, GLsizei width, 77801e04c3fSmrg GLint height, GLint depth, 779af69d88dSmrg GLvoid *img) 7804a49301eSmrg{ 781af69d88dSmrg const GLuint dimensions = 782af69d88dSmrg _mesa_get_texture_dimensions(texImage->TexObject->Target); 783af69d88dSmrg struct compressed_pixelstore store; 78401e04c3fSmrg GLint slice; 785af69d88dSmrg GLubyte *dest; 786af69d88dSmrg 787af69d88dSmrg _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat, 78801e04c3fSmrg width, height, depth, 78901e04c3fSmrg &ctx->Pack, &store); 7904a49301eSmrg 7917ec681f3Smrg if (ctx->Pack.BufferObj) { 7924a49301eSmrg /* pack texture image into a PBO */ 793af69d88dSmrg dest = (GLubyte *) 794af69d88dSmrg ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size, 795af69d88dSmrg GL_MAP_WRITE_BIT, ctx->Pack.BufferObj, 796af69d88dSmrg MAP_INTERNAL); 797af69d88dSmrg if (!dest) { 7984a49301eSmrg /* out of memory or other unexpected error */ 7994a49301eSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 8004a49301eSmrg "glGetCompresssedTexImage(map PBO failed)"); 8014a49301eSmrg return; 8024a49301eSmrg } 803af69d88dSmrg dest = ADD_POINTERS(dest, img); 804af69d88dSmrg } else { 805af69d88dSmrg dest = img; 8064a49301eSmrg } 8074a49301eSmrg 808af69d88dSmrg dest += store.SkipBytes; 8094a49301eSmrg 810af69d88dSmrg for (slice = 0; slice < store.CopySlices; slice++) { 811af69d88dSmrg GLint srcRowStride; 812af69d88dSmrg GLubyte *src; 813af69d88dSmrg 814af69d88dSmrg /* map src texture buffer */ 81501e04c3fSmrg ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice, 81601e04c3fSmrg xoffset, yoffset, width, height, 817af69d88dSmrg GL_MAP_READ_BIT, &src, &srcRowStride); 818af69d88dSmrg 819af69d88dSmrg if (src) { 82001e04c3fSmrg GLint i; 821af69d88dSmrg for (i = 0; i < store.CopyRowsPerSlice; i++) { 822af69d88dSmrg memcpy(dest, src, store.CopyBytesPerRow); 823af69d88dSmrg dest += store.TotalBytesPerRow; 824af69d88dSmrg src += srcRowStride; 825af69d88dSmrg } 826af69d88dSmrg 82701e04c3fSmrg ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice); 828af69d88dSmrg 829af69d88dSmrg /* Advance to next slice */ 83001e04c3fSmrg dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - 83101e04c3fSmrg store.CopyRowsPerSlice); 832af69d88dSmrg 833af69d88dSmrg } else { 834af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage"); 8354a49301eSmrg } 8364a49301eSmrg } 8374a49301eSmrg 8387ec681f3Smrg if (ctx->Pack.BufferObj) { 839af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL); 8404a49301eSmrg } 8414a49301eSmrg} 8424a49301eSmrg 8434a49301eSmrg 844af69d88dSmrg/** 84501e04c3fSmrg * Validate the texture target enum supplied to glGetTex(ture)Image or 84601e04c3fSmrg * glGetCompressedTex(ture)Image. 847af69d88dSmrg */ 848af69d88dSmrgstatic GLboolean 84901e04c3fSmrglegal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa) 850af69d88dSmrg{ 851af69d88dSmrg switch (target) { 852af69d88dSmrg case GL_TEXTURE_1D: 853af69d88dSmrg case GL_TEXTURE_2D: 854af69d88dSmrg case GL_TEXTURE_3D: 855af69d88dSmrg return GL_TRUE; 856af69d88dSmrg case GL_TEXTURE_RECTANGLE_NV: 857af69d88dSmrg return ctx->Extensions.NV_texture_rectangle; 858af69d88dSmrg case GL_TEXTURE_1D_ARRAY_EXT: 859af69d88dSmrg case GL_TEXTURE_2D_ARRAY_EXT: 860af69d88dSmrg return ctx->Extensions.EXT_texture_array; 861af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 862af69d88dSmrg return ctx->Extensions.ARB_texture_cube_map_array; 86301e04c3fSmrg 86401e04c3fSmrg /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec 86501e04c3fSmrg * (30.10.2014) says: 86601e04c3fSmrg * "An INVALID_ENUM error is generated if the effective target is not 86701e04c3fSmrg * one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY, 86801e04c3fSmrg * TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of 86901e04c3fSmrg * the targets from table 8.19 (for GetTexImage and GetnTexImage *only*), 87001e04c3fSmrg * or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.) 87101e04c3fSmrg */ 87201e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 87301e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 87401e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 87501e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 87601e04c3fSmrg case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 87701e04c3fSmrg case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 87801e04c3fSmrg return dsa ? GL_FALSE : ctx->Extensions.ARB_texture_cube_map; 87901e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 88001e04c3fSmrg return dsa ? GL_TRUE : GL_FALSE; 881af69d88dSmrg default: 882af69d88dSmrg return GL_FALSE; 883af69d88dSmrg } 884af69d88dSmrg} 885af69d88dSmrg 8864a49301eSmrg 8874a49301eSmrg/** 88801e04c3fSmrg * Wrapper for _mesa_select_tex_image() which can handle target being 88901e04c3fSmrg * GL_TEXTURE_CUBE_MAP in which case we use zoffset to select a cube face. 89001e04c3fSmrg * This can happen for glGetTextureImage and glGetTextureSubImage (DSA 89101e04c3fSmrg * functions). 8924a49301eSmrg */ 89301e04c3fSmrgstatic struct gl_texture_image * 89401e04c3fSmrgselect_tex_image(const struct gl_texture_object *texObj, GLenum target, 89501e04c3fSmrg GLint level, GLint zoffset) 8964a49301eSmrg{ 89701e04c3fSmrg assert(level >= 0); 89801e04c3fSmrg assert(level < MAX_TEXTURE_LEVELS); 89901e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 90001e04c3fSmrg assert(zoffset >= 0); 90101e04c3fSmrg assert(zoffset < 6); 90201e04c3fSmrg target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset; 90301e04c3fSmrg } 90401e04c3fSmrg return _mesa_select_tex_image(texObj, target, level); 90501e04c3fSmrg} 9064a49301eSmrg 90701e04c3fSmrg 90801e04c3fSmrg/** 90901e04c3fSmrg * Error-check the offset and size arguments to 91001e04c3fSmrg * glGet[Compressed]TextureSubImage(). 91101e04c3fSmrg * \return true if error, false if no error. 91201e04c3fSmrg */ 91301e04c3fSmrgstatic bool 91401e04c3fSmrgdimensions_error_check(struct gl_context *ctx, 91501e04c3fSmrg struct gl_texture_object *texObj, 91601e04c3fSmrg GLenum target, GLint level, 91701e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 91801e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 91901e04c3fSmrg const char *caller) 92001e04c3fSmrg{ 92101e04c3fSmrg const struct gl_texture_image *texImage; 92201e04c3fSmrg GLuint imageWidth = 0, imageHeight = 0, imageDepth = 0; 92301e04c3fSmrg 92401e04c3fSmrg if (xoffset < 0) { 92501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset = %d)", caller, xoffset); 92601e04c3fSmrg return true; 9274a49301eSmrg } 9284a49301eSmrg 92901e04c3fSmrg if (yoffset < 0) { 93001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset = %d)", caller, yoffset); 93101e04c3fSmrg return true; 9324a49301eSmrg } 9334a49301eSmrg 93401e04c3fSmrg if (zoffset < 0) { 93501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset = %d)", caller, zoffset); 93601e04c3fSmrg return true; 9374a49301eSmrg } 9384a49301eSmrg 93901e04c3fSmrg if (width < 0) { 94001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(width = %d)", caller, width); 94101e04c3fSmrg return true; 94201e04c3fSmrg } 9434a49301eSmrg 94401e04c3fSmrg if (height < 0) { 94501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(height = %d)", caller, height); 94601e04c3fSmrg return true; 9474a49301eSmrg } 9484a49301eSmrg 94901e04c3fSmrg if (depth < 0) { 95001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(depth = %d)", caller, depth); 95101e04c3fSmrg return true; 9524a49301eSmrg } 9534a49301eSmrg 95401e04c3fSmrg /* do special per-target checks */ 95501e04c3fSmrg switch (target) { 95601e04c3fSmrg case GL_TEXTURE_1D: 95701e04c3fSmrg if (yoffset != 0) { 95801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 95901e04c3fSmrg "%s(1D, yoffset = %d)", caller, yoffset); 96001e04c3fSmrg return true; 96101e04c3fSmrg } 96201e04c3fSmrg if (height != 1) { 96301e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 96401e04c3fSmrg "%s(1D, height = %d)", caller, height); 96501e04c3fSmrg return true; 96601e04c3fSmrg } 9677ec681f3Smrg FALLTHROUGH; 96801e04c3fSmrg case GL_TEXTURE_1D_ARRAY: 96901e04c3fSmrg case GL_TEXTURE_2D: 97001e04c3fSmrg case GL_TEXTURE_RECTANGLE: 97101e04c3fSmrg if (zoffset != 0) { 97201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 97301e04c3fSmrg "%s(zoffset = %d)", caller, zoffset); 97401e04c3fSmrg return true; 97501e04c3fSmrg } 97601e04c3fSmrg if (depth != 1) { 97701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 97801e04c3fSmrg "%s(depth = %d)", caller, depth); 97901e04c3fSmrg return true; 98001e04c3fSmrg } 98101e04c3fSmrg break; 98201e04c3fSmrg case GL_TEXTURE_CUBE_MAP: 98301e04c3fSmrg /* Non-array cube maps are special because we have a gl_texture_image 98401e04c3fSmrg * per face. 98501e04c3fSmrg */ 98601e04c3fSmrg if (zoffset + depth > 6) { 98701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 98801e04c3fSmrg "%s(zoffset + depth = %d)", caller, zoffset + depth); 98901e04c3fSmrg return true; 99001e04c3fSmrg } 99101e04c3fSmrg break; 99201e04c3fSmrg default: 99301e04c3fSmrg ; /* nothing */ 9944a49301eSmrg } 99501e04c3fSmrg 99601e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 99701e04c3fSmrg if (texImage) { 99801e04c3fSmrg imageWidth = texImage->Width; 99901e04c3fSmrg imageHeight = texImage->Height; 100001e04c3fSmrg imageDepth = texImage->Depth; 10014a49301eSmrg } 100201e04c3fSmrg 100301e04c3fSmrg if (xoffset + width > imageWidth) { 100401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 100501e04c3fSmrg "%s(xoffset %d + width %d > %u)", 100601e04c3fSmrg caller, xoffset, width, imageWidth); 100701e04c3fSmrg return true; 1008af69d88dSmrg } 100901e04c3fSmrg 101001e04c3fSmrg if (yoffset + height > imageHeight) { 101101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 101201e04c3fSmrg "%s(yoffset %d + height %d > %u)", 101301e04c3fSmrg caller, yoffset, height, imageHeight); 101401e04c3fSmrg return true; 10154a49301eSmrg } 101601e04c3fSmrg 101701e04c3fSmrg if (target != GL_TEXTURE_CUBE_MAP) { 101801e04c3fSmrg /* Cube map error checking was done above */ 101901e04c3fSmrg if (zoffset + depth > imageDepth) { 102001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 102101e04c3fSmrg "%s(zoffset %d + depth %d > %u)", 102201e04c3fSmrg caller, zoffset, depth, imageDepth); 102301e04c3fSmrg return true; 102401e04c3fSmrg } 10254a49301eSmrg } 102601e04c3fSmrg 102701e04c3fSmrg /* Extra checks for compressed textures */ 102801e04c3fSmrg if (texImage) { 102901e04c3fSmrg GLuint bw, bh, bd; 103001e04c3fSmrg _mesa_get_format_block_size_3d(texImage->TexFormat, &bw, &bh, &bd); 103101e04c3fSmrg if (bw > 1 || bh > 1 || bd > 1) { 103201e04c3fSmrg /* offset must be multiple of block size */ 103301e04c3fSmrg if (xoffset % bw != 0) { 103401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 103501e04c3fSmrg "%s(xoffset = %d)", caller, xoffset); 103601e04c3fSmrg return true; 103701e04c3fSmrg } 103801e04c3fSmrg if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) { 103901e04c3fSmrg if (yoffset % bh != 0) { 104001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 104101e04c3fSmrg "%s(yoffset = %d)", caller, yoffset); 104201e04c3fSmrg return true; 104301e04c3fSmrg } 104401e04c3fSmrg } 104501e04c3fSmrg 104601e04c3fSmrg if (zoffset % bd != 0) { 104701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 104801e04c3fSmrg "%s(zoffset = %d)", caller, zoffset); 104901e04c3fSmrg return true; 105001e04c3fSmrg } 105101e04c3fSmrg 105201e04c3fSmrg /* The size must be a multiple of bw x bh x bd, or we must be using a 105301e04c3fSmrg * offset+size that exactly hits the edge of the image. 105401e04c3fSmrg */ 105501e04c3fSmrg if ((width % bw != 0) && 105601e04c3fSmrg (xoffset + width != (GLint) texImage->Width)) { 105701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 105801e04c3fSmrg "%s(width = %d)", caller, width); 105901e04c3fSmrg return true; 106001e04c3fSmrg } 106101e04c3fSmrg 106201e04c3fSmrg if ((height % bh != 0) && 106301e04c3fSmrg (yoffset + height != (GLint) texImage->Height)) { 106401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 106501e04c3fSmrg "%s(height = %d)", caller, height); 106601e04c3fSmrg return true; 106701e04c3fSmrg } 106801e04c3fSmrg 106901e04c3fSmrg if ((depth % bd != 0) && 107001e04c3fSmrg (zoffset + depth != (GLint) texImage->Depth)) { 107101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 107201e04c3fSmrg "%s(depth = %d)", caller, depth); 107301e04c3fSmrg return true; 107401e04c3fSmrg } 107501e04c3fSmrg } 107601e04c3fSmrg } 107701e04c3fSmrg 107801e04c3fSmrg if (width == 0 || height == 0 || depth == 0) { 107901e04c3fSmrg /* Not an error, but nothing to do. Return 'true' so that the 108001e04c3fSmrg * caller simply returns. 108101e04c3fSmrg */ 108201e04c3fSmrg return true; 10834a49301eSmrg } 10844a49301eSmrg 108501e04c3fSmrg return false; 108601e04c3fSmrg} 108701e04c3fSmrg 108801e04c3fSmrg 108901e04c3fSmrg/** 109001e04c3fSmrg * Do PBO-related error checking for getting uncompressed images. 109101e04c3fSmrg * \return true if there was an error (or the GetTexImage is to be a no-op) 109201e04c3fSmrg */ 109301e04c3fSmrgstatic bool 109401e04c3fSmrgpbo_error_check(struct gl_context *ctx, GLenum target, 109501e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 109601e04c3fSmrg GLenum format, GLenum type, GLsizei clientMemSize, 109701e04c3fSmrg GLvoid *pixels, 109801e04c3fSmrg const char *caller) 109901e04c3fSmrg{ 110001e04c3fSmrg const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; 110101e04c3fSmrg 110201e04c3fSmrg if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, width, height, depth, 11033464ebd5Sriastradh format, type, clientMemSize, pixels)) { 11047ec681f3Smrg if (ctx->Pack.BufferObj) { 11054a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 110601e04c3fSmrg "%s(out of bounds PBO access)", caller); 11073464ebd5Sriastradh } else { 11083464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 110901e04c3fSmrg "%s(out of bounds access: bufSize (%d) is too small)", 111001e04c3fSmrg caller, clientMemSize); 11114a49301eSmrg } 111201e04c3fSmrg return true; 11133464ebd5Sriastradh } 11144a49301eSmrg 11157ec681f3Smrg if (ctx->Pack.BufferObj) { 11164a49301eSmrg /* PBO should not be mapped */ 1117af69d88dSmrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 11184a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 111901e04c3fSmrg "%s(PBO is mapped)", caller); 112001e04c3fSmrg return true; 11214a49301eSmrg } 11224a49301eSmrg } 11234a49301eSmrg 11247ec681f3Smrg if (!ctx->Pack.BufferObj && !pixels) { 112501e04c3fSmrg /* not an error, do nothing */ 112601e04c3fSmrg return true; 112701e04c3fSmrg } 11284a49301eSmrg 112901e04c3fSmrg return false; 113001e04c3fSmrg} 11314a49301eSmrg 11324a49301eSmrg 11334a49301eSmrg/** 113401e04c3fSmrg * Do teximage-related error checking for getting uncompressed images. 113501e04c3fSmrg * \return true if there was an error 11364a49301eSmrg */ 113701e04c3fSmrgstatic bool 113801e04c3fSmrgteximage_error_check(struct gl_context *ctx, 113901e04c3fSmrg struct gl_texture_image *texImage, 114001e04c3fSmrg GLenum format, const char *caller) 11414a49301eSmrg{ 114201e04c3fSmrg GLenum baseFormat; 114301e04c3fSmrg assert(texImage); 1144af69d88dSmrg 114501e04c3fSmrg /* 114601e04c3fSmrg * Format and type checking has been moved up to GetnTexImage and 114701e04c3fSmrg * GetTextureImage so that it happens before getting the texImage object. 114801e04c3fSmrg */ 11494a49301eSmrg 115001e04c3fSmrg baseFormat = _mesa_get_format_base_format(texImage->TexFormat); 11514a49301eSmrg 115201e04c3fSmrg /* Make sure the requested image format is compatible with the 115301e04c3fSmrg * texture's format. 115401e04c3fSmrg */ 115501e04c3fSmrg if (_mesa_is_color_format(format) 115601e04c3fSmrg && !_mesa_is_color_format(baseFormat)) { 115701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 115801e04c3fSmrg "%s(format mismatch)", caller); 115901e04c3fSmrg return true; 11604a49301eSmrg } 116101e04c3fSmrg else if (_mesa_is_depth_format(format) 116201e04c3fSmrg && !_mesa_is_depth_format(baseFormat) 116301e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat)) { 116401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 116501e04c3fSmrg "%s(format mismatch)", caller); 116601e04c3fSmrg return true; 11674a49301eSmrg } 116801e04c3fSmrg else if (_mesa_is_stencil_format(format) 116901e04c3fSmrg && !ctx->Extensions.ARB_texture_stencil8) { 117001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 117101e04c3fSmrg "%s(format=GL_STENCIL_INDEX)", caller); 117201e04c3fSmrg return true; 11734a49301eSmrg } 117401e04c3fSmrg else if (_mesa_is_stencil_format(format) 117501e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat) 117601e04c3fSmrg && !_mesa_is_stencil_format(baseFormat)) { 117701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 117801e04c3fSmrg "%s(format mismatch)", caller); 117901e04c3fSmrg return true; 118001e04c3fSmrg } 118101e04c3fSmrg else if (_mesa_is_ycbcr_format(format) 118201e04c3fSmrg && !_mesa_is_ycbcr_format(baseFormat)) { 118301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 118401e04c3fSmrg "%s(format mismatch)", caller); 118501e04c3fSmrg return true; 118601e04c3fSmrg } 118701e04c3fSmrg else if (_mesa_is_depthstencil_format(format) 118801e04c3fSmrg && !_mesa_is_depthstencil_format(baseFormat)) { 118901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 119001e04c3fSmrg "%s(format mismatch)", caller); 119101e04c3fSmrg return true; 119201e04c3fSmrg } 119301e04c3fSmrg else if (!_mesa_is_stencil_format(format) && 119401e04c3fSmrg _mesa_is_enum_format_integer(format) != 119501e04c3fSmrg _mesa_is_format_integer(texImage->TexFormat)) { 119601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 119701e04c3fSmrg "%s(format mismatch)", caller); 119801e04c3fSmrg return true; 119901e04c3fSmrg } 120001e04c3fSmrg 120101e04c3fSmrg return false; 12024a49301eSmrg} 12034a49301eSmrg 12044a49301eSmrg 120501e04c3fSmrg/** 120601e04c3fSmrg * Do common teximage-related error checking for getting uncompressed images. 120701e04c3fSmrg * \return true if there was an error 120801e04c3fSmrg */ 120901e04c3fSmrgstatic bool 121001e04c3fSmrgcommon_error_check(struct gl_context *ctx, 121101e04c3fSmrg struct gl_texture_object *texObj, 121201e04c3fSmrg GLenum target, GLint level, 121301e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 121401e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 121501e04c3fSmrg GLvoid *pixels, const char *caller) 12163464ebd5Sriastradh{ 121701e04c3fSmrg GLenum err; 121801e04c3fSmrg GLint maxLevels; 121901e04c3fSmrg 122001e04c3fSmrg if (texObj->Target == 0) { 122101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); 122201e04c3fSmrg return true; 122301e04c3fSmrg } 122401e04c3fSmrg 122501e04c3fSmrg maxLevels = _mesa_max_texture_levels(ctx, target); 122601e04c3fSmrg if (level < 0 || level >= maxLevels) { 122701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level = %d)", caller, level); 122801e04c3fSmrg return true; 122901e04c3fSmrg } 123001e04c3fSmrg 123101e04c3fSmrg err = _mesa_error_check_format_and_type(ctx, format, type); 123201e04c3fSmrg if (err != GL_NO_ERROR) { 123301e04c3fSmrg _mesa_error(ctx, err, "%s(format/type)", caller); 123401e04c3fSmrg return true; 123501e04c3fSmrg } 123601e04c3fSmrg 123701e04c3fSmrg /* According to OpenGL 4.6 spec, section 8.11.4 ("Texture Image Queries"): 123801e04c3fSmrg * 123901e04c3fSmrg * "An INVALID_OPERATION error is generated by GetTextureImage if the 124001e04c3fSmrg * effective target is TEXTURE_CUBE_MAP or TEXTURE_CUBE_MAP_ARRAY , 124101e04c3fSmrg * and the texture object is not cube complete or cube array complete, 124201e04c3fSmrg * respectively." 124301e04c3fSmrg * 124401e04c3fSmrg * This applies also to GetTextureSubImage, GetCompressedTexImage, 124501e04c3fSmrg * GetCompressedTextureImage, and GetnCompressedTexImage. 124601e04c3fSmrg */ 124701e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP && !_mesa_cube_complete(texObj)) { 124801e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 124901e04c3fSmrg "%s(cube incomplete)", caller); 125001e04c3fSmrg return true; 125101e04c3fSmrg } 125201e04c3fSmrg 125301e04c3fSmrg return false; 12543464ebd5Sriastradh} 12553464ebd5Sriastradh 12564a49301eSmrg 12574a49301eSmrg/** 125801e04c3fSmrg * Do error checking for all (non-compressed) get-texture-image functions. 125901e04c3fSmrg * \return true if any error, false if no errors. 12604a49301eSmrg */ 126101e04c3fSmrgstatic bool 126201e04c3fSmrggetteximage_error_check(struct gl_context *ctx, 126301e04c3fSmrg struct gl_texture_object *texObj, 126401e04c3fSmrg GLenum target, GLint level, 126501e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 126601e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 126701e04c3fSmrg GLvoid *pixels, const char *caller) 12684a49301eSmrg{ 12694a49301eSmrg struct gl_texture_image *texImage; 12704a49301eSmrg 127101e04c3fSmrg assert(texObj); 127201e04c3fSmrg 127301e04c3fSmrg if (common_error_check(ctx, texObj, target, level, width, height, depth, 127401e04c3fSmrg format, type, bufSize, pixels, caller)) { 127501e04c3fSmrg return true; 12764a49301eSmrg } 12774a49301eSmrg 127801e04c3fSmrg if (width == 0 || height == 0 || depth == 0) { 127901e04c3fSmrg /* Not an error, but nothing to do. Return 'true' so that the 128001e04c3fSmrg * caller simply returns. 128101e04c3fSmrg */ 128201e04c3fSmrg return true; 128301e04c3fSmrg } 128401e04c3fSmrg 128501e04c3fSmrg if (pbo_error_check(ctx, target, width, height, depth, 128601e04c3fSmrg format, type, bufSize, pixels, caller)) { 128701e04c3fSmrg return true; 128801e04c3fSmrg } 128901e04c3fSmrg 129001e04c3fSmrg texImage = select_tex_image(texObj, target, level, 0); 129101e04c3fSmrg if (teximage_error_check(ctx, texImage, format, caller)) { 129201e04c3fSmrg return true; 129301e04c3fSmrg } 129401e04c3fSmrg 129501e04c3fSmrg return false; 129601e04c3fSmrg} 129701e04c3fSmrg 129801e04c3fSmrg 129901e04c3fSmrg/** 130001e04c3fSmrg * Do error checking for all (non-compressed) get-texture-image functions. 130101e04c3fSmrg * \return true if any error, false if no errors. 130201e04c3fSmrg */ 130301e04c3fSmrgstatic bool 130401e04c3fSmrggettexsubimage_error_check(struct gl_context *ctx, 130501e04c3fSmrg struct gl_texture_object *texObj, 130601e04c3fSmrg GLenum target, GLint level, 130701e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 130801e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 130901e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 131001e04c3fSmrg GLvoid *pixels, const char *caller) 131101e04c3fSmrg{ 131201e04c3fSmrg struct gl_texture_image *texImage; 131301e04c3fSmrg 131401e04c3fSmrg assert(texObj); 131501e04c3fSmrg 131601e04c3fSmrg if (common_error_check(ctx, texObj, target, level, width, height, depth, 131701e04c3fSmrg format, type, bufSize, pixels, caller)) { 131801e04c3fSmrg return true; 131901e04c3fSmrg } 132001e04c3fSmrg 132101e04c3fSmrg if (dimensions_error_check(ctx, texObj, target, level, 132201e04c3fSmrg xoffset, yoffset, zoffset, 132301e04c3fSmrg width, height, depth, caller)) { 132401e04c3fSmrg return true; 132501e04c3fSmrg } 132601e04c3fSmrg 132701e04c3fSmrg if (pbo_error_check(ctx, target, width, height, depth, 132801e04c3fSmrg format, type, bufSize, pixels, caller)) { 132901e04c3fSmrg return true; 133001e04c3fSmrg } 133101e04c3fSmrg 133201e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 133301e04c3fSmrg if (teximage_error_check(ctx, texImage, format, caller)) { 133401e04c3fSmrg return true; 133501e04c3fSmrg } 133601e04c3fSmrg 133701e04c3fSmrg return false; 133801e04c3fSmrg} 133901e04c3fSmrg 134001e04c3fSmrg 134101e04c3fSmrg/** 134201e04c3fSmrg * Return the width, height and depth of a texture image. 134301e04c3fSmrg * This function must be resilient to bad parameter values since 134401e04c3fSmrg * this is called before full error checking. 134501e04c3fSmrg */ 134601e04c3fSmrgstatic void 134701e04c3fSmrgget_texture_image_dims(const struct gl_texture_object *texObj, 134801e04c3fSmrg GLenum target, GLint level, 134901e04c3fSmrg GLsizei *width, GLsizei *height, GLsizei *depth) 135001e04c3fSmrg{ 135101e04c3fSmrg const struct gl_texture_image *texImage = NULL; 135201e04c3fSmrg 135301e04c3fSmrg if (level >= 0 && level < MAX_TEXTURE_LEVELS) { 135401e04c3fSmrg texImage = _mesa_select_tex_image(texObj, target, level); 135501e04c3fSmrg } 135601e04c3fSmrg 135701e04c3fSmrg if (texImage) { 135801e04c3fSmrg *width = texImage->Width; 135901e04c3fSmrg *height = texImage->Height; 136001e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 136101e04c3fSmrg *depth = 6; 136201e04c3fSmrg } 136301e04c3fSmrg else { 136401e04c3fSmrg *depth = texImage->Depth; 136501e04c3fSmrg } 136601e04c3fSmrg } 136701e04c3fSmrg else { 136801e04c3fSmrg *width = *height = *depth = 0; 136901e04c3fSmrg } 137001e04c3fSmrg} 137101e04c3fSmrg 137201e04c3fSmrg 137301e04c3fSmrg/** 137401e04c3fSmrg * Common code for all (uncompressed) get-texture-image functions. 137501e04c3fSmrg * \param texObj the texture object (should not be null) 137601e04c3fSmrg * \param target user-provided target, or 0 for DSA 137701e04c3fSmrg * \param level image level. 137801e04c3fSmrg * \param format pixel data format for returned image. 137901e04c3fSmrg * \param type pixel data type for returned image. 138001e04c3fSmrg * \param bufSize size of the pixels data buffer. 138101e04c3fSmrg * \param pixels returned pixel data. 138201e04c3fSmrg * \param caller name of calling function 138301e04c3fSmrg */ 138401e04c3fSmrgstatic void 138501e04c3fSmrgget_texture_image(struct gl_context *ctx, 138601e04c3fSmrg struct gl_texture_object *texObj, 138701e04c3fSmrg GLenum target, GLint level, 138801e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 138901e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 139001e04c3fSmrg GLenum format, GLenum type, 139101e04c3fSmrg GLvoid *pixels, const char *caller) 139201e04c3fSmrg{ 139301e04c3fSmrg struct gl_texture_image *texImage; 139401e04c3fSmrg unsigned firstFace, numFaces, i; 139501e04c3fSmrg GLint imageStride; 139601e04c3fSmrg 13977ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 139801e04c3fSmrg 139901e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 140001e04c3fSmrg assert(texImage); /* should have been error checked already */ 140101e04c3fSmrg 140201e04c3fSmrg if (_mesa_is_zero_size_texture(texImage)) { 140301e04c3fSmrg /* no image data to return */ 140401e04c3fSmrg return; 140501e04c3fSmrg } 140601e04c3fSmrg 140701e04c3fSmrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 140801e04c3fSmrg _mesa_debug(ctx, "%s(tex %u) format = %s, w=%d, h=%d," 140901e04c3fSmrg " dstFmt=0x%x, dstType=0x%x\n", 141001e04c3fSmrg caller, texObj->Name, 141101e04c3fSmrg _mesa_get_format_name(texImage->TexFormat), 141201e04c3fSmrg texImage->Width, texImage->Height, 141301e04c3fSmrg format, type); 141401e04c3fSmrg } 141501e04c3fSmrg 141601e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 141701e04c3fSmrg /* Compute stride between cube faces */ 141801e04c3fSmrg imageStride = _mesa_image_image_stride(&ctx->Pack, width, height, 141901e04c3fSmrg format, type); 142001e04c3fSmrg firstFace = zoffset; 142101e04c3fSmrg numFaces = depth; 142201e04c3fSmrg zoffset = 0; 142301e04c3fSmrg depth = 1; 142401e04c3fSmrg } 142501e04c3fSmrg else { 142601e04c3fSmrg imageStride = 0; 142701e04c3fSmrg firstFace = _mesa_tex_target_to_face(target); 142801e04c3fSmrg numFaces = 1; 142901e04c3fSmrg } 143001e04c3fSmrg 143101e04c3fSmrg _mesa_lock_texture(ctx, texObj); 143201e04c3fSmrg 143301e04c3fSmrg for (i = 0; i < numFaces; i++) { 143401e04c3fSmrg texImage = texObj->Image[firstFace + i][level]; 143501e04c3fSmrg assert(texImage); 143601e04c3fSmrg 143701e04c3fSmrg ctx->Driver.GetTexSubImage(ctx, xoffset, yoffset, zoffset, 143801e04c3fSmrg width, height, depth, 143901e04c3fSmrg format, type, pixels, texImage); 144001e04c3fSmrg 144101e04c3fSmrg /* next cube face */ 144201e04c3fSmrg pixels = (GLubyte *) pixels + imageStride; 144301e04c3fSmrg } 144401e04c3fSmrg 144501e04c3fSmrg _mesa_unlock_texture(ctx, texObj); 144601e04c3fSmrg} 144701e04c3fSmrg 14487ec681f3Smrgstatic void 14497ec681f3Smrg_get_texture_image(struct gl_context *ctx, 14507ec681f3Smrg struct gl_texture_object *texObj, 14517ec681f3Smrg GLenum target, GLint level, 14527ec681f3Smrg GLenum format, GLenum type, 14537ec681f3Smrg GLsizei bufSize, GLvoid *pixels, 14547ec681f3Smrg const char *caller) 145501e04c3fSmrg{ 145601e04c3fSmrg GLsizei width, height, depth; 14577ec681f3Smrg /* EXT/ARB direct_state_access variants don't call _get_texture_image 14587ec681f3Smrg * with a NULL texObj */ 14597ec681f3Smrg bool is_dsa = texObj != NULL; 146001e04c3fSmrg 14617ec681f3Smrg if (!is_dsa) { 14627ec681f3Smrg texObj = _mesa_get_current_tex_object(ctx, target); 14637ec681f3Smrg assert(texObj); 146401e04c3fSmrg } 146501e04c3fSmrg 146601e04c3fSmrg 146701e04c3fSmrg get_texture_image_dims(texObj, target, level, &width, &height, &depth); 146801e04c3fSmrg 146901e04c3fSmrg if (getteximage_error_check(ctx, texObj, target, level, 147001e04c3fSmrg width, height, depth, 147101e04c3fSmrg format, type, bufSize, pixels, caller)) { 147201e04c3fSmrg return; 147301e04c3fSmrg } 147401e04c3fSmrg 147501e04c3fSmrg get_texture_image(ctx, texObj, target, level, 147601e04c3fSmrg 0, 0, 0, width, height, depth, 147701e04c3fSmrg format, type, pixels, caller); 147801e04c3fSmrg} 147901e04c3fSmrg 148001e04c3fSmrg 148101e04c3fSmrgvoid GLAPIENTRY 14827ec681f3Smrg_mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format, GLenum type, 14837ec681f3Smrg GLsizei bufSize, GLvoid *pixels) 148401e04c3fSmrg{ 148501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 14867ec681f3Smrg static const char *caller = "glGetnTexImageARB"; 148701e04c3fSmrg 148801e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 148901e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 149001e04c3fSmrg return; 14914a49301eSmrg } 14924a49301eSmrg 14937ec681f3Smrg _get_texture_image(ctx, NULL, target, level, format, type, 14947ec681f3Smrg bufSize, pixels, caller); 14957ec681f3Smrg} 149601e04c3fSmrg 149701e04c3fSmrg 14987ec681f3Smrgvoid GLAPIENTRY 14997ec681f3Smrg_mesa_GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, 15007ec681f3Smrg GLvoid *pixels ) 15017ec681f3Smrg{ 15027ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 15037ec681f3Smrg static const char *caller = "glGetTexImage"; 15047ec681f3Smrg 15057ec681f3Smrg if (!legal_getteximage_target(ctx, target, false)) { 15067ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 150701e04c3fSmrg return; 150801e04c3fSmrg } 150901e04c3fSmrg 15107ec681f3Smrg _get_texture_image(ctx, NULL, target, level, format, type, 15117ec681f3Smrg INT_MAX, pixels, caller); 151201e04c3fSmrg} 151301e04c3fSmrg 151401e04c3fSmrg 151501e04c3fSmrgvoid GLAPIENTRY 151601e04c3fSmrg_mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, 151701e04c3fSmrg GLsizei bufSize, GLvoid *pixels) 151801e04c3fSmrg{ 151901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 152001e04c3fSmrg static const char *caller = "glGetTextureImage"; 152101e04c3fSmrg struct gl_texture_object *texObj = 152201e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 152301e04c3fSmrg 15244a49301eSmrg if (!texObj) { 152501e04c3fSmrg return; 152601e04c3fSmrg } 152701e04c3fSmrg 152801e04c3fSmrg if (!legal_getteximage_target(ctx, texObj->Target, true)) { 152901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 153001e04c3fSmrg return; 15314a49301eSmrg } 15324a49301eSmrg 15337ec681f3Smrg _get_texture_image(ctx, texObj, texObj->Target, level, format, type, 15347ec681f3Smrg bufSize, pixels, caller); 15357ec681f3Smrg} 15367ec681f3Smrg 15377ec681f3Smrg 15387ec681f3Smrgvoid GLAPIENTRY 15397ec681f3Smrg_mesa_GetTextureImageEXT(GLuint texture, GLenum target, GLint level, 15407ec681f3Smrg GLenum format, GLenum type, GLvoid *pixels) 15417ec681f3Smrg{ 15427ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 15437ec681f3Smrg static const char *caller = "glGetTextureImageEXT"; 15447ec681f3Smrg struct gl_texture_object *texObj = 15457ec681f3Smrg _mesa_lookup_or_create_texture(ctx, target, texture, 15467ec681f3Smrg false, true, caller); 15477ec681f3Smrg 15487ec681f3Smrg if (!texObj) { 15497ec681f3Smrg return; 15507ec681f3Smrg } 15517ec681f3Smrg 15527ec681f3Smrg if (!legal_getteximage_target(ctx, target, true)) { 15537ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 15547ec681f3Smrg return; 15557ec681f3Smrg } 15567ec681f3Smrg 15577ec681f3Smrg _get_texture_image(ctx, texObj, target, level, format, type, 15587ec681f3Smrg INT_MAX, pixels, caller); 15597ec681f3Smrg} 15607ec681f3Smrg 15617ec681f3Smrg 15627ec681f3Smrgvoid GLAPIENTRY 15637ec681f3Smrg_mesa_GetMultiTexImageEXT(GLenum texunit, GLenum target, GLint level, 15647ec681f3Smrg GLenum format, GLenum type, GLvoid *pixels) 15657ec681f3Smrg{ 15667ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 15677ec681f3Smrg GLsizei width, height, depth; 15687ec681f3Smrg static const char *caller = "glGetMultiTexImageEXT"; 15697ec681f3Smrg 15707ec681f3Smrg struct gl_texture_object *texObj = 15717ec681f3Smrg _mesa_get_texobj_by_target_and_texunit(ctx, target, 15727ec681f3Smrg texunit - GL_TEXTURE0, 15737ec681f3Smrg false, 15747ec681f3Smrg caller); 15757ec681f3Smrg 15767ec681f3Smrg if (!texObj) { 15777ec681f3Smrg return; 15787ec681f3Smrg } 15797ec681f3Smrg 15807ec681f3Smrg if (!legal_getteximage_target(ctx, texObj->Target, true)) { 15817ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 15827ec681f3Smrg return; 15837ec681f3Smrg } 15847ec681f3Smrg 158501e04c3fSmrg get_texture_image_dims(texObj, texObj->Target, level, 158601e04c3fSmrg &width, &height, &depth); 158701e04c3fSmrg 158801e04c3fSmrg if (getteximage_error_check(ctx, texObj, texObj->Target, level, 158901e04c3fSmrg width, height, depth, 15907ec681f3Smrg format, type, INT_MAX, pixels, caller)) { 159101e04c3fSmrg return; 159201e04c3fSmrg } 159301e04c3fSmrg 159401e04c3fSmrg get_texture_image(ctx, texObj, texObj->Target, level, 159501e04c3fSmrg 0, 0, 0, width, height, depth, 159601e04c3fSmrg format, type, pixels, caller); 159701e04c3fSmrg} 159801e04c3fSmrg 159901e04c3fSmrg 160001e04c3fSmrgvoid GLAPIENTRY 160101e04c3fSmrg_mesa_GetTextureSubImage(GLuint texture, GLint level, 160201e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 160301e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 160401e04c3fSmrg GLenum format, GLenum type, GLsizei bufSize, 160501e04c3fSmrg void *pixels) 160601e04c3fSmrg{ 160701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 160801e04c3fSmrg static const char *caller = "glGetTextureSubImage"; 160901e04c3fSmrg struct gl_texture_object *texObj = 161001e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 16114a49301eSmrg 161201e04c3fSmrg if (!texObj) { 161301e04c3fSmrg return; 161401e04c3fSmrg } 161501e04c3fSmrg 161601e04c3fSmrg if (!legal_getteximage_target(ctx, texObj->Target, true)) { 161701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 161801e04c3fSmrg "%s(buffer/multisample texture)", caller); 161901e04c3fSmrg return; 162001e04c3fSmrg } 162101e04c3fSmrg 162201e04c3fSmrg if (gettexsubimage_error_check(ctx, texObj, texObj->Target, level, 162301e04c3fSmrg xoffset, yoffset, zoffset, 162401e04c3fSmrg width, height, depth, 162501e04c3fSmrg format, type, bufSize, pixels, caller)) { 162601e04c3fSmrg return; 162701e04c3fSmrg } 162801e04c3fSmrg 162901e04c3fSmrg get_texture_image(ctx, texObj, texObj->Target, level, 163001e04c3fSmrg xoffset, yoffset, zoffset, width, height, depth, 163101e04c3fSmrg format, type, pixels, caller); 163201e04c3fSmrg} 163301e04c3fSmrg 163401e04c3fSmrg 163501e04c3fSmrg 163601e04c3fSmrg/** 163701e04c3fSmrg * Compute the number of bytes which will be written when retrieving 163801e04c3fSmrg * a sub-region of a compressed texture. 163901e04c3fSmrg */ 164001e04c3fSmrgstatic GLsizei 164101e04c3fSmrgpacked_compressed_size(GLuint dimensions, mesa_format format, 164201e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 164301e04c3fSmrg const struct gl_pixelstore_attrib *packing) 164401e04c3fSmrg{ 164501e04c3fSmrg struct compressed_pixelstore st; 164601e04c3fSmrg GLsizei totalBytes; 164701e04c3fSmrg 164801e04c3fSmrg _mesa_compute_compressed_pixelstore(dimensions, format, 164901e04c3fSmrg width, height, depth, 165001e04c3fSmrg packing, &st); 165101e04c3fSmrg totalBytes = 165201e04c3fSmrg (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow + 165301e04c3fSmrg st.SkipBytes + 165401e04c3fSmrg (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow + 165501e04c3fSmrg st.CopyBytesPerRow; 165601e04c3fSmrg 165701e04c3fSmrg return totalBytes; 165801e04c3fSmrg} 165901e04c3fSmrg 166001e04c3fSmrg 166101e04c3fSmrg/** 166201e04c3fSmrg * Do error checking for getting compressed texture images. 166301e04c3fSmrg * \return true if any error, false if no errors. 166401e04c3fSmrg */ 166501e04c3fSmrgstatic bool 166601e04c3fSmrggetcompressedteximage_error_check(struct gl_context *ctx, 166701e04c3fSmrg struct gl_texture_object *texObj, 166801e04c3fSmrg GLenum target, GLint level, 166901e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 167001e04c3fSmrg GLsizei width, GLsizei height, GLsizei depth, 167101e04c3fSmrg GLsizei bufSize, GLvoid *pixels, 167201e04c3fSmrg const char *caller) 167301e04c3fSmrg{ 167401e04c3fSmrg struct gl_texture_image *texImage; 167501e04c3fSmrg GLint maxLevels; 167601e04c3fSmrg GLsizei totalBytes; 167701e04c3fSmrg GLuint dimensions; 167801e04c3fSmrg 167901e04c3fSmrg assert(texObj); 168001e04c3fSmrg 168101e04c3fSmrg if (texObj->Target == 0) { 168201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller); 168301e04c3fSmrg return true; 168401e04c3fSmrg } 168501e04c3fSmrg 168601e04c3fSmrg maxLevels = _mesa_max_texture_levels(ctx, target); 168701e04c3fSmrg if (level < 0 || level >= maxLevels) { 16884a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 168901e04c3fSmrg "%s(bad level = %d)", caller, level); 169001e04c3fSmrg return true; 16914a49301eSmrg } 16924a49301eSmrg 169301e04c3fSmrg if (dimensions_error_check(ctx, texObj, target, level, 169401e04c3fSmrg xoffset, yoffset, zoffset, 169501e04c3fSmrg width, height, depth, caller)) { 169601e04c3fSmrg return true; 169701e04c3fSmrg } 169801e04c3fSmrg 169901e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 170001e04c3fSmrg assert(texImage); 170101e04c3fSmrg 17024a49301eSmrg if (!_mesa_is_format_compressed(texImage->TexFormat)) { 17034a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 170401e04c3fSmrg "%s(texture is not compressed)", caller); 170501e04c3fSmrg return true; 17064a49301eSmrg } 17074a49301eSmrg 1708af69d88dSmrg /* Check for invalid pixel storage modes */ 170901e04c3fSmrg dimensions = _mesa_get_texture_dimensions(texObj->Target); 1710af69d88dSmrg if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions, 171101e04c3fSmrg &ctx->Pack, 171201e04c3fSmrg caller)) { 171301e04c3fSmrg return true; 1714af69d88dSmrg } 1715af69d88dSmrg 171601e04c3fSmrg /* Compute number of bytes that may be touched in the dest buffer */ 171701e04c3fSmrg totalBytes = packed_compressed_size(dimensions, texImage->TexFormat, 171801e04c3fSmrg width, height, depth, 171901e04c3fSmrg &ctx->Pack); 172001e04c3fSmrg 172101e04c3fSmrg /* Do dest buffer bounds checking */ 17227ec681f3Smrg if (ctx->Pack.BufferObj) { 17234a49301eSmrg /* do bounds checking on PBO write */ 172401e04c3fSmrg if ((GLubyte *) pixels + totalBytes > 172501e04c3fSmrg (GLubyte *) ctx->Pack.BufferObj->Size) { 17264a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 172701e04c3fSmrg "%s(out of bounds PBO access)", caller); 172801e04c3fSmrg return true; 17293464ebd5Sriastradh } 17303464ebd5Sriastradh 17313464ebd5Sriastradh /* make sure PBO is not mapped */ 1732af69d88dSmrg if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 173301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller); 173401e04c3fSmrg return true; 173501e04c3fSmrg } 173601e04c3fSmrg } 173701e04c3fSmrg else { 173801e04c3fSmrg /* do bounds checking on writing to client memory */ 173901e04c3fSmrg if (totalBytes > bufSize) { 17403464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 174101e04c3fSmrg "%s(out of bounds access: bufSize (%d) is too small)", 174201e04c3fSmrg caller, bufSize); 174301e04c3fSmrg return true; 17444a49301eSmrg } 17454a49301eSmrg } 17464a49301eSmrg 17477ec681f3Smrg if (!ctx->Pack.BufferObj && !pixels) { 174801e04c3fSmrg /* not an error, but do nothing */ 174901e04c3fSmrg return true; 175001e04c3fSmrg } 175101e04c3fSmrg 175201e04c3fSmrg return false; 17534a49301eSmrg} 17544a49301eSmrg 17554a49301eSmrg 175601e04c3fSmrg/** 175701e04c3fSmrg * Common helper for all glGetCompressed-teximage functions. 175801e04c3fSmrg */ 175901e04c3fSmrgstatic void 176001e04c3fSmrgget_compressed_texture_image(struct gl_context *ctx, 176101e04c3fSmrg struct gl_texture_object *texObj, 176201e04c3fSmrg GLenum target, GLint level, 176301e04c3fSmrg GLint xoffset, GLint yoffset, GLint zoffset, 176401e04c3fSmrg GLsizei width, GLsizei height, GLint depth, 176501e04c3fSmrg GLvoid *pixels, 176601e04c3fSmrg const char *caller) 17674a49301eSmrg{ 17684a49301eSmrg struct gl_texture_image *texImage; 176901e04c3fSmrg unsigned firstFace, numFaces, i, imageStride; 1770af69d88dSmrg 17717ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 17724a49301eSmrg 177301e04c3fSmrg texImage = select_tex_image(texObj, target, level, zoffset); 177401e04c3fSmrg assert(texImage); /* should have been error checked already */ 17754a49301eSmrg 1776af69d88dSmrg if (_mesa_is_zero_size_texture(texImage)) 1777af69d88dSmrg return; 1778af69d88dSmrg 17794a49301eSmrg if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) { 17804a49301eSmrg _mesa_debug(ctx, 178101e04c3fSmrg "%s(tex %u) format = %s, w=%d, h=%d\n", 178201e04c3fSmrg caller, texObj->Name, 17834a49301eSmrg _mesa_get_format_name(texImage->TexFormat), 17844a49301eSmrg texImage->Width, texImage->Height); 17854a49301eSmrg } 17864a49301eSmrg 178701e04c3fSmrg if (target == GL_TEXTURE_CUBE_MAP) { 178801e04c3fSmrg struct compressed_pixelstore store; 178901e04c3fSmrg 179001e04c3fSmrg /* Compute image stride between cube faces */ 179101e04c3fSmrg _mesa_compute_compressed_pixelstore(2, texImage->TexFormat, 179201e04c3fSmrg width, height, depth, 179301e04c3fSmrg &ctx->Pack, &store); 179401e04c3fSmrg imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice; 179501e04c3fSmrg 179601e04c3fSmrg firstFace = zoffset; 179701e04c3fSmrg numFaces = depth; 179801e04c3fSmrg zoffset = 0; 179901e04c3fSmrg depth = 1; 180001e04c3fSmrg } 180101e04c3fSmrg else { 180201e04c3fSmrg imageStride = 0; 180301e04c3fSmrg firstFace = _mesa_tex_target_to_face(target); 180401e04c3fSmrg numFaces = 1; 180501e04c3fSmrg } 180601e04c3fSmrg 18074a49301eSmrg _mesa_lock_texture(ctx, texObj); 180801e04c3fSmrg 180901e04c3fSmrg for (i = 0; i < numFaces; i++) { 181001e04c3fSmrg texImage = texObj->Image[firstFace + i][level]; 181101e04c3fSmrg assert(texImage); 181201e04c3fSmrg 181301e04c3fSmrg get_compressed_texsubimage_sw(ctx, texImage, 181401e04c3fSmrg xoffset, yoffset, zoffset, 181501e04c3fSmrg width, height, depth, pixels); 181601e04c3fSmrg 181701e04c3fSmrg /* next cube face */ 181801e04c3fSmrg pixels = (GLubyte *) pixels + imageStride; 18194a49301eSmrg } 182001e04c3fSmrg 18214a49301eSmrg _mesa_unlock_texture(ctx, texObj); 18224a49301eSmrg} 18233464ebd5Sriastradh 182401e04c3fSmrg 18253464ebd5Sriastradhvoid GLAPIENTRY 182601e04c3fSmrg_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize, 182701e04c3fSmrg GLvoid *pixels) 18283464ebd5Sriastradh{ 182901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 183001e04c3fSmrg static const char *caller = "glGetnCompressedTexImageARB"; 183101e04c3fSmrg GLsizei width, height, depth; 183201e04c3fSmrg struct gl_texture_object *texObj; 183301e04c3fSmrg 183401e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 183501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 183601e04c3fSmrg return; 183701e04c3fSmrg } 183801e04c3fSmrg 183901e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 184001e04c3fSmrg assert(texObj); 184101e04c3fSmrg 184201e04c3fSmrg get_texture_image_dims(texObj, target, level, &width, &height, &depth); 184301e04c3fSmrg 184401e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, target, level, 184501e04c3fSmrg 0, 0, 0, width, height, depth, 184601e04c3fSmrg INT_MAX, pixels, caller)) { 184701e04c3fSmrg return; 184801e04c3fSmrg } 184901e04c3fSmrg 185001e04c3fSmrg get_compressed_texture_image(ctx, texObj, target, level, 185101e04c3fSmrg 0, 0, 0, width, height, depth, 185201e04c3fSmrg pixels, caller); 185301e04c3fSmrg} 185401e04c3fSmrg 185501e04c3fSmrg 185601e04c3fSmrgvoid GLAPIENTRY 185701e04c3fSmrg_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels) 185801e04c3fSmrg{ 185901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 186001e04c3fSmrg static const char *caller = "glGetCompressedTexImage"; 186101e04c3fSmrg GLsizei width, height, depth; 186201e04c3fSmrg struct gl_texture_object *texObj; 186301e04c3fSmrg 186401e04c3fSmrg if (!legal_getteximage_target(ctx, target, false)) { 186501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller); 186601e04c3fSmrg return; 186701e04c3fSmrg } 186801e04c3fSmrg 186901e04c3fSmrg texObj = _mesa_get_current_tex_object(ctx, target); 187001e04c3fSmrg assert(texObj); 187101e04c3fSmrg 187201e04c3fSmrg get_texture_image_dims(texObj, target, level, 187301e04c3fSmrg &width, &height, &depth); 187401e04c3fSmrg 187501e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, target, level, 187601e04c3fSmrg 0, 0, 0, width, height, depth, 187701e04c3fSmrg INT_MAX, pixels, caller)) { 187801e04c3fSmrg return; 187901e04c3fSmrg } 188001e04c3fSmrg 188101e04c3fSmrg get_compressed_texture_image(ctx, texObj, target, level, 188201e04c3fSmrg 0, 0, 0, width, height, depth, 188301e04c3fSmrg pixels, caller); 188401e04c3fSmrg} 188501e04c3fSmrg 188601e04c3fSmrg 18877ec681f3Smrgvoid GLAPIENTRY 18887ec681f3Smrg_mesa_GetCompressedTextureImageEXT(GLuint texture, GLenum target, GLint level, 18897ec681f3Smrg GLvoid *pixels) 18907ec681f3Smrg{ 18917ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 18927ec681f3Smrg struct gl_texture_object* texObj; 18937ec681f3Smrg GLsizei width, height, depth; 18947ec681f3Smrg static const char *caller = "glGetCompressedTextureImageEXT"; 18957ec681f3Smrg 18967ec681f3Smrg texObj = _mesa_lookup_or_create_texture(ctx, target, texture, 18977ec681f3Smrg false, true, caller); 18987ec681f3Smrg 18997ec681f3Smrg get_texture_image_dims(texObj, texObj->Target, level, 19007ec681f3Smrg &width, &height, &depth); 19017ec681f3Smrg 19027ec681f3Smrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 19037ec681f3Smrg 0, 0, 0, width, height, depth, 19047ec681f3Smrg INT_MAX, pixels, caller)) { 19057ec681f3Smrg return; 19067ec681f3Smrg } 19077ec681f3Smrg 19087ec681f3Smrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 19097ec681f3Smrg 0, 0, 0, width, height, depth, 19107ec681f3Smrg pixels, caller); 19117ec681f3Smrg} 19127ec681f3Smrg 19137ec681f3Smrg 19147ec681f3Smrgvoid GLAPIENTRY 19157ec681f3Smrg_mesa_GetCompressedMultiTexImageEXT(GLenum texunit, GLenum target, GLint level, 19167ec681f3Smrg GLvoid *pixels) 19177ec681f3Smrg{ 19187ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 19197ec681f3Smrg struct gl_texture_object* texObj; 19207ec681f3Smrg GLsizei width, height, depth; 19217ec681f3Smrg static const char *caller = "glGetCompressedMultiTexImageEXT"; 19227ec681f3Smrg 19237ec681f3Smrg texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target, 19247ec681f3Smrg texunit - GL_TEXTURE0, 19257ec681f3Smrg false, 19267ec681f3Smrg caller); 19277ec681f3Smrg 19287ec681f3Smrg get_texture_image_dims(texObj, texObj->Target, level, 19297ec681f3Smrg &width, &height, &depth); 19307ec681f3Smrg 19317ec681f3Smrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 19327ec681f3Smrg 0, 0, 0, width, height, depth, 19337ec681f3Smrg INT_MAX, pixels, caller)) { 19347ec681f3Smrg return; 19357ec681f3Smrg } 19367ec681f3Smrg 19377ec681f3Smrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 19387ec681f3Smrg 0, 0, 0, width, height, depth, 19397ec681f3Smrg pixels, caller); 19407ec681f3Smrg} 19417ec681f3Smrg 19427ec681f3Smrg 194301e04c3fSmrgvoid GLAPIENTRY 194401e04c3fSmrg_mesa_GetCompressedTextureImage(GLuint texture, GLint level, 194501e04c3fSmrg GLsizei bufSize, GLvoid *pixels) 194601e04c3fSmrg{ 194701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 194801e04c3fSmrg static const char *caller = "glGetCompressedTextureImage"; 194901e04c3fSmrg GLsizei width, height, depth; 195001e04c3fSmrg struct gl_texture_object *texObj = 195101e04c3fSmrg _mesa_lookup_texture_err(ctx, texture, caller); 195201e04c3fSmrg 195301e04c3fSmrg if (!texObj) { 195401e04c3fSmrg return; 195501e04c3fSmrg } 195601e04c3fSmrg 195701e04c3fSmrg get_texture_image_dims(texObj, texObj->Target, level, 195801e04c3fSmrg &width, &height, &depth); 195901e04c3fSmrg 196001e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 196101e04c3fSmrg 0, 0, 0, width, height, depth, 196201e04c3fSmrg bufSize, pixels, caller)) { 196301e04c3fSmrg return; 196401e04c3fSmrg } 196501e04c3fSmrg 196601e04c3fSmrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 196701e04c3fSmrg 0, 0, 0, width, height, depth, 196801e04c3fSmrg pixels, caller); 196901e04c3fSmrg} 197001e04c3fSmrg 197101e04c3fSmrg 19727ec681f3Smrgvoid GLAPIENTRY 197301e04c3fSmrg_mesa_GetCompressedTextureSubImage(GLuint texture, GLint level, 197401e04c3fSmrg GLint xoffset, GLint yoffset, 197501e04c3fSmrg GLint zoffset, GLsizei width, 197601e04c3fSmrg GLsizei height, GLsizei depth, 197701e04c3fSmrg GLsizei bufSize, void *pixels) 197801e04c3fSmrg{ 197901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 198001e04c3fSmrg static const char *caller = "glGetCompressedTextureImage"; 198101e04c3fSmrg struct gl_texture_object *texObj = NULL; 198201e04c3fSmrg 198301e04c3fSmrg texObj = _mesa_lookup_texture_err(ctx, texture, caller); 198401e04c3fSmrg if (!texObj) { 198501e04c3fSmrg return; 198601e04c3fSmrg } 198701e04c3fSmrg 198801e04c3fSmrg if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level, 198901e04c3fSmrg xoffset, yoffset, zoffset, 199001e04c3fSmrg width, height, depth, 199101e04c3fSmrg bufSize, pixels, caller)) { 199201e04c3fSmrg return; 199301e04c3fSmrg } 199401e04c3fSmrg 199501e04c3fSmrg get_compressed_texture_image(ctx, texObj, texObj->Target, level, 199601e04c3fSmrg xoffset, yoffset, zoffset, 199701e04c3fSmrg width, height, depth, 199801e04c3fSmrg pixels, caller); 19993464ebd5Sriastradh} 2000