mesa: use _mesa_get_current_tex_object()
[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];
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 size = _mesa_format_image_size(texImage->TexFormat,
525 texImage->Width,
526 texImage->Height,
527 texImage->Depth);
528
529 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
530 /* pack texture image into a PBO */
531 GLubyte *buf = (GLubyte *)
532 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
533 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
534 if (!buf) {
535 /* out of memory or other unexpected error */
536 _mesa_error(ctx, GL_OUT_OF_MEMORY,
537 "glGetCompresssedTexImage(map PBO failed)");
538 return;
539 }
540 img = ADD_POINTERS(buf, img);
541 }
542
543 /* just memcpy, no pixelstore or pixel transfer */
544 _mesa_memcpy(img, texImage->Data, size);
545
546 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
547 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
548 ctx->Pack.BufferObj);
549 }
550 }
551
552
553
554 /**
555 * Do error checking for a glGetTexImage() call.
556 * \return GL_TRUE if any error, GL_FALSE if no errors.
557 */
558 static GLboolean
559 getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
560 GLenum format, GLenum type, GLvoid *pixels )
561 {
562 struct gl_texture_object *texObj;
563 struct gl_texture_image *texImage;
564 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
565 GLenum baseFormat;
566
567 if (maxLevels == 0) {
568 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
569 return GL_TRUE;
570 }
571
572 if (level < 0 || level >= maxLevels) {
573 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
574 return GL_TRUE;
575 }
576
577 if (_mesa_sizeof_packed_type(type) <= 0) {
578 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
579 return GL_TRUE;
580 }
581
582 if (_mesa_components_in_format(format) <= 0 ||
583 format == GL_STENCIL_INDEX) {
584 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
585 return GL_TRUE;
586 }
587
588 if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
589 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
590 return GL_TRUE;
591 }
592
593 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
594 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
595 return GL_TRUE;
596 }
597
598 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
599 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
600 return GL_TRUE;
601 }
602
603 if (!ctx->Extensions.EXT_packed_depth_stencil
604 && _mesa_is_depthstencil_format(format)) {
605 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
606 return GL_TRUE;
607 }
608
609 if (!ctx->Extensions.ATI_envmap_bumpmap
610 && _mesa_is_dudv_format(format)) {
611 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
612 return GL_TRUE;
613 }
614
615 texObj = _mesa_get_current_tex_object(ctx, target);
616
617 if (!texObj || _mesa_is_proxy_texture(target)) {
618 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
619 return GL_TRUE;
620 }
621
622 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
623 if (!texImage) {
624 /* out of memory */
625 return GL_TRUE;
626 }
627
628 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
629
630 /* Make sure the requested image format is compatible with the
631 * texture's format. Note that a color index texture can be converted
632 * to RGBA so that combo is allowed.
633 */
634 if (_mesa_is_color_format(format)
635 && !_mesa_is_color_format(baseFormat)
636 && !_mesa_is_index_format(baseFormat)) {
637 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
638 return GL_TRUE;
639 }
640 else if (_mesa_is_index_format(format)
641 && !_mesa_is_index_format(baseFormat)) {
642 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
643 return GL_TRUE;
644 }
645 else if (_mesa_is_depth_format(format)
646 && !_mesa_is_depth_format(baseFormat)
647 && !_mesa_is_depthstencil_format(baseFormat)) {
648 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
649 return GL_TRUE;
650 }
651 else if (_mesa_is_ycbcr_format(format)
652 && !_mesa_is_ycbcr_format(baseFormat)) {
653 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
654 return GL_TRUE;
655 }
656 else if (_mesa_is_depthstencil_format(format)
657 && !_mesa_is_depthstencil_format(baseFormat)) {
658 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
659 return GL_TRUE;
660 }
661 else if (_mesa_is_dudv_format(format)
662 && !_mesa_is_dudv_format(baseFormat)) {
663 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
664 return GL_TRUE;
665 }
666
667 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
668 /* packing texture image into a PBO */
669 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
670 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
671 texImage->Height, texImage->Depth,
672 format, type, pixels)) {
673 _mesa_error(ctx, GL_INVALID_OPERATION,
674 "glGetTexImage(out of bounds PBO write)");
675 return GL_TRUE;
676 }
677
678 /* PBO should not be mapped */
679 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
680 _mesa_error(ctx, GL_INVALID_OPERATION,
681 "glGetTexImage(PBO is mapped)");
682 return GL_TRUE;
683 }
684 }
685
686 return GL_FALSE;
687 }
688
689
690
691 /**
692 * Get texture image. Called by glGetTexImage.
693 *
694 * \param target texture target.
695 * \param level image level.
696 * \param format pixel data format for returned image.
697 * \param type pixel data type for returned image.
698 * \param pixels returned pixel data.
699 */
700 void GLAPIENTRY
701 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
702 GLenum type, GLvoid *pixels )
703 {
704 struct gl_texture_object *texObj;
705 struct gl_texture_image *texImage;
706 GET_CURRENT_CONTEXT(ctx);
707 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
708
709 if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
710 return;
711 }
712
713 if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
714 /* not an error, do nothing */
715 return;
716 }
717
718 texObj = _mesa_get_current_tex_object(ctx, target);
719 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
720
721 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
722 _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
723 " dstFmt=0x%x, dstType=0x%x\n",
724 texObj->Name,
725 _mesa_get_format_name(texImage->TexFormat),
726 texImage->Width, texImage->Height,
727 format, type);
728 }
729
730 _mesa_lock_texture(ctx, texObj);
731 {
732 ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
733 texObj, texImage);
734 }
735 _mesa_unlock_texture(ctx, texObj);
736 }
737
738
739
740 /**
741 * Do error checking for a glGetCompressedTexImage() call.
742 * \return GL_TRUE if any error, GL_FALSE if no errors.
743 */
744 static GLboolean
745 getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
746 GLvoid *img)
747 {
748 struct gl_texture_object *texObj;
749 struct gl_texture_image *texImage;
750 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
751
752 if (maxLevels == 0) {
753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
754 target);
755 return GL_TRUE;
756 }
757
758 if (level < 0 || level >= maxLevels) {
759 _mesa_error(ctx, GL_INVALID_VALUE,
760 "glGetCompressedTexImageARB(bad level = %d)", level);
761 return GL_TRUE;
762 }
763
764 if (_mesa_is_proxy_texture(target)) {
765 _mesa_error(ctx, GL_INVALID_ENUM,
766 "glGetCompressedTexImageARB(bad target = %s)",
767 _mesa_lookup_enum_by_nr(target));
768 return GL_TRUE;
769 }
770
771 texObj = _mesa_get_current_tex_object(ctx, target);
772 if (!texObj) {
773 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
774 return GL_TRUE;
775 }
776
777 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
778
779 if (!texImage) {
780 /* probably invalid mipmap level */
781 _mesa_error(ctx, GL_INVALID_VALUE,
782 "glGetCompressedTexImageARB(level)");
783 return GL_TRUE;
784 }
785
786 if (!_mesa_is_format_compressed(texImage->TexFormat)) {
787 _mesa_error(ctx, GL_INVALID_OPERATION,
788 "glGetCompressedTexImageARB(texture is not compressed)");
789 return GL_TRUE;
790 }
791
792 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
793 GLuint compressedSize;
794
795 /* make sure PBO is not mapped */
796 if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
797 _mesa_error(ctx, GL_INVALID_OPERATION,
798 "glGetCompressedTexImage(PBO is mapped)");
799 return GL_TRUE;
800 }
801
802 compressedSize = _mesa_format_image_size(texImage->TexFormat,
803 texImage->Width,
804 texImage->Height,
805 texImage->Depth);
806
807 /* do bounds checking on PBO write */
808 if ((const GLubyte *) img + compressedSize >
809 (const GLubyte *) ctx->Pack.BufferObj->Size) {
810 _mesa_error(ctx, GL_INVALID_OPERATION,
811 "glGetCompressedTexImage(out of bounds PBO write)");
812 return GL_TRUE;
813 }
814 }
815
816 return GL_FALSE;
817 }
818
819
820 void GLAPIENTRY
821 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
822 {
823 struct gl_texture_object *texObj;
824 struct gl_texture_image *texImage;
825 GET_CURRENT_CONTEXT(ctx);
826 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
827
828 if (getcompressedteximage_error_check(ctx, target, level, img)) {
829 return;
830 }
831
832 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
833 /* not an error, do nothing */
834 return;
835 }
836
837 texObj = _mesa_get_current_tex_object(ctx, target);
838 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
839
840 if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
841 _mesa_debug(ctx,
842 "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
843 texObj->Name,
844 _mesa_get_format_name(texImage->TexFormat),
845 texImage->Width, texImage->Height);
846 }
847
848 _mesa_lock_texture(ctx, texObj);
849 {
850 ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
851 texObj, texImage);
852 }
853 _mesa_unlock_texture(ctx, texObj);
854 }