2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (c) 2009 VMware, Inc.
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
28 * Code for glGetTexImage() and glGetCompressedTexImage().
33 #include "bufferobj.h"
36 #include "texcompress.h"
37 #include "texformat.h"
38 #include "texgetimage.h"
44 #if FEATURE_EXT_texture_sRGB
47 * Test if given texture image is an sRGB format.
50 is_srgb_teximage(const struct gl_texture_image
*texImage
)
52 switch (texImage
->TexFormat
) {
53 case MESA_FORMAT_SRGB8
:
54 case MESA_FORMAT_SRGBA8
:
55 case MESA_FORMAT_SARGB8
:
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
:
70 * Convert a float value from linear space to a
71 * non-linear sRGB value in [0, 255].
72 * Not terribly efficient.
75 linear_to_nonlinear(GLfloat cl
)
77 /* can't have values outside [0, 1] */
79 if (cl
< 0.0031308f
) {
83 cs
= (GLfloat
)(1.055 * _mesa_pow(cl
, 0.41666) - 0.055);
88 #endif /* FEATURE_EXT_texture_sRGB */
92 * Can the given type represent negative values?
94 static INLINE GLboolean
95 type_with_negative_values(GLenum type
)
102 case GL_HALF_FLOAT_ARB
:
111 * This is the software fallback for Driver.GetTexImage().
112 * All error checking will have been done before this routine is called.
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
)
120 const GLuint dimensions
= (target
== GL_TEXTURE_3D
) ? 3 : 2;
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.
129 GLubyte
*buf
= (GLubyte
*)
130 ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
131 GL_WRITE_ONLY_ARB
, ctx
->Pack
.BufferObj
);
133 /* buffer is already mapped - that's an error */
134 _mesa_error(ctx
, GL_INVALID_OPERATION
,"glGetTexImage(PBO is mapped)");
137 /* <pixels> was an offset into the PBO.
138 * Now make it a real, client-side pointer inside the mapped region.
140 pixels
= ADD_POINTERS(buf
, pixels
);
148 const GLint width
= texImage
->Width
;
149 const GLint height
= texImage
->Height
;
150 const GLint depth
= texImage
->Depth
;
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
,
160 if (format
== GL_COLOR_INDEX
) {
161 GLuint indexRow
[MAX_WIDTH
];
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
];
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
];
181 "Color index problem in _mesa_GetTexImage");
183 _mesa_pack_index_span(ctx
, width
, type
, dest
,
184 indexRow
, &ctx
->Pack
,
185 0 /* no image transfer */);
187 else if (format
== GL_DEPTH_COMPONENT
) {
188 GLfloat depthRow
[MAX_WIDTH
];
190 for (col
= 0; col
< width
; col
++) {
191 (*texImage
->FetchTexelf
)(texImage
, col
, row
, img
,
194 _mesa_pack_depth_span(ctx
, width
, dest
, type
,
195 depthRow
, &ctx
->Pack
);
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
);
206 else if (format
== GL_YCBCR_MESA
) {
207 /* No pixel transfer */
208 const GLint rowstride
= texImage
->RowStride
;
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
);
220 else if (ctx
->Pack
.SwapBytes
) {
221 _mesa_swap2((GLushort
*) dest
, width
);
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];
230 GLbitfield transferOps
= 0x0;
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;
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;
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
]);
251 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
,
253 &ctx
->Pack
, transferOps
);
255 #endif /* FEATURE_EXT_texture_sRGB */
257 /* general case: convert row to RGBA format */
258 GLfloat rgba
[MAX_WIDTH
][4];
260 GLbitfield transferOps
= 0x0;
262 _mesa_get_format_datatype(texImage
->TexFormat
);
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.
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
;
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;
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;
287 else if (texImage
->_BaseFormat
== GL_LUMINANCE_ALPHA
) {
288 rgba
[col
][GCOMP
] = 0.0;
289 rgba
[col
][BCOMP
] = 0.0;
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;
297 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
,
299 &ctx
->Pack
, transferOps
);
305 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
306 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
307 ctx
->Pack
.BufferObj
);
314 * This is the software fallback for Driver.GetCompressedTexImage().
315 * All error checking will have been done before this routine is called.
318 _mesa_get_compressed_teximage(GLcontext
*ctx
, GLenum target
, GLint level
,
320 struct gl_texture_object
*texObj
,
321 struct gl_texture_image
*texImage
)
325 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
326 /* pack texture image into a PBO */
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)");
334 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
336 ctx
->Pack
.BufferObj
);
338 /* buffer is already mapped - that's an error */
339 _mesa_error(ctx
, GL_INVALID_OPERATION
,
340 "glGetCompressedTexImage(PBO is mapped)");
343 img
= ADD_POINTERS(buf
, img
);
350 /* don't use texImage->CompressedSize since that may be padded out */
351 size
= _mesa_compressed_texture_size(ctx
, texImage
->Width
, texImage
->Height
,
353 texImage
->TexFormat
);
355 /* just memcpy, no pixelstore or pixel transfer */
356 _mesa_memcpy(img
, texImage
->Data
, size
);
358 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
359 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
360 ctx
->Pack
.BufferObj
);
367 * Do error checking for a glGetTexImage() call.
368 * \return GL_TRUE if any error, GL_FALSE if no errors.
371 getteximage_error_check(GLcontext
*ctx
, GLenum target
, GLint level
,
372 GLenum format
, GLenum type
, GLvoid
*pixels
)
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
);
380 if (maxLevels
== 0) {
381 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target=0x%x)", target
);
385 if (level
< 0 || level
>= maxLevels
) {
386 _mesa_error( ctx
, GL_INVALID_VALUE
, "glGetTexImage(level)" );
390 if (_mesa_sizeof_packed_type(type
) <= 0) {
391 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(type)" );
395 if (_mesa_components_in_format(format
) <= 0 ||
396 format
== GL_STENCIL_INDEX
) {
397 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)" );
401 if (!ctx
->Extensions
.EXT_paletted_texture
&& _mesa_is_index_format(format
)) {
402 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
406 if (!ctx
->Extensions
.ARB_depth_texture
&& _mesa_is_depth_format(format
)) {
407 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
411 if (!ctx
->Extensions
.MESA_ycbcr_texture
&& _mesa_is_ycbcr_format(format
)) {
412 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
416 if (!ctx
->Extensions
.EXT_packed_depth_stencil
417 && _mesa_is_depthstencil_format(format
)) {
418 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
422 if (!ctx
->Extensions
.ATI_envmap_bumpmap
423 && _mesa_is_dudv_format(format
)) {
424 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
428 texUnit
= _mesa_get_current_tex_unit(ctx
);
429 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
431 if (!texObj
|| _mesa_is_proxy_texture(target
)) {
432 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target)");
436 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
442 baseFormat
= _mesa_get_format_base_format(texImage
->TexFormat
);
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.
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)");
454 else if (_mesa_is_index_format(format
)
455 && !_mesa_is_index_format(baseFormat
)) {
456 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
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)");
465 else if (_mesa_is_ycbcr_format(format
)
466 && !_mesa_is_ycbcr_format(baseFormat
)) {
467 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
470 else if (_mesa_is_depthstencil_format(format
)
471 && !_mesa_is_depthstencil_format(baseFormat
)) {
472 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
475 else if (_mesa_is_dudv_format(format
)
476 && !_mesa_is_dudv_format(baseFormat
)) {
477 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
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)");
499 * Get texture image. Called by glGetTexImage.
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.
508 _mesa_GetTexImage( GLenum target
, GLint level
, GLenum format
,
509 GLenum type
, GLvoid
*pixels
)
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
);
516 if (getteximage_error_check(ctx
, target
, level
, format
, type
, pixels
)) {
520 texUnit
= _mesa_get_current_tex_unit(ctx
);
521 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
523 _mesa_lock_texture(ctx
, texObj
);
525 struct gl_texture_image
*texImage
=
526 _mesa_select_tex_image(ctx
, texObj
, target
, level
);
528 /* typically, this will call _mesa_get_teximage() */
529 ctx
->Driver
.GetTexImage(ctx
, target
, level
, format
, type
, pixels
,
532 _mesa_unlock_texture(ctx
, texObj
);
537 _mesa_GetCompressedTexImageARB(GLenum target
, GLint level
, GLvoid
*img
)
539 const struct gl_texture_unit
*texUnit
;
540 struct gl_texture_object
*texObj
;
541 struct gl_texture_image
*texImage
;
543 GET_CURRENT_CONTEXT(ctx
);
544 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
546 texUnit
= _mesa_get_current_tex_unit(ctx
);
547 texObj
= _mesa_select_tex_object(ctx
, texUnit
, target
);
549 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetCompressedTexImageARB");
553 maxLevels
= _mesa_max_texture_levels(ctx
, target
);
554 ASSERT(maxLevels
> 0); /* 0 indicates bad target, caught above */
556 if (level
< 0 || level
>= maxLevels
) {
557 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGetCompressedTexImageARB(level)");
561 if (_mesa_is_proxy_texture(target
)) {
562 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetCompressedTexImageARB(target)");
566 _mesa_lock_texture(ctx
, texObj
);
568 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
570 if (texImage
->IsCompressed
) {
571 /* this typically calls _mesa_get_compressed_teximage() */
572 ctx
->Driver
.GetCompressedTexImage(ctx
, target
, level
, img
,
576 _mesa_error(ctx
, GL_INVALID_OPERATION
,
577 "glGetCompressedTexImageARB");
581 /* probably invalid mipmap level */
582 _mesa_error(ctx
, GL_INVALID_VALUE
,
583 "glGetCompressedTexImageARB(level)");
586 _mesa_unlock_texture(ctx
, texObj
);