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