• 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 function assumes that all error checking has been done.
765  */
766 static void
get_compressed_texsubimage_sw(struct gl_context * ctx,struct gl_texture_image * texImage,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLint height,GLint depth,GLvoid * img)767 get_compressed_texsubimage_sw(struct gl_context *ctx,
768                               struct gl_texture_image *texImage,
769                               GLint xoffset, GLint yoffset,
770                               GLint zoffset, GLsizei width,
771                               GLint height, GLint depth,
772                               GLvoid *img)
773 {
774    const GLuint dimensions =
775       _mesa_get_texture_dimensions(texImage->TexObject->Target);
776    struct compressed_pixelstore store;
777    GLint slice;
778    GLubyte *dest;
779 
780    _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat,
781                                        width, height, depth,
782                                        &ctx->Pack, &store);
783 
784    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
785       /* pack texture image into a PBO */
786       dest = (GLubyte *)
787          ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
788 				    GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
789                                     MAP_INTERNAL);
790       if (!dest) {
791          /* out of memory or other unexpected error */
792          _mesa_error(ctx, GL_OUT_OF_MEMORY,
793                      "glGetCompresssedTexImage(map PBO failed)");
794          return;
795       }
796       dest = ADD_POINTERS(dest, img);
797    } else {
798       dest = img;
799    }
800 
801    dest += store.SkipBytes;
802 
803    for (slice = 0; slice < store.CopySlices; slice++) {
804       GLint srcRowStride;
805       GLubyte *src;
806 
807       /* map src texture buffer */
808       ctx->Driver.MapTextureImage(ctx, texImage, zoffset + slice,
809                                   xoffset, yoffset, width, height,
810                                   GL_MAP_READ_BIT, &src, &srcRowStride);
811 
812       if (src) {
813          GLint i;
814          for (i = 0; i < store.CopyRowsPerSlice; i++) {
815             memcpy(dest, src, store.CopyBytesPerRow);
816             dest += store.TotalBytesPerRow;
817             src += srcRowStride;
818          }
819 
820          ctx->Driver.UnmapTextureImage(ctx, texImage, zoffset + slice);
821 
822          /* Advance to next slice */
823          dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice -
824                                            store.CopyRowsPerSlice);
825 
826       } else {
827          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
828       }
829    }
830 
831    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
832       ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
833    }
834 }
835 
836 
837 /**
838  * Validate the texture target enum supplied to glGetTex(ture)Image or
839  * glGetCompressedTex(ture)Image.
840  */
841 static GLboolean
legal_getteximage_target(struct gl_context * ctx,GLenum target,bool dsa)842 legal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa)
843 {
844    switch (target) {
845    case GL_TEXTURE_1D:
846    case GL_TEXTURE_2D:
847    case GL_TEXTURE_3D:
848       return GL_TRUE;
849    case GL_TEXTURE_RECTANGLE_NV:
850       return ctx->Extensions.NV_texture_rectangle;
851    case GL_TEXTURE_1D_ARRAY_EXT:
852    case GL_TEXTURE_2D_ARRAY_EXT:
853       return ctx->Extensions.EXT_texture_array;
854    case GL_TEXTURE_CUBE_MAP_ARRAY:
855       return ctx->Extensions.ARB_texture_cube_map_array;
856 
857    /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec
858     * (30.10.2014) says:
859     *    "An INVALID_ENUM error is generated if the effective target is not
860     *    one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY,
861     *    TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of
862     *    the targets from table 8.19 (for GetTexImage and GetnTexImage *only*),
863     *    or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.)
864     */
865    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
866    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
867    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
868    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
869    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
870    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
871       return dsa ? GL_FALSE : ctx->Extensions.ARB_texture_cube_map;
872    case GL_TEXTURE_CUBE_MAP:
873       return dsa ? GL_TRUE : GL_FALSE;
874    default:
875       return GL_FALSE;
876    }
877 }
878 
879 
880 /**
881  * Wrapper for _mesa_select_tex_image() which can handle target being
882  * GL_TEXTURE_CUBE_MAP in which case we use zoffset to select a cube face.
883  * This can happen for glGetTextureImage and glGetTextureSubImage (DSA
884  * functions).
885  */
886 static struct gl_texture_image *
select_tex_image(const struct gl_texture_object * texObj,GLenum target,GLint level,GLint zoffset)887 select_tex_image(const struct gl_texture_object *texObj, GLenum target,
888                  GLint level, GLint zoffset)
889 {
890    assert(level >= 0);
891    assert(level < MAX_TEXTURE_LEVELS);
892    if (target == GL_TEXTURE_CUBE_MAP) {
893       assert(zoffset >= 0);
894       assert(zoffset < 6);
895       target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset;
896    }
897    return _mesa_select_tex_image(texObj, target, level);
898 }
899 
900 
901 /**
902  * Error-check the offset and size arguments to
903  * glGet[Compressed]TextureSubImage().  Also checks if the specified
904  * texture image is missing.
905  * \return true if error, false if no error.
906  */
907 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)908 dimensions_error_check(struct gl_context *ctx,
909                        struct gl_texture_object *texObj,
910                        GLenum target, GLint level,
911                        GLint xoffset, GLint yoffset, GLint zoffset,
912                        GLsizei width, GLsizei height, GLsizei depth,
913                        const char *caller)
914 {
915    const struct gl_texture_image *texImage;
916    int i;
917 
918    if (xoffset < 0) {
919       _mesa_error(ctx, GL_INVALID_VALUE, "%s(xoffset = %d)", caller, xoffset);
920       return true;
921    }
922 
923    if (yoffset < 0) {
924       _mesa_error(ctx, GL_INVALID_VALUE, "%s(yoffset = %d)", caller, yoffset);
925       return true;
926    }
927 
928    if (zoffset < 0) {
929       _mesa_error(ctx, GL_INVALID_VALUE, "%s(zoffset = %d)", caller, zoffset);
930       return true;
931    }
932 
933    if (width < 0) {
934       _mesa_error(ctx, GL_INVALID_VALUE, "%s(width = %d)", caller, width);
935       return true;
936    }
937 
938    if (height < 0) {
939       _mesa_error(ctx, GL_INVALID_VALUE, "%s(height = %d)", caller, height);
940       return true;
941    }
942 
943    if (depth < 0) {
944       _mesa_error(ctx, GL_INVALID_VALUE, "%s(depth = %d)", caller, depth);
945       return true;
946    }
947 
948    /* do special per-target checks */
949    switch (target) {
950    case GL_TEXTURE_1D:
951       if (yoffset != 0) {
952          _mesa_error(ctx, GL_INVALID_VALUE,
953                      "%s(1D, yoffset = %d)", caller, yoffset);
954          return true;
955       }
956       if (height > 1) {
957          _mesa_error(ctx, GL_INVALID_VALUE,
958                      "%s(1D, height = %d)", caller, height);
959          return true;
960       }
961       /* fall-through */
962    case GL_TEXTURE_1D_ARRAY:
963    case GL_TEXTURE_2D:
964    case GL_TEXTURE_RECTANGLE:
965       if (zoffset != 0) {
966          _mesa_error(ctx, GL_INVALID_VALUE,
967                      "%s(zoffset = %d)", caller, zoffset);
968          return true;
969       }
970       if (depth > 1) {
971          _mesa_error(ctx, GL_INVALID_VALUE,
972                      "%s(depth = %d)", caller, depth);
973          return true;
974       }
975       break;
976    case GL_TEXTURE_CUBE_MAP:
977       /* Non-array cube maps are special because we have a gl_texture_image
978        * per face.
979        */
980       if (zoffset + depth > 6) {
981          _mesa_error(ctx, GL_INVALID_VALUE,
982                      "%s(zoffset + depth = %d)", caller, zoffset + depth);
983          return true;
984       }
985       /* check that the range of faces exist */
986       for (i = 0; i < depth; i++) {
987          GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset + i;
988          if (!_mesa_select_tex_image(texObj, face, level)) {
989             /* non-existant face */
990             _mesa_error(ctx, GL_INVALID_OPERATION,
991                         "%s(missing cube face)", caller);
992             return true;
993          }
994       }
995       break;
996    default:
997       ; /* nothing */
998    }
999 
1000    texImage = select_tex_image(texObj, target, level, zoffset);
1001    if (!texImage) {
1002       /* missing texture image */
1003       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(missing image)", caller);
1004       return true;
1005    }
1006 
1007    if (xoffset + width > texImage->Width) {
1008       _mesa_error(ctx, GL_INVALID_VALUE,
1009                   "%s(xoffset %d + width %d > %u)",
1010                   caller, xoffset, width, texImage->Width);
1011       return true;
1012    }
1013 
1014    if (yoffset + height > texImage->Height) {
1015       _mesa_error(ctx, GL_INVALID_VALUE,
1016                   "%s(yoffset %d + height %d > %u)",
1017                   caller, yoffset, height, texImage->Height);
1018       return true;
1019    }
1020 
1021    if (target != GL_TEXTURE_CUBE_MAP) {
1022       /* Cube map error checking was done above */
1023       if (zoffset + depth > texImage->Depth) {
1024          _mesa_error(ctx, GL_INVALID_VALUE,
1025                      "%s(zoffset %d + depth %d > %u)",
1026                      caller, zoffset, depth, texImage->Depth);
1027          return true;
1028       }
1029    }
1030 
1031    /* Extra checks for compressed textures */
1032    {
1033       GLuint bw, bh, bd;
1034       _mesa_get_format_block_size_3d(texImage->TexFormat, &bw, &bh, &bd);
1035       if (bw > 1 || bh > 1 || bd > 1) {
1036          /* offset must be multiple of block size */
1037          if (xoffset % bw != 0) {
1038             _mesa_error(ctx, GL_INVALID_VALUE,
1039                         "%s(xoffset = %d)", caller, xoffset);
1040             return true;
1041          }
1042          if (target != GL_TEXTURE_1D && target != GL_TEXTURE_1D_ARRAY) {
1043             if (yoffset % bh != 0) {
1044                _mesa_error(ctx, GL_INVALID_VALUE,
1045                            "%s(yoffset = %d)", caller, yoffset);
1046                return true;
1047             }
1048          }
1049 
1050          if (zoffset % bd != 0) {
1051             _mesa_error(ctx, GL_INVALID_VALUE,
1052                         "%s(zoffset = %d)", caller, zoffset);
1053             return true;
1054          }
1055 
1056          /* The size must be a multiple of bw x bh x bd, or we must be using a
1057           * offset+size that exactly hits the edge of the image.
1058           */
1059          if ((width % bw != 0) &&
1060              (xoffset + width != (GLint) texImage->Width)) {
1061             _mesa_error(ctx, GL_INVALID_VALUE,
1062                         "%s(width = %d)", caller, width);
1063             return true;
1064          }
1065 
1066          if ((height % bh != 0) &&
1067              (yoffset + height != (GLint) texImage->Height)) {
1068             _mesa_error(ctx, GL_INVALID_VALUE,
1069                         "%s(height = %d)", caller, height);
1070             return true;
1071          }
1072 
1073          if ((depth % bd != 0) &&
1074              (zoffset + depth != (GLint) texImage->Depth)) {
1075             _mesa_error(ctx, GL_INVALID_VALUE,
1076                         "%s(depth = %d)", caller, depth);
1077             return true;
1078          }
1079       }
1080    }
1081 
1082    if (width == 0 || height == 0 || depth == 0) {
1083       /* Not an error, but nothing to do.  Return 'true' so that the
1084        * caller simply returns.
1085        */
1086       return true;
1087    }
1088 
1089    return false;
1090 }
1091 
1092 
1093 /**
1094  * Do PBO-related error checking for getting uncompressed images.
1095  * \return true if there was an error (or the GetTexImage is to be a no-op)
1096  */
1097 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)1098 pbo_error_check(struct gl_context *ctx, GLenum target,
1099                 GLsizei width, GLsizei height, GLsizei depth,
1100                 GLenum format, GLenum type, GLsizei clientMemSize,
1101                 GLvoid *pixels,
1102                 const char *caller)
1103 {
1104    const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
1105 
1106    if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, width, height, depth,
1107                                   format, type, clientMemSize, pixels)) {
1108       if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1109          _mesa_error(ctx, GL_INVALID_OPERATION,
1110                      "%s(out of bounds PBO access)", caller);
1111       } else {
1112          _mesa_error(ctx, GL_INVALID_OPERATION,
1113                      "%s(out of bounds access: bufSize (%d) is too small)",
1114                      caller, clientMemSize);
1115       }
1116       return true;
1117    }
1118 
1119    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1120       /* PBO should not be mapped */
1121       if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1122          _mesa_error(ctx, GL_INVALID_OPERATION,
1123                      "%s(PBO is mapped)", caller);
1124          return true;
1125       }
1126    }
1127 
1128    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
1129       /* not an error, do nothing */
1130       return true;
1131    }
1132 
1133    return false;
1134 }
1135 
1136 
1137 /**
1138  * Do error checking for all (non-compressed) get-texture-image functions.
1139  * \return true if any error, false if no errors.
1140  */
1141 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)1142 getteximage_error_check(struct gl_context *ctx,
1143                         struct gl_texture_object *texObj,
1144                         GLenum target, GLint level,
1145                         GLint xoffset, GLint yoffset, GLint zoffset,
1146                         GLsizei width, GLsizei height, GLsizei depth,
1147                         GLenum format, GLenum type, GLsizei bufSize,
1148                         GLvoid *pixels, const char *caller)
1149 {
1150    struct gl_texture_image *texImage;
1151    GLenum baseFormat, err;
1152    GLint maxLevels;
1153 
1154    assert(texObj);
1155 
1156    if (texObj->Target == 0) {
1157       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
1158       return true;
1159    }
1160 
1161    maxLevels = _mesa_max_texture_levels(ctx, target);
1162    if (level < 0 || level >= maxLevels) {
1163       _mesa_error(ctx, GL_INVALID_VALUE, "%s(level = %d)", caller, level);
1164       return true;
1165    }
1166 
1167    err = _mesa_error_check_format_and_type(ctx, format, type);
1168    if (err != GL_NO_ERROR) {
1169       _mesa_error(ctx, err, "%s(format/type)", caller);
1170       return true;
1171    }
1172 
1173    if (dimensions_error_check(ctx, texObj, target, level,
1174                               xoffset, yoffset, zoffset,
1175                               width, height, depth, caller)) {
1176       return true;
1177    }
1178 
1179    if (pbo_error_check(ctx, target, width, height, depth,
1180                        format, type, bufSize, pixels, caller)) {
1181       return true;
1182    }
1183 
1184    texImage = select_tex_image(texObj, target, level, zoffset);
1185    assert(texImage);
1186 
1187    /*
1188     * Format and type checking has been moved up to GetnTexImage and
1189     * GetTextureImage so that it happens before getting the texImage object.
1190     */
1191 
1192    baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
1193 
1194    /* Make sure the requested image format is compatible with the
1195     * texture's format.
1196     */
1197    if (_mesa_is_color_format(format)
1198        && !_mesa_is_color_format(baseFormat)) {
1199       _mesa_error(ctx, GL_INVALID_OPERATION,
1200                   "%s(format mismatch)", caller);
1201       return true;
1202    }
1203    else if (_mesa_is_depth_format(format)
1204             && !_mesa_is_depth_format(baseFormat)
1205             && !_mesa_is_depthstencil_format(baseFormat)) {
1206       _mesa_error(ctx, GL_INVALID_OPERATION,
1207                   "%s(format mismatch)", caller);
1208       return true;
1209    }
1210    else if (_mesa_is_stencil_format(format)
1211             && !ctx->Extensions.ARB_texture_stencil8) {
1212       _mesa_error(ctx, GL_INVALID_ENUM,
1213                   "%s(format=GL_STENCIL_INDEX)", caller);
1214       return true;
1215    }
1216    else if (_mesa_is_stencil_format(format)
1217 	    && !_mesa_is_depthstencil_format(baseFormat)
1218 	    && !_mesa_is_stencil_format(baseFormat)) {
1219       _mesa_error(ctx, GL_INVALID_OPERATION,
1220                   "%s(format mismatch)", caller);
1221       return true;
1222    }
1223    else if (_mesa_is_ycbcr_format(format)
1224             && !_mesa_is_ycbcr_format(baseFormat)) {
1225       _mesa_error(ctx, GL_INVALID_OPERATION,
1226                   "%s(format mismatch)", caller);
1227       return true;
1228    }
1229    else if (_mesa_is_depthstencil_format(format)
1230             && !_mesa_is_depthstencil_format(baseFormat)) {
1231       _mesa_error(ctx, GL_INVALID_OPERATION,
1232                   "%s(format mismatch)", caller);
1233       return true;
1234    }
1235    else if (!_mesa_is_stencil_format(format) &&
1236             _mesa_is_enum_format_integer(format) !=
1237             _mesa_is_format_integer(texImage->TexFormat)) {
1238       _mesa_error(ctx, GL_INVALID_OPERATION,
1239                   "%s(format mismatch)", caller);
1240       return true;
1241    }
1242 
1243    return false;
1244 }
1245 
1246 
1247 /**
1248  * Return the width, height and depth of a texture image.
1249  * This function must be resilient to bad parameter values since
1250  * this is called before full error checking.
1251  */
1252 static void
get_texture_image_dims(const struct gl_texture_object * texObj,GLenum target,GLint level,GLsizei * width,GLsizei * height,GLsizei * depth)1253 get_texture_image_dims(const struct gl_texture_object *texObj,
1254                        GLenum target, GLint level,
1255                        GLsizei *width, GLsizei *height, GLsizei *depth)
1256 {
1257    const struct gl_texture_image *texImage = NULL;
1258 
1259    if (level >= 0 && level < MAX_TEXTURE_LEVELS) {
1260       texImage = _mesa_select_tex_image(texObj, target, level);
1261    }
1262 
1263    if (texImage) {
1264       *width = texImage->Width;
1265       *height = texImage->Height;
1266       if (target == GL_TEXTURE_CUBE_MAP) {
1267          *depth = 6;
1268       }
1269       else {
1270          *depth = texImage->Depth;
1271       }
1272    }
1273    else {
1274       *width = *height = *depth = 0;
1275    }
1276 }
1277 
1278 
1279 /**
1280  * Common code for all (uncompressed) get-texture-image functions.
1281  * \param texObj  the texture object (should not be null)
1282  * \param target  user-provided target, or 0 for DSA
1283  * \param level image level.
1284  * \param format pixel data format for returned image.
1285  * \param type pixel data type for returned image.
1286  * \param bufSize size of the pixels data buffer.
1287  * \param pixels returned pixel data.
1288  * \param caller  name of calling function
1289  */
1290 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)1291 get_texture_image(struct gl_context *ctx,
1292                   struct gl_texture_object *texObj,
1293                   GLenum target, GLint level,
1294                   GLint xoffset, GLint yoffset, GLint zoffset,
1295                   GLsizei width, GLsizei height, GLint depth,
1296                   GLenum format, GLenum type,
1297                   GLvoid *pixels, const char *caller)
1298 {
1299    struct gl_texture_image *texImage;
1300    unsigned firstFace, numFaces, i;
1301    GLint imageStride;
1302 
1303    FLUSH_VERTICES(ctx, 0);
1304 
1305    texImage = select_tex_image(texObj, target, level, zoffset);
1306    assert(texImage);  /* should have been error checked already */
1307 
1308    if (_mesa_is_zero_size_texture(texImage)) {
1309       /* no image data to return */
1310       return;
1311    }
1312 
1313    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1314       _mesa_debug(ctx, "%s(tex %u) format = %s, w=%d, h=%d,"
1315                   " dstFmt=0x%x, dstType=0x%x\n",
1316                   caller, texObj->Name,
1317                   _mesa_get_format_name(texImage->TexFormat),
1318                   texImage->Width, texImage->Height,
1319                   format, type);
1320    }
1321 
1322    if (target == GL_TEXTURE_CUBE_MAP) {
1323       /* Compute stride between cube faces */
1324       imageStride = _mesa_image_image_stride(&ctx->Pack, width, height,
1325                                              format, type);
1326       firstFace = zoffset;
1327       numFaces = depth;
1328       zoffset = 0;
1329       depth = 1;
1330    }
1331    else {
1332       imageStride = 0;
1333       firstFace = _mesa_tex_target_to_face(target);
1334       numFaces = 1;
1335    }
1336 
1337    _mesa_lock_texture(ctx, texObj);
1338 
1339    for (i = 0; i < numFaces; i++) {
1340       texImage = texObj->Image[firstFace + i][level];
1341       assert(texImage);
1342 
1343       ctx->Driver.GetTexSubImage(ctx, xoffset, yoffset, zoffset,
1344                                  width, height, depth,
1345                                  format, type, pixels, texImage);
1346 
1347       /* next cube face */
1348       pixels = (GLubyte *) pixels + imageStride;
1349    }
1350 
1351    _mesa_unlock_texture(ctx, texObj);
1352 }
1353 
1354 
1355 void GLAPIENTRY
_mesa_GetnTexImageARB(GLenum target,GLint level,GLenum format,GLenum type,GLsizei bufSize,GLvoid * pixels)1356 _mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format, GLenum type,
1357                       GLsizei bufSize, GLvoid *pixels)
1358 {
1359    GET_CURRENT_CONTEXT(ctx);
1360    static const char *caller = "glGetnTexImageARB";
1361    GLsizei width, height, depth;
1362    struct gl_texture_object *texObj;
1363 
1364    if (!legal_getteximage_target(ctx, target, false)) {
1365       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1366       return;
1367    }
1368 
1369    texObj = _mesa_get_current_tex_object(ctx, target);
1370    assert(texObj);
1371 
1372    get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1373 
1374    if (getteximage_error_check(ctx, texObj, target, level,
1375                                0, 0, 0, width, height, depth,
1376                                format, type, bufSize, pixels, caller)) {
1377       return;
1378    }
1379 
1380    get_texture_image(ctx, texObj, target, level,
1381                      0, 0, 0, width, height, depth,
1382                      format, type, pixels, caller);
1383 }
1384 
1385 
1386 void GLAPIENTRY
_mesa_GetTexImage(GLenum target,GLint level,GLenum format,GLenum type,GLvoid * pixels)1387 _mesa_GetTexImage(GLenum target, GLint level, GLenum format, GLenum type,
1388                   GLvoid *pixels )
1389 {
1390    GET_CURRENT_CONTEXT(ctx);
1391    static const char *caller = "glGetTexImage";
1392    GLsizei width, height, depth;
1393    struct gl_texture_object *texObj;
1394 
1395    if (!legal_getteximage_target(ctx, target, false)) {
1396       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1397       return;
1398    }
1399 
1400    texObj = _mesa_get_current_tex_object(ctx, target);
1401    assert(texObj);
1402 
1403    get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1404 
1405    if (getteximage_error_check(ctx, texObj, target, level,
1406                                0, 0, 0, width, height, depth,
1407                                format, type, INT_MAX, pixels, caller)) {
1408       return;
1409    }
1410 
1411    get_texture_image(ctx, texObj, target, level,
1412                      0, 0, 0, width, height, depth,
1413                      format, type, pixels, caller);
1414 }
1415 
1416 
1417 void GLAPIENTRY
_mesa_GetTextureImage(GLuint texture,GLint level,GLenum format,GLenum type,GLsizei bufSize,GLvoid * pixels)1418 _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type,
1419                       GLsizei bufSize, GLvoid *pixels)
1420 {
1421    GET_CURRENT_CONTEXT(ctx);
1422    GLsizei width, height, depth;
1423    static const char *caller = "glGetTextureImage";
1424    struct gl_texture_object *texObj =
1425       _mesa_lookup_texture_err(ctx, texture, caller);
1426 
1427    if (!texObj) {
1428       return;
1429    }
1430 
1431    if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1432       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1433       return;
1434    }
1435 
1436    get_texture_image_dims(texObj, texObj->Target, level,
1437                           &width, &height, &depth);
1438 
1439    if (getteximage_error_check(ctx, texObj, texObj->Target, level,
1440                                0, 0, 0, width, height, depth,
1441                                format, type, bufSize, pixels, caller)) {
1442       return;
1443    }
1444 
1445    get_texture_image(ctx, texObj, texObj->Target, level,
1446                      0, 0, 0, width, height, depth,
1447                      format, type, pixels, caller);
1448 }
1449 
1450 
1451 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)1452 _mesa_GetTextureSubImage(GLuint texture, GLint level,
1453                          GLint xoffset, GLint yoffset, GLint zoffset,
1454                          GLsizei width, GLsizei height, GLsizei depth,
1455                          GLenum format, GLenum type, GLsizei bufSize,
1456                          void *pixels)
1457 {
1458    GET_CURRENT_CONTEXT(ctx);
1459    static const char *caller = "glGetTextureSubImage";
1460    struct gl_texture_object *texObj =
1461       _mesa_lookup_texture_err(ctx, texture, caller);
1462 
1463    if (!texObj) {
1464       return;
1465    }
1466 
1467    if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1468       _mesa_error(ctx, GL_INVALID_OPERATION,
1469                   "%s(buffer/multisample texture)", caller);
1470       return;
1471    }
1472 
1473    if (getteximage_error_check(ctx, texObj, texObj->Target, level,
1474                                xoffset, yoffset, zoffset, width, height, depth,
1475                                format, type, bufSize, pixels, caller)) {
1476       return;
1477    }
1478 
1479    get_texture_image(ctx, texObj, texObj->Target, level,
1480                      xoffset, yoffset, zoffset, width, height, depth,
1481                      format, type, pixels, caller);
1482 }
1483 
1484 
1485 
1486 /**
1487  * Compute the number of bytes which will be written when retrieving
1488  * a sub-region of a compressed texture.
1489  */
1490 static GLsizei
packed_compressed_size(GLuint dimensions,mesa_format format,GLsizei width,GLsizei height,GLsizei depth,const struct gl_pixelstore_attrib * packing)1491 packed_compressed_size(GLuint dimensions, mesa_format format,
1492                        GLsizei width, GLsizei height, GLsizei depth,
1493                        const struct gl_pixelstore_attrib *packing)
1494 {
1495    struct compressed_pixelstore st;
1496    GLsizei totalBytes;
1497 
1498    _mesa_compute_compressed_pixelstore(dimensions, format,
1499                                        width, height, depth,
1500                                        packing, &st);
1501    totalBytes =
1502       (st.CopySlices - 1) * st.TotalRowsPerSlice * st.TotalBytesPerRow +
1503       st.SkipBytes +
1504       (st.CopyRowsPerSlice - 1) * st.TotalBytesPerRow +
1505       st.CopyBytesPerRow;
1506 
1507    return totalBytes;
1508 }
1509 
1510 
1511 /**
1512  * Do error checking for getting compressed texture images.
1513  * \return true if any error, false if no errors.
1514  */
1515 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)1516 getcompressedteximage_error_check(struct gl_context *ctx,
1517                                   struct gl_texture_object *texObj,
1518                                   GLenum target, GLint level,
1519                                   GLint xoffset, GLint yoffset, GLint zoffset,
1520                                   GLsizei width, GLsizei height, GLsizei depth,
1521                                   GLsizei bufSize, GLvoid *pixels,
1522                                   const char *caller)
1523 {
1524    struct gl_texture_image *texImage;
1525    GLint maxLevels;
1526    GLsizei totalBytes;
1527    GLuint dimensions;
1528 
1529    assert(texObj);
1530 
1531    if (texObj->Target == 0) {
1532       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid texture)", caller);
1533       return true;
1534    }
1535 
1536    maxLevels = _mesa_max_texture_levels(ctx, target);
1537    if (level < 0 || level >= maxLevels) {
1538       _mesa_error(ctx, GL_INVALID_VALUE,
1539                   "%s(bad level = %d)", caller, level);
1540       return true;
1541    }
1542 
1543    if (dimensions_error_check(ctx, texObj, target, level,
1544                               xoffset, yoffset, zoffset,
1545                               width, height, depth, caller)) {
1546       return true;
1547    }
1548 
1549    texImage = select_tex_image(texObj, target, level, zoffset);
1550    assert(texImage);
1551 
1552    if (!_mesa_is_format_compressed(texImage->TexFormat)) {
1553       _mesa_error(ctx, GL_INVALID_OPERATION,
1554                   "%s(texture is not compressed)", caller);
1555       return true;
1556    }
1557 
1558    /* Check for invalid pixel storage modes */
1559    dimensions = _mesa_get_texture_dimensions(texObj->Target);
1560    if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
1561                                                    &ctx->Pack,
1562                                                    caller)) {
1563       return true;
1564    }
1565 
1566    /* Compute number of bytes that may be touched in the dest buffer */
1567    totalBytes = packed_compressed_size(dimensions, texImage->TexFormat,
1568                                        width, height, depth,
1569                                        &ctx->Pack);
1570 
1571    /* Do dest buffer bounds checking */
1572    if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1573       /* do bounds checking on PBO write */
1574       if ((GLubyte *) pixels + totalBytes >
1575           (GLubyte *) ctx->Pack.BufferObj->Size) {
1576          _mesa_error(ctx, GL_INVALID_OPERATION,
1577                      "%s(out of bounds PBO access)", caller);
1578          return true;
1579       }
1580 
1581       /* make sure PBO is not mapped */
1582       if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1583          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", caller);
1584          return true;
1585       }
1586    }
1587    else {
1588       /* do bounds checking on writing to client memory */
1589       if (totalBytes > bufSize) {
1590          _mesa_error(ctx, GL_INVALID_OPERATION,
1591                      "%s(out of bounds access: bufSize (%d) is too small)",
1592                      caller, bufSize);
1593          return true;
1594       }
1595    }
1596 
1597    if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
1598       /* not an error, but do nothing */
1599       return true;
1600    }
1601 
1602    return false;
1603 }
1604 
1605 
1606 /**
1607  * Common helper for all glGetCompressed-teximage functions.
1608  */
1609 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)1610 get_compressed_texture_image(struct gl_context *ctx,
1611                              struct gl_texture_object *texObj,
1612                              GLenum target, GLint level,
1613                              GLint xoffset, GLint yoffset, GLint zoffset,
1614                              GLsizei width, GLsizei height, GLint depth,
1615                              GLvoid *pixels,
1616                              const char *caller)
1617 {
1618    struct gl_texture_image *texImage;
1619    unsigned firstFace, numFaces, i, imageStride;
1620 
1621    FLUSH_VERTICES(ctx, 0);
1622 
1623    texImage = select_tex_image(texObj, target, level, zoffset);
1624    assert(texImage);  /* should have been error checked already */
1625 
1626    if (_mesa_is_zero_size_texture(texImage))
1627       return;
1628 
1629    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1630       _mesa_debug(ctx,
1631                   "%s(tex %u) format = %s, w=%d, h=%d\n",
1632                   caller, texObj->Name,
1633                   _mesa_get_format_name(texImage->TexFormat),
1634                   texImage->Width, texImage->Height);
1635    }
1636 
1637    if (target == GL_TEXTURE_CUBE_MAP) {
1638       struct compressed_pixelstore store;
1639 
1640       /* Compute image stride between cube faces */
1641       _mesa_compute_compressed_pixelstore(2, texImage->TexFormat,
1642                                           width, height, depth,
1643                                           &ctx->Pack, &store);
1644       imageStride = store.TotalBytesPerRow * store.TotalRowsPerSlice;
1645 
1646       firstFace = zoffset;
1647       numFaces = depth;
1648       zoffset = 0;
1649       depth = 1;
1650    }
1651    else {
1652       imageStride = 0;
1653       firstFace = _mesa_tex_target_to_face(target);
1654       numFaces = 1;
1655    }
1656 
1657    _mesa_lock_texture(ctx, texObj);
1658 
1659    for (i = 0; i < numFaces; i++) {
1660       texImage = texObj->Image[firstFace + i][level];
1661       assert(texImage);
1662 
1663       get_compressed_texsubimage_sw(ctx, texImage,
1664                                     xoffset, yoffset, zoffset,
1665                                     width, height, depth, pixels);
1666 
1667       /* next cube face */
1668       pixels = (GLubyte *) pixels + imageStride;
1669    }
1670 
1671    _mesa_unlock_texture(ctx, texObj);
1672 }
1673 
1674 
1675 void GLAPIENTRY
_mesa_GetnCompressedTexImageARB(GLenum target,GLint level,GLsizei bufSize,GLvoid * pixels)1676 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1677                                 GLvoid *pixels)
1678 {
1679    GET_CURRENT_CONTEXT(ctx);
1680    static const char *caller = "glGetnCompressedTexImageARB";
1681    GLsizei width, height, depth;
1682    struct gl_texture_object *texObj;
1683 
1684    if (!legal_getteximage_target(ctx, target, false)) {
1685       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1686       return;
1687    }
1688 
1689    texObj = _mesa_get_current_tex_object(ctx, target);
1690    assert(texObj);
1691 
1692    get_texture_image_dims(texObj, target, level, &width, &height, &depth);
1693 
1694    if (getcompressedteximage_error_check(ctx, texObj, target, level,
1695                                          0, 0, 0, width, height, depth,
1696                                          INT_MAX, pixels, caller)) {
1697       return;
1698    }
1699 
1700    get_compressed_texture_image(ctx, texObj, target, level,
1701                                 0, 0, 0, width, height, depth,
1702                                 pixels, caller);
1703 }
1704 
1705 
1706 void GLAPIENTRY
_mesa_GetCompressedTexImage(GLenum target,GLint level,GLvoid * pixels)1707 _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *pixels)
1708 {
1709    GET_CURRENT_CONTEXT(ctx);
1710    static const char *caller = "glGetCompressedTexImage";
1711    GLsizei width, height, depth;
1712    struct gl_texture_object *texObj;
1713 
1714    if (!legal_getteximage_target(ctx, target, false)) {
1715       _mesa_error(ctx, GL_INVALID_ENUM, "%s", caller);
1716       return;
1717    }
1718 
1719    texObj = _mesa_get_current_tex_object(ctx, target);
1720    assert(texObj);
1721 
1722    get_texture_image_dims(texObj, target, level,
1723                           &width, &height, &depth);
1724 
1725    if (getcompressedteximage_error_check(ctx, texObj, target, level,
1726                                          0, 0, 0, width, height, depth,
1727                                          INT_MAX, pixels, caller)) {
1728       return;
1729    }
1730 
1731    get_compressed_texture_image(ctx, texObj, target, level,
1732                                 0, 0, 0, width, height, depth,
1733                                 pixels, caller);
1734 }
1735 
1736 
1737 void GLAPIENTRY
_mesa_GetCompressedTextureImage(GLuint texture,GLint level,GLsizei bufSize,GLvoid * pixels)1738 _mesa_GetCompressedTextureImage(GLuint texture, GLint level,
1739                                 GLsizei bufSize, GLvoid *pixels)
1740 {
1741    GET_CURRENT_CONTEXT(ctx);
1742    static const char *caller = "glGetCompressedTextureImage";
1743    GLsizei width, height, depth;
1744    struct gl_texture_object *texObj =
1745       _mesa_lookup_texture_err(ctx, texture, caller);
1746 
1747    if (!texObj) {
1748       return;
1749    }
1750 
1751    get_texture_image_dims(texObj, texObj->Target, level,
1752                           &width, &height, &depth);
1753 
1754    if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1755                                          0, 0, 0, width, height, depth,
1756                                          bufSize, pixels, caller)) {
1757       return;
1758    }
1759 
1760    get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1761                                 0, 0, 0, width, height, depth,
1762                                 pixels, caller);
1763 }
1764 
1765 
1766 void APIENTRY
_mesa_GetCompressedTextureSubImage(GLuint texture,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLsizei bufSize,void * pixels)1767 _mesa_GetCompressedTextureSubImage(GLuint texture, GLint level,
1768                                    GLint xoffset, GLint yoffset,
1769                                    GLint zoffset, GLsizei width,
1770                                    GLsizei height, GLsizei depth,
1771                                    GLsizei bufSize, void *pixels)
1772 {
1773    GET_CURRENT_CONTEXT(ctx);
1774    static const char *caller = "glGetCompressedTextureImage";
1775    struct gl_texture_object *texObj = NULL;
1776 
1777    texObj = _mesa_lookup_texture_err(ctx, texture, caller);
1778    if (!texObj) {
1779       return;
1780    }
1781 
1782    if (getcompressedteximage_error_check(ctx, texObj, texObj->Target, level,
1783                                          xoffset, yoffset, zoffset,
1784                                          width, height, depth,
1785                                          bufSize, pixels, caller)) {
1786       return;
1787    }
1788 
1789    get_compressed_texture_image(ctx, texObj, texObj->Target, level,
1790                                 xoffset, yoffset, zoffset,
1791                                 width, height, depth,
1792                                 pixels, caller);
1793 }
1794