diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c index a31ce36790..a7ea646244 100644 --- a/demos/gtk-demo/main.c +++ b/demos/gtk-demo/main.c @@ -512,7 +512,7 @@ load_file (const char *demoname, info_buffer = gtk_text_buffer_new (NULL); gtk_text_buffer_create_tag (info_buffer, "title", - "font", "Sans 18", + "size", 18 * 1024, "pixels-below-lines", 10, NULL); diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index b7640edf87..4d7ef4b3d3 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -282,7 +282,7 @@ snapshot_uniforms (GskGLUniformState *state, { const GskGLUniformMapping *mapping = &program->mappings[i]; - if (!mapping->info.initial && mapping->location > -1) + if (!mapping->info.initial && mapping->info.format && mapping->location > -1) { uniform[count].location = mapping->location; uniform[count].info = mapping->info; diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c index 327dea93ff..0390f97702 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -44,9 +44,6 @@ #include #include -#define ATLAS_SIZE 512 -#define MAX_OLD_RATIO 0.5 - G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT) static guint @@ -156,50 +153,6 @@ gsk_gl_driver_collect_unused_textures (GskGLDriver *self, return collected; } -static void -gsk_gl_texture_atlas_free (GskGLTextureAtlas *atlas) -{ - if (atlas->texture_id != 0) - { - glDeleteTextures (1, &atlas->texture_id); - atlas->texture_id = 0; - } - - g_clear_pointer (&atlas->nodes, g_free); - g_slice_free (GskGLTextureAtlas, atlas); -} - -GskGLTextureAtlas * -gsk_gl_driver_create_atlas (GskGLDriver *self) -{ - GskGLTextureAtlas *atlas; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - - atlas = g_slice_new0 (GskGLTextureAtlas); - atlas->width = ATLAS_SIZE; - atlas->height = ATLAS_SIZE; - /* TODO: We might want to change the strategy about the amount of - * nodes here? stb_rect_pack.h says width is optimal. */ - atlas->nodes = g_malloc0_n (atlas->width, sizeof (struct stbrp_node)); - stbrp_init_target (&atlas->context, atlas->width, atlas->height, atlas->nodes, atlas->width); - atlas->texture_id = gsk_gl_command_queue_create_texture (self->command_queue, - atlas->width, - atlas->height, - GL_RGBA8, - GL_LINEAR, - GL_LINEAR); - - gdk_gl_context_label_object_printf (gdk_gl_context_get_current (), - GL_TEXTURE, atlas->texture_id, - "Texture atlas %d", - atlas->texture_id); - - g_ptr_array_add (self->atlases, atlas); - - return atlas; -} - static void remove_program (gpointer data) { @@ -226,6 +179,29 @@ gsk_gl_driver_shader_weak_cb (gpointer data, g_hash_table_remove (self->shader_cache, where_object_was); } +G_GNUC_NULL_TERMINATED static inline GBytes * +join_sources (GBytes *first_bytes, + ...) +{ + GByteArray *byte_array = g_byte_array_new (); + GBytes *bytes = first_bytes; + va_list args; + + va_start (args, first_bytes); + while (bytes != NULL) + { + gsize len; + const guint8 *data = g_bytes_get_data (bytes, &len); + if (len > 0) + g_byte_array_append (byte_array, data, len); + g_bytes_unref (bytes); + bytes = va_arg (args, GBytes *); + } + va_end (args); + + return g_byte_array_free_to_bytes (byte_array); +} + static void gsk_gl_driver_dispose (GObject *object) { @@ -235,6 +211,10 @@ gsk_gl_driver_dispose (GObject *object) g_assert (self->in_frame == FALSE); #define GSK_GL_NO_UNIFORMS +#define GSK_GL_SHADER_RESOURCE(name) +#define GSK_GL_SHADER_STRING(str) +#define GSK_GL_SHADER_SINGLE(name) +#define GSK_GL_SHADER_JOINED(kind, ...) #define GSK_GL_ADD_UNIFORM(pos, KEY, name) #define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \ GSK_GL_DELETE_PROGRAM(name); \ @@ -248,6 +228,10 @@ gsk_gl_driver_dispose (GObject *object) } G_STMT_END; # include "gskglprograms.defs" #undef GSK_GL_NO_UNIFORMS +#undef GSK_GL_SHADER_RESOURCE +#undef GSK_GL_SHADER_STRING +#undef GSK_GL_SHADER_SINGLE +#undef GSK_GL_SHADER_JOINED #undef GSK_GL_ADD_UNIFORM #undef GSK_GL_DEFINE_PROGRAM @@ -289,11 +273,10 @@ gsk_gl_driver_dispose (GObject *object) g_assert (!self->texture_id_to_key || g_hash_table_size (self->texture_id_to_key) == 0); g_assert (!self->key_to_texture_id|| g_hash_table_size (self->key_to_texture_id) == 0); - g_clear_object (&self->glyphs); - g_clear_object (&self->icons); - g_clear_object (&self->shadows); + g_clear_object (&self->glyphs_library); + g_clear_object (&self->icons_library); + g_clear_object (&self->shadows_library); - g_clear_pointer (&self->atlases, g_ptr_array_unref); g_clear_pointer (&self->autorelease_framebuffers, g_array_unref); g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref); g_clear_pointer (&self->textures, g_hash_table_unref); @@ -330,7 +313,6 @@ gsk_gl_driver_init (GskGLDriver *self) self->shader_cache = g_hash_table_new_full (NULL, NULL, NULL, remove_program); self->texture_pool = g_array_new (FALSE, FALSE, sizeof (guint)); self->render_targets = g_ptr_array_new (); - self->atlases = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); } static gboolean @@ -348,14 +330,14 @@ gsk_gl_driver_load_programs (GskGLDriver *self, /* Setup preambles that are shared by all shaders */ gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_ALL, - "/org/gtk/libgsk/gl/preamble.glsl"); + GSK_GL_COMPILER_ALL, + "/org/gtk/libgsk/gl/preamble.glsl"); gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_VERTEX, - "/org/gtk/libgsk/gl/preamble.vs.glsl"); + GSK_GL_COMPILER_VERTEX, + "/org/gtk/libgsk/gl/preamble.vs.glsl"); gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_FRAGMENT, - "/org/gtk/libgsk/gl/preamble.fs.glsl"); + GSK_GL_COMPILER_FRAGMENT, + "/org/gtk/libgsk/gl/preamble.fs.glsl"); /* Setup attributes that are provided via VBO */ gsk_gl_compiler_bind_attribute (compiler, "aPosition", 0); @@ -365,10 +347,28 @@ gsk_gl_driver_load_programs (GskGLDriver *self, /* Use XMacros to register all of our programs and their uniforms */ #define GSK_GL_NO_UNIFORMS +#define GSK_GL_SHADER_RESOURCE(name) \ + g_bytes_ref(g_resources_lookup_data("/org/gtk/libgsk/gl/" name, 0, NULL)) +#define GSK_GL_SHADER_STRING(str) \ + g_bytes_new_static(str, strlen(str)) +#define GSK_GL_SHADER_SINGLE(bytes) \ + G_STMT_START { \ + GBytes *b = bytes; \ + gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_ALL, b); \ + g_bytes_unref (b); \ + } G_STMT_END; +#define GSK_GL_SHADER_JOINED(kind, ...) \ + G_STMT_START { \ + GBytes *bytes = join_sources(__VA_ARGS__); \ + gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_##kind, bytes); \ + g_bytes_unref (bytes); \ + } G_STMT_END; #define GSK_GL_ADD_UNIFORM(pos, KEY, name) \ gsk_gl_program_add_uniform (program, #name, UNIFORM_##KEY); -#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \ - gsk_gl_compiler_set_source_from_resource (compiler, GSK_GL_COMPILER_ALL, resource); \ +#define GSK_GL_DEFINE_PROGRAM(name, sources, uniforms) \ + gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \ + gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \ + sources \ GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \ GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \ GSK_GL_COMPILE_PROGRAM(name, uniforms, ""); @@ -401,6 +401,11 @@ gsk_gl_driver_load_programs (GskGLDriver *self, #undef GSK_GL_DEFINE_PROGRAM_CLIP #undef GSK_GL_DEFINE_PROGRAM #undef GSK_GL_ADD_UNIFORM +#undef GSK_GL_SHADER_SINGLE +#undef GSK_GL_SHADER_JOINED +#undef GSK_GL_SHADER_RESOURCE +#undef GSK_GL_SHADER_STRING +#undef GSK_GL_NO_UNIFORMS ret = TRUE; @@ -456,9 +461,9 @@ gsk_gl_driver_new (GskGLCommandQueue *command_queue, return NULL; } - self->glyphs = gsk_gl_glyph_library_new (self); - self->icons = gsk_gl_icon_library_new (self); - self->shadows = gsk_gl_shadow_library_new (self); + self->glyphs_library = gsk_gl_glyph_library_new (self); + self->icons_library = gsk_gl_icon_library_new (self); + self->shadows_library = gsk_gl_shadow_library_new (self); gdk_profiler_end_mark (before, "create GskGLDriver", NULL); @@ -518,37 +523,6 @@ failure: return g_steal_pointer (&driver); } -static GPtrArray * -gsk_gl_driver_compact_atlases (GskGLDriver *self) -{ - GPtrArray *removed = NULL; - - g_assert (GSK_IS_GL_DRIVER (self)); - - for (guint i = self->atlases->len; i > 0; i--) - { - GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1); - - if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO) - { - GSK_NOTE (GLYPH_CACHE, - g_message ("Dropping atlas %d (%g.2%% old)", i, - 100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas))); - if (removed == NULL) - removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); - g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1)); - } - } - - GSK_NOTE (GLYPH_CACHE, { - static guint timestamp; - if (timestamp++ % 60 == 0) - g_message ("%d atlases", self->atlases->len); - }); - - return removed; -} - /** * gsk_gl_driver_begin_frame: * @self: a `GskGLDriver` @@ -565,7 +539,6 @@ gsk_gl_driver_begin_frame (GskGLDriver *self, GskGLCommandQueue *command_queue) { gint64 last_frame_id; - GPtrArray *removed; g_return_if_fail (GSK_IS_GL_DRIVER (self)); g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue)); @@ -580,19 +553,14 @@ gsk_gl_driver_begin_frame (GskGLDriver *self, gsk_gl_command_queue_begin_frame (self->command_queue); - /* Compact atlases with too many freed pixels */ - removed = gsk_gl_driver_compact_atlases (self); - /* Mark unused pixel regions of the atlases */ - gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons), - self->current_frame_id, - removed); - gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs), - self->current_frame_id, - removed); + gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons_library), + self->current_frame_id); + gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs_library), + self->current_frame_id); /* Cleanup old shadows */ - gsk_gl_shadow_library_begin_frame (self->shadows); + gsk_gl_shadow_library_begin_frame (self->shadows_library); /* Remove all textures that are from a previous frame or are no * longer used by linked GdkTexture. We do this at the beginning @@ -600,9 +568,6 @@ gsk_gl_driver_begin_frame (GskGLDriver *self, * we block on any resources while delivering our frames. */ gsk_gl_driver_collect_unused_textures (self, last_frame_id - 1); - - /* Now free atlas textures */ - g_clear_pointer (&removed, g_ptr_array_unref); } /** @@ -1182,14 +1147,23 @@ void gsk_gl_driver_save_atlases_to_png (GskGLDriver *self, const char *directory) { + GPtrArray *atlases; + g_return_if_fail (GSK_IS_GL_DRIVER (self)); if (directory == NULL) directory = "."; - for (guint i = 0; i < self->atlases->len; i++) +#define copy_atlases(dst, library) \ + g_ptr_array_extend(dst, GSK_GL_TEXTURE_LIBRARY(library)->atlases, NULL, NULL) + atlases = g_ptr_array_new (); + copy_atlases (atlases, self->glyphs_library); + copy_atlases (atlases, self->icons_library); +#undef copy_atlases + + for (guint i = 0; i < atlases->len; i++) { - GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i); + GskGLTextureAtlas *atlas = g_ptr_array_index (atlases, i); char *filename = g_strdup_printf ("%s%sframe-%d-atlas-%d.png", directory, G_DIR_SEPARATOR_S, @@ -1198,6 +1172,8 @@ gsk_gl_driver_save_atlases_to_png (GskGLDriver *self, write_atlas_to_png (self, atlas, filename); g_free (filename); } + + g_ptr_array_unref (atlases); } #endif diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h index 4500962ed8..accae5b3bb 100644 --- a/gsk/gl/gskgldriverprivate.h +++ b/gsk/gl/gskgldriverprivate.h @@ -100,17 +100,15 @@ struct _GskGLDriver GskGLCommandQueue *shared_command_queue; GskGLCommandQueue *command_queue; - GskGLGlyphLibrary *glyphs; - GskGLIconLibrary *icons; - GskGLShadowLibrary *shadows; + GskGLGlyphLibrary *glyphs_library; + GskGLIconLibrary *icons_library; + GskGLShadowLibrary *shadows_library; GArray *texture_pool; GHashTable *textures; GHashTable *key_to_texture_id; GHashTable *texture_id_to_key; - GPtrArray *atlases; - GHashTable *shader_cache; GArray *autorelease_framebuffers; @@ -184,7 +182,6 @@ void gsk_gl_driver_add_texture_slices (GskGLDriver *s GskGLProgram * gsk_gl_driver_lookup_shader (GskGLDriver *self, GskGLShader *shader, GError **error); -GskGLTextureAtlas * gsk_gl_driver_create_atlas (GskGLDriver *self); #ifdef G_ENABLE_DEBUG void gsk_gl_driver_save_atlases_to_png (GskGLDriver *self, diff --git a/gsk/gl/gskglglyphlibrary.c b/gsk/gl/gskglglyphlibrary.c index b749384674..58e34bc938 100644 --- a/gsk/gl/gskglglyphlibrary.c +++ b/gsk/gl/gskglglyphlibrary.c @@ -84,15 +84,64 @@ gsk_gl_glyph_value_free (gpointer data) } static void -gsk_gl_glyph_library_begin_frame (GskGLTextureLibrary *library, - gint64 frame_id, - GPtrArray *removed_atlases) +gsk_gl_glyph_library_clear_cache (GskGLTextureLibrary *library) { GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)library; + g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); + memset (self->front, 0, sizeof self->front); } +static void +gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self, + GskGLTextureAtlas *atlas) +{ + gboolean packed G_GNUC_UNUSED; + int x, y; + guint gl_format; + guint gl_type; + guint8 pixel_data[4 * 3 * 3]; + + g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); + g_assert (atlas != NULL); + + /* Insert a single pixel at 0,0 for use in coloring */ + + gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), + "Initializing Atlas"); + + packed = gsk_gl_texture_library_allocate (self, atlas, 3, 3, &x, &y); + g_assert (packed); + g_assert (x == 0 && y == 0); + + memset (pixel_data, 255, sizeof pixel_data); + + if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) + { + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + } + else + { + 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, + 0, 0, + 3, 3, + gl_format, gl_type, + pixel_data); + + gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); + + self->driver->command_queue->n_uploads++; +} + + static void gsk_gl_glyph_library_finalize (GObject *object) { @@ -111,7 +160,8 @@ gsk_gl_glyph_library_class_init (GskGLGlyphLibraryClass *klass) object_class->finalize = gsk_gl_glyph_library_finalize; - library_class->begin_frame = gsk_gl_glyph_library_begin_frame; + library_class->clear_cache = gsk_gl_glyph_library_clear_cache; + library_class->init_atlas = gsk_gl_glyph_library_init_atlas; } static void diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs index a6d9515a78..1ff99fab89 100644 --- a/gsk/gl/gskglprograms.defs +++ b/gsk/gl/gskglprograms.defs @@ -1,71 +1,71 @@ GSK_GL_DEFINE_PROGRAM (blend, - "/org/gtk/libgsk/gl/blend.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blend.glsl")), GSK_GL_ADD_UNIFORM (1, BLEND_SOURCE2, u_source2) GSK_GL_ADD_UNIFORM (2, BLEND_MODE, u_mode)) GSK_GL_DEFINE_PROGRAM (blit, - "/org/gtk/libgsk/gl/blit.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blit.glsl")), GSK_GL_NO_UNIFORMS) GSK_GL_DEFINE_PROGRAM (blur, - "/org/gtk/libgsk/gl/blur.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blur.glsl")), GSK_GL_ADD_UNIFORM (1, BLUR_RADIUS, u_blur_radius) GSK_GL_ADD_UNIFORM (2, BLUR_SIZE, u_blur_size) GSK_GL_ADD_UNIFORM (3, BLUR_DIR, u_blur_dir)) GSK_GL_DEFINE_PROGRAM (border, - "/org/gtk/libgsk/gl/border.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("border.glsl")), GSK_GL_ADD_UNIFORM (1, BORDER_WIDTHS, u_widths) GSK_GL_ADD_UNIFORM (2, BORDER_OUTLINE_RECT, u_outline_rect)) GSK_GL_DEFINE_PROGRAM (color, - "/org/gtk/libgsk/gl/color.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color.glsl")), GSK_GL_NO_UNIFORMS) GSK_GL_DEFINE_PROGRAM (coloring, - "/org/gtk/libgsk/gl/coloring.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("coloring.glsl")), GSK_GL_NO_UNIFORMS) GSK_GL_DEFINE_PROGRAM (color_matrix, - "/org/gtk/libgsk/gl/color_matrix.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color_matrix.glsl")), GSK_GL_ADD_UNIFORM (1, COLOR_MATRIX_COLOR_MATRIX, u_color_matrix) GSK_GL_ADD_UNIFORM (2, COLOR_MATRIX_COLOR_OFFSET, u_color_offset)) GSK_GL_DEFINE_PROGRAM (conic_gradient, - "/org/gtk/libgsk/gl/conic_gradient.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("conic_gradient.glsl")), GSK_GL_ADD_UNIFORM (1, CONIC_GRADIENT_COLOR_STOPS, u_color_stops) GSK_GL_ADD_UNIFORM (2, CONIC_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) GSK_GL_ADD_UNIFORM (3, CONIC_GRADIENT_GEOMETRY, u_geometry)) GSK_GL_DEFINE_PROGRAM (cross_fade, - "/org/gtk/libgsk/gl/cross_fade.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("cross_fade.glsl")), GSK_GL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress) GSK_GL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2)) GSK_GL_DEFINE_PROGRAM (filled_border, - "/org/gtk/libgsk/gl/filled_border.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("filled_border.glsl")), GSK_GL_ADD_UNIFORM (1, FILLED_BORDER_WIDTHS, u_widths) GSK_GL_ADD_UNIFORM (2, FILLED_BORDER_OUTLINE_RECT, u_outline_rect)) GSK_GL_DEFINE_PROGRAM (inset_shadow, - "/org/gtk/libgsk/gl/inset_shadow.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("inset_shadow.glsl")), GSK_GL_ADD_UNIFORM (1, INSET_SHADOW_SPREAD, u_spread) GSK_GL_ADD_UNIFORM (2, INSET_SHADOW_OFFSET, u_offset) GSK_GL_ADD_UNIFORM (3, INSET_SHADOW_OUTLINE_RECT, u_outline_rect)) GSK_GL_DEFINE_PROGRAM (linear_gradient, - "/org/gtk/libgsk/gl/linear_gradient.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("linear_gradient.glsl")), GSK_GL_ADD_UNIFORM (1, LINEAR_GRADIENT_COLOR_STOPS, u_color_stops) GSK_GL_ADD_UNIFORM (2, LINEAR_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) GSK_GL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points) GSK_GL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat)) GSK_GL_DEFINE_PROGRAM (outset_shadow, - "/org/gtk/libgsk/gl/outset_shadow.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")), GSK_GL_ADD_UNIFORM (1, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect)) GSK_GL_DEFINE_PROGRAM (radial_gradient, - "/org/gtk/libgsk/gl/radial_gradient.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("radial_gradient.glsl")), GSK_GL_ADD_UNIFORM (1, RADIAL_GRADIENT_COLOR_STOPS, u_color_stops) GSK_GL_ADD_UNIFORM (2, RADIAL_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) GSK_GL_ADD_UNIFORM (3, RADIAL_GRADIENT_REPEAT, u_repeat) @@ -73,12 +73,12 @@ GSK_GL_DEFINE_PROGRAM (radial_gradient, GSK_GL_ADD_UNIFORM (5, RADIAL_GRADIENT_GEOMETRY, u_geometry)) GSK_GL_DEFINE_PROGRAM (repeat, - "/org/gtk/libgsk/gl/repeat.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("repeat.glsl")), GSK_GL_ADD_UNIFORM (1, REPEAT_CHILD_BOUNDS, u_child_bounds) GSK_GL_ADD_UNIFORM (2, REPEAT_TEXTURE_RECT, u_texture_rect)) GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow, - "/org/gtk/libgsk/gl/unblurred_outset_shadow.glsl", + GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("unblurred_outset_shadow.glsl")), GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread) GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset) GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect)) diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index afefe7a018..30c6cd7a41 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -2512,7 +2512,9 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job, scaled_outline.corner[i].height *= scale_y; } - cached_tid = gsk_gl_shadow_library_lookup (job->driver->shadows, &scaled_outline, blur_radius); + cached_tid = gsk_gl_shadow_library_lookup (job->driver->shadows_library, + &scaled_outline, + blur_radius); if (cached_tid == 0) { @@ -2574,7 +2576,7 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job, blur_radius * scale_x, blur_radius * scale_y); - gsk_gl_shadow_library_insert (job->driver->shadows, + gsk_gl_shadow_library_insert (job->driver->shadows_library, &scaled_outline, blur_radius, blurred_texture_id); @@ -2996,7 +2998,7 @@ gsk_gl_render_job_visit_text_node (GskGLRenderJob *job, guint num_glyphs = gsk_text_node_get_num_glyphs (node); float x = offset->x + job->offset_x; float y = offset->y + job->offset_y; - GskGLGlyphLibrary *library = job->driver->glyphs; + GskGLGlyphLibrary *library = job->driver->glyphs_library; GskGLCommandBatch *batch; int x_position = 0; GskGLGlyphKey lookup; @@ -3499,14 +3501,14 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job, GdkTexture *texture, GskGLRenderOffscreen *offscreen) { - if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons, + if (gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library, texture->width, texture->height) && !GDK_IS_GL_TEXTURE (texture)) { const GskGLIconData *icon_data; - gsk_gl_icon_library_lookup_or_add (job->driver->icons, texture, &icon_data); + gsk_gl_icon_library_lookup_or_add (job->driver->icons_library, texture, &icon_data); offscreen->texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data); memcpy (&offscreen->area, &icon_data->entry.area, sizeof offscreen->area); } diff --git a/gsk/gl/gskglshadowlibrary.c b/gsk/gl/gskglshadowlibrary.c index 86e4e5a476..119ba8145b 100644 --- a/gsk/gl/gskglshadowlibrary.c +++ b/gsk/gl/gskglshadowlibrary.c @@ -29,9 +29,9 @@ struct _GskGLShadowLibrary { - GObject parent_instance; + GObject parent_instance; GskGLDriver *driver; - GArray *shadows; + GArray *shadows; }; typedef struct _Shadow diff --git a/gsk/gl/gskgltexturelibrary.c b/gsk/gl/gskgltexturelibrary.c index 3d32c95945..3e6463a848 100644 --- a/gsk/gl/gskgltexturelibrary.c +++ b/gsk/gl/gskgltexturelibrary.c @@ -27,7 +27,10 @@ #include "gskgldriverprivate.h" #include "gskgltexturelibraryprivate.h" -#define MAX_FRAME_AGE 60 +#define DEFAULT_MAX_FRAME_AGE 60 +#define DEFAULT_ATLAS_WIDTH 512 +#define DEFAULT_ATLAS_HEIGHT 512 +#define MAX_OLD_RATIO 0.5 G_DEFINE_ABSTRACT_TYPE (GskGLTextureLibrary, gsk_gl_texture_library, G_TYPE_OBJECT) @@ -39,6 +42,143 @@ enum { static GParamSpec *properties [N_PROPS]; +static void +gsk_gl_texture_atlas_free (GskGLTextureAtlas *atlas) +{ + if (atlas->texture_id != 0) + { + glDeleteTextures (1, &atlas->texture_id); + atlas->texture_id = 0; + } + + g_clear_pointer (&atlas->nodes, g_free); + g_slice_free (GskGLTextureAtlas, atlas); +} + +static gboolean +gsk_gl_texture_library_real_compact (GskGLTextureLibrary *self, + gint64 frame_id) +{ + GPtrArray *removed = NULL; + gboolean ret = FALSE; + gboolean periodic_scan; + + g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); + + periodic_scan = (self->max_frame_age > 0 && + (frame_id % self->max_frame_age) == 0); + + for (guint i = self->atlases->len; i > 0; i--) + { + GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1); + + if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO) + { + GSK_NOTE (GLYPH_CACHE, + g_message ("Dropping atlas %d (%g.2%% old)", i, + 100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas))); + if (removed == NULL) + removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); + g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1)); + } + } + + if (periodic_scan || removed != NULL) + { + GskGLTextureAtlasEntry *entry; + GHashTableIter iter; + guint dropped = 0; + guint atlased = 0; + + g_hash_table_iter_init (&iter, self->hash_table); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry)) + { + if (entry->is_atlased) + { + if (removed && g_ptr_array_find (removed, entry->atlas, NULL)) + { + g_hash_table_iter_remove (&iter); + dropped++; + } + else if (periodic_scan) + { + gsk_gl_texture_atlas_entry_mark_unused (entry); + entry->accessed = FALSE; + if (entry->is_atlased) + atlased++; + } + } + else if (!entry->accessed) + { + gsk_gl_driver_release_texture (self->driver, entry->texture); + g_hash_table_iter_remove (&iter); + dropped++; + } + } + + GSK_NOTE (GLYPH_CACHE, g_message ("%s: Dropped %d individual items", + G_OBJECT_TYPE_NAME (self), + dropped); + g_message ("%s: %d items cached (%d atlased, %d individually)", + G_OBJECT_TYPE_NAME (self), + g_hash_table_size (self->hash_table), + atlased, + g_hash_table_size (self->hash_table) - atlased)); + + if (dropped > 0) + gsk_gl_texture_library_clear_cache (self); + + ret = TRUE; + + g_clear_pointer (&removed, g_ptr_array_unref); + } + + GSK_NOTE (GLYPH_CACHE, { + static gint64 last_message; + gint64 now = g_get_monotonic_time (); + if (now - last_message > G_USEC_PER_SEC) + { + last_message = now; + g_message ("%s contains %d atlases", + G_OBJECT_TYPE_NAME (self), + self->atlases->len); + } + }); + + return ret; +} + +static gboolean +gsk_gl_texture_library_real_allocate (GskGLTextureLibrary *self, + GskGLTextureAtlas *atlas, + int width, + int height, + int *out_x, + int *out_y) +{ + stbrp_rect rect; + + g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); + g_assert (atlas != NULL); + g_assert (width > 0); + g_assert (height > 0); + g_assert (out_x != NULL); + g_assert (out_y != NULL); + + rect.w = width; + rect.h = height; + + stbrp_pack_rects (&atlas->context, &rect, 1); + + if (rect.was_packed) + { + *out_x = rect.x; + *out_y = rect.y; + } + + return rect.was_packed; +} + static void gsk_gl_texture_library_constructed (GObject *object) { @@ -52,6 +192,7 @@ gsk_gl_texture_library_dispose (GObject *object) { GskGLTextureLibrary *self = (GskGLTextureLibrary *)object; + g_clear_pointer (&self->atlases, g_ptr_array_unref); g_clear_object (&self->driver); G_OBJECT_CLASS (gsk_gl_texture_library_parent_class)->dispose (object); @@ -105,6 +246,9 @@ gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass) object_class->get_property = gsk_gl_texture_library_get_property; object_class->set_property = gsk_gl_texture_library_set_property; + klass->compact = gsk_gl_texture_library_real_compact; + klass->allocate = gsk_gl_texture_library_real_allocate; + properties [PROP_DRIVER] = g_param_spec_object ("driver", "Driver", @@ -118,6 +262,10 @@ gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass) static void gsk_gl_texture_library_init (GskGLTextureLibrary *self) { + self->max_frame_age = DEFAULT_MAX_FRAME_AGE; + self->atlas_width = DEFAULT_ATLAS_WIDTH; + self->atlas_height = DEFAULT_ATLAS_HEIGHT; + self->atlases = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); } void @@ -136,78 +284,14 @@ gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, - gint64 frame_id, - GPtrArray *removed_atlases) + gint64 frame_id) { - GHashTableIter iter; - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); + gsk_gl_texture_library_compact (self, frame_id); + if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame) - GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id, removed_atlases); - - if (removed_atlases != NULL) - { - GskGLTextureAtlasEntry *entry; - guint dropped = 0; - - g_hash_table_iter_init (&iter, self->hash_table); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry)) - { - if (entry->is_atlased) - { - for (guint i = 0; i < removed_atlases->len; i++) - { - GskGLTextureAtlas *atlas = g_ptr_array_index (removed_atlases, i); - - if (atlas == entry->atlas) - { - g_hash_table_iter_remove (&iter); - dropped++; - break; - } - } - } - } - - GSK_NOTE (GLYPH_CACHE, - if (dropped > 0) - g_message ("%s: Dropped %d items", - G_OBJECT_TYPE_NAME (self), dropped)); - } - - if (frame_id % MAX_FRAME_AGE == 0) - { - GskGLTextureAtlasEntry *entry; - int atlased = 0; - int dropped = 0; - - g_hash_table_iter_init (&iter, self->hash_table); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry)) - { - if (!entry->is_atlased && !entry->accessed) - { - gsk_gl_driver_release_texture (self->driver, entry->texture); - g_hash_table_iter_remove (&iter); - dropped++; - continue; - } - - gsk_gl_texture_atlas_entry_mark_unused (entry); - entry->accessed = FALSE; - if (entry->is_atlased) - atlased++; - } - - GSK_NOTE (GLYPH_CACHE, g_message ("%s: Dropped %d individual items", - G_OBJECT_TYPE_NAME (self), - dropped); - g_message ("%s: %d items cached (%d atlased, %d individually)", - G_OBJECT_TYPE_NAME (self), - g_hash_table_size (self->hash_table), - atlased, - g_hash_table_size (self->hash_table) - atlased)); - } + GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id); } static GskGLTexture * @@ -234,90 +318,29 @@ gsk_gl_texture_library_pack_one (GskGLTextureLibrary *self, return texture; } -static inline gboolean -gsk_gl_texture_atlas_pack (GskGLTextureAtlas *self, - int width, - int height, - int *out_x, - int *out_y) -{ - stbrp_rect rect; - - rect.w = width; - rect.h = height; - - stbrp_pack_rects (&self->context, &rect, 1); - - if (rect.was_packed) - { - *out_x = rect.x; - *out_y = rect.y; - } - - return rect.was_packed; -} - static void -gsk_gl_texture_atlas_initialize (GskGLDriver *driver, - GskGLTextureAtlas *atlas) -{ - /* Insert a single pixel at 0,0 for use in coloring */ - - gboolean packed G_GNUC_UNUSED; - int x, y; - guint gl_format; - guint gl_type; - guint8 pixel_data[4 * 3 * 3]; - - gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), - "Initializing Atlas"); - - packed = gsk_gl_texture_atlas_pack (atlas, 3, 3, &x, &y); - g_assert (packed); - g_assert (x == 0 && y == 0); - - memset (pixel_data, 255, sizeof pixel_data); - - if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - { - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - } - else - { - 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, - 0, 0, - 3, 3, - gl_format, gl_type, - pixel_data); - - gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); - - driver->command_queue->n_uploads++; -} - -static void -gsk_gl_texture_atlases_pack (GskGLDriver *driver, - int width, - int height, - GskGLTextureAtlas **out_atlas, - int *out_x, - int *out_y) +gsk_gl_texture_library_pack_any_atlas (GskGLTextureLibrary *self, + int width, + int height, + GskGLTextureAtlas **out_atlas, + int *out_x, + int *out_y) { GskGLTextureAtlas *atlas = NULL; int x, y; - for (guint i = 0; i < driver->atlases->len; i++) - { - atlas = g_ptr_array_index (driver->atlases, i); + g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); + g_assert (width > 0); + g_assert (height > 0); + g_assert (out_atlas != NULL); + g_assert (out_x != NULL); + g_assert (out_y != NULL); - if (gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y)) + for (guint i = 0; i < self->atlases->len; i++) + { + atlas = g_ptr_array_index (self->atlases, i); + + if (gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y)) break; atlas = NULL; @@ -326,12 +349,10 @@ gsk_gl_texture_atlases_pack (GskGLDriver *driver, if (atlas == NULL) { /* No atlas has enough space, so create a new one... */ - atlas = gsk_gl_driver_create_atlas (driver); - - gsk_gl_texture_atlas_initialize (driver, atlas); + atlas = gsk_gl_texture_library_acquire_atlas (self); /* Pack it onto that one, which surely has enough space... */ - if (!gsk_gl_texture_atlas_pack (atlas, width, height, &x, &y)) + if (!gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y)) g_assert_not_reached (); } @@ -380,17 +401,19 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self, *out_packed_x = 0; *out_packed_y = 0; } - else if (width <= self->max_entry_size && height <= self->max_entry_size) + else if (self->max_entry_size == 0 || + (width <= self->max_entry_size && + height <= self->max_entry_size)) { int packed_x; int packed_y; - gsk_gl_texture_atlases_pack (self->driver, - padding + width + padding, - padding + height + padding, - &atlas, - &packed_x, - &packed_y); + gsk_gl_texture_library_pack_any_atlas (self, + padding + width + padding, + padding + height + padding, + &atlas, + &packed_x, + &packed_y); entry->atlas = atlas; entry->is_atlased = TRUE; @@ -424,3 +447,134 @@ gsk_gl_texture_library_pack (GskGLTextureLibrary *self, return entry; } + +/* + * gsk_gl_texture_library_clear_cache: + * + * Clear the front cache if the texture library is using one. For + * example the glyph cache would drop it's front cache to force + * next lookups to fall through to the GHashTable key lookup. + */ +void +gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self) +{ + g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); + + if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache) + GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache (self); +} + +/* + * gsk_gl_texture_library_compact: + * + * Requests that the texture library compact it's altases. That + * generally means to traverse them to look for unused pixels over + * a certain threshold and release them if necessary. + * + * Returns: %TRUE if any compaction occurred. + */ +gboolean +gsk_gl_texture_library_compact (GskGLTextureLibrary *self, + gint64 frame_id) +{ + g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), FALSE); + + if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact) + return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact (self, frame_id); + + return FALSE; +} + +void +gsk_gl_texture_library_reset (GskGLTextureLibrary *self) +{ + g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); + + gsk_gl_texture_library_clear_cache (self); + + g_hash_table_remove_all (self->hash_table); + + if (self->atlases->len) + g_ptr_array_remove_range (self->atlases, 0, self->atlases->len); +} + +void +gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self, + int width, + int height) +{ + g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); + + if (width <= 0) + width = DEFAULT_ATLAS_WIDTH; + + if (height <= 0) + height = DEFAULT_ATLAS_HEIGHT; + + self->atlas_height = height; + self->atlas_width = width; + + gsk_gl_texture_library_reset (self); +} + +/* + * gsk_gl_texture_library_acquire_atlas: + * + * Allocates a new texture atlas based on the current size + * and format requirements. + */ +GskGLTextureAtlas * +gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self) +{ + GskGLTextureAtlas *atlas; + + g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), NULL); + g_return_val_if_fail (GSK_IS_GL_DRIVER (self->driver), NULL); + g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->driver->command_queue), NULL); + g_return_val_if_fail (self->atlas_width > 0, NULL); + g_return_val_if_fail (self->atlas_height > 0, NULL); + + atlas = g_slice_new0 (GskGLTextureAtlas); + atlas->width = self->atlas_width; + atlas->height = self->atlas_height; + /* TODO: We might want to change the strategy about the amount of + * nodes here? stb_rect_pack.h says width is optimal. */ + atlas->nodes = g_malloc0_n (atlas->width, sizeof (struct stbrp_node)); + stbrp_init_target (&atlas->context, atlas->width, atlas->height, atlas->nodes, atlas->width); + atlas->texture_id = gsk_gl_command_queue_create_texture (self->driver->command_queue, + atlas->width, + atlas->height, + GL_RGBA8, + GL_LINEAR, + GL_LINEAR); + + gdk_gl_context_label_object_printf (gdk_gl_context_get_current (), + GL_TEXTURE, atlas->texture_id, + "Texture atlas %d", + atlas->texture_id); + + g_ptr_array_add (self->atlases, atlas); + + if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas) + GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas (self, atlas); + + return atlas; +} + +gboolean +gsk_gl_texture_library_allocate (GskGLTextureLibrary *self, + GskGLTextureAtlas *atlas, + int width, + int height, + int *out_x, + int *out_y) +{ + g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); + g_assert (atlas != NULL); + g_assert (width > 0); + g_assert (height > 0); + g_assert (out_x != NULL); + g_assert (out_y != NULL); + + return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->allocate (self, atlas, width, height, out_x, out_y); +} diff --git a/gsk/gl/gskgltexturelibraryprivate.h b/gsk/gl/gskgltexturelibraryprivate.h index a784449889..a0292c497b 100644 --- a/gsk/gl/gskgltexturelibraryprivate.h +++ b/gsk/gl/gskgltexturelibraryprivate.h @@ -50,7 +50,6 @@ typedef struct _GskGLTextureAtlas */ int unused_pixels; - void *user_data; } GskGLTextureAtlas; typedef struct _GskGLTextureAtlasEntry @@ -89,40 +88,67 @@ typedef struct _GskGLTextureAtlasEntry typedef struct _GskGLTextureLibrary { - GObject parent_instance; + GObject parent_instance; GskGLDriver *driver; - GHashTable *hash_table; - guint max_entry_size; + GPtrArray *atlases; + GHashTable *hash_table; + guint max_entry_size; + guint max_frame_age; + guint atlas_width; + guint atlas_height; } GskGLTextureLibrary; typedef struct _GskGLTextureLibraryClass { GObjectClass parent_class; - void (*begin_frame) (GskGLTextureLibrary *library, - gint64 frame_id, - GPtrArray *removed_atlases); + void (*begin_frame) (GskGLTextureLibrary *library, + gint64 frame_id); + gboolean (*compact) (GskGLTextureLibrary *library, + gint64 frame_id); + void (*clear_cache) (GskGLTextureLibrary *library); + void (*init_atlas) (GskGLTextureLibrary *library, + GskGLTextureAtlas *atlas); + gboolean (*allocate) (GskGLTextureLibrary *library, + GskGLTextureAtlas *atlas, + int width, + int height, + int *out_x, + int *out_y); } GskGLTextureLibraryClass; G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskGLTextureLibrary, g_object_unref) -GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST; -void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, - GHashFunc hash_func, - GEqualFunc equal_func, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy); -void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, - gint64 frame_id, - GPtrArray *removed_atlases); -gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self, - gpointer key, - gsize valuelen, - guint width, - guint height, - int padding, - guint *out_packed_x, - guint *out_packed_y); +GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST; +gboolean gsk_gl_texture_library_compact (GskGLTextureLibrary *self, + gint64 frame_id); +void gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self); +void gsk_gl_texture_library_reset (GskGLTextureLibrary *self); +void gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self, + int width, + int height); +GskGLTextureAtlas *gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self); +void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, + GHashFunc hash_func, + GEqualFunc equal_func, + GDestroyNotify key_destroy, + GDestroyNotify value_destroy); +void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, + gint64 frame_id); +gboolean gsk_gl_texture_library_allocate (GskGLTextureLibrary *self, + GskGLTextureAtlas *atlas, + int width, + int height, + int *out_x, + int *out_y); +gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self, + gpointer key, + gsize valuelen, + guint width, + guint height, + int padding, + guint *out_packed_x, + guint *out_packed_y); static inline void gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self,