diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h index 0081a2f90..4c759cf93 100644 --- a/cogl/cogl-framebuffer-private.h +++ b/cogl/cogl-framebuffer-private.h @@ -93,6 +93,16 @@ typedef enum _CoglFramebufferState #define COGL_FRAMEBUFFER_STATE_ALL ((1<clear_clip_dirty) { @@ -1986,6 +2078,32 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, return TRUE; } + /* Workaround for cases where its faster to read into a temporary + * PBO. This is only worth doing if: + * + * • The GPU is an Intel GPU. In that case there is a known + * fast-path when reading into a PBO that will use the blitter + * instead of the Mesa fallback code. The driver bug will only be + * set if this is the case. + * • We're not already reading into a PBO. + * • The target format is BGRA. The fast-path blit does not get hit + * otherwise. + * • The size of the data is not trivially small. This isn't a + * requirement to hit the fast-path blit but intuitively it feels + * like if the amount of data is too small then the cost of + * allocating a PBO will outweigh the cost of temporarily + * converting the data to floats. + */ + if ((ctx->gpu.driver_bugs & + COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS) && + (width > 8 || height > 8) && + (format & ~COGL_PREMULT_BIT) == COGL_PIXEL_FORMAT_BGRA_8888 && + cogl_bitmap_get_buffer (bitmap) == NULL) + return _cogl_framebuffer_slow_read_pixels_workaround (framebuffer, + x, y, + source, + bitmap); + /* make sure any batched primitives get emitted to the GL driver * before issuing our read pixels... */ @@ -2006,8 +2124,6 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, if (!cogl_is_offscreen (framebuffer)) y = framebuffer_height - y - height; - format = cogl_bitmap_get_format (bitmap); - required_format = ctx->driver_vtable->pixel_format_to_gl (ctx, format, &gl_intformat, @@ -2017,6 +2133,7 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, /* NB: All offscreen rendering is done upside down so there is no need * to flip in this case... */ if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) && + (source & COGL_READ_PIXELS_NO_FLIP) == 0 && !cogl_is_offscreen (framebuffer)) { GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE)); @@ -2152,7 +2269,9 @@ cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer, /* NB: All offscreen rendering is done upside down so there is no need * to flip in this case... */ - if (!cogl_is_offscreen (framebuffer) && !pack_invert_set) + if (!cogl_is_offscreen (framebuffer) && + (source & COGL_READ_PIXELS_NO_FLIP) == 0 && + !pack_invert_set) { guint8 *temprow; int rowstride; diff --git a/cogl/cogl-gpu-info-private.h b/cogl/cogl-gpu-info-private.h index 2930d6bd1..70f150a2d 100644 --- a/cogl/cogl-gpu-info-private.h +++ b/cogl/cogl-gpu-info-private.h @@ -40,7 +40,12 @@ typedef enum typedef enum { - COGL_GPU_INFO_DRIVER_STUB + /* If this bug is present then it is faster to read pixels into a + * PBO and then memcpy out of the PBO into system memory rather than + * directly read into system memory. + * https://bugs.freedesktop.org/show_bug.cgi?id=46631 + */ + COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS = 1 << 0 } CoglGpuInfoDriverBug; typedef struct _CoglGpuInfoVersion CoglGpuInfoVersion; diff --git a/cogl/cogl-gpu-info.c b/cogl/cogl-gpu-info.c index f62bbc330..e64fdbda7 100644 --- a/cogl/cogl-gpu-info.c +++ b/cogl/cogl-gpu-info.c @@ -250,5 +250,15 @@ _cogl_gpu_info_init (CoglContext *ctx, } /* Determine the driver bugs */ - gpu->driver_bugs = 0; + + /* In Mesa < 8.0.2 the glReadPixels implementation is really slow + because it converts each pixel to a floating point representation + and back even if the data could just be memcpy'd. The Intel + driver has a fast blit path when reading into a PBO. Reading into + a temporary PBO and then memcpying back out to the application's + memory is faster than a regular glReadPixels in this case */ + if (gpu->vendor == COGL_GPU_INFO_VENDOR_INTEL && + gpu->driver_package == COGL_GPU_INFO_DRIVER_PACKAGE_MESA && + gpu->driver_package_version < COGL_VERSION_ENCODE (8, 0, 2)) + gpu->driver_bugs |= COGL_GPU_INFO_DRIVER_BUG_MESA_46631_SLOW_READ_PIXELS; }