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.
27 * Code for glGetTexImage() and glGetCompressedTexImage().
33 * Can the given type represent negative values?
35 static inline GLboolean
36 type_needs_clamping(GLenum type
)
43 case GL_UNSIGNED_INT_10F_11F_11F_REV
:
44 case GL_UNSIGNED_INT_5_9_9_9_REV
:
53 * glGetTexImage for depth/Z pixels.
56 get_tex_depth(struct gl_context
*ctx
, GLuint dimensions
,
57 GLenum format
, GLenum type
, GLvoid
*pixels
,
58 struct gl_texture_image
*texImage
)
60 const GLint width
= texImage
->Width
;
61 const GLint height
= texImage
->Height
;
62 const GLint depth
= texImage
->Depth
;
64 GLfloat
*depthRow
= (GLfloat
*) malloc(width
* sizeof(GLfloat
));
67 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
71 for (img
= 0; img
< depth
; img
++) {
75 /* map src texture buffer */
76 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
77 0, 0, width
, height
, GL_MAP_READ_BIT
,
78 &srcMap
, &srcRowStride
);
81 for (row
= 0; row
< height
; row
++) {
82 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
83 width
, height
, format
, type
,
85 const GLubyte
*src
= srcMap
+ row
* srcRowStride
;
86 _mesa_unpack_float_z_row(texImage
->TexFormat
, width
, src
, depthRow
);
87 _mesa_pack_depth_span(ctx
, width
, dest
, type
, depthRow
, &ctx
->Pack
);
90 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
93 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
102 * glGetTexImage for YCbCr pixels.
105 get_tex_ycbcr(struct gl_context
*ctx
, GLuint dimensions
,
106 GLenum format
, GLenum type
, GLvoid
*pixels
,
107 struct gl_texture_image
*texImage
)
109 const GLint width
= texImage
->Width
;
110 const GLint height
= texImage
->Height
;
111 const GLint depth
= texImage
->Depth
;
114 for (img
= 0; img
< depth
; img
++) {
118 /* map src texture buffer */
119 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
120 0, 0, width
, height
, GL_MAP_READ_BIT
,
121 &srcMap
, &rowstride
);
124 for (row
= 0; row
< height
; row
++) {
125 const GLubyte
*src
= srcMap
+ row
* rowstride
;
126 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
127 width
, height
, format
, type
,
129 memcpy(dest
, src
, width
* sizeof(GLushort
));
131 /* check for byte swapping */
132 if ((texImage
->TexFormat
== MESA_FORMAT_YCBCR
133 && type
== GL_UNSIGNED_SHORT_8_8_REV_MESA
) ||
134 (texImage
->TexFormat
== MESA_FORMAT_YCBCR_REV
135 && type
== GL_UNSIGNED_SHORT_8_8_MESA
)) {
136 if (!ctx
->Pack
.SwapBytes
)
137 _mesa_swap2((GLushort
*) dest
, width
);
139 else if (ctx
->Pack
.SwapBytes
) {
140 _mesa_swap2((GLushort
*) dest
, width
);
144 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
147 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
154 * Get an uncompressed color texture image.
157 get_tex_rgba_uncompressed(struct gl_context
*ctx
, GLuint dimensions
,
158 GLenum format
, GLenum type
, GLvoid
*pixels
,
159 struct gl_texture_image
*texImage
,
160 GLbitfield transferOps
)
162 const gl_format texFormat
= texImage
->TexFormat
;
163 const GLuint width
= texImage
->Width
;
164 const GLenum destBaseFormat
= _mesa_base_tex_format(ctx
, format
);
165 GLenum rebaseFormat
= GL_NONE
;
166 GLuint height
= texImage
->Height
;
167 GLuint depth
= texImage
->Depth
;
170 GLuint (*rgba_uint
)[4];
171 GLboolean is_integer
= _mesa_is_format_integer_color(texImage
->TexFormat
);
173 /* Allocate buffer for one row of texels */
174 rgba
= (GLfloat (*)[4]) malloc(4 * width
* sizeof(GLfloat
));
175 rgba_uint
= (GLuint (*)[4]) rgba
;
177 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage()");
181 if (texImage
->_BaseFormat
== GL_LUMINANCE
||
182 texImage
->_BaseFormat
== GL_INTENSITY
||
183 texImage
->_BaseFormat
== GL_LUMINANCE_ALPHA
) {
184 /* If a luminance (or intensity) texture is read back as RGB(A), the
185 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat
188 rebaseFormat
= texImage
->_BaseFormat
;
190 else if ((texImage
->_BaseFormat
== GL_RGBA
||
191 texImage
->_BaseFormat
== GL_RGB
) &&
192 (destBaseFormat
== GL_LUMINANCE
||
193 destBaseFormat
== GL_LUMINANCE_ALPHA
||
194 destBaseFormat
== GL_LUMINANCE_INTEGER_EXT
||
195 destBaseFormat
== GL_LUMINANCE_ALPHA_INTEGER_EXT
)) {
196 /* If we're reading back an RGB(A) texture as luminance then we need
197 * to return L=tex(R). Note, that's different from glReadPixels which
200 rebaseFormat
= GL_LUMINANCE_ALPHA
; /* this covers GL_LUMINANCE too */
203 for (img
= 0; img
< depth
; img
++) {
207 /* map src texture buffer */
208 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
209 0, 0, width
, height
, GL_MAP_READ_BIT
,
210 &srcMap
, &rowstride
);
212 for (row
= 0; row
< height
; row
++) {
213 const GLubyte
*src
= srcMap
+ row
* rowstride
;
214 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
215 width
, height
, format
, type
,
219 _mesa_unpack_uint_rgba_row(texFormat
, width
, src
, rgba_uint
);
221 _mesa_rebase_rgba_uint(width
, rgba_uint
, rebaseFormat
);
222 _mesa_pack_rgba_span_int(ctx
, width
, rgba_uint
,
225 _mesa_unpack_rgba_row(texFormat
, width
, src
, rgba
);
227 _mesa_rebase_rgba_float(width
, rgba
, rebaseFormat
);
228 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
,
230 &ctx
->Pack
, transferOps
);
234 /* Unmap the src texture buffer */
235 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
238 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
248 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
249 * Compressed textures are handled here as well.
252 get_tex_rgba(struct gl_context
*ctx
, GLuint dimensions
,
253 GLenum format
, GLenum type
, GLvoid
*pixels
,
254 struct gl_texture_image
*texImage
)
256 const GLenum dataType
= _mesa_get_format_datatype(texImage
->TexFormat
);
257 GLbitfield transferOps
= 0x0;
259 /* In general, clamping does not apply to glGetTexImage, except when
260 * the returned type of the image can't hold negative values.
262 if (type_needs_clamping(type
)) {
263 /* the returned image type can't have negative values */
264 if (dataType
== GL_FLOAT
||
265 dataType
== GL_SIGNED_NORMALIZED
||
266 format
== GL_LUMINANCE
||
267 format
== GL_LUMINANCE_ALPHA
) {
268 transferOps
|= IMAGE_CLAMP_BIT
;
271 /* This applies to RGB, RGBA textures. if the format is either LUMINANCE
272 * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to
273 * clamp the sum to [0,1].
275 else if ((format
== GL_LUMINANCE
||
276 format
== GL_LUMINANCE_ALPHA
) &&
277 dataType
== GL_UNSIGNED_NORMALIZED
) {
278 transferOps
|= IMAGE_CLAMP_BIT
;
280 get_tex_rgba_uncompressed(ctx
, dimensions
, format
, type
,
281 pixels
, texImage
, transferOps
);
286 * Try to do glGetTexImage() with simple memcpy().
287 * \return GL_TRUE if done, GL_FALSE otherwise
290 get_tex_memcpy(struct gl_context
*ctx
, GLenum format
, GLenum type
,
292 struct gl_texture_image
*texImage
)
294 const GLenum target
= texImage
->TexObject
->Target
;
295 GLboolean memCopy
= GL_FALSE
;
298 * Check if the src/dst formats are compatible.
299 * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
300 * so we don't have to worry about those.
301 * XXX more format combinations could be supported here.
303 if (target
== GL_TEXTURE_1D
||
304 target
== GL_TEXTURE_2D
||
305 _mesa_is_cube_face(target
)) {
306 if ((texImage
->TexFormat
== MESA_FORMAT_ARGB8888
) &&
308 (type
== GL_UNSIGNED_BYTE
|| type
== GL_UNSIGNED_INT_8_8_8_8_REV
) &&
309 !ctx
->Pack
.SwapBytes
&&
310 _mesa_little_endian()) {
313 else if ((texImage
->TexFormat
== MESA_FORMAT_AL88
) &&
314 format
== GL_LUMINANCE_ALPHA
&&
315 type
== GL_UNSIGNED_BYTE
&&
316 !ctx
->Pack
.SwapBytes
&&
317 _mesa_little_endian()) {
320 else if ((texImage
->TexFormat
== MESA_FORMAT_L8
) &&
321 format
== GL_LUMINANCE
&&
322 type
== GL_UNSIGNED_BYTE
) {
325 else if (texImage
->TexFormat
== MESA_FORMAT_L16
&&
326 format
== GL_LUMINANCE
&&
327 type
== GL_UNSIGNED_SHORT
) {
330 else if (texImage
->TexFormat
== MESA_FORMAT_A8
&&
331 format
== GL_ALPHA
&&
332 type
== GL_UNSIGNED_BYTE
) {
335 else if (texImage
->TexFormat
== MESA_FORMAT_A16
&&
336 format
== GL_ALPHA
&&
337 type
== GL_UNSIGNED_SHORT
) {
343 const GLuint bpp
= _mesa_get_format_bytes(texImage
->TexFormat
);
344 const GLuint bytesPerRow
= texImage
->Width
* bpp
;
346 _mesa_image_address2d(&ctx
->Pack
, pixels
, texImage
->Width
,
347 texImage
->Height
, format
, type
, 0, 0);
348 const GLint dstRowStride
=
349 _mesa_image_row_stride(&ctx
->Pack
, texImage
->Width
, format
, type
);
353 /* map src texture buffer */
354 ctx
->Driver
.MapTextureImage(ctx
, texImage
, 0,
355 0, 0, texImage
->Width
, texImage
->Height
,
356 GL_MAP_READ_BIT
, &src
, &srcRowStride
);
359 if (bytesPerRow
== dstRowStride
&& bytesPerRow
== srcRowStride
) {
360 memcpy(dst
, src
, bytesPerRow
* texImage
->Height
);
364 for (row
= 0; row
< texImage
->Height
; row
++) {
365 memcpy(dst
, src
, bytesPerRow
);
371 /* unmap src texture buffer */
372 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, 0);
375 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
384 * This is the software fallback for Driver.GetTexImage().
385 * All error checking will have been done before this routine is called.
386 * We'll call ctx->Driver.MapTextureImage() to access the data, then
387 * unmap with ctx->Driver.UnmapTextureImage().
390 _mesa_get_teximage(struct gl_context
*ctx
,
391 GLenum format
, GLenum type
, GLvoid
*pixels
,
392 struct gl_texture_image
*texImage
)
396 switch (texImage
->TexObject
->Target
) {
404 if (get_tex_memcpy(ctx
, format
, type
, pixels
, texImage
)) {
407 else if (format
== GL_DEPTH_COMPONENT
) {
408 get_tex_depth(ctx
, dimensions
, format
, type
, pixels
, texImage
);
410 else if (format
== GL_YCBCR_MESA
) {
411 get_tex_ycbcr(ctx
, dimensions
, format
, type
, pixels
, texImage
);
414 get_tex_rgba(ctx
, dimensions
, format
, type
, pixels
, texImage
);
419 * Do error checking for a glGetTexImage() call.
420 * \return GL_TRUE if any error, GL_FALSE if no errors.
423 getteximage_error_check(struct gl_context
*ctx
, GLenum target
, GLint level
,
424 GLenum format
, GLenum type
, GLvoid
*pixels
)
426 struct gl_texture_object
*texObj
;
427 struct gl_texture_image
*texImage
;
428 const GLint maxLevels
= _mesa_max_texture_levels(ctx
, target
);
429 GLenum baseFormat
, err
;
431 if (maxLevels
== 0) {
432 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target=0x%x)", target
);
436 if (level
< 0 || level
>= maxLevels
) {
437 _mesa_error( ctx
, GL_INVALID_VALUE
, "glGetTexImage(level)" );
441 if (_mesa_sizeof_packed_type(type
) <= 0) {
442 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(type)" );
446 if (_mesa_components_in_format(format
) <= 0 ||
447 format
== GL_STENCIL_INDEX
||
448 format
== GL_COLOR_INDEX
) {
449 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)" );
453 if (_mesa_is_depth_format(format
)) {
454 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
458 if (!ctx
->Extensions
.MESA_ycbcr_texture
&& _mesa_is_ycbcr_format(format
)) {
459 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
463 err
= _mesa_error_check_format_and_type(ctx
, format
, type
);
464 if (err
!= GL_NO_ERROR
) {
465 _mesa_error(ctx
, err
, "glGetTexImage(format/type)");
469 texObj
= _mesa_select_tex_object(ctx
, target
);
471 if (!texObj
|| _mesa_is_proxy_texture(target
)) {
472 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target)");
476 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
478 /* non-existant texture image */
482 baseFormat
= _mesa_get_format_base_format(texImage
->TexFormat
);
484 /* Make sure the requested image format is compatible with the
487 if (_mesa_is_color_format(format
)
488 && !_mesa_is_color_format(baseFormat
)) {
489 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
492 else if (_mesa_is_depth_format(format
)
493 && !_mesa_is_depth_format(baseFormat
)) {
494 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
497 else if (_mesa_is_ycbcr_format(format
)
498 && !_mesa_is_ycbcr_format(baseFormat
)) {
499 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
509 * Get texture image. Called by glGetTexImage.
511 * \param target texture target.
512 * \param level image level.
513 * \param format pixel data format for returned image.
514 * \param type pixel data type for returned image.
515 * \param bufSize size of the pixels data buffer.
516 * \param pixels returned pixel data.
519 _mesa_GetTexImage( GLenum target
, GLint level
, GLenum format
,
520 GLenum type
, GLvoid
*pixels
)
522 struct gl_texture_object
*texObj
;
523 struct gl_texture_image
*texImage
;
524 GET_CURRENT_CONTEXT(ctx
);
525 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
527 if (getteximage_error_check(ctx
, target
, level
, format
, type
, pixels
)) {
532 /* not an error, do nothing */
536 texObj
= _mesa_select_tex_object(ctx
, target
);
537 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
539 if (_mesa_is_zero_size_texture(texImage
))
542 if (MESA_VERBOSE
& (VERBOSE_API
| VERBOSE_TEXTURE
)) {
543 _mesa_debug(ctx
, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
544 " dstFmt=0x%x, dstType=0x%x\n",
546 _mesa_get_format_name(texImage
->TexFormat
),
547 texImage
->Width
, texImage
->Height
,
551 _mesa_lock_texture(ctx
, texObj
);
553 ctx
->Driver
.GetTexImage(ctx
, format
, type
, pixels
, texImage
);
555 _mesa_unlock_texture(ctx
, texObj
);