1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci * Copyright (c) 2009 VMware, Inc.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci/**
28bf215546Sopenharmony_ci * Code for glGetTexImage() and glGetCompressedTexImage().
29bf215546Sopenharmony_ci */
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "glheader.h"
33bf215546Sopenharmony_ci#include "bufferobj.h"
34bf215546Sopenharmony_ci#include "enums.h"
35bf215546Sopenharmony_ci#include "context.h"
36bf215546Sopenharmony_ci#include "formats.h"
37bf215546Sopenharmony_ci#include "format_unpack.h"
38bf215546Sopenharmony_ci#include "glformats.h"
39bf215546Sopenharmony_ci#include "image.h"
40bf215546Sopenharmony_ci#include "mtypes.h"
41bf215546Sopenharmony_ci#include "pack.h"
42bf215546Sopenharmony_ci#include "pbo.h"
43bf215546Sopenharmony_ci#include "pixelstore.h"
44bf215546Sopenharmony_ci#include "texcompress.h"
45bf215546Sopenharmony_ci#include "texgetimage.h"
46bf215546Sopenharmony_ci#include "teximage.h"
47bf215546Sopenharmony_ci#include "texobj.h"
48bf215546Sopenharmony_ci#include "texstore.h"
49bf215546Sopenharmony_ci#include "format_utils.h"
50bf215546Sopenharmony_ci#include "pixeltransfer.h"
51bf215546Sopenharmony_ci#include "api_exec_decl.h"
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci#include "state_tracker/st_cb_texture.h"
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci/**
56bf215546Sopenharmony_ci * Can the given type represent negative values?
57bf215546Sopenharmony_ci */
58bf215546Sopenharmony_cistatic inline GLboolean
59bf215546Sopenharmony_citype_needs_clamping(GLenum type)
60bf215546Sopenharmony_ci{
61bf215546Sopenharmony_ci   switch (type) {
62bf215546Sopenharmony_ci   case GL_BYTE:
63bf215546Sopenharmony_ci   case GL_SHORT:
64bf215546Sopenharmony_ci   case GL_INT:
65bf215546Sopenharmony_ci   case GL_FLOAT:
66bf215546Sopenharmony_ci   case GL_HALF_FLOAT_ARB:
67bf215546Sopenharmony_ci   case GL_UNSIGNED_INT_10F_11F_11F_REV:
68bf215546Sopenharmony_ci   case GL_UNSIGNED_INT_5_9_9_9_REV:
69bf215546Sopenharmony_ci      return GL_FALSE;
70bf215546Sopenharmony_ci   default:
71bf215546Sopenharmony_ci      return GL_TRUE;
72bf215546Sopenharmony_ci   }
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci/**
77bf215546Sopenharmony_ci * glGetTexImage for depth/Z pixels.
78bf215546Sopenharmony_ci */
79bf215546Sopenharmony_cistatic void
80bf215546Sopenharmony_ciget_tex_depth(struct gl_context *ctx, GLuint dimensions,
81bf215546Sopenharmony_ci              GLint xoffset, GLint yoffset, GLint zoffset,
82bf215546Sopenharmony_ci              GLsizei width, GLsizei height, GLint depth,
83bf215546Sopenharmony_ci              GLenum format, GLenum type, GLvoid *pixels,
84bf215546Sopenharmony_ci              struct gl_texture_image *texImage)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci   GLint img, row;
87bf215546Sopenharmony_ci   GLfloat *depthRow = malloc(width * sizeof(GLfloat));
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (!depthRow) {
90bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
91bf215546Sopenharmony_ci      return;
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   for (img = 0; img < depth; img++) {
95bf215546Sopenharmony_ci      GLubyte *srcMap;
96bf215546Sopenharmony_ci      GLint srcRowStride;
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci      /* map src texture buffer */
99bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + img,
100bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
101bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &srcMap, &srcRowStride);
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci      if (srcMap) {
104bf215546Sopenharmony_ci         for (row = 0; row < height; row++) {
105bf215546Sopenharmony_ci            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
106bf215546Sopenharmony_ci                                             width, height, format, type,
107bf215546Sopenharmony_ci                                             img, row, 0);
108bf215546Sopenharmony_ci            const GLubyte *src = srcMap + row * srcRowStride;
109bf215546Sopenharmony_ci            _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
110bf215546Sopenharmony_ci            _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
111bf215546Sopenharmony_ci         }
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + img);
114bf215546Sopenharmony_ci      }
115bf215546Sopenharmony_ci      else {
116bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
117bf215546Sopenharmony_ci         break;
118bf215546Sopenharmony_ci      }
119bf215546Sopenharmony_ci   }
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   free(depthRow);
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci/**
126bf215546Sopenharmony_ci * glGetTexImage for depth/stencil pixels.
127bf215546Sopenharmony_ci */
128bf215546Sopenharmony_cistatic void
129bf215546Sopenharmony_ciget_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
130bf215546Sopenharmony_ci                      GLint xoffset, GLint yoffset, GLint zoffset,
131bf215546Sopenharmony_ci                      GLsizei width, GLsizei height, GLint depth,
132bf215546Sopenharmony_ci                      GLenum format, GLenum type, GLvoid *pixels,
133bf215546Sopenharmony_ci                      struct gl_texture_image *texImage)
134bf215546Sopenharmony_ci{
135bf215546Sopenharmony_ci   GLint img, row;
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   assert(format == GL_DEPTH_STENCIL);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   for (img = 0; img < depth; img++) {
140bf215546Sopenharmony_ci      GLubyte *srcMap;
141bf215546Sopenharmony_ci      GLint rowstride;
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci      /* map src texture buffer */
144bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + img,
145bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
146bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &srcMap, &rowstride);
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci      if (srcMap) {
149bf215546Sopenharmony_ci         for (row = 0; row < height; row++) {
150bf215546Sopenharmony_ci            const GLubyte *src = srcMap + row * rowstride;
151bf215546Sopenharmony_ci            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
152bf215546Sopenharmony_ci                                             width, height, format, type,
153bf215546Sopenharmony_ci                                             img, row, 0);
154bf215546Sopenharmony_ci            switch (type) {
155bf215546Sopenharmony_ci            case GL_UNSIGNED_INT_24_8:
156bf215546Sopenharmony_ci               _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat,
157bf215546Sopenharmony_ci                                                        width, src, dest);
158bf215546Sopenharmony_ci               break;
159bf215546Sopenharmony_ci            case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
160bf215546Sopenharmony_ci               _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat,
161bf215546Sopenharmony_ci                                                                 width,
162bf215546Sopenharmony_ci                                                                 src, dest);
163bf215546Sopenharmony_ci               break;
164bf215546Sopenharmony_ci            default:
165bf215546Sopenharmony_ci               unreachable("bad type in get_tex_depth_stencil()");
166bf215546Sopenharmony_ci            }
167bf215546Sopenharmony_ci            if (ctx->Pack.SwapBytes) {
168bf215546Sopenharmony_ci               _mesa_swap4((GLuint *) dest, width);
169bf215546Sopenharmony_ci            }
170bf215546Sopenharmony_ci         }
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + img);
173bf215546Sopenharmony_ci      }
174bf215546Sopenharmony_ci      else {
175bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
176bf215546Sopenharmony_ci         break;
177bf215546Sopenharmony_ci      }
178bf215546Sopenharmony_ci   }
179bf215546Sopenharmony_ci}
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci/**
182bf215546Sopenharmony_ci * glGetTexImage for stencil pixels.
183bf215546Sopenharmony_ci */
184bf215546Sopenharmony_cistatic void
185bf215546Sopenharmony_ciget_tex_stencil(struct gl_context *ctx, GLuint dimensions,
186bf215546Sopenharmony_ci                GLint xoffset, GLint yoffset, GLint zoffset,
187bf215546Sopenharmony_ci                GLsizei width, GLsizei height, GLint depth,
188bf215546Sopenharmony_ci                GLenum format, GLenum type, GLvoid *pixels,
189bf215546Sopenharmony_ci                struct gl_texture_image *texImage)
190bf215546Sopenharmony_ci{
191bf215546Sopenharmony_ci   GLint img, row;
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   assert(format == GL_STENCIL_INDEX);
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   for (img = 0; img < depth; img++) {
196bf215546Sopenharmony_ci      GLubyte *srcMap;
197bf215546Sopenharmony_ci      GLint rowstride;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci      /* map src texture buffer */
200bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + img,
201bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
202bf215546Sopenharmony_ci                         GL_MAP_READ_BIT,
203bf215546Sopenharmony_ci                         &srcMap, &rowstride);
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci      if (srcMap) {
206bf215546Sopenharmony_ci         for (row = 0; row < height; row++) {
207bf215546Sopenharmony_ci            const GLubyte *src = srcMap + row * rowstride;
208bf215546Sopenharmony_ci            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
209bf215546Sopenharmony_ci                                             width, height, format, type,
210bf215546Sopenharmony_ci                                             img, row, 0);
211bf215546Sopenharmony_ci            _mesa_unpack_ubyte_stencil_row(texImage->TexFormat,
212bf215546Sopenharmony_ci                                           width,
213bf215546Sopenharmony_ci                                           (const GLuint *) src,
214bf215546Sopenharmony_ci                                           dest);
215bf215546Sopenharmony_ci         }
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + img);
218bf215546Sopenharmony_ci      }
219bf215546Sopenharmony_ci      else {
220bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
221bf215546Sopenharmony_ci         break;
222bf215546Sopenharmony_ci      }
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci/**
228bf215546Sopenharmony_ci * glGetTexImage for YCbCr pixels.
229bf215546Sopenharmony_ci */
230bf215546Sopenharmony_cistatic void
231bf215546Sopenharmony_ciget_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
232bf215546Sopenharmony_ci              GLint xoffset, GLint yoffset, GLint zoffset,
233bf215546Sopenharmony_ci              GLsizei width, GLsizei height, GLint depth,
234bf215546Sopenharmony_ci              GLenum format, GLenum type, GLvoid *pixels,
235bf215546Sopenharmony_ci              struct gl_texture_image *texImage)
236bf215546Sopenharmony_ci{
237bf215546Sopenharmony_ci   GLint img, row;
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   for (img = 0; img < depth; img++) {
240bf215546Sopenharmony_ci      GLubyte *srcMap;
241bf215546Sopenharmony_ci      GLint rowstride;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci      /* map src texture buffer */
244bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + img,
245bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
246bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &srcMap, &rowstride);
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci      if (srcMap) {
249bf215546Sopenharmony_ci         for (row = 0; row < height; row++) {
250bf215546Sopenharmony_ci            const GLubyte *src = srcMap + row * rowstride;
251bf215546Sopenharmony_ci            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
252bf215546Sopenharmony_ci                                             width, height, format, type,
253bf215546Sopenharmony_ci                                             img, row, 0);
254bf215546Sopenharmony_ci            memcpy(dest, src, width * sizeof(GLushort));
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci            /* check for byte swapping */
257bf215546Sopenharmony_ci            if ((texImage->TexFormat == MESA_FORMAT_YCBCR
258bf215546Sopenharmony_ci                 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
259bf215546Sopenharmony_ci                (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
260bf215546Sopenharmony_ci                 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
261bf215546Sopenharmony_ci               if (!ctx->Pack.SwapBytes)
262bf215546Sopenharmony_ci                  _mesa_swap2((GLushort *) dest, width);
263bf215546Sopenharmony_ci            }
264bf215546Sopenharmony_ci            else if (ctx->Pack.SwapBytes) {
265bf215546Sopenharmony_ci               _mesa_swap2((GLushort *) dest, width);
266bf215546Sopenharmony_ci            }
267bf215546Sopenharmony_ci         }
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + img);
270bf215546Sopenharmony_ci      }
271bf215546Sopenharmony_ci      else {
272bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
273bf215546Sopenharmony_ci         break;
274bf215546Sopenharmony_ci      }
275bf215546Sopenharmony_ci   }
276bf215546Sopenharmony_ci}
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci/**
279bf215546Sopenharmony_ci * Depending on the base format involved we may need to apply a rebase
280bf215546Sopenharmony_ci * transform (for example: if we download to a Luminance format we want
281bf215546Sopenharmony_ci * G=0 and B=0).
282bf215546Sopenharmony_ci */
283bf215546Sopenharmony_cistatic bool
284bf215546Sopenharmony_citeximage_needs_rebase(mesa_format texFormat, GLenum baseFormat,
285bf215546Sopenharmony_ci                      bool is_compressed, uint8_t *rebaseSwizzle)
286bf215546Sopenharmony_ci{
287bf215546Sopenharmony_ci   bool needsRebase = false;
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   if (baseFormat == GL_LUMINANCE ||
290bf215546Sopenharmony_ci       baseFormat == GL_INTENSITY) {
291bf215546Sopenharmony_ci      needsRebase = true;
292bf215546Sopenharmony_ci      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
293bf215546Sopenharmony_ci      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
294bf215546Sopenharmony_ci      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
295bf215546Sopenharmony_ci      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
296bf215546Sopenharmony_ci   } else if (baseFormat == GL_LUMINANCE_ALPHA) {
297bf215546Sopenharmony_ci      needsRebase = true;
298bf215546Sopenharmony_ci      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
299bf215546Sopenharmony_ci      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
300bf215546Sopenharmony_ci      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
301bf215546Sopenharmony_ci      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W;
302bf215546Sopenharmony_ci   } else if (!is_compressed &&
303bf215546Sopenharmony_ci              (baseFormat != _mesa_get_format_base_format(texFormat))) {
304bf215546Sopenharmony_ci      needsRebase =
305bf215546Sopenharmony_ci         _mesa_compute_rgba2base2rgba_component_mapping(baseFormat,
306bf215546Sopenharmony_ci                                                        rebaseSwizzle);
307bf215546Sopenharmony_ci   }
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   return needsRebase;
310bf215546Sopenharmony_ci}
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci/**
314bf215546Sopenharmony_ci * Get a color texture image with decompression.
315bf215546Sopenharmony_ci */
316bf215546Sopenharmony_cistatic void
317bf215546Sopenharmony_ciget_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions,
318bf215546Sopenharmony_ci                        GLint xoffset, GLint yoffset, GLint zoffset,
319bf215546Sopenharmony_ci                        GLsizei width, GLsizei height, GLint depth,
320bf215546Sopenharmony_ci                        GLenum format, GLenum type, GLvoid *pixels,
321bf215546Sopenharmony_ci                        struct gl_texture_image *texImage,
322bf215546Sopenharmony_ci                        GLbitfield transferOps)
323bf215546Sopenharmony_ci{
324bf215546Sopenharmony_ci   /* don't want to apply sRGB -> RGB conversion here so override the format */
325bf215546Sopenharmony_ci   const mesa_format texFormat =
326bf215546Sopenharmony_ci      _mesa_get_srgb_format_linear(texImage->TexFormat);
327bf215546Sopenharmony_ci   const GLenum baseFormat = _mesa_get_format_base_format(texFormat);
328bf215546Sopenharmony_ci   GLfloat *tempImage, *tempSlice;
329bf215546Sopenharmony_ci   GLuint slice;
330bf215546Sopenharmony_ci   int srcStride, dstStride;
331bf215546Sopenharmony_ci   uint32_t dstFormat;
332bf215546Sopenharmony_ci   bool needsRebase;
333bf215546Sopenharmony_ci   uint8_t rebaseSwizzle[4];
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   /* Decompress into temp float buffer, then pack into user buffer */
336bf215546Sopenharmony_ci   tempImage = malloc(width * height * depth * 4 * sizeof(GLfloat));
337bf215546Sopenharmony_ci   if (!tempImage) {
338bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
339bf215546Sopenharmony_ci      return;
340bf215546Sopenharmony_ci   }
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   /* Decompress the texture image slices - results in 'tempImage' */
343bf215546Sopenharmony_ci   for (slice = 0; slice < depth; slice++) {
344bf215546Sopenharmony_ci      GLubyte *srcMap;
345bf215546Sopenharmony_ci      GLint srcRowStride;
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci      tempSlice = tempImage + slice * 4 * width * height;
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + slice,
350bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
351bf215546Sopenharmony_ci                         GL_MAP_READ_BIT,
352bf215546Sopenharmony_ci                         &srcMap, &srcRowStride);
353bf215546Sopenharmony_ci      if (srcMap) {
354bf215546Sopenharmony_ci         _mesa_decompress_image(texFormat, width, height,
355bf215546Sopenharmony_ci                                srcMap, srcRowStride, tempSlice);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + slice);
358bf215546Sopenharmony_ci      }
359bf215546Sopenharmony_ci      else {
360bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
361bf215546Sopenharmony_ci         free(tempImage);
362bf215546Sopenharmony_ci         return;
363bf215546Sopenharmony_ci      }
364bf215546Sopenharmony_ci   }
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci   needsRebase = teximage_needs_rebase(texFormat, baseFormat, true,
367bf215546Sopenharmony_ci                                       rebaseSwizzle);
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   srcStride = 4 * width * sizeof(GLfloat);
370bf215546Sopenharmony_ci   dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
371bf215546Sopenharmony_ci   dstFormat = _mesa_format_from_format_and_type(format, type);
372bf215546Sopenharmony_ci   tempSlice = tempImage;
373bf215546Sopenharmony_ci   for (slice = 0; slice < depth; slice++) {
374bf215546Sopenharmony_ci      void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
375bf215546Sopenharmony_ci                                       width, height, format, type,
376bf215546Sopenharmony_ci                                       slice, 0, 0);
377bf215546Sopenharmony_ci      _mesa_format_convert(dest, dstFormat, dstStride,
378bf215546Sopenharmony_ci                           tempSlice, RGBA32_FLOAT, srcStride,
379bf215546Sopenharmony_ci                           width, height,
380bf215546Sopenharmony_ci                           needsRebase ? rebaseSwizzle : NULL);
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci      /* Handle byte swapping if required */
383bf215546Sopenharmony_ci      if (ctx->Pack.SwapBytes) {
384bf215546Sopenharmony_ci         _mesa_swap_bytes_2d_image(format, type, &ctx->Pack,
385bf215546Sopenharmony_ci                                   width, height, dest, dest);
386bf215546Sopenharmony_ci      }
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci      tempSlice += 4 * width * height;
389bf215546Sopenharmony_ci   }
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci   free(tempImage);
392bf215546Sopenharmony_ci}
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci/**
396bf215546Sopenharmony_ci * Return a base GL format given the user-requested format
397bf215546Sopenharmony_ci * for glGetTexImage().
398bf215546Sopenharmony_ci */
399bf215546Sopenharmony_ciGLenum
400bf215546Sopenharmony_ci_mesa_base_pack_format(GLenum format)
401bf215546Sopenharmony_ci{
402bf215546Sopenharmony_ci   switch (format) {
403bf215546Sopenharmony_ci   case GL_ABGR_EXT:
404bf215546Sopenharmony_ci   case GL_BGRA:
405bf215546Sopenharmony_ci   case GL_BGRA_INTEGER:
406bf215546Sopenharmony_ci   case GL_RGBA_INTEGER:
407bf215546Sopenharmony_ci      return GL_RGBA;
408bf215546Sopenharmony_ci   case GL_BGR:
409bf215546Sopenharmony_ci   case GL_BGR_INTEGER:
410bf215546Sopenharmony_ci   case GL_RGB_INTEGER:
411bf215546Sopenharmony_ci      return GL_RGB;
412bf215546Sopenharmony_ci   case GL_RED_INTEGER:
413bf215546Sopenharmony_ci      return GL_RED;
414bf215546Sopenharmony_ci   case GL_GREEN_INTEGER:
415bf215546Sopenharmony_ci      return GL_GREEN;
416bf215546Sopenharmony_ci   case GL_BLUE_INTEGER:
417bf215546Sopenharmony_ci      return GL_BLUE;
418bf215546Sopenharmony_ci   case GL_ALPHA_INTEGER:
419bf215546Sopenharmony_ci      return GL_ALPHA;
420bf215546Sopenharmony_ci   case GL_LUMINANCE_INTEGER_EXT:
421bf215546Sopenharmony_ci      return GL_LUMINANCE;
422bf215546Sopenharmony_ci   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
423bf215546Sopenharmony_ci      return GL_LUMINANCE_ALPHA;
424bf215546Sopenharmony_ci   default:
425bf215546Sopenharmony_ci      return format;
426bf215546Sopenharmony_ci   }
427bf215546Sopenharmony_ci}
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci/**
431bf215546Sopenharmony_ci * Get an uncompressed color texture image.
432bf215546Sopenharmony_ci */
433bf215546Sopenharmony_cistatic void
434bf215546Sopenharmony_ciget_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
435bf215546Sopenharmony_ci                          GLint xoffset, GLint yoffset, GLint zoffset,
436bf215546Sopenharmony_ci                          GLsizei width, GLsizei height, GLint depth,
437bf215546Sopenharmony_ci                          GLenum format, GLenum type, GLvoid *pixels,
438bf215546Sopenharmony_ci                          struct gl_texture_image *texImage,
439bf215546Sopenharmony_ci                          GLbitfield transferOps)
440bf215546Sopenharmony_ci{
441bf215546Sopenharmony_ci   /* don't want to apply sRGB -> RGB conversion here so override the format */
442bf215546Sopenharmony_ci   const mesa_format texFormat =
443bf215546Sopenharmony_ci      _mesa_get_srgb_format_linear(texImage->TexFormat);
444bf215546Sopenharmony_ci   GLuint img;
445bf215546Sopenharmony_ci   GLboolean dst_is_integer;
446bf215546Sopenharmony_ci   uint32_t dst_format;
447bf215546Sopenharmony_ci   int dst_stride;
448bf215546Sopenharmony_ci   uint8_t rebaseSwizzle[4];
449bf215546Sopenharmony_ci   bool needsRebase;
450bf215546Sopenharmony_ci   void *rgba = NULL;
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   needsRebase = teximage_needs_rebase(texFormat, texImage->_BaseFormat, false,
453bf215546Sopenharmony_ci                                       rebaseSwizzle);
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   /* Describe the dst format */
456bf215546Sopenharmony_ci   dst_is_integer = _mesa_is_enum_format_integer(format);
457bf215546Sopenharmony_ci   dst_format = _mesa_format_from_format_and_type(format, type);
458bf215546Sopenharmony_ci   dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   /* Since _mesa_format_convert does not handle transferOps we need to handle
461bf215546Sopenharmony_ci    * them before we call the function. This requires to convert to RGBA float
462bf215546Sopenharmony_ci    * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is
463bf215546Sopenharmony_ci    * integer then transferOps do not apply.
464bf215546Sopenharmony_ci    */
465bf215546Sopenharmony_ci   assert(!transferOps || (transferOps && !dst_is_integer));
466bf215546Sopenharmony_ci   (void) dst_is_integer; /* silence unused var warning */
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   for (img = 0; img < depth; img++) {
469bf215546Sopenharmony_ci      GLubyte *srcMap;
470bf215546Sopenharmony_ci      GLint rowstride;
471bf215546Sopenharmony_ci      GLubyte *img_src;
472bf215546Sopenharmony_ci      void *dest;
473bf215546Sopenharmony_ci      void *src;
474bf215546Sopenharmony_ci      int src_stride;
475bf215546Sopenharmony_ci      uint32_t src_format;
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci      /* map src texture buffer */
478bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + img,
479bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
480bf215546Sopenharmony_ci                         GL_MAP_READ_BIT,
481bf215546Sopenharmony_ci                         &srcMap, &rowstride);
482bf215546Sopenharmony_ci      if (!srcMap) {
483bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
484bf215546Sopenharmony_ci         goto done;
485bf215546Sopenharmony_ci      }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci      img_src = srcMap;
488bf215546Sopenharmony_ci      dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
489bf215546Sopenharmony_ci                                 width, height, format, type,
490bf215546Sopenharmony_ci                                 img, 0, 0);
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci      if (transferOps) {
493bf215546Sopenharmony_ci         uint32_t rgba_format;
494bf215546Sopenharmony_ci         int rgba_stride;
495bf215546Sopenharmony_ci         bool need_convert = false;
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci         /* We will convert to RGBA float */
498bf215546Sopenharmony_ci         rgba_format = RGBA32_FLOAT;
499bf215546Sopenharmony_ci         rgba_stride = width * 4 * sizeof(GLfloat);
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci         /* If we are lucky and the dst format matches the RGBA format we need
502bf215546Sopenharmony_ci          * to convert to, then we can convert directly into the dst buffer
503bf215546Sopenharmony_ci          * and avoid the final conversion/copy from the rgba buffer to the dst
504bf215546Sopenharmony_ci          * buffer.
505bf215546Sopenharmony_ci          */
506bf215546Sopenharmony_ci         if (format == rgba_format) {
507bf215546Sopenharmony_ci            rgba = dest;
508bf215546Sopenharmony_ci         } else {
509bf215546Sopenharmony_ci            need_convert = true;
510bf215546Sopenharmony_ci            if (rgba == NULL) { /* Allocate the RGBA buffer only once */
511bf215546Sopenharmony_ci               rgba = malloc(height * rgba_stride);
512bf215546Sopenharmony_ci               if (!rgba) {
513bf215546Sopenharmony_ci                  _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
514bf215546Sopenharmony_ci                  st_UnmapTextureImage(ctx, texImage, img);
515bf215546Sopenharmony_ci                  return;
516bf215546Sopenharmony_ci               }
517bf215546Sopenharmony_ci            }
518bf215546Sopenharmony_ci         }
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci         _mesa_format_convert(rgba, rgba_format, rgba_stride,
521bf215546Sopenharmony_ci                              img_src, texFormat, rowstride,
522bf215546Sopenharmony_ci                              width, height,
523bf215546Sopenharmony_ci                              needsRebase ? rebaseSwizzle : NULL);
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci         /* Handle transfer ops now */
526bf215546Sopenharmony_ci         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba);
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_ci         /* If we had to rebase, we have already handled that */
529bf215546Sopenharmony_ci         needsRebase = false;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci         /* If we were lucky and our RGBA conversion matches the dst format,
532bf215546Sopenharmony_ci          * then we are done.
533bf215546Sopenharmony_ci          */
534bf215546Sopenharmony_ci         if (!need_convert)
535bf215546Sopenharmony_ci            goto do_swap;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci         /* Otherwise, we need to convert from RGBA to dst next */
538bf215546Sopenharmony_ci         src = rgba;
539bf215546Sopenharmony_ci         src_format = rgba_format;
540bf215546Sopenharmony_ci         src_stride = rgba_stride;
541bf215546Sopenharmony_ci      } else {
542bf215546Sopenharmony_ci         /* No RGBA conversion needed, convert directly to dst */
543bf215546Sopenharmony_ci         src = img_src;
544bf215546Sopenharmony_ci         src_format = texFormat;
545bf215546Sopenharmony_ci         src_stride = rowstride;
546bf215546Sopenharmony_ci      }
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_ci      /* Do the conversion to destination format */
549bf215546Sopenharmony_ci      _mesa_format_convert(dest, dst_format, dst_stride,
550bf215546Sopenharmony_ci                           src, src_format, src_stride,
551bf215546Sopenharmony_ci                           width, height,
552bf215546Sopenharmony_ci                           needsRebase ? rebaseSwizzle : NULL);
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci   do_swap:
555bf215546Sopenharmony_ci      /* Handle byte swapping if required */
556bf215546Sopenharmony_ci      if (ctx->Pack.SwapBytes)
557bf215546Sopenharmony_ci         _mesa_swap_bytes_2d_image(format, type, &ctx->Pack,
558bf215546Sopenharmony_ci                                   width, height, dest, dest);
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci      /* Unmap the src texture buffer */
561bf215546Sopenharmony_ci      st_UnmapTextureImage(ctx, texImage, zoffset + img);
562bf215546Sopenharmony_ci   }
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_cidone:
565bf215546Sopenharmony_ci   free(rgba);
566bf215546Sopenharmony_ci}
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci/**
570bf215546Sopenharmony_ci * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
571bf215546Sopenharmony_ci * Compressed textures are handled here as well.
572bf215546Sopenharmony_ci */
573bf215546Sopenharmony_cistatic void
574bf215546Sopenharmony_ciget_tex_rgba(struct gl_context *ctx, GLuint dimensions,
575bf215546Sopenharmony_ci             GLint xoffset, GLint yoffset, GLint zoffset,
576bf215546Sopenharmony_ci             GLsizei width, GLsizei height, GLint depth,
577bf215546Sopenharmony_ci             GLenum format, GLenum type, GLvoid *pixels,
578bf215546Sopenharmony_ci             struct gl_texture_image *texImage)
579bf215546Sopenharmony_ci{
580bf215546Sopenharmony_ci   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
581bf215546Sopenharmony_ci   GLbitfield transferOps = 0x0;
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   /* In general, clamping does not apply to glGetTexImage, except when
584bf215546Sopenharmony_ci    * the returned type of the image can't hold negative values.
585bf215546Sopenharmony_ci    */
586bf215546Sopenharmony_ci   if (type_needs_clamping(type)) {
587bf215546Sopenharmony_ci      /* the returned image type can't have negative values */
588bf215546Sopenharmony_ci      if (dataType == GL_FLOAT ||
589bf215546Sopenharmony_ci          dataType == GL_HALF_FLOAT ||
590bf215546Sopenharmony_ci          dataType == GL_SIGNED_NORMALIZED ||
591bf215546Sopenharmony_ci          format == GL_LUMINANCE ||
592bf215546Sopenharmony_ci          format == GL_LUMINANCE_ALPHA) {
593bf215546Sopenharmony_ci         transferOps |= IMAGE_CLAMP_BIT;
594bf215546Sopenharmony_ci      }
595bf215546Sopenharmony_ci   }
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   if (_mesa_is_format_compressed(texImage->TexFormat)) {
598bf215546Sopenharmony_ci      get_tex_rgba_compressed(ctx, dimensions,
599bf215546Sopenharmony_ci                              xoffset, yoffset, zoffset,
600bf215546Sopenharmony_ci                              width, height, depth,
601bf215546Sopenharmony_ci                              format, type,
602bf215546Sopenharmony_ci                              pixels, texImage, transferOps);
603bf215546Sopenharmony_ci   }
604bf215546Sopenharmony_ci   else {
605bf215546Sopenharmony_ci      get_tex_rgba_uncompressed(ctx, dimensions,
606bf215546Sopenharmony_ci                                xoffset, yoffset, zoffset,
607bf215546Sopenharmony_ci                                width, height, depth,
608bf215546Sopenharmony_ci                                format, type,
609bf215546Sopenharmony_ci                                pixels, texImage, transferOps);
610bf215546Sopenharmony_ci   }
611bf215546Sopenharmony_ci}
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci/**
615bf215546Sopenharmony_ci * Try to do glGetTexImage() with simple memcpy().
616bf215546Sopenharmony_ci * \return GL_TRUE if done, GL_FALSE otherwise
617bf215546Sopenharmony_ci */
618bf215546Sopenharmony_cistatic GLboolean
619bf215546Sopenharmony_ciget_tex_memcpy(struct gl_context *ctx,
620bf215546Sopenharmony_ci               GLint xoffset, GLint yoffset, GLint zoffset,
621bf215546Sopenharmony_ci               GLsizei width, GLsizei height, GLint depth,
622bf215546Sopenharmony_ci               GLenum format, GLenum type, GLvoid *pixels,
623bf215546Sopenharmony_ci               struct gl_texture_image *texImage)
624bf215546Sopenharmony_ci{
625bf215546Sopenharmony_ci   const GLenum target = texImage->TexObject->Target;
626bf215546Sopenharmony_ci   GLboolean memCopy = GL_FALSE;
627bf215546Sopenharmony_ci   GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat);
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci   /*
630bf215546Sopenharmony_ci    * Check if we can use memcpy to copy from the hardware texture
631bf215546Sopenharmony_ci    * format to the user's format/type.
632bf215546Sopenharmony_ci    * Note that GL's pixel transfer ops don't apply to glGetTexImage()
633bf215546Sopenharmony_ci    */
634bf215546Sopenharmony_ci   if ((target == GL_TEXTURE_1D ||
635bf215546Sopenharmony_ci        target == GL_TEXTURE_2D ||
636bf215546Sopenharmony_ci        target == GL_TEXTURE_RECTANGLE ||
637bf215546Sopenharmony_ci        _mesa_is_cube_face(target)) &&
638bf215546Sopenharmony_ci       texBaseFormat == texImage->_BaseFormat) {
639bf215546Sopenharmony_ci      memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat,
640bf215546Sopenharmony_ci                                                     format, type,
641bf215546Sopenharmony_ci                                                     ctx->Pack.SwapBytes, NULL);
642bf215546Sopenharmony_ci   }
643bf215546Sopenharmony_ci
644bf215546Sopenharmony_ci   if (depth > 1) {
645bf215546Sopenharmony_ci      /* only a single slice is supported at this time */
646bf215546Sopenharmony_ci      memCopy = GL_FALSE;
647bf215546Sopenharmony_ci   }
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_ci   if (memCopy) {
650bf215546Sopenharmony_ci      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
651bf215546Sopenharmony_ci      const GLint bytesPerRow = width * bpp;
652bf215546Sopenharmony_ci      GLubyte *dst =
653bf215546Sopenharmony_ci         _mesa_image_address2d(&ctx->Pack, pixels, width, height,
654bf215546Sopenharmony_ci                               format, type, 0, 0);
655bf215546Sopenharmony_ci      const GLint dstRowStride =
656bf215546Sopenharmony_ci         _mesa_image_row_stride(&ctx->Pack, width, format, type);
657bf215546Sopenharmony_ci      GLubyte *src;
658bf215546Sopenharmony_ci      GLint srcRowStride;
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci      /* map src texture buffer */
661bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset,
662bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
663bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &src, &srcRowStride);
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci      if (src) {
666bf215546Sopenharmony_ci         if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
667bf215546Sopenharmony_ci            memcpy(dst, src, bytesPerRow * height);
668bf215546Sopenharmony_ci         }
669bf215546Sopenharmony_ci         else {
670bf215546Sopenharmony_ci            GLuint row;
671bf215546Sopenharmony_ci            for (row = 0; row < height; row++) {
672bf215546Sopenharmony_ci               memcpy(dst, src, bytesPerRow);
673bf215546Sopenharmony_ci               dst += dstRowStride;
674bf215546Sopenharmony_ci               src += srcRowStride;
675bf215546Sopenharmony_ci            }
676bf215546Sopenharmony_ci         }
677bf215546Sopenharmony_ci
678bf215546Sopenharmony_ci         /* unmap src texture buffer */
679bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset);
680bf215546Sopenharmony_ci      }
681bf215546Sopenharmony_ci      else {
682bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
683bf215546Sopenharmony_ci      }
684bf215546Sopenharmony_ci   }
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci   return memCopy;
687bf215546Sopenharmony_ci}
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci
690bf215546Sopenharmony_ci/**
691bf215546Sopenharmony_ci * This is the software fallback for GetTexSubImage().
692bf215546Sopenharmony_ci * All error checking will have been done before this routine is called.
693bf215546Sopenharmony_ci */
694bf215546Sopenharmony_civoid
695bf215546Sopenharmony_ci_mesa_GetTexSubImage_sw(struct gl_context *ctx,
696bf215546Sopenharmony_ci                        GLint xoffset, GLint yoffset, GLint zoffset,
697bf215546Sopenharmony_ci                        GLsizei width, GLsizei height, GLint depth,
698bf215546Sopenharmony_ci                        GLenum format, GLenum type, GLvoid *pixels,
699bf215546Sopenharmony_ci                        struct gl_texture_image *texImage)
700bf215546Sopenharmony_ci{
701bf215546Sopenharmony_ci   const GLuint dimensions =
702bf215546Sopenharmony_ci      _mesa_get_texture_dimensions(texImage->TexObject->Target);
703bf215546Sopenharmony_ci
704bf215546Sopenharmony_ci   /* map dest buffer, if PBO */
705bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
706bf215546Sopenharmony_ci      /* Packing texture image into a PBO.
707bf215546Sopenharmony_ci       * Map the (potentially) VRAM-based buffer into our process space so
708bf215546Sopenharmony_ci       * we can write into it with the code below.
709bf215546Sopenharmony_ci       * A hardware driver might use a sophisticated blit to move the
710bf215546Sopenharmony_ci       * texture data to the PBO if the PBO is in VRAM along with the texture.
711bf215546Sopenharmony_ci       */
712bf215546Sopenharmony_ci      GLubyte *buf = (GLubyte *)
713bf215546Sopenharmony_ci         _mesa_bufferobj_map_range(ctx, 0, ctx->Pack.BufferObj->Size,
714bf215546Sopenharmony_ci                                   GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
715bf215546Sopenharmony_ci                                   MAP_INTERNAL);
716bf215546Sopenharmony_ci      if (!buf) {
717bf215546Sopenharmony_ci         /* out of memory or other unexpected error */
718bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
719bf215546Sopenharmony_ci         return;
720bf215546Sopenharmony_ci      }
721bf215546Sopenharmony_ci      /* <pixels> was an offset into the PBO.
722bf215546Sopenharmony_ci       * Now make it a real, client-side pointer inside the mapped region.
723bf215546Sopenharmony_ci       */
724bf215546Sopenharmony_ci      pixels = ADD_POINTERS(buf, pixels);
725bf215546Sopenharmony_ci   }
726bf215546Sopenharmony_ci
727bf215546Sopenharmony_ci   /* for all array textures, the Z axis selects the layer */
728bf215546Sopenharmony_ci   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
729bf215546Sopenharmony_ci      depth = height;
730bf215546Sopenharmony_ci      height = 1;
731bf215546Sopenharmony_ci      zoffset = yoffset;
732bf215546Sopenharmony_ci      yoffset = 0;
733bf215546Sopenharmony_ci      assert(zoffset + depth <= texImage->Height);
734bf215546Sopenharmony_ci   } else {
735bf215546Sopenharmony_ci      assert(zoffset + depth <= texImage->Depth);
736bf215546Sopenharmony_ci   }
737bf215546Sopenharmony_ci
738bf215546Sopenharmony_ci   if (get_tex_memcpy(ctx, xoffset, yoffset, zoffset, width, height, depth,
739bf215546Sopenharmony_ci                      format, type, pixels, texImage)) {
740bf215546Sopenharmony_ci      /* all done */
741bf215546Sopenharmony_ci   }
742bf215546Sopenharmony_ci   else if (format == GL_DEPTH_COMPONENT) {
743bf215546Sopenharmony_ci      get_tex_depth(ctx, dimensions, xoffset, yoffset, zoffset,
744bf215546Sopenharmony_ci                    width, height, depth, format, type, pixels, texImage);
745bf215546Sopenharmony_ci   }
746bf215546Sopenharmony_ci   else if (format == GL_DEPTH_STENCIL_EXT) {
747bf215546Sopenharmony_ci      get_tex_depth_stencil(ctx, dimensions, xoffset, yoffset, zoffset,
748bf215546Sopenharmony_ci                            width, height, depth, format, type, pixels,
749bf215546Sopenharmony_ci                            texImage);
750bf215546Sopenharmony_ci   }
751bf215546Sopenharmony_ci   else if (format == GL_STENCIL_INDEX) {
752bf215546Sopenharmony_ci      get_tex_stencil(ctx, dimensions, xoffset, yoffset, zoffset,
753bf215546Sopenharmony_ci                      width, height, depth, format, type, pixels, texImage);
754bf215546Sopenharmony_ci   }
755bf215546Sopenharmony_ci   else if (format == GL_YCBCR_MESA) {
756bf215546Sopenharmony_ci      get_tex_ycbcr(ctx, dimensions, xoffset, yoffset, zoffset,
757bf215546Sopenharmony_ci                    width, height, depth, format, type, pixels, texImage);
758bf215546Sopenharmony_ci   }
759bf215546Sopenharmony_ci   else {
760bf215546Sopenharmony_ci      get_tex_rgba(ctx, dimensions, xoffset, yoffset, zoffset,
761bf215546Sopenharmony_ci                   width, height, depth, format, type, pixels, texImage);
762bf215546Sopenharmony_ci   }
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
765bf215546Sopenharmony_ci      _mesa_bufferobj_unmap(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
766bf215546Sopenharmony_ci   }
767bf215546Sopenharmony_ci}
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci
771bf215546Sopenharmony_ci/**
772bf215546Sopenharmony_ci * This function assumes that all error checking has been done.
773bf215546Sopenharmony_ci */
774bf215546Sopenharmony_cistatic void
775bf215546Sopenharmony_ciget_compressed_texsubimage_sw(struct gl_context *ctx,
776bf215546Sopenharmony_ci                              struct gl_texture_image *texImage,
777bf215546Sopenharmony_ci                              GLint xoffset, GLint yoffset,
778bf215546Sopenharmony_ci                              GLint zoffset, GLsizei width,
779bf215546Sopenharmony_ci                              GLint height, GLint depth,
780bf215546Sopenharmony_ci                              GLvoid *img)
781bf215546Sopenharmony_ci{
782bf215546Sopenharmony_ci   const GLuint dimensions =
783bf215546Sopenharmony_ci      _mesa_get_texture_dimensions(texImage->TexObject->Target);
784bf215546Sopenharmony_ci   struct compressed_pixelstore store;
785bf215546Sopenharmony_ci   GLint slice;
786bf215546Sopenharmony_ci   GLubyte *dest;
787bf215546Sopenharmony_ci
788bf215546Sopenharmony_ci   _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat,
789bf215546Sopenharmony_ci                                       width, height, depth,
790bf215546Sopenharmony_ci                                       &ctx->Pack, &store);
791bf215546Sopenharmony_ci
792bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
793bf215546Sopenharmony_ci      /* pack texture image into a PBO */
794bf215546Sopenharmony_ci      dest = (GLubyte *)
795bf215546Sopenharmony_ci         _mesa_bufferobj_map_range(ctx, 0, ctx->Pack.BufferObj->Size,
796bf215546Sopenharmony_ci                                   GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
797bf215546Sopenharmony_ci                                   MAP_INTERNAL);
798bf215546Sopenharmony_ci      if (!dest) {
799bf215546Sopenharmony_ci         /* out of memory or other unexpected error */
800bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY,
801bf215546Sopenharmony_ci                     "glGetCompresssedTexImage(map PBO failed)");
802bf215546Sopenharmony_ci         return;
803bf215546Sopenharmony_ci      }
804bf215546Sopenharmony_ci      dest = ADD_POINTERS(dest, img);
805bf215546Sopenharmony_ci   } else {
806bf215546Sopenharmony_ci      dest = img;
807bf215546Sopenharmony_ci   }
808bf215546Sopenharmony_ci
809bf215546Sopenharmony_ci   dest += store.SkipBytes;
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci   for (slice = 0; slice < store.CopySlices; slice++) {
812bf215546Sopenharmony_ci      GLint srcRowStride;
813bf215546Sopenharmony_ci      GLubyte *src;
814bf215546Sopenharmony_ci
815bf215546Sopenharmony_ci      /* map src texture buffer */
816bf215546Sopenharmony_ci      st_MapTextureImage(ctx, texImage, zoffset + slice,
817bf215546Sopenharmony_ci                         xoffset, yoffset, width, height,
818bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &src, &srcRowStride);
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci      if (src) {
821bf215546Sopenharmony_ci         GLint i;
822bf215546Sopenharmony_ci         for (i = 0; i < store.CopyRowsPerSlice; i++) {
823bf215546Sopenharmony_ci            memcpy(dest, src, store.CopyBytesPerRow);
824bf215546Sopenharmony_ci            dest += store.TotalBytesPerRow;
825bf215546Sopenharmony_ci            src += srcRowStride;
826bf215546Sopenharmony_ci         }
827bf215546Sopenharmony_ci
828bf215546Sopenharmony_ci         st_UnmapTextureImage(ctx, texImage, zoffset + slice);
829bf215546Sopenharmony_ci
830bf215546Sopenharmony_ci         /* Advance to next slice */
831bf215546Sopenharmony_ci         dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice -
832bf215546Sopenharmony_ci                                           store.CopyRowsPerSlice);
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci      } else {
835bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
836bf215546Sopenharmony_ci      }
837bf215546Sopenharmony_ci   }
838bf215546Sopenharmony_ci
839bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
840bf215546Sopenharmony_ci      _mesa_bufferobj_unmap(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
841bf215546Sopenharmony_ci   }
842bf215546Sopenharmony_ci}
843bf215546Sopenharmony_ci
844bf215546Sopenharmony_ci
845bf215546Sopenharmony_ci/**
846bf215546Sopenharmony_ci * Validate the texture target enum supplied to glGetTex(ture)Image or
847bf215546Sopenharmony_ci * glGetCompressedTex(ture)Image.
848bf215546Sopenharmony_ci */
849bf215546Sopenharmony_cistatic GLboolean
850bf215546Sopenharmony_cilegal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa)
851bf215546Sopenharmony_ci{
852bf215546Sopenharmony_ci   switch (target) {
853bf215546Sopenharmony_ci   case GL_TEXTURE_1D:
854bf215546Sopenharmony_ci   case GL_TEXTURE_2D:
855bf215546Sopenharmony_ci   case GL_TEXTURE_3D:
856bf215546Sopenharmony_ci      return GL_TRUE;
857bf215546Sopenharmony_ci   case GL_TEXTURE_RECTANGLE_NV:
858bf215546Sopenharmony_ci      return ctx->Extensions.NV_texture_rectangle;
859bf215546Sopenharmony_ci   case GL_TEXTURE_1D_ARRAY_EXT:
860bf215546Sopenharmony_ci   case GL_TEXTURE_2D_ARRAY_EXT:
861bf215546Sopenharmony_ci      return ctx->Extensions.EXT_texture_array;
862bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_ARRAY:
863bf215546Sopenharmony_ci      return ctx->Extensions.ARB_texture_cube_map_array;
864bf215546Sopenharmony_ci
865bf215546Sopenharmony_ci   /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec
866bf215546Sopenharmony_ci    * (30.10.2014) says:
867bf215546Sopenharmony_ci    *    "An INVALID_ENUM error is generated if the effective target is not
868bf215546Sopenharmony_ci    *    one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY,
869bf215546Sopenharmony_ci    *    TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of
870bf215546Sopenharmony_ci    *    the targets from table 8.19 (for GetTexImage and GetnTexImage *only*),
871bf215546Sopenharmony_ci    *    or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.)
872bf215546Sopenharmony_ci    */
873bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
874bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
875bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
876bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
877bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
878bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
879bf215546Sopenharmony_ci      return dsa ? GL_FALSE : GL_TRUE;
880bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP:
881bf215546Sopenharmony_ci      return dsa ? GL_TRUE : GL_FALSE;
882bf215546Sopenharmony_ci   default:
883bf215546Sopenharmony_ci      return GL_FALSE;
884bf215546Sopenharmony_ci   }
885bf215546Sopenharmony_ci}
886bf215546Sopenharmony_ci
887bf215546Sopenharmony_ci
888bf215546Sopenharmony_ci/**
889bf215546Sopenharmony_ci * Wrapper for _mesa_select_tex_image() which can handle target being
890bf215546Sopenharmony_ci * GL_TEXTURE_CUBE_MAP in which case we use zoffset to select a cube face.
891bf215546Sopenharmony_ci * This can happen for glGetTextureImage and glGetTextureSubImage (DSA
892bf215546Sopenharmony_ci * functions).
893bf215546Sopenharmony_ci */
894bf215546Sopenharmony_cistatic struct gl_texture_image *
895bf215546Sopenharmony_ciselect_tex_image(const struct gl_texture_object *texObj, GLenum target,
896bf215546Sopenharmony_ci                 GLint level, GLint zoffset)
897bf215546Sopenharmony_ci{
898bf215546Sopenharmony_ci   assert(level >= 0);
899bf215546Sopenharmony_ci   assert(level < MAX_TEXTURE_LEVELS);
900bf215546Sopenharmony_ci   if (target == GL_TEXTURE_CUBE_MAP) {
901bf215546Sopenharmony_ci      assert(zoffset >= 0);
902bf215546Sopenharmony_ci      assert(zoffset < 6);
903bf215546Sopenharmony_ci      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset;
904bf215546Sopenharmony_ci   }
905bf215546Sopenharmony_ci   return _mesa_select_tex_image(texObj, target, level);
906bf215546Sopenharmony_ci}
907bf215546Sopenharmony_ci
908bf215546Sopenharmony_ci
909bf215546Sopenharmony_ci/**
910bf215546Sopenharmony_ci * Error-check the offset and size arguments to
911bf215546Sopenharmony_ci * glGet[Compressed]TextureSubImage().
912bf215546Sopenharmony_ci * \return true if error, false if no error.
913bf215546Sopenharmony_ci */
914bf215546Sopenharmony_cistatic bool
915bf215546Sopenharmony_cidimensions_error_check(struct gl_context *ctx,
916bf215546Sopenharmony_ci                       struct gl_texture_object *texObj,
917bf215546Sopenharmony_ci                       GLenum target, GLint level,
918bf215546Sopenharmony_ci                       GLint xoffset, GLint yoffset, GLint zoffset,
919bf215546Sopenharmony_ci                       GLsizei width, GLsizei height, GLsizei depth,
920bf215546Sopenharmony_ci                       const char *caller)
921bf215546Sopenharmony_ci{
922bf215546Sopenharmony_ci   const struct gl_texture_image *texImage;
923bf215546Sopenharmony_ci   GLuint imageWidth = 0, imageHeight = 0, imageDepth = 0;
924bf215546Sopenharmony_ci
925bf215546Sopenharmony_ci   if (xoffset < 0) {
926bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset = %d)", caller, xoffset);
927bf215546Sopenharmony_ci      return true;
928bf215546Sopenharmony_ci   }
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci   if (yoffset < 0) {
931bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset = %d)", caller, yoffset);
932bf215546Sopenharmony_ci      return true;
933bf215546Sopenharmony_ci   }
934bf215546Sopenharmony_ci
935bf215546Sopenharmony_ci   if (zoffset < 0) {
936bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset = %d)", caller, zoffset);
937bf215546Sopenharmony_ci      return true;
938bf215546Sopenharmony_ci   }
939bf215546Sopenharmony_ci
940bf215546Sopenharmony_ci   if (width < 0) {
941bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width = %d)", caller, width);
942bf215546Sopenharmony_ci      return true;
943bf215546Sopenharmony_ci   }
944bf215546Sopenharmony_ci
945bf215546Sopenharmony_ci   if (height < 0) {
946bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height = %d)", caller, height);
947bf215546Sopenharmony_ci      return true;
948bf215546Sopenharmony_ci   }
949bf215546Sopenharmony_ci
950bf215546Sopenharmony_ci   if (depth < 0) {
951bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(depth = %d)", caller, depth);
952bf215546Sopenharmony_ci      return true;
953bf215546Sopenharmony_ci   }
954bf215546Sopenharmony_ci
955bf215546Sopenharmony_ci   /* do special per-target checks */
956bf215546Sopenharmony_ci   switch (target) {
957bf215546Sopenharmony_ci   case GL_TEXTURE_1D:
958bf215546Sopenharmony_ci      if (yoffset != 0) {
959bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
960bf215546Sopenharmony_ci                     "%s(1D, yoffset = %d)", caller, yoffset);
961bf215546Sopenharmony_ci         return true;
962bf215546Sopenharmony_ci      }
963bf215546Sopenharmony_ci      if (height != 1) {
964bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
965bf215546Sopenharmony_ci                     "%s(1D, height = %d)", caller, height);
966bf215546Sopenharmony_ci         return true;
967bf215546Sopenharmony_ci      }
968bf215546Sopenharmony_ci      FALLTHROUGH;
969bf215546Sopenharmony_ci   case GL_TEXTURE_1D_ARRAY:
970bf215546Sopenharmony_ci   case GL_TEXTURE_2D:
971bf215546Sopenharmony_ci   case GL_TEXTURE_RECTANGLE:
972bf215546Sopenharmony_ci      if (zoffset != 0) {
973bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
974bf215546Sopenharmony_ci                     "%s(zoffset = %d)", caller, zoffset);
975bf215546Sopenharmony_ci         return true;
976bf215546Sopenharmony_ci      }
977bf215546Sopenharmony_ci      if (depth != 1) {
978bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
979bf215546Sopenharmony_ci                     "%s(depth = %d)", caller, depth);
980bf215546Sopenharmony_ci         return true;
981bf215546Sopenharmony_ci      }
982bf215546Sopenharmony_ci      break;
983bf215546Sopenharmony_ci   case GL_TEXTURE_CUBE_MAP:
984bf215546Sopenharmony_ci      /* Non-array cube maps are special because we have a gl_texture_image
985bf215546Sopenharmony_ci       * per face.
986bf215546Sopenharmony_ci       */
987bf215546Sopenharmony_ci      if (zoffset + depth > 6) {
988bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
989bf215546Sopenharmony_ci                     "%s(zoffset + depth = %d)", caller, zoffset + depth);
990bf215546Sopenharmony_ci         return true;
991bf215546Sopenharmony_ci      }
992bf215546Sopenharmony_ci      break;
993bf215546Sopenharmony_ci   default:
994bf215546Sopenharmony_ci      ; /* nothing */
995bf215546Sopenharmony_ci   }
996bf215546Sopenharmony_ci
997bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, zoffset);
998bf215546Sopenharmony_ci   if (texImage) {
999bf215546Sopenharmony_ci      imageWidth = texImage->Width;
1000bf215546Sopenharmony_ci      imageHeight = texImage->Height;
1001bf215546Sopenharmony_ci      imageDepth = texImage->Depth;
1002bf215546Sopenharmony_ci   }
1003bf215546Sopenharmony_ci
1004bf215546Sopenharmony_ci   if (xoffset + width > imageWidth) {
1005bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
1006bf215546Sopenharmony_ci                  "%s(xoffset %d + width %d > %u)",
1007bf215546Sopenharmony_ci                  caller, xoffset, width, imageWidth);
1008bf215546Sopenharmony_ci      return true;
1009bf215546Sopenharmony_ci   }
1010bf215546Sopenharmony_ci
1011bf215546Sopenharmony_ci   if (yoffset + height > imageHeight) {
1012bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
1013bf215546Sopenharmony_ci                  "%s(yoffset %d + height %d > %u)",
1014bf215546Sopenharmony_ci                  caller, yoffset, height, imageHeight);
1015bf215546Sopenharmony_ci      return true;
1016bf215546Sopenharmony_ci   }
1017bf215546Sopenharmony_ci
1018bf215546Sopenharmony_ci   if (target != GL_TEXTURE_CUBE_MAP) {
1019bf215546Sopenharmony_ci      /* Cube map error checking was done above */
1020bf215546Sopenharmony_ci      if (zoffset + depth > imageDepth) {
1021bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
1022bf215546Sopenharmony_ci                     "%s(zoffset %d + depth %d > %u)",
1023bf215546Sopenharmony_ci                     caller, zoffset, depth, imageDepth);
1024bf215546Sopenharmony_ci         return true;
1025bf215546Sopenharmony_ci      }
1026bf215546Sopenharmony_ci   }
1027bf215546Sopenharmony_ci
1028bf215546Sopenharmony_ci   /* Extra checks for compressed textures */
1029bf215546Sopenharmony_ci   if (texImage) {
1030bf215546Sopenharmony_ci      GLuint bw, bh, bd;
1031bf215546Sopenharmony_ci      _mesa_get_format_block_size_3d(texImage->TexFormat, &bw, &bh, &bd);
1032bf215546Sopenharmony_ci      if (bw > 1 || bh > 1 || bd > 1) {
1033bf215546Sopenharmony_ci         /* offset must be multiple of block size */
1034bf215546Sopenharmony_ci         if (xoffset % bw != 0) {
1035bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1036bf215546Sopenharmony_ci                        "%s(xoffset = %d)", caller, xoffset);
1037bf215546Sopenharmony_ci            return true;
1038bf215546Sopenharmony_ci         }
1039bf215546Sopenharmony_ci         if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) {
1040bf215546Sopenharmony_ci            if (yoffset % bh != 0) {
1041bf215546Sopenharmony_ci               _mesa_error(ctx, GL_INVALID_VALUE,
1042bf215546Sopenharmony_ci                           "%s(yoffset = %d)", caller, yoffset);
1043bf215546Sopenharmony_ci               return true;
1044bf215546Sopenharmony_ci            }
1045bf215546Sopenharmony_ci         }
1046bf215546Sopenharmony_ci
1047bf215546Sopenharmony_ci         if (zoffset % bd != 0) {
1048bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1049bf215546Sopenharmony_ci                        "%s(zoffset = %d)", caller, zoffset);
1050bf215546Sopenharmony_ci            return true;
1051bf215546Sopenharmony_ci         }
1052bf215546Sopenharmony_ci
1053bf215546Sopenharmony_ci         /* The size must be a multiple of bw x bh x bd, or we must be using a
1054bf215546Sopenharmony_ci          * offset+size that exactly hits the edge of the image.
1055bf215546Sopenharmony_ci          */
1056bf215546Sopenharmony_ci         if ((width % bw != 0) &&
1057bf215546Sopenharmony_ci             (xoffset + width != (GLint) texImage->Width)) {
1058bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1059bf215546Sopenharmony_ci                        "%s(width = %d)", caller, width);
1060bf215546Sopenharmony_ci            return true;
1061bf215546Sopenharmony_ci         }
1062bf215546Sopenharmony_ci
1063bf215546Sopenharmony_ci         if ((height % bh != 0) &&
1064bf215546Sopenharmony_ci             (yoffset + height != (GLint) texImage->Height)) {
1065bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1066bf215546Sopenharmony_ci                        "%s(height = %d)", caller, height);
1067bf215546Sopenharmony_ci            return true;
1068bf215546Sopenharmony_ci         }
1069bf215546Sopenharmony_ci
1070bf215546Sopenharmony_ci         if ((depth % bd != 0) &&
1071bf215546Sopenharmony_ci             (zoffset + depth != (GLint) texImage->Depth)) {
1072bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
1073bf215546Sopenharmony_ci                        "%s(depth = %d)", caller, depth);
1074bf215546Sopenharmony_ci            return true;
1075bf215546Sopenharmony_ci         }
1076bf215546Sopenharmony_ci      }
1077bf215546Sopenharmony_ci   }
1078bf215546Sopenharmony_ci
1079bf215546Sopenharmony_ci   if (width == 0 || height == 0 || depth == 0) {
1080bf215546Sopenharmony_ci      /* Not an error, but nothing to do.  Return 'true' so that the
1081bf215546Sopenharmony_ci       * caller simply returns.
1082bf215546Sopenharmony_ci       */
1083bf215546Sopenharmony_ci      return true;
1084bf215546Sopenharmony_ci   }
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci   return false;
1087bf215546Sopenharmony_ci}
1088bf215546Sopenharmony_ci
1089bf215546Sopenharmony_ci
1090bf215546Sopenharmony_ci/**
1091bf215546Sopenharmony_ci * Do PBO-related error checking for getting uncompressed images.
1092bf215546Sopenharmony_ci * \return true if there was an error (or the GetTexImage is to be a no-op)
1093bf215546Sopenharmony_ci */
1094bf215546Sopenharmony_cistatic bool
1095bf215546Sopenharmony_cipbo_error_check(struct gl_context *ctx, GLenum target,
1096bf215546Sopenharmony_ci                GLsizei width, GLsizei height, GLsizei depth,
1097bf215546Sopenharmony_ci                GLenum format, GLenum type, GLsizei clientMemSize,
1098bf215546Sopenharmony_ci                GLvoid *pixels,
1099bf215546Sopenharmony_ci                const char *caller)
1100bf215546Sopenharmony_ci{
1101bf215546Sopenharmony_ci   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
1102bf215546Sopenharmony_ci
1103bf215546Sopenharmony_ci   if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, width, height, depth,
1104bf215546Sopenharmony_ci                                  format, type, clientMemSize, pixels)) {
1105bf215546Sopenharmony_ci      if (ctx->Pack.BufferObj) {
1106bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1107bf215546Sopenharmony_ci                     "%s(out of bounds PBO access)", caller);
1108bf215546Sopenharmony_ci      } else {
1109bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1110bf215546Sopenharmony_ci                     "%s(out of bounds access: bufSize (%d) is too small)",
1111bf215546Sopenharmony_ci                     caller, clientMemSize);
1112bf215546Sopenharmony_ci      }
1113bf215546Sopenharmony_ci      return true;
1114bf215546Sopenharmony_ci   }
1115bf215546Sopenharmony_ci
1116bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
1117bf215546Sopenharmony_ci      /* PBO should not be mapped */
1118bf215546Sopenharmony_ci      if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1119bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1120bf215546Sopenharmony_ci                     "%s(PBO is mapped)", caller);
1121bf215546Sopenharmony_ci         return true;
1122bf215546Sopenharmony_ci      }
1123bf215546Sopenharmony_ci   }
1124bf215546Sopenharmony_ci
1125bf215546Sopenharmony_ci   if (!ctx->Pack.BufferObj && !pixels) {
1126bf215546Sopenharmony_ci      /* not an error, do nothing */
1127bf215546Sopenharmony_ci      return true;
1128bf215546Sopenharmony_ci   }
1129bf215546Sopenharmony_ci
1130bf215546Sopenharmony_ci   return false;
1131bf215546Sopenharmony_ci}
1132bf215546Sopenharmony_ci
1133bf215546Sopenharmony_ci
1134bf215546Sopenharmony_ci/**
1135bf215546Sopenharmony_ci * Do teximage-related error checking for getting uncompressed images.
1136bf215546Sopenharmony_ci * \return true if there was an error
1137bf215546Sopenharmony_ci */
1138bf215546Sopenharmony_cistatic bool
1139bf215546Sopenharmony_citeximage_error_check(struct gl_context *ctx,
1140bf215546Sopenharmony_ci                     struct gl_texture_image *texImage,
1141bf215546Sopenharmony_ci                     GLenum format, const char *caller)
1142bf215546Sopenharmony_ci{
1143bf215546Sopenharmony_ci   GLenum baseFormat;
1144bf215546Sopenharmony_ci   assert(texImage);
1145bf215546Sopenharmony_ci
1146bf215546Sopenharmony_ci   /*
1147bf215546Sopenharmony_ci    * Format and type checking has been moved up to GetnTexImage and
1148bf215546Sopenharmony_ci    * GetTextureImage so that it happens before getting the texImage object.
1149bf215546Sopenharmony_ci    */
1150bf215546Sopenharmony_ci
1151bf215546Sopenharmony_ci   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
1152bf215546Sopenharmony_ci
1153bf215546Sopenharmony_ci   /* Make sure the requested image format is compatible with the
1154bf215546Sopenharmony_ci    * texture's format.
1155bf215546Sopenharmony_ci    */
1156bf215546Sopenharmony_ci   if (_mesa_is_color_format(format)
1157bf215546Sopenharmony_ci       && !_mesa_is_color_format(baseFormat)) {
1158bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1159bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1160bf215546Sopenharmony_ci      return true;
1161bf215546Sopenharmony_ci   }
1162bf215546Sopenharmony_ci   else if (_mesa_is_depth_format(format)
1163bf215546Sopenharmony_ci            && !_mesa_is_depth_format(baseFormat)
1164bf215546Sopenharmony_ci            && !_mesa_is_depthstencil_format(baseFormat)) {
1165bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1166bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1167bf215546Sopenharmony_ci      return true;
1168bf215546Sopenharmony_ci   }
1169bf215546Sopenharmony_ci   else if (_mesa_is_stencil_format(format)
1170bf215546Sopenharmony_ci            && !ctx->Extensions.ARB_texture_stencil8) {
1171bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
1172bf215546Sopenharmony_ci                  "%s(format=GL_STENCIL_INDEX)", caller);
1173bf215546Sopenharmony_ci      return true;
1174bf215546Sopenharmony_ci   }
1175bf215546Sopenharmony_ci   else if (_mesa_is_stencil_format(format)
1176bf215546Sopenharmony_ci            && !_mesa_is_depthstencil_format(baseFormat)
1177bf215546Sopenharmony_ci            && !_mesa_is_stencil_format(baseFormat)) {
1178bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1179bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1180bf215546Sopenharmony_ci      return true;
1181bf215546Sopenharmony_ci   }
1182bf215546Sopenharmony_ci   else if (_mesa_is_ycbcr_format(format)
1183bf215546Sopenharmony_ci            && !_mesa_is_ycbcr_format(baseFormat)) {
1184bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1185bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1186bf215546Sopenharmony_ci      return true;
1187bf215546Sopenharmony_ci   }
1188bf215546Sopenharmony_ci   else if (_mesa_is_depthstencil_format(format)
1189bf215546Sopenharmony_ci            && !_mesa_is_depthstencil_format(baseFormat)) {
1190bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1191bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1192bf215546Sopenharmony_ci      return true;
1193bf215546Sopenharmony_ci   }
1194bf215546Sopenharmony_ci   else if (!_mesa_is_stencil_format(format) &&
1195bf215546Sopenharmony_ci            _mesa_is_enum_format_integer(format) !=
1196bf215546Sopenharmony_ci            _mesa_is_format_integer(texImage->TexFormat)) {
1197bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1198bf215546Sopenharmony_ci                  "%s(format mismatch)", caller);
1199bf215546Sopenharmony_ci      return true;
1200bf215546Sopenharmony_ci   }
1201bf215546Sopenharmony_ci
1202bf215546Sopenharmony_ci   return false;
1203bf215546Sopenharmony_ci}
1204bf215546Sopenharmony_ci
1205bf215546Sopenharmony_ci
1206bf215546Sopenharmony_ci/**
1207bf215546Sopenharmony_ci * Do common teximage-related error checking for getting uncompressed images.
1208bf215546Sopenharmony_ci * \return true if there was an error
1209bf215546Sopenharmony_ci */
1210bf215546Sopenharmony_cistatic bool
1211bf215546Sopenharmony_cicommon_error_check(struct gl_context *ctx,
1212bf215546Sopenharmony_ci                   struct gl_texture_object *texObj,
1213bf215546Sopenharmony_ci                   GLenum target, GLint level,
1214bf215546Sopenharmony_ci                   GLsizei width, GLsizei height, GLsizei depth,
1215bf215546Sopenharmony_ci                   GLenum format, GLenum type, GLsizei bufSize,
1216bf215546Sopenharmony_ci                   GLvoid *pixels, const char *caller)
1217bf215546Sopenharmony_ci{
1218bf215546Sopenharmony_ci   GLenum err;
1219bf215546Sopenharmony_ci   GLint maxLevels;
1220bf215546Sopenharmony_ci
1221bf215546Sopenharmony_ci   if (texObj->Target == 0) {
1222bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
1223bf215546Sopenharmony_ci      return true;
1224bf215546Sopenharmony_ci   }
1225bf215546Sopenharmony_ci
1226bf215546Sopenharmony_ci   maxLevels = _mesa_max_texture_levels(ctx, target);
1227bf215546Sopenharmony_ci   if (level < 0 || level >= maxLevels) {
1228bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level = %d)", caller, level);
1229bf215546Sopenharmony_ci      return true;
1230bf215546Sopenharmony_ci   }
1231bf215546Sopenharmony_ci
1232bf215546Sopenharmony_ci   err = _mesa_error_check_format_and_type(ctx, format, type);
1233bf215546Sopenharmony_ci   if (err != GL_NO_ERROR) {
1234bf215546Sopenharmony_ci      _mesa_error(ctx, err, "%s(format/type)", caller);
1235bf215546Sopenharmony_ci      return true;
1236bf215546Sopenharmony_ci   }
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ci   /* According to OpenGL 4.6 spec, section 8.11.4 ("Texture Image Queries"):
1239bf215546Sopenharmony_ci    *
1240bf215546Sopenharmony_ci    *   "An INVALID_OPERATION error is generated by GetTextureImage if the
1241bf215546Sopenharmony_ci    *   effective target is TEXTURE_CUBE_MAP or TEXTURE_CUBE_MAP_ARRAY ,
1242bf215546Sopenharmony_ci    *   and the texture object is not cube complete or cube array complete,
1243bf215546Sopenharmony_ci    *   respectively."
1244bf215546Sopenharmony_ci    *
1245bf215546Sopenharmony_ci    * This applies also to GetTextureSubImage, GetCompressedTexImage,
1246bf215546Sopenharmony_ci    * GetCompressedTextureImage, and GetnCompressedTexImage.
1247bf215546Sopenharmony_ci    */
1248bf215546Sopenharmony_ci   if (target == GL_TEXTURE_CUBE_MAP && !_mesa_cube_complete(texObj)) {
1249bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1250bf215546Sopenharmony_ci                  "%s(cube incomplete)", caller);
1251bf215546Sopenharmony_ci      return true;
1252bf215546Sopenharmony_ci   }
1253bf215546Sopenharmony_ci
1254bf215546Sopenharmony_ci   return false;
1255bf215546Sopenharmony_ci}
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_ci
1258bf215546Sopenharmony_ci/**
1259bf215546Sopenharmony_ci * Do error checking for all (non-compressed) get-texture-image functions.
1260bf215546Sopenharmony_ci * \return true if any error, false if no errors.
1261bf215546Sopenharmony_ci */
1262bf215546Sopenharmony_cistatic bool
1263bf215546Sopenharmony_cigetteximage_error_check(struct gl_context *ctx,
1264bf215546Sopenharmony_ci                        struct gl_texture_object *texObj,
1265bf215546Sopenharmony_ci                        GLenum target, GLint level,
1266bf215546Sopenharmony_ci                        GLsizei width, GLsizei height, GLsizei depth,
1267bf215546Sopenharmony_ci                        GLenum format, GLenum type, GLsizei bufSize,
1268bf215546Sopenharmony_ci                        GLvoid *pixels, const char *caller)
1269bf215546Sopenharmony_ci{
1270bf215546Sopenharmony_ci   struct gl_texture_image *texImage;
1271bf215546Sopenharmony_ci
1272bf215546Sopenharmony_ci   assert(texObj);
1273bf215546Sopenharmony_ci
1274bf215546Sopenharmony_ci   if (common_error_check(ctx, texObj, target, level, width, height, depth,
1275bf215546Sopenharmony_ci                          format, type, bufSize, pixels, caller)) {
1276bf215546Sopenharmony_ci      return true;
1277bf215546Sopenharmony_ci   }
1278bf215546Sopenharmony_ci
1279bf215546Sopenharmony_ci   if (width == 0 || height == 0 || depth == 0) {
1280bf215546Sopenharmony_ci      /* Not an error, but nothing to do.  Return 'true' so that the
1281bf215546Sopenharmony_ci       * caller simply returns.
1282bf215546Sopenharmony_ci       */
1283bf215546Sopenharmony_ci      return true;
1284bf215546Sopenharmony_ci   }
1285bf215546Sopenharmony_ci
1286bf215546Sopenharmony_ci   if (pbo_error_check(ctx, target, width, height, depth,
1287bf215546Sopenharmony_ci                       format, type, bufSize, pixels, caller)) {
1288bf215546Sopenharmony_ci      return true;
1289bf215546Sopenharmony_ci   }
1290bf215546Sopenharmony_ci
1291bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, 0);
1292bf215546Sopenharmony_ci   if (teximage_error_check(ctx, texImage, format, caller)) {
1293bf215546Sopenharmony_ci      return true;
1294bf215546Sopenharmony_ci   }
1295bf215546Sopenharmony_ci
1296bf215546Sopenharmony_ci   return false;
1297bf215546Sopenharmony_ci}
1298bf215546Sopenharmony_ci
1299bf215546Sopenharmony_ci
1300bf215546Sopenharmony_ci/**
1301bf215546Sopenharmony_ci * Do error checking for all (non-compressed) get-texture-image functions.
1302bf215546Sopenharmony_ci * \return true if any error, false if no errors.
1303bf215546Sopenharmony_ci */
1304bf215546Sopenharmony_cistatic bool
1305bf215546Sopenharmony_cigettexsubimage_error_check(struct gl_context *ctx,
1306bf215546Sopenharmony_ci                           struct gl_texture_object *texObj,
1307bf215546Sopenharmony_ci                           GLenum target, GLint level,
1308bf215546Sopenharmony_ci                           GLint xoffset, GLint yoffset, GLint zoffset,
1309bf215546Sopenharmony_ci                           GLsizei width, GLsizei height, GLsizei depth,
1310bf215546Sopenharmony_ci                           GLenum format, GLenum type, GLsizei bufSize,
1311bf215546Sopenharmony_ci                           GLvoid *pixels, const char *caller)
1312bf215546Sopenharmony_ci{
1313bf215546Sopenharmony_ci   struct gl_texture_image *texImage;
1314bf215546Sopenharmony_ci
1315bf215546Sopenharmony_ci   assert(texObj);
1316bf215546Sopenharmony_ci
1317bf215546Sopenharmony_ci   if (common_error_check(ctx, texObj, target, level, width, height, depth,
1318bf215546Sopenharmony_ci                          format, type, bufSize, pixels, caller)) {
1319bf215546Sopenharmony_ci      return true;
1320bf215546Sopenharmony_ci   }
1321bf215546Sopenharmony_ci
1322bf215546Sopenharmony_ci   if (dimensions_error_check(ctx, texObj, target, level,
1323bf215546Sopenharmony_ci                              xoffset, yoffset, zoffset,
1324bf215546Sopenharmony_ci                              width, height, depth, caller)) {
1325bf215546Sopenharmony_ci      return true;
1326bf215546Sopenharmony_ci   }
1327bf215546Sopenharmony_ci
1328bf215546Sopenharmony_ci   if (pbo_error_check(ctx, target, width, height, depth,
1329bf215546Sopenharmony_ci                       format, type, bufSize, pixels, caller)) {
1330bf215546Sopenharmony_ci      return true;
1331bf215546Sopenharmony_ci   }
1332bf215546Sopenharmony_ci
1333bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, zoffset);
1334bf215546Sopenharmony_ci   if (teximage_error_check(ctx, texImage, format, caller)) {
1335bf215546Sopenharmony_ci      return true;
1336bf215546Sopenharmony_ci   }
1337bf215546Sopenharmony_ci
1338bf215546Sopenharmony_ci   return false;
1339bf215546Sopenharmony_ci}
1340bf215546Sopenharmony_ci
1341bf215546Sopenharmony_ci
1342bf215546Sopenharmony_ci/**
1343bf215546Sopenharmony_ci * Return the width, height and depth of a texture image.
1344bf215546Sopenharmony_ci * This function must be resilient to bad parameter values since
1345bf215546Sopenharmony_ci * this is called before full error checking.
1346bf215546Sopenharmony_ci */
1347bf215546Sopenharmony_cistatic void
1348bf215546Sopenharmony_ciget_texture_image_dims(const struct gl_texture_object *texObj,
1349bf215546Sopenharmony_ci                       GLenum target, GLint level,
1350bf215546Sopenharmony_ci                       GLsizei *width, GLsizei *height, GLsizei *depth)
1351bf215546Sopenharmony_ci{
1352bf215546Sopenharmony_ci   const struct gl_texture_image *texImage = NULL;
1353bf215546Sopenharmony_ci
1354bf215546Sopenharmony_ci   if (level >= 0 && level < MAX_TEXTURE_LEVELS) {
1355bf215546Sopenharmony_ci      texImage = _mesa_select_tex_image(texObj, target, level);
1356bf215546Sopenharmony_ci   }
1357bf215546Sopenharmony_ci
1358bf215546Sopenharmony_ci   if (texImage) {
1359bf215546Sopenharmony_ci      *width = texImage->Width;
1360bf215546Sopenharmony_ci      *height = texImage->Height;
1361bf215546Sopenharmony_ci      if (target == GL_TEXTURE_CUBE_MAP) {
1362bf215546Sopenharmony_ci         *depth = 6;
1363bf215546Sopenharmony_ci      }
1364bf215546Sopenharmony_ci      else {
1365bf215546Sopenharmony_ci         *depth = texImage->Depth;
1366bf215546Sopenharmony_ci      }
1367bf215546Sopenharmony_ci   }
1368bf215546Sopenharmony_ci   else {
1369bf215546Sopenharmony_ci      *width = *height = *depth = 0;
1370bf215546Sopenharmony_ci   }
1371bf215546Sopenharmony_ci}
1372bf215546Sopenharmony_ci
1373bf215546Sopenharmony_ci
1374bf215546Sopenharmony_ci/**
1375bf215546Sopenharmony_ci * Common code for all (uncompressed) get-texture-image functions.
1376bf215546Sopenharmony_ci * \param texObj  the texture object (should not be null)
1377bf215546Sopenharmony_ci * \param target  user-provided target, or 0 for DSA
1378bf215546Sopenharmony_ci * \param level image level.
1379bf215546Sopenharmony_ci * \param format pixel data format for returned image.
1380bf215546Sopenharmony_ci * \param type pixel data type for returned image.
1381bf215546Sopenharmony_ci * \param bufSize size of the pixels data buffer.
1382bf215546Sopenharmony_ci * \param pixels returned pixel data.
1383bf215546Sopenharmony_ci * \param caller  name of calling function
1384bf215546Sopenharmony_ci */
1385bf215546Sopenharmony_cistatic void
1386bf215546Sopenharmony_ciget_texture_image(struct gl_context *ctx,
1387bf215546Sopenharmony_ci                  struct gl_texture_object *texObj,
1388bf215546Sopenharmony_ci                  GLenum target, GLint level,
1389bf215546Sopenharmony_ci                  GLint xoffset, GLint yoffset, GLint zoffset,
1390bf215546Sopenharmony_ci                  GLsizei width, GLsizei height, GLint depth,
1391bf215546Sopenharmony_ci                  GLenum format, GLenum type,
1392bf215546Sopenharmony_ci                  GLvoid *pixels, const char *caller)
1393bf215546Sopenharmony_ci{
1394bf215546Sopenharmony_ci   struct gl_texture_image *texImage;
1395bf215546Sopenharmony_ci   unsigned firstFace, numFaces, i;
1396bf215546Sopenharmony_ci   GLint imageStride;
1397bf215546Sopenharmony_ci
1398bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
1399bf215546Sopenharmony_ci
1400bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, zoffset);
1401bf215546Sopenharmony_ci   assert(texImage);  /* should have been error checked already */
1402bf215546Sopenharmony_ci
1403bf215546Sopenharmony_ci   if (_mesa_is_zero_size_texture(texImage)) {
1404bf215546Sopenharmony_ci      /* no image data to return */
1405bf215546Sopenharmony_ci      return;
1406bf215546Sopenharmony_ci   }
1407bf215546Sopenharmony_ci
1408bf215546Sopenharmony_ci   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1409bf215546Sopenharmony_ci      _mesa_debug(ctx, "%s(tex %u) format = %s, w=%d, h=%d,"
1410bf215546Sopenharmony_ci                  " dstFmt=0x%x, dstType=0x%x\n",
1411bf215546Sopenharmony_ci                  caller, texObj->Name,
1412bf215546Sopenharmony_ci                  _mesa_get_format_name(texImage->TexFormat),
1413bf215546Sopenharmony_ci                  texImage->Width, texImage->Height,
1414bf215546Sopenharmony_ci                  format, type);
1415bf215546Sopenharmony_ci   }
1416bf215546Sopenharmony_ci
1417bf215546Sopenharmony_ci   if (target == GL_TEXTURE_CUBE_MAP) {
1418bf215546Sopenharmony_ci      /* Compute stride between cube faces */
1419bf215546Sopenharmony_ci      imageStride = _mesa_image_image_stride(&ctx->Pack, width, height,
1420bf215546Sopenharmony_ci                                             format, type);
1421bf215546Sopenharmony_ci      firstFace = zoffset;
1422bf215546Sopenharmony_ci      numFaces = depth;
1423bf215546Sopenharmony_ci      zoffset = 0;
1424bf215546Sopenharmony_ci      depth = 1;
1425bf215546Sopenharmony_ci   }
1426bf215546Sopenharmony_ci   else {
1427bf215546Sopenharmony_ci      imageStride = 0;
1428bf215546Sopenharmony_ci      firstFace = _mesa_tex_target_to_face(target);
1429bf215546Sopenharmony_ci      numFaces = 1;
1430bf215546Sopenharmony_ci   }
1431bf215546Sopenharmony_ci
1432bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj)
1433bf215546Sopenharmony_ci      ctx->Pack.BufferObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
1434bf215546Sopenharmony_ci
1435bf215546Sopenharmony_ci   _mesa_lock_texture(ctx, texObj);
1436bf215546Sopenharmony_ci
1437bf215546Sopenharmony_ci   for (i = 0; i < numFaces; i++) {
1438bf215546Sopenharmony_ci      texImage = texObj->Image[firstFace + i][level];
1439bf215546Sopenharmony_ci      assert(texImage);
1440bf215546Sopenharmony_ci
1441bf215546Sopenharmony_ci      st_GetTexSubImage(ctx, xoffset, yoffset, zoffset,
1442bf215546Sopenharmony_ci                        width, height, depth,
1443bf215546Sopenharmony_ci                        format, type, pixels, texImage);
1444bf215546Sopenharmony_ci
1445bf215546Sopenharmony_ci      /* next cube face */
1446bf215546Sopenharmony_ci      pixels = (GLubyte *) pixels + imageStride;
1447bf215546Sopenharmony_ci   }
1448bf215546Sopenharmony_ci
1449bf215546Sopenharmony_ci   _mesa_unlock_texture(ctx, texObj);
1450bf215546Sopenharmony_ci}
1451bf215546Sopenharmony_ci
1452bf215546Sopenharmony_cistatic void
1453bf215546Sopenharmony_ci_get_texture_image(struct gl_context *ctx,
1454bf215546Sopenharmony_ci                  struct gl_texture_object *texObj,
1455bf215546Sopenharmony_ci                  GLenum target, GLint level,
1456bf215546Sopenharmony_ci                  GLenum format, GLenum type,
1457bf215546Sopenharmony_ci                  GLsizei bufSize, GLvoid *pixels,
1458bf215546Sopenharmony_ci                  const char *caller)
1459bf215546Sopenharmony_ci{
1460bf215546Sopenharmony_ci   GLsizei width, height, depth;
1461bf215546Sopenharmony_ci   /* EXT/ARB direct_state_access variants don't call _get_texture_image
1462bf215546Sopenharmony_ci    * with a NULL texObj */
1463bf215546Sopenharmony_ci   bool is_dsa = texObj != NULL;
1464bf215546Sopenharmony_ci
1465bf215546Sopenharmony_ci   if (!is_dsa) {
1466bf215546Sopenharmony_ci      texObj = _mesa_get_current_tex_object(ctx, target);
1467bf215546Sopenharmony_ci      assert(texObj);
1468bf215546Sopenharmony_ci   }
1469bf215546Sopenharmony_ci
1470bf215546Sopenharmony_ci
1471bf215546Sopenharmony_ci   get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1472bf215546Sopenharmony_ci
1473bf215546Sopenharmony_ci   if (getteximage_error_check(ctx, texObj, target, level,
1474bf215546Sopenharmony_ci                               width, height, depth,
1475bf215546Sopenharmony_ci                               format, type, bufSize, pixels, caller)) {
1476bf215546Sopenharmony_ci      return;
1477bf215546Sopenharmony_ci   }
1478bf215546Sopenharmony_ci
1479bf215546Sopenharmony_ci   get_texture_image(ctx, texObj, target, level,
1480bf215546Sopenharmony_ci                     0, 0, 0, width, height, depth,
1481bf215546Sopenharmony_ci                     format, type, pixels, caller);
1482bf215546Sopenharmony_ci}
1483bf215546Sopenharmony_ci
1484bf215546Sopenharmony_ci
1485bf215546Sopenharmony_civoid GLAPIENTRY
1486bf215546Sopenharmony_ci_mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format, GLenum type,
1487bf215546Sopenharmony_ci                      GLsizei bufSize, GLvoid *pixels)
1488bf215546Sopenharmony_ci{
1489bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1490bf215546Sopenharmony_ci   static const char *caller = "glGetnTexImageARB";
1491bf215546Sopenharmony_ci
1492bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, target, false)) {
1493bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1494bf215546Sopenharmony_ci      return;
1495bf215546Sopenharmony_ci   }
1496bf215546Sopenharmony_ci
1497bf215546Sopenharmony_ci   _get_texture_image(ctx, NULL, target, level, format, type,
1498bf215546Sopenharmony_ci                      bufSize, pixels, caller);
1499bf215546Sopenharmony_ci}
1500bf215546Sopenharmony_ci
1501bf215546Sopenharmony_ci
1502bf215546Sopenharmony_civoid GLAPIENTRY
1503bf215546Sopenharmony_ci_mesa_GetTexImage(GLenum target, GLint level, GLenum format, GLenum type,
1504bf215546Sopenharmony_ci                  GLvoid *pixels )
1505bf215546Sopenharmony_ci{
1506bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1507bf215546Sopenharmony_ci   static const char *caller = "glGetTexImage";
1508bf215546Sopenharmony_ci
1509bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, target, false)) {
1510bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1511bf215546Sopenharmony_ci      return;
1512bf215546Sopenharmony_ci   }
1513bf215546Sopenharmony_ci
1514bf215546Sopenharmony_ci   _get_texture_image(ctx, NULL, target, level, format, type,
1515bf215546Sopenharmony_ci                      INT_MAX, pixels, caller);
1516bf215546Sopenharmony_ci}
1517bf215546Sopenharmony_ci
1518bf215546Sopenharmony_ci
1519bf215546Sopenharmony_civoid GLAPIENTRY
1520bf215546Sopenharmony_ci_mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type,
1521bf215546Sopenharmony_ci                      GLsizei bufSize, GLvoid *pixels)
1522bf215546Sopenharmony_ci{
1523bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1524bf215546Sopenharmony_ci   static const char *caller = "glGetTextureImage";
1525bf215546Sopenharmony_ci   struct gl_texture_object *texObj =
1526bf215546Sopenharmony_ci      _mesa_lookup_texture_err(ctx, texture, caller);
1527bf215546Sopenharmony_ci
1528bf215546Sopenharmony_ci   if (!texObj) {
1529bf215546Sopenharmony_ci      return;
1530bf215546Sopenharmony_ci   }
1531bf215546Sopenharmony_ci
1532bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1533bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1534bf215546Sopenharmony_ci      return;
1535bf215546Sopenharmony_ci   }
1536bf215546Sopenharmony_ci
1537bf215546Sopenharmony_ci   _get_texture_image(ctx, texObj, texObj->Target, level, format, type,
1538bf215546Sopenharmony_ci                      bufSize, pixels, caller);
1539bf215546Sopenharmony_ci}
1540bf215546Sopenharmony_ci
1541bf215546Sopenharmony_ci
1542bf215546Sopenharmony_civoid GLAPIENTRY
1543bf215546Sopenharmony_ci_mesa_GetTextureImageEXT(GLuint texture, GLenum target, GLint level,
1544bf215546Sopenharmony_ci                         GLenum format, GLenum type, GLvoid *pixels)
1545bf215546Sopenharmony_ci{
1546bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1547bf215546Sopenharmony_ci   static const char *caller = "glGetTextureImageEXT";
1548bf215546Sopenharmony_ci   struct gl_texture_object *texObj =
1549bf215546Sopenharmony_ci      _mesa_lookup_or_create_texture(ctx, target, texture,
1550bf215546Sopenharmony_ci                                     false, true, caller);
1551bf215546Sopenharmony_ci
1552bf215546Sopenharmony_ci   if (!texObj) {
1553bf215546Sopenharmony_ci      return;
1554bf215546Sopenharmony_ci   }
1555bf215546Sopenharmony_ci
1556bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, target, true)) {
1557bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1558bf215546Sopenharmony_ci      return;
1559bf215546Sopenharmony_ci   }
1560bf215546Sopenharmony_ci
1561bf215546Sopenharmony_ci   _get_texture_image(ctx, texObj, target, level, format, type,
1562bf215546Sopenharmony_ci                      INT_MAX, pixels, caller);
1563bf215546Sopenharmony_ci}
1564bf215546Sopenharmony_ci
1565bf215546Sopenharmony_ci
1566bf215546Sopenharmony_civoid GLAPIENTRY
1567bf215546Sopenharmony_ci_mesa_GetMultiTexImageEXT(GLenum texunit, GLenum target, GLint level,
1568bf215546Sopenharmony_ci                          GLenum format, GLenum type, GLvoid *pixels)
1569bf215546Sopenharmony_ci{
1570bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1571bf215546Sopenharmony_ci   GLsizei width, height, depth;
1572bf215546Sopenharmony_ci   static const char *caller = "glGetMultiTexImageEXT";
1573bf215546Sopenharmony_ci
1574bf215546Sopenharmony_ci   struct gl_texture_object *texObj =
1575bf215546Sopenharmony_ci      _mesa_get_texobj_by_target_and_texunit(ctx, target,
1576bf215546Sopenharmony_ci                                             texunit - GL_TEXTURE0,
1577bf215546Sopenharmony_ci                                             false,
1578bf215546Sopenharmony_ci                                             caller);
1579bf215546Sopenharmony_ci
1580bf215546Sopenharmony_ci   if (!texObj) {
1581bf215546Sopenharmony_ci      return;
1582bf215546Sopenharmony_ci   }
1583bf215546Sopenharmony_ci
1584bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1585bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1586bf215546Sopenharmony_ci      return;
1587bf215546Sopenharmony_ci   }
1588bf215546Sopenharmony_ci
1589bf215546Sopenharmony_ci   get_texture_image_dims(texObj, texObj->Target, level,
1590bf215546Sopenharmony_ci                          &width, &height, &depth);
1591bf215546Sopenharmony_ci
1592bf215546Sopenharmony_ci   if (getteximage_error_check(ctx, texObj, texObj->Target, level,
1593bf215546Sopenharmony_ci                               width, height, depth,
1594bf215546Sopenharmony_ci                               format, type, INT_MAX, pixels, caller)) {
1595bf215546Sopenharmony_ci      return;
1596bf215546Sopenharmony_ci   }
1597bf215546Sopenharmony_ci
1598bf215546Sopenharmony_ci   get_texture_image(ctx, texObj, texObj->Target, level,
1599bf215546Sopenharmony_ci                     0, 0, 0, width, height, depth,
1600bf215546Sopenharmony_ci                     format, type, pixels, caller);
1601bf215546Sopenharmony_ci}
1602bf215546Sopenharmony_ci
1603bf215546Sopenharmony_ci
1604bf215546Sopenharmony_civoid GLAPIENTRY
1605bf215546Sopenharmony_ci_mesa_GetTextureSubImage(GLuint texture, GLint level,
1606bf215546Sopenharmony_ci                         GLint xoffset, GLint yoffset, GLint zoffset,
1607bf215546Sopenharmony_ci                         GLsizei width, GLsizei height, GLsizei depth,
1608bf215546Sopenharmony_ci                         GLenum format, GLenum type, GLsizei bufSize,
1609bf215546Sopenharmony_ci                         void *pixels)
1610bf215546Sopenharmony_ci{
1611bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1612bf215546Sopenharmony_ci   static const char *caller = "glGetTextureSubImage";
1613bf215546Sopenharmony_ci   struct gl_texture_object *texObj =
1614bf215546Sopenharmony_ci      _mesa_lookup_texture_err(ctx, texture, caller);
1615bf215546Sopenharmony_ci
1616bf215546Sopenharmony_ci   if (!texObj) {
1617bf215546Sopenharmony_ci      return;
1618bf215546Sopenharmony_ci   }
1619bf215546Sopenharmony_ci
1620bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1621bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1622bf215546Sopenharmony_ci                  "%s(buffer/multisample texture)", caller);
1623bf215546Sopenharmony_ci      return;
1624bf215546Sopenharmony_ci   }
1625bf215546Sopenharmony_ci
1626bf215546Sopenharmony_ci   if (gettexsubimage_error_check(ctx, texObj, texObj->Target, level,
1627bf215546Sopenharmony_ci                                  xoffset, yoffset, zoffset,
1628bf215546Sopenharmony_ci                                  width, height, depth,
1629bf215546Sopenharmony_ci                                  format, type, bufSize, pixels, caller)) {
1630bf215546Sopenharmony_ci      return;
1631bf215546Sopenharmony_ci   }
1632bf215546Sopenharmony_ci
1633bf215546Sopenharmony_ci   get_texture_image(ctx, texObj, texObj->Target, level,
1634bf215546Sopenharmony_ci                     xoffset, yoffset, zoffset, width, height, depth,
1635bf215546Sopenharmony_ci                     format, type, pixels, caller);
1636bf215546Sopenharmony_ci}
1637bf215546Sopenharmony_ci
1638bf215546Sopenharmony_ci
1639bf215546Sopenharmony_ci
1640bf215546Sopenharmony_ci/**
1641bf215546Sopenharmony_ci * Compute the number of bytes which will be written when retrieving
1642bf215546Sopenharmony_ci * a sub-region of a compressed texture.
1643bf215546Sopenharmony_ci */
1644bf215546Sopenharmony_cistatic GLsizei
1645bf215546Sopenharmony_cipacked_compressed_size(GLuint dimensions, mesa_format format,
1646bf215546Sopenharmony_ci                       GLsizei width, GLsizei height, GLsizei depth,
1647bf215546Sopenharmony_ci                       const struct gl_pixelstore_attrib *packing)
1648bf215546Sopenharmony_ci{
1649bf215546Sopenharmony_ci   struct compressed_pixelstore st;
1650bf215546Sopenharmony_ci   GLsizei totalBytes;
1651bf215546Sopenharmony_ci
1652bf215546Sopenharmony_ci   _mesa_compute_compressed_pixelstore(dimensions, format,
1653bf215546Sopenharmony_ci                                       width, height, depth,
1654bf215546Sopenharmony_ci                                       packing, &st);
1655bf215546Sopenharmony_ci   totalBytes =
1656bf215546Sopenharmony_ci      (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow +
1657bf215546Sopenharmony_ci      st.SkipBytes +
1658bf215546Sopenharmony_ci      (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow +
1659bf215546Sopenharmony_ci      st.CopyBytesPerRow;
1660bf215546Sopenharmony_ci
1661bf215546Sopenharmony_ci   return totalBytes;
1662bf215546Sopenharmony_ci}
1663bf215546Sopenharmony_ci
1664bf215546Sopenharmony_ci
1665bf215546Sopenharmony_ci/**
1666bf215546Sopenharmony_ci * Do error checking for getting compressed texture images.
1667bf215546Sopenharmony_ci * \return true if any error, false if no errors.
1668bf215546Sopenharmony_ci */
1669bf215546Sopenharmony_cistatic bool
1670bf215546Sopenharmony_cigetcompressedteximage_error_check(struct gl_context *ctx,
1671bf215546Sopenharmony_ci                                  struct gl_texture_object *texObj,
1672bf215546Sopenharmony_ci                                  GLenum target, GLint level,
1673bf215546Sopenharmony_ci                                  GLint xoffset, GLint yoffset, GLint zoffset,
1674bf215546Sopenharmony_ci                                  GLsizei width, GLsizei height, GLsizei depth,
1675bf215546Sopenharmony_ci                                  GLsizei bufSize, GLvoid *pixels,
1676bf215546Sopenharmony_ci                                  const char *caller)
1677bf215546Sopenharmony_ci{
1678bf215546Sopenharmony_ci   struct gl_texture_image *texImage;
1679bf215546Sopenharmony_ci   GLint maxLevels;
1680bf215546Sopenharmony_ci   GLsizei totalBytes;
1681bf215546Sopenharmony_ci   GLuint dimensions;
1682bf215546Sopenharmony_ci
1683bf215546Sopenharmony_ci   assert(texObj);
1684bf215546Sopenharmony_ci
1685bf215546Sopenharmony_ci   if (texObj->Target == 0) {
1686bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
1687bf215546Sopenharmony_ci      return true;
1688bf215546Sopenharmony_ci   }
1689bf215546Sopenharmony_ci
1690bf215546Sopenharmony_ci   maxLevels = _mesa_max_texture_levels(ctx, target);
1691bf215546Sopenharmony_ci   if (level < 0 || level >= maxLevels) {
1692bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
1693bf215546Sopenharmony_ci                  "%s(bad level = %d)", caller, level);
1694bf215546Sopenharmony_ci      return true;
1695bf215546Sopenharmony_ci   }
1696bf215546Sopenharmony_ci
1697bf215546Sopenharmony_ci   if (dimensions_error_check(ctx, texObj, target, level,
1698bf215546Sopenharmony_ci                              xoffset, yoffset, zoffset,
1699bf215546Sopenharmony_ci                              width, height, depth, caller)) {
1700bf215546Sopenharmony_ci      return true;
1701bf215546Sopenharmony_ci   }
1702bf215546Sopenharmony_ci
1703bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, zoffset);
1704bf215546Sopenharmony_ci   assert(texImage);
1705bf215546Sopenharmony_ci
1706bf215546Sopenharmony_ci   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
1707bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1708bf215546Sopenharmony_ci                  "%s(texture is not compressed)", caller);
1709bf215546Sopenharmony_ci      return true;
1710bf215546Sopenharmony_ci   }
1711bf215546Sopenharmony_ci
1712bf215546Sopenharmony_ci   /* Check for invalid pixel storage modes */
1713bf215546Sopenharmony_ci   dimensions = _mesa_get_texture_dimensions(texObj->Target);
1714bf215546Sopenharmony_ci   if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
1715bf215546Sopenharmony_ci                                                   &ctx->Pack,
1716bf215546Sopenharmony_ci                                                   caller)) {
1717bf215546Sopenharmony_ci      return true;
1718bf215546Sopenharmony_ci   }
1719bf215546Sopenharmony_ci
1720bf215546Sopenharmony_ci   /* Compute number of bytes that may be touched in the dest buffer */
1721bf215546Sopenharmony_ci   totalBytes = packed_compressed_size(dimensions, texImage->TexFormat,
1722bf215546Sopenharmony_ci                                       width, height, depth,
1723bf215546Sopenharmony_ci                                       &ctx->Pack);
1724bf215546Sopenharmony_ci
1725bf215546Sopenharmony_ci   /* Do dest buffer bounds checking */
1726bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj) {
1727bf215546Sopenharmony_ci      /* do bounds checking on PBO write */
1728bf215546Sopenharmony_ci      if ((GLubyte *) pixels + totalBytes >
1729bf215546Sopenharmony_ci          (GLubyte *) ctx->Pack.BufferObj->Size) {
1730bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1731bf215546Sopenharmony_ci                     "%s(out of bounds PBO access)", caller);
1732bf215546Sopenharmony_ci         return true;
1733bf215546Sopenharmony_ci      }
1734bf215546Sopenharmony_ci
1735bf215546Sopenharmony_ci      /* make sure PBO is not mapped */
1736bf215546Sopenharmony_ci      if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1737bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller);
1738bf215546Sopenharmony_ci         return true;
1739bf215546Sopenharmony_ci      }
1740bf215546Sopenharmony_ci   }
1741bf215546Sopenharmony_ci   else {
1742bf215546Sopenharmony_ci      /* do bounds checking on writing to client memory */
1743bf215546Sopenharmony_ci      if (totalBytes > bufSize) {
1744bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1745bf215546Sopenharmony_ci                     "%s(out of bounds access: bufSize (%d) is too small)",
1746bf215546Sopenharmony_ci                     caller, bufSize);
1747bf215546Sopenharmony_ci         return true;
1748bf215546Sopenharmony_ci      }
1749bf215546Sopenharmony_ci   }
1750bf215546Sopenharmony_ci
1751bf215546Sopenharmony_ci   if (!ctx->Pack.BufferObj && !pixels) {
1752bf215546Sopenharmony_ci      /* not an error, but do nothing */
1753bf215546Sopenharmony_ci      return true;
1754bf215546Sopenharmony_ci   }
1755bf215546Sopenharmony_ci
1756bf215546Sopenharmony_ci   return false;
1757bf215546Sopenharmony_ci}
1758bf215546Sopenharmony_ci
1759bf215546Sopenharmony_ci
1760bf215546Sopenharmony_ci/**
1761bf215546Sopenharmony_ci * Common helper for all glGetCompressed-teximage functions.
1762bf215546Sopenharmony_ci */
1763bf215546Sopenharmony_cistatic void
1764bf215546Sopenharmony_ciget_compressed_texture_image(struct gl_context *ctx,
1765bf215546Sopenharmony_ci                             struct gl_texture_object *texObj,
1766bf215546Sopenharmony_ci                             GLenum target, GLint level,
1767bf215546Sopenharmony_ci                             GLint xoffset, GLint yoffset, GLint zoffset,
1768bf215546Sopenharmony_ci                             GLsizei width, GLsizei height, GLint depth,
1769bf215546Sopenharmony_ci                             GLvoid *pixels,
1770bf215546Sopenharmony_ci                             const char *caller)
1771bf215546Sopenharmony_ci{
1772bf215546Sopenharmony_ci   struct gl_texture_image *texImage;
1773bf215546Sopenharmony_ci   unsigned firstFace, numFaces, i, imageStride;
1774bf215546Sopenharmony_ci
1775bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
1776bf215546Sopenharmony_ci
1777bf215546Sopenharmony_ci   texImage = select_tex_image(texObj, target, level, zoffset);
1778bf215546Sopenharmony_ci   assert(texImage);  /* should have been error checked already */
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_ci   if (_mesa_is_zero_size_texture(texImage))
1781bf215546Sopenharmony_ci      return;
1782bf215546Sopenharmony_ci
1783bf215546Sopenharmony_ci   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1784bf215546Sopenharmony_ci      _mesa_debug(ctx,
1785bf215546Sopenharmony_ci                  "%s(tex %u) format = %s, w=%d, h=%d\n",
1786bf215546Sopenharmony_ci                  caller, texObj->Name,
1787bf215546Sopenharmony_ci                  _mesa_get_format_name(texImage->TexFormat),
1788bf215546Sopenharmony_ci                  texImage->Width, texImage->Height);
1789bf215546Sopenharmony_ci   }
1790bf215546Sopenharmony_ci
1791bf215546Sopenharmony_ci   if (target == GL_TEXTURE_CUBE_MAP) {
1792bf215546Sopenharmony_ci      struct compressed_pixelstore store;
1793bf215546Sopenharmony_ci
1794bf215546Sopenharmony_ci      /* Compute image stride between cube faces */
1795bf215546Sopenharmony_ci      _mesa_compute_compressed_pixelstore(2, texImage->TexFormat,
1796bf215546Sopenharmony_ci                                          width, height, depth,
1797bf215546Sopenharmony_ci                                          &ctx->Pack, &store);
1798bf215546Sopenharmony_ci      imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice;
1799bf215546Sopenharmony_ci
1800bf215546Sopenharmony_ci      firstFace = zoffset;
1801bf215546Sopenharmony_ci      numFaces = depth;
1802bf215546Sopenharmony_ci      zoffset = 0;
1803bf215546Sopenharmony_ci      depth = 1;
1804bf215546Sopenharmony_ci   }
1805bf215546Sopenharmony_ci   else {
1806bf215546Sopenharmony_ci      imageStride = 0;
1807bf215546Sopenharmony_ci      firstFace = _mesa_tex_target_to_face(target);
1808bf215546Sopenharmony_ci      numFaces = 1;
1809bf215546Sopenharmony_ci   }
1810bf215546Sopenharmony_ci
1811bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj)
1812bf215546Sopenharmony_ci      ctx->Pack.BufferObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
1813bf215546Sopenharmony_ci
1814bf215546Sopenharmony_ci   _mesa_lock_texture(ctx, texObj);
1815bf215546Sopenharmony_ci
1816bf215546Sopenharmony_ci   for (i = 0; i < numFaces; i++) {
1817bf215546Sopenharmony_ci      texImage = texObj->Image[firstFace + i][level];
1818bf215546Sopenharmony_ci      assert(texImage);
1819bf215546Sopenharmony_ci
1820bf215546Sopenharmony_ci      get_compressed_texsubimage_sw(ctx, texImage,
1821bf215546Sopenharmony_ci                                    xoffset, yoffset, zoffset,
1822bf215546Sopenharmony_ci                                    width, height, depth, pixels);
1823bf215546Sopenharmony_ci
1824bf215546Sopenharmony_ci      /* next cube face */
1825bf215546Sopenharmony_ci      pixels = (GLubyte *) pixels + imageStride;
1826bf215546Sopenharmony_ci   }
1827bf215546Sopenharmony_ci
1828bf215546Sopenharmony_ci   _mesa_unlock_texture(ctx, texObj);
1829bf215546Sopenharmony_ci}
1830bf215546Sopenharmony_ci
1831bf215546Sopenharmony_ci
1832bf215546Sopenharmony_civoid GLAPIENTRY
1833bf215546Sopenharmony_ci_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1834bf215546Sopenharmony_ci                                GLvoid *pixels)
1835bf215546Sopenharmony_ci{
1836bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1837bf215546Sopenharmony_ci   static const char *caller = "glGetnCompressedTexImageARB";
1838bf215546Sopenharmony_ci   GLsizei width, height, depth;
1839bf215546Sopenharmony_ci   struct gl_texture_object *texObj;
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, target, false)) {
1842bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1843bf215546Sopenharmony_ci      return;
1844bf215546Sopenharmony_ci   }
1845bf215546Sopenharmony_ci
1846bf215546Sopenharmony_ci   texObj = _mesa_get_current_tex_object(ctx, target);
1847bf215546Sopenharmony_ci   assert(texObj);
1848bf215546Sopenharmony_ci
1849bf215546Sopenharmony_ci   get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1850bf215546Sopenharmony_ci
1851bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, target, level,
1852bf215546Sopenharmony_ci                                         0, 0, 0, width, height, depth,
1853bf215546Sopenharmony_ci                                         INT_MAX, pixels, caller)) {
1854bf215546Sopenharmony_ci      return;
1855bf215546Sopenharmony_ci   }
1856bf215546Sopenharmony_ci
1857bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, target, level,
1858bf215546Sopenharmony_ci                                0, 0, 0, width, height, depth,
1859bf215546Sopenharmony_ci                                pixels, caller);
1860bf215546Sopenharmony_ci}
1861bf215546Sopenharmony_ci
1862bf215546Sopenharmony_ci
1863bf215546Sopenharmony_civoid GLAPIENTRY
1864bf215546Sopenharmony_ci_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels)
1865bf215546Sopenharmony_ci{
1866bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1867bf215546Sopenharmony_ci   static const char *caller = "glGetCompressedTexImage";
1868bf215546Sopenharmony_ci   GLsizei width, height, depth;
1869bf215546Sopenharmony_ci   struct gl_texture_object *texObj;
1870bf215546Sopenharmony_ci
1871bf215546Sopenharmony_ci   if (!legal_getteximage_target(ctx, target, false)) {
1872bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1873bf215546Sopenharmony_ci      return;
1874bf215546Sopenharmony_ci   }
1875bf215546Sopenharmony_ci
1876bf215546Sopenharmony_ci   texObj = _mesa_get_current_tex_object(ctx, target);
1877bf215546Sopenharmony_ci   assert(texObj);
1878bf215546Sopenharmony_ci
1879bf215546Sopenharmony_ci   get_texture_image_dims(texObj, target, level,
1880bf215546Sopenharmony_ci                          &width, &height, &depth);
1881bf215546Sopenharmony_ci
1882bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, target, level,
1883bf215546Sopenharmony_ci                                         0, 0, 0, width, height, depth,
1884bf215546Sopenharmony_ci                                         INT_MAX, pixels, caller)) {
1885bf215546Sopenharmony_ci      return;
1886bf215546Sopenharmony_ci   }
1887bf215546Sopenharmony_ci
1888bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, target, level,
1889bf215546Sopenharmony_ci                                0, 0, 0, width, height, depth,
1890bf215546Sopenharmony_ci                                pixels, caller);
1891bf215546Sopenharmony_ci}
1892bf215546Sopenharmony_ci
1893bf215546Sopenharmony_ci
1894bf215546Sopenharmony_civoid GLAPIENTRY
1895bf215546Sopenharmony_ci_mesa_GetCompressedTextureImageEXT(GLuint texture, GLenum target, GLint level,
1896bf215546Sopenharmony_ci                                   GLvoid *pixels)
1897bf215546Sopenharmony_ci{
1898bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1899bf215546Sopenharmony_ci   struct gl_texture_object*  texObj;
1900bf215546Sopenharmony_ci   GLsizei width, height, depth;
1901bf215546Sopenharmony_ci   static const char *caller = "glGetCompressedTextureImageEXT";
1902bf215546Sopenharmony_ci
1903bf215546Sopenharmony_ci   texObj = _mesa_lookup_or_create_texture(ctx, target, texture,
1904bf215546Sopenharmony_ci                                           false, true, caller);
1905bf215546Sopenharmony_ci
1906bf215546Sopenharmony_ci   get_texture_image_dims(texObj, texObj->Target, level,
1907bf215546Sopenharmony_ci                          &width, &height, &depth);
1908bf215546Sopenharmony_ci
1909bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1910bf215546Sopenharmony_ci                                         0, 0, 0, width, height, depth,
1911bf215546Sopenharmony_ci                                         INT_MAX, pixels, caller)) {
1912bf215546Sopenharmony_ci      return;
1913bf215546Sopenharmony_ci   }
1914bf215546Sopenharmony_ci
1915bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1916bf215546Sopenharmony_ci                                0, 0, 0, width, height, depth,
1917bf215546Sopenharmony_ci                                pixels, caller);
1918bf215546Sopenharmony_ci}
1919bf215546Sopenharmony_ci
1920bf215546Sopenharmony_ci
1921bf215546Sopenharmony_civoid GLAPIENTRY
1922bf215546Sopenharmony_ci_mesa_GetCompressedMultiTexImageEXT(GLenum texunit, GLenum target, GLint level,
1923bf215546Sopenharmony_ci                                    GLvoid *pixels)
1924bf215546Sopenharmony_ci{
1925bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1926bf215546Sopenharmony_ci   struct gl_texture_object*  texObj;
1927bf215546Sopenharmony_ci   GLsizei width, height, depth;
1928bf215546Sopenharmony_ci   static const char *caller = "glGetCompressedMultiTexImageEXT";
1929bf215546Sopenharmony_ci
1930bf215546Sopenharmony_ci   texObj = _mesa_get_texobj_by_target_and_texunit(ctx, target,
1931bf215546Sopenharmony_ci                                                   texunit - GL_TEXTURE0,
1932bf215546Sopenharmony_ci                                                   false,
1933bf215546Sopenharmony_ci                                                   caller);
1934bf215546Sopenharmony_ci
1935bf215546Sopenharmony_ci   get_texture_image_dims(texObj, texObj->Target, level,
1936bf215546Sopenharmony_ci                          &width, &height, &depth);
1937bf215546Sopenharmony_ci
1938bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1939bf215546Sopenharmony_ci                                         0, 0, 0, width, height, depth,
1940bf215546Sopenharmony_ci                                         INT_MAX, pixels, caller)) {
1941bf215546Sopenharmony_ci      return;
1942bf215546Sopenharmony_ci   }
1943bf215546Sopenharmony_ci
1944bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1945bf215546Sopenharmony_ci                                0, 0, 0, width, height, depth,
1946bf215546Sopenharmony_ci                                pixels, caller);
1947bf215546Sopenharmony_ci}
1948bf215546Sopenharmony_ci
1949bf215546Sopenharmony_ci
1950bf215546Sopenharmony_civoid GLAPIENTRY
1951bf215546Sopenharmony_ci_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
1952bf215546Sopenharmony_ci                                GLsizei bufSize, GLvoid *pixels)
1953bf215546Sopenharmony_ci{
1954bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1955bf215546Sopenharmony_ci   static const char *caller = "glGetCompressedTextureImage";
1956bf215546Sopenharmony_ci   GLsizei width, height, depth;
1957bf215546Sopenharmony_ci   struct gl_texture_object *texObj =
1958bf215546Sopenharmony_ci      _mesa_lookup_texture_err(ctx, texture, caller);
1959bf215546Sopenharmony_ci
1960bf215546Sopenharmony_ci   if (!texObj) {
1961bf215546Sopenharmony_ci      return;
1962bf215546Sopenharmony_ci   }
1963bf215546Sopenharmony_ci
1964bf215546Sopenharmony_ci   get_texture_image_dims(texObj, texObj->Target, level,
1965bf215546Sopenharmony_ci                          &width, &height, &depth);
1966bf215546Sopenharmony_ci
1967bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1968bf215546Sopenharmony_ci                                         0, 0, 0, width, height, depth,
1969bf215546Sopenharmony_ci                                         bufSize, pixels, caller)) {
1970bf215546Sopenharmony_ci      return;
1971bf215546Sopenharmony_ci   }
1972bf215546Sopenharmony_ci
1973bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1974bf215546Sopenharmony_ci                                0, 0, 0, width, height, depth,
1975bf215546Sopenharmony_ci                                pixels, caller);
1976bf215546Sopenharmony_ci}
1977bf215546Sopenharmony_ci
1978bf215546Sopenharmony_ci
1979bf215546Sopenharmony_civoid GLAPIENTRY
1980bf215546Sopenharmony_ci_mesa_GetCompressedTextureSubImage(GLuint texture, GLint level,
1981bf215546Sopenharmony_ci                                   GLint xoffset, GLint yoffset,
1982bf215546Sopenharmony_ci                                   GLint zoffset, GLsizei width,
1983bf215546Sopenharmony_ci                                   GLsizei height, GLsizei depth,
1984bf215546Sopenharmony_ci                                   GLsizei bufSize, void *pixels)
1985bf215546Sopenharmony_ci{
1986bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1987bf215546Sopenharmony_ci   static const char *caller = "glGetCompressedTextureImage";
1988bf215546Sopenharmony_ci   struct gl_texture_object *texObj = NULL;
1989bf215546Sopenharmony_ci
1990bf215546Sopenharmony_ci   texObj = _mesa_lookup_texture_err(ctx, texture, caller);
1991bf215546Sopenharmony_ci   if (!texObj) {
1992bf215546Sopenharmony_ci      return;
1993bf215546Sopenharmony_ci   }
1994bf215546Sopenharmony_ci
1995bf215546Sopenharmony_ci   if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1996bf215546Sopenharmony_ci                                         xoffset, yoffset, zoffset,
1997bf215546Sopenharmony_ci                                         width, height, depth,
1998bf215546Sopenharmony_ci                                         bufSize, pixels, caller)) {
1999bf215546Sopenharmony_ci      return;
2000bf215546Sopenharmony_ci   }
2001bf215546Sopenharmony_ci
2002bf215546Sopenharmony_ci   get_compressed_texture_image(ctx, texObj, texObj->Target, level,
2003bf215546Sopenharmony_ci                                xoffset, yoffset, zoffset,
2004bf215546Sopenharmony_ci                                width, height, depth,
2005bf215546Sopenharmony_ci                                pixels, caller);
2006bf215546Sopenharmony_ci}
2007