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