a69c4ff70e8c16518b496e93d3d960ad4a330b95
[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
250 ctx->Driver.MapTextureImage(ctx, texImage, 0,
251 0, 0, width, height,
252 GL_MAP_READ_BIT,
253 &srcMap, &srcRowStride);
254 if (srcMap) {
255 _mesa_decompress_image(texFormat, width, height,
256 srcMap, srcRowStride, tempImage);
257
258 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
259 }
260 else {
261 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
262 }
263 }
264
265 if (baseFormat == GL_LUMINANCE ||
266 baseFormat == GL_LUMINANCE_ALPHA) {
267 /* Set green and blue to zero since the pack function here will
268 * compute L=R+G+B.
269 */
270 GLuint i;
271 for (i = 0; i < width * height; i++) {
272 tempImage[i * 4 + GCOMP] = tempImage[i * 4 + BCOMP] = 0.0f;
273 }
274 }
275
276 srcRow = tempImage;
277 for (row = 0; row < height; row++) {
278 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
279 width, height, format, type,
280 0, row, 0);
281
282 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow,
283 format, type, dest, &ctx->Pack, transferOps);
284 srcRow += width * 4;
285 }
286
287 free(tempImage);
288 }
289
290
291 /**
292 * Get an uncompressed color texture image.
293 */
294 static void
295 get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
296 GLenum format, GLenum type, GLvoid *pixels,
297 struct gl_texture_image *texImage,
298 GLbitfield transferOps)
299 {
300 /* don't want to apply sRGB -> RGB conversion here so override the format */
301 const gl_format texFormat =
302 _mesa_get_srgb_format_linear(texImage->TexFormat);
303 const GLuint width = texImage->Width;
304 GLuint height = texImage->Height;
305 GLuint depth = texImage->Depth;
306 GLuint img, row;
307 GLfloat (*rgba)[4];
308 GLuint (*rgba_uint)[4];
309 GLboolean is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
310
311 /* Allocate buffer for one row of texels */
312 rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
313 rgba_uint = (GLuint (*)[4]) rgba;
314 if (!rgba) {
315 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
316 return;
317 }
318
319 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
320 depth = height;
321 height = 1;
322 }
323
324 for (img = 0; img < depth; img++) {
325 GLubyte *srcMap;
326 GLint rowstride;
327
328 /* map src texture buffer */
329 ctx->Driver.MapTextureImage(ctx, texImage, img,
330 0, 0, width, height, GL_MAP_READ_BIT,
331 &srcMap, &rowstride);
332 if (srcMap) {
333 for (row = 0; row < height; row++) {
334 const GLubyte *src = srcMap + row * rowstride;
335 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
336 width, height, format, type,
337 img, row, 0);
338
339 if (is_integer) {
340 _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
341
342 if (texImage->_BaseFormat == GL_ALPHA) {
343 GLuint col;
344 for (col = 0; col < width; col++) {
345 rgba_uint[col][RCOMP] = 0;
346 rgba_uint[col][GCOMP] = 0;
347 rgba_uint[col][BCOMP] = 0;
348 }
349 }
350 else if (texImage->_BaseFormat == GL_LUMINANCE) {
351 GLuint col;
352 for (col = 0; col < width; col++) {
353 rgba_uint[col][GCOMP] = 0;
354 rgba_uint[col][BCOMP] = 0;
355 rgba_uint[col][ACOMP] = 1;
356 }
357 }
358 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
359 GLuint col;
360 for (col = 0; col < width; col++) {
361 rgba_uint[col][GCOMP] = 0;
362 rgba_uint[col][BCOMP] = 0;
363 }
364 }
365 else if (texImage->_BaseFormat == GL_INTENSITY) {
366 GLuint col;
367 for (col = 0; col < width; col++) {
368 rgba_uint[col][GCOMP] = 0;
369 rgba_uint[col][BCOMP] = 0;
370 rgba_uint[col][ACOMP] = 1;
371 }
372 }
373
374 _mesa_pack_rgba_span_int(ctx, width, rgba_uint,
375 format, type, dest);
376 } else {
377 _mesa_unpack_rgba_row(texFormat, width, src, rgba);
378
379 if (texImage->_BaseFormat == GL_ALPHA) {
380 GLuint col;
381 for (col = 0; col < width; col++) {
382 rgba[col][RCOMP] = 0.0F;
383 rgba[col][GCOMP] = 0.0F;
384 rgba[col][BCOMP] = 0.0F;
385 }
386 }
387 else if (texImage->_BaseFormat == GL_LUMINANCE) {
388 GLuint col;
389 for (col = 0; col < width; col++) {
390 rgba[col][GCOMP] = 0.0F;
391 rgba[col][BCOMP] = 0.0F;
392 rgba[col][ACOMP] = 1.0F;
393 }
394 }
395 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
396 GLuint col;
397 for (col = 0; col < width; col++) {
398 rgba[col][GCOMP] = 0.0F;
399 rgba[col][BCOMP] = 0.0F;
400 }
401 }
402 else if (texImage->_BaseFormat == GL_INTENSITY) {
403 GLuint col;
404 for (col = 0; col < width; col++) {
405 rgba[col][GCOMP] = 0.0F;
406 rgba[col][BCOMP] = 0.0F;
407 rgba[col][ACOMP] = 1.0F;
408 }
409 }
410
411 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
412 format, type, dest,
413 &ctx->Pack, transferOps);
414 }
415 }
416
417 /* Unmap the src texture buffer */
418 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
419 }
420 else {
421 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
422 break;
423 }
424 }
425
426 free(rgba);
427 }
428
429
430 /**
431 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
432 * Compressed textures are handled here as well.
433 */
434 static void
435 get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
436 GLenum format, GLenum type, GLvoid *pixels,
437 struct gl_texture_image *texImage)
438 {
439 const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
440 GLbitfield transferOps = 0x0;
441
442 /* In general, clamping does not apply to glGetTexImage, except when
443 * the returned type of the image can't hold negative values.
444 */
445 if (type_needs_clamping(type)) {
446 /* the returned image type can't have negative values */
447 if (dataType == GL_FLOAT ||
448 dataType == GL_SIGNED_NORMALIZED ||
449 format == GL_LUMINANCE ||
450 format == GL_LUMINANCE_ALPHA) {
451 transferOps |= IMAGE_CLAMP_BIT;
452 }
453 }
454 /* This applies to RGB, RGBA textures. if the format is either LUMINANCE
455 * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to
456 * clamp the sum to [0,1].
457 */
458 else if ((format == GL_LUMINANCE ||
459 format == GL_LUMINANCE_ALPHA) &&
460 dataType == GL_UNSIGNED_NORMALIZED) {
461 transferOps |= IMAGE_CLAMP_BIT;
462 }
463
464 if (_mesa_is_format_compressed(texImage->TexFormat)) {
465 get_tex_rgba_compressed(ctx, dimensions, format, type,
466 pixels, texImage, transferOps);
467 }
468 else {
469 get_tex_rgba_uncompressed(ctx, dimensions, format, type,
470 pixels, texImage, transferOps);
471 }
472 }
473
474
475 /**
476 * Try to do glGetTexImage() with simple memcpy().
477 * \return GL_TRUE if done, GL_FALSE otherwise
478 */
479 static GLboolean
480 get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
481 GLvoid *pixels,
482 struct gl_texture_image *texImage)
483 {
484 const GLenum target = texImage->TexObject->Target;
485 GLboolean memCopy = GL_FALSE;
486
487 /*
488 * Check if the src/dst formats are compatible.
489 * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
490 * so we don't have to worry about those.
491 * XXX more format combinations could be supported here.
492 */
493 if (target == GL_TEXTURE_1D ||
494 target == GL_TEXTURE_2D ||
495 target == GL_TEXTURE_RECTANGLE ||
496 _mesa_is_cube_face(target)) {
497 if ((texImage->TexFormat == MESA_FORMAT_ARGB8888 ||
498 texImage->TexFormat == MESA_FORMAT_SARGB8) &&
499 format == GL_BGRA &&
500 (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT_8_8_8_8_REV) &&
501 !ctx->Pack.SwapBytes &&
502 _mesa_little_endian()) {
503 memCopy = GL_TRUE;
504 }
505 else if ((texImage->TexFormat == MESA_FORMAT_AL88 ||
506 texImage->TexFormat == MESA_FORMAT_SLA8) &&
507 format == GL_LUMINANCE_ALPHA &&
508 type == GL_UNSIGNED_BYTE &&
509 !ctx->Pack.SwapBytes &&
510 _mesa_little_endian()) {
511 memCopy = GL_TRUE;
512 }
513 else if ((texImage->TexFormat == MESA_FORMAT_L8 ||
514 texImage->TexFormat == MESA_FORMAT_SL8) &&
515 format == GL_LUMINANCE &&
516 type == GL_UNSIGNED_BYTE) {
517 memCopy = GL_TRUE;
518 }
519 else if (texImage->TexFormat == MESA_FORMAT_L16 &&
520 format == GL_LUMINANCE &&
521 type == GL_UNSIGNED_SHORT) {
522 memCopy = GL_TRUE;
523 }
524 else if (texImage->TexFormat == MESA_FORMAT_A8 &&
525 format == GL_ALPHA &&
526 type == GL_UNSIGNED_BYTE) {
527 memCopy = GL_TRUE;
528 }
529 else if (texImage->TexFormat == MESA_FORMAT_A16 &&
530 format == GL_ALPHA &&
531 type == GL_UNSIGNED_SHORT) {
532 memCopy = GL_TRUE;
533 }
534 }
535
536 if (memCopy) {
537 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
538 const GLuint bytesPerRow = texImage->Width * bpp;
539 GLubyte *dst =
540 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
541 texImage->Height, format, type, 0, 0);
542 const GLint dstRowStride =
543 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
544 GLubyte *src;
545 GLint srcRowStride;
546
547 /* map src texture buffer */
548 ctx->Driver.MapTextureImage(ctx, texImage, 0,
549 0, 0, texImage->Width, texImage->Height,
550 GL_MAP_READ_BIT, &src, &srcRowStride);
551
552 if (src) {
553 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
554 memcpy(dst, src, bytesPerRow * texImage->Height);
555 }
556 else {
557 GLuint row;
558 for (row = 0; row < texImage->Height; row++) {
559 memcpy(dst, src, bytesPerRow);
560 dst += dstRowStride;
561 src += srcRowStride;
562 }
563 }
564
565 /* unmap src texture buffer */
566 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
567 }
568 else {
569 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
570 }
571 }
572
573 return memCopy;
574 }
575
576
577 /**
578 * This is the software fallback for Driver.GetTexImage().
579 * All error checking will have been done before this routine is called.
580 * We'll call ctx->Driver.MapTextureImage() to access the data, then
581 * unmap with ctx->Driver.UnmapTextureImage().
582 */
583 void
584 _mesa_get_teximage(struct gl_context *ctx,
585 GLenum format, GLenum type, GLvoid *pixels,
586 struct gl_texture_image *texImage)
587 {
588 GLuint dimensions;
589
590 switch (texImage->TexObject->Target) {
591 case GL_TEXTURE_1D:
592 dimensions = 1;
593 break;
594 case GL_TEXTURE_3D:
595 dimensions = 3;
596 break;
597 default:
598 dimensions = 2;
599 }
600
601 /* map dest buffer, if PBO */
602 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
603 /* Packing texture image into a PBO.
604 * Map the (potentially) VRAM-based buffer into our process space so
605 * we can write into it with the code below.
606 * A hardware driver might use a sophisticated blit to move the
607 * texture data to the PBO if the PBO is in VRAM along with the texture.
608 */
609 GLubyte *buf = (GLubyte *)
610 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
611 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
612 if (!buf) {
613 /* out of memory or other unexpected error */
614 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
615 return;
616 }
617 /* <pixels> was an offset into the PBO.
618 * Now make it a real, client-side pointer inside the mapped region.
619 */
620 pixels = ADD_POINTERS(buf, pixels);
621 }
622
623 if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
624 /* all done */
625 }
626 else if (format == GL_DEPTH_COMPONENT) {
627 get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
628 }
629 else if (format == GL_DEPTH_STENCIL_EXT) {
630 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
631 }
632 else if (format == GL_YCBCR_MESA) {
633 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
634 }
635 else {
636 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
637 }
638
639 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
640 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
641 }
642 }
643
644
645
646 /**
647 * This is the software fallback for Driver.GetCompressedTexImage().
648 * All error checking will have been done before this routine is called.
649 */
650 void
651 _mesa_get_compressed_teximage(struct gl_context *ctx,
652 struct gl_texture_image *texImage,
653 GLvoid *img)
654 {
655 const GLuint row_stride =
656 _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
657 GLuint i;
658 GLubyte *src;
659 GLint srcRowStride;
660
661 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
662 /* pack texture image into a PBO */
663 GLubyte *buf = (GLubyte *)
664 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
665 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj);
666 if (!buf) {
667 /* out of memory or other unexpected error */
668 _mesa_error(ctx, GL_OUT_OF_MEMORY,
669 "glGetCompresssedTexImage(map PBO failed)");
670 return;
671 }
672 img = ADD_POINTERS(buf, img);
673 }
674
675 /* map src texture buffer */
676 ctx->Driver.MapTextureImage(ctx, texImage, 0,
677 0, 0, texImage->Width, texImage->Height,
678 GL_MAP_READ_BIT, &src, &srcRowStride);
679
680 if (src) {
681 /* no pixelstore or pixel transfer, but respect stride */
682
683 if (row_stride == srcRowStride) {
684 const GLuint size = _mesa_format_image_size(texImage->TexFormat,
685 texImage->Width,
686 texImage->Height,
687 texImage->Depth);
688 memcpy(img, src, size);
689 }
690 else {
691 GLuint bw, bh;
692 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
693 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
694 memcpy((GLubyte *)img + i * row_stride,
695 (GLubyte *)src + i * srcRowStride,
696 row_stride);
697 }
698 }
699
700 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
701 }
702 else {
703 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
704 }
705
706 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
707 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj);
708 }
709 }
710
711
712
713 /**
714 * Do error checking for a glGetTexImage() call.
715 * \return GL_TRUE if any error, GL_FALSE if no errors.
716 */
717 static GLboolean
718 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
719 GLenum format, GLenum type, GLsizei clientMemSize,
720 GLvoid *pixels )
721 {
722 struct gl_texture_object *texObj;
723 struct gl_texture_image *texImage;
724 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
725 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
726 GLenum baseFormat, err;
727
728 if (maxLevels == 0) {
729 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
730 return GL_TRUE;
731 }
732
733 if (level < 0 || level >= maxLevels) {
734 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
735 return GL_TRUE;
736 }
737
738 err = _mesa_error_check_format_and_type(ctx, format, type);
739 if (err != GL_NO_ERROR) {
740 _mesa_error(ctx, err, "glGetTexImage(format/type)");
741 return GL_TRUE;
742 }
743
744 texObj = _mesa_get_current_tex_object(ctx, target);
745
746 if (!texObj || _mesa_is_proxy_texture(target)) {
747 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
748 return GL_TRUE;
749 }
750
751 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
752 if (!texImage) {
753 /* non-existant texture image */
754 return GL_TRUE;
755 }
756
757 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
758
759 /* Make sure the requested image format is compatible with the
760 * texture's format.
761 */
762 if (_mesa_is_color_format(format)
763 && !_mesa_is_color_format(baseFormat)) {
764 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
765 return GL_TRUE;
766 }
767 else if (_mesa_is_depth_format(format)
768 && !_mesa_is_depth_format(baseFormat)
769 && !_mesa_is_depthstencil_format(baseFormat)) {
770 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
771 return GL_TRUE;
772 }
773 else if (_mesa_is_ycbcr_format(format)
774 && !_mesa_is_ycbcr_format(baseFormat)) {
775 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
776 return GL_TRUE;
777 }
778 else if (_mesa_is_depthstencil_format(format)
779 && !_mesa_is_depthstencil_format(baseFormat)) {
780 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
781 return GL_TRUE;
782 }
783 else if (_mesa_is_dudv_format(format)
784 && !_mesa_is_dudv_format(baseFormat)) {
785 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
786 return GL_TRUE;
787 }
788
789 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
790 texImage->Height, texImage->Depth,
791 format, type, clientMemSize, pixels)) {
792 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
793 _mesa_error(ctx, GL_INVALID_OPERATION,
794 "glGetTexImage(out of bounds PBO access)");
795 } else {
796 _mesa_error(ctx, GL_INVALID_OPERATION,
797 "glGetnTexImageARB(out of bounds access:"
798 " bufSize (%d) is too small)", clientMemSize);
799 }
800 return GL_TRUE;
801 }
802
803 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
804 /* PBO should not be mapped */
805 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
806 _mesa_error(ctx, GL_INVALID_OPERATION,
807 "glGetTexImage(PBO is mapped)");
808 return GL_TRUE;
809 }
810 }
811
812 return GL_FALSE;
813 }
814
815
816
817 /**
818 * Get texture image. Called by glGetTexImage.
819 *
820 * \param target texture target.
821 * \param level image level.
822 * \param format pixel data format for returned image.
823 * \param type pixel data type for returned image.
824 * \param bufSize size of the pixels data buffer.
825 * \param pixels returned pixel data.
826 */
827 void GLAPIENTRY
828 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
829 GLenum type, GLsizei bufSize, GLvoid *pixels )
830 {
831 struct gl_texture_object *texObj;
832 struct gl_texture_image *texImage;
833 GET_CURRENT_CONTEXT(ctx);
834 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
835
836 if (getteximage_error_check(ctx, target, level, format, type,
837 bufSize, pixels)) {
838 return;
839 }
840
841 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
842 /* not an error, do nothing */
843 return;
844 }
845
846 texObj = _mesa_get_current_tex_object(ctx, target);
847 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
848
849 if (_mesa_is_zero_size_texture(texImage))
850 return;
851
852 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
853 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
854 " dstFmt=0x%x, dstType=0x%x\n",
855 texObj->Name,
856 _mesa_get_format_name(texImage->TexFormat),
857 texImage->Width, texImage->Height,
858 format, type);
859 }
860
861 _mesa_lock_texture(ctx, texObj);
862 {
863 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
864 }
865 _mesa_unlock_texture(ctx, texObj);
866 }
867
868
869 void GLAPIENTRY
870 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
871 GLenum type, GLvoid *pixels )
872 {
873 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
874 }
875
876
877 /**
878 * Do error checking for a glGetCompressedTexImage() call.
879 * \return GL_TRUE if any error, GL_FALSE if no errors.
880 */
881 static GLboolean
882 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
883 GLint level, GLsizei clientMemSize, GLvoid *img)
884 {
885 struct gl_texture_object *texObj;
886 struct gl_texture_image *texImage;
887 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
888 GLuint compressedSize;
889
890 if (maxLevels == 0) {
891 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
892 target);
893 return GL_TRUE;
894 }
895
896 if (level < 0 || level >= maxLevels) {
897 _mesa_error(ctx, GL_INVALID_VALUE,
898 "glGetCompressedTexImageARB(bad level = %d)", level);
899 return GL_TRUE;
900 }
901
902 if (_mesa_is_proxy_texture(target)) {
903 _mesa_error(ctx, GL_INVALID_ENUM,
904 "glGetCompressedTexImageARB(bad target = %s)",
905 _mesa_lookup_enum_by_nr(target));
906 return GL_TRUE;
907 }
908
909 texObj = _mesa_get_current_tex_object(ctx, target);
910 if (!texObj) {
911 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
912 return GL_TRUE;
913 }
914
915 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
916
917 if (!texImage) {
918 /* probably invalid mipmap level */
919 _mesa_error(ctx, GL_INVALID_VALUE,
920 "glGetCompressedTexImageARB(level)");
921 return GL_TRUE;
922 }
923
924 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
925 _mesa_error(ctx, GL_INVALID_OPERATION,
926 "glGetCompressedTexImageARB(texture is not compressed)");
927 return GL_TRUE;
928 }
929
930 compressedSize = _mesa_format_image_size(texImage->TexFormat,
931 texImage->Width,
932 texImage->Height,
933 texImage->Depth);
934
935 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
936 /* do bounds checking on writing to client memory */
937 if (clientMemSize < compressedSize) {
938 _mesa_error(ctx, GL_INVALID_OPERATION,
939 "glGetnCompressedTexImageARB(out of bounds access:"
940 " bufSize (%d) is too small)", clientMemSize);
941 return GL_TRUE;
942 }
943 } else {
944 /* do bounds checking on PBO write */
945 if ((const GLubyte *) img + compressedSize >
946 (const GLubyte *) ctx->Pack.BufferObj->Size) {
947 _mesa_error(ctx, GL_INVALID_OPERATION,
948 "glGetCompressedTexImage(out of bounds PBO access)");
949 return GL_TRUE;
950 }
951
952 /* make sure PBO is not mapped */
953 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
954 _mesa_error(ctx, GL_INVALID_OPERATION,
955 "glGetCompressedTexImage(PBO is mapped)");
956 return GL_TRUE;
957 }
958 }
959
960 return GL_FALSE;
961 }
962
963
964 void GLAPIENTRY
965 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
966 GLvoid *img)
967 {
968 struct gl_texture_object *texObj;
969 struct gl_texture_image *texImage;
970 GET_CURRENT_CONTEXT(ctx);
971 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
972
973 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
974 return;
975 }
976
977 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
978 /* not an error, do nothing */
979 return;
980 }
981
982 texObj = _mesa_get_current_tex_object(ctx, target);
983 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
984
985 if (_mesa_is_zero_size_texture(texImage))
986 return;
987
988 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
989 _mesa_debug(ctx,
990 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
991 texObj->Name,
992 _mesa_get_format_name(texImage->TexFormat),
993 texImage->Width, texImage->Height);
994 }
995
996 _mesa_lock_texture(ctx, texObj);
997 {
998 ctx->Driver.GetCompressedTexImage(ctx, texImage, img);
999 }
1000 _mesa_unlock_texture(ctx, texObj);
1001 }
1002
1003 void GLAPIENTRY
1004 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
1005 {
1006 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
1007 }