[gtk/wip/chergert/glproto: 717/920] flesh out glyph uploads a bit
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto: 717/920] flesh out glyph uploads a bit
- Date: Mon, 8 Feb 2021 19:15:39 +0000 (UTC)
commit 5a6be53302e8ace7a0769c47faf017fbd4bd738b
Author: Christian Hergert <chergert redhat com>
Date: Tue Jan 19 14:24:22 2021 -0800
flesh out glyph uploads a bit
still plenty to work on here, but some basics in place
gsk/next/gskglglyphlibrary.c | 171 +++++++++++++++++++++++-
gsk/next/gskglglyphlibraryprivate.h | 14 +-
gsk/next/gskgliconlibrary.c | 2 +
gsk/next/gskglrenderjob.c | 9 +-
gsk/next/gskglshadowlibrary.c | 2 +
gsk/next/gskgltextureatlas.c | 238 ----------------------------------
gsk/next/gskgltextureatlasprivate.h | 36 -----
gsk/next/gskgltexturelibrary.c | 23 +++-
gsk/next/gskgltexturelibraryprivate.h | 6 +-
9 files changed, 209 insertions(+), 292 deletions(-)
---
diff --git a/gsk/next/gskglglyphlibrary.c b/gsk/next/gskglglyphlibrary.c
index 3710697636..3b633bafdc 100644
--- a/gsk/next/gskglglyphlibrary.c
+++ b/gsk/next/gskglglyphlibrary.c
@@ -20,6 +20,9 @@
#include "config.h"
+#include <gdk/gdkglcontextprivate.h>
+#include <gdk/gdkmemorytextureprivate.h>
+
#include "gskgldriverprivate.h"
#include "gskglglyphlibraryprivate.h"
@@ -66,7 +69,10 @@ gsk_gl_glyph_key_equal (gconstpointer v1,
static void
gsk_gl_glyph_key_free (gpointer data)
{
- g_slice_free (GskGLGlyphKey, data);
+ GskGLGlyphKey *key = data;
+
+ g_clear_object (&key->font);
+ g_slice_free (GskGLGlyphKey, key);
}
static void
@@ -81,6 +87,7 @@ gsk_gl_glyph_library_finalize (GObject *object)
GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)object;
g_clear_pointer (&self->hash_table, g_hash_table_unref);
+ g_clear_pointer (&self->surface_data, g_free);
G_OBJECT_CLASS (gsk_gl_glyph_library_parent_class)->finalize (object);
}
@@ -104,9 +111,160 @@ gsk_gl_glyph_library_init (GskGLGlyphLibrary *self)
gsk_gl_glyph_value_free);
}
+static cairo_surface_t *
+gsk_gl_glyph_library_create_surface (GskGLGlyphLibrary *self,
+ int stride,
+ int width,
+ int height,
+ double device_scale)
+{
+ cairo_surface_t *surface;
+ gsize n_bytes;
+
+ g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
+ g_assert (width > 0);
+ g_assert (height > 0);
+
+ n_bytes = stride * height;
+
+ if G_LIKELY (n_bytes > self->surface_data_len)
+ {
+ self->surface_data = g_realloc (self->surface_data, n_bytes);
+ self->surface_data_len = n_bytes;
+ }
+
+ memset (self->surface_data, 0, n_bytes);
+ surface = cairo_image_surface_create_for_data (self->surface_data,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_set_device_scale (surface, device_scale, device_scale);
+
+ return surface;
+}
+
+static void
+render_glyph (cairo_surface_t *surface,
+ const cairo_scaled_font_t *scaled_font,
+ const GskGLGlyphKey *key,
+ const GskGLGlyphValue *value)
+{
+ cairo_t *cr;
+ PangoGlyphString glyph_string;
+ PangoGlyphInfo glyph_info;
+
+ g_assert (surface != NULL);
+ g_assert (scaled_font != NULL);
+
+ cr = cairo_create (surface);
+ cairo_set_scaled_font (cr, scaled_font);
+ cairo_set_source_rgba (cr, 1, 1, 1, 1);
+
+ glyph_info.glyph = key->glyph;
+ glyph_info.geometry.width = value->ink_rect.width * 1024;
+ if (glyph_info.glyph & PANGO_GLYPH_UNKNOWN_FLAG)
+ glyph_info.geometry.x_offset = 0;
+ else
+ glyph_info.geometry.x_offset = - value->ink_rect.x * 1024;
+ glyph_info.geometry.y_offset = - value->ink_rect.y * 1024;
+
+ glyph_string.num_glyphs = 1;
+ glyph_string.glyphs = &glyph_info;
+
+ pango_cairo_show_glyph_string (cr, key->font, &glyph_string);
+ cairo_destroy (cr);
+
+ cairo_surface_flush (surface);
+}
+
+static void
+gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
+ const GskGLGlyphKey *key,
+ const GskGLGlyphValue *value,
+ int width,
+ int height,
+ double device_scale)
+{
+ cairo_scaled_font_t *scaled_font;
+ GskGLTextureAtlas *atlas;
+ cairo_surface_t *surface;
+ guchar *pixel_data;
+ guchar *free_data = NULL;
+ guint gl_format;
+ guint gl_type;
+ guint texture_id;
+ gsize stride;
+ int x, y;
+
+ g_assert (GSK_IS_GL_GLYPH_LIBRARY (self));
+ g_assert (key != NULL);
+ g_assert (value != NULL);
+
+ scaled_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *)key->font);
+ if G_UNLIKELY (scaled_font == NULL ||
+ cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)
+ return;
+
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
+ atlas = value->entry.is_atlased ? value->entry.atlas : NULL;
+
+ gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
+ "Uploading glyph %d",
+ key->glyph);
+
+ surface = gsk_gl_glyph_library_create_surface (self, stride, width, height, device_scale);
+ render_glyph (surface, scaled_font, key, value);
+
+ texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value);
+
+ g_assert (texture_id > 0);
+
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4);
+ glBindTexture (GL_TEXTURE_2D, texture_id);
+
+ if G_UNLIKELY (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
+ {
+ pixel_data = free_data = g_malloc (width * height * 4);
+ gdk_memory_convert (pixel_data,
+ width * 4,
+ GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ cairo_image_surface_get_data (surface),
+ width * 4,
+ GDK_MEMORY_DEFAULT,
+ width, height);
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ }
+ else
+ {
+ pixel_data = cairo_image_surface_get_data (surface);
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ if G_LIKELY (atlas != NULL)
+ {
+ x = atlas->width * value->entry.area.origin.x;
+ y = atlas->width * value->entry.area.origin.y;
+ }
+ else
+ {
+ x = 0;
+ y = 0;
+ }
+
+ glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height,
+ gl_format, gl_type, pixel_data);
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+
+ cairo_surface_destroy (surface);
+ g_free (free_data);
+
+ gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ());
+}
+
gboolean
gsk_gl_glyph_library_add (GskGLGlyphLibrary *self,
- const GskGLGlyphKey *key,
+ GskGLGlyphKey *key,
const GskGLGlyphValue **out_value)
{
PangoRectangle ink_rect;
@@ -131,14 +289,21 @@ gsk_gl_glyph_library_add (GskGLGlyphLibrary *self,
value = gsk_gl_texture_library_pack (GSK_GL_TEXTURE_LIBRARY (self),
key,
- sizeof *key,
sizeof *value,
width,
height);
memcpy (&value->ink_rect, &ink_rect, sizeof ink_rect);
+ if (key->scale > 0 && width > 0 && height > 0)
+ gsk_gl_glyph_library_upload_glyph (self,
+ key,
+ value,
+ width,
+ height,
+ key->scale / 1024.0);
+ *out_value = value;
return TRUE;
}
diff --git a/gsk/next/gskglglyphlibraryprivate.h b/gsk/next/gskglglyphlibraryprivate.h
index b373339ce1..3e7a286148 100644
--- a/gsk/next/gskglglyphlibraryprivate.h
+++ b/gsk/next/gskglglyphlibraryprivate.h
@@ -54,13 +54,15 @@ G_DECLARE_FINAL_TYPE (GskGLGlyphLibrary, gsk_gl_glyph_library, GSK, GL_GLYPH_LIB
struct _GskGLGlyphLibrary
{
- GskGLTextureLibrary parent_instance;
- GHashTable *hash_table;
+ GskGLTextureLibrary parent_instance;
+ GHashTable *hash_table;
+ guint8 *surface_data;
+ gsize surface_data_len;
};
GskGLGlyphLibrary *gsk_gl_glyph_library_new (GskNextDriver *driver);
gboolean gsk_gl_glyph_library_add (GskGLGlyphLibrary *self,
- const GskGLGlyphKey *key,
+ GskGLGlyphKey *key,
const GskGLGlyphValue **out_value);
static inline int
@@ -86,6 +88,7 @@ gsk_gl_glyph_library_lookup_or_add (GskGLGlyphLibrary *self,
const GskGLGlyphValue **out_value)
{
GskGLTextureAtlasEntry *entry;
+ GskGLGlyphKey *k;
if G_LIKELY (gsk_gl_texture_library_lookup ((GskGLTextureLibrary *)self, key, &entry))
{
@@ -93,7 +96,10 @@ gsk_gl_glyph_library_lookup_or_add (GskGLGlyphLibrary *self,
return TRUE;
}
- return gsk_gl_glyph_library_add (self, key, out_value);
+ k = g_slice_copy (sizeof *key, key);
+ g_object_ref (k->font);
+
+ return gsk_gl_glyph_library_add (self, k, out_value);
}
G_END_DECLS
diff --git a/gsk/next/gskgliconlibrary.c b/gsk/next/gskgliconlibrary.c
index 5cbdccb04a..207ff04ea5 100644
--- a/gsk/next/gskgliconlibrary.c
+++ b/gsk/next/gskgliconlibrary.c
@@ -48,4 +48,6 @@ gsk_gl_icon_library_class_init (GskGLIconLibraryClass *klass)
static void
gsk_gl_icon_library_init (GskGLIconLibrary *self)
{
+ gsk_gl_texture_library_set_funcs (GSK_GL_TEXTURE_LIBRARY (self),
+ NULL, NULL, NULL, NULL);
}
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index c1ac95ec88..3e467c10ea 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -2538,13 +2538,20 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job,
texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (glyph);
- if (last_texture != texture_id)
+ if G_UNLIKELY (last_texture != texture_id)
{
+ gsk_gl_program_end_draw (program);
gsk_gl_program_set_uniform_texture (program,
UNIFORM_SHARED_SOURCE,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id);
+ gsk_gl_program_begin_draw (program,
+ &job->viewport,
+ &job->projection,
+ gsk_gl_render_job_get_modelview_matrix (job),
+ gsk_gl_render_job_get_clip (job),
+ job->alpha);
last_texture = texture_id;
}
diff --git a/gsk/next/gskglshadowlibrary.c b/gsk/next/gskglshadowlibrary.c
index dbcba6f6ed..f33c608b10 100644
--- a/gsk/next/gskglshadowlibrary.c
+++ b/gsk/next/gskglshadowlibrary.c
@@ -48,4 +48,6 @@ gsk_gl_shadow_library_class_init (GskGLShadowLibraryClass *klass)
static void
gsk_gl_shadow_library_init (GskGLShadowLibrary *self)
{
+ gsk_gl_texture_library_set_funcs (GSK_GL_TEXTURE_LIBRARY (self),
+ NULL, NULL, NULL, NULL);
}
diff --git a/gsk/next/gskgltexturelibrary.c b/gsk/next/gskgltexturelibrary.c
index c4ef5e849d..347fcf8490 100644
--- a/gsk/next/gskgltexturelibrary.c
+++ b/gsk/next/gskgltexturelibrary.c
@@ -232,8 +232,7 @@ gsk_gl_texture_atlases_pack (GskNextDriver *driver,
gpointer
gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
- gconstpointer key,
- gsize keylen,
+ gpointer key,
gsize valuelen,
guint width,
guint height)
@@ -243,14 +242,26 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self));
g_assert (key != NULL);
- g_assert (keylen > 0);
g_assert (valuelen > sizeof (GskGLTextureAtlasEntry));
entry = g_slice_alloc0 (valuelen);
entry->n_pixels = width * height;
entry->accessed = TRUE;
- if (width <= self->max_entry_size && height <= self->max_entry_size)
+ /* If our size is invisible then we just want an entry in the
+ * cache for faster lookups, but do not actually spend any texture
+ * allocations on this entry.
+ */
+ if (width <= 0 && height <= 0)
+ {
+ entry->is_atlased = FALSE;
+ entry->texture = NULL;
+ entry->area.origin.x = 0.0f;
+ entry->area.origin.y = 0.0f;
+ entry->area.size.width = 0.0f;
+ entry->area.size.height = 0.0f;
+ }
+ else if (width <= self->max_entry_size && height <= self->max_entry_size)
{
int packed_x;
int packed_y;
@@ -281,9 +292,7 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
entry->area.size.height = 1.0f;
}
- g_hash_table_insert (self->hash_table,
- g_slice_copy (keylen, key),
- entry);
+ g_hash_table_insert (self->hash_table, key, entry);
return entry;
}
diff --git a/gsk/next/gskgltexturelibraryprivate.h b/gsk/next/gskgltexturelibraryprivate.h
index 491f87b6b8..0f9b554954 100644
--- a/gsk/next/gskgltexturelibraryprivate.h
+++ b/gsk/next/gskgltexturelibraryprivate.h
@@ -113,8 +113,7 @@ void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self,
void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self);
void gsk_gl_texture_library_end_frame (GskGLTextureLibrary *self);
gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self,
- gconstpointer key,
- gsize keylen,
+ gpointer key,
gsize valuelen,
guint width,
guint height);
@@ -172,7 +171,8 @@ GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (gconstpointer d)
{
const GskGLTextureAtlasEntry *e = d;
- return e->is_atlased ? e->atlas->texture_id : e->texture->texture_id;
+ return e->is_atlased ? e->atlas->texture_id
+ : e->texture ? e->texture->texture_id : 0;
}
static inline double
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]