readpix.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg#include "glheader.h" 26848b8605Smrg#include "imports.h" 27848b8605Smrg#include "blend.h" 28848b8605Smrg#include "bufferobj.h" 29848b8605Smrg#include "context.h" 30848b8605Smrg#include "enums.h" 31848b8605Smrg#include "readpix.h" 32848b8605Smrg#include "framebuffer.h" 33848b8605Smrg#include "formats.h" 34848b8605Smrg#include "format_unpack.h" 35848b8605Smrg#include "image.h" 36848b8605Smrg#include "mtypes.h" 37848b8605Smrg#include "pack.h" 38848b8605Smrg#include "pbo.h" 39848b8605Smrg#include "state.h" 40848b8605Smrg#include "glformats.h" 41848b8605Smrg#include "fbobject.h" 42848b8605Smrg 43848b8605Smrg 44848b8605Smrg/** 45848b8605Smrg * Return true if the conversion L=R+G+B is needed. 46848b8605Smrg */ 47848b8605Smrgstatic GLboolean 48848b8605Smrgneed_rgb_to_luminance_conversion(mesa_format texFormat, GLenum format) 49848b8605Smrg{ 50848b8605Smrg GLenum baseTexFormat = _mesa_get_format_base_format(texFormat); 51848b8605Smrg 52848b8605Smrg return (baseTexFormat == GL_RG || 53848b8605Smrg baseTexFormat == GL_RGB || 54848b8605Smrg baseTexFormat == GL_RGBA) && 55848b8605Smrg (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA); 56848b8605Smrg} 57848b8605Smrg 58848b8605Smrg 59848b8605Smrg/** 60848b8605Smrg * Return transfer op flags for this ReadPixels operation. 61848b8605Smrg */ 62848b8605Smrgstatic GLbitfield 63848b8605Smrgget_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, 64848b8605Smrg GLenum format, GLenum type, GLboolean uses_blit) 65848b8605Smrg{ 66848b8605Smrg GLbitfield transferOps = ctx->_ImageTransferState; 67848b8605Smrg 68848b8605Smrg if (format == GL_DEPTH_COMPONENT || 69848b8605Smrg format == GL_DEPTH_STENCIL || 70848b8605Smrg format == GL_STENCIL_INDEX) { 71848b8605Smrg return 0; 72848b8605Smrg } 73848b8605Smrg 74848b8605Smrg /* Pixel transfer ops (scale, bias, table lookup) do not apply 75848b8605Smrg * to integer formats. 76848b8605Smrg */ 77848b8605Smrg if (_mesa_is_enum_format_integer(format)) { 78848b8605Smrg return 0; 79848b8605Smrg } 80848b8605Smrg 81848b8605Smrg if (uses_blit) { 82848b8605Smrg /* For blit-based ReadPixels packing, the clamping is done automatically 83848b8605Smrg * unless the type is float. */ 84848b8605Smrg if (_mesa_get_clamp_read_color(ctx) && 85848b8605Smrg (type == GL_FLOAT || type == GL_HALF_FLOAT)) { 86848b8605Smrg transferOps |= IMAGE_CLAMP_BIT; 87848b8605Smrg } 88848b8605Smrg } 89848b8605Smrg else { 90848b8605Smrg /* For CPU-based ReadPixels packing, the clamping must always be done 91848b8605Smrg * for non-float types, */ 92848b8605Smrg if (_mesa_get_clamp_read_color(ctx) || 93848b8605Smrg (type != GL_FLOAT && type != GL_HALF_FLOAT)) { 94848b8605Smrg transferOps |= IMAGE_CLAMP_BIT; 95848b8605Smrg } 96848b8605Smrg } 97848b8605Smrg 98848b8605Smrg /* If the format is unsigned normalized, we can ignore clamping 99848b8605Smrg * because the values are already in the range [0,1] so it won't 100848b8605Smrg * have any effect anyway. 101848b8605Smrg */ 102848b8605Smrg if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED && 103848b8605Smrg !need_rgb_to_luminance_conversion(texFormat, format)) { 104848b8605Smrg transferOps &= ~IMAGE_CLAMP_BIT; 105848b8605Smrg } 106848b8605Smrg 107848b8605Smrg return transferOps; 108848b8605Smrg} 109848b8605Smrg 110848b8605Smrg 111848b8605Smrg/** 112848b8605Smrg * Return true if memcpy cannot be used for ReadPixels. 113848b8605Smrg * 114848b8605Smrg * If uses_blit is true, the function returns true if a simple 3D engine blit 115848b8605Smrg * cannot be used for ReadPixels packing. 116848b8605Smrg * 117848b8605Smrg * NOTE: This doesn't take swizzling and format conversions between 118848b8605Smrg * the readbuffer and the pixel pack buffer into account. 119848b8605Smrg */ 120848b8605SmrgGLboolean 121848b8605Smrg_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format, 122848b8605Smrg GLenum type, GLboolean uses_blit) 123848b8605Smrg{ 124848b8605Smrg struct gl_renderbuffer *rb = 125848b8605Smrg _mesa_get_read_renderbuffer_for_format(ctx, format); 126848b8605Smrg GLenum srcType; 127848b8605Smrg 128848b8605Smrg ASSERT(rb); 129848b8605Smrg 130848b8605Smrg /* There are different rules depending on the base format. */ 131848b8605Smrg switch (format) { 132848b8605Smrg case GL_DEPTH_STENCIL: 133848b8605Smrg return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) || 134848b8605Smrg ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f || 135848b8605Smrg ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || 136848b8605Smrg ctx->Pixel.MapStencilFlag; 137848b8605Smrg 138848b8605Smrg case GL_DEPTH_COMPONENT: 139848b8605Smrg return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f; 140848b8605Smrg 141848b8605Smrg case GL_STENCIL_INDEX: 142848b8605Smrg return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || 143848b8605Smrg ctx->Pixel.MapStencilFlag; 144848b8605Smrg 145848b8605Smrg default: 146848b8605Smrg /* Color formats. */ 147848b8605Smrg if (need_rgb_to_luminance_conversion(rb->Format, format)) { 148848b8605Smrg return GL_TRUE; 149848b8605Smrg } 150848b8605Smrg 151848b8605Smrg /* Conversion between signed and unsigned integers needs masking 152848b8605Smrg * (it isn't just memcpy). */ 153848b8605Smrg srcType = _mesa_get_format_datatype(rb->Format); 154848b8605Smrg 155848b8605Smrg if ((srcType == GL_INT && 156848b8605Smrg (type == GL_UNSIGNED_INT || 157848b8605Smrg type == GL_UNSIGNED_SHORT || 158848b8605Smrg type == GL_UNSIGNED_BYTE)) || 159848b8605Smrg (srcType == GL_UNSIGNED_INT && 160848b8605Smrg (type == GL_INT || 161848b8605Smrg type == GL_SHORT || 162848b8605Smrg type == GL_BYTE))) { 163848b8605Smrg return GL_TRUE; 164848b8605Smrg } 165848b8605Smrg 166848b8605Smrg /* And finally, see if there are any transfer ops. */ 167848b8605Smrg return get_readpixels_transfer_ops(ctx, rb->Format, format, type, 168848b8605Smrg uses_blit) != 0; 169848b8605Smrg } 170848b8605Smrg return GL_FALSE; 171848b8605Smrg} 172848b8605Smrg 173848b8605Smrg 174848b8605Smrgstatic GLboolean 175848b8605Smrgreadpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum type, 176848b8605Smrg const struct gl_pixelstore_attrib *packing) 177848b8605Smrg{ 178848b8605Smrg struct gl_renderbuffer *rb = 179848b8605Smrg _mesa_get_read_renderbuffer_for_format(ctx, format); 180848b8605Smrg 181848b8605Smrg ASSERT(rb); 182848b8605Smrg 183848b8605Smrg if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) { 184848b8605Smrg return GL_FALSE; 185848b8605Smrg } 186848b8605Smrg 187848b8605Smrg /* The base internal format and the base Mesa format must match. */ 188848b8605Smrg if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) { 189848b8605Smrg return GL_FALSE; 190848b8605Smrg } 191848b8605Smrg 192848b8605Smrg /* The Mesa format must match the input format and type. */ 193848b8605Smrg if (!_mesa_format_matches_format_and_type(rb->Format, format, type, 194848b8605Smrg packing->SwapBytes)) { 195848b8605Smrg return GL_FALSE; 196848b8605Smrg } 197848b8605Smrg 198848b8605Smrg return GL_TRUE; 199848b8605Smrg} 200848b8605Smrg 201848b8605Smrg 202848b8605Smrgstatic GLboolean 203848b8605Smrgreadpixels_memcpy(struct gl_context *ctx, 204848b8605Smrg GLint x, GLint y, 205848b8605Smrg GLsizei width, GLsizei height, 206848b8605Smrg GLenum format, GLenum type, 207848b8605Smrg GLvoid *pixels, 208848b8605Smrg const struct gl_pixelstore_attrib *packing) 209848b8605Smrg{ 210848b8605Smrg struct gl_renderbuffer *rb = 211848b8605Smrg _mesa_get_read_renderbuffer_for_format(ctx, format); 212848b8605Smrg GLubyte *dst, *map; 213848b8605Smrg int dstStride, stride, j, texelBytes; 214848b8605Smrg 215848b8605Smrg /* Fail if memcpy cannot be used. */ 216848b8605Smrg if (!readpixels_can_use_memcpy(ctx, format, type, packing)) { 217848b8605Smrg return GL_FALSE; 218848b8605Smrg } 219848b8605Smrg 220848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, format, type); 221848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 222848b8605Smrg format, type, 0, 0); 223848b8605Smrg 224848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 225848b8605Smrg &map, &stride); 226848b8605Smrg if (!map) { 227848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 228848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 229848b8605Smrg } 230848b8605Smrg 231848b8605Smrg texelBytes = _mesa_get_format_bytes(rb->Format); 232848b8605Smrg 233848b8605Smrg /* memcpy*/ 234848b8605Smrg for (j = 0; j < height; j++) { 235848b8605Smrg memcpy(dst, map, width * texelBytes); 236848b8605Smrg dst += dstStride; 237848b8605Smrg map += stride; 238848b8605Smrg } 239848b8605Smrg 240848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 241848b8605Smrg return GL_TRUE; 242848b8605Smrg} 243848b8605Smrg 244848b8605Smrg 245848b8605Smrg/** 246848b8605Smrg * Optimized path for conversion of depth values to GL_DEPTH_COMPONENT, 247848b8605Smrg * GL_UNSIGNED_INT. 248848b8605Smrg */ 249848b8605Smrgstatic GLboolean 250848b8605Smrgread_uint_depth_pixels( struct gl_context *ctx, 251848b8605Smrg GLint x, GLint y, 252848b8605Smrg GLsizei width, GLsizei height, 253848b8605Smrg GLenum type, GLvoid *pixels, 254848b8605Smrg const struct gl_pixelstore_attrib *packing ) 255848b8605Smrg{ 256848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 257848b8605Smrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 258848b8605Smrg GLubyte *map, *dst; 259848b8605Smrg int stride, dstStride, j; 260848b8605Smrg 261848b8605Smrg if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) 262848b8605Smrg return GL_FALSE; 263848b8605Smrg 264848b8605Smrg if (packing->SwapBytes) 265848b8605Smrg return GL_FALSE; 266848b8605Smrg 267848b8605Smrg if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) 268848b8605Smrg return GL_FALSE; 269848b8605Smrg 270848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 271848b8605Smrg &map, &stride); 272848b8605Smrg 273848b8605Smrg if (!map) { 274848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 275848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 276848b8605Smrg } 277848b8605Smrg 278848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); 279848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 280848b8605Smrg GL_DEPTH_COMPONENT, type, 0, 0); 281848b8605Smrg 282848b8605Smrg for (j = 0; j < height; j++) { 283848b8605Smrg _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); 284848b8605Smrg 285848b8605Smrg map += stride; 286848b8605Smrg dst += dstStride; 287848b8605Smrg } 288848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 289848b8605Smrg 290848b8605Smrg return GL_TRUE; 291848b8605Smrg} 292848b8605Smrg 293848b8605Smrg/** 294848b8605Smrg * Read pixels for format=GL_DEPTH_COMPONENT. 295848b8605Smrg */ 296848b8605Smrgstatic void 297848b8605Smrgread_depth_pixels( struct gl_context *ctx, 298848b8605Smrg GLint x, GLint y, 299848b8605Smrg GLsizei width, GLsizei height, 300848b8605Smrg GLenum type, GLvoid *pixels, 301848b8605Smrg const struct gl_pixelstore_attrib *packing ) 302848b8605Smrg{ 303848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 304848b8605Smrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 305848b8605Smrg GLint j; 306848b8605Smrg GLubyte *dst, *map; 307848b8605Smrg int dstStride, stride; 308848b8605Smrg GLfloat *depthValues; 309848b8605Smrg 310848b8605Smrg if (!rb) 311848b8605Smrg return; 312848b8605Smrg 313848b8605Smrg /* clipping should have been done already */ 314848b8605Smrg ASSERT(x >= 0); 315848b8605Smrg ASSERT(y >= 0); 316848b8605Smrg ASSERT(x + width <= (GLint) rb->Width); 317848b8605Smrg ASSERT(y + height <= (GLint) rb->Height); 318848b8605Smrg 319848b8605Smrg if (type == GL_UNSIGNED_INT && 320848b8605Smrg read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) { 321848b8605Smrg return; 322848b8605Smrg } 323848b8605Smrg 324848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); 325848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 326848b8605Smrg GL_DEPTH_COMPONENT, type, 0, 0); 327848b8605Smrg 328848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 329848b8605Smrg &map, &stride); 330848b8605Smrg if (!map) { 331848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 332848b8605Smrg return; 333848b8605Smrg } 334848b8605Smrg 335848b8605Smrg depthValues = malloc(width * sizeof(GLfloat)); 336848b8605Smrg 337848b8605Smrg if (depthValues) { 338848b8605Smrg /* General case (slower) */ 339848b8605Smrg for (j = 0; j < height; j++, y++) { 340848b8605Smrg _mesa_unpack_float_z_row(rb->Format, width, map, depthValues); 341848b8605Smrg _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing); 342848b8605Smrg 343848b8605Smrg dst += dstStride; 344848b8605Smrg map += stride; 345848b8605Smrg } 346848b8605Smrg } 347848b8605Smrg else { 348848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 349848b8605Smrg } 350848b8605Smrg 351848b8605Smrg free(depthValues); 352848b8605Smrg 353848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 354848b8605Smrg} 355848b8605Smrg 356848b8605Smrg 357848b8605Smrg/** 358848b8605Smrg * Read pixels for format=GL_STENCIL_INDEX. 359848b8605Smrg */ 360848b8605Smrgstatic void 361848b8605Smrgread_stencil_pixels( struct gl_context *ctx, 362848b8605Smrg GLint x, GLint y, 363848b8605Smrg GLsizei width, GLsizei height, 364848b8605Smrg GLenum type, GLvoid *pixels, 365848b8605Smrg const struct gl_pixelstore_attrib *packing ) 366848b8605Smrg{ 367848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 368848b8605Smrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 369848b8605Smrg GLint j; 370848b8605Smrg GLubyte *map, *stencil; 371848b8605Smrg GLint stride; 372848b8605Smrg 373848b8605Smrg if (!rb) 374848b8605Smrg return; 375848b8605Smrg 376848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 377848b8605Smrg &map, &stride); 378848b8605Smrg if (!map) { 379848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 380848b8605Smrg return; 381848b8605Smrg } 382848b8605Smrg 383848b8605Smrg stencil = malloc(width * sizeof(GLubyte)); 384848b8605Smrg 385848b8605Smrg if (stencil) { 386848b8605Smrg /* process image row by row */ 387848b8605Smrg for (j = 0; j < height; j++) { 388848b8605Smrg GLvoid *dest; 389848b8605Smrg 390848b8605Smrg _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil); 391848b8605Smrg dest = _mesa_image_address2d(packing, pixels, width, height, 392848b8605Smrg GL_STENCIL_INDEX, type, j, 0); 393848b8605Smrg 394848b8605Smrg _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing); 395848b8605Smrg 396848b8605Smrg map += stride; 397848b8605Smrg } 398848b8605Smrg } 399848b8605Smrg else { 400848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 401848b8605Smrg } 402848b8605Smrg 403848b8605Smrg free(stencil); 404848b8605Smrg 405848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 406848b8605Smrg} 407848b8605Smrg 408848b8605Smrg 409848b8605Smrg/** 410848b8605Smrg * Try to do glReadPixels of RGBA data using swizzle. 411848b8605Smrg * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path) 412848b8605Smrg */ 413848b8605Smrgstatic GLboolean 414848b8605Smrgread_rgba_pixels_swizzle(struct gl_context *ctx, 415848b8605Smrg GLint x, GLint y, 416848b8605Smrg GLsizei width, GLsizei height, 417848b8605Smrg GLenum format, GLenum type, 418848b8605Smrg GLvoid *pixels, 419848b8605Smrg const struct gl_pixelstore_attrib *packing) 420848b8605Smrg{ 421848b8605Smrg struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 422848b8605Smrg GLubyte *dst, *map; 423848b8605Smrg int dstStride, stride, j; 424848b8605Smrg GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE; 425848b8605Smrg 426848b8605Smrg /* XXX we could check for other swizzle/special cases here as needed */ 427848b8605Smrg if (rb->Format == MESA_FORMAT_R8G8B8A8_UNORM && 428848b8605Smrg format == GL_BGRA && 429848b8605Smrg type == GL_UNSIGNED_INT_8_8_8_8_REV && 430848b8605Smrg !ctx->Pack.SwapBytes) { 431848b8605Smrg swizzle_rb = GL_TRUE; 432848b8605Smrg } 433848b8605Smrg else if (rb->Format == MESA_FORMAT_B8G8R8X8_UNORM && 434848b8605Smrg format == GL_BGRA && 435848b8605Smrg type == GL_UNSIGNED_INT_8_8_8_8_REV && 436848b8605Smrg !ctx->Pack.SwapBytes) { 437848b8605Smrg copy_xrgb = GL_TRUE; 438848b8605Smrg } 439848b8605Smrg else { 440848b8605Smrg return GL_FALSE; 441848b8605Smrg } 442848b8605Smrg 443848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, format, type); 444848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 445848b8605Smrg format, type, 0, 0); 446848b8605Smrg 447848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 448848b8605Smrg &map, &stride); 449848b8605Smrg if (!map) { 450848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 451848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 452848b8605Smrg } 453848b8605Smrg 454848b8605Smrg if (swizzle_rb) { 455848b8605Smrg /* swap R/B */ 456848b8605Smrg for (j = 0; j < height; j++) { 457848b8605Smrg int i; 458848b8605Smrg for (i = 0; i < width; i++) { 459848b8605Smrg GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; 460848b8605Smrg GLuint pixel = map4[i]; 461848b8605Smrg dst4[i] = (pixel & 0xff00ff00) 462848b8605Smrg | ((pixel & 0x00ff0000) >> 16) 463848b8605Smrg | ((pixel & 0x000000ff) << 16); 464848b8605Smrg } 465848b8605Smrg dst += dstStride; 466848b8605Smrg map += stride; 467848b8605Smrg } 468848b8605Smrg } else if (copy_xrgb) { 469848b8605Smrg /* convert xrgb -> argb */ 470848b8605Smrg for (j = 0; j < height; j++) { 471848b8605Smrg GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; 472848b8605Smrg int i; 473848b8605Smrg for (i = 0; i < width; i++) { 474848b8605Smrg dst4[i] = map4[i] | 0xff000000; /* set A=0xff */ 475848b8605Smrg } 476848b8605Smrg dst += dstStride; 477848b8605Smrg map += stride; 478848b8605Smrg } 479848b8605Smrg } 480848b8605Smrg 481848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 482848b8605Smrg 483848b8605Smrg return GL_TRUE; 484848b8605Smrg} 485848b8605Smrg 486848b8605Smrgstatic void 487848b8605Smrgslow_read_rgba_pixels( struct gl_context *ctx, 488848b8605Smrg GLint x, GLint y, 489848b8605Smrg GLsizei width, GLsizei height, 490848b8605Smrg GLenum format, GLenum type, 491848b8605Smrg GLvoid *pixels, 492848b8605Smrg const struct gl_pixelstore_attrib *packing, 493848b8605Smrg GLbitfield transferOps ) 494848b8605Smrg{ 495848b8605Smrg struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 496848b8605Smrg const mesa_format rbFormat = _mesa_get_srgb_format_linear(rb->Format); 497848b8605Smrg void *rgba; 498848b8605Smrg GLubyte *dst, *map; 499848b8605Smrg int dstStride, stride, j; 500848b8605Smrg GLboolean dst_is_integer = _mesa_is_enum_format_integer(format); 501848b8605Smrg GLboolean dst_is_uint = _mesa_is_format_unsigned(rbFormat); 502848b8605Smrg 503848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, format, type); 504848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, 505848b8605Smrg format, type, 0, 0); 506848b8605Smrg 507848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 508848b8605Smrg &map, &stride); 509848b8605Smrg if (!map) { 510848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 511848b8605Smrg return; 512848b8605Smrg } 513848b8605Smrg 514848b8605Smrg rgba = malloc(width * MAX_PIXEL_BYTES); 515848b8605Smrg if (!rgba) 516848b8605Smrg goto done; 517848b8605Smrg 518848b8605Smrg for (j = 0; j < height; j++) { 519848b8605Smrg if (dst_is_integer) { 520848b8605Smrg _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba); 521848b8605Smrg _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba, 522848b8605Smrg rb->_BaseFormat); 523848b8605Smrg if (dst_is_uint) { 524848b8605Smrg _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba, format, 525848b8605Smrg type, dst); 526848b8605Smrg } else { 527848b8605Smrg _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba, format, 528848b8605Smrg type, dst); 529848b8605Smrg } 530848b8605Smrg } else { 531848b8605Smrg _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba); 532848b8605Smrg _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba, 533848b8605Smrg rb->_BaseFormat); 534848b8605Smrg _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, 535848b8605Smrg type, dst, packing, transferOps); 536848b8605Smrg } 537848b8605Smrg dst += dstStride; 538848b8605Smrg map += stride; 539848b8605Smrg } 540848b8605Smrg 541848b8605Smrg free(rgba); 542848b8605Smrg 543848b8605Smrgdone: 544848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 545848b8605Smrg} 546848b8605Smrg 547848b8605Smrg/* 548848b8605Smrg * Read R, G, B, A, RGB, L, or LA pixels. 549848b8605Smrg */ 550848b8605Smrgstatic void 551848b8605Smrgread_rgba_pixels( struct gl_context *ctx, 552848b8605Smrg GLint x, GLint y, 553848b8605Smrg GLsizei width, GLsizei height, 554848b8605Smrg GLenum format, GLenum type, GLvoid *pixels, 555848b8605Smrg const struct gl_pixelstore_attrib *packing ) 556848b8605Smrg{ 557848b8605Smrg GLbitfield transferOps; 558848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 559848b8605Smrg struct gl_renderbuffer *rb = fb->_ColorReadBuffer; 560848b8605Smrg 561848b8605Smrg if (!rb) 562848b8605Smrg return; 563848b8605Smrg 564848b8605Smrg transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type, 565848b8605Smrg GL_FALSE); 566848b8605Smrg 567848b8605Smrg /* Try the optimized paths first. */ 568848b8605Smrg if (!transferOps && 569848b8605Smrg read_rgba_pixels_swizzle(ctx, x, y, width, height, 570848b8605Smrg format, type, pixels, packing)) { 571848b8605Smrg return; 572848b8605Smrg } 573848b8605Smrg 574848b8605Smrg slow_read_rgba_pixels(ctx, x, y, width, height, 575848b8605Smrg format, type, pixels, packing, transferOps); 576848b8605Smrg} 577848b8605Smrg 578848b8605Smrg/** 579848b8605Smrg * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the 580848b8605Smrg * data (possibly swapping 8/24 vs 24/8 as we go). 581848b8605Smrg */ 582848b8605Smrgstatic GLboolean 583848b8605Smrgfast_read_depth_stencil_pixels(struct gl_context *ctx, 584848b8605Smrg GLint x, GLint y, 585848b8605Smrg GLsizei width, GLsizei height, 586848b8605Smrg GLubyte *dst, int dstStride) 587848b8605Smrg{ 588848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 589848b8605Smrg struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 590848b8605Smrg struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 591848b8605Smrg GLubyte *map; 592848b8605Smrg int stride, i; 593848b8605Smrg 594848b8605Smrg if (rb != stencilRb) 595848b8605Smrg return GL_FALSE; 596848b8605Smrg 597848b8605Smrg if (rb->Format != MESA_FORMAT_S8_UINT_Z24_UNORM && 598848b8605Smrg rb->Format != MESA_FORMAT_Z24_UNORM_S8_UINT) 599848b8605Smrg return GL_FALSE; 600848b8605Smrg 601848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, 602848b8605Smrg &map, &stride); 603848b8605Smrg if (!map) { 604848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 605848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 606848b8605Smrg } 607848b8605Smrg 608848b8605Smrg for (i = 0; i < height; i++) { 609848b8605Smrg _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width, 610848b8605Smrg map, (GLuint *)dst); 611848b8605Smrg map += stride; 612848b8605Smrg dst += dstStride; 613848b8605Smrg } 614848b8605Smrg 615848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, rb); 616848b8605Smrg 617848b8605Smrg return GL_TRUE; 618848b8605Smrg} 619848b8605Smrg 620848b8605Smrg 621848b8605Smrg/** 622848b8605Smrg * For non-float-depth and stencil buffers being read as 24/8 depth/stencil, 623848b8605Smrg * copy the integer data directly instead of converting depth to float and 624848b8605Smrg * re-packing. 625848b8605Smrg */ 626848b8605Smrgstatic GLboolean 627848b8605Smrgfast_read_depth_stencil_pixels_separate(struct gl_context *ctx, 628848b8605Smrg GLint x, GLint y, 629848b8605Smrg GLsizei width, GLsizei height, 630848b8605Smrg uint32_t *dst, int dstStride) 631848b8605Smrg{ 632848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 633848b8605Smrg struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 634848b8605Smrg struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 635848b8605Smrg GLubyte *depthMap, *stencilMap, *stencilVals; 636848b8605Smrg int depthStride, stencilStride, i, j; 637848b8605Smrg 638848b8605Smrg if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED) 639848b8605Smrg return GL_FALSE; 640848b8605Smrg 641848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, 642848b8605Smrg GL_MAP_READ_BIT, &depthMap, &depthStride); 643848b8605Smrg if (!depthMap) { 644848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 645848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 646848b8605Smrg } 647848b8605Smrg 648848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, 649848b8605Smrg GL_MAP_READ_BIT, &stencilMap, &stencilStride); 650848b8605Smrg if (!stencilMap) { 651848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 652848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 653848b8605Smrg return GL_TRUE; /* don't bother trying the slow path */ 654848b8605Smrg } 655848b8605Smrg 656848b8605Smrg stencilVals = malloc(width * sizeof(GLubyte)); 657848b8605Smrg 658848b8605Smrg if (stencilVals) { 659848b8605Smrg for (j = 0; j < height; j++) { 660848b8605Smrg _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst); 661848b8605Smrg _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, 662848b8605Smrg stencilMap, stencilVals); 663848b8605Smrg 664848b8605Smrg for (i = 0; i < width; i++) { 665848b8605Smrg dst[i] = (dst[i] & 0xffffff00) | stencilVals[i]; 666848b8605Smrg } 667848b8605Smrg 668848b8605Smrg depthMap += depthStride; 669848b8605Smrg stencilMap += stencilStride; 670848b8605Smrg dst += dstStride / 4; 671848b8605Smrg } 672848b8605Smrg } 673848b8605Smrg else { 674848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 675848b8605Smrg } 676848b8605Smrg 677848b8605Smrg free(stencilVals); 678848b8605Smrg 679848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 680848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); 681848b8605Smrg 682848b8605Smrg return GL_TRUE; 683848b8605Smrg} 684848b8605Smrg 685848b8605Smrgstatic void 686848b8605Smrgslow_read_depth_stencil_pixels_separate(struct gl_context *ctx, 687848b8605Smrg GLint x, GLint y, 688848b8605Smrg GLsizei width, GLsizei height, 689848b8605Smrg GLenum type, 690848b8605Smrg const struct gl_pixelstore_attrib *packing, 691848b8605Smrg GLubyte *dst, int dstStride) 692848b8605Smrg{ 693848b8605Smrg struct gl_framebuffer *fb = ctx->ReadBuffer; 694848b8605Smrg struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 695848b8605Smrg struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 696848b8605Smrg GLubyte *depthMap, *stencilMap; 697848b8605Smrg int depthStride, stencilStride, j; 698848b8605Smrg GLubyte *stencilVals; 699848b8605Smrg GLfloat *depthVals; 700848b8605Smrg 701848b8605Smrg 702848b8605Smrg /* The depth and stencil buffers might be separate, or a single buffer. 703848b8605Smrg * If one buffer, only map it once. 704848b8605Smrg */ 705848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, 706848b8605Smrg GL_MAP_READ_BIT, &depthMap, &depthStride); 707848b8605Smrg if (!depthMap) { 708848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 709848b8605Smrg return; 710848b8605Smrg } 711848b8605Smrg 712848b8605Smrg if (stencilRb != depthRb) { 713848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, 714848b8605Smrg GL_MAP_READ_BIT, &stencilMap, 715848b8605Smrg &stencilStride); 716848b8605Smrg if (!stencilMap) { 717848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 718848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 719848b8605Smrg return; 720848b8605Smrg } 721848b8605Smrg } 722848b8605Smrg else { 723848b8605Smrg stencilMap = depthMap; 724848b8605Smrg stencilStride = depthStride; 725848b8605Smrg } 726848b8605Smrg 727848b8605Smrg stencilVals = malloc(width * sizeof(GLubyte)); 728848b8605Smrg depthVals = malloc(width * sizeof(GLfloat)); 729848b8605Smrg 730848b8605Smrg if (stencilVals && depthVals) { 731848b8605Smrg for (j = 0; j < height; j++) { 732848b8605Smrg _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals); 733848b8605Smrg _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, 734848b8605Smrg stencilMap, stencilVals); 735848b8605Smrg 736848b8605Smrg _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst, 737848b8605Smrg depthVals, stencilVals, packing); 738848b8605Smrg 739848b8605Smrg depthMap += depthStride; 740848b8605Smrg stencilMap += stencilStride; 741848b8605Smrg dst += dstStride; 742848b8605Smrg } 743848b8605Smrg } 744848b8605Smrg else { 745848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); 746848b8605Smrg } 747848b8605Smrg 748848b8605Smrg free(stencilVals); 749848b8605Smrg free(depthVals); 750848b8605Smrg 751848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, depthRb); 752848b8605Smrg if (stencilRb != depthRb) { 753848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); 754848b8605Smrg } 755848b8605Smrg} 756848b8605Smrg 757848b8605Smrg 758848b8605Smrg/** 759848b8605Smrg * Read combined depth/stencil values. 760848b8605Smrg * We'll have already done error checking to be sure the expected 761848b8605Smrg * depth and stencil buffers really exist. 762848b8605Smrg */ 763848b8605Smrgstatic void 764848b8605Smrgread_depth_stencil_pixels(struct gl_context *ctx, 765848b8605Smrg GLint x, GLint y, 766848b8605Smrg GLsizei width, GLsizei height, 767848b8605Smrg GLenum type, GLvoid *pixels, 768848b8605Smrg const struct gl_pixelstore_attrib *packing ) 769848b8605Smrg{ 770848b8605Smrg const GLboolean scaleOrBias 771848b8605Smrg = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; 772848b8605Smrg const GLboolean stencilTransfer = ctx->Pixel.IndexShift 773848b8605Smrg || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; 774848b8605Smrg GLubyte *dst; 775848b8605Smrg int dstStride; 776848b8605Smrg 777848b8605Smrg dst = (GLubyte *) _mesa_image_address2d(packing, pixels, 778848b8605Smrg width, height, 779848b8605Smrg GL_DEPTH_STENCIL_EXT, 780848b8605Smrg type, 0, 0); 781848b8605Smrg dstStride = _mesa_image_row_stride(packing, width, 782848b8605Smrg GL_DEPTH_STENCIL_EXT, type); 783848b8605Smrg 784848b8605Smrg /* Fast 24/8 reads. */ 785848b8605Smrg if (type == GL_UNSIGNED_INT_24_8 && 786848b8605Smrg !scaleOrBias && !stencilTransfer && !packing->SwapBytes) { 787848b8605Smrg if (fast_read_depth_stencil_pixels(ctx, x, y, width, height, 788848b8605Smrg dst, dstStride)) 789848b8605Smrg return; 790848b8605Smrg 791848b8605Smrg if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height, 792848b8605Smrg (uint32_t *)dst, dstStride)) 793848b8605Smrg return; 794848b8605Smrg } 795848b8605Smrg 796848b8605Smrg slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height, 797848b8605Smrg type, packing, 798848b8605Smrg dst, dstStride); 799848b8605Smrg} 800848b8605Smrg 801848b8605Smrg 802848b8605Smrg 803848b8605Smrg/** 804848b8605Smrg * Software fallback routine for ctx->Driver.ReadPixels(). 805848b8605Smrg * By time we get here, all error checking will have been done. 806848b8605Smrg */ 807848b8605Smrgvoid 808848b8605Smrg_mesa_readpixels(struct gl_context *ctx, 809848b8605Smrg GLint x, GLint y, GLsizei width, GLsizei height, 810848b8605Smrg GLenum format, GLenum type, 811848b8605Smrg const struct gl_pixelstore_attrib *packing, 812848b8605Smrg GLvoid *pixels) 813848b8605Smrg{ 814848b8605Smrg struct gl_pixelstore_attrib clippedPacking = *packing; 815848b8605Smrg 816848b8605Smrg if (ctx->NewState) 817848b8605Smrg _mesa_update_state(ctx); 818848b8605Smrg 819848b8605Smrg /* Do all needed clipping here, so that we can forget about it later */ 820848b8605Smrg if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { 821848b8605Smrg 822848b8605Smrg pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels); 823848b8605Smrg 824848b8605Smrg if (pixels) { 825848b8605Smrg /* Try memcpy first. */ 826848b8605Smrg if (readpixels_memcpy(ctx, x, y, width, height, format, type, 827848b8605Smrg pixels, packing)) { 828848b8605Smrg _mesa_unmap_pbo_dest(ctx, &clippedPacking); 829848b8605Smrg return; 830848b8605Smrg } 831848b8605Smrg 832848b8605Smrg /* Otherwise take the slow path. */ 833848b8605Smrg switch (format) { 834848b8605Smrg case GL_STENCIL_INDEX: 835848b8605Smrg read_stencil_pixels(ctx, x, y, width, height, type, pixels, 836848b8605Smrg &clippedPacking); 837848b8605Smrg break; 838848b8605Smrg case GL_DEPTH_COMPONENT: 839848b8605Smrg read_depth_pixels(ctx, x, y, width, height, type, pixels, 840848b8605Smrg &clippedPacking); 841848b8605Smrg break; 842848b8605Smrg case GL_DEPTH_STENCIL_EXT: 843848b8605Smrg read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, 844848b8605Smrg &clippedPacking); 845848b8605Smrg break; 846848b8605Smrg default: 847848b8605Smrg /* all other formats should be color formats */ 848848b8605Smrg read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, 849848b8605Smrg &clippedPacking); 850848b8605Smrg } 851848b8605Smrg 852848b8605Smrg _mesa_unmap_pbo_dest(ctx, &clippedPacking); 853848b8605Smrg } 854848b8605Smrg } 855848b8605Smrg} 856848b8605Smrg 857848b8605Smrg 858848b8605Smrgstatic GLenum 859848b8605Smrgread_pixels_es3_error_check(GLenum format, GLenum type, 860848b8605Smrg const struct gl_renderbuffer *rb) 861848b8605Smrg{ 862848b8605Smrg const GLenum internalFormat = rb->InternalFormat; 863848b8605Smrg const GLenum data_type = _mesa_get_format_datatype(rb->Format); 864848b8605Smrg GLboolean is_unsigned_int = GL_FALSE; 865848b8605Smrg GLboolean is_signed_int = GL_FALSE; 866848b8605Smrg 867848b8605Smrg if (!_mesa_is_color_format(internalFormat)) { 868848b8605Smrg return GL_INVALID_OPERATION; 869848b8605Smrg } 870848b8605Smrg 871848b8605Smrg is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat); 872848b8605Smrg if (!is_unsigned_int) { 873848b8605Smrg is_signed_int = _mesa_is_enum_format_signed_int(internalFormat); 874848b8605Smrg } 875848b8605Smrg 876848b8605Smrg switch (format) { 877848b8605Smrg case GL_RGBA: 878848b8605Smrg if (type == GL_FLOAT && data_type == GL_FLOAT) 879848b8605Smrg return GL_NO_ERROR; /* EXT_color_buffer_float */ 880848b8605Smrg if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED) 881848b8605Smrg return GL_NO_ERROR; 882848b8605Smrg if (internalFormat == GL_RGB10_A2 && 883848b8605Smrg type == GL_UNSIGNED_INT_2_10_10_10_REV) 884848b8605Smrg return GL_NO_ERROR; 885848b8605Smrg if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE) 886848b8605Smrg return GL_NO_ERROR; 887848b8605Smrg break; 888848b8605Smrg case GL_BGRA: 889848b8605Smrg /* GL_EXT_read_format_bgra */ 890848b8605Smrg if (type == GL_UNSIGNED_BYTE || 891848b8605Smrg type == GL_UNSIGNED_SHORT_4_4_4_4_REV || 892848b8605Smrg type == GL_UNSIGNED_SHORT_1_5_5_5_REV) 893848b8605Smrg return GL_NO_ERROR; 894848b8605Smrg break; 895848b8605Smrg case GL_RGBA_INTEGER: 896848b8605Smrg if ((is_signed_int && type == GL_INT) || 897848b8605Smrg (is_unsigned_int && type == GL_UNSIGNED_INT)) 898848b8605Smrg return GL_NO_ERROR; 899848b8605Smrg break; 900848b8605Smrg } 901848b8605Smrg 902848b8605Smrg return GL_INVALID_OPERATION; 903848b8605Smrg} 904848b8605Smrg 905848b8605Smrg 906848b8605Smrgvoid GLAPIENTRY 907848b8605Smrg_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, 908848b8605Smrg GLenum format, GLenum type, GLsizei bufSize, 909848b8605Smrg GLvoid *pixels ) 910848b8605Smrg{ 911848b8605Smrg GLenum err = GL_NO_ERROR; 912848b8605Smrg struct gl_renderbuffer *rb; 913848b8605Smrg 914848b8605Smrg GET_CURRENT_CONTEXT(ctx); 915848b8605Smrg 916848b8605Smrg FLUSH_VERTICES(ctx, 0); 917848b8605Smrg FLUSH_CURRENT(ctx, 0); 918848b8605Smrg 919848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 920848b8605Smrg _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", 921848b8605Smrg width, height, 922848b8605Smrg _mesa_lookup_enum_by_nr(format), 923848b8605Smrg _mesa_lookup_enum_by_nr(type), 924848b8605Smrg pixels); 925848b8605Smrg 926848b8605Smrg if (width < 0 || height < 0) { 927848b8605Smrg _mesa_error( ctx, GL_INVALID_VALUE, 928848b8605Smrg "glReadPixels(width=%d height=%d)", width, height ); 929848b8605Smrg return; 930848b8605Smrg } 931848b8605Smrg 932848b8605Smrg if (ctx->NewState) 933848b8605Smrg _mesa_update_state(ctx); 934848b8605Smrg 935848b8605Smrg if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 936848b8605Smrg _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 937848b8605Smrg "glReadPixels(incomplete framebuffer)" ); 938848b8605Smrg return; 939848b8605Smrg } 940848b8605Smrg 941848b8605Smrg rb = _mesa_get_read_renderbuffer_for_format(ctx, format); 942848b8605Smrg if (rb == NULL) { 943848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 944848b8605Smrg "glReadPixels(read buffer)"); 945848b8605Smrg return; 946848b8605Smrg } 947848b8605Smrg 948848b8605Smrg /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the 949848b8605Smrg * combinations of format and type that can be used. 950848b8605Smrg * 951848b8605Smrg * Technically, only two combinations are actually allowed: 952848b8605Smrg * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal 953848b8605Smrg * preferred combination. This code doesn't know what that preferred 954848b8605Smrg * combination is, and Mesa can handle anything valid. Just work instead. 955848b8605Smrg */ 956848b8605Smrg if (_mesa_is_gles(ctx)) { 957848b8605Smrg if (ctx->API == API_OPENGLES2 && 958848b8605Smrg _mesa_is_color_format(format) && 959848b8605Smrg _mesa_get_color_read_format(ctx) == format && 960848b8605Smrg _mesa_get_color_read_type(ctx) == type) { 961848b8605Smrg err = GL_NO_ERROR; 962848b8605Smrg } else if (ctx->Version < 30) { 963848b8605Smrg err = _mesa_es_error_check_format_and_type(format, type, 2); 964848b8605Smrg if (err == GL_NO_ERROR) { 965848b8605Smrg if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) { 966848b8605Smrg err = GL_INVALID_OPERATION; 967848b8605Smrg } 968848b8605Smrg } 969848b8605Smrg } else { 970848b8605Smrg err = read_pixels_es3_error_check(format, type, rb); 971848b8605Smrg } 972848b8605Smrg 973848b8605Smrg if (err == GL_NO_ERROR && (format == GL_DEPTH_COMPONENT 974848b8605Smrg || format == GL_DEPTH_STENCIL)) { 975848b8605Smrg err = GL_INVALID_ENUM; 976848b8605Smrg } 977848b8605Smrg 978848b8605Smrg if (err != GL_NO_ERROR) { 979848b8605Smrg _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", 980848b8605Smrg _mesa_lookup_enum_by_nr(format), 981848b8605Smrg _mesa_lookup_enum_by_nr(type)); 982848b8605Smrg return; 983848b8605Smrg } 984848b8605Smrg } 985848b8605Smrg 986848b8605Smrg err = _mesa_error_check_format_and_type(ctx, format, type); 987848b8605Smrg if (err != GL_NO_ERROR) { 988848b8605Smrg _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", 989848b8605Smrg _mesa_lookup_enum_by_nr(format), 990848b8605Smrg _mesa_lookup_enum_by_nr(type)); 991848b8605Smrg return; 992848b8605Smrg } 993848b8605Smrg 994848b8605Smrg if (_mesa_is_user_fbo(ctx->ReadBuffer) && 995848b8605Smrg ctx->ReadBuffer->Visual.samples > 0) { 996848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)"); 997848b8605Smrg return; 998848b8605Smrg } 999848b8605Smrg 1000848b8605Smrg if (!_mesa_source_buffer_exists(ctx, format)) { 1001848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); 1002848b8605Smrg return; 1003848b8605Smrg } 1004848b8605Smrg 1005848b8605Smrg /* Check that the destination format and source buffer are both 1006848b8605Smrg * integer-valued or both non-integer-valued. 1007848b8605Smrg */ 1008848b8605Smrg if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { 1009848b8605Smrg const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; 1010848b8605Smrg const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); 1011848b8605Smrg const GLboolean dstInteger = _mesa_is_enum_format_integer(format); 1012848b8605Smrg if (dstInteger != srcInteger) { 1013848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1014848b8605Smrg "glReadPixels(integer / non-integer format mismatch"); 1015848b8605Smrg return; 1016848b8605Smrg } 1017848b8605Smrg } 1018848b8605Smrg 1019848b8605Smrg if (width == 0 || height == 0) 1020848b8605Smrg return; /* nothing to do */ 1021848b8605Smrg 1022848b8605Smrg if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, 1023848b8605Smrg format, type, bufSize, pixels)) { 1024848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { 1025848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1026848b8605Smrg "glReadPixels(out of bounds PBO access)"); 1027848b8605Smrg } else { 1028848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1029848b8605Smrg "glReadnPixelsARB(out of bounds access:" 1030848b8605Smrg " bufSize (%d) is too small)", bufSize); 1031848b8605Smrg } 1032848b8605Smrg return; 1033848b8605Smrg } 1034848b8605Smrg 1035848b8605Smrg if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && 1036848b8605Smrg _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { 1037848b8605Smrg /* buffer is mapped - that's an error */ 1038848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); 1039848b8605Smrg return; 1040848b8605Smrg } 1041848b8605Smrg 1042848b8605Smrg ctx->Driver.ReadPixels(ctx, x, y, width, height, 1043848b8605Smrg format, type, &ctx->Pack, pixels); 1044848b8605Smrg} 1045848b8605Smrg 1046848b8605Smrgvoid GLAPIENTRY 1047848b8605Smrg_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, 1048848b8605Smrg GLenum format, GLenum type, GLvoid *pixels ) 1049848b8605Smrg{ 1050848b8605Smrg _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels); 1051848b8605Smrg} 1052