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.
27 #include "bufferobj.h"
31 #include "framebuffer.h"
33 #include "format_unpack.h"
39 #include "glformats.h"
43 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
47 fast_read_depth_pixels( struct gl_context
*ctx
,
49 GLsizei width
, GLsizei height
,
50 GLenum type
, GLvoid
*pixels
,
51 const struct gl_pixelstore_attrib
*packing
)
53 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
54 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
56 int stride
, dstStride
, j
;
58 if (ctx
->Pixel
.DepthScale
!= 1.0 || ctx
->Pixel
.DepthBias
!= 0.0)
61 if (packing
->SwapBytes
)
64 if (_mesa_get_format_datatype(rb
->Format
) != GL_UNSIGNED_NORMALIZED
)
67 if (!((type
== GL_UNSIGNED_SHORT
&& rb
->Format
== MESA_FORMAT_Z16
) ||
68 type
== GL_UNSIGNED_INT
))
71 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
75 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
76 return GL_TRUE
; /* don't bother trying the slow path */
79 dstStride
= _mesa_image_row_stride(packing
, width
, GL_DEPTH_COMPONENT
, type
);
80 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
81 GL_DEPTH_COMPONENT
, type
, 0, 0);
83 for (j
= 0; j
< height
; j
++) {
84 if (type
== GL_UNSIGNED_INT
) {
85 _mesa_unpack_uint_z_row(rb
->Format
, width
, map
, (GLuint
*)dst
);
87 ASSERT(type
== GL_UNSIGNED_SHORT
&& rb
->Format
== MESA_FORMAT_Z16
);
88 memcpy(dst
, map
, width
* 2);
94 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
100 * Read pixels for format=GL_DEPTH_COMPONENT.
103 read_depth_pixels( struct gl_context
*ctx
,
105 GLsizei width
, GLsizei height
,
106 GLenum type
, GLvoid
*pixels
,
107 const struct gl_pixelstore_attrib
*packing
)
109 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
110 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
113 int dstStride
, stride
;
114 GLfloat
*depthValues
;
119 /* clipping should have been done already */
122 ASSERT(x
+ width
<= (GLint
) rb
->Width
);
123 ASSERT(y
+ height
<= (GLint
) rb
->Height
);
125 if (fast_read_depth_pixels(ctx
, x
, y
, width
, height
, type
, pixels
, packing
))
128 dstStride
= _mesa_image_row_stride(packing
, width
, GL_DEPTH_COMPONENT
, type
);
129 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
130 GL_DEPTH_COMPONENT
, type
, 0, 0);
132 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
135 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
139 depthValues
= (GLfloat
*) malloc(width
* sizeof(GLfloat
));
142 /* General case (slower) */
143 for (j
= 0; j
< height
; j
++, y
++) {
144 _mesa_unpack_float_z_row(rb
->Format
, width
, map
, depthValues
);
145 _mesa_pack_depth_span(ctx
, width
, dst
, type
, depthValues
, packing
);
152 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
157 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
162 * Read pixels for format=GL_STENCIL_INDEX.
165 read_stencil_pixels( struct gl_context
*ctx
,
167 GLsizei width
, GLsizei height
,
168 GLenum type
, GLvoid
*pixels
,
169 const struct gl_pixelstore_attrib
*packing
)
171 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
172 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
174 GLubyte
*map
, *stencil
;
180 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
183 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
187 stencil
= (GLubyte
*) malloc(width
* sizeof(GLubyte
));
190 /* process image row by row */
191 for (j
= 0; j
< height
; j
++) {
194 _mesa_unpack_ubyte_stencil_row(rb
->Format
, width
, map
, stencil
);
195 dest
= _mesa_image_address2d(packing
, pixels
, width
, height
,
196 GL_STENCIL_INDEX
, type
, j
, 0);
198 _mesa_pack_stencil_span(ctx
, width
, type
, dest
, stencil
, packing
);
204 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
209 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
214 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
215 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
218 fast_read_rgba_pixels_memcpy( struct gl_context
*ctx
,
220 GLsizei width
, GLsizei height
,
221 GLenum format
, GLenum type
,
223 const struct gl_pixelstore_attrib
*packing
,
224 GLbitfield transferOps
)
226 struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
228 int dstStride
, stride
, j
, texelBytes
;
229 GLboolean swizzle_rb
= GL_FALSE
, copy_xrgb
= GL_FALSE
;
231 /* XXX we could check for other swizzle/special cases here as needed */
232 if (rb
->Format
== MESA_FORMAT_RGBA8888_REV
&&
234 type
== GL_UNSIGNED_INT_8_8_8_8_REV
&&
235 !ctx
->Pack
.SwapBytes
) {
236 swizzle_rb
= GL_TRUE
;
238 else if (rb
->Format
== MESA_FORMAT_XRGB8888
&&
240 type
== GL_UNSIGNED_INT_8_8_8_8_REV
&&
241 !ctx
->Pack
.SwapBytes
) {
244 else if (!_mesa_format_matches_format_and_type(rb
->Format
, format
, type
,
245 ctx
->Pack
.SwapBytes
))
248 /* If the format is unsigned normalized then we can ignore clamping
249 * because the values are already in the range [0,1] so it won't
250 * have any effect anyway.
252 if (_mesa_get_format_datatype(rb
->Format
) == GL_UNSIGNED_NORMALIZED
)
253 transferOps
&= ~IMAGE_CLAMP_BIT
;
258 dstStride
= _mesa_image_row_stride(packing
, width
, format
, type
);
259 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
262 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
265 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
266 return GL_TRUE
; /* don't bother trying the slow path */
269 texelBytes
= _mesa_get_format_bytes(rb
->Format
);
273 for (j
= 0; j
< height
; j
++) {
275 for (i
= 0; i
< width
; i
++) {
276 GLuint
*dst4
= (GLuint
*) dst
, *map4
= (GLuint
*) map
;
277 GLuint pixel
= map4
[i
];
278 dst4
[i
] = (pixel
& 0xff00ff00)
279 | ((pixel
& 0x00ff0000) >> 16)
280 | ((pixel
& 0x000000ff) << 16);
285 } else if (copy_xrgb
) {
286 /* convert xrgb -> argb */
287 for (j
= 0; j
< height
; j
++) {
288 GLuint
*dst4
= (GLuint
*) dst
, *map4
= (GLuint
*) map
;
290 for (i
= 0; i
< width
; i
++) {
291 dst4
[i
] = map4
[i
] | 0xff000000; /* set A=0xff */
298 for (j
= 0; j
< height
; j
++) {
299 memcpy(dst
, map
, width
* texelBytes
);
305 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
311 slow_read_rgba_pixels( struct gl_context
*ctx
,
313 GLsizei width
, GLsizei height
,
314 GLenum format
, GLenum type
,
316 const struct gl_pixelstore_attrib
*packing
,
317 GLbitfield transferOps
)
319 struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
320 const gl_format rbFormat
= _mesa_get_srgb_format_linear(rb
->Format
);
323 int dstStride
, stride
, j
;
325 dstStride
= _mesa_image_row_stride(packing
, width
, format
, type
);
326 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
, width
, height
,
329 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
332 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
336 rgba
= malloc(width
* MAX_PIXEL_BYTES
);
340 for (j
= 0; j
< height
; j
++) {
341 if (_mesa_is_enum_format_integer(format
)) {
342 _mesa_unpack_uint_rgba_row(rbFormat
, width
, map
, (GLuint (*)[4]) rgba
);
343 _mesa_rebase_rgba_uint(width
, (GLuint (*)[4]) rgba
,
345 _mesa_pack_rgba_span_int(ctx
, width
, (GLuint (*)[4]) rgba
, format
,
348 _mesa_unpack_rgba_row(rbFormat
, width
, map
, (GLfloat (*)[4]) rgba
);
349 _mesa_rebase_rgba_float(width
, (GLfloat (*)[4]) rgba
,
351 _mesa_pack_rgba_span_float(ctx
, width
, (GLfloat (*)[4]) rgba
, format
,
352 type
, dst
, packing
, transferOps
);
361 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
365 * Read R, G, B, A, RGB, L, or LA pixels.
368 read_rgba_pixels( struct gl_context
*ctx
,
370 GLsizei width
, GLsizei height
,
371 GLenum format
, GLenum type
, GLvoid
*pixels
,
372 const struct gl_pixelstore_attrib
*packing
)
374 GLbitfield transferOps
= ctx
->_ImageTransferState
;
375 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
376 struct gl_renderbuffer
*rb
= fb
->_ColorReadBuffer
;
381 if ((ctx
->Color
._ClampReadColor
== GL_TRUE
|| type
!= GL_FLOAT
) &&
382 !_mesa_is_enum_format_integer(format
)) {
383 transferOps
|= IMAGE_CLAMP_BIT
;
386 /* Try the optimized paths first. */
387 if (fast_read_rgba_pixels_memcpy(ctx
, x
, y
, width
, height
,
388 format
, type
, pixels
, packing
,
393 slow_read_rgba_pixels(ctx
, x
, y
, width
, height
,
394 format
, type
, pixels
, packing
, transferOps
);
398 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
399 * data (possibly swapping 8/24 vs 24/8 as we go).
402 fast_read_depth_stencil_pixels(struct gl_context
*ctx
,
404 GLsizei width
, GLsizei height
,
405 GLubyte
*dst
, int dstStride
)
407 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
408 struct gl_renderbuffer
*rb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
409 struct gl_renderbuffer
*stencilRb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
416 if (rb
->Format
!= MESA_FORMAT_Z24_S8
&&
417 rb
->Format
!= MESA_FORMAT_S8_Z24
)
420 ctx
->Driver
.MapRenderbuffer(ctx
, rb
, x
, y
, width
, height
, GL_MAP_READ_BIT
,
423 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
424 return GL_TRUE
; /* don't bother trying the slow path */
427 for (i
= 0; i
< height
; i
++) {
428 _mesa_unpack_uint_24_8_depth_stencil_row(rb
->Format
, width
,
434 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
441 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
442 * copy the integer data directly instead of converting depth to float and
446 fast_read_depth_stencil_pixels_separate(struct gl_context
*ctx
,
448 GLsizei width
, GLsizei height
,
449 uint32_t *dst
, int dstStride
)
451 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
452 struct gl_renderbuffer
*depthRb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
453 struct gl_renderbuffer
*stencilRb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
454 GLubyte
*depthMap
, *stencilMap
, *stencilVals
;
455 int depthStride
, stencilStride
, i
, j
;
457 if (_mesa_get_format_datatype(depthRb
->Format
) != GL_UNSIGNED_NORMALIZED
)
460 ctx
->Driver
.MapRenderbuffer(ctx
, depthRb
, x
, y
, width
, height
,
461 GL_MAP_READ_BIT
, &depthMap
, &depthStride
);
463 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
464 return GL_TRUE
; /* don't bother trying the slow path */
467 ctx
->Driver
.MapRenderbuffer(ctx
, stencilRb
, x
, y
, width
, height
,
468 GL_MAP_READ_BIT
, &stencilMap
, &stencilStride
);
470 ctx
->Driver
.UnmapRenderbuffer(ctx
, depthRb
);
471 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
472 return GL_TRUE
; /* don't bother trying the slow path */
475 stencilVals
= (GLubyte
*) malloc(width
* sizeof(GLubyte
));
478 for (j
= 0; j
< height
; j
++) {
479 _mesa_unpack_uint_z_row(depthRb
->Format
, width
, depthMap
, dst
);
480 _mesa_unpack_ubyte_stencil_row(stencilRb
->Format
, width
,
481 stencilMap
, stencilVals
);
483 for (i
= 0; i
< width
; i
++) {
484 dst
[i
] = (dst
[i
] & 0xffffff00) | stencilVals
[i
];
487 depthMap
+= depthStride
;
488 stencilMap
+= stencilStride
;
489 dst
+= dstStride
/ 4;
493 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
498 ctx
->Driver
.UnmapRenderbuffer(ctx
, depthRb
);
499 ctx
->Driver
.UnmapRenderbuffer(ctx
, stencilRb
);
505 slow_read_depth_stencil_pixels_separate(struct gl_context
*ctx
,
507 GLsizei width
, GLsizei height
,
509 const struct gl_pixelstore_attrib
*packing
,
510 GLubyte
*dst
, int dstStride
)
512 struct gl_framebuffer
*fb
= ctx
->ReadBuffer
;
513 struct gl_renderbuffer
*depthRb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
514 struct gl_renderbuffer
*stencilRb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
515 GLubyte
*depthMap
, *stencilMap
;
516 int depthStride
, stencilStride
, j
;
517 GLubyte
*stencilVals
;
521 /* The depth and stencil buffers might be separate, or a single buffer.
522 * If one buffer, only map it once.
524 ctx
->Driver
.MapRenderbuffer(ctx
, depthRb
, x
, y
, width
, height
,
525 GL_MAP_READ_BIT
, &depthMap
, &depthStride
);
527 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
531 if (stencilRb
!= depthRb
) {
532 ctx
->Driver
.MapRenderbuffer(ctx
, stencilRb
, x
, y
, width
, height
,
533 GL_MAP_READ_BIT
, &stencilMap
,
536 ctx
->Driver
.UnmapRenderbuffer(ctx
, depthRb
);
537 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
542 stencilMap
= depthMap
;
543 stencilStride
= depthStride
;
546 stencilVals
= (GLubyte
*) malloc(width
* sizeof(GLubyte
));
547 depthVals
= (GLfloat
*) malloc(width
* sizeof(GLfloat
));
549 if (stencilVals
&& depthVals
) {
550 for (j
= 0; j
< height
; j
++) {
551 _mesa_unpack_float_z_row(depthRb
->Format
, width
, depthMap
, depthVals
);
552 _mesa_unpack_ubyte_stencil_row(stencilRb
->Format
, width
,
553 stencilMap
, stencilVals
);
555 _mesa_pack_depth_stencil_span(ctx
, width
, type
, (GLuint
*)dst
,
556 depthVals
, stencilVals
, packing
);
558 depthMap
+= depthStride
;
559 stencilMap
+= stencilStride
;
564 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glReadPixels");
570 ctx
->Driver
.UnmapRenderbuffer(ctx
, depthRb
);
571 if (stencilRb
!= depthRb
) {
572 ctx
->Driver
.UnmapRenderbuffer(ctx
, stencilRb
);
578 * Read combined depth/stencil values.
579 * We'll have already done error checking to be sure the expected
580 * depth and stencil buffers really exist.
583 read_depth_stencil_pixels(struct gl_context
*ctx
,
585 GLsizei width
, GLsizei height
,
586 GLenum type
, GLvoid
*pixels
,
587 const struct gl_pixelstore_attrib
*packing
)
589 const GLboolean scaleOrBias
590 = ctx
->Pixel
.DepthScale
!= 1.0 || ctx
->Pixel
.DepthBias
!= 0.0;
591 const GLboolean stencilTransfer
= ctx
->Pixel
.IndexShift
592 || ctx
->Pixel
.IndexOffset
|| ctx
->Pixel
.MapStencilFlag
;
596 dst
= (GLubyte
*) _mesa_image_address2d(packing
, pixels
,
598 GL_DEPTH_STENCIL_EXT
,
600 dstStride
= _mesa_image_row_stride(packing
, width
,
601 GL_DEPTH_STENCIL_EXT
, type
);
603 /* Fast 24/8 reads. */
604 if (type
== GL_UNSIGNED_INT_24_8
&&
605 !scaleOrBias
&& !stencilTransfer
&& !packing
->SwapBytes
) {
606 if (fast_read_depth_stencil_pixels(ctx
, x
, y
, width
, height
,
610 if (fast_read_depth_stencil_pixels_separate(ctx
, x
, y
, width
, height
,
611 (uint32_t *)dst
, dstStride
))
615 slow_read_depth_stencil_pixels_separate(ctx
, x
, y
, width
, height
,
623 * Software fallback routine for ctx->Driver.ReadPixels().
624 * By time we get here, all error checking will have been done.
627 _mesa_readpixels(struct gl_context
*ctx
,
628 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
629 GLenum format
, GLenum type
,
630 const struct gl_pixelstore_attrib
*packing
,
633 struct gl_pixelstore_attrib clippedPacking
= *packing
;
636 _mesa_update_state(ctx
);
638 /* Do all needed clipping here, so that we can forget about it later */
639 if (_mesa_clip_readpixels(ctx
, &x
, &y
, &width
, &height
, &clippedPacking
)) {
641 pixels
= _mesa_map_pbo_dest(ctx
, &clippedPacking
, pixels
);
645 case GL_STENCIL_INDEX
:
646 read_stencil_pixels(ctx
, x
, y
, width
, height
, type
, pixels
,
649 case GL_DEPTH_COMPONENT
:
650 read_depth_pixels(ctx
, x
, y
, width
, height
, type
, pixels
,
653 case GL_DEPTH_STENCIL_EXT
:
654 read_depth_stencil_pixels(ctx
, x
, y
, width
, height
, type
, pixels
,
658 /* all other formats should be color formats */
659 read_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
,
663 _mesa_unmap_pbo_dest(ctx
, &clippedPacking
);
670 _mesa_ReadnPixelsARB( GLint x
, GLint y
, GLsizei width
, GLsizei height
,
671 GLenum format
, GLenum type
, GLsizei bufSize
,
676 GET_CURRENT_CONTEXT(ctx
);
677 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
);
679 FLUSH_CURRENT(ctx
, 0);
681 if (MESA_VERBOSE
& VERBOSE_API
)
682 _mesa_debug(ctx
, "glReadPixels(%d, %d, %s, %s, %p)\n",
684 _mesa_lookup_enum_by_nr(format
),
685 _mesa_lookup_enum_by_nr(type
),
688 if (width
< 0 || height
< 0) {
689 _mesa_error( ctx
, GL_INVALID_VALUE
,
690 "glReadPixels(width=%d height=%d)", width
, height
);
695 _mesa_update_state(ctx
);
697 err
= _mesa_error_check_format_and_type(ctx
, format
, type
);
698 if (err
!= GL_NO_ERROR
) {
699 _mesa_error(ctx
, err
, "glReadPixels(invalid format %s and/or type %s)",
700 _mesa_lookup_enum_by_nr(format
),
701 _mesa_lookup_enum_by_nr(type
));
705 if (ctx
->ReadBuffer
->_Status
!= GL_FRAMEBUFFER_COMPLETE_EXT
) {
706 _mesa_error(ctx
, GL_INVALID_FRAMEBUFFER_OPERATION_EXT
,
707 "glReadPixels(incomplete framebuffer)" );
711 /* Check that the destination format and source buffer are both
712 * integer-valued or both non-integer-valued.
714 if (ctx
->Extensions
.EXT_texture_integer
&& _mesa_is_color_format(format
)) {
715 const struct gl_renderbuffer
*rb
= ctx
->ReadBuffer
->_ColorReadBuffer
;
716 const GLboolean srcInteger
= _mesa_is_format_integer_color(rb
->Format
);
717 const GLboolean dstInteger
= _mesa_is_enum_format_integer(format
);
718 if (dstInteger
!= srcInteger
) {
719 _mesa_error(ctx
, GL_INVALID_OPERATION
,
720 "glReadPixels(integer / non-integer format mismatch");
725 if (ctx
->ReadBuffer
->Name
!= 0 && ctx
->ReadBuffer
->Visual
.samples
> 0) {
726 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glReadPixels(multisample FBO)");
730 if (!_mesa_source_buffer_exists(ctx
, format
)) {
731 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glReadPixels(no readbuffer)");
735 if (width
== 0 || height
== 0)
736 return; /* nothing to do */
738 if (!_mesa_validate_pbo_access(2, &ctx
->Pack
, width
, height
, 1,
739 format
, type
, bufSize
, pixels
)) {
740 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
)) {
741 _mesa_error(ctx
, GL_INVALID_OPERATION
,
742 "glReadPixels(out of bounds PBO access)");
744 _mesa_error(ctx
, GL_INVALID_OPERATION
,
745 "glReadnPixelsARB(out of bounds access:"
746 " bufSize (%d) is too small)", bufSize
);
751 if (_mesa_is_bufferobj(ctx
->Pack
.BufferObj
) &&
752 _mesa_bufferobj_mapped(ctx
->Pack
.BufferObj
)) {
753 /* buffer is mapped - that's an error */
754 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glReadPixels(PBO is mapped)");
758 ctx
->Driver
.ReadPixels(ctx
, x
, y
, width
, height
,
759 format
, type
, &ctx
->Pack
, pixels
);
763 _mesa_ReadPixels( GLint x
, GLint y
, GLsizei width
, GLsizei height
,
764 GLenum format
, GLenum type
, GLvoid
*pixels
)
766 _mesa_ReadnPixelsARB(x
, y
, width
, height
, format
, type
, INT_MAX
, pixels
);