+GLboolean
+_mesa_need_rgb_to_luminance_conversion(GLenum srcBaseFormat,
+ GLenum dstBaseFormat)
+{
+ 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.
+ */
+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 ||
+ format == GL_STENCIL_INDEX) {
+ return 0;
+ }
+
+ /* Pixel transfer ops (scale, bias, table lookup) do not apply
+ * to integer formats.
+ */
+ if (_mesa_is_enum_format_integer(format)) {
+ return 0;
+ }
+
+ 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, ctx->ReadBuffer) &&
+ (type == GL_FLOAT || type == GL_HALF_FLOAT)) {
+ transferOps |= IMAGE_CLAMP_BIT;
+ }
+ }
+ else {
+ /* For CPU-based ReadPixels packing, the clamping must always be done
+ * for non-float types, */
+ if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) ||
+ (type != GL_FLOAT && type != GL_HALF_FLOAT)) {
+ transferOps |= IMAGE_CLAMP_BIT;
+ }
+ }
+
+ /* If the format is unsigned normalized, we can ignore clamping
+ * because the values are already in the range [0,1] so it won't
+ * have any effect anyway.
+ */
+ if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED &&
+ !_mesa_need_rgb_to_luminance_conversion(srcBaseFormat, dstBaseFormat)) {
+ transferOps &= ~IMAGE_CLAMP_BIT;
+ }
+
+ return transferOps;
+}
+
+
+/**
+ * Return true if memcpy cannot be used for ReadPixels.
+ *
+ * If uses_blit is true, the function returns true if a simple 3D engine blit
+ * cannot be used for ReadPixels packing.
+ *
+ * NOTE: This doesn't take swizzling and format conversions between
+ * the readbuffer and the pixel pack buffer into account.
+ */
+GLboolean
+_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
+ GLenum type, GLboolean uses_blit)
+{
+ struct gl_renderbuffer *rb =
+ _mesa_get_read_renderbuffer_for_format(ctx, format);
+ GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);
+
+ assert(rb);
+
+ /* There are different rules depending on the base format. */
+ switch (format) {
+ case GL_DEPTH_STENCIL:
+ return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) ||
+ ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f ||
+ ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
+ ctx->Pixel.MapStencilFlag;
+
+ case GL_DEPTH_COMPONENT:
+ return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;
+
+ case GL_STENCIL_INDEX:
+ return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
+ ctx->Pixel.MapStencilFlag;
+
+ default:
+ /* Color formats. */
+ if (_mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat,
+ dstBaseFormat)) {
+ return GL_TRUE;
+ }
+
+ /* And finally, see if there are any transfer ops. */
+ return _mesa_get_readpixels_transfer_ops(ctx, rb->Format, format, type,
+ uses_blit) != 0;
+ }
+ return GL_FALSE;
+}
+
+