2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
32 fast_read_depth_pixels( struct gl_context
*ctx
,
34 GLsizei width
, GLsizei height
,
35 GLenum type
, GLvoid
*pixels
,
36 const struct gl_pixelstore_attrib
*packing
)
38 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
39 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
41 int stride
, dstStride
, j
;
43 if (ctx
->Pixel
.DepthScale
!= 1.0 || ctx
->Pixel
.DepthBias
!= 0.0)
46 if (packing
->SwapBytes
)
49 if (_mesa_get_format_datatype(rb
->Format
) != GL_UNSIGNED_NORMALIZED
)
52 if (!((type
== GL_UNSIGNED_SHORT
&& rb
->Format
== MESA_FORMAT_Z16
) ||
53 type
== GL_UNSIGNED_INT
))
56 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
60 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
61 return GL_TRUE
; /* don't bother trying the slow path */
64 dstStride
= _mesa_image_row_stride(packing
, width
, GL_DEPTH_COMPONENT
, type
);
65 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
66 GL_DEPTH_COMPONENT
, type
, 0, 0);
68 for (j
= 0; j
< height
; j
++) {
69 if (type
== GL_UNSIGNED_INT
) {
70 _mesa_unpack_uint_z_row(rb
->Format
, width
, map
, (GLuint
*)dst
);
72 ASSERT(type
== GL_UNSIGNED_SHORT
&& rb
->Format
== MESA_FORMAT_Z16
);
73 memcpy(dst
, map
, width
* 2);
79 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
85 * Read pixels for format=GL_DEPTH_COMPONENT.
88 read_depth_pixels( struct gl_context
*ctx
,
90 GLsizei width
, GLsizei height
,
91 GLenum type
, GLvoid
*pixels
,
92 const struct gl_pixelstore_attrib
*packing
)
94 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
95 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
98 int dstStride
, stride
;
103 /* clipping should have been done already */
106 ASSERT(x
+ width
<= (GLint
) rb
->Width
);
107 ASSERT(y
+ height
<= (GLint
) rb
->Height
);
108 /* width should never be > MAX_WIDTH since we did clipping earlier */
109 ASSERT(width
<= MAX_WIDTH
);
111 if (fast_read_depth_pixels(ctx
, x
, y
, width
, height
, type
, pixels
, packing
))
114 dstStride
= _mesa_image_row_stride(packing
, width
, GL_DEPTH_COMPONENT
, type
);
115 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
116 GL_DEPTH_COMPONENT
, type
, 0, 0);
118 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
121 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
125 /* General case (slower) */
126 for (j
= 0; j
< height
; j
++, y
++) {
127 GLfloat depthValues
[MAX_WIDTH
];
128 _mesa_unpack_float_z_row(rb
->Format
, width
, map
, depthValues
);
129 _mesa_pack_depth_span(ctx
, width
, dst
, type
, depthValues
, packing
);
135 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
140 * Read pixels for format=GL_STENCIL_INDEX.
143 read_stencil_pixels( struct gl_context
*ctx
,
145 GLsizei width
, GLsizei height
,
146 GLenum type
, GLvoid
*pixels
,
147 const struct gl_pixelstore_attrib
*packing
)
149 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
150 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
158 /* width should never be > MAX_WIDTH since we did clipping earlier */
159 ASSERT(width
<= MAX_WIDTH
);
161 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
164 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
168 /* process image row by row */
169 for (j
= 0; j
< height
; j
++) {
171 GLubyte stencil
[MAX_WIDTH
];
173 _mesa_unpack_ubyte_stencil_row(rb
->Format
, width
, map
, stencil
);
174 dest
= _mesa_image_address2d(packing
, pixels
, width
, height
,
175 GL_STENCIL_INDEX
, type
, j
, 0);
177 _mesa_pack_stencil_span(ctx
, width
, type
, dest
, stencil
, packing
);
182 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
187 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
188 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
191 fast_read_rgba_pixels_memcpy( struct gl_context
*ctx
,
193 GLsizei width
, GLsizei height
,
194 GLenum format
, GLenum type
,
196 const struct gl_pixelstore_attrib
*packing
,
197 GLbitfield transferOps
)
199 struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
201 int dstStride
, stride
, j
, texelBytes
;
202 GLboolean swizzle_rb
= GL_FALSE
, copy_xrgb
= GL_FALSE
;
204 /* XXX we could check for other swizzle/special cases here as needed */
205 if (rb
->Format
== MESA_FORMAT_RGBA8888_REV
&&
207 type
== GL_UNSIGNED_INT_8_8_8_8_REV
) {
208 swizzle_rb
= GL_TRUE
;
210 else if (rb
->Format
== MESA_FORMAT_XRGB8888
&&
212 type
== GL_UNSIGNED_INT_8_8_8_8_REV
) {
215 else if (!_mesa_format_matches_format_and_type(rb
->Format
, format
, type
))
218 /* check for things we can't handle here */
219 if (packing
->SwapBytes
) {
223 /* If the format is unsigned normalized then we can ignore clamping
224 * because the values are already in the range [0,1] so it won't
225 * have any effect anyway.
227 if (_mesa_get_format_datatype(rb
->Format
) == GL_UNSIGNED_NORMALIZED
)
228 transferOps
&= ~IMAGE_CLAMP_BIT
;
233 dstStride
= _mesa_image_row_stride(packing
, width
, format
, type
);
234 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
237 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
240 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
241 return GL_TRUE
; /* don't bother trying the slow path */
244 texelBytes
= _mesa_get_format_bytes(rb
->Format
);
248 for (j
= 0; j
< height
; j
++) {
250 for (i
= 0; i
< width
; i
++) {
251 GLuint
*dst4
= (GLuint
*) dst
, *map4
= (GLuint
*) map
;
252 GLuint pixel
= map4
[i
];
253 dst4
[i
] = (pixel
& 0xff00ff00)
254 | ((pixel
& 0x00ff0000) >> 16)
255 | ((pixel
& 0x000000ff) << 16);
260 } else if (copy_xrgb
) {
261 /* convert xrgb -> argb */
262 for (j
= 0; j
< height
; j
++) {
263 GLuint
*dst4
= (GLuint
*) dst
, *map4
= (GLuint
*) map
;
265 for (i
= 0; i
< width
; i
++) {
266 dst4
[i
] = map4
[i
] | 0xff000000; /* set A=0xff */
273 for (j
= 0; j
< height
; j
++) {
274 memcpy(dst
, map
, width
* texelBytes
);
280 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
286 slow_read_rgba_pixels( struct gl_context
*ctx
,
288 GLsizei width
, GLsizei height
,
289 GLenum format
, GLenum type
,
291 const struct gl_pixelstore_attrib
*packing
,
292 GLbitfield transferOps
)
294 struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
295 const gl_format rbFormat
= rb
->Format
;
298 int dstStride
, stride
, j
;
300 dstStride
= _mesa_image_row_stride(packing
, width
, format
, type
);
301 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
304 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
307 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
311 rgba
= malloc(width
* MAX_PIXEL_BYTES
);
315 for (j
= 0; j
< height
; j
++) {
316 if (_mesa_is_integer_format(format
)) {
317 _mesa_unpack_uint_rgba_row(rbFormat
, width
, map
, (GLuint (*)[4]) rgba
);
318 _mesa_rebase_rgba_uint(width
, (GLuint (*)[4]) rgba
,
320 _mesa_pack_rgba_span_int(ctx
, width
, (GLuint (*)[4]) rgba
, format
,
323 _mesa_unpack_rgba_row(rbFormat
, width
, map
, (GLfloat (*)[4]) rgba
);
324 _mesa_rebase_rgba_float(width
, (GLfloat (*)[4]) rgba
,
326 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
, format
,
327 type
, dst
, packing
, transferOps
);
336 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
340 * Read R, G, B, A, RGB, L, or LA pixels.
343 read_rgba_pixels( struct gl_context
*ctx
,
345 GLsizei width
, GLsizei height
,
346 GLenum format
, GLenum type
, GLvoid
*pixels
,
347 const struct gl_pixelstore_attrib
*packing
)
349 GLbitfield transferOps
= ctx
->_ImageTransferState
;
350 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
351 struct gl_renderbuffer
*rb
= fb
->_ColorReadBuffer
;
356 if (!_mesa_is_integer_format(format
)) {
357 transferOps
|= IMAGE_CLAMP_BIT
;
360 /* Try the optimized paths first. */
361 if (fast_read_rgba_pixels_memcpy(ctx
, x
, y
, width
, height
,
362 format
, type
, pixels
, packing
,
367 slow_read_rgba_pixels(ctx
, x
, y
, width
, height
,
368 format
, type
, pixels
, packing
, transferOps
);
372 * Software fallback routine for ctx->Driver.ReadPixels().
373 * By time we get here, all error checking will have been done.
376 _mesa_readpixels(struct gl_context
*ctx
,
377 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
378 GLenum format
, GLenum type
,
379 const struct gl_pixelstore_attrib
*packing
,
382 struct gl_pixelstore_attrib clippedPacking
= *packing
;
385 _mesa_update_state(ctx
);
387 /* Do all needed clipping here, so that we can forget about it later */
388 if (_mesa_clip_readpixels(ctx
, &x
, &y
, &width
, &height
, &clippedPacking
)) {
392 case GL_STENCIL_INDEX
:
393 read_stencil_pixels(ctx
, x
, y
, width
, height
, type
, pixels
,
396 case GL_DEPTH_COMPONENT
:
397 read_depth_pixels(ctx
, x
, y
, width
, height
, type
, pixels
,
401 /* all other formats should be color formats */
402 read_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
,
411 * Do error checking of the format/type parameters to glReadPixels and
413 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
415 * \return GL_TRUE if error detected, GL_FALSE if no errors
418 _mesa_error_check_format_type(struct gl_context
*ctx
, GLenum format
,
419 GLenum type
, GLboolean drawing
)
421 const char *readDraw
= drawing
? "Draw" : "Read";
422 const GLboolean reading
= !drawing
;
425 /* state validation should have already been done */
426 ASSERT(ctx
->NewState
== 0x0);
428 /* basic combinations test */
429 err
= _mesa_error_check_format_and_type(ctx
, format
, type
);
430 if (err
!= GL_NO_ERROR
) {
431 _mesa_error(ctx
, err
, "gl%sPixels(format or type)", readDraw
);
435 /* additional checks */
443 case GL_LUMINANCE_ALPHA
:
449 case GL_RED_INTEGER_EXT
:
450 case GL_GREEN_INTEGER_EXT
:
451 case GL_BLUE_INTEGER_EXT
:
452 case GL_ALPHA_INTEGER_EXT
:
453 case GL_RGB_INTEGER_EXT
:
454 case GL_RGBA_INTEGER_EXT
:
455 case GL_BGR_INTEGER_EXT
:
456 case GL_BGRA_INTEGER_EXT
:
457 case GL_LUMINANCE_INTEGER_EXT
:
458 case GL_LUMINANCE_ALPHA_INTEGER_EXT
:
461 if (!_mesa_source_buffer_exists(ctx
, GL_COLOR
)) {
462 _mesa_error(ctx
, GL_INVALID_OPERATION
,
463 "glReadPixels(no color buffer)");
470 if (ctx
->PixelMaps
.ItoR
.Size
== 0 ||
471 ctx
->PixelMaps
.ItoG
.Size
== 0 ||
472 ctx
->PixelMaps
.ItoB
.Size
== 0) {
473 _mesa_error(ctx
, GL_INVALID_OPERATION
,
474 "glDrawPixels(drawing color index pixels into RGB buffer)");
480 if (!_mesa_source_buffer_exists(ctx
, GL_COLOR
)) {
481 _mesa_error(ctx
, GL_INVALID_OPERATION
,
482 "glReadPixels(no color buffer)");
485 /* We no longer support CI-mode color buffers so trying to read
486 * GL_COLOR_INDEX pixels is always an error.
488 _mesa_error(ctx
, GL_INVALID_OPERATION
,
489 "glReadPixels(color buffer is RGB)");
493 case GL_STENCIL_INDEX
:
494 if ((drawing
&& !_mesa_dest_buffer_exists(ctx
, format
)) ||
495 (reading
&& !_mesa_source_buffer_exists(ctx
, format
))) {
496 _mesa_error(ctx
, GL_INVALID_OPERATION
,
497 "gl%sPixels(no stencil buffer)", readDraw
);
501 case GL_DEPTH_COMPONENT
:
502 if ((drawing
&& !_mesa_dest_buffer_exists(ctx
, format
))) {
503 _mesa_error(ctx
, GL_INVALID_OPERATION
,
504 "gl%sPixels(no depth buffer)", readDraw
);
509 /* this should have been caught in _mesa_error_check_format_type() */
510 _mesa_problem(ctx
, "unexpected format in _mesa_%sPixels", readDraw
);
521 _mesa_ReadPixels( GLint x
, GLint y
, GLsizei width
, GLsizei height
,
522 GLenum format
, GLenum type
, GLvoid
*pixels
)
524 GET_CURRENT_CONTEXT(ctx
);
525 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
527 FLUSH_CURRENT(ctx
, 0);
529 if (MESA_VERBOSE
& VERBOSE_API
)
530 _mesa_debug(ctx
, "glReadPixels(%d, %d, %s, %s, %p)\n",
532 _mesa_lookup_enum_by_nr(format
),
533 _mesa_lookup_enum_by_nr(type
),
536 if (width
< 0 || height
< 0) {
537 _mesa_error( ctx
, GL_INVALID_VALUE
,
538 "glReadPixels(width=%d height=%d)", width
, height
);
543 _mesa_update_state(ctx
);
545 if (_mesa_error_check_format_type(ctx
, format
, type
, GL_FALSE
)) {
550 /* Check that the destination format and source buffer are both
551 * integer-valued or both non-integer-valued.
553 if (ctx
->Extensions
.EXT_texture_integer
&& _mesa_is_color_format(format
)) {
554 const struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
555 const GLboolean srcInteger
= _mesa_is_format_integer_color(rb
->Format
);
556 const GLboolean dstInteger
= _mesa_is_integer_format(format
);
557 if (dstInteger
!= srcInteger
) {
558 _mesa_error(ctx
, GL_INVALID_OPERATION
,
559 "glReadPixels(integer / non-integer format mismatch");
564 if (!_mesa_source_buffer_exists(ctx
, format
)) {
565 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glReadPixels(no readbuffer)");
569 if (width
== 0 || height
== 0)
570 return; /* nothing to do */
572 ctx
->Driver
.ReadPixels(ctx
, x
, y
, width
, height
,
573 format
, type
, &ctx
->Pack
, pixels
);