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