Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  7.7
4
 *
5
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6
 * Copyright (c) 2009 VMware, Inc.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the "Software"),
10
 * to deal in the Software without restriction, including without limitation
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
 * and/or sell copies of the Software, and to permit persons to whom the
13
 * Software is furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included
16
 * in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
 * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 "image.h"
38
#include "pack.h"
39
#include "texgetimage.h"
40
#include "teximage.h"
41
 
42
 
43
 
44
/**
45
 * Can the given type represent negative values?
46
 */
47
static INLINE GLboolean
48
type_with_negative_values(GLenum type)
49
{
50
   switch (type) {
51
   case GL_BYTE:
52
   case GL_SHORT:
53
   case GL_INT:
54
   case GL_FLOAT:
55
   case GL_HALF_FLOAT_ARB:
56
      return GL_TRUE;
57
   default:
58
      return GL_FALSE;
59
   }
60
}
61
 
62
 
63
/**
64
 * glGetTexImage for color index pixels.
65
 */
66
static void
67
get_tex_color_index(struct gl_context *ctx, GLuint dimensions,
68
                    GLenum format, GLenum type, GLvoid *pixels,
69
                    const struct gl_texture_image *texImage)
70
{
71
   const GLint width = texImage->Width;
72
   const GLint height = texImage->Height;
73
   const GLint depth = texImage->Depth;
74
   const GLuint indexBits =
75
      _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
76
   const GLbitfield transferOps = 0x0;
77
   GLint img, row, col;
78
 
79
   for (img = 0; img < depth; img++) {
80
      for (row = 0; row < height; row++) {
81
         GLuint indexRow[MAX_WIDTH] = { 0 };
82
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
83
                                          width, height, format, type,
84
                                          img, row, 0);
85
         assert(dest);
86
 
87
         if (indexBits == 8) {
88
            const GLubyte *src = (const GLubyte *) texImage->Data;
89
            src += width * (img * texImage->Height + row);
90
            for (col = 0; col < width; col++) {
91
               indexRow[col] = src[col];
92
            }
93
         }
94
         else if (indexBits == 16) {
95
            const GLushort *src = (const GLushort *) texImage->Data;
96
            src += width * (img * texImage->Height + row);
97
            for (col = 0; col < width; col++) {
98
               indexRow[col] = src[col];
99
            }
100
         }
101
         else {
102
            _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
103
         }
104
         _mesa_pack_index_span(ctx, width, type, dest,
105
                               indexRow, &ctx->Pack, transferOps);
106
      }
107
   }
108
}
109
 
110
 
111
/**
112
 * glGetTexImage for depth/Z pixels.
113
 */
114
static void
115
get_tex_depth(struct gl_context *ctx, GLuint dimensions,
116
              GLenum format, GLenum type, GLvoid *pixels,
117
              const struct gl_texture_image *texImage)
118
{
119
   const GLint width = texImage->Width;
120
   const GLint height = texImage->Height;
121
   const GLint depth = texImage->Depth;
122
   GLint img, row, col;
123
   GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
124
 
125
   if (!depthRow) {
126
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
127
      return;
128
   }
129
 
130
   for (img = 0; img < depth; img++) {
131
      for (row = 0; row < height; row++) {
132
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
133
                                          width, height, format, type,
134
                                          img, row, 0);
135
         assert(dest);
136
 
137
         for (col = 0; col < width; col++) {
138
            texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
139
         }
140
         _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
141
      }
142
   }
143
 
144
   free(depthRow);
145
}
146
 
147
 
148
/**
149
 * glGetTexImage for depth/stencil pixels.
150
 */
151
static void
152
get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
153
                      GLenum format, GLenum type, GLvoid *pixels,
154
                      const struct gl_texture_image *texImage)
155
{
156
   const GLint width = texImage->Width;
157
   const GLint height = texImage->Height;
158
   const GLint depth = texImage->Depth;
159
   const GLuint *src = (const GLuint *) texImage->Data;
160
   GLint img, row;
161
 
162
   for (img = 0; img < depth; img++) {
163
      for (row = 0; row < height; row++) {
164
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
165
                                          width, height, format, type,
166
                                          img, row, 0);
167
         memcpy(dest, src, width * sizeof(GLuint));
168
         if (ctx->Pack.SwapBytes) {
169
            _mesa_swap4((GLuint *) dest, width);
170
         }
171
 
172
         src += width * row + width * height * img;
173
      }
174
   }
175
}
176
 
177
 
178
/**
179
 * glGetTexImage for YCbCr pixels.
180
 */
181
static void
182
get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
183
              GLenum format, GLenum type, GLvoid *pixels,
184
              const 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
   const GLint rowstride = texImage->RowStride;
190
   const GLushort *src = (const GLushort *) texImage->Data;
191
   GLint img, row;
192
 
193
   for (img = 0; img < depth; img++) {
194
      for (row = 0; row < height; row++) {
195
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
196
                                          width, height, format, type,
197
                                          img, row, 0);
198
         memcpy(dest, src, width * sizeof(GLushort));
199
 
200
         /* check for byte swapping */
201
         if ((texImage->TexFormat == MESA_FORMAT_YCBCR
202
              && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
203
             (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
204
              && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
205
            if (!ctx->Pack.SwapBytes)
206
               _mesa_swap2((GLushort *) dest, width);
207
         }
208
         else if (ctx->Pack.SwapBytes) {
209
            _mesa_swap2((GLushort *) dest, width);
210
         }
211
 
212
         src += rowstride;
213
      }
214
   }
215
}
216
 
217
 
218
#if FEATURE_EXT_texture_sRGB
219
 
220
 
221
/**
222
 * Convert a float value from linear space to a
223
 * non-linear sRGB value in [0, 255].
224
 * Not terribly efficient.
225
 */
226
static INLINE GLfloat
227
linear_to_nonlinear(GLfloat cl)
228
{
229
   /* can't have values outside [0, 1] */
230
   GLfloat cs;
231
   if (cl < 0.0031308f) {
232
      cs = 12.92f * cl;
233
   }
234
   else {
235
      cs = (GLfloat)(1.055 * pow(cl, 0.41666) - 0.055);
236
   }
237
   return cs;
238
}
239
 
240
 
241
/**
242
 * glGetTexImagefor sRGB pixels;
243
 */
244
static void
245
get_tex_srgb(struct gl_context *ctx, GLuint dimensions,
246
             GLenum format, GLenum type, GLvoid *pixels,
247
             const struct gl_texture_image *texImage)
248
{
249
   const GLint width = texImage->Width;
250
   const GLint height = texImage->Height;
251
   const GLint depth = texImage->Depth;
252
   const GLbitfield transferOps = 0x0;
253
   GLint img, row;
254
   GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
255
 
256
   if (!rgba) {
257
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
258
      return;
259
   }
260
 
261
   for (img = 0; img < depth; img++) {
262
      for (row = 0; row < height; row++) {
263
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
264
                                          width, height, format, type,
265
                                          img, row, 0);
266
 
267
         GLint col;
268
 
269
         /* convert row to RGBA format */
270
         for (col = 0; col < width; col++) {
271
            texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
272
            if (texImage->_BaseFormat == GL_LUMINANCE) {
273
               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
274
               rgba[col][GCOMP] = 0.0;
275
               rgba[col][BCOMP] = 0.0;
276
            }
277
            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
278
               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
279
               rgba[col][GCOMP] = 0.0;
280
               rgba[col][BCOMP] = 0.0;
281
            }
282
            else if (texImage->_BaseFormat == GL_RGB ||
283
                     texImage->_BaseFormat == GL_RGBA) {
284
               rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
285
               rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
286
               rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
287
            }
288
         }
289
         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
290
                                    format, type, dest,
291
                                    &ctx->Pack, transferOps);
292
      }
293
   }
294
 
295
   free(rgba);
296
}
297
 
298
 
299
#else /* FEATURE_EXT_texture_sRGB */
300
 
301
 
302
static INLINE void
303
get_tex_srgb(struct gl_context *ctx, GLuint dimensions,
304
             GLenum format, GLenum type, GLvoid *pixels,
305
             const struct gl_texture_image *texImage)
306
{
307
   ASSERT_NO_FEATURE();
308
}
309
 
310
 
311
#endif /* FEATURE_EXT_texture_sRGB */
312
 
313
 
314
/**
315
 * glGetTexImagefor RGBA, Luminance, etc. pixels.
316
 * This is the slow way since we use texture sampling.
317
 */
318
static void
319
get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
320
             GLenum format, GLenum type, GLvoid *pixels,
321
             const struct gl_texture_image *texImage)
322
{
323
   const GLint width = texImage->Width;
324
   const GLint height = texImage->Height;
325
   const GLint depth = texImage->Depth;
326
   /* Normally, no pixel transfer ops are performed during glGetTexImage.
327
    * The only possible exception is component clamping to [0,1].
328
    */
329
   GLbitfield transferOps = 0x0;
330
   GLint img, row;
331
   GLfloat (*rgba)[4] = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
332
 
333
   if (!rgba) {
334
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
335
      return;
336
   }
337
 
338
   for (img = 0; img < depth; img++) {
339
      for (row = 0; row < height; row++) {
340
         void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
341
                                          width, height, format, type,
342
                                          img, row, 0);
343
         GLint col;
344
         GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
345
 
346
         /* clamp does not apply to GetTexImage (final conversion)?
347
          * Looks like we need clamp though when going from format
348
          * containing negative values to unsigned format.
349
          */
350
         if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
351
            transferOps |= IMAGE_CLAMP_BIT;
352
         }
353
         else if (!type_with_negative_values(type) &&
354
                  (dataType == GL_FLOAT ||
355
                   dataType == GL_SIGNED_NORMALIZED)) {
356
            transferOps |= IMAGE_CLAMP_BIT;
357
         }
358
 
359
         for (col = 0; col < width; col++) {
360
            texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
361
            if (texImage->_BaseFormat == GL_ALPHA) {
362
               rgba[col][RCOMP] = 0.0F;
363
               rgba[col][GCOMP] = 0.0F;
364
               rgba[col][BCOMP] = 0.0F;
365
            }
366
            else if (texImage->_BaseFormat == GL_LUMINANCE) {
367
               rgba[col][GCOMP] = 0.0F;
368
               rgba[col][BCOMP] = 0.0F;
369
               rgba[col][ACOMP] = 1.0F;
370
            }
371
            else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
372
               rgba[col][GCOMP] = 0.0F;
373
               rgba[col][BCOMP] = 0.0F;
374
            }
375
            else if (texImage->_BaseFormat == GL_INTENSITY) {
376
               rgba[col][GCOMP] = 0.0F;
377
               rgba[col][BCOMP] = 0.0F;
378
               rgba[col][ACOMP] = 1.0F;
379
            }
380
         }
381
         _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
382
                                    format, type, dest,
383
                                    &ctx->Pack, transferOps);
384
      }
385
   }
386
 
387
   free(rgba);
388
}
389
 
390
 
391
/**
392
 * Try to do glGetTexImage() with simple memcpy().
393
 * \return GL_TRUE if done, GL_FALSE otherwise
394
 */
395
static GLboolean
396
get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type, GLvoid *pixels,
397
               const struct gl_texture_object *texObj,
398
               const struct gl_texture_image *texImage)
399
{
400
   GLboolean memCopy = GL_FALSE;
401
 
402
   /* Texture image should have been mapped already */
403
   assert(texImage->Data);
404
 
405
   /*
406
    * Check if the src/dst formats are compatible.
407
    * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
408
    * so we don't have to worry about those.
409
    * XXX more format combinations could be supported here.
410
    */
411
   if ((texObj->Target == GL_TEXTURE_1D ||
412
        texObj->Target == GL_TEXTURE_2D ||
413
        texObj->Target == GL_TEXTURE_RECTANGLE ||
414
        (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
415
         texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
416
      if (texImage->TexFormat == MESA_FORMAT_ARGB8888 &&
417
          format == GL_BGRA &&
418
          type == GL_UNSIGNED_BYTE &&
419
          !ctx->Pack.SwapBytes &&
420
          _mesa_little_endian()) {
421
         memCopy = GL_TRUE;
422
      }
423
      else if (texImage->TexFormat == MESA_FORMAT_AL88 &&
424
               format == GL_LUMINANCE_ALPHA &&
425
               type == GL_UNSIGNED_BYTE &&
426
               !ctx->Pack.SwapBytes &&
427
               _mesa_little_endian()) {
428
         memCopy = GL_TRUE;
429
      }
430
      else if (texImage->TexFormat == MESA_FORMAT_L8 &&
431
               format == GL_LUMINANCE &&
432
               type == GL_UNSIGNED_BYTE) {
433
         memCopy = GL_TRUE;
434
      }
435
      else if (texImage->TexFormat == MESA_FORMAT_A8 &&
436
               format == GL_ALPHA &&
437
               type == GL_UNSIGNED_BYTE) {
438
         memCopy = GL_TRUE;
439
      }
440
   }
441
 
442
   if (memCopy) {
443
      const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
444
      const GLuint bytesPerRow = texImage->Width * bpp;
445
      GLubyte *dst =
446
         _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
447
                               texImage->Height, format, type, 0, 0);
448
      const GLint dstRowStride =
449
         _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
450
      const GLubyte *src = texImage->Data;
451
      const GLint srcRowStride = texImage->RowStride * bpp;
452
      GLuint row;
453
 
454
      if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
455
         memcpy(dst, src, bytesPerRow * texImage->Height);
456
      }
457
      else {
458
         for (row = 0; row < texImage->Height; row++) {
459
            memcpy(dst, src, bytesPerRow);
460
            dst += dstRowStride;
461
            src += srcRowStride;
462
         }
463
      }
464
   }
465
 
466
   return memCopy;
467
}
468
 
469
 
470
/**
471
 * This is the software fallback for Driver.GetTexImage().
472
 * All error checking will have been done before this routine is called.
473
 * The texture image must be mapped.
474
 */
475
void
476
_mesa_get_teximage(struct gl_context *ctx, GLenum target, GLint level,
477
                   GLenum format, GLenum type, GLvoid *pixels,
478
                   struct gl_texture_object *texObj,
479
                   struct gl_texture_image *texImage)
480
{
481
   GLuint dimensions;
482
 
483
   /* If we get here, the texture image should be mapped */
484
   assert(texImage->Data);
485
 
486
   switch (target) {
487
   case GL_TEXTURE_1D:
488
      dimensions = 1;
489
      break;
490
   case GL_TEXTURE_3D:
491
      dimensions = 3;
492
      break;
493
   default:
494
      dimensions = 2;
495
   }
496
 
497
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
498
      /* Packing texture image into a PBO.
499
       * Map the (potentially) VRAM-based buffer into our process space so
500
       * we can write into it with the code below.
501
       * A hardware driver might use a sophisticated blit to move the
502
       * texture data to the PBO if the PBO is in VRAM along with the texture.
503
       */
504
      GLubyte *buf = (GLubyte *)
505
         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
506
                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
507
      if (!buf) {
508
         /* out of memory or other unexpected error */
509
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
510
         return;
511
      }
512
      /*  was an offset into the PBO.
513
       * Now make it a real, client-side pointer inside the mapped region.
514
       */
515
      pixels = ADD_POINTERS(buf, pixels);
516
   }
517
 
518
   if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
519
      /* all done */
520
   }
521
   else if (format == GL_COLOR_INDEX) {
522
      get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
523
   }
524
   else if (format == GL_DEPTH_COMPONENT) {
525
      get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
526
   }
527
   else if (format == GL_DEPTH_STENCIL_EXT) {
528
      get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
529
   }
530
   else if (format == GL_YCBCR_MESA) {
531
      get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
532
   }
533
   else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) {
534
      get_tex_srgb(ctx, dimensions, format, type, pixels, texImage);
535
   }
536
   else {
537
      get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
538
   }
539
 
540
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
541
      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
542
                              ctx->Pack.BufferObj);
543
   }
544
}
545
 
546
 
547
 
548
/**
549
 * This is the software fallback for Driver.GetCompressedTexImage().
550
 * All error checking will have been done before this routine is called.
551
 */
552
void
553
_mesa_get_compressed_teximage(struct gl_context *ctx, GLenum target, GLint level,
554
                              GLvoid *img,
555
                              struct gl_texture_object *texObj,
556
                              struct gl_texture_image *texImage)
557
{
558
   const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
559
                                                     texImage->Width);
560
   const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
561
                                                            texImage->RowStride);
562
   GLuint i;
563
 
564
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
565
      /* pack texture image into a PBO */
566
      GLubyte *buf = (GLubyte *)
567
         ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
568
                               GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
569
      if (!buf) {
570
         /* out of memory or other unexpected error */
571
         _mesa_error(ctx, GL_OUT_OF_MEMORY,
572
                     "glGetCompresssedTexImage(map PBO failed)");
573
         return;
574
      }
575
      img = ADD_POINTERS(buf, img);
576
   }
577
 
578
   /* no pixelstore or pixel transfer, but respect stride */
579
 
580
   if (row_stride == row_stride_stored) {
581
      const GLuint size = _mesa_format_image_size(texImage->TexFormat,
582
                                                  texImage->Width,
583
                                                  texImage->Height,
584
                                                  texImage->Depth);
585
      memcpy(img, texImage->Data, size);
586
   }
587
   else {
588
      GLuint bw, bh;
589
      _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
590
      for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
591
         memcpy((GLubyte *)img + i * row_stride,
592
                (GLubyte *)texImage->Data + i * row_stride_stored,
593
                row_stride);
594
      }
595
   }
596
 
597
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
598
      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
599
                              ctx->Pack.BufferObj);
600
   }
601
}
602
 
603
 
604
 
605
/**
606
 * Do error checking for a glGetTexImage() call.
607
 * \return GL_TRUE if any error, GL_FALSE if no errors.
608
 */
609
static GLboolean
610
getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
611
                        GLenum format, GLenum type, GLvoid *pixels )
612
{
613
   struct gl_texture_object *texObj;
614
   struct gl_texture_image *texImage;
615
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
616
   GLenum baseFormat;
617
 
618
   if (maxLevels == 0) {
619
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
620
      return GL_TRUE;
621
   }
622
 
623
   if (level < 0 || level >= maxLevels) {
624
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
625
      return GL_TRUE;
626
   }
627
 
628
   if (_mesa_sizeof_packed_type(type) <= 0) {
629
      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
630
      return GL_TRUE;
631
   }
632
 
633
   if (_mesa_components_in_format(format) <= 0 ||
634
       format == GL_STENCIL_INDEX) {
635
      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
636
      return GL_TRUE;
637
   }
638
 
639
   if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
640
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
641
      return GL_TRUE;
642
   }
643
 
644
   if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
645
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
646
      return GL_TRUE;
647
   }
648
 
649
   if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
650
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
651
      return GL_TRUE;
652
   }
653
 
654
   if (!ctx->Extensions.EXT_packed_depth_stencil
655
       && _mesa_is_depthstencil_format(format)) {
656
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
657
      return GL_TRUE;
658
   }
659
 
660
   if (!ctx->Extensions.ATI_envmap_bumpmap
661
       && _mesa_is_dudv_format(format)) {
662
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
663
      return GL_TRUE;
664
   }
665
 
666
   texObj = _mesa_get_current_tex_object(ctx, target);
667
 
668
   if (!texObj || _mesa_is_proxy_texture(target)) {
669
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
670
      return GL_TRUE;
671
   }
672
 
673
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
674
   if (!texImage) {
675
      /* out of memory */
676
      return GL_TRUE;
677
   }
678
 
679
   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
680
 
681
   /* Make sure the requested image format is compatible with the
682
    * texture's format.  Note that a color index texture can be converted
683
    * to RGBA so that combo is allowed.
684
    */
685
   if (_mesa_is_color_format(format)
686
       && !_mesa_is_color_format(baseFormat)
687
       && !_mesa_is_index_format(baseFormat)) {
688
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
689
      return GL_TRUE;
690
   }
691
   else if (_mesa_is_index_format(format)
692
            && !_mesa_is_index_format(baseFormat)) {
693
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
694
      return GL_TRUE;
695
   }
696
   else if (_mesa_is_depth_format(format)
697
            && !_mesa_is_depth_format(baseFormat)
698
            && !_mesa_is_depthstencil_format(baseFormat)) {
699
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
700
      return GL_TRUE;
701
   }
702
   else if (_mesa_is_ycbcr_format(format)
703
            && !_mesa_is_ycbcr_format(baseFormat)) {
704
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
705
      return GL_TRUE;
706
   }
707
   else if (_mesa_is_depthstencil_format(format)
708
            && !_mesa_is_depthstencil_format(baseFormat)) {
709
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
710
      return GL_TRUE;
711
   }
712
   else if (_mesa_is_dudv_format(format)
713
            && !_mesa_is_dudv_format(baseFormat)) {
714
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
715
      return GL_TRUE;
716
   }
717
 
718
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
719
      /* packing texture image into a PBO */
720
      const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
721
      if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
722
                                     texImage->Height, texImage->Depth,
723
                                     format, type, pixels)) {
724
         _mesa_error(ctx, GL_INVALID_OPERATION,
725
                     "glGetTexImage(out of bounds PBO write)");
726
         return GL_TRUE;
727
      }
728
 
729
      /* PBO should not be mapped */
730
      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
731
         _mesa_error(ctx, GL_INVALID_OPERATION,
732
                     "glGetTexImage(PBO is mapped)");
733
         return GL_TRUE;
734
      }
735
   }
736
 
737
   return GL_FALSE;
738
}
739
 
740
 
741
 
742
/**
743
 * Get texture image.  Called by glGetTexImage.
744
 *
745
 * \param target texture target.
746
 * \param level image level.
747
 * \param format pixel data format for returned image.
748
 * \param type pixel data type for returned image.
749
 * \param pixels returned pixel data.
750
 */
751
void GLAPIENTRY
752
_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
753
                   GLenum type, GLvoid *pixels )
754
{
755
   struct gl_texture_object *texObj;
756
   struct gl_texture_image *texImage;
757
   GET_CURRENT_CONTEXT(ctx);
758
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
759
 
760
   if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
761
      return;
762
   }
763
 
764
   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
765
      /* not an error, do nothing */
766
      return;
767
   }
768
 
769
   texObj = _mesa_get_current_tex_object(ctx, target);
770
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
771
 
772
   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
773
      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
774
                  " dstFmt=0x%x, dstType=0x%x\n",
775
                  texObj->Name,
776
                  _mesa_get_format_name(texImage->TexFormat),
777
                  texImage->Width, texImage->Height,
778
                  format, type);
779
   }
780
 
781
   _mesa_lock_texture(ctx, texObj);
782
   {
783
      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
784
                              texObj, texImage);
785
   }
786
   _mesa_unlock_texture(ctx, texObj);
787
}
788
 
789
 
790
 
791
/**
792
 * Do error checking for a glGetCompressedTexImage() call.
793
 * \return GL_TRUE if any error, GL_FALSE if no errors.
794
 */
795
static GLboolean
796
getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
797
                                  GLvoid *img)
798
{
799
   struct gl_texture_object *texObj;
800
   struct gl_texture_image *texImage;
801
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
802
 
803
   if (maxLevels == 0) {
804
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
805
                  target);
806
      return GL_TRUE;
807
   }
808
 
809
   if (level < 0 || level >= maxLevels) {
810
      _mesa_error(ctx, GL_INVALID_VALUE,
811
                  "glGetCompressedTexImageARB(bad level = %d)", level);
812
      return GL_TRUE;
813
   }
814
 
815
   if (_mesa_is_proxy_texture(target)) {
816
      _mesa_error(ctx, GL_INVALID_ENUM,
817
                  "glGetCompressedTexImageARB(bad target = %s)",
818
                  _mesa_lookup_enum_by_nr(target));
819
      return GL_TRUE;
820
   }
821
 
822
   texObj = _mesa_get_current_tex_object(ctx, target);
823
   if (!texObj) {
824
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
825
      return GL_TRUE;
826
   }
827
 
828
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
829
 
830
   if (!texImage) {
831
      /* probably invalid mipmap level */
832
      _mesa_error(ctx, GL_INVALID_VALUE,
833
                  "glGetCompressedTexImageARB(level)");
834
      return GL_TRUE;
835
   }
836
 
837
   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
838
      _mesa_error(ctx, GL_INVALID_OPERATION,
839
                  "glGetCompressedTexImageARB(texture is not compressed)");
840
      return GL_TRUE;
841
   }
842
 
843
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
844
      GLuint compressedSize;
845
 
846
      /* make sure PBO is not mapped */
847
      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
848
         _mesa_error(ctx, GL_INVALID_OPERATION,
849
                     "glGetCompressedTexImage(PBO is mapped)");
850
         return GL_TRUE;
851
      }
852
 
853
      compressedSize = _mesa_format_image_size(texImage->TexFormat,
854
                                               texImage->Width,
855
                                               texImage->Height,
856
                                               texImage->Depth);
857
 
858
      /* do bounds checking on PBO write */
859
      if ((const GLubyte *) img + compressedSize >
860
          (const GLubyte *) ctx->Pack.BufferObj->Size) {
861
         _mesa_error(ctx, GL_INVALID_OPERATION,
862
                     "glGetCompressedTexImage(out of bounds PBO write)");
863
         return GL_TRUE;
864
      }
865
   }
866
 
867
   return GL_FALSE;
868
}
869
 
870
 
871
void GLAPIENTRY
872
_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
873
{
874
   struct gl_texture_object *texObj;
875
   struct gl_texture_image *texImage;
876
   GET_CURRENT_CONTEXT(ctx);
877
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
878
 
879
   if (getcompressedteximage_error_check(ctx, target, level, img)) {
880
      return;
881
   }
882
 
883
   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
884
      /* not an error, do nothing */
885
      return;
886
   }
887
 
888
   texObj = _mesa_get_current_tex_object(ctx, target);
889
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
890
 
891
   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
892
      _mesa_debug(ctx,
893
                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
894
                  texObj->Name,
895
                  _mesa_get_format_name(texImage->TexFormat),
896
                  texImage->Width, texImage->Height);
897
   }
898
 
899
   _mesa_lock_texture(ctx, texObj);
900
   {
901
      ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
902
                                        texObj, texImage);
903
   }
904
   _mesa_unlock_texture(ctx, texObj);
905
}