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