X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Freadpix.c;h=882d863c1c7c658ea78d149e4d7901891dea65d7;hb=09550c16a51e89dbf64b0864d3fb4ddb6accac52;hp=e16346896ba3efb4993f302da948de4b3c245d14;hpb=eeed49f5f290793870c60b5b635b977a732a1eb4;p=mesa.git diff --git a/src/mesa/main/readpix.c b/src/mesa/main/readpix.c index e16346896ba..882d863c1c7 100644 --- a/src/mesa/main/readpix.c +++ b/src/mesa/main/readpix.c @@ -39,31 +39,55 @@ #include "state.h" #include "glformats.h" #include "fbobject.h" +#include "format_utils.h" +#include "pixeltransfer.h" /** * Return true if the conversion L=R+G+B is needed. */ -static GLboolean -need_rgb_to_luminance_conversion(mesa_format texFormat, GLenum format) +GLboolean +_mesa_need_rgb_to_luminance_conversion(GLenum srcBaseFormat, + GLenum dstBaseFormat) { - GLenum baseTexFormat = _mesa_get_format_base_format(texFormat); - - return (baseTexFormat == GL_RG || - baseTexFormat == GL_RGB || - baseTexFormat == GL_RGBA) && - (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA); + return (srcBaseFormat == GL_RG || + srcBaseFormat == GL_RGB || + srcBaseFormat == GL_RGBA) && + (dstBaseFormat == GL_LUMINANCE || + dstBaseFormat == GL_LUMINANCE_ALPHA); } +/** + * Return true if the conversion L,I to RGB conversion is needed. + */ +GLboolean +_mesa_need_luminance_to_rgb_conversion(GLenum srcBaseFormat, + GLenum dstBaseFormat) +{ + return (srcBaseFormat == GL_LUMINANCE || + srcBaseFormat == GL_LUMINANCE_ALPHA || + srcBaseFormat == GL_INTENSITY) && + (dstBaseFormat == GL_GREEN || + dstBaseFormat == GL_BLUE || + dstBaseFormat == GL_RG || + dstBaseFormat == GL_RGB || + dstBaseFormat == GL_BGR || + dstBaseFormat == GL_RGBA || + dstBaseFormat == GL_BGRA); +} /** * Return transfer op flags for this ReadPixels operation. */ -static GLbitfield -get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, - GLenum format, GLenum type, GLboolean uses_blit) +GLbitfield +_mesa_get_readpixels_transfer_ops(const struct gl_context *ctx, + mesa_format texFormat, + GLenum format, GLenum type, + GLboolean uses_blit) { GLbitfield transferOps = ctx->_ImageTransferState; + GLenum srcBaseFormat = _mesa_get_format_base_format(texFormat); + GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format); if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL || @@ -81,7 +105,7 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, if (uses_blit) { /* For blit-based ReadPixels packing, the clamping is done automatically * unless the type is float. */ - if (_mesa_get_clamp_read_color(ctx) && + if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) && (type == GL_FLOAT || type == GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } @@ -89,7 +113,7 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, else { /* For CPU-based ReadPixels packing, the clamping must always be done * for non-float types, */ - if (_mesa_get_clamp_read_color(ctx) || + if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) || (type != GL_FLOAT && type != GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } @@ -100,7 +124,7 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, * have any effect anyway. */ if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED && - !need_rgb_to_luminance_conversion(texFormat, format)) { + !_mesa_need_rgb_to_luminance_conversion(srcBaseFormat, dstBaseFormat)) { transferOps &= ~IMAGE_CLAMP_BIT; } @@ -123,9 +147,9 @@ _mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format, { struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); - GLenum srcType; + GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format); - ASSERT(rb); + assert(rb); /* There are different rules depending on the base format. */ switch (format) { @@ -144,28 +168,14 @@ _mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format, default: /* Color formats. */ - if (need_rgb_to_luminance_conversion(rb->Format, format)) { - return GL_TRUE; - } - - /* Conversion between signed and unsigned integers needs masking - * (it isn't just memcpy). */ - srcType = _mesa_get_format_datatype(rb->Format); - - if ((srcType == GL_INT && - (type == GL_UNSIGNED_INT || - type == GL_UNSIGNED_SHORT || - type == GL_UNSIGNED_BYTE)) || - (srcType == GL_UNSIGNED_INT && - (type == GL_INT || - type == GL_SHORT || - type == GL_BYTE))) { + if (_mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat, + dstBaseFormat)) { return GL_TRUE; } /* And finally, see if there are any transfer ops. */ - return get_readpixels_transfer_ops(ctx, rb->Format, format, type, - uses_blit) != 0; + return _mesa_get_readpixels_transfer_ops(ctx, rb->Format, format, type, + uses_blit) != 0; } return GL_FALSE; } @@ -178,7 +188,7 @@ readpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum ty struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); - ASSERT(rb); + assert(rb); if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) { return GL_FALSE; @@ -191,7 +201,7 @@ readpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum ty /* The Mesa format must match the input format and type. */ if (!_mesa_format_matches_format_and_type(rb->Format, format, type, - packing->SwapBytes)) { + packing->SwapBytes, NULL)) { return GL_FALSE; } @@ -258,7 +268,7 @@ read_uint_depth_pixels( struct gl_context *ctx, GLubyte *map, *dst; int stride, dstStride, j; - if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) + if (ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F) return GL_FALSE; if (packing->SwapBytes) @@ -311,10 +321,10 @@ read_depth_pixels( struct gl_context *ctx, return; /* clipping should have been done already */ - ASSERT(x >= 0); - ASSERT(y >= 0); - ASSERT(x + width <= (GLint) rb->Width); - ASSERT(y + height <= (GLint) rb->Height); + assert(x >= 0); + assert(y >= 0); + assert(x + width <= (GLint) rb->Width); + assert(y + height <= (GLint) rb->Height); if (type == GL_UNSIGNED_INT && read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) { @@ -405,174 +415,211 @@ read_stencil_pixels( struct gl_context *ctx, ctx->Driver.UnmapRenderbuffer(ctx, rb); } - -/** - * Try to do glReadPixels of RGBA data using swizzle. - * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path) +/* + * Read R, G, B, A, RGB, L, or LA pixels. */ -static GLboolean -read_rgba_pixels_swizzle(struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLvoid *pixels, - const struct gl_pixelstore_attrib *packing) +static void +read_rgba_pixels( struct gl_context *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, GLvoid *pixels, + const struct gl_pixelstore_attrib *packing ) { - struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; + GLbitfield transferOps; + bool dst_is_integer, convert_rgb_to_lum, needs_rebase; + int dst_stride, src_stride, rb_stride; + uint32_t dst_format, src_format; GLubyte *dst, *map; - int dstStride, stride, j; - GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE; - - /* XXX we could check for other swizzle/special cases here as needed */ - if (rb->Format == MESA_FORMAT_R8G8B8A8_UNORM && - format == GL_BGRA && - type == GL_UNSIGNED_INT_8_8_8_8_REV && - !ctx->Pack.SwapBytes) { - swizzle_rb = GL_TRUE; - } - else if (rb->Format == MESA_FORMAT_B8G8R8X8_UNORM && - format == GL_BGRA && - type == GL_UNSIGNED_INT_8_8_8_8_REV && - !ctx->Pack.SwapBytes) { - copy_xrgb = GL_TRUE; - } - else { - return GL_FALSE; - } + mesa_format rb_format; + bool needs_rgba; + void *rgba, *src; + bool src_is_uint = false; + uint8_t rebase_swizzle[4]; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct gl_renderbuffer *rb = fb->_ColorReadBuffer; + GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format); - dstStride = _mesa_image_row_stride(packing, width, format, type); + if (!rb) + return; + + transferOps = _mesa_get_readpixels_transfer_ops(ctx, rb->Format, format, + type, GL_FALSE); + /* Describe the dst format */ + dst_is_integer = _mesa_is_enum_format_integer(format); + dst_stride = _mesa_image_row_stride(packing, width, format, type); + dst_format = _mesa_format_from_format_and_type(format, type); + convert_rgb_to_lum = + _mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat, dstBaseFormat); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, - format, type, 0, 0); + format, type, 0, 0); + /* Map the source render buffer */ ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); + &map, &rb_stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); - return GL_TRUE; /* don't bother trying the slow path */ + return; } + rb_format = _mesa_get_srgb_format_linear(rb->Format); - if (swizzle_rb) { - /* swap R/B */ - for (j = 0; j < height; j++) { - int i; - for (i = 0; i < width; i++) { - GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; - GLuint pixel = map4[i]; - dst4[i] = (pixel & 0xff00ff00) - | ((pixel & 0x00ff0000) >> 16) - | ((pixel & 0x000000ff) << 16); - } - dst += dstStride; - map += stride; - } - } else if (copy_xrgb) { - /* convert xrgb -> argb */ - for (j = 0; j < height; j++) { - GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map; - int i; - for (i = 0; i < width; i++) { - dst4[i] = map4[i] | 0xff000000; /* set A=0xff */ - } - dst += dstStride; - map += stride; - } + /* + * Depending on the base formats involved in the conversion we might need to + * rebase some values, so for these formats we compute a rebase swizzle. + */ + if (rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY) { + needs_rebase = true; + rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; + rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; + rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; + rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_ONE; + } else if (rb->_BaseFormat == GL_LUMINANCE_ALPHA) { + needs_rebase = true; + rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X; + rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO; + rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO; + rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_W; + } else if (_mesa_get_format_base_format(rb_format) != rb->_BaseFormat) { + needs_rebase = + _mesa_compute_rgba2base2rgba_component_mapping(rb->_BaseFormat, + rebase_swizzle); + } else { + needs_rebase = false; } - ctx->Driver.UnmapRenderbuffer(ctx, rb); - - return GL_TRUE; -} - -static void -slow_read_rgba_pixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - GLvoid *pixels, - const struct gl_pixelstore_attrib *packing, - GLbitfield transferOps ) -{ - struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; - const mesa_format rbFormat = _mesa_get_srgb_format_linear(rb->Format); - void *rgba; - GLubyte *dst, *map; - int dstStride, stride, j; - GLboolean dst_is_integer = _mesa_is_enum_format_integer(format); - GLboolean dst_is_uint = _mesa_is_format_unsigned(rbFormat); - - dstStride = _mesa_image_row_stride(packing, width, format, type); - dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, - format, type, 0, 0); - - ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, - &map, &stride); - if (!map) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); - return; - } + /* Since _mesa_format_convert does not handle transferOps we need to handle + * them before we call the function. This requires to convert to RGBA float + * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is + * integer transferOps do not apply. + * + * Converting to luminance also requires converting to RGBA first, so we can + * then compute luminance values as L=R+G+B. Notice that this is different + * from GetTexImage, where we compute L=R. + */ + assert(!transferOps || (transferOps && !dst_is_integer)); - rgba = malloc(width * MAX_PIXEL_BYTES); - if (!rgba) - goto done; + needs_rgba = transferOps || convert_rgb_to_lum; + rgba = NULL; + if (needs_rgba) { + uint32_t rgba_format; + int rgba_stride; + bool need_convert; - for (j = 0; j < height; j++) { + /* Convert to RGBA float or int/uint depending on the type of the src */ if (dst_is_integer) { - _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba); - _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba, - rb->_BaseFormat); - if (dst_is_uint) { - _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba, format, - type, dst); + src_is_uint = _mesa_is_format_unsigned(rb_format); + if (src_is_uint) { + rgba_format = RGBA32_UINT; + rgba_stride = width * 4 * sizeof(GLuint); } else { - _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba, format, - type, dst); + rgba_format = RGBA32_INT; + rgba_stride = width * 4 * sizeof(GLint); } } else { - _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba); - _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba, - rb->_BaseFormat); - _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, - type, dst, packing, transferOps); + rgba_format = RGBA32_FLOAT; + rgba_stride = width * 4 * sizeof(GLfloat); } - dst += dstStride; - map += stride; - } - - free(rgba); -done: - ctx->Driver.UnmapRenderbuffer(ctx, rb); -} + /* If we are lucky and the dst format matches the RGBA format we need to + * convert to, then we can convert directly into the dst buffer and avoid + * the final conversion/copy from the rgba buffer to the dst buffer. + */ + if (dst_format == rgba_format && + dst_stride == rgba_stride) { + need_convert = false; + rgba = dst; + } else { + need_convert = true; + rgba = malloc(height * rgba_stride); + if (!rgba) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); + goto done_unmap; + } + } -/* - * Read R, G, B, A, RGB, L, or LA pixels. - */ -static void -read_rgba_pixels( struct gl_context *ctx, - GLint x, GLint y, - GLsizei width, GLsizei height, - GLenum format, GLenum type, GLvoid *pixels, - const struct gl_pixelstore_attrib *packing ) -{ - GLbitfield transferOps; - struct gl_framebuffer *fb = ctx->ReadBuffer; - struct gl_renderbuffer *rb = fb->_ColorReadBuffer; + /* Convert to RGBA now */ + _mesa_format_convert(rgba, rgba_format, rgba_stride, + map, rb_format, rb_stride, + width, height, + needs_rebase ? rebase_swizzle : NULL); + + /* Handle transfer ops if necessary */ + if (transferOps) + _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba); + + /* If we had to rebase, we have already taken care of that */ + needs_rebase = false; + + /* If we were lucky and our RGBA conversion matches the dst format, then + * we are done. + */ + if (!need_convert) + goto done_swap; + + /* Otherwise, we need to convert from RGBA to dst next */ + src = rgba; + src_format = rgba_format; + src_stride = rgba_stride; + } else { + /* No RGBA conversion needed, convert directly to dst */ + src = map; + src_format = rb_format; + src_stride = rb_stride; + } - if (!rb) - return; + /* Do the conversion. + * + * If the dst format is Luminance, we need to do the conversion by computing + * L=R+G+B values. + */ + if (!convert_rgb_to_lum) { + _mesa_format_convert(dst, dst_format, dst_stride, + src, src_format, src_stride, + width, height, + needs_rebase ? rebase_swizzle : NULL); + } else if (!dst_is_integer) { + /* Compute float Luminance values from RGBA float */ + int luminance_stride, luminance_bytes; + void *luminance; + uint32_t luminance_format; + + luminance_stride = width * sizeof(GLfloat); + if (format == GL_LUMINANCE_ALPHA) + luminance_stride *= 2; + luminance_bytes = height * luminance_stride; + luminance = malloc(luminance_bytes); + if (!luminance) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); + free(rgba); + goto done_unmap; + } + _mesa_pack_luminance_from_rgba_float(width * height, src, + luminance, format, transferOps); + + /* Convert from Luminance float to dst (this will hadle type conversion + * from float to the type of dst if necessary) + */ + luminance_format = _mesa_format_from_format_and_type(format, GL_FLOAT); + _mesa_format_convert(dst, dst_format, dst_stride, + luminance, luminance_format, luminance_stride, + width, height, NULL); + free(luminance); + } else { + _mesa_pack_luminance_from_rgba_integer(width * height, src, !src_is_uint, + dst, format, type); + } - transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type, - GL_FALSE); + if (rgba) + free(rgba); - /* Try the optimized paths first. */ - if (!transferOps && - read_rgba_pixels_swizzle(ctx, x, y, width, height, - format, type, pixels, packing)) { - return; +done_swap: + /* Handle byte swapping if required */ + if (packing->SwapBytes) { + _mesa_swap_bytes_2d_image(format, type, packing, + width, height, dst, dst); } - slow_read_rgba_pixels(ctx, x, y, width, height, - format, type, pixels, packing, transferOps); +done_unmap: + ctx->Driver.UnmapRenderbuffer(ctx, rb); } /** @@ -595,7 +642,7 @@ fast_read_depth_stencil_pixels(struct gl_context *ctx, return GL_FALSE; if (rb->Format != MESA_FORMAT_S8_UINT_Z24_UNORM && - rb->Format != MESA_FORMAT_Z24_UNORM_X8_UINT) + rb->Format != MESA_FORMAT_Z24_UNORM_S8_UINT) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, @@ -768,7 +815,7 @@ read_depth_stencil_pixels(struct gl_context *ctx, const struct gl_pixelstore_attrib *packing ) { const GLboolean scaleOrBias - = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0; + = ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F; const GLboolean stencilTransfer = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; GLubyte *dst; @@ -811,46 +858,40 @@ _mesa_readpixels(struct gl_context *ctx, const struct gl_pixelstore_attrib *packing, GLvoid *pixels) { - struct gl_pixelstore_attrib clippedPacking = *packing; - if (ctx->NewState) _mesa_update_state(ctx); - /* Do all needed clipping here, so that we can forget about it later */ - if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { - - pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels); - - if (pixels) { - /* Try memcpy first. */ - if (readpixels_memcpy(ctx, x, y, width, height, format, type, - pixels, packing)) { - _mesa_unmap_pbo_dest(ctx, &clippedPacking); - return; - } + pixels = _mesa_map_pbo_dest(ctx, packing, pixels); - /* Otherwise take the slow path. */ - switch (format) { - case GL_STENCIL_INDEX: - read_stencil_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - case GL_DEPTH_COMPONENT: - read_depth_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - case GL_DEPTH_STENCIL_EXT: - read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, - &clippedPacking); - break; - default: - /* all other formats should be color formats */ - read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, - &clippedPacking); - } + if (pixels) { + /* Try memcpy first. */ + if (readpixels_memcpy(ctx, x, y, width, height, format, type, + pixels, packing)) { + _mesa_unmap_pbo_dest(ctx, packing); + return; + } - _mesa_unmap_pbo_dest(ctx, &clippedPacking); + /* Otherwise take the slow path. */ + switch (format) { + case GL_STENCIL_INDEX: + read_stencil_pixels(ctx, x, y, width, height, type, pixels, + packing); + break; + case GL_DEPTH_COMPONENT: + read_depth_pixels(ctx, x, y, width, height, type, pixels, + packing); + break; + case GL_DEPTH_STENCIL_EXT: + read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels, + packing); + break; + default: + /* all other formats should be color formats */ + read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, + packing); } + + _mesa_unmap_pbo_dest(ctx, packing); } } @@ -863,10 +904,8 @@ read_pixels_es3_error_check(GLenum format, GLenum type, const GLenum data_type = _mesa_get_format_datatype(rb->Format); GLboolean is_unsigned_int = GL_FALSE; GLboolean is_signed_int = GL_FALSE; - - if (!_mesa_is_color_format(internalFormat)) { - return GL_INVALID_OPERATION; - } + GLboolean is_float_depth = (internalFormat == GL_DEPTH_COMPONENT32F) || + (internalFormat == GL_DEPTH32F_STENCIL8); is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat); if (!is_unsigned_int) { @@ -897,6 +936,44 @@ read_pixels_es3_error_check(GLenum format, GLenum type, (is_unsigned_int && type == GL_UNSIGNED_INT)) return GL_NO_ERROR; break; + case GL_DEPTH_STENCIL: + switch (type) { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + if (is_float_depth) + return GL_NO_ERROR; + break; + case GL_UNSIGNED_INT_24_8: + if (!is_float_depth) + return GL_NO_ERROR; + break; + default: + return GL_INVALID_ENUM; + } + break; + case GL_DEPTH_COMPONENT: + switch (type) { + case GL_FLOAT: + if (is_float_depth) + return GL_NO_ERROR; + break; + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_24_8: + if (!is_float_depth) + return GL_NO_ERROR; + break; + default: + return GL_INVALID_ENUM; + } + break; + case GL_STENCIL_INDEX: + switch (type) { + case GL_UNSIGNED_BYTE: + return GL_NO_ERROR; + default: + return GL_INVALID_ENUM; + } + break; } return GL_INVALID_OPERATION; @@ -910,6 +987,7 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, { GLenum err = GL_NO_ERROR; struct gl_renderbuffer *rb; + struct gl_pixelstore_attrib clippedPacking; GET_CURRENT_CONTEXT(ctx); @@ -919,8 +997,8 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", width, height, - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type), + _mesa_enum_to_string(format), + _mesa_enum_to_string(type), pixels); if (width < 0 || height < 0) { @@ -960,7 +1038,7 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, _mesa_get_color_read_type(ctx) == type) { err = GL_NO_ERROR; } else if (ctx->Version < 30) { - err = _mesa_es_error_check_format_and_type(format, type, 2); + err = _mesa_es_error_check_format_and_type(ctx, format, type, 2); if (err == GL_NO_ERROR) { if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) { err = GL_INVALID_OPERATION; @@ -970,15 +1048,10 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, err = read_pixels_es3_error_check(format, type, rb); } - if (err == GL_NO_ERROR && (format == GL_DEPTH_COMPONENT - || format == GL_DEPTH_STENCIL)) { - err = GL_INVALID_ENUM; - } - if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type)); + _mesa_enum_to_string(format), + _mesa_enum_to_string(type)); return; } } @@ -986,8 +1059,8 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", - _mesa_lookup_enum_by_nr(format), - _mesa_lookup_enum_by_nr(type)); + _mesa_enum_to_string(format), + _mesa_enum_to_string(type)); return; } @@ -1016,7 +1089,9 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, } } - if (width == 0 || height == 0) + /* Do all needed clipping here, so that we can forget about it later */ + clippedPacking = ctx->Pack; + if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) return; /* nothing to do */ if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, @@ -1033,14 +1108,14 @@ _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, } if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && - _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { + _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); return; } ctx->Driver.ReadPixels(ctx, x, y, width, height, - format, type, &ctx->Pack, pixels); + format, type, &clippedPacking, pixels); } void GLAPIENTRY