Use MESA_pack_invert to avoid read_pixels flip

cogl_read_pixels returns image data in a top-down memory order, but
because OpenGL normally returns pixel data in a bottom-up order we
have to flip the data before returning it to the user. If the OpenGL
driver supports the GL_MESA_pack_invert extension though we can ask the
driver to return the data in a top-down order in the first place.

Signed-off-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
Robert Bragg 2011-07-13 18:28:49 +01:00
parent 1527b017c5
commit 6f79eb8a5a
3 changed files with 27 additions and 4 deletions

View File

@ -138,6 +138,7 @@ typedef enum
typedef enum typedef enum
{ {
COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE = 1L<<0, COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE = 1L<<0,
COGL_PRIVATE_FEATURE_MESA_PACK_INVERT = 1L<<1
} CoglPrivateFeatureFlags; } CoglPrivateFeatureFlags;
gboolean gboolean

View File

@ -47,6 +47,10 @@
#include "cogl-attribute-private.h" #include "cogl-attribute-private.h"
#include "cogl-framebuffer-private.h" #include "cogl-framebuffer-private.h"
#ifndef GL_PACK_INVERT_MESA
#define GL_PACK_INVERT_MESA 0x8758
#endif
#ifdef COGL_GL_DEBUG #ifdef COGL_GL_DEBUG
/* GL error to string conversion */ /* GL error to string conversion */
static const struct { static const struct {
@ -474,6 +478,7 @@ _cogl_read_pixels_with_rowstride (int x,
GLenum gl_format; GLenum gl_format;
GLenum gl_type; GLenum gl_type;
CoglPixelFormat bmp_format; CoglPixelFormat bmp_format;
gboolean pack_invert_set;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -546,6 +551,17 @@ _cogl_read_pixels_with_rowstride (int x,
&gl_format, &gl_format,
&gl_type); &gl_type);
/* 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) &&
!cogl_is_offscreen (framebuffer))
{
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
pack_invert_set = TRUE;
}
else
pack_invert_set = FALSE;
/* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
implementation specific format under implementation specific format under
GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and
@ -609,15 +625,18 @@ _cogl_read_pixels_with_rowstride (int x,
_cogl_bitmap_convert_premult_status (bmp, format); _cogl_bitmap_convert_premult_status (bmp, format);
} }
/* Currently this function owns the pack_invert state and we don't want this
* to interfere with other Cogl components so all other code can assume that
* we leave the pack_invert state off. */
if (pack_invert_set)
GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE));
/* NB: All offscreen rendering is done upside down so there is no need /* NB: All offscreen rendering is done upside down so there is no need
* to flip in this case... */ * to flip in this case... */
if (!cogl_is_offscreen (framebuffer)) if (!cogl_is_offscreen (framebuffer) && !pack_invert_set)
{ {
guint8 *temprow = g_alloca (rowstride * sizeof (guint8)); guint8 *temprow = g_alloca (rowstride * sizeof (guint8));
/* TODO: consider using the GL_MESA_pack_invert extension in the future
* to avoid this flip... */
/* vertically flip the buffer in-place */ /* vertically flip the buffer in-place */
for (y = 0; y < height / 2; y++) for (y = 0; y < height / 2; y++)
{ {

View File

@ -183,6 +183,9 @@ _cogl_gl_update_features (CoglContext *context)
} }
#endif #endif
if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions))
private_flags |= COGL_PRIVATE_FEATURE_MESA_PACK_INVERT;
GE( ctx, glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) ); GE( ctx, glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
/* We need at least three stencil bits to combine clips */ /* We need at least three stencil bits to combine clips */
if (num_stencil_bits > 2) if (num_stencil_bits > 2)