mesa: Add support for glGetTexImage() from integer textures.
[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 "format_unpack.h"
38 #include "image.h"
39 #include "mfeatures.h"
40 #include "mtypes.h"
41 #include "pack.h"
42 #include "pbo.h"
43 #include "texcompress.h"
44 #include "texgetimage.h"
45 #include "teximage.h"
46
47
48
49 /**
50 * Can the given type represent negative values?
51 */
52 static inline GLboolean
53 type_needs_clamping(GLenum type)
54 {
55 switch (type) {
56 case GL_BYTE:
57 case GL_SHORT:
58 case GL_INT:
59 case GL_FLOAT:
60 case GL_HALF_FLOAT_ARB:
61 case GL_UNSIGNED_INT_10F_11F_11F_REV:
62 case GL_UNSIGNED_INT_5_9_9_9_REV:
63 return GL_FALSE;
64 default:
65 return GL_TRUE;
66 }
67 }
68
69
70 /**
71 * glGetTexImage for depth/Z pixels.
72 */
73 static void
74 get_tex_depth(struct gl_context *ctx, GLuint dimensions,
75 GLenum format, GLenum type, GLvoid *pixels,
76 struct gl_texture_image *texImage)
77 {
78 const GLint width = texImage->Width;
79 const GLint height = texImage->Height;
80 const GLint depth = texImage->Depth;
81 GLint img, row;
82 GLfloat *depthRow = (GLfloat *) malloc(width * sizeof(GLfloat));
83
84 if (!depthRow) {
85 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
86 return;
87 }
88
89 for (img = 0; img < depth; img++) {
90 GLubyte *srcMap;
91 GLint srcRowStride;
92
93 /* map src texture buffer */
94 ctx->Driver.MapTextureImage(ctx, texImage, img,
95 0, 0, width, height, GL_MAP_READ_BIT,
96 &srcMap, &srcRowStride);
97
98 if (srcMap) {
99 for (row = 0; row < height; row++) {
100 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
101 width, height, format, type,
102 img, row, 0);
103 const GLubyte *src = srcMap + row * srcRowStride;
104 _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
105 _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
106 }
107
108 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
109 }
110 else {
111 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
112 break;
113 }
114 }
115
116 free(depthRow);
117 }
118
119
120 /**
121 * glGetTexImage for depth/stencil pixels.
122 */
123 static void
124 get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
125 GLenum format, GLenum type, GLvoid *pixels,
126 struct gl_texture_image *texImage)
127 {
128 const GLint width = texImage->Width;
129 const GLint height = texImage->Height;
130 const GLint depth = texImage->Depth;
131 GLint img, row;
132
133 for (img = 0; img < depth; img++) {
134 GLubyte *srcMap;
135 GLint rowstride;
136
137 /* map src texture buffer */
138 ctx->Driver.MapTextureImage(ctx, texImage, img,
139 0, 0, width, height, GL_MAP_READ_BIT,
140 &srcMap, &rowstride);
141
142 if (srcMap) {
143 for (row = 0; row < height; row++) {
144 const GLubyte *src = srcMap + row * rowstride;
145 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
146 width, height, format, type,
147 img, row, 0);
148 /* XXX Z24_S8 vs. S8_Z24??? */
149 memcpy(dest, src, width * sizeof(GLuint));
150 if (ctx->Pack.SwapBytes) {
151 _mesa_swap4((GLuint *) dest, width);
152 }
153 }
154
155 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
156 }
157 else {
158 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
159 break;
160 }
161 }
162 }
163
164
165 /**
166 * glGetTexImage for YCbCr pixels.
167 */
168 static void
169 get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
170 GLenum format, GLenum type, GLvoid *pixels,
171 struct gl_texture_image *texImage)
172 {
173 const GLint width = texImage->Width;
174 const GLint height = texImage->Height;
175 const GLint depth = texImage->Depth;
176 GLint img, row;
177
178 for (img = 0; img < depth; img++) {
179 GLubyte *srcMap;
180 GLint rowstride;
181
182 /* map src texture buffer */
183 ctx->Driver.MapTextureImage(ctx, texImage, img,
184 0, 0, width, height, GL_MAP_READ_BIT,
185 &srcMap, &rowstride);
186
187 if (srcMap) {
188 for (row = 0; row < height; row++) {
189 const GLubyte *src = srcMap + row * rowstride;
190 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
191 width, height, format, type,
192 img, row, 0);
193 memcpy(dest, src, width * sizeof(GLushort));
194
195 /* check for byte swapping */
196 if ((texImage->TexFormat == MESA_FORMAT_YCBCR
197 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
198 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
199 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
200 if (!ctx->Pack.SwapBytes)
201 _mesa_swap2((GLushort *) dest, width);
202 }
203 else if (ctx->Pack.SwapBytes) {
204 _mesa_swap2((GLushort *) dest, width);
205 }
206 }
207
208 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
209 }
210 else {
211 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
212 break;
213 }
214 }
215 }
216
217
218 /**
219 * Get a color texture image with decompression.
220 */
221 static void
222 get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions,
223 GLenum format, GLenum type, GLvoid *pixels,
224 struct gl_texture_image *texImage,
225 GLbitfield transferOps)
226 {
227 /* don't want to apply sRGB -> RGB conversion here so override the format */
228 const gl_format texFormat =
229 _mesa_get_srgb_format_linear(texImage->TexFormat);
230 const GLenum baseFormat = _mesa_get_format_base_format(texFormat);
231 const GLuint width = texImage->Width;
232 const GLuint height = texImage->Height;
233 const GLuint depth = texImage->Depth;
234 GLfloat *tempImage, *srcRow;
235 GLuint row;
236
237 /* Decompress into temp float buffer, then pack into user buffer */
238 tempImage = (GLfloat *) malloc(width * height * depth
239 * 4 * sizeof(GLfloat));
240 if (!tempImage) {
241 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
242 return;
243 }
244
245 /* Decompress the texture image - results in 'tempImage' */
246 {
247 GLubyte *srcMap;
248 GLint srcRowStride;
249 GLuint bytes, bw, bh;
250
251 bytes = _mesa_get_format_bytes(texFormat);
252 _mesa_get_format_block_size(texFormat, &bw, &bh);
253
254 ctx->Driver.MapTextureImage(ctx, texImage, 0,
255 0, 0, width, height,
256 GL_MAP_READ_BIT,
257 &srcMap, &srcRowStride);
258 if (srcMap) {
259 /* XXX This line is a bit of a hack to work around the
260 * mismatch of compressed row strides as returned by
261 * MapTextureImage() vs. what the texture decompression code
262 * uses. This will be fixed in the future.
263 */
264 srcRowStride = srcRowStride * bh / bytes;
265
266 _mesa_decompress_image(texFormat, width, height,
267 srcMap, srcRowStride, tempImage);
268
269 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
270 }
271 else {
272 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
273 }
274 }
275
276 if (baseFormat == GL_LUMINANCE ||
277 baseFormat == GL_LUMINANCE_ALPHA) {
278 /* Set green and blue to zero since the pack function here will
279 * compute L=R+G+B.
280 */
281 GLuint i;
282 for (i = 0; i < width * height; i++) {
283 tempImage[i * 4 + GCOMP] = tempImage[i * 4 + BCOMP] = 0.0f;
284 }
285 }
286
287 srcRow = tempImage;
288 for (row = 0; row < height; row++) {
289 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
290 width, height, format, type,
291 0, row, 0);
292
293 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow,
294 format, type, dest, &ctx->Pack, transferOps);
295 srcRow += width * 4;
296 }
297
298 free(tempImage);
299 }
300
301
302 /**
303 * Get an uncompressed color texture image.
304 */
305 static void
306 get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
307 GLenum format, GLenum type, GLvoid *pixels,
308 struct gl_texture_image *texImage,
309 GLbitfield transferOps)
310 {
311 /* don't want to apply sRGB -> RGB conversion here so override the format */
312 const gl_format texFormat =
313 _mesa_get_srgb_format_linear(texImage->TexFormat);
314 const GLuint width = texImage->Width;
315 const GLuint height = texImage->Height;
316 const GLuint depth = texImage->Depth;
317 GLuint img, row;
318 GLfloat (*rgba)[4];
319 GLuint (*rgba_uint)[4];
320 GLboolean is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
321
322 /* Allocate buffer for one row of texels */
323 rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
324 rgba_uint = (GLuint (*)[4]) rgba;
325 if (!rgba) {
326 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
327 return;
328 }
329
330 for (img = 0; img < depth; img++) {
331 GLubyte *srcMap;
332 GLint rowstride;
333
334 /* map src texture buffer */
335 ctx->Driver.MapTextureImage(ctx, texImage, img,
336 0, 0, width, height, GL_MAP_READ_BIT,
337 &srcMap, &rowstride);
338 if (srcMap) {
339 for (row = 0; row < height; row++) {
340 const GLubyte *src = srcMap + row * rowstride;
341 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
342 width, height, format, type,
343 img, row, 0);
344
345 if (is_integer) {
346 _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
347
348 if (texImage->_BaseFormat == GL_ALPHA) {
349 GLint col;
350 for (col = 0; col < width; col++) {
351 rgba_uint[col][RCOMP] = 0;
352 rgba_uint[col][GCOMP] = 0;
353 rgba_uint[col][BCOMP] = 0;
354 }
355 }
356 else if (texImage->_BaseFormat == GL_LUMINANCE) {
357 GLint col;
358 for (col = 0; col < width; col++) {
359 rgba_uint[col][GCOMP] = 0;
360 rgba_uint[col][BCOMP] = 0;
361 rgba_uint[col][ACOMP] = 1;
362 }
363 }
364 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
365 GLint col;
366 for (col = 0; col < width; col++) {
367 rgba_uint[col][GCOMP] = 0;
368 rgba_uint[col][BCOMP] = 0;
369 }
370 }
371 else if (texImage->_BaseFormat == GL_INTENSITY) {
372 GLint col;
373 for (col = 0; col < width; col++) {
374 rgba_uint[col][GCOMP] = 0;
375 rgba_uint[col][BCOMP] = 0;
376 rgba_uint[col][ACOMP] = 1;
377 }
378 }
379
380 _mesa_pack_rgba_span_int(ctx, width, rgba_uint,
381 format, type, dest);
382 } else {
383 _mesa_unpack_rgba_row(texFormat, width, src, rgba);
384
385 if (texImage->_BaseFormat == GL_ALPHA) {
386 GLint col;
387 for (col = 0; col < width; col++) {
388 rgba[col][RCOMP] = 0.0F;
389 rgba[col][GCOMP] = 0.0F;
390 rgba[col][BCOMP] = 0.0F;
391 }
392 }
393 else if (texImage->_BaseFormat == GL_LUMINANCE) {
394 GLint col;
395 for (col = 0; col < width; col++) {
396 rgba[col][GCOMP] = 0.0F;
397 rgba[col][BCOMP] = 0.0F;
398 rgba[col][ACOMP] = 1.0F;
399 }
400 }
401 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
402 GLint col;
403 for (col = 0; col < width; col++) {
404 rgba[col][GCOMP] = 0.0F;
405 rgba[col][BCOMP] = 0.0F;
406 }
407 }
408 else if (texImage->_BaseFormat == GL_INTENSITY) {
409 GLint col;
410 for (col = 0; col < width; col++) {
411 rgba[col][GCOMP] = 0.0F;
412 rgba[col][BCOMP] = 0.0F;
413 rgba[col][ACOMP] = 1.0F;
414 }
415 }
416
417 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
418 format, type, dest,
419 &ctx->Pack, transferOps);
420 }
421 }
422
423 /* Unmap the src texture buffer */
424 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
425 }
426 else {
427 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
428 break;
429 }
430 }
431
432 free(rgba);
433 }
434
435
436 /**
437 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
438 * Compressed textures are handled here as well.
439 */
440 static void
441 get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
442 GLenum format, GLenum type, GLvoid *pixels,
443 struct gl_texture_image *texImage)
444 {
445 const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
446 GLbitfield transferOps = 0x0;
447
448 /* In general, clamping does not apply to glGetTexImage, except when
449 * the returned type of the image can't hold negative values.
450 */
451 if (type_needs_clamping(type)) {
452 /* the returned image type can't have negative values */
453 if (dataType == GL_FLOAT ||
454 dataType == GL_SIGNED_NORMALIZED ||
455 format == GL_LUMINANCE ||
456 format == GL_LUMINANCE_ALPHA) {
457 transferOps |= IMAGE_CLAMP_BIT;
458 }
459 }
460
461 if (_mesa_is_format_compressed(texImage->TexFormat)) {
462 get_tex_rgba_compressed(ctx, dimensions, format, type,
463 pixels, texImage, transferOps);
464 }
465 else {
466 get_tex_rgba_uncompressed(ctx, dimensions, format, type,
467 pixels, texImage, transferOps);
468 }
469 }
470
471
472 /**
473 * Try to do glGetTexImage() with simple memcpy().
474 * \return GL_TRUE if done, GL_FALSE otherwise
475 */
476 static GLboolean
477 get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
478 GLvoid *pixels,
479 struct gl_texture_image *texImage)
480 {
481 const GLenum target = texImage->TexObject->Target;
482 GLboolean memCopy = GL_FALSE;
483
484 /*
485 * Check if the src/dst formats are compatible.
486 * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
487 * so we don't have to worry about those.
488 * XXX more format combinations could be supported here.
489 */
490 if (target == GL_TEXTURE_1D ||
491 target == GL_TEXTURE_2D ||
492 target == GL_TEXTURE_RECTANGLE ||
493 _mesa_is_cube_face(target)) {
494 if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 ||
495 texImage->TexFormat == MESA_FORMAT_SARGB8) &&
496 format == GL_BGRA &&
497 (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
498 !ctx->Pack.SwapBytes &&
499 _mesa_little_endian()) {
500 memCopy = GL_TRUE;
501 }
502 else if ((texImage->TexFormat == MESA_FORMAT_AL88 ||
503 texImage->TexFormat == MESA_FORMAT_SLA8) &&
504 format == GL_LUMINANCE_ALPHA &&
505 type == GL_UNSIGNED_BYTE &&
506 !ctx->Pack.SwapBytes &&
507 _mesa_little_endian()) {
508 memCopy = GL_TRUE;
509 }
510 else if ((texImage->TexFormat == MESA_FORMAT_L8 ||
511 texImage->TexFormat == MESA_FORMAT_SL8) &&
512 format == GL_LUMINANCE &&
513 type == GL_UNSIGNED_BYTE) {
514 memCopy = GL_TRUE;
515 }
516 else if (texImage->TexFormat == MESA_FORMAT_L16 &&
517 format == GL_LUMINANCE &&
518 type == GL_UNSIGNED_SHORT) {
519 memCopy = GL_TRUE;
520 }
521 else if (texImage->TexFormat == MESA_FORMAT_A8 &&
522 format == GL_ALPHA &&
523 type == GL_UNSIGNED_BYTE) {
524 memCopy = GL_TRUE;
525 }
526 else if (texImage->TexFormat == MESA_FORMAT_A16 &&
527 format == GL_ALPHA &&
528 type == GL_UNSIGNED_SHORT) {
529 memCopy = GL_TRUE;
530 }
531 }
532
533 if (memCopy) {
534 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
535 const GLuint bytesPerRow = texImage->Width * bpp;
536 GLubyte *dst =
537 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
538 texImage->Height, format, type, 0, 0);
539 const GLint dstRowStride =
540 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
541 GLubyte *src;
542 GLint srcRowStride;
543
544 /* map src texture buffer */
545 ctx->Driver.MapTextureImage(ctx, texImage, 0,
546 0, 0, texImage->Width, texImage->Height,
547 GL_MAP_READ_BIT, &src, &srcRowStride);
548
549 if (src) {
550 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
551 memcpy(dst, src, bytesPerRow * texImage->Height);
552 }
553 else {
554 GLuint row;
555 for (row = 0; row < texImage->Height; row++) {
556 memcpy(dst, src, bytesPerRow);
557 dst += dstRowStride;
558 src += srcRowStride;
559 }
560 }
561
562 /* unmap src texture buffer */
563 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
564 }
565 else {
566 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
567 }
568 }
569
570 return memCopy;
571 }
572
573
574 /**
575 * This is the software fallback for Driver.GetTexImage().
576 * All error checking will have been done before this routine is called.
577 * We'll call ctx->Driver.MapTextureImage() to access the data, then
578 * unmap with ctx->Driver.UnmapTextureImage().
579 */
580 void
581 _mesa_get_teximage(struct gl_context *ctx,
582 GLenum format, GLenum type, GLvoid *pixels,
583 struct gl_texture_image *texImage)
584 {
585 GLuint dimensions;
586
587 switch (texImage->TexObject->Target) {
588 case GL_TEXTURE_1D:
589 dimensions = 1;
590 break;
591 case GL_TEXTURE_3D:
592 dimensions = 3;
593 break;
594 default:
595 dimensions = 2;
596 }
597
598 /* map dest buffer, if PBO */
599 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
600 /* Packing texture image into a PBO.
601 * Map the (potentially) VRAM-based buffer into our process space so
602 * we can write into it with the code below.
603 * A hardware driver might use a sophisticated blit to move the
604 * texture data to the PBO if the PBO is in VRAM along with the texture.
605 */
606 GLubyte *buf = (GLubyte *)
607 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
608 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
609 if (!buf) {
610 /* out of memory or other unexpected error */
611 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
612 return;
613 }
614 /* <pixels> was an offset into the PBO.
615 * Now make it a real, client-side pointer inside the mapped region.
616 */
617 pixels = ADD_POINTERS(buf, pixels);
618 }
619
620 if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
621 /* all done */
622 }
623 else if (format == GL_DEPTH_COMPONENT) {
624 get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
625 }
626 else if (format == GL_DEPTH_STENCIL_EXT) {
627 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
628 }
629 else if (format == GL_YCBCR_MESA) {
630 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
631 }
632 else {
633 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
634 }
635
636 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
637 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
638 }
639 }
640
641
642
643 /**
644 * This is the software fallback for Driver.GetCompressedTexImage().
645 * All error checking will have been done before this routine is called.
646 */
647 void
648 _mesa_get_compressed_teximage(struct gl_context *ctx,
649 struct gl_texture_image *texImage,
650 GLvoid *img)
651 {
652 const GLuint row_stride =
653 _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
654 GLuint i;
655 GLubyte *src;
656 GLint srcRowStride;
657
658 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
659 /* pack texture image into a PBO */
660 GLubyte *buf = (GLubyte *)
661 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
662 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
663 if (!buf) {
664 /* out of memory or other unexpected error */
665 _mesa_error(ctx, GL_OUT_OF_MEMORY,
666 "glGetCompresssedTexImage(map PBO failed)");
667 return;
668 }
669 img = ADD_POINTERS(buf, img);
670 }
671
672 /* map src texture buffer */
673 ctx->Driver.MapTextureImage(ctx, texImage, 0,
674 0, 0, texImage->Width, texImage->Height,
675 GL_MAP_READ_BIT, &src, &srcRowStride);
676
677 if (src) {
678 /* no pixelstore or pixel transfer, but respect stride */
679
680 if (row_stride == srcRowStride) {
681 const GLuint size = _mesa_format_image_size(texImage->TexFormat,
682 texImage->Width,
683 texImage->Height,
684 texImage->Depth);
685 memcpy(img, src, size);
686 }
687 else {
688 GLuint bw, bh;
689 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
690 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
691 memcpy((GLubyte *)img + i * row_stride,
692 (GLubyte *)src + i * srcRowStride,
693 row_stride);
694 }
695 }
696
697 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
698 }
699 else {
700 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
701 }
702
703 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
704 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
705 }
706 }
707
708
709
710 /**
711 * Do error checking for a glGetTexImage() call.
712 * \return GL_TRUE if any error, GL_FALSE if no errors.
713 */
714 static GLboolean
715 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
716 GLenum format, GLenum type, GLsizei clientMemSize,
717 GLvoid *pixels )
718 {
719 struct gl_texture_object *texObj;
720 struct gl_texture_image *texImage;
721 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
722 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
723 GLenum baseFormat;
724
725 if (maxLevels == 0) {
726 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
727 return GL_TRUE;
728 }
729
730 if (level < 0 || level >= maxLevels) {
731 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
732 return GL_TRUE;
733 }
734
735 if (_mesa_sizeof_packed_type(type) <= 0) {
736 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
737 return GL_TRUE;
738 }
739
740 if (_mesa_components_in_format(format) <= 0 ||
741 format == GL_STENCIL_INDEX ||
742 format == GL_COLOR_INDEX) {
743 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
744 return GL_TRUE;
745 }
746
747 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
748 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
749 return GL_TRUE;
750 }
751
752 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
754 return GL_TRUE;
755 }
756
757 if (!ctx->Extensions.EXT_packed_depth_stencil
758 && _mesa_is_depthstencil_format(format)) {
759 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
760 return GL_TRUE;
761 }
762
763 if (!ctx->Extensions.ATI_envmap_bumpmap
764 && _mesa_is_dudv_format(format)) {
765 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
766 return GL_TRUE;
767 }
768
769 texObj = _mesa_get_current_tex_object(ctx, target);
770
771 if (!texObj || _mesa_is_proxy_texture(target)) {
772 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
773 return GL_TRUE;
774 }
775
776 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
777 /* GL_INVALID_OPERATION is generated by a format/type
778 * mismatch (see the 1.2 spec page 94, sec 3.6.4.)
779 */
780 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(target)");
781 return GL_TRUE;
782 }
783
784 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
785 if (!texImage) {
786 /* non-existant texture image */
787 return GL_TRUE;
788 }
789
790 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
791
792 /* Make sure the requested image format is compatible with the
793 * texture's format.
794 */
795 if (_mesa_is_color_format(format)
796 && !_mesa_is_color_format(baseFormat)) {
797 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
798 return GL_TRUE;
799 }
800 else if (_mesa_is_depth_format(format)
801 && !_mesa_is_depth_format(baseFormat)
802 && !_mesa_is_depthstencil_format(baseFormat)) {
803 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
804 return GL_TRUE;
805 }
806 else if (_mesa_is_ycbcr_format(format)
807 && !_mesa_is_ycbcr_format(baseFormat)) {
808 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
809 return GL_TRUE;
810 }
811 else if (_mesa_is_depthstencil_format(format)
812 && !_mesa_is_depthstencil_format(baseFormat)) {
813 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
814 return GL_TRUE;
815 }
816 else if (_mesa_is_dudv_format(format)
817 && !_mesa_is_dudv_format(baseFormat)) {
818 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
819 return GL_TRUE;
820 }
821
822 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
823 texImage->Height, texImage->Depth,
824 format, type, clientMemSize, pixels)) {
825 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
826 _mesa_error(ctx, GL_INVALID_OPERATION,
827 "glGetTexImage(out of bounds PBO access)");
828 } else {
829 _mesa_error(ctx, GL_INVALID_OPERATION,
830 "glGetnTexImageARB(out of bounds access:"
831 " bufSize (%d) is too small)", clientMemSize);
832 }
833 return GL_TRUE;
834 }
835
836 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
837 /* PBO should not be mapped */
838 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
839 _mesa_error(ctx, GL_INVALID_OPERATION,
840 "glGetTexImage(PBO is mapped)");
841 return GL_TRUE;
842 }
843 }
844
845 return GL_FALSE;
846 }
847
848
849
850 /**
851 * Get texture image. Called by glGetTexImage.
852 *
853 * \param target texture target.
854 * \param level image level.
855 * \param format pixel data format for returned image.
856 * \param type pixel data type for returned image.
857 * \param bufSize size of the pixels data buffer.
858 * \param pixels returned pixel data.
859 */
860 void GLAPIENTRY
861 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
862 GLenum type, GLsizei bufSize, GLvoid *pixels )
863 {
864 struct gl_texture_object *texObj;
865 struct gl_texture_image *texImage;
866 GET_CURRENT_CONTEXT(ctx);
867 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
868
869 if (getteximage_error_check(ctx, target, level, format, type,
870 bufSize, pixels)) {
871 return;
872 }
873
874 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
875 /* not an error, do nothing */
876 return;
877 }
878
879 texObj = _mesa_get_current_tex_object(ctx, target);
880 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
881
882 if (_mesa_is_zero_size_texture(texImage))
883 return;
884
885 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
886 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
887 " dstFmt=0x%x, dstType=0x%x\n",
888 texObj->Name,
889 _mesa_get_format_name(texImage->TexFormat),
890 texImage->Width, texImage->Height,
891 format, type);
892 }
893
894 _mesa_lock_texture(ctx, texObj);
895 {
896 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
897 }
898 _mesa_unlock_texture(ctx, texObj);
899 }
900
901
902 void GLAPIENTRY
903 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
904 GLenum type, GLvoid *pixels )
905 {
906 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
907 }
908
909
910 /**
911 * Do error checking for a glGetCompressedTexImage() call.
912 * \return GL_TRUE if any error, GL_FALSE if no errors.
913 */
914 static GLboolean
915 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
916 GLint level, GLsizei clientMemSize, GLvoid *img)
917 {
918 struct gl_texture_object *texObj;
919 struct gl_texture_image *texImage;
920 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
921 GLuint compressedSize;
922
923 if (maxLevels == 0) {
924 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
925 target);
926 return GL_TRUE;
927 }
928
929 if (level < 0 || level >= maxLevels) {
930 _mesa_error(ctx, GL_INVALID_VALUE,
931 "glGetCompressedTexImageARB(bad level = %d)", level);
932 return GL_TRUE;
933 }
934
935 if (_mesa_is_proxy_texture(target)) {
936 _mesa_error(ctx, GL_INVALID_ENUM,
937 "glGetCompressedTexImageARB(bad target = %s)",
938 _mesa_lookup_enum_by_nr(target));
939 return GL_TRUE;
940 }
941
942 texObj = _mesa_get_current_tex_object(ctx, target);
943 if (!texObj) {
944 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
945 return GL_TRUE;
946 }
947
948 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
949
950 if (!texImage) {
951 /* probably invalid mipmap level */
952 _mesa_error(ctx, GL_INVALID_VALUE,
953 "glGetCompressedTexImageARB(level)");
954 return GL_TRUE;
955 }
956
957 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
958 _mesa_error(ctx, GL_INVALID_OPERATION,
959 "glGetCompressedTexImageARB(texture is not compressed)");
960 return GL_TRUE;
961 }
962
963 compressedSize = _mesa_format_image_size(texImage->TexFormat,
964 texImage->Width,
965 texImage->Height,
966 texImage->Depth);
967
968 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
969 /* do bounds checking on writing to client memory */
970 if (clientMemSize < compressedSize) {
971 _mesa_error(ctx, GL_INVALID_OPERATION,
972 "glGetnCompressedTexImageARB(out of bounds access:"
973 " bufSize (%d) is too small)", clientMemSize);
974 return GL_TRUE;
975 }
976 } else {
977 /* do bounds checking on PBO write */
978 if ((const GLubyte *) img + compressedSize >
979 (const GLubyte *) ctx->Pack.BufferObj->Size) {
980 _mesa_error(ctx, GL_INVALID_OPERATION,
981 "glGetCompressedTexImage(out of bounds PBO access)");
982 return GL_TRUE;
983 }
984
985 /* make sure PBO is not mapped */
986 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
987 _mesa_error(ctx, GL_INVALID_OPERATION,
988 "glGetCompressedTexImage(PBO is mapped)");
989 return GL_TRUE;
990 }
991 }
992
993 return GL_FALSE;
994 }
995
996
997 void GLAPIENTRY
998 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
999 GLvoid *img)
1000 {
1001 struct gl_texture_object *texObj;
1002 struct gl_texture_image *texImage;
1003 GET_CURRENT_CONTEXT(ctx);
1004 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1005
1006 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
1007 return;
1008 }
1009
1010 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
1011 /* not an error, do nothing */
1012 return;
1013 }
1014
1015 texObj = _mesa_get_current_tex_object(ctx, target);
1016 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
1017
1018 if (_mesa_is_zero_size_texture(texImage))
1019 return;
1020
1021 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1022 _mesa_debug(ctx,
1023 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
1024 texObj->Name,
1025 _mesa_get_format_name(texImage->TexFormat),
1026 texImage->Width, texImage->Height);
1027 }
1028
1029 _mesa_lock_texture(ctx, texObj);
1030 {
1031 ctx->Driver.GetCompressedTexImage(ctx, texImage, img);
1032 }
1033 _mesa_unlock_texture(ctx, texObj);
1034 }
1035
1036 void GLAPIENTRY
1037 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
1038 {
1039 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
1040 }