754c3658ced7780b5e28da70202d6d2855e96c99
[mesa.git] / src / mesa / main / texgetimage.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 * Copyright (c) 2009 VMware, Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /**
28 * Code for glGetTexImage() and glGetCompressedTexImage().
29 */
30
31
32 #include "glheader.h"
33 #include "bufferobj.h"
34 #include "enums.h"
35 #include "context.h"
36 #include "formats.h"
37 #include "format_unpack.h"
38 #include "glformats.h"
39 #include "image.h"
40 #include "mtypes.h"
41 #include "pack.h"
42 #include "pbo.h"
43 #include "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 = 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 assert(format == GL_DEPTH_STENCIL);
134 assert(type == GL_UNSIGNED_INT_24_8);
135 /* XXX type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV is not handled yet */
136
137 for (img = 0; img < depth; img++) {
138 GLubyte *srcMap;
139 GLint rowstride;
140
141 /* map src texture buffer */
142 ctx->Driver.MapTextureImage(ctx, texImage, img,
143 0, 0, width, height, GL_MAP_READ_BIT,
144 &srcMap, &rowstride);
145
146 if (srcMap) {
147 for (row = 0; row < height; row++) {
148 const GLubyte *src = srcMap + row * rowstride;
149 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
150 width, height, format, type,
151 img, row, 0);
152 /* Unpack from texture's format to GL's z24_s8 layout */
153 _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat,
154 width,
155 (const GLuint *) src,
156 dest);
157 if (ctx->Pack.SwapBytes) {
158 _mesa_swap4((GLuint *) dest, width);
159 }
160 }
161
162 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
163 }
164 else {
165 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
166 break;
167 }
168 }
169 }
170
171
172 /**
173 * glGetTexImage for YCbCr pixels.
174 */
175 static void
176 get_tex_ycbcr(struct gl_context *ctx, GLuint dimensions,
177 GLenum format, GLenum type, GLvoid *pixels,
178 struct gl_texture_image *texImage)
179 {
180 const GLint width = texImage->Width;
181 const GLint height = texImage->Height;
182 const GLint depth = texImage->Depth;
183 GLint img, row;
184
185 for (img = 0; img < depth; img++) {
186 GLubyte *srcMap;
187 GLint rowstride;
188
189 /* map src texture buffer */
190 ctx->Driver.MapTextureImage(ctx, texImage, img,
191 0, 0, width, height, GL_MAP_READ_BIT,
192 &srcMap, &rowstride);
193
194 if (srcMap) {
195 for (row = 0; row < height; row++) {
196 const GLubyte *src = srcMap + row * rowstride;
197 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
198 width, height, format, type,
199 img, row, 0);
200 memcpy(dest, src, width * sizeof(GLushort));
201
202 /* check for byte swapping */
203 if ((texImage->TexFormat == MESA_FORMAT_YCBCR
204 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
205 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
206 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
207 if (!ctx->Pack.SwapBytes)
208 _mesa_swap2((GLushort *) dest, width);
209 }
210 else if (ctx->Pack.SwapBytes) {
211 _mesa_swap2((GLushort *) dest, width);
212 }
213 }
214
215 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
216 }
217 else {
218 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
219 break;
220 }
221 }
222 }
223
224
225 /**
226 * Get a color texture image with decompression.
227 */
228 static void
229 get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions,
230 GLenum format, GLenum type, GLvoid *pixels,
231 struct gl_texture_image *texImage,
232 GLbitfield transferOps)
233 {
234 /* don't want to apply sRGB -> RGB conversion here so override the format */
235 const mesa_format texFormat =
236 _mesa_get_srgb_format_linear(texImage->TexFormat);
237 const GLenum baseFormat = _mesa_get_format_base_format(texFormat);
238 const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format);
239 GLenum rebaseFormat = GL_NONE;
240 const GLuint width = texImage->Width;
241 const GLuint height = texImage->Height;
242 const GLuint depth = texImage->Depth;
243 GLfloat *tempImage, *tempSlice, *srcRow;
244 GLuint row, slice;
245
246 /* Decompress into temp float buffer, then pack into user buffer */
247 tempImage = malloc(width * height * depth
248 * 4 * sizeof(GLfloat));
249 if (!tempImage) {
250 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
251 return;
252 }
253
254 /* Decompress the texture image slices - results in 'tempImage' */
255 for (slice = 0; slice < depth; slice++) {
256 GLubyte *srcMap;
257 GLint srcRowStride;
258
259 tempSlice = tempImage + slice * 4 * width * height;
260
261 ctx->Driver.MapTextureImage(ctx, texImage, slice,
262 0, 0, width, height,
263 GL_MAP_READ_BIT,
264 &srcMap, &srcRowStride);
265 if (srcMap) {
266 _mesa_decompress_image(texFormat, width, height,
267 srcMap, srcRowStride, tempSlice);
268
269 ctx->Driver.UnmapTextureImage(ctx, texImage, slice);
270 }
271 else {
272 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
273 free(tempImage);
274 return;
275 }
276 }
277
278 if (baseFormat == GL_LUMINANCE ||
279 baseFormat == GL_INTENSITY ||
280 baseFormat == GL_LUMINANCE_ALPHA) {
281 /* If a luminance (or intensity) texture is read back as RGB(A), the
282 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat
283 * here to get G=B=0.
284 */
285 rebaseFormat = texImage->_BaseFormat;
286 }
287 else if ((baseFormat == GL_RGBA ||
288 baseFormat == GL_RGB ||
289 baseFormat == GL_RG) &&
290 (destBaseFormat == GL_LUMINANCE ||
291 destBaseFormat == GL_LUMINANCE_ALPHA ||
292 destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
293 destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) {
294 /* If we're reading back an RGB(A) texture as luminance then we need
295 * to return L=tex(R). Note, that's different from glReadPixels which
296 * returns L=R+G+B.
297 */
298 rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */
299 }
300
301 if (rebaseFormat) {
302 _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage,
303 rebaseFormat);
304 }
305
306 tempSlice = tempImage;
307 for (slice = 0; slice < depth; slice++) {
308 srcRow = tempSlice;
309 for (row = 0; row < height; row++) {
310 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
311 width, height, format, type,
312 slice, row, 0);
313
314 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow,
315 format, type, dest, &ctx->Pack, transferOps);
316 srcRow += 4 * width;
317 }
318 tempSlice += 4 * width * height;
319 }
320
321 free(tempImage);
322 }
323
324
325 /**
326 * Return a base GL format given the user-requested format
327 * for glGetTexImage().
328 */
329 GLenum
330 _mesa_base_pack_format(GLenum format)
331 {
332 switch (format) {
333 case GL_ABGR_EXT:
334 case GL_BGRA:
335 case GL_BGRA_INTEGER:
336 case GL_RGBA_INTEGER:
337 return GL_RGBA;
338 case GL_BGR:
339 case GL_BGR_INTEGER:
340 case GL_RGB_INTEGER:
341 return GL_RGB;
342 case GL_RED_INTEGER:
343 return GL_RED;
344 case GL_GREEN_INTEGER:
345 return GL_GREEN;
346 case GL_BLUE_INTEGER:
347 return GL_BLUE;
348 case GL_ALPHA_INTEGER:
349 return GL_ALPHA;
350 case GL_LUMINANCE_INTEGER_EXT:
351 return GL_LUMINANCE;
352 case GL_LUMINANCE_ALPHA_INTEGER_EXT:
353 return GL_LUMINANCE_ALPHA;
354 default:
355 return format;
356 }
357 }
358
359
360 /**
361 * Get an uncompressed color texture image.
362 */
363 static void
364 get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions,
365 GLenum format, GLenum type, GLvoid *pixels,
366 struct gl_texture_image *texImage,
367 GLbitfield transferOps)
368 {
369 /* don't want to apply sRGB -> RGB conversion here so override the format */
370 const mesa_format texFormat =
371 _mesa_get_srgb_format_linear(texImage->TexFormat);
372 const GLuint width = texImage->Width;
373 GLenum destBaseFormat = _mesa_base_pack_format(format);
374 GLenum rebaseFormat = GL_NONE;
375 GLuint height = texImage->Height;
376 GLuint depth = texImage->Depth;
377 GLuint img, row;
378 GLfloat (*rgba)[4];
379 GLuint (*rgba_uint)[4];
380 GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat);
381 GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat);
382 GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat);
383
384 /* Allocate buffer for one row of texels */
385 rgba = malloc(4 * width * sizeof(GLfloat));
386 rgba_uint = (GLuint (*)[4]) rgba;
387 if (!rgba) {
388 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()");
389 return;
390 }
391
392 if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
393 depth = height;
394 height = 1;
395 }
396
397 if (texImage->_BaseFormat == GL_LUMINANCE ||
398 texImage->_BaseFormat == GL_INTENSITY ||
399 texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
400 /* If a luminance (or intensity) texture is read back as RGB(A), the
401 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat
402 * here to get G=B=0.
403 */
404 rebaseFormat = texImage->_BaseFormat;
405 }
406 else if ((texImage->_BaseFormat == GL_RGBA ||
407 texImage->_BaseFormat == GL_RGB ||
408 texImage->_BaseFormat == GL_RG) &&
409 (destBaseFormat == GL_LUMINANCE ||
410 destBaseFormat == GL_LUMINANCE_ALPHA ||
411 destBaseFormat == GL_LUMINANCE_INTEGER_EXT ||
412 destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) {
413 /* If we're reading back an RGB(A) texture as luminance then we need
414 * to return L=tex(R). Note, that's different from glReadPixels which
415 * returns L=R+G+B.
416 */
417 rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */
418 }
419 else if (texImage->_BaseFormat != texBaseFormat) {
420 /* The internal format and the real format differ, so we can't rely
421 * on the unpack functions setting the correct constant values.
422 * (e.g. reading back GL_RGB8 which is actually RGBA won't set alpha=1)
423 */
424 switch (texImage->_BaseFormat) {
425 case GL_RED:
426 if ((texBaseFormat == GL_RGBA ||
427 texBaseFormat == GL_RGB ||
428 texBaseFormat == GL_RG) &&
429 (destBaseFormat == GL_RGBA ||
430 destBaseFormat == GL_RGB ||
431 destBaseFormat == GL_RG ||
432 destBaseFormat == GL_GREEN)) {
433 rebaseFormat = texImage->_BaseFormat;
434 break;
435 }
436 /* fall through */
437 case GL_RG:
438 if ((texBaseFormat == GL_RGBA ||
439 texBaseFormat == GL_RGB) &&
440 (destBaseFormat == GL_RGBA ||
441 destBaseFormat == GL_RGB ||
442 destBaseFormat == GL_BLUE)) {
443 rebaseFormat = texImage->_BaseFormat;
444 break;
445 }
446 /* fall through */
447 case GL_RGB:
448 if (texBaseFormat == GL_RGBA &&
449 (destBaseFormat == GL_RGBA ||
450 destBaseFormat == GL_ALPHA ||
451 destBaseFormat == GL_LUMINANCE_ALPHA)) {
452 rebaseFormat = texImage->_BaseFormat;
453 }
454 break;
455
456 case GL_ALPHA:
457 if (destBaseFormat != GL_ALPHA) {
458 rebaseFormat = texImage->_BaseFormat;
459 }
460 break;
461 }
462 }
463
464 for (img = 0; img < depth; img++) {
465 GLubyte *srcMap;
466 GLint rowstride;
467
468 /* map src texture buffer */
469 ctx->Driver.MapTextureImage(ctx, texImage, img,
470 0, 0, width, height, GL_MAP_READ_BIT,
471 &srcMap, &rowstride);
472 if (srcMap) {
473 for (row = 0; row < height; row++) {
474 const GLubyte *src = srcMap + row * rowstride;
475 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
476 width, height, format, type,
477 img, row, 0);
478
479 if (tex_is_integer) {
480 _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint);
481 if (rebaseFormat)
482 _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat);
483 if (tex_is_uint) {
484 _mesa_pack_rgba_span_from_uints(ctx, width,
485 (GLuint (*)[4]) rgba_uint,
486 format, type, dest);
487 } else {
488 _mesa_pack_rgba_span_from_ints(ctx, width,
489 (GLint (*)[4]) rgba_uint,
490 format, type, dest);
491 }
492 } else {
493 _mesa_unpack_rgba_row(texFormat, width, src, rgba);
494 if (rebaseFormat)
495 _mesa_rebase_rgba_float(width, rgba, rebaseFormat);
496 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
497 format, type, dest,
498 &ctx->Pack, transferOps);
499 }
500 }
501
502 /* Unmap the src texture buffer */
503 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
504 }
505 else {
506 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
507 break;
508 }
509 }
510
511 free(rgba);
512 }
513
514
515 /**
516 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
517 * Compressed textures are handled here as well.
518 */
519 static void
520 get_tex_rgba(struct gl_context *ctx, GLuint dimensions,
521 GLenum format, GLenum type, GLvoid *pixels,
522 struct gl_texture_image *texImage)
523 {
524 const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
525 GLbitfield transferOps = 0x0;
526
527 /* In general, clamping does not apply to glGetTexImage, except when
528 * the returned type of the image can't hold negative values.
529 */
530 if (type_needs_clamping(type)) {
531 /* the returned image type can't have negative values */
532 if (dataType == GL_FLOAT ||
533 dataType == GL_HALF_FLOAT ||
534 dataType == GL_SIGNED_NORMALIZED ||
535 format == GL_LUMINANCE ||
536 format == GL_LUMINANCE_ALPHA) {
537 transferOps |= IMAGE_CLAMP_BIT;
538 }
539 }
540
541 if (_mesa_is_format_compressed(texImage->TexFormat)) {
542 get_tex_rgba_compressed(ctx, dimensions, format, type,
543 pixels, texImage, transferOps);
544 }
545 else {
546 get_tex_rgba_uncompressed(ctx, dimensions, format, type,
547 pixels, texImage, transferOps);
548 }
549 }
550
551
552 /**
553 * Try to do glGetTexImage() with simple memcpy().
554 * \return GL_TRUE if done, GL_FALSE otherwise
555 */
556 static GLboolean
557 get_tex_memcpy(struct gl_context *ctx, GLenum format, GLenum type,
558 GLvoid *pixels,
559 struct gl_texture_image *texImage)
560 {
561 const GLenum target = texImage->TexObject->Target;
562 GLboolean memCopy = GL_FALSE;
563 GLenum texBaseFormat = _mesa_get_format_base_format(texImage->TexFormat);
564
565 /*
566 * Check if we can use memcpy to copy from the hardware texture
567 * format to the user's format/type.
568 * Note that GL's pixel transfer ops don't apply to glGetTexImage()
569 */
570 if ((target == GL_TEXTURE_1D ||
571 target == GL_TEXTURE_2D ||
572 target == GL_TEXTURE_RECTANGLE ||
573 _mesa_is_cube_face(target)) &&
574 texBaseFormat == texImage->_BaseFormat) {
575 memCopy = _mesa_format_matches_format_and_type(texImage->TexFormat,
576 format, type,
577 ctx->Pack.SwapBytes);
578 }
579
580 if (memCopy) {
581 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
582 const GLuint bytesPerRow = texImage->Width * bpp;
583 GLubyte *dst =
584 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
585 texImage->Height, format, type, 0, 0);
586 const GLint dstRowStride =
587 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
588 GLubyte *src;
589 GLint srcRowStride;
590
591 /* map src texture buffer */
592 ctx->Driver.MapTextureImage(ctx, texImage, 0,
593 0, 0, texImage->Width, texImage->Height,
594 GL_MAP_READ_BIT, &src, &srcRowStride);
595
596 if (src) {
597 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
598 memcpy(dst, src, bytesPerRow * texImage->Height);
599 }
600 else {
601 GLuint row;
602 for (row = 0; row < texImage->Height; row++) {
603 memcpy(dst, src, bytesPerRow);
604 dst += dstRowStride;
605 src += srcRowStride;
606 }
607 }
608
609 /* unmap src texture buffer */
610 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
611 }
612 else {
613 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
614 }
615 }
616
617 return memCopy;
618 }
619
620
621 /**
622 * This is the software fallback for Driver.GetTexImage().
623 * All error checking will have been done before this routine is called.
624 * We'll call ctx->Driver.MapTextureImage() to access the data, then
625 * unmap with ctx->Driver.UnmapTextureImage().
626 */
627 void
628 _mesa_get_teximage(struct gl_context *ctx,
629 GLenum format, GLenum type, GLvoid *pixels,
630 struct gl_texture_image *texImage)
631 {
632 const GLuint dimensions =
633 _mesa_get_texture_dimensions(texImage->TexObject->Target);
634
635 /* map dest buffer, if PBO */
636 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
637 /* Packing texture image into a PBO.
638 * Map the (potentially) VRAM-based buffer into our process space so
639 * we can write into it with the code below.
640 * A hardware driver might use a sophisticated blit to move the
641 * texture data to the PBO if the PBO is in VRAM along with the texture.
642 */
643 GLubyte *buf = (GLubyte *)
644 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
645 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
646 MAP_INTERNAL);
647 if (!buf) {
648 /* out of memory or other unexpected error */
649 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
650 return;
651 }
652 /* <pixels> was an offset into the PBO.
653 * Now make it a real, client-side pointer inside the mapped region.
654 */
655 pixels = ADD_POINTERS(buf, pixels);
656 }
657
658 if (get_tex_memcpy(ctx, format, type, pixels, texImage)) {
659 /* all done */
660 }
661 else if (format == GL_DEPTH_COMPONENT) {
662 get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
663 }
664 else if (format == GL_DEPTH_STENCIL_EXT) {
665 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
666 }
667 else if (format == GL_YCBCR_MESA) {
668 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
669 }
670 else {
671 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
672 }
673
674 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
675 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
676 }
677 }
678
679
680
681 /**
682 * This is the software fallback for Driver.GetCompressedTexImage().
683 * All error checking will have been done before this routine is called.
684 */
685 void
686 _mesa_get_compressed_teximage(struct gl_context *ctx,
687 struct gl_texture_image *texImage,
688 GLvoid *img)
689 {
690 const GLuint row_stride =
691 _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
692 GLuint i;
693 GLubyte *src;
694 GLint srcRowStride;
695
696 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
697 /* pack texture image into a PBO */
698 GLubyte *buf = (GLubyte *)
699 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
700 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
701 MAP_INTERNAL);
702 if (!buf) {
703 /* out of memory or other unexpected error */
704 _mesa_error(ctx, GL_OUT_OF_MEMORY,
705 "glGetCompresssedTexImage(map PBO failed)");
706 return;
707 }
708 img = ADD_POINTERS(buf, img);
709 }
710
711 /* map src texture buffer */
712 ctx->Driver.MapTextureImage(ctx, texImage, 0,
713 0, 0, texImage->Width, texImage->Height,
714 GL_MAP_READ_BIT, &src, &srcRowStride);
715
716 if (src) {
717 /* no pixelstore or pixel transfer, but respect stride */
718
719 if (row_stride == srcRowStride) {
720 const GLuint size = _mesa_format_image_size(texImage->TexFormat,
721 texImage->Width,
722 texImage->Height,
723 texImage->Depth);
724 memcpy(img, src, size);
725 }
726 else {
727 GLuint bw, bh;
728 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
729 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
730 memcpy((GLubyte *)img + i * row_stride,
731 (GLubyte *)src + i * srcRowStride,
732 row_stride);
733 }
734 }
735
736 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
737 }
738 else {
739 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
740 }
741
742 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
743 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
744 }
745 }
746
747
748 /**
749 * Validate the texture target enum supplied to glTexImage or
750 * glCompressedTexImage.
751 */
752 static GLboolean
753 legal_getteximage_target(struct gl_context *ctx, GLenum target)
754 {
755 switch (target) {
756 case GL_TEXTURE_1D:
757 case GL_TEXTURE_2D:
758 case GL_TEXTURE_3D:
759 return GL_TRUE;
760 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
761 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
762 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
763 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
764 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
765 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
766 return ctx->Extensions.ARB_texture_cube_map;
767 case GL_TEXTURE_RECTANGLE_NV:
768 return ctx->Extensions.NV_texture_rectangle;
769 case GL_TEXTURE_1D_ARRAY_EXT:
770 case GL_TEXTURE_2D_ARRAY_EXT:
771 return ctx->Extensions.EXT_texture_array;
772 case GL_TEXTURE_CUBE_MAP_ARRAY:
773 return ctx->Extensions.ARB_texture_cube_map_array;
774 default:
775 return GL_FALSE;
776 }
777 }
778
779
780 /**
781 * Do error checking for a glGetTexImage() call.
782 * \return GL_TRUE if any error, GL_FALSE if no errors.
783 */
784 static GLboolean
785 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
786 GLenum format, GLenum type, GLsizei clientMemSize,
787 GLvoid *pixels )
788 {
789 struct gl_texture_object *texObj;
790 struct gl_texture_image *texImage;
791 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
792 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
793 GLenum baseFormat, err;
794
795 if (!legal_getteximage_target(ctx, target)) {
796 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
797 return GL_TRUE;
798 }
799
800 assert(maxLevels != 0);
801 if (level < 0 || level >= maxLevels) {
802 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
803 return GL_TRUE;
804 }
805
806 err = _mesa_error_check_format_and_type(ctx, format, type);
807 if (err != GL_NO_ERROR) {
808 _mesa_error(ctx, err, "glGetTexImage(format/type)");
809 return GL_TRUE;
810 }
811
812 texObj = _mesa_get_current_tex_object(ctx, target);
813
814 if (!texObj) {
815 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
816 return GL_TRUE;
817 }
818
819 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
820 if (!texImage) {
821 /* non-existant texture image */
822 return GL_TRUE;
823 }
824
825 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
826
827 /* Make sure the requested image format is compatible with the
828 * texture's format.
829 */
830 if (_mesa_is_color_format(format)
831 && !_mesa_is_color_format(baseFormat)) {
832 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
833 return GL_TRUE;
834 }
835 else if (_mesa_is_depth_format(format)
836 && !_mesa_is_depth_format(baseFormat)
837 && !_mesa_is_depthstencil_format(baseFormat)) {
838 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
839 return GL_TRUE;
840 }
841 else if (_mesa_is_stencil_format(format)
842 && !ctx->Extensions.ARB_texture_stencil8) {
843 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)");
844 return GL_TRUE;
845 }
846 else if (_mesa_is_ycbcr_format(format)
847 && !_mesa_is_ycbcr_format(baseFormat)) {
848 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
849 return GL_TRUE;
850 }
851 else if (_mesa_is_depthstencil_format(format)
852 && !_mesa_is_depthstencil_format(baseFormat)) {
853 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
854 return GL_TRUE;
855 }
856 else if (_mesa_is_dudv_format(format)
857 && !_mesa_is_dudv_format(baseFormat)) {
858 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
859 return GL_TRUE;
860 }
861 else if (_mesa_is_enum_format_integer(format) !=
862 _mesa_is_format_integer(texImage->TexFormat)) {
863 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
864 return GL_TRUE;
865 }
866
867 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
868 texImage->Height, texImage->Depth,
869 format, type, clientMemSize, pixels)) {
870 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
871 _mesa_error(ctx, GL_INVALID_OPERATION,
872 "glGetTexImage(out of bounds PBO access)");
873 } else {
874 _mesa_error(ctx, GL_INVALID_OPERATION,
875 "glGetnTexImageARB(out of bounds access:"
876 " bufSize (%d) is too small)", clientMemSize);
877 }
878 return GL_TRUE;
879 }
880
881 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
882 /* PBO should not be mapped */
883 if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
884 _mesa_error(ctx, GL_INVALID_OPERATION,
885 "glGetTexImage(PBO is mapped)");
886 return GL_TRUE;
887 }
888 }
889
890 return GL_FALSE;
891 }
892
893
894
895 /**
896 * Get texture image. Called by glGetTexImage.
897 *
898 * \param target texture target.
899 * \param level image level.
900 * \param format pixel data format for returned image.
901 * \param type pixel data type for returned image.
902 * \param bufSize size of the pixels data buffer.
903 * \param pixels returned pixel data.
904 */
905 void GLAPIENTRY
906 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
907 GLenum type, GLsizei bufSize, GLvoid *pixels )
908 {
909 struct gl_texture_object *texObj;
910 struct gl_texture_image *texImage;
911 GET_CURRENT_CONTEXT(ctx);
912
913 FLUSH_VERTICES(ctx, 0);
914
915 if (getteximage_error_check(ctx, target, level, format, type,
916 bufSize, pixels)) {
917 return;
918 }
919
920 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
921 /* not an error, do nothing */
922 return;
923 }
924
925 texObj = _mesa_get_current_tex_object(ctx, target);
926 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
927
928 if (_mesa_is_zero_size_texture(texImage))
929 return;
930
931 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
932 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
933 " dstFmt=0x%x, dstType=0x%x\n",
934 texObj->Name,
935 _mesa_get_format_name(texImage->TexFormat),
936 texImage->Width, texImage->Height,
937 format, type);
938 }
939
940 _mesa_lock_texture(ctx, texObj);
941 {
942 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
943 }
944 _mesa_unlock_texture(ctx, texObj);
945 }
946
947
948 void GLAPIENTRY
949 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
950 GLenum type, GLvoid *pixels )
951 {
952 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
953 }
954
955
956 /**
957 * Do error checking for a glGetCompressedTexImage() call.
958 * \return GL_TRUE if any error, GL_FALSE if no errors.
959 */
960 static GLboolean
961 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
962 GLint level, GLsizei clientMemSize, GLvoid *img)
963 {
964 struct gl_texture_object *texObj;
965 struct gl_texture_image *texImage;
966 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
967 GLuint compressedSize;
968
969 if (!legal_getteximage_target(ctx, target)) {
970 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
971 target);
972 return GL_TRUE;
973 }
974
975 assert(maxLevels != 0);
976 if (level < 0 || level >= maxLevels) {
977 _mesa_error(ctx, GL_INVALID_VALUE,
978 "glGetCompressedTexImageARB(bad level = %d)", level);
979 return GL_TRUE;
980 }
981
982 texObj = _mesa_get_current_tex_object(ctx, target);
983 if (!texObj) {
984 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
985 return GL_TRUE;
986 }
987
988 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
989
990 if (!texImage) {
991 /* probably invalid mipmap level */
992 _mesa_error(ctx, GL_INVALID_VALUE,
993 "glGetCompressedTexImageARB(level)");
994 return GL_TRUE;
995 }
996
997 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
998 _mesa_error(ctx, GL_INVALID_OPERATION,
999 "glGetCompressedTexImageARB(texture is not compressed)");
1000 return GL_TRUE;
1001 }
1002
1003 compressedSize = _mesa_format_image_size(texImage->TexFormat,
1004 texImage->Width,
1005 texImage->Height,
1006 texImage->Depth);
1007
1008 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1009 /* do bounds checking on writing to client memory */
1010 if (clientMemSize < (GLsizei) compressedSize) {
1011 _mesa_error(ctx, GL_INVALID_OPERATION,
1012 "glGetnCompressedTexImageARB(out of bounds access:"
1013 " bufSize (%d) is too small)", clientMemSize);
1014 return GL_TRUE;
1015 }
1016 } else {
1017 /* do bounds checking on PBO write */
1018 if ((const GLubyte *) img + compressedSize >
1019 (const GLubyte *) ctx->Pack.BufferObj->Size) {
1020 _mesa_error(ctx, GL_INVALID_OPERATION,
1021 "glGetCompressedTexImage(out of bounds PBO access)");
1022 return GL_TRUE;
1023 }
1024
1025 /* make sure PBO is not mapped */
1026 if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1027 _mesa_error(ctx, GL_INVALID_OPERATION,
1028 "glGetCompressedTexImage(PBO is mapped)");
1029 return GL_TRUE;
1030 }
1031 }
1032
1033 return GL_FALSE;
1034 }
1035
1036
1037 void GLAPIENTRY
1038 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1039 GLvoid *img)
1040 {
1041 struct gl_texture_object *texObj;
1042 struct gl_texture_image *texImage;
1043 GET_CURRENT_CONTEXT(ctx);
1044
1045 FLUSH_VERTICES(ctx, 0);
1046
1047 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
1048 return;
1049 }
1050
1051 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
1052 /* not an error, do nothing */
1053 return;
1054 }
1055
1056 texObj = _mesa_get_current_tex_object(ctx, target);
1057 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
1058
1059 if (_mesa_is_zero_size_texture(texImage))
1060 return;
1061
1062 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1063 _mesa_debug(ctx,
1064 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
1065 texObj->Name,
1066 _mesa_get_format_name(texImage->TexFormat),
1067 texImage->Width, texImage->Height);
1068 }
1069
1070 _mesa_lock_texture(ctx, texObj);
1071 {
1072 ctx->Driver.GetCompressedTexImage(ctx, texImage, img);
1073 }
1074 _mesa_unlock_texture(ctx, texObj);
1075 }
1076
1077 void GLAPIENTRY
1078 _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img)
1079 {
1080 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
1081 }