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