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"
37 #include "format_unpack.h"
39 #include "mfeatures.h"
42 #include "texgetimage.h"
48 * Can the given type represent negative values?
50 static inline GLboolean
51 type_needs_clamping(GLenum type
)
58 case GL_HALF_FLOAT_ARB
:
59 case GL_UNSIGNED_INT_10F_11F_11F_REV
:
60 case GL_UNSIGNED_INT_5_9_9_9_REV
:
69 * glGetTexImage for depth/Z pixels.
72 get_tex_depth(struct gl_context
*ctx
, GLuint dimensions
,
73 GLenum format
, GLenum type
, GLvoid
*pixels
,
74 struct gl_texture_image
*texImage
)
76 const GLint width
= texImage
->Width
;
77 const GLint height
= texImage
->Height
;
78 const GLint depth
= texImage
->Depth
;
80 GLfloat
*depthRow
= (GLfloat
*) malloc(width
* sizeof(GLfloat
));
83 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
87 for (img
= 0; img
< depth
; img
++) {
91 /* map src texture buffer */
92 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
93 0, 0, width
, height
, GL_MAP_READ_BIT
,
94 &srcMap
, &srcRowStride
);
97 for (row
= 0; row
< height
; row
++) {
98 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
99 width
, height
, format
, type
,
101 const GLubyte
*src
= srcMap
+ row
* srcRowStride
;
102 _mesa_unpack_float_z_row(texImage
->TexFormat
, width
, src
, depthRow
);
103 _mesa_pack_depth_span(ctx
, width
, dest
, type
, depthRow
, &ctx
->Pack
);
106 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
109 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
118 * glGetTexImage for YCbCr pixels.
121 get_tex_ycbcr(struct gl_context
*ctx
, GLuint dimensions
,
122 GLenum format
, GLenum type
, GLvoid
*pixels
,
123 struct gl_texture_image
*texImage
)
125 const GLint width
= texImage
->Width
;
126 const GLint height
= texImage
->Height
;
127 const GLint depth
= texImage
->Depth
;
130 for (img
= 0; img
< depth
; img
++) {
134 /* map src texture buffer */
135 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
136 0, 0, width
, height
, GL_MAP_READ_BIT
,
137 &srcMap
, &rowstride
);
140 for (row
= 0; row
< height
; row
++) {
141 const GLubyte
*src
= srcMap
+ row
* rowstride
;
142 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
143 width
, height
, format
, type
,
145 memcpy(dest
, src
, width
* sizeof(GLushort
));
147 /* check for byte swapping */
148 if ((texImage
->TexFormat
== MESA_FORMAT_YCBCR
149 && type
== GL_UNSIGNED_SHORT_8_8_REV_MESA
) ||
150 (texImage
->TexFormat
== MESA_FORMAT_YCBCR_REV
151 && type
== GL_UNSIGNED_SHORT_8_8_MESA
)) {
152 if (!ctx
->Pack
.SwapBytes
)
153 _mesa_swap2((GLushort
*) dest
, width
);
155 else if (ctx
->Pack
.SwapBytes
) {
156 _mesa_swap2((GLushort
*) dest
, width
);
160 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
163 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
170 * Get an uncompressed color texture image.
173 get_tex_rgba_uncompressed(struct gl_context
*ctx
, GLuint dimensions
,
174 GLenum format
, GLenum type
, GLvoid
*pixels
,
175 struct gl_texture_image
*texImage
,
176 GLbitfield transferOps
)
178 const gl_format texFormat
= texImage
->TexFormat
;
179 const GLuint width
= texImage
->Width
;
180 const GLenum destBaseFormat
= _mesa_base_tex_format(ctx
, format
);
181 GLenum rebaseFormat
= GL_NONE
;
182 GLuint height
= texImage
->Height
;
183 GLuint depth
= texImage
->Depth
;
186 GLuint (*rgba_uint
)[4];
187 GLboolean is_integer
= _mesa_is_format_integer_color(texImage
->TexFormat
);
189 /* Allocate buffer for one row of texels */
190 rgba
= (GLfloat (*)[4]) malloc(4 * width
* sizeof(GLfloat
));
191 rgba_uint
= (GLuint (*)[4]) rgba
;
193 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage()");
197 if (texImage
->_BaseFormat
== GL_LUMINANCE
||
198 texImage
->_BaseFormat
== GL_INTENSITY
||
199 texImage
->_BaseFormat
== GL_LUMINANCE_ALPHA
) {
200 /* If a luminance (or intensity) texture is read back as RGB(A), the
201 * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat
204 rebaseFormat
= texImage
->_BaseFormat
;
206 else if ((texImage
->_BaseFormat
== GL_RGBA
||
207 texImage
->_BaseFormat
== GL_RGB
) &&
208 (destBaseFormat
== GL_LUMINANCE
||
209 destBaseFormat
== GL_LUMINANCE_ALPHA
||
210 destBaseFormat
== GL_LUMINANCE_INTEGER_EXT
||
211 destBaseFormat
== GL_LUMINANCE_ALPHA_INTEGER_EXT
)) {
212 /* If we're reading back an RGB(A) texture as luminance then we need
213 * to return L=tex(R). Note, that's different from glReadPixels which
216 rebaseFormat
= GL_LUMINANCE_ALPHA
; /* this covers GL_LUMINANCE too */
219 for (img
= 0; img
< depth
; img
++) {
223 /* map src texture buffer */
224 ctx
->Driver
.MapTextureImage(ctx
, texImage
, img
,
225 0, 0, width
, height
, GL_MAP_READ_BIT
,
226 &srcMap
, &rowstride
);
228 for (row
= 0; row
< height
; row
++) {
229 const GLubyte
*src
= srcMap
+ row
* rowstride
;
230 void *dest
= _mesa_image_address(dimensions
, &ctx
->Pack
, pixels
,
231 width
, height
, format
, type
,
235 _mesa_unpack_uint_rgba_row(texFormat
, width
, src
, rgba_uint
);
237 _mesa_rebase_rgba_uint(width
, rgba_uint
, rebaseFormat
);
238 _mesa_pack_rgba_span_int(ctx
, width
, rgba_uint
,
241 _mesa_unpack_rgba_row(texFormat
, width
, src
, rgba
);
243 _mesa_rebase_rgba_float(width
, rgba
, rebaseFormat
);
244 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
,
246 &ctx
->Pack
, transferOps
);
250 /* Unmap the src texture buffer */
251 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, img
);
254 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
264 * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc).
265 * Compressed textures are handled here as well.
268 get_tex_rgba(struct gl_context
*ctx
, GLuint dimensions
,
269 GLenum format
, GLenum type
, GLvoid
*pixels
,
270 struct gl_texture_image
*texImage
)
272 const GLenum dataType
= _mesa_get_format_datatype(texImage
->TexFormat
);
273 GLbitfield transferOps
= 0x0;
275 /* In general, clamping does not apply to glGetTexImage, except when
276 * the returned type of the image can't hold negative values.
278 if (type_needs_clamping(type
)) {
279 /* the returned image type can't have negative values */
280 if (dataType
== GL_FLOAT
||
281 dataType
== GL_SIGNED_NORMALIZED
||
282 format
== GL_LUMINANCE
||
283 format
== GL_LUMINANCE_ALPHA
) {
284 transferOps
|= IMAGE_CLAMP_BIT
;
287 /* This applies to RGB, RGBA textures. if the format is either LUMINANCE
288 * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to
289 * clamp the sum to [0,1].
291 else if ((format
== GL_LUMINANCE
||
292 format
== GL_LUMINANCE_ALPHA
) &&
293 dataType
== GL_UNSIGNED_NORMALIZED
) {
294 transferOps
|= IMAGE_CLAMP_BIT
;
296 get_tex_rgba_uncompressed(ctx
, dimensions
, format
, type
,
297 pixels
, texImage
, transferOps
);
302 * Try to do glGetTexImage() with simple memcpy().
303 * \return GL_TRUE if done, GL_FALSE otherwise
306 get_tex_memcpy(struct gl_context
*ctx
, GLenum format
, GLenum type
,
308 struct gl_texture_image
*texImage
)
310 const GLenum target
= texImage
->TexObject
->Target
;
311 GLboolean memCopy
= GL_FALSE
;
314 * Check if the src/dst formats are compatible.
315 * Also note that GL's pixel transfer ops don't apply to glGetTexImage()
316 * so we don't have to worry about those.
317 * XXX more format combinations could be supported here.
319 if (target
== GL_TEXTURE_1D
||
320 target
== GL_TEXTURE_2D
||
321 _mesa_is_cube_face(target
)) {
322 if ((texImage
->TexFormat
== MESA_FORMAT_ARGB8888
) &&
324 (type
== GL_UNSIGNED_BYTE
|| type
== GL_UNSIGNED_INT_8_8_8_8_REV
) &&
325 !ctx
->Pack
.SwapBytes
&&
326 _mesa_little_endian()) {
329 else if ((texImage
->TexFormat
== MESA_FORMAT_AL88
) &&
330 format
== GL_LUMINANCE_ALPHA
&&
331 type
== GL_UNSIGNED_BYTE
&&
332 !ctx
->Pack
.SwapBytes
&&
333 _mesa_little_endian()) {
336 else if ((texImage
->TexFormat
== MESA_FORMAT_L8
) &&
337 format
== GL_LUMINANCE
&&
338 type
== GL_UNSIGNED_BYTE
) {
341 else if (texImage
->TexFormat
== MESA_FORMAT_L16
&&
342 format
== GL_LUMINANCE
&&
343 type
== GL_UNSIGNED_SHORT
) {
346 else if (texImage
->TexFormat
== MESA_FORMAT_A8
&&
347 format
== GL_ALPHA
&&
348 type
== GL_UNSIGNED_BYTE
) {
351 else if (texImage
->TexFormat
== MESA_FORMAT_A16
&&
352 format
== GL_ALPHA
&&
353 type
== GL_UNSIGNED_SHORT
) {
359 const GLuint bpp
= _mesa_get_format_bytes(texImage
->TexFormat
);
360 const GLuint bytesPerRow
= texImage
->Width
* bpp
;
362 _mesa_image_address2d(&ctx
->Pack
, pixels
, texImage
->Width
,
363 texImage
->Height
, format
, type
, 0, 0);
364 const GLint dstRowStride
=
365 _mesa_image_row_stride(&ctx
->Pack
, texImage
->Width
, format
, type
);
369 /* map src texture buffer */
370 ctx
->Driver
.MapTextureImage(ctx
, texImage
, 0,
371 0, 0, texImage
->Width
, texImage
->Height
,
372 GL_MAP_READ_BIT
, &src
, &srcRowStride
);
375 if (bytesPerRow
== dstRowStride
&& bytesPerRow
== srcRowStride
) {
376 memcpy(dst
, src
, bytesPerRow
* texImage
->Height
);
380 for (row
= 0; row
< texImage
->Height
; row
++) {
381 memcpy(dst
, src
, bytesPerRow
);
387 /* unmap src texture buffer */
388 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, 0);
391 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGetTexImage");
400 * This is the software fallback for Driver.GetTexImage().
401 * All error checking will have been done before this routine is called.
402 * We'll call ctx->Driver.MapTextureImage() to access the data, then
403 * unmap with ctx->Driver.UnmapTextureImage().
406 _mesa_get_teximage(struct gl_context
*ctx
,
407 GLenum format
, GLenum type
, GLvoid
*pixels
,
408 struct gl_texture_image
*texImage
)
412 switch (texImage
->TexObject
->Target
) {
423 if (get_tex_memcpy(ctx
, format
, type
, pixels
, texImage
)) {
426 else if (format
== GL_DEPTH_COMPONENT
) {
427 get_tex_depth(ctx
, dimensions
, format
, type
, pixels
, texImage
);
429 else if (format
== GL_YCBCR_MESA
) {
430 get_tex_ycbcr(ctx
, dimensions
, format
, type
, pixels
, texImage
);
433 get_tex_rgba(ctx
, dimensions
, format
, type
, pixels
, texImage
);
438 * Do error checking for a glGetTexImage() call.
439 * \return GL_TRUE if any error, GL_FALSE if no errors.
442 getteximage_error_check(struct gl_context
*ctx
, GLenum target
, GLint level
,
443 GLenum format
, GLenum type
, GLvoid
*pixels
)
445 struct gl_texture_object
*texObj
;
446 struct gl_texture_image
*texImage
;
447 const GLint maxLevels
= _mesa_max_texture_levels(ctx
, target
);
448 GLenum baseFormat
, err
;
450 if (maxLevels
== 0) {
451 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target=0x%x)", target
);
455 if (level
< 0 || level
>= maxLevels
) {
456 _mesa_error( ctx
, GL_INVALID_VALUE
, "glGetTexImage(level)" );
460 if (_mesa_sizeof_packed_type(type
) <= 0) {
461 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(type)" );
465 if (_mesa_components_in_format(format
) <= 0 ||
466 format
== GL_STENCIL_INDEX
||
467 format
== GL_COLOR_INDEX
) {
468 _mesa_error( ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)" );
472 if (_mesa_is_depth_format(format
)) {
473 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
477 if (!ctx
->Extensions
.MESA_ycbcr_texture
&& _mesa_is_ycbcr_format(format
)) {
478 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(format)");
482 err
= _mesa_error_check_format_and_type(ctx
, format
, type
);
483 if (err
!= GL_NO_ERROR
) {
484 _mesa_error(ctx
, err
, "glGetTexImage(format/type)");
488 texObj
= _mesa_select_tex_object(ctx
, target
);
490 if (!texObj
|| _mesa_is_proxy_texture(target
)) {
491 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetTexImage(target)");
495 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
497 /* non-existant texture image */
501 baseFormat
= _mesa_get_format_base_format(texImage
->TexFormat
);
503 /* Make sure the requested image format is compatible with the
506 if (_mesa_is_color_format(format
)
507 && !_mesa_is_color_format(baseFormat
)) {
508 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
511 else if (_mesa_is_depth_format(format
)
512 && !_mesa_is_depth_format(baseFormat
)) {
513 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
516 else if (_mesa_is_ycbcr_format(format
)
517 && !_mesa_is_ycbcr_format(baseFormat
)) {
518 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetTexImage(format mismatch)");
528 * Get texture image. Called by glGetTexImage.
530 * \param target texture target.
531 * \param level image level.
532 * \param format pixel data format for returned image.
533 * \param type pixel data type for returned image.
534 * \param bufSize size of the pixels data buffer.
535 * \param pixels returned pixel data.
538 _mesa_GetTexImage( GLenum target
, GLint level
, GLenum format
,
539 GLenum type
, GLvoid
*pixels
)
541 struct gl_texture_object
*texObj
;
542 struct gl_texture_image
*texImage
;
543 GET_CURRENT_CONTEXT(ctx
);
544 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
546 if (getteximage_error_check(ctx
, target
, level
, format
, type
, pixels
)) {
551 /* not an error, do nothing */
555 texObj
= _mesa_select_tex_object(ctx
, target
);
556 texImage
= _mesa_select_tex_image(ctx
, texObj
, target
, level
);
558 if (_mesa_is_zero_size_texture(texImage
))
561 if (MESA_VERBOSE
& (VERBOSE_API
| VERBOSE_TEXTURE
)) {
562 _mesa_debug(ctx
, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
563 " dstFmt=0x%x, dstType=0x%x\n",
565 _mesa_get_format_name(texImage
->TexFormat
),
566 texImage
->Width
, texImage
->Height
,
570 _mesa_lock_texture(ctx
, texObj
);
572 ctx
->Driver
.GetTexImage(ctx
, format
, type
, pixels
, texImage
);
574 _mesa_unlock_texture(ctx
, texObj
);