• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
type_needs_clamping(GLenum type)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
get_tex_depth(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
get_tex_depth_stencil(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
get_tex_stencil(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
get_tex_ycbcr(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
teximage_needs_rebase(mesa_format texFormat,GLenum baseFormat,bool is_compressed,uint8_t * rebaseSwizzle)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
get_tex_rgba_compressed(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage,GLbitfield transferOps)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
_mesa_base_pack_format(GLenum format)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
get_tex_rgba_uncompressed(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage,GLbitfield transferOps)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
get_tex_rgba(struct gl_context * ctx,GLuint dimensions,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
get_tex_memcpy(struct gl_context * ctx,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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 * 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
_mesa_GetTexSubImage_sw(struct gl_context * ctx,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,struct gl_texture_image * texImage)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
_mesa_GetCompressedTexSubImage_sw(struct gl_context * ctx,struct gl_texture_image * texImage,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLint height,GLint depth,GLvoid * img)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
legal_getteximage_target(struct gl_context * ctx,GLenum target,bool dsa)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 *
select_tex_image(const struct gl_texture_object * texObj,GLenum target,GLint level,GLint zoffset)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
dimensions_error_check(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,const char * caller)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
pbo_error_check(struct gl_context * ctx,GLenum target,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei clientMemSize,GLvoid * pixels,const char * caller)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
getteximage_error_check(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei bufSize,GLvoid * pixels,const char * caller)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
get_texture_image_dims(const struct gl_texture_object * texObj,GLenum target,GLint level,GLsizei * width,GLsizei * height,GLsizei * depth)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
get_texture_image(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLenum format,GLenum type,GLvoid * pixels,const char * caller)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
_mesa_GetnTexImageARB(GLenum target,GLint level,GLenum format,GLenum type,GLsizei bufSize,GLvoid * pixels)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
_mesa_GetTexImage(GLenum target,GLint level,GLenum format,GLenum type,GLvoid * pixels)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
_mesa_GetTextureImage(GLuint texture,GLint level,GLenum format,GLenum type,GLsizei bufSize,GLvoid * pixels)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    if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1433       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1434       return;
1435    }
1436 
1437    get_texture_image_dims(texObj, texObj->Target, level,
1438                           &width, &height, &depth);
1439 
1440    if (getteximage_error_check(ctx, texObj, texObj->Target, level,
1441                                0, 0, 0, width, height, depth,
1442                                format, type, bufSize, pixels, caller)) {
1443       return;
1444    }
1445 
1446    get_texture_image(ctx, texObj, texObj->Target, level,
1447                      0, 0, 0, width, height, depth,
1448                      format, type, pixels, caller);
1449 }
1450 
1451 
1452 void GLAPIENTRY
_mesa_GetTextureSubImage(GLuint texture,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,GLsizei bufSize,void * pixels)1453 _mesa_GetTextureSubImage(GLuint texture, GLint level,
1454                          GLint xoffset, GLint yoffset, GLint zoffset,
1455                          GLsizei width, GLsizei height, GLsizei depth,
1456                          GLenum format, GLenum type, GLsizei bufSize,
1457                          void *pixels)
1458 {
1459    GET_CURRENT_CONTEXT(ctx);
1460    static const char *caller = "glGetTextureSubImage";
1461    struct gl_texture_object *texObj =
1462       _mesa_lookup_texture_err(ctx, texture, caller);
1463 
1464    if (!texObj) {
1465       return;
1466    }
1467 
1468    if (getteximage_error_check(ctx, texObj, texObj->Target, level,
1469                                xoffset, yoffset, zoffset, width, height, depth,
1470                                format, type, bufSize, pixels, caller)) {
1471       return;
1472    }
1473 
1474    get_texture_image(ctx, texObj, texObj->Target, level,
1475                      xoffset, yoffset, zoffset, width, height, depth,
1476                      format, type, pixels, caller);
1477 }
1478 
1479 
1480 
1481 /**
1482  * Compute the number of bytes which will be written when retrieving
1483  * a sub-region of a compressed texture.
1484  */
1485 static GLsizei
packed_compressed_size(GLuint dimensions,mesa_format format,GLsizei width,GLsizei height,GLsizei depth,const struct gl_pixelstore_attrib * packing)1486 packed_compressed_size(GLuint dimensions, mesa_format format,
1487                        GLsizei width, GLsizei height, GLsizei depth,
1488                        const struct gl_pixelstore_attrib *packing)
1489 {
1490    struct compressed_pixelstore st;
1491    GLsizei totalBytes;
1492 
1493    _mesa_compute_compressed_pixelstore(dimensions, format,
1494                                        width, height, depth,
1495                                        packing, &st);
1496    totalBytes =
1497       (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow +
1498       st.SkipBytes +
1499       (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow +
1500       st.CopyBytesPerRow;
1501 
1502    return totalBytes;
1503 }
1504 
1505 
1506 /**
1507  * Do error checking for getting compressed texture images.
1508  * \return true if any error, false if no errors.
1509  */
1510 static bool
getcompressedteximage_error_check(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLsizei bufSize,GLvoid * pixels,const char * caller)1511 getcompressedteximage_error_check(struct gl_context *ctx,
1512                                   struct gl_texture_object *texObj,
1513                                   GLenum target, GLint level,
1514                                   GLint xoffset, GLint yoffset, GLint zoffset,
1515                                   GLsizei width, GLsizei height, GLsizei depth,
1516                                   GLsizei bufSize, GLvoid *pixels,
1517                                   const char *caller)
1518 {
1519    struct gl_texture_image *texImage;
1520    GLint maxLevels;
1521    GLsizei totalBytes;
1522    GLuint dimensions;
1523 
1524    assert(texObj);
1525 
1526    if (texObj->Target == 0) {
1527       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
1528       return true;
1529    }
1530 
1531    maxLevels = _mesa_max_texture_levels(ctx, target);
1532    if (level < 0 || level >= maxLevels) {
1533       _mesa_error(ctx, GL_INVALID_VALUE,
1534                   "%s(bad level = %d)", caller, level);
1535       return true;
1536    }
1537 
1538    if (dimensions_error_check(ctx, texObj, target, level,
1539                               xoffset, yoffset, zoffset,
1540                               width, height, depth, caller)) {
1541       return true;
1542    }
1543 
1544    texImage = select_tex_image(texObj, target, level, zoffset);
1545    assert(texImage);
1546 
1547    if (!_mesa_is_format_compressed(texImage->TexFormat)) {
1548       _mesa_error(ctx, GL_INVALID_OPERATION,
1549                   "%s(texture is not compressed)", caller);
1550       return true;
1551    }
1552 
1553    /* Check for invalid pixel storage modes */
1554    dimensions = _mesa_get_texture_dimensions(texObj->Target);
1555    if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
1556                                                    &ctx->Pack,
1557                                                    caller)) {
1558       return true;
1559    }
1560 
1561    /* Compute number of bytes that may be touched in the dest buffer */
1562    totalBytes = packed_compressed_size(dimensions, texImage->TexFormat,
1563                                        width, height, depth,
1564                                        &ctx->Pack);
1565 
1566    /* Do dest buffer bounds checking */
1567    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1568       /* do bounds checking on PBO write */
1569       if ((GLubyte *) pixels + totalBytes >
1570           (GLubyte *) ctx->Pack.BufferObj->Size) {
1571          _mesa_error(ctx, GL_INVALID_OPERATION,
1572                      "%s(out of bounds PBO access)", caller);
1573          return true;
1574       }
1575 
1576       /* make sure PBO is not mapped */
1577       if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1578          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller);
1579          return true;
1580       }
1581    }
1582    else {
1583       /* do bounds checking on writing to client memory */
1584       if (totalBytes > bufSize) {
1585          _mesa_error(ctx, GL_INVALID_OPERATION,
1586                      "%s(out of bounds access: bufSize (%d) is too small)",
1587                      caller, bufSize);
1588          return true;
1589       }
1590    }
1591 
1592    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
1593       /* not an error, but do nothing */
1594       return true;
1595    }
1596 
1597    return false;
1598 }
1599 
1600 
1601 /**
1602  * Common helper for all glGetCompressed-teximage functions.
1603  */
1604 static void
get_compressed_texture_image(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLint depth,GLvoid * pixels,const char * caller)1605 get_compressed_texture_image(struct gl_context *ctx,
1606                              struct gl_texture_object *texObj,
1607                              GLenum target, GLint level,
1608                              GLint xoffset, GLint yoffset, GLint zoffset,
1609                              GLsizei width, GLsizei height, GLint depth,
1610                              GLvoid *pixels,
1611                              const char *caller)
1612 {
1613    struct gl_texture_image *texImage;
1614    unsigned firstFace, numFaces, i, imageStride;
1615 
1616    FLUSH_VERTICES(ctx, 0);
1617 
1618    texImage = select_tex_image(texObj, target, level, zoffset);
1619    assert(texImage);  /* should have been error checked already */
1620 
1621    if (_mesa_is_zero_size_texture(texImage))
1622       return;
1623 
1624    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1625       _mesa_debug(ctx,
1626                   "%s(tex %u) format = %s, w=%d, h=%d\n",
1627                   caller, texObj->Name,
1628                   _mesa_get_format_name(texImage->TexFormat),
1629                   texImage->Width, texImage->Height);
1630    }
1631 
1632    if (target == GL_TEXTURE_CUBE_MAP) {
1633       struct compressed_pixelstore store;
1634 
1635       /* Compute image stride between cube faces */
1636       _mesa_compute_compressed_pixelstore(2, texImage->TexFormat,
1637                                           width, height, depth,
1638                                           &ctx->Pack, &store);
1639       imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice;
1640 
1641       firstFace = zoffset;
1642       numFaces = depth;
1643       zoffset = 0;
1644       depth = 1;
1645    }
1646    else {
1647       imageStride = 0;
1648       firstFace = _mesa_tex_target_to_face(target);
1649       numFaces = 1;
1650    }
1651 
1652    _mesa_lock_texture(ctx, texObj);
1653 
1654    for (i = 0; i < numFaces; i++) {
1655       texImage = texObj->Image[firstFace + i][level];
1656       assert(texImage);
1657 
1658       ctx->Driver.GetCompressedTexSubImage(ctx, texImage,
1659                                            xoffset, yoffset, zoffset,
1660                                            width, height, depth, pixels);
1661 
1662       /* next cube face */
1663       pixels = (GLubyte *) pixels + imageStride;
1664    }
1665 
1666    _mesa_unlock_texture(ctx, texObj);
1667 }
1668 
1669 
1670 void GLAPIENTRY
_mesa_GetnCompressedTexImageARB(GLenum target,GLint level,GLsizei bufSize,GLvoid * pixels)1671 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1672                                 GLvoid *pixels)
1673 {
1674    GET_CURRENT_CONTEXT(ctx);
1675    static const char *caller = "glGetnCompressedTexImageARB";
1676    GLsizei width, height, depth;
1677    struct gl_texture_object *texObj;
1678 
1679    if (!legal_getteximage_target(ctx, target, false)) {
1680       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1681       return;
1682    }
1683 
1684    texObj = _mesa_get_current_tex_object(ctx, target);
1685    assert(texObj);
1686 
1687    get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1688 
1689    if (getcompressedteximage_error_check(ctx, texObj, target, level,
1690                                          0, 0, 0, width, height, depth,
1691                                          INT_MAX, pixels, caller)) {
1692       return;
1693    }
1694 
1695    get_compressed_texture_image(ctx, texObj, target, level,
1696                                 0, 0, 0, width, height, depth,
1697                                 pixels, caller);
1698 }
1699 
1700 
1701 void GLAPIENTRY
_mesa_GetCompressedTexImage(GLenum target,GLint level,GLvoid * pixels)1702 _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels)
1703 {
1704    GET_CURRENT_CONTEXT(ctx);
1705    static const char *caller = "glGetCompressedTexImage";
1706    GLsizei width, height, depth;
1707    struct gl_texture_object *texObj;
1708 
1709    if (!legal_getteximage_target(ctx, target, false)) {
1710       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1711       return;
1712    }
1713 
1714    texObj = _mesa_get_current_tex_object(ctx, target);
1715    assert(texObj);
1716 
1717    get_texture_image_dims(texObj, target, level,
1718                           &width, &height, &depth);
1719 
1720    if (getcompressedteximage_error_check(ctx, texObj, target, level,
1721                                          0, 0, 0, width, height, depth,
1722                                          INT_MAX, pixels, caller)) {
1723       return;
1724    }
1725 
1726    get_compressed_texture_image(ctx, texObj, target, level,
1727                                 0, 0, 0, width, height, depth,
1728                                 pixels, caller);
1729 }
1730 
1731 
1732 void GLAPIENTRY
_mesa_GetCompressedTextureImage(GLuint texture,GLint level,GLsizei bufSize,GLvoid * pixels)1733 _mesa_GetCompressedTextureImage(GLuint texture, GLint level,
1734                                 GLsizei bufSize, GLvoid *pixels)
1735 {
1736    GET_CURRENT_CONTEXT(ctx);
1737    static const char *caller = "glGetCompressedTextureImage";
1738    GLsizei width, height, depth;
1739    struct gl_texture_object *texObj =
1740       _mesa_lookup_texture_err(ctx, texture, caller);
1741 
1742    if (!texObj) {
1743       return;
1744    }
1745 
1746    get_texture_image_dims(texObj, texObj->Target, level,
1747                           &width, &height, &depth);
1748 
1749    if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1750                                          0, 0, 0, width, height, depth,
1751                                          bufSize, pixels, caller)) {
1752       return;
1753    }
1754 
1755    get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1756                                 0, 0, 0, width, height, depth,
1757                                 pixels, caller);
1758 }
1759 
1760 
1761 void APIENTRY
_mesa_GetCompressedTextureSubImage(GLuint texture,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLsizei bufSize,void * pixels)1762 _mesa_GetCompressedTextureSubImage(GLuint texture, GLint level,
1763                                    GLint xoffset, GLint yoffset,
1764                                    GLint zoffset, GLsizei width,
1765                                    GLsizei height, GLsizei depth,
1766                                    GLsizei bufSize, void *pixels)
1767 {
1768    GET_CURRENT_CONTEXT(ctx);
1769    static const char *caller = "glGetCompressedTextureImage";
1770    struct gl_texture_object *texObj;
1771 
1772    texObj = _mesa_lookup_texture_err(ctx, texture, caller);
1773    if (!texObj) {
1774       return;
1775    }
1776 
1777    if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1778                                          xoffset, yoffset, zoffset,
1779                                          width, height, depth,
1780                                          bufSize, pixels, caller)) {
1781       return;
1782    }
1783 
1784    get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1785                                 xoffset, yoffset, zoffset,
1786                                 width, height, depth,
1787                                 pixels, caller);
1788 }
1789