Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5
 * Copyright (c) 2009 VMware, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
 
27
/**
28
 * Code for glGetTexImage() and glGetCompressedTexImage().
29
 */
30
 
31
 
32
#include "glheader.h"
33
#include "bufferobj.h"
34
#include "enums.h"
35
#include "context.h"
36
#include "formats.h"
37
#include "format_unpack.h"
38
#include "glformats.h"
39
#include "image.h"
40
#include "mtypes.h"
41
#include "pack.h"
42
#include "pbo.h"
43
#include "pixelstore.h"
44
#include "texcompress.h"
45
#include "texgetimage.h"
46
#include "teximage.h"
47
#include "texobj.h"
48
#include "texstore.h"
49
#include "format_utils.h"
50
#include "pixeltransfer.h"
51
 
52
/**
53
 * Can the given type represent negative values?
54
 */
55
static inline GLboolean
56
type_needs_clamping(GLenum type)
57
{
58
   switch (type) {
59
   case GL_BYTE:
60
   case GL_SHORT:
61
   case GL_INT:
62
   case GL_FLOAT:
63
   case GL_HALF_FLOAT_ARB:
64
   case GL_UNSIGNED_INT_10F_11F_11F_REV:
65
   case GL_UNSIGNED_INT_5_9_9_9_REV:
66
      return GL_FALSE;
67
   default:
68
      return GL_TRUE;
69
   }
70
}
71
 
72
 
73
/**
74
 * glGetTexImage for depth/Z pixels.
75
 */
76
static void
77
get_tex_depth(struct gl_context *ctx, GLuint dimensions,
78
              GLenum format, GLenum type, GLvoid *pixels,
79
              struct gl_texture_image *texImage)
80
{
81
   const GLint width = texImage->Width;
82
   GLint height = texImage->Height;
83
   GLint depth = texImage->Depth;
84
   GLint img, row;
85
   GLfloat *depthRow = malloc(width * sizeof(GLfloat));
86
 
87
   if (!depthRow) {
88
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
89
      return;
90
   }
91
 
92
   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
93
      depth = height;
94
      height = 1;
95
   }
96
 
97
   for (img = 0; img < depth; img++) {
98
      GLubyte *srcMap;
99
      GLint srcRowStride;
100
 
101
      /* map src texture buffer */
102
      ctx->Driver.MapTextureImage(ctx, texImage, img,
103
                                  0, 0, width, height, GL_MAP_READ_BIT,
104
                                  &srcMap, &srcRowStride);
105
 
106
      if (srcMap) {
107
         for (row = 0; row < height; row++) {
108
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
109
                                             width, height, format, type,
110
                                             img, row, 0);
111
            const GLubyte *src = srcMap + row * srcRowStride;
112
            _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
113
            _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
114
         }
115
 
116
         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
117
      }
118
      else {
119
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
120
         break;
121
      }
122
   }
123
 
124
   free(depthRow);
125
}
126
 
127
 
128
/**
129
 * glGetTexImage for depth/stencil pixels.
130
 */
131
static void
132
get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
133
                      GLenum format, GLenum type, GLvoid *pixels,
134
                      struct gl_texture_image *texImage)
135
{
136
   const GLint width = texImage->Width;
137
   const GLint height = texImage->Height;
138
   const GLint depth = texImage->Depth;
139
   GLint img, row;
140
 
141
   assert(format == GL_DEPTH_STENCIL);
142
   assert(type == GL_UNSIGNED_INT_24_8 ||
143
          type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
144
 
145
   for (img = 0; img < depth; img++) {
146
      GLubyte *srcMap;
147
      GLint rowstride;
148
 
149
      /* map src texture buffer */
150
      ctx->Driver.MapTextureImage(ctx, texImage, img,
151
                                  0, 0, width, height, GL_MAP_READ_BIT,
152
                                  &srcMap, &rowstride);
153
 
154
      if (srcMap) {
155
         for (row = 0; row < height; row++) {
156
            const GLubyte *src = srcMap + row * rowstride;
157
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
158
                                             width, height, format, type,
159
                                             img, row, 0);
160
            _mesa_unpack_depth_stencil_row(texImage->TexFormat,
161
                                           width,
162
                                           (const GLuint *) src,
163
                                           type, dest);
164
            if (ctx->Pack.SwapBytes) {
165
               _mesa_swap4((GLuint *) dest, width);
166
            }
167
         }
168
 
169
         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
170
      }
171
      else {
172
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
173
         break;
174
      }
175
   }
176
}
177
 
178
/**
179
 * glGetTexImage for stencil pixels.
180
 */
181
static void
182
get_tex_stencil(struct gl_context *ctx, GLuint dimensions,
183
                GLenum format, GLenum type, GLvoid *pixels,
184
                struct gl_texture_image *texImage)
185
{
186
   const GLint width = texImage->Width;
187
   const GLint height = texImage->Height;
188
   const GLint depth = texImage->Depth;
189
   GLint img, row;
190
 
191
   assert(format == GL_STENCIL_INDEX);
192
 
193
   for (img = 0; img < depth; img++) {
194
      GLubyte *srcMap;
195
      GLint rowstride;
196
 
197
      /* map src texture buffer */
198
      ctx->Driver.MapTextureImage(ctx, texImage, img,
199
                                  0, 0, width, height, GL_MAP_READ_BIT,
200
                                  &srcMap, &rowstride);
201
 
202
      if (srcMap) {
203
         for (row = 0; row < height; row++) {
204
            const GLubyte *src = srcMap + row * rowstride;
205
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
206
                                             width, height, format, type,
207
                                             img, row, 0);
208
            _mesa_unpack_ubyte_stencil_row(texImage->TexFormat,
209
                                           width,
210
                                           (const GLuint *) src,
211
                                           dest);
212
         }
213
 
214
         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
215
      }
216
      else {
217
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
218
         break;
219
      }
220
   }
221
}
222
 
223
 
224
/**
225
 * glGetTexImage for YCbCr pixels.
226
 */
227
static void
228
get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
229
              GLenum format, GLenum type, GLvoid *pixels,
230
              struct gl_texture_image *texImage)
231
{
232
   const GLint width = texImage->Width;
233
   const GLint height = texImage->Height;
234
   const GLint depth = texImage->Depth;
235
   GLint img, row;
236
 
237
   for (img = 0; img < depth; img++) {
238
      GLubyte *srcMap;
239
      GLint rowstride;
240
 
241
      /* map src texture buffer */
242
      ctx->Driver.MapTextureImage(ctx, texImage, img,
243
                                  0, 0, width, height, GL_MAP_READ_BIT,
244
                                  &srcMap, &rowstride);
245
 
246
      if (srcMap) {
247
         for (row = 0; row < height; row++) {
248
            const GLubyte *src = srcMap + row * rowstride;
249
            void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
250
                                             width, height, format, type,
251
                                             img, row, 0);
252
            memcpy(dest, src, width * sizeof(GLushort));
253
 
254
            /* check for byte swapping */
255
            if ((texImage->TexFormat == MESA_FORMAT_YCBCR
256
                 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
257
                (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
258
                 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
259
               if (!ctx->Pack.SwapBytes)
260
                  _mesa_swap2((GLushort *) dest, width);
261
            }
262
            else if (ctx->Pack.SwapBytes) {
263
               _mesa_swap2((GLushort *) dest, width);
264
            }
265
         }
266
 
267
         ctx->Driver.UnmapTextureImage(ctx, texImage, img);
268
      }
269
      else {
270
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
271
         break;
272
      }
273
   }
274
}
275
 
276
 
277
/**
278
 * Get a color texture image with decompression.
279
 */
280
static void
281
get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions,
282
                        GLenum format, GLenum type, GLvoid *pixels,
283
                        struct gl_texture_image *texImage,
284
                        GLbitfield transferOps)
285
{
286
   /* don't want to apply sRGB -> RGB conversion here so override the format */
287
   const mesa_format texFormat =
288
      _mesa_get_srgb_format_linear(texImage->TexFormat);
289
   const GLenum baseFormat = _mesa_get_format_base_format(texFormat);
290
   const GLuint width = texImage->Width;
291
   const GLuint height = texImage->Height;
292
   const GLuint depth = texImage->Depth;
293
   GLfloat *tempImage, *tempSlice;
294
   GLuint slice;
295
   int srcStride, dstStride;
296
   uint32_t dstFormat;
297
   bool needsRebase;
298
   uint8_t rebaseSwizzle[4];
299
 
300
   /* Decompress into temp float buffer, then pack into user buffer */
301
   tempImage = malloc(width * height * depth
302
                                  * 4 * sizeof(GLfloat));
303
   if (!tempImage) {
304
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
305
      return;
306
   }
307
 
308
   /* Decompress the texture image slices - results in 'tempImage' */
309
   for (slice = 0; slice < depth; slice++) {
310
      GLubyte *srcMap;
311
      GLint srcRowStride;
312
 
313
      tempSlice = tempImage + slice * 4 * width * height;
314
 
315
      ctx->Driver.MapTextureImage(ctx, texImage, slice,
316
                                  0, 0, width, height,
317
                                  GL_MAP_READ_BIT,
318
                                  &srcMap, &srcRowStride);
319
      if (srcMap) {
320
         _mesa_decompress_image(texFormat, width, height,
321
                                srcMap, srcRowStride, tempSlice);
322
 
323
         ctx->Driver.UnmapTextureImage(ctx, texImage, slice);
324
      }
325
      else {
326
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
327
         free(tempImage);
328
         return;
329
      }
330
   }
331
 
332
   /* Depending on the base format involved we may need to apply a rebase
333
    * transform (for example: if we download to a Luminance format we want
334
    * G=0 and B=0).
335
    */
336
   if (baseFormat == GL_LUMINANCE ||
337
       baseFormat == GL_INTENSITY) {
338
      needsRebase = true;
339
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
340
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
341
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
342
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
343
   } else if (baseFormat == GL_LUMINANCE_ALPHA) {
344
      needsRebase = true;
345
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
346
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
347
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
348
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W;
349
   } else {
350
      needsRebase = false;
351
   }
352
 
353
   srcStride = 4 * width * sizeof(GLfloat);
354
   dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
355
   dstFormat = _mesa_format_from_format_and_type(format, type);
356
   tempSlice = tempImage;
357
   for (slice = 0; slice < depth; slice++) {
358
      void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
359
                                       width, height, format, type,
360
                                       slice, 0, 0);
361
      _mesa_format_convert(dest, dstFormat, dstStride,
362
                           tempSlice, RGBA32_FLOAT, srcStride,
363
                           width, height,
364
                           needsRebase ? rebaseSwizzle : NULL);
365
      tempSlice += 4 * width * height;
366
   }
367
 
368
   free(tempImage);
369
}
370
 
371
 
372
/**
373
 * Return a base GL format given the user-requested format
374
 * for glGetTexImage().
375
 */
376
GLenum
377
_mesa_base_pack_format(GLenum format)
378
{
379
   switch (format) {
380
   case GL_ABGR_EXT:
381
   case GL_BGRA:
382
   case GL_BGRA_INTEGER:
383
   case GL_RGBA_INTEGER:
384
      return GL_RGBA;
385
   case GL_BGR:
386
   case GL_BGR_INTEGER:
387
   case GL_RGB_INTEGER:
388
      return GL_RGB;
389
   case GL_RED_INTEGER:
390
      return GL_RED;
391
   case GL_GREEN_INTEGER:
392
      return GL_GREEN;
393
   case GL_BLUE_INTEGER:
394
      return GL_BLUE;
395
   case GL_ALPHA_INTEGER:
396
      return GL_ALPHA;
397
   case GL_LUMINANCE_INTEGER_EXT:
398
      return GL_LUMINANCE;
399
   case GL_LUMINANCE_ALPHA_INTEGER_EXT:
400
      return GL_LUMINANCE_ALPHA;
401
   default:
402
      return format;
403
   }
404
}
405
 
406
 
407
/**
408
 * Get an uncompressed color texture image.
409
 */
410
static void
411
get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
412
                          GLenum format, GLenum type, GLvoid *pixels,
413
                          struct gl_texture_image *texImage,
414
                          GLbitfield transferOps)
415
{
416
   /* don't want to apply sRGB -> RGB conversion here so override the format */
417
   const mesa_format texFormat =
418
      _mesa_get_srgb_format_linear(texImage->TexFormat);
419
   const GLuint width = texImage->Width;
420
   GLuint height = texImage->Height;
421
   GLuint depth = texImage->Depth;
422
   GLuint img;
423
   GLboolean dst_is_integer;
424
   uint32_t dst_format;
425
   int dst_stride;
426
   uint8_t rebaseSwizzle[4];
427
   bool needsRebase;
428
   void *rgba = NULL;
429
 
430
   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
431
      depth = height;
432
      height = 1;
433
   }
434
 
435
   /* Depending on the base format involved we may need to apply a rebase
436
    * transform (for example: if we download to a Luminance format we want
437
    * G=0 and B=0).
438
    */
439
   if (texImage->_BaseFormat == GL_LUMINANCE ||
440
       texImage->_BaseFormat == GL_INTENSITY) {
441
      needsRebase = true;
442
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
443
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
444
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
445
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
446
   } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
447
      needsRebase = true;
448
      rebaseSwizzle[0] = MESA_FORMAT_SWIZZLE_X;
449
      rebaseSwizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
450
      rebaseSwizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
451
      rebaseSwizzle[3] = MESA_FORMAT_SWIZZLE_W;
452
    } else if (texImage->_BaseFormat != _mesa_get_format_base_format(texFormat)) {
453
      needsRebase =
454
         _mesa_compute_rgba2base2rgba_component_mapping(texImage->_BaseFormat,
455
                                                        rebaseSwizzle);
456
    } else {
457
      needsRebase = false;
458
    }
459
 
460
   /* Describe the dst format */
461
   dst_is_integer = _mesa_is_enum_format_integer(format);
462
   dst_format = _mesa_format_from_format_and_type(format, type);
463
   dst_stride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
464
 
465
   /* Since _mesa_format_convert does not handle transferOps we need to handle
466
    * them before we call the function. This requires to convert to RGBA float
467
    * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is
468
    * integer then transferOps do not apply.
469
    */
470
   assert(!transferOps || (transferOps && !dst_is_integer));
471
   (void) dst_is_integer; /* silence unused var warning */
472
 
473
   for (img = 0; img < depth; img++) {
474
      GLubyte *srcMap;
475
      GLint rowstride;
476
      GLubyte *img_src;
477
      void *dest;
478
      void *src;
479
      int src_stride;
480
      uint32_t src_format;
481
 
482
      /* map src texture buffer */
483
      ctx->Driver.MapTextureImage(ctx, texImage, img,
484
                                  0, 0, width, height, GL_MAP_READ_BIT,
485
                                  &srcMap, &rowstride);
486
      if (!srcMap) {
487
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
488
         goto done;
489
      }
490
 
491
      img_src = srcMap;
492
      dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
493
                                 width, height, format, type,
494
                                 img, 0, 0);
495
 
496
      if (transferOps) {
497
         uint32_t rgba_format;
498
         int rgba_stride;
499
         bool need_convert = false;
500
 
501
         /* We will convert to RGBA float */
502
         rgba_format = RGBA32_FLOAT;
503
         rgba_stride = width * 4 * sizeof(GLfloat);
504
 
505
         /* If we are lucky and the dst format matches the RGBA format we need
506
          * to convert to, then we can convert directly into the dst buffer
507
          * and avoid the final conversion/copy from the rgba buffer to the dst
508
          * buffer.
509
          */
510
         if (format == rgba_format) {
511
            rgba = dest;
512
         } else if (rgba == NULL) { /* Allocate the RGBA buffer only once */
513
            need_convert = true;
514
            rgba = malloc(height * rgba_stride);
515
            if (!rgba) {
516
               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
517
               ctx->Driver.UnmapTextureImage(ctx, texImage, img);
518
               return;
519
            }
520
         }
521
 
522
         _mesa_format_convert(rgba, rgba_format, rgba_stride,
523
                              img_src, texFormat, rowstride,
524
                              width, height,
525
                              needsRebase ? rebaseSwizzle : NULL);
526
 
527
         /* Handle transfer ops now */
528
         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba);
529
 
530
         /* If we had to rebase, we have already handled that */
531
         needsRebase = false;
532
 
533
         /* If we were lucky and our RGBA conversion matches the dst format, then
534
          * we are done.
535
          */
536
         if (!need_convert)
537
            goto do_swap;
538
 
539
         /* Otherwise, we need to convert from RGBA to dst next */
540
         src = rgba;
541
         src_format = rgba_format;
542
         src_stride = rgba_stride;
543
      } else {
544
         /* No RGBA conversion needed, convert directly to dst */
545
         src = img_src;
546
         src_format = texFormat;
547
         src_stride = rowstride;
548
      }
549
 
550
      /* Do the conversion to destination format */
551
      _mesa_format_convert(dest, dst_format, dst_stride,
552
                           src, src_format, src_stride,
553
                           width, height,
554
                           needsRebase ? rebaseSwizzle : NULL);
555
 
556
   do_swap:
557
      /* Handle byte swapping if required */
558
      if (ctx->Pack.SwapBytes) {
559
         GLint swapSize = _mesa_sizeof_packed_type(type);
560
         if (swapSize == 2 || swapSize == 4) {
561
            int swapsPerPixel = _mesa_bytes_per_pixel(format, type) / swapSize;
562
            assert(_mesa_bytes_per_pixel(format, type) % swapSize == 0);
563
            if (swapSize == 2)
564
               _mesa_swap2((GLushort *) dest, width * height * swapsPerPixel);
565
            else if (swapSize == 4)
566
               _mesa_swap4((GLuint *) dest, width * height * swapsPerPixel);
567
         }
568
      }
569
 
570
      /* Unmap the src texture buffer */
571
      ctx->Driver.UnmapTextureImage(ctx, texImage, img);
572
   }
573
 
574
done:
575
   if (rgba)
576
      free(rgba);
577
}
578
 
579
 
580
/**
581
 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
582
 * Compressed textures are handled here as well.
583
 */
584
static void
585
get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
586
             GLenum format, GLenum type, GLvoid *pixels,
587
             struct gl_texture_image *texImage)
588
{
589
   const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
590
   GLbitfield transferOps = 0x0;
591
 
592
   /* In general, clamping does not apply to glGetTexImage, except when
593
    * the returned type of the image can't hold negative values.
594
    */
595
   if (type_needs_clamping(type)) {
596
      /* the returned image type can't have negative values */
597
      if (dataType == GL_FLOAT ||
598
          dataType == GL_HALF_FLOAT ||
599
          dataType == GL_SIGNED_NORMALIZED ||
600
          format == GL_LUMINANCE ||
601
          format == GL_LUMINANCE_ALPHA) {
602
         transferOps |= IMAGE_CLAMP_BIT;
603
      }
604
   }
605
 
606
   if (_mesa_is_format_compressed(texImage->TexFormat)) {
607
      get_tex_rgba_compressed(ctx, dimensions, format, type,
608
                              pixels, texImage, transferOps);
609
   }
610
   else {
611
      get_tex_rgba_uncompressed(ctx, dimensions, format, type,
612
                                pixels, texImage, transferOps);
613
   }
614
}
615
 
616
 
617
/**
618
 * Try to do glGetTexImage() with simple memcpy().
619
 * \return GL_TRUE if done, GL_FALSE otherwise
620
 */
621
static GLboolean
622
get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
623
               GLvoid *pixels,
624
               struct gl_texture_image *texImage)
625
{
626
   const GLenum target = texImage->TexObject->Target;
627
   GLboolean memCopy = GL_FALSE;
628
   GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat);
629
 
630
   /*
631
    * Check if we can use memcpy to copy from the hardware texture
632
    * format to the user's format/type.
633
    * Note that GL's pixel transfer ops don't apply to glGetTexImage()
634
    */
635
   if ((target == GL_TEXTURE_1D ||
636
        target == GL_TEXTURE_2D ||
637
        target == GL_TEXTURE_RECTANGLE ||
638
        _mesa_is_cube_face(target)) &&
639
       texBaseFormat == texImage->_BaseFormat) {
640
      memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat,
641
                                                     format, type,
642
                                                     ctx->Pack.SwapBytes);
643
   }
644
 
645
   if (memCopy) {
646
      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
647
      const GLint bytesPerRow = texImage->Width * bpp;
648
      GLubyte *dst =
649
         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
650
                               texImage->Height, format, type, 0, 0);
651
      const GLint dstRowStride =
652
         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
653
      GLubyte *src;
654
      GLint srcRowStride;
655
 
656
      /* map src texture buffer */
657
      ctx->Driver.MapTextureImage(ctx, texImage, 0,
658
                                  0, 0, texImage->Width, texImage->Height,
659
                                  GL_MAP_READ_BIT, &src, &srcRowStride);
660
 
661
      if (src) {
662
         if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
663
            memcpy(dst, src, bytesPerRow * texImage->Height);
664
         }
665
         else {
666
            GLuint row;
667
            for (row = 0; row < texImage->Height; row++) {
668
               memcpy(dst, src, bytesPerRow);
669
               dst += dstRowStride;
670
               src += srcRowStride;
671
            }
672
         }
673
 
674
         /* unmap src texture buffer */
675
         ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
676
      }
677
      else {
678
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
679
      }
680
   }
681
 
682
   return memCopy;
683
}
684
 
685
 
686
/**
687
 * This is the software fallback for Driver.GetTexImage().
688
 * All error checking will have been done before this routine is called.
689
 * We'll call ctx->Driver.MapTextureImage() to access the data, then
690
 * unmap with ctx->Driver.UnmapTextureImage().
691
 */
692
void
693
_mesa_GetTexImage_sw(struct gl_context *ctx,
694
                     GLenum format, GLenum type, GLvoid *pixels,
695
                     struct gl_texture_image *texImage)
696
{
697
   const GLuint dimensions =
698
      _mesa_get_texture_dimensions(texImage->TexObject->Target);
699
 
700
   /* map dest buffer, if PBO */
701
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
702
      /* Packing texture image into a PBO.
703
       * Map the (potentially) VRAM-based buffer into our process space so
704
       * we can write into it with the code below.
705
       * A hardware driver might use a sophisticated blit to move the
706
       * texture data to the PBO if the PBO is in VRAM along with the texture.
707
       */
708
      GLubyte *buf = (GLubyte *)
709
         ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
710
				    GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
711
                                    MAP_INTERNAL);
712
      if (!buf) {
713
         /* out of memory or other unexpected error */
714
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
715
         return;
716
      }
717
      /*  was an offset into the PBO.
718
       * Now make it a real, client-side pointer inside the mapped region.
719
       */
720
      pixels = ADD_POINTERS(buf, pixels);
721
   }
722
 
723
   if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
724
      /* all done */
725
   }
726
   else if (format == GL_DEPTH_COMPONENT) {
727
      get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
728
   }
729
   else if (format == GL_DEPTH_STENCIL_EXT) {
730
      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
731
   }
732
   else if (format == GL_STENCIL_INDEX) {
733
      get_tex_stencil(ctx, dimensions, format, type, pixels, texImage);
734
   }
735
   else if (format == GL_YCBCR_MESA) {
736
      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
737
   }
738
   else {
739
      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
740
   }
741
 
742
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
743
      ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
744
   }
745
}
746
 
747
 
748
 
749
/**
750
 * This is the software fallback for Driver.GetCompressedTexImage().
751
 * All error checking will have been done before this routine is called.
752
 */
753
void
754
_mesa_GetCompressedTexImage_sw(struct gl_context *ctx,
755
                               struct gl_texture_image *texImage,
756
                               GLvoid *img)
757
{
758
   const GLuint dimensions =
759
      _mesa_get_texture_dimensions(texImage->TexObject->Target);
760
   struct compressed_pixelstore store;
761
   GLint slice;
762
   GLubyte *dest;
763
 
764
   _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat,
765
                                       texImage->Width, texImage->Height,
766
                                       texImage->Depth,
767
                                       &ctx->Pack,
768
                                       &store);
769
 
770
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
771
      /* pack texture image into a PBO */
772
      dest = (GLubyte *)
773
         ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
774
				    GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
775
                                    MAP_INTERNAL);
776
      if (!dest) {
777
         /* out of memory or other unexpected error */
778
         _mesa_error(ctx, GL_OUT_OF_MEMORY,
779
                     "glGetCompresssedTexImage(map PBO failed)");
780
         return;
781
      }
782
      dest = ADD_POINTERS(dest, img);
783
   } else {
784
      dest = img;
785
   }
786
 
787
   dest += store.SkipBytes;
788
 
789
   for (slice = 0; slice < store.CopySlices; slice++) {
790
      GLint srcRowStride;
791
      GLubyte *src;
792
 
793
      /* map src texture buffer */
794
      ctx->Driver.MapTextureImage(ctx, texImage, slice,
795
                                  0, 0, texImage->Width, texImage->Height,
796
                                  GL_MAP_READ_BIT, &src, &srcRowStride);
797
 
798
      if (src) {
799
         GLint i;
800
         for (i = 0; i < store.CopyRowsPerSlice; i++) {
801
            memcpy(dest, src, store.CopyBytesPerRow);
802
            dest += store.TotalBytesPerRow;
803
            src += srcRowStride;
804
         }
805
 
806
         ctx->Driver.UnmapTextureImage(ctx, texImage, slice);
807
 
808
         /* Advance to next slice */
809
         dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice);
810
 
811
      } else {
812
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
813
      }
814
   }
815
 
816
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
817
      ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
818
   }
819
}
820
 
821
 
822
/**
823
 * Validate the texture target enum supplied to glGetTex(ture)Image or
824
 * glGetCompressedTex(ture)Image.
825
 */
826
static GLboolean
827
legal_getteximage_target(struct gl_context *ctx, GLenum target, bool dsa)
828
{
829
   switch (target) {
830
   case GL_TEXTURE_1D:
831
   case GL_TEXTURE_2D:
832
   case GL_TEXTURE_3D:
833
      return GL_TRUE;
834
   case GL_TEXTURE_RECTANGLE_NV:
835
      return ctx->Extensions.NV_texture_rectangle;
836
   case GL_TEXTURE_1D_ARRAY_EXT:
837
   case GL_TEXTURE_2D_ARRAY_EXT:
838
      return ctx->Extensions.EXT_texture_array;
839
   case GL_TEXTURE_CUBE_MAP_ARRAY:
840
      return ctx->Extensions.ARB_texture_cube_map_array;
841
 
842
   /* Section 8.11 (Texture Queries) of the OpenGL 4.5 core profile spec
843
    * (30.10.2014) says:
844
    *    "An INVALID_ENUM error is generated if the effective target is not
845
    *    one of TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_1D_ARRAY,
846
    *    TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY, TEXTURE_RECTANGLE, one of
847
    *    the targets from table 8.19 (for GetTexImage and GetnTexImage *only*),
848
    *    or TEXTURE_CUBE_MAP (for GetTextureImage *only*)." (Emphasis added.)
849
    */
850
   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
851
   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
852
   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
853
   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
854
   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
855
   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
856
      return dsa ? GL_FALSE : ctx->Extensions.ARB_texture_cube_map;
857
   case GL_TEXTURE_CUBE_MAP:
858
      return dsa ? GL_TRUE : GL_FALSE;
859
   default:
860
      return GL_FALSE;
861
   }
862
}
863
 
864
 
865
/**
866
 * Do error checking for a glGetTex(ture)Image() call.
867
 * \return GL_TRUE if any error, GL_FALSE if no errors.
868
 */
869
static GLboolean
870
getteximage_error_check(struct gl_context *ctx,
871
                        struct gl_texture_image *texImage,
872
                        GLenum target, GLint level,
873
                        GLenum format, GLenum type, GLsizei clientMemSize,
874
                        GLvoid *pixels, bool dsa)
875
{
876
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
877
   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
878
   GLenum baseFormat;
879
   const char *suffix = dsa ? "ture" : "";
880
 
881
   assert(texImage);
882
   assert(maxLevels != 0);
883
   if (level < 0 || level >= maxLevels) {
884
      _mesa_error(ctx, GL_INVALID_VALUE,
885
                  "glGetTex%sImage(level out of range)", suffix);
886
      return GL_TRUE;
887
   }
888
 
889
   /*
890
    * Format and type checking has been moved up to GetnTexImage and
891
    * GetTextureImage so that it happens before getting the texImage object.
892
    */
893
 
894
   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
895
 
896
   /* Make sure the requested image format is compatible with the
897
    * texture's format.
898
    */
899
   if (_mesa_is_color_format(format)
900
       && !_mesa_is_color_format(baseFormat)) {
901
      _mesa_error(ctx, GL_INVALID_OPERATION,
902
                  "glGetTex%sImage(format mismatch)", suffix);
903
      return GL_TRUE;
904
   }
905
   else if (_mesa_is_depth_format(format)
906
            && !_mesa_is_depth_format(baseFormat)
907
            && !_mesa_is_depthstencil_format(baseFormat)) {
908
      _mesa_error(ctx, GL_INVALID_OPERATION,
909
                  "glGetTex%sImage(format mismatch)", suffix);
910
      return GL_TRUE;
911
   }
912
   else if (_mesa_is_stencil_format(format)
913
            && !ctx->Extensions.ARB_texture_stencil8) {
914
      _mesa_error(ctx, GL_INVALID_ENUM,
915
                  "glGetTex%sImage(format=GL_STENCIL_INDEX)", suffix);
916
      return GL_TRUE;
917
   }
918
   else if (_mesa_is_ycbcr_format(format)
919
            && !_mesa_is_ycbcr_format(baseFormat)) {
920
      _mesa_error(ctx, GL_INVALID_OPERATION,
921
                  "glGetTex%sImage(format mismatch)", suffix);
922
      return GL_TRUE;
923
   }
924
   else if (_mesa_is_depthstencil_format(format)
925
            && !_mesa_is_depthstencil_format(baseFormat)) {
926
      _mesa_error(ctx, GL_INVALID_OPERATION,
927
                  "glGetTex%sImage(format mismatch)", suffix);
928
      return GL_TRUE;
929
   }
930
   else if (!_mesa_is_stencil_format(format) && _mesa_is_enum_format_integer(format) !=
931
            _mesa_is_format_integer(texImage->TexFormat)) {
932
      _mesa_error(ctx, GL_INVALID_OPERATION,
933
                  "glGetTex%sImage(format mismatch)", suffix);
934
      return GL_TRUE;
935
   }
936
 
937
   if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
938
                                  texImage->Height, texImage->Depth,
939
                                  format, type, clientMemSize, pixels)) {
940
      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
941
         _mesa_error(ctx, GL_INVALID_OPERATION,
942
                     "glGetTex%sImage(out of bounds PBO access)", suffix);
943
      } else {
944
         _mesa_error(ctx, GL_INVALID_OPERATION,
945
                     "%s(out of bounds access:"
946
                     " bufSize (%d) is too small)",
947
                     dsa ? "glGetTextureImage" : "glGetnTexImageARB",
948
                     clientMemSize);
949
      }
950
      return GL_TRUE;
951
   }
952
 
953
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
954
      /* PBO should not be mapped */
955
      if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
956
         _mesa_error(ctx, GL_INVALID_OPERATION,
957
                     "glGetTex%sImage(PBO is mapped)", suffix);
958
         return GL_TRUE;
959
      }
960
   }
961
 
962
   return GL_FALSE;
963
}
964
 
965
 
966
/**
967
 * This is the implementation for glGetnTexImageARB, glGetTextureImage,
968
 * and glGetTexImage.
969
 *
970
 * Requires caller to pass in texImage object because _mesa_GetTextureImage
971
 * must handle the GL_TEXTURE_CUBE_MAP target.
972
 *
973
 * \param target texture target.
974
 * \param level image level.
975
 * \param format pixel data format for returned image.
976
 * \param type pixel data type for returned image.
977
 * \param bufSize size of the pixels data buffer.
978
 * \param pixels returned pixel data.
979
 * \param dsa True when the caller is an ARB_direct_state_access function,
980
 *            false otherwise
981
 */
982
void
983
_mesa_get_texture_image(struct gl_context *ctx,
984
                        struct gl_texture_object *texObj,
985
                        struct gl_texture_image *texImage, GLenum target,
986
                        GLint level, GLenum format, GLenum type,
987
                        GLsizei bufSize, GLvoid *pixels, bool dsa)
988
{
989
   assert(texObj);
990
   assert(texImage);
991
 
992
   FLUSH_VERTICES(ctx, 0);
993
 
994
   /*
995
    * Legal target checking has been moved up to GetnTexImage and
996
    * GetTextureImage so that it can be caught before receiving a NULL
997
    * texImage object and exiting.
998
    */
999
 
1000
   if (getteximage_error_check(ctx, texImage, target, level, format,
1001
                               type, bufSize, pixels, dsa)) {
1002
      return;
1003
   }
1004
 
1005
   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
1006
      /* not an error, do nothing */
1007
      return;
1008
   }
1009
 
1010
   if (_mesa_is_zero_size_texture(texImage))
1011
      return;
1012
 
1013
   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1014
      _mesa_debug(ctx, "glGetTex%sImage(tex %u) format = %s, w=%d, h=%d,"
1015
                  " dstFmt=0x%x, dstType=0x%x\n",
1016
                  dsa ? "ture": "",
1017
                  texObj->Name,
1018
                  _mesa_get_format_name(texImage->TexFormat),
1019
                  texImage->Width, texImage->Height,
1020
                  format, type);
1021
   }
1022
 
1023
   _mesa_lock_texture(ctx, texObj);
1024
   {
1025
      ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
1026
   }
1027
   _mesa_unlock_texture(ctx, texObj);
1028
}
1029
 
1030
/**
1031
 * Get texture image.  Called by glGetTexImage.
1032
 *
1033
 * \param target texture target.
1034
 * \param level image level.
1035
 * \param format pixel data format for returned image.
1036
 * \param type pixel data type for returned image.
1037
 * \param bufSize size of the pixels data buffer.
1038
 * \param pixels returned pixel data.
1039
 */
1040
void GLAPIENTRY
1041
_mesa_GetnTexImageARB(GLenum target, GLint level, GLenum format,
1042
                      GLenum type, GLsizei bufSize, GLvoid *pixels)
1043
{
1044
   struct gl_texture_object *texObj;
1045
   struct gl_texture_image *texImage;
1046
   GLenum err;
1047
   GET_CURRENT_CONTEXT(ctx);
1048
 
1049
   /*
1050
    * This has been moved here because a format/type mismatch can cause a NULL
1051
    * texImage object, which in turn causes the mismatch error to be
1052
    * ignored.
1053
    */
1054
   err = _mesa_error_check_format_and_type(ctx, format, type);
1055
   if (err != GL_NO_ERROR) {
1056
      _mesa_error(ctx, err, "glGetnTexImage(format/type)");
1057
      return;
1058
   }
1059
 
1060
   /*
1061
    * Legal target checking has been moved here to prevent exiting with a NULL
1062
    * texImage object.
1063
    */
1064
   if (!legal_getteximage_target(ctx, target, false)) {
1065
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetnTexImage(target=0x%x)",
1066
                  target);
1067
      return;
1068
   }
1069
 
1070
   texObj = _mesa_get_current_tex_object(ctx, target);
1071
   if (!texObj)
1072
      return;
1073
 
1074
   texImage = _mesa_select_tex_image(texObj, target, level);
1075
   if (!texImage)
1076
      return;
1077
 
1078
   _mesa_get_texture_image(ctx, texObj, texImage, target, level, format, type,
1079
                           bufSize, pixels, false);
1080
}
1081
 
1082
 
1083
void GLAPIENTRY
1084
_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
1085
                   GLenum type, GLvoid *pixels )
1086
{
1087
   _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
1088
}
1089
 
1090
/**
1091
 * Get texture image.
1092
 *
1093
 * \param texture texture name.
1094
 * \param level image level.
1095
 * \param format pixel data format for returned image.
1096
 * \param type pixel data type for returned image.
1097
 * \param bufSize size of the pixels data buffer.
1098
 * \param pixels returned pixel data.
1099
 */
1100
void GLAPIENTRY
1101
_mesa_GetTextureImage(GLuint texture, GLint level, GLenum format,
1102
                      GLenum type, GLsizei bufSize, GLvoid *pixels)
1103
{
1104
   struct gl_texture_object *texObj;
1105
   struct gl_texture_image *texImage;
1106
   int i;
1107
   GLint image_stride;
1108
   GLenum err;
1109
   GET_CURRENT_CONTEXT(ctx);
1110
 
1111
   if (!ctx->Extensions.ARB_direct_state_access) {
1112
      _mesa_error(ctx, GL_INVALID_OPERATION,
1113
                  "glGetTextureImage(GL_ARB_direct_state_access "
1114
                  "is not supported)");
1115
      return;
1116
   }
1117
 
1118
   /*
1119
    * This has been moved here because a format/type mismatch can cause a NULL
1120
    * texImage object, which in turn causes the mismatch error to be
1121
    * ignored.
1122
    */
1123
   err = _mesa_error_check_format_and_type(ctx, format, type);
1124
   if (err != GL_NO_ERROR) {
1125
      _mesa_error(ctx, err, "glGetTextureImage(format/type)");
1126
      return;
1127
   }
1128
 
1129
   texObj = _mesa_lookup_texture_err(ctx, texture, "glGetTextureImage");
1130
   if (!texObj)
1131
      return;
1132
 
1133
   /*
1134
    * Legal target checking has been moved here to prevent exiting with a NULL
1135
    * texImage object.
1136
    */
1137
   if (!legal_getteximage_target(ctx, texObj->Target, true)) {
1138
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTextureImage(target=%s)",
1139
                  _mesa_lookup_enum_by_nr(texObj->Target));
1140
      return;
1141
   }
1142
 
1143
   /* Must handle special case GL_TEXTURE_CUBE_MAP. */
1144
   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
1145
 
1146
      /* Make sure the texture object is a proper cube.
1147
       * (See texturesubimage in teximage.c for details on why this check is
1148
       * performed.)
1149
       */
1150
      if (!_mesa_cube_level_complete(texObj, level)) {
1151
         _mesa_error(ctx, GL_INVALID_OPERATION,
1152
                     "glGetTextureImage(cube map incomplete)");
1153
         return;
1154
      }
1155
 
1156
      /* Copy each face. */
1157
      for (i = 0; i < 6; ++i) {
1158
         texImage = texObj->Image[i][level];
1159
         assert(texImage);
1160
 
1161
         _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level,
1162
                                 format, type, bufSize, pixels, true);
1163
 
1164
         image_stride = _mesa_image_image_stride(&ctx->Pack, texImage->Width,
1165
                                                 texImage->Height, format,
1166
                                                 type);
1167
         pixels = (GLubyte *) pixels + image_stride;
1168
         bufSize -= image_stride;
1169
      }
1170
   }
1171
   else {
1172
      texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
1173
      if (!texImage)
1174
         return;
1175
 
1176
      _mesa_get_texture_image(ctx, texObj, texImage, texObj->Target, level,
1177
                              format, type, bufSize, pixels, true);
1178
   }
1179
}
1180
 
1181
/**
1182
 * Do error checking for a glGetCompressedTexImage() call.
1183
 * \return GL_TRUE if any error, GL_FALSE if no errors.
1184
 */
1185
static GLboolean
1186
getcompressedteximage_error_check(struct gl_context *ctx,
1187
                                  struct gl_texture_image *texImage,
1188
                                  GLenum target,
1189
                                  GLint level, GLsizei clientMemSize,
1190
                                  GLvoid *img, bool dsa)
1191
{
1192
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
1193
   GLuint compressedSize, dimensions;
1194
   const char *suffix = dsa ? "ture" : "";
1195
 
1196
   assert(texImage);
1197
 
1198
   if (!legal_getteximage_target(ctx, target, dsa)) {
1199
      _mesa_error(ctx, GL_INVALID_ENUM,
1200
                  "glGetCompressedTex%sImage(target=%s)", suffix,
1201
                  _mesa_lookup_enum_by_nr(target));
1202
      return GL_TRUE;
1203
   }
1204
 
1205
   assert(maxLevels != 0);
1206
   if (level < 0 || level >= maxLevels) {
1207
      _mesa_error(ctx, GL_INVALID_VALUE,
1208
                  "glGetCompressedTex%sImage(bad level = %d)", suffix, level);
1209
      return GL_TRUE;
1210
   }
1211
 
1212
   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
1213
      _mesa_error(ctx, GL_INVALID_OPERATION,
1214
                  "glGetCompressedTex%sImage(texture is not compressed)",
1215
                  suffix);
1216
      return GL_TRUE;
1217
   }
1218
 
1219
   compressedSize = _mesa_format_image_size(texImage->TexFormat,
1220
                                            texImage->Width,
1221
                                            texImage->Height,
1222
                                            texImage->Depth);
1223
 
1224
   /* Check for invalid pixel storage modes */
1225
   dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target);
1226
   if (!_mesa_compressed_pixel_storage_error_check(ctx, dimensions,
1227
                                              &ctx->Pack, dsa ?
1228
                                              "glGetCompressedTextureImage":
1229
                                              "glGetCompressedTexImage")) {
1230
      return GL_TRUE;
1231
   }
1232
 
1233
   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1234
      /* do bounds checking on writing to client memory */
1235
      if (clientMemSize < (GLsizei) compressedSize) {
1236
         _mesa_error(ctx, GL_INVALID_OPERATION,
1237
                     "%s(out of bounds access: bufSize (%d) is too small)",
1238
                     dsa ? "glGetCompressedTextureImage" :
1239
                     "glGetnCompressedTexImageARB", clientMemSize);
1240
         return GL_TRUE;
1241
      }
1242
   } else {
1243
      /* do bounds checking on PBO write */
1244
      if ((const GLubyte *) img + compressedSize >
1245
          (const GLubyte *) ctx->Pack.BufferObj->Size) {
1246
         _mesa_error(ctx, GL_INVALID_OPERATION,
1247
                     "glGetCompressedTex%sImage(out of bounds PBO access)",
1248
                     suffix);
1249
         return GL_TRUE;
1250
      }
1251
 
1252
      /* make sure PBO is not mapped */
1253
      if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1254
         _mesa_error(ctx, GL_INVALID_OPERATION,
1255
                     "glGetCompressedTex%sImage(PBO is mapped)", suffix);
1256
         return GL_TRUE;
1257
      }
1258
   }
1259
 
1260
   return GL_FALSE;
1261
}
1262
 
1263
/** Implements glGetnCompressedTexImageARB, glGetCompressedTexImage, and
1264
 * glGetCompressedTextureImage.
1265
 *
1266
 * texImage must be passed in because glGetCompressedTexImage must handle the
1267
 * target GL_TEXTURE_CUBE_MAP.
1268
 */
1269
void
1270
_mesa_get_compressed_texture_image(struct gl_context *ctx,
1271
                                   struct gl_texture_object *texObj,
1272
                                   struct gl_texture_image *texImage,
1273
                                   GLenum target, GLint level,
1274
                                   GLsizei bufSize, GLvoid *pixels,
1275
                                   bool dsa)
1276
{
1277
   assert(texObj);
1278
   assert(texImage);
1279
 
1280
   FLUSH_VERTICES(ctx, 0);
1281
 
1282
   if (getcompressedteximage_error_check(ctx, texImage, target, level,
1283
                                         bufSize, pixels, dsa)) {
1284
      return;
1285
   }
1286
 
1287
   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
1288
      /* not an error, do nothing */
1289
      return;
1290
   }
1291
 
1292
   if (_mesa_is_zero_size_texture(texImage))
1293
      return;
1294
 
1295
   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1296
      _mesa_debug(ctx,
1297
                  "glGetCompressedTex%sImage(tex %u) format = %s, w=%d, h=%d\n",
1298
                  dsa ? "ture" : "", texObj->Name,
1299
                  _mesa_get_format_name(texImage->TexFormat),
1300
                  texImage->Width, texImage->Height);
1301
   }
1302
 
1303
   _mesa_lock_texture(ctx, texObj);
1304
   {
1305
      ctx->Driver.GetCompressedTexImage(ctx, texImage, pixels);
1306
   }
1307
   _mesa_unlock_texture(ctx, texObj);
1308
}
1309
 
1310
void GLAPIENTRY
1311
_mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1312
                                GLvoid *img)
1313
{
1314
   struct gl_texture_object *texObj;
1315
   struct gl_texture_image *texImage;
1316
   GET_CURRENT_CONTEXT(ctx);
1317
 
1318
   texObj = _mesa_get_current_tex_object(ctx, target);
1319
   if (!texObj)
1320
      return;
1321
 
1322
   texImage = _mesa_select_tex_image(texObj, target, level);
1323
   if (!texImage)
1324
      return;
1325
 
1326
   _mesa_get_compressed_texture_image(ctx, texObj, texImage, target, level,
1327
                                      bufSize, img, false);
1328
}
1329
 
1330
void GLAPIENTRY
1331
_mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img)
1332
{
1333
   _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
1334
}
1335
 
1336
/**
1337
 * Get compressed texture image.
1338
 *
1339
 * \param texture texture name.
1340
 * \param level image level.
1341
 * \param bufSize size of the pixels data buffer.
1342
 * \param pixels returned pixel data.
1343
 */
1344
void GLAPIENTRY
1345
_mesa_GetCompressedTextureImage(GLuint texture, GLint level,
1346
                                GLsizei bufSize, GLvoid *pixels)
1347
{
1348
   struct gl_texture_object *texObj;
1349
   struct gl_texture_image *texImage;
1350
   int i;
1351
   GLint image_stride;
1352
   GET_CURRENT_CONTEXT(ctx);
1353
 
1354
   if (!ctx->Extensions.ARB_direct_state_access) {
1355
      _mesa_error(ctx, GL_INVALID_OPERATION,
1356
                  "glGetCompressedTextureImage(GL_ARB_direct_state_access "
1357
                  "is not supported)");
1358
      return;
1359
   }
1360
 
1361
   texObj = _mesa_lookup_texture_err(ctx, texture,
1362
                                     "glGetCompressedTextureImage");
1363
   if (!texObj)
1364
      return;
1365
 
1366
   /* Must handle special case GL_TEXTURE_CUBE_MAP. */
1367
   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
1368
 
1369
      /* Make sure the texture object is a proper cube.
1370
       * (See texturesubimage in teximage.c for details on why this check is
1371
       * performed.)
1372
       */
1373
      if (!_mesa_cube_level_complete(texObj, level)) {
1374
         _mesa_error(ctx, GL_INVALID_OPERATION,
1375
                     "glGetCompressedTextureImage(cube map incomplete)");
1376
         return;
1377
      }
1378
 
1379
      /* Copy each face. */
1380
      for (i = 0; i < 6; ++i) {
1381
         texImage = texObj->Image[i][level];
1382
         assert(texImage);
1383
 
1384
         _mesa_get_compressed_texture_image(ctx, texObj, texImage,
1385
                                            texObj->Target, level,
1386
                                            bufSize, pixels, true);
1387
 
1388
         /* Compressed images don't have a client format */
1389
         image_stride = _mesa_format_image_size(texImage->TexFormat,
1390
                                                texImage->Width,
1391
                                                texImage->Height, 1);
1392
 
1393
         pixels = (GLubyte *) pixels + image_stride;
1394
         bufSize -= image_stride;
1395
      }
1396
   }
1397
   else {
1398
      texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
1399
      if (!texImage)
1400
         return;
1401
 
1402
      _mesa_get_compressed_texture_image(ctx, texObj, texImage,
1403
                                         texObj->Target, level, bufSize,
1404
                                         pixels, true);
1405
   }
1406
}