3e3951b1c494bb1e0e70088fb0af28587d3576d8
[mesa.git] / src / mesa / main / texgetimage.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.5
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 "context.h"
35 #include "image.h"
36 #include "texcompress.h"
37 #include "texformat.h"
38 #include "texgetimage.h"
39 #include "teximage.h"
40 #include "texstate.h"
41
42
43
44 #if FEATURE_EXT_texture_sRGB
45
46 /**
47 * Test if given texture image is an sRGB format.
48 */
49 static GLboolean
50 is_srgb_teximage(const struct gl_texture_image *texImage)
51 {
52 switch (texImage->TexFormat) {
53 case MESA_FORMAT_SRGB8:
54 case MESA_FORMAT_SRGBA8:
55 case MESA_FORMAT_SARGB8:
56 case MESA_FORMAT_SL8:
57 case MESA_FORMAT_SLA8:
58 case MESA_FORMAT_SRGB_DXT1:
59 case MESA_FORMAT_SRGBA_DXT1:
60 case MESA_FORMAT_SRGBA_DXT3:
61 case MESA_FORMAT_SRGBA_DXT5:
62 return GL_TRUE;
63 default:
64 return GL_FALSE;
65 }
66 }
67
68
69 /**
70 * Convert a float value from linear space to a
71 * non-linear sRGB value in [0, 255].
72 * Not terribly efficient.
73 */
74 static INLINE GLfloat
75 linear_to_nonlinear(GLfloat cl)
76 {
77 /* can't have values outside [0, 1] */
78 GLfloat cs;
79 if (cl < 0.0031308f) {
80 cs = 12.92f * cl;
81 }
82 else {
83 cs = (GLfloat)(1.055 * _mesa_pow(cl, 0.41666) - 0.055);
84 }
85 return cs;
86 }
87
88 #endif /* FEATURE_EXT_texture_sRGB */
89
90
91 /**
92 * Can the given type represent negative values?
93 */
94 static INLINE GLboolean
95 type_with_negative_values(GLenum type)
96 {
97 switch (type) {
98 case GL_BYTE:
99 case GL_SHORT:
100 case GL_INT:
101 case GL_FLOAT:
102 case GL_HALF_FLOAT_ARB:
103 return GL_TRUE;
104 default:
105 return GL_FALSE;
106 }
107 }
108
109
110 /**
111 * This is the software fallback for Driver.GetTexImage().
112 * All error checking will have been done before this routine is called.
113 */
114 void
115 _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level,
116 GLenum format, GLenum type, GLvoid *pixels,
117 struct gl_texture_object *texObj,
118 struct gl_texture_image *texImage)
119 {
120 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
121
122 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
123 /* Packing texture image into a PBO.
124 * Map the (potentially) VRAM-based buffer into our process space so
125 * we can write into it with the code below.
126 * A hardware driver might use a sophisticated blit to move the
127 * texture data to the PBO if the PBO is in VRAM along with the texture.
128 */
129 GLubyte *buf = (GLubyte *)
130 ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
131 GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj);
132 if (!buf) {
133 /* buffer is already mapped - that's an error */
134 _mesa_error(ctx, GL_INVALID_OPERATION,"glGetTexImage(PBO is mapped)");
135 return;
136 }
137 /* <pixels> was an offset into the PBO.
138 * Now make it a real, client-side pointer inside the mapped region.
139 */
140 pixels = ADD_POINTERS(buf, pixels);
141 }
142 else if (!pixels) {
143 /* not an error */
144 return;
145 }
146
147 {
148 const GLint width = texImage->Width;
149 const GLint height = texImage->Height;
150 const GLint depth = texImage->Depth;
151 GLint img, row;
152 for (img = 0; img < depth; img++) {
153 for (row = 0; row < height; row++) {
154 /* compute destination address in client memory */
155 GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels,
156 width, height, format, type,
157 img, row, 0);
158 assert(dest);
159
160 if (format == GL_COLOR_INDEX) {
161 GLuint indexRow[MAX_WIDTH];
162 GLint col;
163 GLuint indexBits = _mesa_get_format_bits(texImage->TexFormat, GL_TEXTURE_INDEX_SIZE_EXT);
164 /* Can't use FetchTexel here because that returns RGBA */
165 if (indexBits == 8) {
166 const GLubyte *src = (const GLubyte *) texImage->Data;
167 src += width * (img * texImage->Height + row);
168 for (col = 0; col < width; col++) {
169 indexRow[col] = src[col];
170 }
171 }
172 else if (indexBits == 16) {
173 const GLushort *src = (const GLushort *) texImage->Data;
174 src += width * (img * texImage->Height + row);
175 for (col = 0; col < width; col++) {
176 indexRow[col] = src[col];
177 }
178 }
179 else {
180 _mesa_problem(ctx,
181 "Color index problem in _mesa_GetTexImage");
182 }
183 _mesa_pack_index_span(ctx, width, type, dest,
184 indexRow, &ctx->Pack,
185 0 /* no image transfer */);
186 }
187 else if (format == GL_DEPTH_COMPONENT) {
188 GLfloat depthRow[MAX_WIDTH];
189 GLint col;
190 for (col = 0; col < width; col++) {
191 (*texImage->FetchTexelf)(texImage, col, row, img,
192 depthRow + col);
193 }
194 _mesa_pack_depth_span(ctx, width, dest, type,
195 depthRow, &ctx->Pack);
196 }
197 else if (format == GL_DEPTH_STENCIL_EXT) {
198 /* XXX Note: we're bypassing texImage->FetchTexel()! */
199 const GLuint *src = (const GLuint *) texImage->Data;
200 src += width * row + width * height * img;
201 _mesa_memcpy(dest, src, width * sizeof(GLuint));
202 if (ctx->Pack.SwapBytes) {
203 _mesa_swap4((GLuint *) dest, width);
204 }
205 }
206 else if (format == GL_YCBCR_MESA) {
207 /* No pixel transfer */
208 const GLint rowstride = texImage->RowStride;
209 MEMCPY(dest,
210 (const GLushort *) texImage->Data + row * rowstride,
211 width * sizeof(GLushort));
212 /* check for byte swapping */
213 if ((texImage->TexFormat == MESA_FORMAT_YCBCR
214 && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) ||
215 (texImage->TexFormat == MESA_FORMAT_YCBCR_REV
216 && type == GL_UNSIGNED_SHORT_8_8_MESA)) {
217 if (!ctx->Pack.SwapBytes)
218 _mesa_swap2((GLushort *) dest, width);
219 }
220 else if (ctx->Pack.SwapBytes) {
221 _mesa_swap2((GLushort *) dest, width);
222 }
223 }
224 #if FEATURE_EXT_texture_sRGB
225 else if (is_srgb_teximage(texImage)) {
226 /* special case this since need to backconvert values */
227 /* convert row to RGBA format */
228 GLfloat rgba[MAX_WIDTH][4];
229 GLint col;
230 GLbitfield transferOps = 0x0;
231
232 for (col = 0; col < width; col++) {
233 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
234 if (texImage->_BaseFormat == GL_LUMINANCE) {
235 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
236 rgba[col][GCOMP] = 0.0;
237 rgba[col][BCOMP] = 0.0;
238 }
239 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
240 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
241 rgba[col][GCOMP] = 0.0;
242 rgba[col][BCOMP] = 0.0;
243 }
244 else if (texImage->_BaseFormat == GL_RGB ||
245 texImage->_BaseFormat == GL_RGBA) {
246 rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]);
247 rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]);
248 rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]);
249 }
250 }
251 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
252 format, type, dest,
253 &ctx->Pack, transferOps);
254 }
255 #endif /* FEATURE_EXT_texture_sRGB */
256 else {
257 /* general case: convert row to RGBA format */
258 GLfloat rgba[MAX_WIDTH][4];
259 GLint col;
260 GLbitfield transferOps = 0x0;
261 GLenum dataType =
262 _mesa_get_format_datatype(texImage->TexFormat);
263
264 /* clamp does not apply to GetTexImage (final conversion)?
265 * Looks like we need clamp though when going from format
266 * containing negative values to unsigned format.
267 */
268 if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA)
269 transferOps |= IMAGE_CLAMP_BIT;
270 else if (!type_with_negative_values(type) &&
271 (dataType == GL_FLOAT ||
272 dataType == GL_SIGNED_NORMALIZED))
273 transferOps |= IMAGE_CLAMP_BIT;
274
275 for (col = 0; col < width; col++) {
276 (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]);
277 if (texImage->_BaseFormat == GL_ALPHA) {
278 rgba[col][RCOMP] = 0.0;
279 rgba[col][GCOMP] = 0.0;
280 rgba[col][BCOMP] = 0.0;
281 }
282 else if (texImage->_BaseFormat == GL_LUMINANCE) {
283 rgba[col][GCOMP] = 0.0;
284 rgba[col][BCOMP] = 0.0;
285 rgba[col][ACOMP] = 1.0;
286 }
287 else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) {
288 rgba[col][GCOMP] = 0.0;
289 rgba[col][BCOMP] = 0.0;
290 }
291 else if (texImage->_BaseFormat == GL_INTENSITY) {
292 rgba[col][GCOMP] = 0.0;
293 rgba[col][BCOMP] = 0.0;
294 rgba[col][ACOMP] = 1.0;
295 }
296 }
297 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba,
298 format, type, dest,
299 &ctx->Pack, transferOps);
300 } /* format */
301 } /* row */
302 } /* img */
303 }
304
305 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
306 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
307 ctx->Pack.BufferObj);
308 }
309 }
310
311
312
313 /**
314 * This is the software fallback for Driver.GetCompressedTexImage().
315 * All error checking will have been done before this routine is called.
316 */
317 void
318 _mesa_get_compressed_teximage(GLcontext *ctx, GLenum target, GLint level,
319 GLvoid *img,
320 struct gl_texture_object *texObj,
321 struct gl_texture_image *texImage)
322 {
323 GLuint size;
324
325 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
326 /* pack texture image into a PBO */
327 GLubyte *buf;
328 if ((const GLubyte *) img + texImage->CompressedSize >
329 (const GLubyte *) ctx->Pack.BufferObj->Size) {
330 _mesa_error(ctx, GL_INVALID_OPERATION,
331 "glGetCompressedTexImage(invalid PBO access)");
332 return;
333 }
334 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
335 GL_WRITE_ONLY_ARB,
336 ctx->Pack.BufferObj);
337 if (!buf) {
338 /* buffer is already mapped - that's an error */
339 _mesa_error(ctx, GL_INVALID_OPERATION,
340 "glGetCompressedTexImage(PBO is mapped)");
341 return;
342 }
343 img = ADD_POINTERS(buf, img);
344 }
345 else if (!img) {
346 /* not an error */
347 return;
348 }
349
350 /* don't use texImage->CompressedSize since that may be padded out */
351 size = _mesa_compressed_texture_size(ctx, texImage->Width, texImage->Height,
352 texImage->Depth,
353 texImage->TexFormat);
354
355 /* just memcpy, no pixelstore or pixel transfer */
356 _mesa_memcpy(img, texImage->Data, size);
357
358 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
359 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
360 ctx->Pack.BufferObj);
361 }
362 }
363
364
365
366 /**
367 * Do error checking for a glGetTexImage() call.
368 * \return GL_TRUE if any error, GL_FALSE if no errors.
369 */
370 static GLboolean
371 getteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
372 GLenum format, GLenum type, GLvoid *pixels )
373 {
374 const struct gl_texture_unit *texUnit;
375 struct gl_texture_object *texObj;
376 struct gl_texture_image *texImage;
377 const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);
378 GLenum baseFormat;
379
380 if (maxLevels == 0) {
381 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
382 return GL_TRUE;
383 }
384
385 if (level < 0 || level >= maxLevels) {
386 _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
387 return GL_TRUE;
388 }
389
390 if (_mesa_sizeof_packed_type(type) <= 0) {
391 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
392 return GL_TRUE;
393 }
394
395 if (_mesa_components_in_format(format) <= 0 ||
396 format == GL_STENCIL_INDEX) {
397 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
398 return GL_TRUE;
399 }
400
401 if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) {
402 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
403 return GL_TRUE;
404 }
405
406 if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) {
407 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
408 return GL_TRUE;
409 }
410
411 if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) {
412 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
413 return GL_TRUE;
414 }
415
416 if (!ctx->Extensions.EXT_packed_depth_stencil
417 && _mesa_is_depthstencil_format(format)) {
418 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
419 return GL_TRUE;
420 }
421
422 if (!ctx->Extensions.ATI_envmap_bumpmap
423 && _mesa_is_dudv_format(format)) {
424 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
425 return GL_TRUE;
426 }
427
428 texUnit = _mesa_get_current_tex_unit(ctx);
429 texObj = _mesa_select_tex_object(ctx, texUnit, target);
430
431 if (!texObj || _mesa_is_proxy_texture(target)) {
432 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
433 return GL_TRUE;
434 }
435
436 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
437 if (!texImage) {
438 /* out of memory */
439 return GL_TRUE;
440 }
441
442 baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
443
444 /* Make sure the requested image format is compatible with the
445 * texture's format. Note that a color index texture can be converted
446 * to RGBA so that combo is allowed.
447 */
448 if (_mesa_is_color_format(format)
449 && !_mesa_is_color_format(baseFormat)
450 && !_mesa_is_index_format(baseFormat)) {
451 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
452 return GL_TRUE;
453 }
454 else if (_mesa_is_index_format(format)
455 && !_mesa_is_index_format(baseFormat)) {
456 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
457 return GL_TRUE;
458 }
459 else if (_mesa_is_depth_format(format)
460 && !_mesa_is_depth_format(baseFormat)
461 && !_mesa_is_depthstencil_format(baseFormat)) {
462 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
463 return GL_TRUE;
464 }
465 else if (_mesa_is_ycbcr_format(format)
466 && !_mesa_is_ycbcr_format(baseFormat)) {
467 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
468 return GL_TRUE;
469 }
470 else if (_mesa_is_depthstencil_format(format)
471 && !_mesa_is_depthstencil_format(baseFormat)) {
472 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
473 return GL_TRUE;
474 }
475 else if (_mesa_is_dudv_format(format)
476 && !_mesa_is_dudv_format(baseFormat)) {
477 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
478 return GL_TRUE;
479 }
480
481 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
482 /* packing texture image into a PBO */
483 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
484 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
485 texImage->Height, texImage->Depth,
486 format, type, pixels)) {
487 _mesa_error(ctx, GL_INVALID_OPERATION,
488 "glGetTexImage(invalid PBO access)");
489 return GL_TRUE;
490 }
491 }
492
493 return GL_FALSE;
494 }
495
496
497
498 /**
499 * Get texture image. Called by glGetTexImage.
500 *
501 * \param target texture target.
502 * \param level image level.
503 * \param format pixel data format for returned image.
504 * \param type pixel data type for returned image.
505 * \param pixels returned pixel data.
506 */
507 void GLAPIENTRY
508 _mesa_GetTexImage( GLenum target, GLint level, GLenum format,
509 GLenum type, GLvoid *pixels )
510 {
511 const struct gl_texture_unit *texUnit;
512 struct gl_texture_object *texObj;
513 GET_CURRENT_CONTEXT(ctx);
514 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
515
516 if (getteximage_error_check(ctx, target, level, format, type, pixels)) {
517 return;
518 }
519
520 texUnit = _mesa_get_current_tex_unit(ctx);
521 texObj = _mesa_select_tex_object(ctx, texUnit, target);
522
523 _mesa_lock_texture(ctx, texObj);
524 {
525 struct gl_texture_image *texImage =
526 _mesa_select_tex_image(ctx, texObj, target, level);
527
528 /* typically, this will call _mesa_get_teximage() */
529 ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
530 texObj, texImage);
531 }
532 _mesa_unlock_texture(ctx, texObj);
533 }
534
535
536 void GLAPIENTRY
537 _mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
538 {
539 const struct gl_texture_unit *texUnit;
540 struct gl_texture_object *texObj;
541 struct gl_texture_image *texImage;
542 GLint maxLevels;
543 GET_CURRENT_CONTEXT(ctx);
544 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
545
546 texUnit = _mesa_get_current_tex_unit(ctx);
547 texObj = _mesa_select_tex_object(ctx, texUnit, target);
548 if (!texObj) {
549 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB");
550 return;
551 }
552
553 maxLevels = _mesa_max_texture_levels(ctx, target);
554 ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */
555
556 if (level < 0 || level >= maxLevels) {
557 _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
558 return;
559 }
560
561 if (_mesa_is_proxy_texture(target)) {
562 _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
563 return;
564 }
565
566 _mesa_lock_texture(ctx, texObj);
567 {
568 texImage = _mesa_select_tex_image(ctx, texObj, target, level);
569 if (texImage) {
570 if (_mesa_is_format_compressed(texImage->TexFormat)) {
571 /* this typically calls _mesa_get_compressed_teximage() */
572 ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
573 texObj, texImage);
574 }
575 else {
576 _mesa_error(ctx, GL_INVALID_OPERATION,
577 "glGetCompressedTexImageARB");
578 }
579 }
580 else {
581 /* probably invalid mipmap level */
582 _mesa_error(ctx, GL_INVALID_VALUE,
583 "glGetCompressedTexImageARB(level)");
584 }
585 }
586 _mesa_unlock_texture(ctx, texObj);
587 }