ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
+
+/**
+ * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
+ * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
+ */
static GLboolean
fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
GLint x, GLint y,
struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
GLubyte *dst, *map;
int dstStride, stride, j, texelBytes;
+ 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_RGBA8888_REV &&
+ 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_XRGB8888 &&
+ format == GL_BGRA &&
+ type == GL_UNSIGNED_INT_8_8_8_8_REV &&
+ !ctx->Pack.SwapBytes) {
+ copy_xrgb = GL_TRUE;
+ }
+ else if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
+ ctx->Pack.SwapBytes))
+ return GL_FALSE;
+
+ /* If the format is unsigned normalized then 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(rb->Format) == GL_UNSIGNED_NORMALIZED)
+ transferOps &= ~IMAGE_CLAMP_BIT;
- if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
- ctx->Pack.SwapBytes))
+ if (transferOps)
return GL_FALSE;
dstStride = _mesa_image_row_stride(packing, width, format, type);
}
texelBytes = _mesa_get_format_bytes(rb->Format);
- for (j = 0; j < height; j++) {
- memcpy(dst, map, width * texelBytes);
- dst += dstStride;
- map += stride;
+
+ 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;
+ }
+ } else {
+ /* just memcpy */
+ for (j = 0; j < height; j++) {
+ memcpy(dst, map, width * texelBytes);
+ dst += dstStride;
+ map += stride;
+ }
}
ctx->Driver.UnmapRenderbuffer(ctx, rb);
for (j = 0; j < height; j++) {
if (_mesa_is_integer_format(format)) {
_mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
+ _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
+ rb->_BaseFormat);
_mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
type, dst);
} 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);
}
transferOps |= IMAGE_CLAMP_BIT;
}
- if (!transferOps) {
- /* Try the optimized paths first. */
- if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
- format, type, pixels, packing,
- transferOps)) {
- return;
- }
+ /* Try the optimized paths first. */
+ if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
+ format, type, pixels, packing,
+ transferOps)) {
+ return;
}
slow_read_rgba_pixels(ctx, x, y, width, height,
return;
}
+ if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+ "glReadPixels(incomplete framebuffer)" );
+ return;
+ }
+
/* Check that the destination format and source buffer are both
* integer-valued or both non-integer-valued.
*/
}
}
- if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
- "glReadPixels(incomplete framebuffer)" );
- return;
- }
-
if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
return;