gl: Add private glReadPixels() wrapper
For the software fallback path in gdk_cairo_draw_from_gl() we use glReadPixels() to read the contents of a framebuffer object in order to put it inside a Cairo image surface we can blend on the CPU. In order to do that, we use GL_PACK_ROW_LENGTH, which is only available in desktop GL, GLES 3.0, or if the GL_EXT_unpack_subimage extension is present. Older GLES 2.0 drivers would just be out of luck. Instead of bailing out, let's implement unpacking line by line, to adjust for the Cairo image surface stride, like we do when uploading textures. In order to avoid complicating an already big function, we should wrap our glReadPixels() call with our own wrapper that performs checks and calls the appropriate functions with the appropriate data.
This commit is contained in:
25
gdk/gdkgl.c
25
gdk/gdkgl.c
@@ -645,13 +645,6 @@ gdk_cairo_draw_from_gl (cairo_t *cr,
|
||||
{
|
||||
/* Software fallback */
|
||||
int major, minor, version;
|
||||
gboolean es_read_bgra = FALSE;
|
||||
|
||||
#ifdef GDK_WINDOWING_WIN32
|
||||
/* on ANGLE GLES, we need to set the glReadPixel() format as GL_BGRA instead */
|
||||
if (GDK_WIN32_IS_GL_CONTEXT(paint_context))
|
||||
es_read_bgra = TRUE;
|
||||
#endif
|
||||
|
||||
gdk_gl_context_get_version (paint_context, &major, &minor);
|
||||
version = major * 100 + minor;
|
||||
@@ -686,24 +679,15 @@ gdk_cairo_draw_from_gl (cairo_t *cr,
|
||||
GL_TEXTURE_2D, source, 0);
|
||||
}
|
||||
|
||||
glPixelStorei (GL_PACK_ALIGNMENT, 4);
|
||||
glPixelStorei (GL_PACK_ROW_LENGTH, cairo_image_surface_get_stride (image) / 4);
|
||||
|
||||
/* The implicit format conversion is going to make this path slower */
|
||||
if (!gdk_gl_context_get_use_es (paint_context))
|
||||
glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
cairo_image_surface_get_data (image));
|
||||
else
|
||||
glReadPixels (x, y, width, height, es_read_bgra ? GL_BGRA : GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
cairo_image_surface_get_data (image));
|
||||
|
||||
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
|
||||
gdk_gl_context_download_texture (paint_context,
|
||||
x, y, width, height,
|
||||
image);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
cairo_surface_mark_dirty (image);
|
||||
|
||||
/* Invert due to opengl having different origin */
|
||||
/* Invert due to GL framebuffers having different origin */
|
||||
cairo_scale (cr, 1, -1);
|
||||
cairo_translate (cr, 0, -height / buffer_scale);
|
||||
|
||||
@@ -717,7 +701,6 @@ gdk_cairo_draw_from_gl (cairo_t *cr,
|
||||
out:
|
||||
if (clip_region)
|
||||
cairo_region_destroy (clip_region);
|
||||
|
||||
}
|
||||
|
||||
/* This is always called with the paint context current */
|
||||
|
@@ -236,6 +236,72 @@ gdk_gl_context_get_property (GObject *gobject,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_gl_context_download_texture (GdkGLContext *context,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
cairo_surface_t *image_surface)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
gboolean es_read_bgra = FALSE;
|
||||
|
||||
#ifdef GDK_WINDOWING_WIN32
|
||||
/* on ANGLE GLES, we need to set the glReadPixel() format as GL_BGRA instead */
|
||||
if (GDK_WIN32_IS_GL_CONTEXT (context))
|
||||
es_read_bgra = TRUE;
|
||||
#endif
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if (!priv->use_es ||
|
||||
(priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage)))
|
||||
{
|
||||
glPixelStorei (GL_PACK_ALIGNMENT, 4);
|
||||
glPixelStorei (GL_PACK_ROW_LENGTH, cairo_image_surface_get_stride (image_surface) / 4);
|
||||
|
||||
if (priv->use_es)
|
||||
glReadPixels (x, y, width, height,
|
||||
es_read_bgra ? GL_BGRA : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
cairo_image_surface_get_data (image_surface));
|
||||
else
|
||||
glReadPixels (x, y, width, height,
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
cairo_image_surface_get_data (image_surface));
|
||||
|
||||
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLvoid *data = cairo_image_surface_get_data (image_surface);
|
||||
int stride = cairo_image_surface_get_stride (image_surface);
|
||||
int i;
|
||||
|
||||
if (priv->use_es)
|
||||
{
|
||||
for (i = y; i < height; i++)
|
||||
glReadPixels (x, i, width, 1,
|
||||
es_read_bgra ? GL_BGRA : GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
(unsigned char *) data + (i * stride));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = y; i < height; i++)
|
||||
glReadPixels (x, i, width, 1,
|
||||
GL_BGRA,
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
(unsigned char *) data + (i * stride));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_gl_context_upload_texture (GdkGLContext *context,
|
||||
cairo_surface_t *image_surface,
|
||||
|
@@ -81,6 +81,12 @@ void gdk_gl_context_upload_texture (GdkGLContext
|
||||
int width,
|
||||
int height,
|
||||
guint texture_target);
|
||||
void gdk_gl_context_download_texture (GdkGLContext *context,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
cairo_surface_t *image_surface);
|
||||
GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context);
|
||||
gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context);
|
||||
gboolean gdk_gl_context_has_framebuffer_blit (GdkGLContext *context);
|
||||
|
Reference in New Issue
Block a user