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