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