summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2020-09-24 15:03:48 +0200
committerAlexander Larsson <alexl@redhat.com>2020-09-25 09:31:43 +0200
commit1001995d496573072171ed2200fa0c470ffac476 (patch)
treed3afa0f084a29dab769e073b7552221d3aa2f736
parent8e59cdabac9596acd2d2bc502ae583f321f4f4d1 (diff)
downloadgtk+-1001995d496573072171ed2200fa0c470ffac476.tar.gz
Correctly upload textures for GLES
GLES doesn't support the GL_BGRA + GL_UNSIGNED_INT_24_8 hack that we use on desktop OpenGL to upload textures directly in the cairo pixel format. This adds the required conversions to all the places that currently need it. We also add a data_format to the internal gdk_gl_context_upload_texture() function to make it clearer what the format are. Currently it is always the cairo image surface format, but eventually we want to support other formats so that we can avoid some of the unnecessary conversions we do. Also, the current gdk_gl_context_upload_texture() code always converts to a cairo format and uploads that like we did before. Later commits will allow this to use other upload formats that gl supports to avoid conversions.
-rw-r--r--gdk/gdkgl.c1
-rw-r--r--gdk/gdkglcontext.c79
-rw-r--r--gdk/gdkglcontextprivate.h2
-rw-r--r--gsk/gl/gskglglyphcache.c29
-rw-r--r--gsk/gl/gskgliconcache.c58
5 files changed, 119 insertions, 50 deletions
diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c
index 309f792613..2fe5cc863e 100644
--- a/gdk/gdkgl.c
+++ b/gdk/gdkgl.c
@@ -482,6 +482,7 @@ gdk_cairo_surface_upload_to_gl (cairo_surface_t *surface,
rect.width,
rect.height,
cairo_image_surface_get_stride (tmp),
+ GDK_MEMORY_DEFAULT,
target);
cairo_surface_unmap_image (surface, tmp);
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 2843ef05f5..9d658660e2 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -87,6 +87,7 @@
#include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h"
+#include "gdkmemorytextureprivate.h"
#include "gdkinternals.h"
#include "gdkintl.h"
@@ -227,49 +228,81 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
int width,
int height,
int stride,
+ GdkMemoryFormat data_format,
guint texture_target)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+ guchar *copy = NULL;
+ guint gl_format;
+ guint gl_type;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
+ if (priv->use_es)
+ {
+ /* GLES only supports rgba, so convert if necessary */
+ if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
+ {
+ copy = g_malloc (width * height * 4);
+ gdk_memory_convert (copy, width * 4,
+ GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ data, stride, data_format,
+ width, height);
+ stride = width * 4;
+ data = copy;
+ }
+
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ }
+ else
+ {
+ if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
+ {
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ else /* Fall-back, convert to cairo-surface-format */
+ {
+ copy = g_malloc (width * height * 4);
+ gdk_memory_convert (copy, width * 4,
+ GDK_MEMORY_DEFAULT,
+ data, stride, data_format,
+ width, height);
+ stride = width * 4;
+ data = copy;
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ }
+
+
/* 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)))
+ if (stride == width * 4)
+ {
+ glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
+ }
+ else if (!priv->use_es ||
+ (priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage)))
{
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4);
- if (priv->use_es)
- glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
- data);
- else
- glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
- data);
+ glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
}
else
{
int i;
-
- if (priv->use_es)
- {
- glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
- for (i = 0; i < height; i++)
- glTexSubImage2D (texture_target, 0, 0, i, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, data + (i * stride));
- }
- else
- {
- glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
-
- for (i = 0; i < height; i++)
- glTexSubImage2D (texture_target, 0, 0, i, width, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data + (i * stride));
- }
+ glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
+ for (i = 0; i < height; i++)
+ glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
}
+
+ g_free (copy);
}
static gboolean
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index 8991332b56..e785fbc63d 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -23,6 +23,7 @@
#include "gdkglcontext.h"
#include "gdkdrawcontextprivate.h"
+#include "gdkmemorytexture.h"
G_BEGIN_DECLS
@@ -84,6 +85,7 @@ void gdk_gl_context_upload_texture (GdkGLContext
int width,
int height,
int stride,
+ GdkMemoryFormat data_format,
guint texture_target);
GdkGLContextPaintData * gdk_gl_context_get_paint_data (GdkGLContext *context);
gboolean gdk_gl_context_use_texture_rectangle (GdkGLContext *context);
diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c
index 4d23eb60be..b147dcef21 100644
--- a/gsk/gl/gskglglyphcache.c
+++ b/gsk/gl/gskglglyphcache.c
@@ -7,6 +7,7 @@
#include "gskgltextureatlasprivate.h"
#include "gdk/gdkglcontextprivate.h"
+#include "gdk/gdkmemorytextureprivate.h"
#include <graphene.h>
#include <cairo.h>
@@ -186,6 +187,10 @@ upload_glyph (GlyphCacheKey *key,
GskGLCachedGlyph *value)
{
GskImageRegion r;
+ guchar *pixel_data;
+ guchar *free_data = NULL;
+ guint gl_format;
+ guint gl_type;
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading glyph %d",
@@ -197,15 +202,27 @@ upload_glyph (GlyphCacheKey *key,
glBindTexture (GL_TEXTURE_2D, value->texture_id);
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
- glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
- GL_RGBA, GL_UNSIGNED_BYTE,
- r.data);
+ {
+ pixel_data = free_data = g_malloc (r.width * r.height * 4);
+ gdk_memory_convert (pixel_data, r.width * 4,
+ GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ r.data, r.width * 4,
+ GDK_MEMORY_DEFAULT, r.width, r.height);
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ }
else
- glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
- GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
- r.data);
+ {
+ pixel_data = r.data;
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ glTexSubImage2D (GL_TEXTURE_2D, 0, r.x, r.y, r.width, r.height,
+ gl_format, gl_type, pixel_data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
g_free (r.data);
+ g_free (free_data);
}
gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
diff --git a/gsk/gl/gskgliconcache.c b/gsk/gl/gskgliconcache.c
index 5097ae597e..4bbbdbb4da 100644
--- a/gsk/gl/gskgliconcache.c
+++ b/gsk/gl/gskgliconcache.c
@@ -1,6 +1,7 @@
#include "gskgliconcacheprivate.h"
#include "gskgltextureatlasprivate.h"
#include "gdk/gdktextureprivate.h"
+#include "gdk/gdkmemorytextureprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include <epoxy/gl.h>
@@ -134,7 +135,10 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
int packed_y = 0;
cairo_surface_t *surface;
unsigned char *surface_data;
+ unsigned char *pixel_data;
+ guchar *free_data = NULL;
guint gl_format;
+ guint gl_type;
gsk_gl_texture_atlases_pack (self->atlases, width + 2, height + 2, &atlas, &packed_x, &packed_y);
@@ -158,36 +162,47 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
"Uploading texture");
if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
- gl_format = GL_RGBA;
+ {
+ pixel_data = free_data = g_malloc (width * height * 4);
+ gdk_memory_convert (pixel_data, width * 4,
+ GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ surface_data, cairo_image_surface_get_stride (surface),
+ GDK_MEMORY_DEFAULT, width, height);
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ }
else
- gl_format = GL_BGRA;
+ {
+ pixel_data = surface_data;
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1,
width, height,
- gl_format,
- GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding top */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y,
width, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1,
1, height,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding top left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y,
1, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
@@ -195,14 +210,14 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y + 1,
1, height,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding top right */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + width + 1, packed_y,
1, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding bottom */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
@@ -210,22 +225,22 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1, packed_y + 1 + height,
width, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding bottom left */
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x, packed_y + 1 + height,
1, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Padding bottom right */
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
glTexSubImage2D (GL_TEXTURE_2D, 0,
packed_x + 1 + width, packed_y + 1 + height,
1, 1,
- gl_format, GL_UNSIGNED_BYTE,
- surface_data);
+ gl_format, gl_type,
+ pixel_data);
/* Reset this */
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
@@ -236,6 +251,7 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self,
*out_icon_data = icon_data;
cairo_surface_destroy (surface);
+ g_free (free_data);
#if 0
{