OSDN Git Service

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