mesa: minor improvements to _mesa_compute_compressed_pixelstore()
[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 #include "texstore.h"
47
48
49
50 /**
51 * Can the given type represent negative values?
52 */
53 static inline GLboolean
54 type_needs_clamping(GLenum type)
55 {
56 switch (type) {
57 case GL_BYTE:
58 case GL_SHORT:
59 case GL_INT:
60 case GL_FLOAT:
61 case GL_HALF_FLOAT_ARB:
62 case GL_UNSIGNED_INT_10F_11F_11F_REV:
63 case GL_UNSIGNED_INT_5_9_9_9_REV:
64 return GL_FALSE;
65 default:
66 return GL_TRUE;
67 }
68 }
69
70
71 /**
72 * glGetTexImage for depth/Z pixels.
73 */
74 static void
75 get_tex_depth(struct gl_context *ctx, GLuint dimensions,
76 GLenum format, GLenum type, GLvoid *pixels,
77 struct gl_texture_image *texImage)
78 {
79 const GLint width = texImage->Width;
80 const GLint height = texImage->Height;
81 const GLint depth = texImage->Depth;
82 GLint img, row;
83 GLfloat *depthRow = malloc(width * sizeof(GLfloat));
84
85 if (!depthRow) {
86 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
87 return;
88 }
89
90 for (img = 0; img < depth; img++) {
91 GLubyte *srcMap;
92 GLint srcRowStride;
93
94 /* map src texture buffer */
95 ctx->Driver.MapTextureImage(ctx, texImage, img,
96 0, 0, width, height, GL_MAP_READ_BIT,
97 &srcMap, &srcRowStride);
98
99 if (srcMap) {
100 for (row = 0; row < height; row++) {
101 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
102 width, height, format, type,
103 img, row, 0);
104 const GLubyte *src = srcMap + row * srcRowStride;
105 _mesa_unpack_float_z_row(texImage->TexFormat, width, src, depthRow);
106 _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
107 }
108
109 ctx->Driver.UnmapTextureImage(ctx, texImage, img);
110 }
111 else {
112 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage");
113 break;
114 }
115 }
116
117 free(depthRow);
118 }
119
120
121 /**
122 * glGetTexImage for depth/stencil pixels.
123 */
124 static void
125 get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
126 GLenum format, GLenum type, GLvoid *pixels,
127 struct gl_texture_image *texImage)
128 {
129 const GLint width = texImage->Width;
130 const GLint height = texImage->Height;
131 const GLint depth = texImage->Depth;
132 GLint img, row;
133
134 assert(format == GL_DEPTH_STENCIL);
135 assert(type == GL_UNSIGNED_INT_24_8 ||
136 type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
137
138 for (img = 0; img < depth; img++) {
139 GLubyte *srcMap;
140 GLint rowstride;
141
142 /* map src texture buffer */
143 ctx->Driver.MapTextureImage(ctx, texImage, img,
144 0, 0, width, height, GL_MAP_READ_BIT,
145 &srcMap, &rowstride);
146
147 if (srcMap) {
148 for (row = 0; row < height; row++) {
149 const GLubyte *src = srcMap + row * rowstride;
150 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
151 width, height, format, type,
152 img, row, 0);
153 _mesa_unpack_depth_stencil_row(texImage->TexFormat,
154 width,
155 (const GLuint *) src,
156 type, 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 dimensions =
691 _mesa_get_texture_dimensions(texImage->TexObject->Target);
692 struct compressed_pixelstore store;
693 GLuint i, slice;
694 GLubyte *dest;
695
696 _mesa_compute_compressed_pixelstore(dimensions, texImage->TexFormat,
697 texImage->Width, texImage->Height,
698 texImage->Depth,
699 &ctx->Pack,
700 &store);
701
702 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
703 /* pack texture image into a PBO */
704 dest = (GLubyte *)
705 ctx->Driver.MapBufferRange(ctx, 0, ctx->Pack.BufferObj->Size,
706 GL_MAP_WRITE_BIT, ctx->Pack.BufferObj,
707 MAP_INTERNAL);
708 if (!dest) {
709 /* out of memory or other unexpected error */
710 _mesa_error(ctx, GL_OUT_OF_MEMORY,
711 "glGetCompresssedTexImage(map PBO failed)");
712 return;
713 }
714 dest = ADD_POINTERS(dest, img);
715 } else {
716 dest = img;
717 }
718
719 dest += store.SkipBytes;
720
721 for (slice = 0; slice < store.CopySlices; slice++) {
722 GLint srcRowStride;
723 GLubyte *src;
724
725 /* map src texture buffer */
726 ctx->Driver.MapTextureImage(ctx, texImage, 0,
727 0, 0, texImage->Width, texImage->Height,
728 GL_MAP_READ_BIT, &src, &srcRowStride);
729
730 if (src) {
731
732 for (i = 0; i < store.CopyRowsPerSlice; i++) {
733 memcpy(dest, src, store.CopyBytesPerRow);
734 dest += store.TotalBytesPerRow;
735 src += srcRowStride;
736 }
737
738 ctx->Driver.UnmapTextureImage(ctx, texImage, 0);
739
740 /* Advance to next slice */
741 dest += store.TotalBytesPerRow * (store.TotalRowsPerSlice - store.CopyRowsPerSlice);
742
743 } else {
744 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetCompresssedTexImage");
745 }
746 }
747
748 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
749 ctx->Driver.UnmapBuffer(ctx, ctx->Pack.BufferObj, MAP_INTERNAL);
750 }
751 }
752
753
754 /**
755 * Validate the texture target enum supplied to glTexImage or
756 * glCompressedTexImage.
757 */
758 static GLboolean
759 legal_getteximage_target(struct gl_context *ctx, GLenum target)
760 {
761 switch (target) {
762 case GL_TEXTURE_1D:
763 case GL_TEXTURE_2D:
764 case GL_TEXTURE_3D:
765 return GL_TRUE;
766 case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
767 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
768 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
769 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
770 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
771 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
772 return ctx->Extensions.ARB_texture_cube_map;
773 case GL_TEXTURE_RECTANGLE_NV:
774 return ctx->Extensions.NV_texture_rectangle;
775 case GL_TEXTURE_1D_ARRAY_EXT:
776 case GL_TEXTURE_2D_ARRAY_EXT:
777 return ctx->Extensions.EXT_texture_array;
778 case GL_TEXTURE_CUBE_MAP_ARRAY:
779 return ctx->Extensions.ARB_texture_cube_map_array;
780 default:
781 return GL_FALSE;
782 }
783 }
784
785
786 /**
787 * Do error checking for a glGetTexImage() call.
788 * \return GL_TRUE if any error, GL_FALSE if no errors.
789 */
790 static GLboolean
791 getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
792 GLenum format, GLenum type, GLsizei clientMemSize,
793 GLvoid *pixels )
794 {
795 struct gl_texture_object *texObj;
796 struct gl_texture_image *texImage;
797 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
798 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
799 GLenum baseFormat, err;
800
801 if (!legal_getteximage_target(ctx, target)) {
802 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
803 return GL_TRUE;
804 }
805
806 assert(maxLevels != 0);
807 if (level < 0 || level >= maxLevels) {
808 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
809 return GL_TRUE;
810 }
811
812 err = _mesa_error_check_format_and_type(ctx, format, type);
813 if (err != GL_NO_ERROR) {
814 _mesa_error(ctx, err, "glGetTexImage(format/type)");
815 return GL_TRUE;
816 }
817
818 texObj = _mesa_get_current_tex_object(ctx, target);
819
820 if (!texObj) {
821 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
822 return GL_TRUE;
823 }
824
825 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
826 if (!texImage) {
827 /* non-existant texture image */
828 return GL_TRUE;
829 }
830
831 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
832
833 /* Make sure the requested image format is compatible with the
834 * texture's format.
835 */
836 if (_mesa_is_color_format(format)
837 && !_mesa_is_color_format(baseFormat)) {
838 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
839 return GL_TRUE;
840 }
841 else if (_mesa_is_depth_format(format)
842 && !_mesa_is_depth_format(baseFormat)
843 && !_mesa_is_depthstencil_format(baseFormat)) {
844 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
845 return GL_TRUE;
846 }
847 else if (_mesa_is_stencil_format(format)
848 && !ctx->Extensions.ARB_texture_stencil8) {
849 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)");
850 return GL_TRUE;
851 }
852 else if (_mesa_is_ycbcr_format(format)
853 && !_mesa_is_ycbcr_format(baseFormat)) {
854 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
855 return GL_TRUE;
856 }
857 else if (_mesa_is_depthstencil_format(format)
858 && !_mesa_is_depthstencil_format(baseFormat)) {
859 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
860 return GL_TRUE;
861 }
862 else if (_mesa_is_enum_format_integer(format) !=
863 _mesa_is_format_integer(texImage->TexFormat)) {
864 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
865 return GL_TRUE;
866 }
867
868 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
869 texImage->Height, texImage->Depth,
870 format, type, clientMemSize, pixels)) {
871 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
872 _mesa_error(ctx, GL_INVALID_OPERATION,
873 "glGetTexImage(out of bounds PBO access)");
874 } else {
875 _mesa_error(ctx, GL_INVALID_OPERATION,
876 "glGetnTexImageARB(out of bounds access:"
877 " bufSize (%d) is too small)", clientMemSize);
878 }
879 return GL_TRUE;
880 }
881
882 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
883 /* PBO should not be mapped */
884 if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
885 _mesa_error(ctx, GL_INVALID_OPERATION,
886 "glGetTexImage(PBO is mapped)");
887 return GL_TRUE;
888 }
889 }
890
891 return GL_FALSE;
892 }
893
894
895
896 /**
897 * Get texture image. Called by glGetTexImage.
898 *
899 * \param target texture target.
900 * \param level image level.
901 * \param format pixel data format for returned image.
902 * \param type pixel data type for returned image.
903 * \param bufSize size of the pixels data buffer.
904 * \param pixels returned pixel data.
905 */
906 void GLAPIENTRY
907 _mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
908 GLenum type, GLsizei bufSize, GLvoid *pixels )
909 {
910 struct gl_texture_object *texObj;
911 struct gl_texture_image *texImage;
912 GET_CURRENT_CONTEXT(ctx);
913
914 FLUSH_VERTICES(ctx, 0);
915
916 if (getteximage_error_check(ctx, target, level, format, type,
917 bufSize, pixels)) {
918 return;
919 }
920
921 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
922 /* not an error, do nothing */
923 return;
924 }
925
926 texObj = _mesa_get_current_tex_object(ctx, target);
927 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
928
929 if (_mesa_is_zero_size_texture(texImage))
930 return;
931
932 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
933 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
934 " dstFmt=0x%x, dstType=0x%x\n",
935 texObj->Name,
936 _mesa_get_format_name(texImage->TexFormat),
937 texImage->Width, texImage->Height,
938 format, type);
939 }
940
941 _mesa_lock_texture(ctx, texObj);
942 {
943 ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
944 }
945 _mesa_unlock_texture(ctx, texObj);
946 }
947
948
949 void GLAPIENTRY
950 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
951 GLenum type, GLvoid *pixels )
952 {
953 _mesa_GetnTexImageARB(target, level, format, type, INT_MAX, pixels);
954 }
955
956
957 /**
958 * Do error checking for a glGetCompressedTexImage() call.
959 * \return GL_TRUE if any error, GL_FALSE if no errors.
960 */
961 static GLboolean
962 getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
963 GLint level, GLsizei clientMemSize, GLvoid *img)
964 {
965 struct gl_texture_object *texObj;
966 struct gl_texture_image *texImage;
967 const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
968 GLuint compressedSize, dimensions;
969
970 if (!legal_getteximage_target(ctx, target)) {
971 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
972 target);
973 return GL_TRUE;
974 }
975
976 assert(maxLevels != 0);
977 if (level < 0 || level >= maxLevels) {
978 _mesa_error(ctx, GL_INVALID_VALUE,
979 "glGetCompressedTexImageARB(bad level = %d)", level);
980 return GL_TRUE;
981 }
982
983 texObj = _mesa_get_current_tex_object(ctx, target);
984 if (!texObj) {
985 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
986 return GL_TRUE;
987 }
988
989 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
990
991 if (!texImage) {
992 /* probably invalid mipmap level */
993 _mesa_error(ctx, GL_INVALID_VALUE,
994 "glGetCompressedTexImageARB(level)");
995 return GL_TRUE;
996 }
997
998 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
999 _mesa_error(ctx, GL_INVALID_OPERATION,
1000 "glGetCompressedTexImageARB(texture is not compressed)");
1001 return GL_TRUE;
1002 }
1003
1004 compressedSize = _mesa_format_image_size(texImage->TexFormat,
1005 texImage->Width,
1006 texImage->Height,
1007 texImage->Depth);
1008
1009 /* Check for invalid pixel storage modes */
1010 dimensions = _mesa_get_texture_dimensions(texImage->TexObject->Target);
1011 if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dimensions,
1012 &ctx->Pack,
1013 "glGetCompressedTexImageARB")) {
1014 return GL_TRUE;
1015 }
1016
1017 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1018 /* do bounds checking on writing to client memory */
1019 if (clientMemSize < (GLsizei) compressedSize) {
1020 _mesa_error(ctx, GL_INVALID_OPERATION,
1021 "glGetnCompressedTexImageARB(out of bounds access:"
1022 " bufSize (%d) is too small)", clientMemSize);
1023 return GL_TRUE;
1024 }
1025 } else {
1026 /* do bounds checking on PBO write */
1027 if ((const GLubyte *) img + compressedSize >
1028 (const GLubyte *) ctx->Pack.BufferObj->Size) {
1029 _mesa_error(ctx, GL_INVALID_OPERATION,
1030 "glGetCompressedTexImage(out of bounds PBO access)");
1031 return GL_TRUE;
1032 }
1033
1034 /* make sure PBO is not mapped */
1035 if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1036 _mesa_error(ctx, GL_INVALID_OPERATION,
1037 "glGetCompressedTexImage(PBO is mapped)");
1038 return GL_TRUE;
1039 }
1040 }
1041
1042 return GL_FALSE;
1043 }
1044
1045
1046 void GLAPIENTRY
1047 _mesa_GetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
1048 GLvoid *img)
1049 {
1050 struct gl_texture_object *texObj;
1051 struct gl_texture_image *texImage;
1052 GET_CURRENT_CONTEXT(ctx);
1053
1054 FLUSH_VERTICES(ctx, 0);
1055
1056 if (getcompressedteximage_error_check(ctx, target, level, bufSize, img)) {
1057 return;
1058 }
1059
1060 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
1061 /* not an error, do nothing */
1062 return;
1063 }
1064
1065 texObj = _mesa_get_current_tex_object(ctx, target);
1066 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
1067
1068 if (_mesa_is_zero_size_texture(texImage))
1069 return;
1070
1071 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
1072 _mesa_debug(ctx,
1073 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
1074 texObj->Name,
1075 _mesa_get_format_name(texImage->TexFormat),
1076 texImage->Width, texImage->Height);
1077 }
1078
1079 _mesa_lock_texture(ctx, texObj);
1080 {
1081 ctx->Driver.GetCompressedTexImage(ctx, texImage, img);
1082 }
1083 _mesa_unlock_texture(ctx, texObj);
1084 }
1085
1086 void GLAPIENTRY
1087 _mesa_GetCompressedTexImage(GLenum target, GLint level, GLvoid *img)
1088 {
1089 _mesa_GetnCompressedTexImageARB(target, level, INT_MAX, img);
1090 }