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