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