Merge branch 'mesa_7_7_branch'
[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 "image.h"
38 #include "texcompress.h"
39 #include "texgetimage.h"
40 #include "teximage.h"
41 #include "texstate.h"
42
43
44
45 #if FEATURE_EXT_texture_sRGB
46
47 /**
48 * Convert a float value from linear space to a
49 * non-linear sRGB value in [0, 255].
50 * Not terribly efficient.
51 */
52 static INLINE GLfloat
53 linear_to_nonlinear(GLfloat cl)
54 {
55 /* can't have values outside [0, 1] */
56 GLfloat cs;
57 if (cl < 0.0031308f) {
58 cs = 12.92f * cl;
59 }
60 else {
61 cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
62 }
63 return cs;
64 }
65
66 #endif /* FEATURE_EXT_texture_sRGB */
67
68
69 /**
70 * Can the given type represent negative values?
71 */
72 static INLINE GLboolean
73 type_with_negative_values(GLenum type)
74 {
75 switch (type) {
76 case GL_BYTE:
77 case GL_SHORT:
78 case GL_INT:
79 case GL_FLOAT:
80 case GL_HALF_FLOAT_ARB:
81 return GL_TRUE;
82 default:
83 return GL_FALSE;
84 }
85 }
86
87
88 /**
89 * glGetTexImage for color index pixels.
90 */
91 static void
92 get_tex_color_index(GLcontext *ctx, GLuint dimensions,
93 GLenum format, GLenum type, GLvoid *pixels,
94 const struct gl_texture_image *texImage)
95 {
96 const GLint width = texImage->Width;
97 const GLint height = texImage->Height;
98 const GLint depth = texImage->Depth;
99 const GLuint indexBits =
100 _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
101 const GLbitfield transferOps = 0x0;
102 GLint img, row, col;
103
104 for (img = 0; img < depth; img++) {
105 for (row = 0; row < height; row++) {
106 GLuint indexRow[MAX_WIDTH] = { 0 };
107 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
108 width, height, format, type,
109 img, row, 0);
110 assert(dest);
111
112 if (indexBits == 8) {
113 const GLubyte *src = (const GLubyte *) texImage->Data;
114 src += width * (img * texImage->Height + row);
115 for (col = 0; col < width; col++) {
116 indexRow[col] = src[col];
117 }
118 }
119 else if (indexBits == 16) {
120 const GLushort *src = (const GLushort *) texImage->Data;
121 src += width * (img * texImage->Height + row);
122 for (col = 0; col < width; col++) {
123 indexRow[col] = src[col];
124 }
125 }
126 else {
127 _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage");
128 }
129 _mesa_pack_index_span(ctx, width, type, dest,
130 indexRow, &ctx->Pack, transferOps);
131 }
132 }
133 }
134
135
136 /**
137 * glGetTexImage for depth/Z pixels.
138 */
139 static void
140 get_tex_depth(GLcontext *ctx, GLuint dimensions,
141 GLenum format, GLenum type, GLvoid *pixels,
142 const struct gl_texture_image *texImage)
143 {
144 const GLint width = texImage->Width;
145 const GLint height = texImage->Height;
146 const GLint depth = texImage->Depth;
147 GLint img, row, col;
148
149 for (img = 0; img < depth; img++) {
150 for (row = 0; row < height; row++) {
151 GLfloat depthRow[MAX_WIDTH];
152 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
153 width, height, format, type,
154 img, row, 0);
155 assert(dest);
156
157 for (col = 0; col < width; col++) {
158 texImage->FetchTexelf(texImage, col, row, img, depthRow + col);
159 }
160 _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack);
161 }
162 }
163 }
164
165
166 /**
167 * glGetTexImage for depth/stencil pixels.
168 */
169 static void
170 get_tex_depth_stencil(GLcontext *ctx, GLuint dimensions,
171 GLenum format, GLenum type, GLvoid *pixels,
172 const struct gl_texture_image *texImage)
173 {
174 const GLint width = texImage->Width;
175 const GLint height = texImage->Height;
176 const GLint depth = texImage->Depth;
177 const GLuint *src = (const GLuint *) texImage->Data;
178 GLint img, row;
179
180 for (img = 0; img < depth; img++) {
181 for (row = 0; row < height; row++) {
182 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
183 width, height, format, type,
184 img, row, 0);
185 _mesa_memcpy(dest, src, width * sizeof(GLuint));
186 if (ctx->Pack.SwapBytes) {
187 _mesa_swap4((GLuint *) dest, width);
188 }
189
190 src += width * row + width * height * img;
191 }
192 }
193 }
194
195
196 /**
197 * glGetTexImage for YCbCr pixels.
198 */
199 static void
200 get_tex_ycbcr(GLcontext *ctx, GLuint dimensions,
201 GLenum format, GLenum type, GLvoid *pixels,
202 const struct gl_texture_image *texImage)
203 {
204 const GLint width = texImage->Width;
205 const GLint height = texImage->Height;
206 const GLint depth = texImage->Depth;
207 const GLint rowstride = texImage->RowStride;
208 const GLushort *src = (const GLushort *) texImage->Data;
209 GLint img, row;
210
211 for (img = 0; img < depth; img++) {
212 for (row = 0; row < height; row++) {
213 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
214 width, height, format, type,
215 img, row, 0);
216 _mesa_memcpy(dest, src, width * sizeof(GLushort));
217
218 /* check for byte swapping */
219 if ((texImage->TexFormat == MESA_FORMAT_YCBCR
220 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
221 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
222 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
223 if (!ctx->Pack.SwapBytes)
224 _mesa_swap2((GLushort *) dest, width);
225 }
226 else if (ctx->Pack.SwapBytes) {
227 _mesa_swap2((GLushort *) dest, width);
228 }
229
230 src += rowstride;
231 }
232 }
233 }
234
235
236 /**
237 * glGetTexImagefor sRGB pixels;
238 */
239 static void
240 get_tex_srgb(GLcontext *ctx, GLuint dimensions,
241 GLenum format, GLenum type, GLvoid *pixels,
242 const struct gl_texture_image *texImage)
243 {
244 const GLint width = texImage->Width;
245 const GLint height = texImage->Height;
246 const GLint depth = texImage->Depth;
247 const GLbitfield transferOps = 0x0;
248 GLint img, row;
249
250 for (img = 0; img < depth; img++) {
251 for (row = 0; row < height; row++) {
252 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
253 width, height, format, type,
254 img, row, 0);
255
256 GLfloat rgba[MAX_WIDTH][4];
257 GLint col;
258
259 /* convert row to RGBA format */
260 for (col = 0; col < width; col++) {
261 texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
262 if (texImage->_BaseFormat == GL_LUMINANCE) {
263 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
264 rgba[col][GCOMP] = 0.0;
265 rgba[col][BCOMP] = 0.0;
266 }
267 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
268 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
269 rgba[col][GCOMP] = 0.0;
270 rgba[col][BCOMP] = 0.0;
271 }
272 else if (texImage->_BaseFormat == GL_RGB ||
273 texImage->_BaseFormat == GL_RGBA) {
274 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
275 rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
276 rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
277 }
278 }
279 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
280 format, type, dest,
281 &ctx->Pack, transferOps);
282 }
283 }
284 }
285
286
287 /**
288 * glGetTexImagefor RGBA, Luminance, etc. pixels.
289 * This is the slow way since we use texture sampling.
290 */
291 static void
292 get_tex_rgba(GLcontext *ctx, GLuint dimensions,
293 GLenum format, GLenum type, GLvoid *pixels,
294 const struct gl_texture_image *texImage)
295 {
296 const GLint width = texImage->Width;
297 const GLint height = texImage->Height;
298 const GLint depth = texImage->Depth;
299 /* Normally, no pixel transfer ops are performed during glGetTexImage.
300 * The only possible exception is component clamping to [0,1].
301 */
302 GLbitfield transferOps = 0x0;
303 GLint img, row;
304
305 for (img = 0; img < depth; img++) {
306 for (row = 0; row < height; row++) {
307 void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
308 width, height, format, type,
309 img, row, 0);
310 GLfloat rgba[MAX_WIDTH][4];
311 GLint col;
312 GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat);
313
314 /* clamp does not apply to GetTexImage (final conversion)?
315 * Looks like we need clamp though when going from format
316 * containing negative values to unsigned format.
317 */
318 if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) {
319 transferOps |= IMAGE_CLAMP_BIT;
320 }
321 else if (!type_with_negative_values(type) &&
322 (dataType == GL_FLOAT ||
323 dataType == GL_SIGNED_NORMALIZED)) {
324 transferOps |= IMAGE_CLAMP_BIT;
325 }
326
327 for (col = 0; col < width; col++) {
328 texImage->FetchTexelf(texImage, col, row, img, rgba[col]);
329 if (texImage->_BaseFormat == GL_ALPHA) {
330 rgba[col][RCOMP] = 0.0F;
331 rgba[col][GCOMP] = 0.0F;
332 rgba[col][BCOMP] = 0.0F;
333 }
334 else if (texImage->_BaseFormat == GL_LUMINANCE) {
335 rgba[col][GCOMP] = 0.0F;
336 rgba[col][BCOMP] = 0.0F;
337 rgba[col][ACOMP] = 1.0F;
338 }
339 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
340 rgba[col][GCOMP] = 0.0F;
341 rgba[col][BCOMP] = 0.0F;
342 }
343 else if (texImage->_BaseFormat == GL_INTENSITY) {
344 rgba[col][GCOMP] = 0.0F;
345 rgba[col][BCOMP] = 0.0F;
346 rgba[col][ACOMP] = 1.0F;
347 }
348 }
349 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
350 format, type, dest,
351 &ctx->Pack, transferOps);
352 }
353 }
354 }
355
356
357 /**
358 * Try to do glGetTexImage() with simple memcpy().
359 * \return GL_TRUE if done, GL_FALSE otherwise
360 */
361 static GLboolean
362 get_tex_memcpy(GLcontext *ctx, GLenum format, GLenum type, GLvoid *pixels,
363 const struct gl_texture_object *texObj,
364 const struct gl_texture_image *texImage)
365 {
366 GLboolean memCopy = GL_FALSE;
367
368 /* Texture image should have been mapped already */
369 assert(texImage->Data);
370
371 /*
372 * Check if the src/dst formats are compatible.
373 * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
374 * so we don't have to worry about those.
375 * XXX more format combinations could be supported here.
376 */
377 if ((texObj->Target == GL_TEXTURE_1D ||
378 texObj->Target == GL_TEXTURE_2D ||
379 texObj->Target == GL_TEXTURE_RECTANGLE ||
380 (texObj->Target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
381 texObj->Target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))) {
382 if (texImage->TexFormat == MESA_FORMAT_ARGB8888 &&
383 format == GL_BGRA &&
384 type == GL_UNSIGNED_BYTE &&
385 !ctx->Pack.SwapBytes &&
386 _mesa_little_endian()) {
387 memCopy = GL_TRUE;
388 }
389 else if (texImage->TexFormat == MESA_FORMAT_AL88 &&
390 format == GL_LUMINANCE_ALPHA &&
391 type == GL_UNSIGNED_BYTE &&
392 !ctx->Pack.SwapBytes &&
393 _mesa_little_endian()) {
394 memCopy = GL_TRUE;
395 }
396 else if (texImage->TexFormat == MESA_FORMAT_L8 &&
397 format == GL_LUMINANCE &&
398 type == GL_UNSIGNED_BYTE) {
399 memCopy = GL_TRUE;
400 }
401 else if (texImage->TexFormat == MESA_FORMAT_A8 &&
402 format == GL_ALPHA &&
403 type == GL_UNSIGNED_BYTE) {
404 memCopy = GL_TRUE;
405 }
406 }
407
408 if (memCopy) {
409 const GLuint bpp = _mesa_get_format_bytes(texImage->TexFormat);
410 const GLuint bytesPerRow = texImage->Width * bpp;
411 GLubyte *dst =
412 _mesa_image_address2d(&ctx->Pack, pixels, texImage->Width,
413 texImage->Height, format, type, 0, 0);
414 const GLint dstRowStride =
415 _mesa_image_row_stride(&ctx->Pack, texImage->Width, format, type);
416 const GLubyte *src = texImage->Data;
417 const GLint srcRowStride = texImage->RowStride * bpp;
418 GLuint row;
419
420 if (bytesPerRow == dstRowStride && bytesPerRow == srcRowStride) {
421 memcpy(dst, src, bytesPerRow * texImage->Height);
422 }
423 else {
424 for (row = 0; row < texImage->Height; row++) {
425 memcpy(dst, src, bytesPerRow);
426 dst += dstRowStride;
427 src += srcRowStride;
428 }
429 }
430 }
431
432 return memCopy;
433 }
434
435
436 /**
437 * This is the software fallback for Driver.GetTexImage().
438 * All error checking will have been done before this routine is called.
439 * The texture image must be mapped.
440 */
441 void
442 _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
443 GLenum format, GLenum type, GLvoid *pixels,
444 struct gl_texture_object *texObj,
445 struct gl_texture_image *texImage)
446 {
447 GLuint dimensions;
448
449 /* If we get here, the texture image should be mapped */
450 assert(texImage->Data);
451
452 switch (target) {
453 case GL_TEXTURE_1D:
454 dimensions = 1;
455 break;
456 case GL_TEXTURE_3D:
457 dimensions = 3;
458 break;
459 default:
460 dimensions = 2;
461 }
462
463 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
464 /* Packing texture image into a PBO.
465 * Map the (potentially) VRAM-based buffer into our process space so
466 * we can write into it with the code below.
467 * A hardware driver might use a sophisticated blit to move the
468 * texture data to the PBO if the PBO is in VRAM along with the texture.
469 */
470 GLubyte *buf = (GLubyte *)
471 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
472 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
473 if (!buf) {
474 /* out of memory or other unexpected error */
475 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage(map PBO failed)");
476 return;
477 }
478 /* <pixels> was an offset into the PBO.
479 * Now make it a real, client-side pointer inside the mapped region.
480 */
481 pixels = ADD_POINTERS(buf, pixels);
482 }
483
484 if (get_tex_memcpy(ctx, format, type, pixels, texObj, texImage)) {
485 /* all done */
486 }
487 else if (format == GL_COLOR_INDEX) {
488 get_tex_color_index(ctx, dimensions, format, type, pixels, texImage);
489 }
490 else if (format == GL_DEPTH_COMPONENT) {
491 get_tex_depth(ctx, dimensions, format, type, pixels, texImage);
492 }
493 else if (format == GL_DEPTH_STENCIL_EXT) {
494 get_tex_depth_stencil(ctx, dimensions, format, type, pixels, texImage);
495 }
496 else if (format == GL_YCBCR_MESA) {
497 get_tex_ycbcr(ctx, dimensions, format, type, pixels, texImage);
498 }
499 else if (_mesa_get_format_color_encoding(texImage->TexFormat) == GL_SRGB) {
500 get_tex_srgb(ctx, dimensions, format, type, pixels, texImage);
501 }
502 else {
503 get_tex_rgba(ctx, dimensions, format, type, pixels, texImage);
504 }
505
506 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
507 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
508 ctx->Pack.BufferObj);
509 }
510 }
511
512
513
514 /**
515 * This is the software fallback for Driver.GetCompressedTexImage().
516 * All error checking will have been done before this routine is called.
517 */
518 void
519 _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
520 GLvoid *img,
521 struct gl_texture_object *texObj,
522 struct gl_texture_image *texImage)
523 {
524 const GLuint row_stride = _mesa_format_row_stride(texImage->TexFormat,
525 texImage->Width);
526 const GLuint row_stride_stored = _mesa_format_row_stride(texImage->TexFormat,
527 texImage->RowStride);
528 GLuint i;
529
530 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
531 /* pack texture image into a PBO */
532 GLubyte *buf = (GLubyte *)
533 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
534 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
535 if (!buf) {
536 /* out of memory or other unexpected error */
537 _mesa_error(ctx, GL_OUT_OF_MEMORY,
538 "glGetCompresssedTexImage(map PBO failed)");
539 return;
540 }
541 img = ADD_POINTERS(buf, img);
542 }
543
544 /* no pixelstore or pixel transfer, but respect stride */
545
546 if (row_stride == row_stride_stored) {
547 const GLuint size = _mesa_format_image_size(texImage->TexFormat,
548 texImage->Width,
549 texImage->Height,
550 texImage->Depth);
551 _mesa_memcpy(img, texImage->Data, size);
552 }
553 else {
554 GLuint bw, bh;
555 _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
556 for (i = 0; i < (texImage->Height + bh - 1) / bh; i++) {
557 memcpy((GLubyte *)img + i * row_stride,
558 (GLubyte *)texImage->Data + i * row_stride_stored,
559 row_stride);
560 }
561 }
562
563 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
564 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
565 ctx->Pack.BufferObj);
566 }
567 }
568
569
570
571 /**
572 * Do error checking for a glGetTexImage() call.
573 * \return GL_TRUE if any error, GL_FALSE if no errors.
574 */
575 static GLboolean
576 getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
577 GLenum format, GLenum type, GLvoid *pixels )
578 {
579 struct gl_texture_object *texObj;
580 struct gl_texture_image *texImage;
581 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
582 GLenum baseFormat;
583
584 if (maxLevels == 0) {
585 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
586 return GL_TRUE;
587 }
588
589 if (level < 0 || level >= maxLevels) {
590 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
591 return GL_TRUE;
592 }
593
594 if (_mesa_sizeof_packed_type(type) <= 0) {
595 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
596 return GL_TRUE;
597 }
598
599 if (_mesa_components_in_format(format) <= 0 ||
600 format == GL_STENCIL_INDEX) {
601 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
602 return GL_TRUE;
603 }
604
605 if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
606 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
607 return GL_TRUE;
608 }
609
610 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
611 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
612 return GL_TRUE;
613 }
614
615 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
616 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
617 return GL_TRUE;
618 }
619
620 if (!ctx->Extensions.EXT_packed_depth_stencil
621 && _mesa_is_depthstencil_format(format)) {
622 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
623 return GL_TRUE;
624 }
625
626 if (!ctx->Extensions.ATI_envmap_bumpmap
627 && _mesa_is_dudv_format(format)) {
628 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
629 return GL_TRUE;
630 }
631
632 texObj = _mesa_get_current_tex_object(ctx, target);
633
634 if (!texObj || _mesa_is_proxy_texture(target)) {
635 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
636 return GL_TRUE;
637 }
638
639 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
640 if (!texImage) {
641 /* out of memory */
642 return GL_TRUE;
643 }
644
645 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
646
647 /* Make sure the requested image format is compatible with the
648 * texture's format. Note that a color index texture can be converted
649 * to RGBA so that combo is allowed.
650 */
651 if (_mesa_is_color_format(format)
652 && !_mesa_is_color_format(baseFormat)
653 && !_mesa_is_index_format(baseFormat)) {
654 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
655 return GL_TRUE;
656 }
657 else if (_mesa_is_index_format(format)
658 && !_mesa_is_index_format(baseFormat)) {
659 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
660 return GL_TRUE;
661 }
662 else if (_mesa_is_depth_format(format)
663 && !_mesa_is_depth_format(baseFormat)
664 && !_mesa_is_depthstencil_format(baseFormat)) {
665 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
666 return GL_TRUE;
667 }
668 else if (_mesa_is_ycbcr_format(format)
669 && !_mesa_is_ycbcr_format(baseFormat)) {
670 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
671 return GL_TRUE;
672 }
673 else if (_mesa_is_depthstencil_format(format)
674 && !_mesa_is_depthstencil_format(baseFormat)) {
675 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
676 return GL_TRUE;
677 }
678 else if (_mesa_is_dudv_format(format)
679 && !_mesa_is_dudv_format(baseFormat)) {
680 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
681 return GL_TRUE;
682 }
683
684 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
685 /* packing texture image into a PBO */
686 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
687 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
688 texImage->Height, texImage->Depth,
689 format, type, pixels)) {
690 _mesa_error(ctx, GL_INVALID_OPERATION,
691 "glGetTexImage(out of bounds PBO write)");
692 return GL_TRUE;
693 }
694
695 /* PBO should not be mapped */
696 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
697 _mesa_error(ctx, GL_INVALID_OPERATION,
698 "glGetTexImage(PBO is mapped)");
699 return GL_TRUE;
700 }
701 }
702
703 return GL_FALSE;
704 }
705
706
707
708 /**
709 * Get texture image. Called by glGetTexImage.
710 *
711 * \param target texture target.
712 * \param level image level.
713 * \param format pixel data format for returned image.
714 * \param type pixel data type for returned image.
715 * \param pixels returned pixel data.
716 */
717 void GLAPIENTRY
718 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
719 GLenum type, GLvoid *pixels )
720 {
721 struct gl_texture_object *texObj;
722 struct gl_texture_image *texImage;
723 GET_CURRENT_CONTEXT(ctx);
724 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
725
726 if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
727 return;
728 }
729
730 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
731 /* not an error, do nothing */
732 return;
733 }
734
735 texObj = _mesa_get_current_tex_object(ctx, target);
736 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
737
738 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
739 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
740 " dstFmt=0x%x, dstType=0x%x\n",
741 texObj->Name,
742 _mesa_get_format_name(texImage->TexFormat),
743 texImage->Width, texImage->Height,
744 format, type);
745 }
746
747 _mesa_lock_texture(ctx, texObj);
748 {
749 ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
750 texObj, texImage);
751 }
752 _mesa_unlock_texture(ctx, texObj);
753 }
754
755
756
757 /**
758 * Do error checking for a glGetCompressedTexImage() call.
759 * \return GL_TRUE if any error, GL_FALSE if no errors.
760 */
761 static GLboolean
762 getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
763 GLvoid *img)
764 {
765 struct gl_texture_object *texObj;
766 struct gl_texture_image *texImage;
767 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
768
769 if (maxLevels == 0) {
770 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
771 target);
772 return GL_TRUE;
773 }
774
775 if (level < 0 || level >= maxLevels) {
776 _mesa_error(ctx, GL_INVALID_VALUE,
777 "glGetCompressedTexImageARB(bad level = %d)", level);
778 return GL_TRUE;
779 }
780
781 if (_mesa_is_proxy_texture(target)) {
782 _mesa_error(ctx, GL_INVALID_ENUM,
783 "glGetCompressedTexImageARB(bad target = %s)",
784 _mesa_lookup_enum_by_nr(target));
785 return GL_TRUE;
786 }
787
788 texObj = _mesa_get_current_tex_object(ctx, target);
789 if (!texObj) {
790 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
791 return GL_TRUE;
792 }
793
794 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
795
796 if (!texImage) {
797 /* probably invalid mipmap level */
798 _mesa_error(ctx, GL_INVALID_VALUE,
799 "glGetCompressedTexImageARB(level)");
800 return GL_TRUE;
801 }
802
803 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
804 _mesa_error(ctx, GL_INVALID_OPERATION,
805 "glGetCompressedTexImageARB(texture is not compressed)");
806 return GL_TRUE;
807 }
808
809 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
810 GLuint compressedSize;
811
812 /* make sure PBO is not mapped */
813 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
814 _mesa_error(ctx, GL_INVALID_OPERATION,
815 "glGetCompressedTexImage(PBO is mapped)");
816 return GL_TRUE;
817 }
818
819 compressedSize = _mesa_format_image_size(texImage->TexFormat,
820 texImage->Width,
821 texImage->Height,
822 texImage->Depth);
823
824 /* do bounds checking on PBO write */
825 if ((const GLubyte *) img + compressedSize >
826 (const GLubyte *) ctx->Pack.BufferObj->Size) {
827 _mesa_error(ctx, GL_INVALID_OPERATION,
828 "glGetCompressedTexImage(out of bounds PBO write)");
829 return GL_TRUE;
830 }
831 }
832
833 return GL_FALSE;
834 }
835
836
837 void GLAPIENTRY
838 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
839 {
840 struct gl_texture_object *texObj;
841 struct gl_texture_image *texImage;
842 GET_CURRENT_CONTEXT(ctx);
843 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
844
845 if (getcompressedteximage_error_check(ctx, target, level, img)) {
846 return;
847 }
848
849 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
850 /* not an error, do nothing */
851 return;
852 }
853
854 texObj = _mesa_get_current_tex_object(ctx, target);
855 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
856
857 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
858 _mesa_debug(ctx,
859 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
860 texObj->Name,
861 _mesa_get_format_name(texImage->TexFormat),
862 texImage->Width, texImage->Height);
863 }
864
865 _mesa_lock_texture(ctx, texObj);
866 {
867 ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
868 texObj, texImage);
869 }
870 _mesa_unlock_texture(ctx, texObj);
871 }