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