diff --git a/gsk/gl/gskglglyphcache.c b/gsk/gl/gskglglyphcache.c index 7cc899e82c..80216ab5be 100644 --- a/gsk/gl/gskglglyphcache.c +++ b/gsk/gl/gskglglyphcache.c @@ -269,13 +269,7 @@ gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache *cache, if (value) { - if (value->atlas && !value->used) - { - gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height); - value->used = TRUE; - } - value->accessed = TRUE; - + gsk_gl_glyph_cache_entry_validate (cache, value); *cached_glyph_out = value; return; } @@ -334,6 +328,8 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, { guint dropped = 0; + self->atlas_timestamp++; + g_hash_table_iter_init (&iter, self->hash_table); while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) { @@ -366,6 +362,12 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, { gsk_gl_driver_destroy_texture (driver, value->texture_id); g_hash_table_iter_remove (&iter); + + /* Sadly, if we drop an atlas-less cached glyph, we + * have to treat it like a dropped atlas and purge + * text node render data. + */ + self->atlas_timestamp++; } } else @@ -375,3 +377,15 @@ gsk_gl_glyph_cache_begin_frame (GskGLGlyphCache *self, GSK_NOTE(GLYPH_CACHE, g_message ("%d glyphs cached", g_hash_table_size (self->hash_table))); } } + +void +gsk_gl_glyph_cache_entry_validate (GskGLGlyphCache *cache, + GskGLCachedGlyph *value) +{ + value->accessed = TRUE; + if (value->atlas && !value->used) + { + gsk_gl_texture_atlas_mark_used (value->atlas, value->draw_width, value->draw_height); + value->used = TRUE; + } +} diff --git a/gsk/gl/gskglglyphcacheprivate.h b/gsk/gl/gskglglyphcacheprivate.h index 16a6feb471..4c2920bee6 100644 --- a/gsk/gl/gskglglyphcacheprivate.h +++ b/gsk/gl/gskglglyphcacheprivate.h @@ -16,6 +16,7 @@ typedef struct GskGLTextureAtlases *atlases; int timestamp; + int atlas_timestamp; /* incremented whenever an atlas is dropped */ } GskGLGlyphCache; typedef struct @@ -79,5 +80,7 @@ void gsk_gl_glyph_cache_lookup_or_add (GskGLGlyphCache GlyphCacheKey *lookup, GskGLDriver *driver, const GskGLCachedGlyph **cached_glyph_out); +void gsk_gl_glyph_cache_entry_validate (GskGLGlyphCache *cache, + GskGLCachedGlyph *entry); #endif diff --git a/gsk/gl/gskgliconcache.c b/gsk/gl/gskgliconcache.c index fc518b8851..b23325ff5c 100644 --- a/gsk/gl/gskgliconcache.c +++ b/gsk/gl/gskgliconcache.c @@ -7,19 +7,13 @@ #define MAX_FRAME_AGE 60 -typedef struct -{ - graphene_rect_t texture_rect; - GskGLTextureAtlas *atlas; - GdkTexture *source_texture; - guint accessed : 1; - guint used : 1; -} IconData; - static void icon_data_free (gpointer p) { - g_object_unref (((IconData *)p)->source_texture); + IconData *icon_data = p; + + gdk_texture_clear_render_data (icon_data->source_texture); + g_object_unref (icon_data->source_texture); g_free (p); } @@ -100,12 +94,12 @@ gsk_gl_icon_cache_begin_frame (GskGLIconCache *self, { if (icon_data->used) { - const int w = icon_data->texture_rect.size.width * icon_data->atlas->width; - const int h = icon_data->texture_rect.size.height * icon_data->atlas->height; - gsk_gl_texture_atlas_mark_unused (icon_data->atlas, w + 2, h + 2); + const int width = icon_data->source_texture->width; + const int height = icon_data->source_texture->height; + gsk_gl_texture_atlas_mark_unused (icon_data->atlas, width + 2, height + 2); icon_data->used = FALSE; } - } + } icon_data->accessed = FALSE; } @@ -117,32 +111,32 @@ gsk_gl_icon_cache_begin_frame (GskGLIconCache *self, void gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, GdkTexture *texture, - int *out_texture_id, - graphene_rect_t *out_texture_rect) + const IconData **out_icon_data) { - IconData *icon_data = g_hash_table_lookup (self->icons, texture); + IconData *icon_data; + + icon_data = gdk_texture_get_render_data (texture, self); + + if (!icon_data) + icon_data = g_hash_table_lookup (self->icons, texture); if (icon_data) { if (!icon_data->used) { - const int w = icon_data->texture_rect.size.width * icon_data->atlas->width; - const int h = icon_data->texture_rect.size.height * icon_data->atlas->height; - - gsk_gl_texture_atlas_mark_used (icon_data->atlas, w + 2, h + 2); + gsk_gl_texture_atlas_mark_used (icon_data->atlas, texture->width + 2, texture->height + 2); icon_data->used = TRUE; } icon_data->accessed = TRUE; - *out_texture_id = icon_data->atlas->texture_id; - *out_texture_rect = icon_data->texture_rect; + *out_icon_data = icon_data; return; } /* texture not on any atlas yet. Find a suitable one. */ { - const int width = gdk_texture_get_width (texture); - const int height = gdk_texture_get_height (texture); + const int width = texture->width; + const int height = texture->height; GskGLTextureAtlas *atlas = NULL; int packed_x = 0; int packed_y = 0; @@ -155,12 +149,12 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, icon_data->atlas = atlas; icon_data->accessed = TRUE; icon_data->used = TRUE; + icon_data->texture_id = atlas->texture_id; icon_data->source_texture = g_object_ref (texture); - graphene_rect_init (&icon_data->texture_rect, - (float)(packed_x + 1) / atlas->width, - (float)(packed_y + 1) / atlas->height, - (float)width / atlas->width, - (float)height / atlas->height); + icon_data->x = (float)(packed_x + 1) / atlas->width; + icon_data->y = (float)(packed_y + 1) / atlas->width; + icon_data->x2 = icon_data->x + (float)width / atlas->width; + icon_data->y2 = icon_data->y + (float)height / atlas->height; g_hash_table_insert (self->icons, texture, icon_data); @@ -240,8 +234,9 @@ gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); - *out_texture_id = atlas->texture_id; - *out_texture_rect = icon_data->texture_rect; + gdk_texture_set_render_data (texture, self, icon_data, NULL); + + *out_icon_data = icon_data; cairo_surface_destroy (surface); diff --git a/gsk/gl/gskgliconcacheprivate.h b/gsk/gl/gskgliconcacheprivate.h index 367e08ceb4..e076278a4e 100644 --- a/gsk/gl/gskgliconcacheprivate.h +++ b/gsk/gl/gskgliconcacheprivate.h @@ -21,6 +21,16 @@ typedef struct int timestamp; } GskGLIconCache; +typedef struct +{ + float x, y, x2, y2; + GskGLTextureAtlas *atlas; + guint used : 1; + guint accessed : 1; + int texture_id; + GdkTexture *source_texture; +} IconData; + GskGLIconCache * gsk_gl_icon_cache_new (GdkDisplay *display, GskGLTextureAtlases *atlases); GskGLIconCache * gsk_gl_icon_cache_ref (GskGLIconCache *self); @@ -29,7 +39,6 @@ void gsk_gl_icon_cache_begin_frame (GskGLIconCache *self, GPtrArray *removed_atlases); void gsk_gl_icon_cache_lookup_or_add (GskGLIconCache *self, GdkTexture *texture, - int *out_texture_id, - graphene_rect_t *out_texture_rect); + const IconData **out_icon_data); #endif diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index f5886cff30..7067b3866f 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -8,6 +8,7 @@ #include "gskglprofilerprivate.h" #include "gskprofilerprivate.h" #include "gskrendererprivate.h" +#include "gskrendernodeprivate.h" #include "gsktransformprivate.h" #include "gskshaderbuilderprivate.h" #include "gskglglyphcacheprivate.h" @@ -328,7 +329,6 @@ struct _GskGLRenderer }; RenderOpBuilder op_builder; - GArray *render_ops; GskGLTextureAtlases *atlases; GskGLGlyphCache *glyph_cache; @@ -536,6 +536,39 @@ render_fallback_node (GskGLRenderer *self, ops_draw (builder, offscreen_vertex_data); } +typedef struct { + int timestamp; + GskGLCachedGlyph *glyphs[]; +} TextRenderData; + +static inline TextRenderData * +ensure_render_data (GskRenderNode *node, + GskGLGlyphCache *cache) +{ + TextRenderData *data; + int num_glyphs; + + num_glyphs = gsk_text_node_get_num_glyphs (node); + data = gsk_text_node_get_render_data (node); + if (data) + { + if (data->timestamp < cache->atlas_timestamp) + { + memset (data->glyphs, 0, sizeof (gpointer) * num_glyphs); + data->timestamp = cache->atlas_timestamp; + } + } + else + { + data = g_new0 (TextRenderData, sizeof (TextRenderData) + sizeof (gpointer) * num_glyphs); + data->timestamp = cache->atlas_timestamp; + + gsk_text_node_set_render_data (node, data); + } + + return data; +} + static inline void render_text_node (GskGLRenderer *self, GskRenderNode *node, @@ -553,6 +586,7 @@ render_text_node (GskGLRenderer *self, float x = offset->x + builder->dx; float y = offset->y + builder->dy; GlyphCacheKey lookup; + TextRenderData *render_data; /* If the font has color glyphs, we don't need to recolor anything */ if (!force_color && gsk_text_node_has_color_glyphs (node)) @@ -565,6 +599,8 @@ render_text_node (GskGLRenderer *self, ops_set_color (builder, color); } + render_data = ensure_render_data (node, self->glyph_cache); + lookup.font = (PangoFont *)font; lookup.scale = (guint) (text_scale * 1024); @@ -585,12 +621,19 @@ render_text_node (GskGLRenderer *self, cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE; cy = (float)(gi->geometry.y_offset) / PANGO_SCALE; - glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy); + glyph = render_data->glyphs[i]; + if (!glyph) + { + glyph_cache_key_set_glyph_and_shift (&lookup, gi->glyph, x + cx, y + cy); - gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache, - &lookup, - self->gl_driver, - &glyph); + gsk_gl_glyph_cache_lookup_or_add (self->glyph_cache, + &lookup, + self->gl_driver, + &glyph); + render_data->glyphs[i] = (GskGLCachedGlyph *)glyph; + } + + gsk_gl_glyph_cache_entry_validate (self->glyph_cache, render_data->glyphs[i]); if (glyph->texture_id == 0) goto next; @@ -784,36 +827,35 @@ upload_texture (GskGLRenderer *self, GdkTexture *texture, TextureRegion *out_region) { - int texture_id; - if (texture->width <= 128 && texture->height <= 128 && !GDK_IS_GL_TEXTURE (texture)) { - graphene_rect_t trect; + const IconData *icon_data; gsk_gl_icon_cache_lookup_or_add (self->icon_cache, texture, - &texture_id, - &trect); - out_region->x = trect.origin.x; - out_region->y = trect.origin.y; - out_region->x2 = out_region->x + trect.size.width; - out_region->y2 = out_region->y + trect.size.height; + &icon_data); + + out_region->texture_id = icon_data->texture_id; + out_region->x = icon_data->x; + out_region->y = icon_data->y; + out_region->x2 = icon_data->x2; + out_region->y2 = icon_data->y2; } else { - texture_id = gsk_gl_driver_get_texture_for_texture (self->gl_driver, - texture, - GL_LINEAR, - GL_LINEAR); + out_region->texture_id = + gsk_gl_driver_get_texture_for_texture (self->gl_driver, + texture, + GL_LINEAR, + GL_LINEAR); + out_region->x = 0; out_region->y = 0; out_region->x2 = 1; out_region->y2 = 1; } - - out_region->texture_id = texture_id; } static inline void @@ -1047,7 +1089,7 @@ render_linear_gradient_node (GskGLRenderer *self, RenderOpBuilder *builder, const GskQuadVertex *vertex_data) { - RenderOp *op; + OpLinearGradient *op; int n_color_stops = MIN (8, gsk_linear_gradient_node_get_n_color_stops (node)); const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node); const graphene_point_t *start = gsk_linear_gradient_node_peek_start (node); @@ -1062,18 +1104,18 @@ render_linear_gradient_node (GskGLRenderer *self, { const GskColorStop *stop = stops + i; - op->linear_gradient.color_stops[(i * 4) + 0] = stop->color.red; - op->linear_gradient.color_stops[(i * 4) + 1] = stop->color.green; - op->linear_gradient.color_stops[(i * 4) + 2] = stop->color.blue; - op->linear_gradient.color_stops[(i * 4) + 3] = stop->color.alpha; - op->linear_gradient.color_offsets[i] = stop->offset; + op->color_stops[(i * 4) + 0] = stop->color.red; + op->color_stops[(i * 4) + 1] = stop->color.green; + op->color_stops[(i * 4) + 2] = stop->color.blue; + op->color_stops[(i * 4) + 3] = stop->color.alpha; + op->color_offsets[i] = stop->offset; } - op->linear_gradient.n_color_stops = n_color_stops; - op->linear_gradient.start_point.x = start->x + builder->dx; - op->linear_gradient.start_point.y = start->y + builder->dy; - op->linear_gradient.end_point.x = end->x + builder->dx; - op->linear_gradient.end_point.y = end->y + builder->dy; + op->n_color_stops = n_color_stops; + op->start_point.x = start->x + builder->dx; + op->start_point.y = start->y + builder->dy; + op->end_point.x = end->x + builder->dx; + op->end_point.y = end->y + builder->dy; ops_draw (builder, vertex_data); } @@ -1212,8 +1254,7 @@ render_rounded_clip_node (GskGLRenderer *self, static inline void render_color_matrix_node (GskGLRenderer *self, GskRenderNode *node, - RenderOpBuilder *builder, - const GskQuadVertex *vertex_data) + RenderOpBuilder *builder) { const float min_x = builder->dx + node->bounds.origin.x; const float min_y = builder->dy + node->bounds.origin.y; @@ -1267,20 +1308,27 @@ render_color_matrix_node (GskGLRenderer *self, } static inline void -render_blur_node (GskGLRenderer *self, - GskRenderNode *node, - RenderOpBuilder *builder, - const GskQuadVertex *vertex_data) +flip_vertex_data_y (GskQuadVertex vertex_data[GL_N_VERTICES]) +{ + vertex_data[0].uv[1] = 1 - vertex_data[0].uv[1]; + vertex_data[1].uv[1] = 1 - vertex_data[1].uv[1]; + vertex_data[2].uv[1] = 1 - vertex_data[2].uv[1]; + vertex_data[3].uv[1] = 1 - vertex_data[3].uv[1]; + vertex_data[4].uv[1] = 1 - vertex_data[4].uv[1]; + vertex_data[5].uv[1] = 1 - vertex_data[5].uv[1]; +} + +static inline void +render_blur_node (GskGLRenderer *self, + GskRenderNode *node, + RenderOpBuilder *builder, + GskQuadVertex *vertex_data) { - const float min_x = builder->dx + node->bounds.origin.x; - const float min_y = builder->dy + node->bounds.origin.y; - const float max_x = min_x + node->bounds.size.width; - const float max_y = min_y + node->bounds.size.height; const float blur_radius = gsk_blur_node_get_radius (node); GskRenderNode *child = gsk_blur_node_get_child (node); TextureRegion region; gboolean is_offscreen; - RenderOp *op; + OpBlur *op; if (blur_radius <= 0) { @@ -1302,29 +1350,15 @@ render_blur_node (GskGLRenderer *self, ops_set_program (builder, &self->blur_program); op = ops_begin (builder, OP_CHANGE_BLUR); - graphene_size_init_from_size (&op->blur.size, &node->bounds.size); - op->blur.radius = blur_radius; + graphene_size_init_from_size (&op->size, &node->bounds.size); + op->radius = blur_radius; ops_set_texture (builder, region.texture_id); if (is_offscreen) - { - GskQuadVertex offscreen_vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 1 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, + flip_vertex_data_y (vertex_data); - { { max_x, max_y }, { 1, 0 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, - }; - - ops_draw (builder, offscreen_vertex_data); - } - else - { - ops_draw (builder, vertex_data); - } + ops_draw (builder, vertex_data); } static inline void @@ -1334,7 +1368,7 @@ render_inset_shadow_node (GskGLRenderer *self, const GskQuadVertex *vertex_data) { const float scale = ops_get_scale (builder); - RenderOp *op; + OpShadow *op; /* TODO: Implement blurred inset shadows as well */ if (gsk_inset_shadow_node_get_blur_radius (node) > 0) @@ -1346,16 +1380,16 @@ render_inset_shadow_node (GskGLRenderer *self, ops_set_program (builder, &self->inset_shadow_program); op = ops_begin (builder, OP_CHANGE_INSET_SHADOW); - rgba_to_float (gsk_inset_shadow_node_peek_color (node), op->inset_shadow.color); + rgba_to_float (gsk_inset_shadow_node_peek_color (node), op->color); rounded_rect_to_floats (self, builder, gsk_inset_shadow_node_peek_outline (node), - op->inset_shadow.outline, - op->inset_shadow.corner_widths, - op->inset_shadow.corner_heights); - op->inset_shadow.radius = gsk_inset_shadow_node_get_blur_radius (node) * scale; - op->inset_shadow.spread = gsk_inset_shadow_node_get_spread (node) * scale; - op->inset_shadow.offset[0] = gsk_inset_shadow_node_get_dx (node) * scale; - op->inset_shadow.offset[1] = -gsk_inset_shadow_node_get_dy (node) * scale; + op->outline, + op->corner_widths, + op->corner_heights); + op->radius = gsk_inset_shadow_node_get_blur_radius (node) * scale; + op->spread = gsk_inset_shadow_node_get_spread (node) * scale; + op->offset[0] = gsk_inset_shadow_node_get_dx (node) * scale; + op->offset[1] = -gsk_inset_shadow_node_get_dy (node) * scale; ops_draw (builder, vertex_data); } @@ -1371,21 +1405,21 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, const float spread = gsk_outset_shadow_node_get_spread (node); const float dx = gsk_outset_shadow_node_get_dx (node); const float dy = gsk_outset_shadow_node_get_dy (node); - RenderOp *op; + OpShadow *op; ops_set_program (builder, &self->unblurred_outset_shadow_program); op = ops_begin (builder, OP_CHANGE_UNBLURRED_OUTSET_SHADOW); - rgba_to_float (gsk_outset_shadow_node_peek_color (node), op->unblurred_outset_shadow.color); + rgba_to_float (gsk_outset_shadow_node_peek_color (node), op->color); rounded_rect_to_floats (self, builder, outline, - op->unblurred_outset_shadow.outline, - op->unblurred_outset_shadow.corner_widths, - op->unblurred_outset_shadow.corner_heights); + op->outline, + op->corner_widths, + op->corner_heights); - op->unblurred_outset_shadow.spread = spread * scale; - op->unblurred_outset_shadow.offset[0] = dx * scale; - op->unblurred_outset_shadow.offset[1] = - dy * scale; + op->spread = spread * scale; + op->offset[0] = dx * scale; + op->offset[1] = - dy * scale; ops_draw (builder, vertex_data); } @@ -1407,7 +1441,8 @@ render_outset_shadow_node (GskGLRenderer *self, const float max_x = min_x + outline->bounds.size.width + (spread + blur_extra/2.0) * 2; const float max_y = min_y + outline->bounds.size.height + (spread + blur_extra/2.0) * 2; float texture_width, texture_height; - RenderOp *op; + OpBlur *op; + OpShadow *shadow; graphene_matrix_t prev_projection; graphene_rect_t prev_viewport; graphene_matrix_t item_proj; @@ -1494,9 +1529,9 @@ render_outset_shadow_node (GskGLRenderer *self, ops_set_program (builder, &self->blur_program); op = ops_begin (builder, OP_CHANGE_BLUR); - op->blur.size.width = texture_width; - op->blur.size.height = texture_height; - op->blur.radius = blur_radius; + op->size.width = texture_width; + op->size.height = texture_height; + op->radius = blur_radius; ops_push_clip (builder, &blit_clip); ops_set_texture (builder, texture_id); @@ -1531,12 +1566,12 @@ render_outset_shadow_node (GskGLRenderer *self, ops_set_program (builder, &self->outset_shadow_program); ops_set_texture (builder, blurred_texture_id); - op = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW); + shadow = ops_begin (builder, OP_CHANGE_OUTSET_SHADOW); rounded_rect_to_floats (self, builder, outline, - op->outset_shadow.outline, - op->outset_shadow.corner_widths, - op->outset_shadow.corner_heights); + shadow->outline, + shadow->corner_widths, + shadow->corner_heights); /* We use the one outset shadow op from above to draw all 8 sides/corners. */ { @@ -1759,8 +1794,7 @@ render_outset_shadow_node (GskGLRenderer *self, static inline void render_shadow_node (GskGLRenderer *self, GskRenderNode *node, - RenderOpBuilder *builder, - const GskQuadVertex *vertex_data) + RenderOpBuilder *builder) { float min_x; float min_y; @@ -1861,30 +1895,20 @@ render_shadow_node (GskGLRenderer *self, } static inline void -render_cross_fade_node (GskGLRenderer *self, - GskRenderNode *node, - RenderOpBuilder *builder) +render_cross_fade_node (GskGLRenderer *self, + GskRenderNode *node, + RenderOpBuilder *builder, + GskQuadVertex vertex_data[GL_N_VERTICES]) { - const float min_x = builder->dx + node->bounds.origin.x; - const float min_y = builder->dy + node->bounds.origin.y; - const float max_x = min_x + node->bounds.size.width; - const float max_y = min_y + node->bounds.size.height; GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node); GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node); float progress = gsk_cross_fade_node_get_progress (node); TextureRegion start_region; TextureRegion end_region; gboolean is_offscreen1, is_offscreen2; - RenderOp *op; - const GskQuadVertex vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 1 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, + OpCrossFade *op; - { { max_x, max_y }, { 1, 0 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, - }; + flip_vertex_data_y (vertex_data); /* TODO: We create 2 textures here as big as the cross-fade node, but both the * start and the end node might be a lot smaller than that. */ @@ -1904,8 +1928,8 @@ render_cross_fade_node (GskGLRenderer *self, ops_set_program (builder, &self->cross_fade_program); op = ops_begin (builder, OP_CHANGE_CROSS_FADE); - op->cross_fade.progress = progress; - op->cross_fade.source2 = end_region.texture_id; + op->progress = progress; + op->source2 = end_region.texture_id; ops_set_texture (builder, start_region.texture_id); @@ -1915,27 +1939,17 @@ render_cross_fade_node (GskGLRenderer *self, static inline void render_blend_node (GskGLRenderer *self, GskRenderNode *node, - RenderOpBuilder *builder) + RenderOpBuilder *builder, + GskQuadVertex vertex_data[GL_N_VERTICES]) { GskRenderNode *top_child = gsk_blend_node_get_top_child (node); GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node); - const float min_x = builder->dx + node->bounds.origin.x; - const float min_y = builder->dy + node->bounds.origin.y; - const float max_x = min_x + node->bounds.size.width; - const float max_y = min_y + node->bounds.size.height; TextureRegion top_region; TextureRegion bottom_region; gboolean is_offscreen1, is_offscreen2; - RenderOp *op; - const GskQuadVertex vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 1 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, + OpBlend *op; - { { max_x, max_y }, { 1, 0 }, }, - { { min_x, max_y }, { 0, 0 }, }, - { { max_x, min_y }, { 1, 1 }, }, - }; + flip_vertex_data_y (vertex_data); /* TODO: We create 2 textures here as big as the blend node, but both the * start and the end node might be a lot smaller than that. */ @@ -1955,8 +1969,8 @@ render_blend_node (GskGLRenderer *self, ops_set_texture (builder, bottom_region.texture_id); op = ops_begin (builder, OP_CHANGE_BLEND); - op->blend.source2 = top_region.texture_id; - op->blend.mode = gsk_blend_node_get_blend_mode (node); + op->source2 = top_region.texture_id; + op->mode = gsk_blend_node_get_blend_mode (node); ops_draw (builder, vertex_data); } @@ -1974,7 +1988,7 @@ render_repeat_node (GskGLRenderer *self, const graphene_rect_t *child_bounds = gsk_repeat_node_peek_child_bounds (node); TextureRegion region; gboolean is_offscreen; - RenderOp *op; + OpRepeat *op; if (child_bounds != NULL && !graphene_rect_equal (child_bounds, &child->bounds)) @@ -1995,23 +2009,23 @@ render_repeat_node (GskGLRenderer *self, ops_set_texture (builder, region.texture_id); op = ops_begin (builder, OP_CHANGE_REPEAT); - op->repeat.child_bounds[0] = 0; /* Both currently unused */ - op->repeat.child_bounds[1] = 0; - op->repeat.child_bounds[2] = node->bounds.size.width / child_bounds->size.width; - op->repeat.child_bounds[3] = node->bounds.size.height / child_bounds->size.height; + op->child_bounds[0] = 0; /* Both currently unused */ + op->child_bounds[1] = 0; + op->child_bounds[2] = node->bounds.size.width / child_bounds->size.width; + op->child_bounds[3] = node->bounds.size.height / child_bounds->size.height; - op->repeat.texture_rect[0] = region.x; - op->repeat.texture_rect[2] = region.x2; + op->texture_rect[0] = region.x; + op->texture_rect[2] = region.x2; if (is_offscreen) { - op->repeat.texture_rect[1] = region.y2; - op->repeat.texture_rect[3] = region.y; + op->texture_rect[1] = region.y2; + op->texture_rect[3] = region.y; } else { - op->repeat.texture_rect[1] = region.y; - op->repeat.texture_rect[3] = region.y2; + op->texture_rect[1] = region.y; + op->texture_rect[3] = region.y2; } if (is_offscreen) @@ -2045,10 +2059,12 @@ render_repeat_node (GskGLRenderer *self, } static inline void -apply_viewport_op (const Program *program, - const RenderOp *op) +apply_viewport_op (const Program *program, + const OpViewport *op) { - OP_PRINT (" -> New Viewport: %f, %f, %f, %f", op->viewport.origin.x, op->viewport.origin.y, op->viewport.size.width, op->viewport.size.height); + OP_PRINT (" -> New Viewport: %f, %f, %f, %f", + op->viewport.origin.x, op->viewport.origin.y, + op->viewport.size.width, op->viewport.size.height); glUniform4f (program->viewport_location, op->viewport.origin.x, op->viewport.origin.y, op->viewport.size.width, op->viewport.size.height); @@ -2057,38 +2073,38 @@ apply_viewport_op (const Program *program, static inline void apply_modelview_op (const Program *program, - const RenderOp *op) + const OpMatrix *op) { float mat[16]; OP_PRINT (" -> Modelview"); - graphene_matrix_to_float (&op->modelview, mat); + graphene_matrix_to_float (&op->matrix, mat); glUniformMatrix4fv (program->modelview_location, 1, GL_FALSE, mat); } static inline void apply_projection_op (const Program *program, - const RenderOp *op) + const OpMatrix *op) { float mat[16]; OP_PRINT (" -> Projection"); - graphene_matrix_to_float (&op->projection, mat); + graphene_matrix_to_float (&op->matrix, mat); glUniformMatrix4fv (program->projection_location, 1, GL_FALSE, mat); } static inline void apply_program_op (const Program *program, - const RenderOp *op) + const OpProgram *op) { OP_PRINT (" -> Program: %d", op->program->index); glUseProgram (op->program->id); } static inline void -apply_render_target_op (GskGLRenderer *self, - const Program *program, - const RenderOp *op) +apply_render_target_op (GskGLRenderer *self, + const Program *program, + const OpRenderTarget *op) { OP_PRINT (" -> Render Target: %d", op->render_target_id); @@ -2101,29 +2117,26 @@ apply_render_target_op (GskGLRenderer *self, } static inline void -apply_color_op (const Program *program, - const RenderOp *op) +apply_color_op (const Program *program, + const OpColor *op) { OP_PRINT (" -> Color: (%f, %f, %f, %f)", - op->color->red, op->color->green, op->color->blue, op->color->alpha); + op->rgba.red, op->rgba.green, op->rgba.blue, op->rgba.alpha); glUniform4f (program->color.color_location, - op->color->red, - op->color->green, - op->color->blue, - op->color->alpha); + op->rgba.red, op->rgba.green, op->rgba.blue, op->rgba.alpha); } static inline void -apply_opacity_op (const Program *program, - const RenderOp *op) +apply_opacity_op (const Program *program, + const OpOpacity *op) { OP_PRINT (" -> Opacity %f", op->opacity); glUniform1f (program->alpha_location, op->opacity); } static inline void -apply_source_texture_op (const Program *program, - const RenderOp *op) +apply_source_texture_op (const Program *program, + const OpTexture *op) { g_assert(op->texture_id != 0); OP_PRINT (" -> New texture: %d", op->texture_id); @@ -2134,22 +2147,22 @@ apply_source_texture_op (const Program *program, } static inline void -apply_color_matrix_op (const Program *program, - const RenderOp *op) +apply_color_matrix_op (const Program *program, + const OpColorMatrix *op) { float mat[16]; float vec[4]; OP_PRINT (" -> Color Matrix"); - graphene_matrix_to_float (&op->color_matrix.matrix, mat); + graphene_matrix_to_float (&op->matrix, mat); glUniformMatrix4fv (program->color_matrix.color_matrix_location, 1, GL_FALSE, mat); - graphene_vec4_to_float (&op->color_matrix.offset, vec); + graphene_vec4_to_float (&op->offset, vec); glUniform4fv (program->color_matrix.color_offset_location, 1, vec); } static inline void -apply_clip_op (const Program *program, - const RenderOp *op) +apply_clip_op (const Program *program, + const OpClip *op) { OP_PRINT (" -> Clip (%f, %f, %f, %f) (%f, %f, %f, %f), (%f, %f, %f, %f)", op->clip.bounds.origin.x, op->clip.bounds.origin.y, @@ -2180,85 +2193,85 @@ apply_clip_op (const Program *program, static inline void apply_inset_shadow_op (const Program *program, - const RenderOp *op) + const OpShadow *op) { OP_PRINT (" -> inset shadow. Color: (%f, %f, %f, %f), Offset: (%f, %f), Spread: %f, Outline: (%f, %f, %f, %f) Corner widths: (%f, %f, %f, %f), Corner Heights: (%f, %f, %f, %f)", - op->inset_shadow.color[0], - op->inset_shadow.color[1], - op->inset_shadow.color[2], - op->inset_shadow.color[3], - op->inset_shadow.offset[0], - op->inset_shadow.offset[1], - op->inset_shadow.spread, - op->inset_shadow.outline[0], - op->inset_shadow.outline[1], - op->inset_shadow.outline[2], - op->inset_shadow.outline[3], - op->inset_shadow.corner_widths[0], - op->inset_shadow.corner_widths[1], - op->inset_shadow.corner_widths[2], - op->inset_shadow.corner_widths[3], - op->inset_shadow.corner_heights[0], - op->inset_shadow.corner_heights[1], - op->inset_shadow.corner_heights[2], - op->inset_shadow.corner_heights[3]); - glUniform4fv (program->inset_shadow.color_location, 1, op->inset_shadow.color); - glUniform2fv (program->inset_shadow.offset_location, 1, op->inset_shadow.offset); - glUniform1f (program->inset_shadow.spread_location, op->inset_shadow.spread); - glUniform4fv (program->inset_shadow.outline_location, 1, op->inset_shadow.outline); - glUniform4fv (program->inset_shadow.corner_widths_location, 1, op->inset_shadow.corner_widths); - glUniform4fv (program->inset_shadow.corner_heights_location, 1, op->inset_shadow.corner_heights); + op->color[0], + op->color[1], + op->color[2], + op->color[3], + op->offset[0], + op->offset[1], + op->spread, + op->outline[0], + op->outline[1], + op->outline[2], + op->outline[3], + op->corner_widths[0], + op->corner_widths[1], + op->corner_widths[2], + op->corner_widths[3], + op->corner_heights[0], + op->corner_heights[1], + op->corner_heights[2], + op->corner_heights[3]); + glUniform4fv (program->inset_shadow.color_location, 1, op->color); + glUniform2fv (program->inset_shadow.offset_location, 1, op->offset); + glUniform1f (program->inset_shadow.spread_location, op->spread); + glUniform4fv (program->inset_shadow.outline_location, 1, op->outline); + glUniform4fv (program->inset_shadow.corner_widths_location, 1, op->corner_widths); + glUniform4fv (program->inset_shadow.corner_heights_location, 1, op->corner_heights); } static inline void apply_unblurred_outset_shadow_op (const Program *program, - const RenderOp *op) + const OpShadow *op) { OP_PRINT (" -> unblurred outset shadow"); - glUniform4fv (program->unblurred_outset_shadow.color_location, 1, op->unblurred_outset_shadow.color); - glUniform2fv (program->unblurred_outset_shadow.offset_location, 1, op->unblurred_outset_shadow.offset); - glUniform1f (program->unblurred_outset_shadow.spread_location, op->unblurred_outset_shadow.spread); - glUniform4fv (program->unblurred_outset_shadow.outline_location, 1, op->unblurred_outset_shadow.outline); + glUniform4fv (program->unblurred_outset_shadow.color_location, 1, op->color); + glUniform2fv (program->unblurred_outset_shadow.offset_location, 1, op->offset); + glUniform1f (program->unblurred_outset_shadow.spread_location, op->spread); + glUniform4fv (program->unblurred_outset_shadow.outline_location, 1, op->outline); glUniform4fv (program->unblurred_outset_shadow.corner_widths_location, 1, - op->unblurred_outset_shadow.corner_widths); + op->corner_widths); glUniform4fv (program->unblurred_outset_shadow.corner_heights_location, 1, - op->unblurred_outset_shadow.corner_heights); + op->corner_heights); } static inline void apply_outset_shadow_op (const Program *program, - const RenderOp *op) + const OpShadow *op) { OP_PRINT (" -> outset shadow"); - glUniform4fv (program->outset_shadow.outline_location, 1, op->outset_shadow.outline); - glUniform4fv (program->outset_shadow.corner_widths_location, 1, op->outset_shadow.corner_widths); - glUniform4fv (program->outset_shadow.corner_heights_location, 1, op->outset_shadow.corner_heights); + glUniform4fv (program->outset_shadow.outline_location, 1, op->outline); + glUniform4fv (program->outset_shadow.corner_widths_location, 1, op->corner_widths); + glUniform4fv (program->outset_shadow.corner_heights_location, 1, op->corner_heights); } static inline void -apply_linear_gradient_op (const Program *program, - const RenderOp *op) +apply_linear_gradient_op (const Program *program, + const OpLinearGradient *op) { OP_PRINT (" -> Linear gradient"); glUniform1i (program->linear_gradient.num_color_stops_location, - op->linear_gradient.n_color_stops); + op->n_color_stops); glUniform4fv (program->linear_gradient.color_stops_location, - op->linear_gradient.n_color_stops, - op->linear_gradient.color_stops); + op->n_color_stops, + op->color_stops); glUniform1fv (program->linear_gradient.color_offsets_location, - op->linear_gradient.n_color_stops, - op->linear_gradient.color_offsets); + op->n_color_stops, + op->color_offsets); glUniform2f (program->linear_gradient.start_point_location, - op->linear_gradient.start_point.x, op->linear_gradient.start_point.y); + op->start_point.x, op->start_point.y); glUniform2f (program->linear_gradient.end_point_location, - op->linear_gradient.end_point.x, op->linear_gradient.end_point.y); + op->end_point.x, op->end_point.y); } static inline void apply_border_op (const Program *program, - const RenderOp *op) + const OpBorder *op) { - const GskRoundedRect *o = &op->border.outline; + const GskRoundedRect *o = &op->outline; float outline[4]; float widths[4]; float heights[4]; @@ -2283,63 +2296,63 @@ apply_border_op (const Program *program, static inline void apply_border_width_op (const Program *program, - const RenderOp *op) + const OpBorder *op) { OP_PRINT (" -> Border width (%f, %f, %f, %f)", - op->border.widths[0], op->border.widths[1], op->border.widths[2], op->border.widths[3]); + op->widths[0], op->widths[1], op->widths[2], op->widths[3]); - glUniform4fv (program->border.widths_location, 1, op->border.widths); + glUniform4fv (program->border.widths_location, 1, op->widths); } static inline void apply_border_color_op (const Program *program, - const RenderOp *op) + const OpBorder *op) { OP_PRINT (" -> Border color (%f, %f, %f, %f)", - op->border.color[0], op->border.color[1], op->border.color[2], op->border.color[3]); - glUniform4fv (program->border.color_location, 1, op->border.color); + op->color[0], op->color[1], op->color[2], op->color[3]); + glUniform4fv (program->border.color_location, 1, op->color); } static inline void -apply_blur_op (const Program *program, - const RenderOp *op) +apply_blur_op (const Program *program, + const OpBlur *op) { OP_PRINT (" -> Blur"); - glUniform1f (program->blur.blur_radius_location, op->blur.radius); - glUniform2f (program->blur.blur_size_location, op->blur.size.width, op->blur.size.height); - /*glUniform2f (program->blur.dir_location, op->blur.dir[0], op->blur.dir[1]);*/ + glUniform1f (program->blur.blur_radius_location, op->radius); + glUniform2f (program->blur.blur_size_location, op->size.width, op->size.height); + /*glUniform2f (program->blur.dir_location, op->dir[0], op->dir[1]);*/ } static inline void -apply_cross_fade_op (const Program *program, - const RenderOp *op) +apply_cross_fade_op (const Program *program, + const OpCrossFade *op) { /* End texture id */ glUniform1i (program->cross_fade.source2_location, 1); glActiveTexture (GL_TEXTURE0 + 1); - glBindTexture (GL_TEXTURE_2D, op->cross_fade.source2); + glBindTexture (GL_TEXTURE_2D, op->source2); /* progress */ - glUniform1f (program->cross_fade.progress_location, op->cross_fade.progress); + glUniform1f (program->cross_fade.progress_location, op->progress); } static inline void -apply_blend_op (const Program *program, - const RenderOp *op) +apply_blend_op (const Program *program, + const OpBlend *op) { /* End texture id */ glUniform1i (program->blend.source2_location, 1); glActiveTexture (GL_TEXTURE0 + 1); - glBindTexture (GL_TEXTURE_2D, op->blend.source2); + glBindTexture (GL_TEXTURE_2D, op->source2); /* progress */ - glUniform1i (program->blend.mode_location, op->blend.mode); + glUniform1i (program->blend.mode_location, op->mode); } static inline void apply_repeat_op (const Program *program, - const RenderOp *op) + const OpRepeat *op) { - glUniform4fv (program->repeat.child_bounds_location, 1, op->repeat.child_bounds); - glUniform4fv (program->repeat.texture_rect_location, 1, op->repeat.texture_rect); + glUniform4fv (program->repeat.child_bounds_location, 1, op->child_bounds); + glUniform4fv (program->repeat.texture_rect_location, 1, op->texture_rect); } static void @@ -2347,7 +2360,6 @@ gsk_gl_renderer_dispose (GObject *gobject) { GskGLRenderer *self = GSK_GL_RENDERER (gobject); - g_clear_pointer (&self->render_ops, g_array_unref); ops_free (&self->op_builder); G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject); @@ -2635,7 +2647,7 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer) /* We don't need to iterate to destroy the associated GL resources, * as they will be dropped when we finalize the GskGLDriver */ - g_array_set_size (self->render_ops, 0); + ops_reset (&self->op_builder); for (i = 0; i < GL_N_PROGRAMS; i ++) glDeleteProgram (self->programs[i].id); @@ -2664,7 +2676,7 @@ gsk_gl_renderer_clear_tree (GskGLRenderer *self) gdk_gl_context_make_current (self->gl_context); - g_array_remove_range (self->render_ops, 0, self->render_ops->len); + ops_reset (&self->op_builder); removed_textures = gsk_gl_driver_collect_textures (self->gl_driver); GSK_RENDERER_NOTE (GSK_RENDERER (self), OPENGL, g_message ("Collected: %d textures", removed_textures)); @@ -2704,26 +2716,53 @@ gsk_gl_renderer_setup_render_mode (GskGLRenderer *self) } } +static void +load_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], + GskRenderNode *node, + RenderOpBuilder *builder) +{ + const float min_x = builder->dx + node->bounds.origin.x; + const float min_y = builder->dy + node->bounds.origin.y; + const float max_x = min_x + node->bounds.size.width; + const float max_y = min_y + node->bounds.size.height; + + vertex_data[0].position[0] = min_x; + vertex_data[0].position[1] = min_y; + vertex_data[0].uv[0] = 0; + vertex_data[0].uv[1] = 0; + + vertex_data[1].position[0] = min_x; + vertex_data[1].position[1] = max_y; + vertex_data[1].uv[0] = 0; + vertex_data[1].uv[1] = 1; + + vertex_data[2].position[0] = max_x; + vertex_data[2].position[1] = min_y; + vertex_data[2].uv[0] = 1; + vertex_data[2].uv[1] = 0; + + vertex_data[3].position[0] = max_x; + vertex_data[3].position[1] = max_y; + vertex_data[3].uv[0] = 1; + vertex_data[3].uv[1] = 1; + + vertex_data[4].position[0] = min_x; + vertex_data[4].position[1] = max_y; + vertex_data[4].uv[0] = 0; + vertex_data[4].uv[1] = 1; + + vertex_data[5].position[0] = max_x; + vertex_data[5].position[1] = min_y; + vertex_data[5].uv[0] = 1; + vertex_data[5].uv[1] = 0; +} static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float min_x = builder->dx + node->bounds.origin.x; - const float min_y = builder->dy + node->bounds.origin.y; - const float max_x = min_x + node->bounds.size.width; - const float max_y = min_y + node->bounds.size.height; - /* Default vertex data */ - const GskQuadVertex vertex_data[GL_N_VERTICES] = { - { { min_x, min_y }, { 0, 0 }, }, - { { min_x, max_y }, { 0, 1 }, }, - { { max_x, min_y }, { 1, 0 }, }, - - { { max_x, max_y }, { 1, 1 }, }, - { { min_x, max_y }, { 0, 1 }, }, - { { max_x, min_y }, { 1, 0 }, }, - }; + GskQuadVertex vertex_data[GL_N_VERTICES]; /* This can still happen, even if the render nodes are created using * GtkSnapshot, so let's juse be safe. */ @@ -2777,6 +2816,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_COLOR_NODE: + load_vertex_data (vertex_data, node, builder); render_color_node (self, node, builder, vertex_data); break; @@ -2793,6 +2833,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_LINEAR_GRADIENT_NODE: + load_vertex_data (vertex_data, node, builder); render_linear_gradient_node (self, node, builder, vertex_data); break; @@ -2810,26 +2851,33 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_COLOR_MATRIX_NODE: - render_color_matrix_node (self, node, builder, vertex_data); + render_color_matrix_node (self, node, builder); break; case GSK_BLUR_NODE: + load_vertex_data (vertex_data, node, builder); render_blur_node (self, node, builder, vertex_data); break; case GSK_INSET_SHADOW_NODE: + load_vertex_data (vertex_data, node, builder); render_inset_shadow_node (self, node, builder, vertex_data); break; case GSK_OUTSET_SHADOW_NODE: if (gsk_outset_shadow_node_get_blur_radius (node) > 0) - render_outset_shadow_node (self, node, builder); + { + render_outset_shadow_node (self, node, builder); + } else - render_unblurred_outset_shadow_node (self, node, builder, vertex_data); + { + load_vertex_data (vertex_data, node, builder); + render_unblurred_outset_shadow_node (self, node, builder, vertex_data); + } break; case GSK_SHADOW_NODE: - render_shadow_node (self, node, builder, vertex_data); + render_shadow_node (self, node, builder); break; case GSK_BORDER_NODE: @@ -2837,11 +2885,13 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_CROSS_FADE_NODE: - render_cross_fade_node (self, node, builder); + load_vertex_data (vertex_data, node, builder); + render_cross_fade_node (self, node, builder, vertex_data); break; case GSK_BLEND_NODE: - render_blend_node (self, node, builder); + load_vertex_data (vertex_data, node, builder); + render_blend_node (self, node, builder, vertex_data); break; case GSK_REPEAT_NODE: @@ -2973,14 +3023,14 @@ add_offscreen_ops (GskGLRenderer *self, } static void -gsk_gl_renderer_render_ops (GskGLRenderer *self, - gsize vertex_data_size) +gsk_gl_renderer_render_ops (GskGLRenderer *self) { - guint i; - guint n_ops = self->render_ops->len; const Program *program = NULL; - gsize buffer_index = 0; - float *vertex_data = g_malloc (vertex_data_size); + gsize vertex_data_size = self->op_builder.vertices->len * sizeof (GskQuadVertex); + float *vertex_data = (float*)self->op_builder.vertices->data; + OpBufferIter iter; + OpKind kind; + gpointer ptr; /*g_message ("%s: Buffer size: %ld", __FUNCTION__, vertex_data_size);*/ @@ -2992,19 +3042,6 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, glGenBuffers (1, &buffer_id); glBindBuffer (GL_ARRAY_BUFFER, buffer_id); - - // Fill buffer data - for (i = 0; i < n_ops; i ++) - { - const RenderOp *op = &g_array_index (self->render_ops, RenderOp, i); - - if (op->op == OP_CHANGE_VAO) - { - memcpy (vertex_data + buffer_index, &op->vertex_data, sizeof (GskQuadVertex) * GL_N_VERTICES); - buffer_index += sizeof (GskQuadVertex) * GL_N_VERTICES / sizeof (float); - } - } - // Set buffer data glBufferData (GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_STATIC_DRAW); @@ -3021,41 +3058,42 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, sizeof (GskQuadVertex), (void *) G_STRUCT_OFFSET (GskQuadVertex, uv)); - for (i = 0; i < n_ops; i ++) + op_buffer_iter_init (&iter, ops_get_buffer (&self->op_builder)); + while ((ptr = op_buffer_iter_next (&iter, &kind))) { - const RenderOp *op = &g_array_index (self->render_ops, RenderOp, i); - - if (op->op == OP_NONE || - op->op == OP_CHANGE_VAO) + if (kind == OP_NONE) continue; if (program == NULL && - op->op != OP_PUSH_DEBUG_GROUP && - op->op != OP_POP_DEBUG_GROUP && - op->op != OP_CHANGE_PROGRAM && - op->op != OP_CHANGE_RENDER_TARGET && - op->op != OP_CLEAR) + kind != OP_PUSH_DEBUG_GROUP && + kind != OP_POP_DEBUG_GROUP && + kind != OP_CHANGE_PROGRAM && + kind != OP_CHANGE_RENDER_TARGET && + kind != OP_CLEAR) continue; - OP_PRINT ("Op %u: %u", i, op->op); + OP_PRINT ("Op %u: %u", iter.pos - 2, kind); - switch (op->op) + switch (kind) { case OP_CHANGE_PROJECTION: - apply_projection_op (program, op); + apply_projection_op (program, ptr); break; case OP_CHANGE_MODELVIEW: - apply_modelview_op (program, op); + apply_modelview_op (program, ptr); break; case OP_CHANGE_PROGRAM: - apply_program_op (program, op); - program = op->program; - break; + { + const OpProgram *op = ptr; + apply_program_op (program, op); + program = op->program; + break; + } case OP_CHANGE_RENDER_TARGET: - apply_render_target_op (self, program, op); + apply_render_target_op (self, program, ptr); break; case OP_CLEAR: @@ -3064,95 +3102,108 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, break; case OP_CHANGE_VIEWPORT: - apply_viewport_op (program, op); + apply_viewport_op (program, ptr); break; case OP_CHANGE_OPACITY: - apply_opacity_op (program, op); + apply_opacity_op (program, ptr); break; case OP_CHANGE_COLOR_MATRIX: - apply_color_matrix_op (program, op); + apply_color_matrix_op (program, ptr); break; case OP_CHANGE_COLOR: /*g_assert (program == &self->color_program || program == &self->coloring_program ||*/ /*program == &self->shadow_program);*/ - apply_color_op (program, op); + apply_color_op (program, ptr); break; case OP_CHANGE_BORDER_COLOR: - apply_border_color_op (program, op); + apply_border_color_op (program, ptr); break; case OP_CHANGE_CLIP: - apply_clip_op (program, op); + apply_clip_op (program, ptr); break; case OP_CHANGE_SOURCE_TEXTURE: - apply_source_texture_op (program, op); + apply_source_texture_op (program, ptr); break; case OP_CHANGE_CROSS_FADE: g_assert (program == &self->cross_fade_program); - apply_cross_fade_op (program, op); + apply_cross_fade_op (program, ptr); break; case OP_CHANGE_BLEND: g_assert (program == &self->blend_program); - apply_blend_op (program, op); + apply_blend_op (program, ptr); break; case OP_CHANGE_LINEAR_GRADIENT: - apply_linear_gradient_op (program, op); + apply_linear_gradient_op (program, ptr); break; case OP_CHANGE_BLUR: - apply_blur_op (program, op); + apply_blur_op (program, ptr); break; case OP_CHANGE_INSET_SHADOW: - apply_inset_shadow_op (program, op); + apply_inset_shadow_op (program, ptr); break; case OP_CHANGE_OUTSET_SHADOW: - apply_outset_shadow_op (program, op); + apply_outset_shadow_op (program, ptr); break; case OP_CHANGE_BORDER: - apply_border_op (program, op); + apply_border_op (program, ptr); break; case OP_CHANGE_BORDER_WIDTH: - apply_border_width_op (program, op); + apply_border_width_op (program, ptr); break; case OP_CHANGE_UNBLURRED_OUTSET_SHADOW: - apply_unblurred_outset_shadow_op (program, op); + apply_unblurred_outset_shadow_op (program, ptr); break; case OP_CHANGE_REPEAT: - apply_repeat_op (program, op); + apply_repeat_op (program, ptr); break; case OP_DRAW: - OP_PRINT (" -> draw %ld, size %ld and program %d\n", - op->draw.vao_offset, op->draw.vao_size, program->index); - glDrawArrays (GL_TRIANGLES, op->draw.vao_offset, op->draw.vao_size); - break; + { + const OpDraw *op = ptr; + + OP_PRINT (" -> draw %ld, size %ld and program %d\n", + op->vao_offset, op->vao_size, program->index); + glDrawArrays (GL_TRIANGLES, op->vao_offset, op->vao_size); + break; + } case OP_DUMP_FRAMEBUFFER: - dump_framebuffer (op->dump.filename, op->dump.width, op->dump.height); - break; + { + const OpDumpFrameBuffer *op = ptr; + + dump_framebuffer (op->filename, op->width, op->height); + break; + } case OP_PUSH_DEBUG_GROUP: - gdk_gl_context_push_debug_group (self->gl_context, op->debug_group.text); - break; + { + const OpDebugGroup *op = ptr; + gdk_gl_context_push_debug_group (self->gl_context, op->text); + break; + } case OP_POP_DEBUG_GROUP: gdk_gl_context_pop_debug_group (self->gl_context); break; + case OP_NONE: + case OP_LAST: default: g_warn_if_reached (); } @@ -3160,9 +3211,6 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, OP_PRINT ("\n"); } - /* Done drawing, destroy the buffer again. - * TODO: Can we reuse the memory, though? */ - g_free (vertex_data); glDeleteVertexArrays (1, &vao_id); glDeleteBuffers (1, &buffer_id); } @@ -3176,7 +3224,6 @@ gsk_gl_renderer_do_render (GskRenderer *renderer, { GskGLRenderer *self = GSK_GL_RENDERER (renderer); graphene_matrix_t projection; - gsize buffer_size; #ifdef G_ENABLE_DEBUG GskProfiler *profiler; gint64 gpu_time, cpu_time, start_time; @@ -3256,7 +3303,6 @@ gsk_gl_renderer_do_render (GskRenderer *renderer, g_assert_cmpint (self->op_builder.current_render_target, ==, fbo_id); ops_pop_modelview (&self->op_builder); ops_pop_clip (&self->op_builder); - buffer_size = self->op_builder.buffer_size; ops_finish (&self->op_builder); /*g_message ("Ops: %u", self->render_ops->len);*/ @@ -3284,7 +3330,7 @@ gsk_gl_renderer_do_render (GskRenderer *renderer, glBlendEquation (GL_FUNC_ADD); gdk_gl_context_push_debug_group (self->gl_context, "Rendering ops"); - gsk_gl_renderer_render_ops (self, buffer_size); + gsk_gl_renderer_render_ops (self); gdk_gl_context_pop_debug_group (self->gl_context); #ifdef G_ENABLE_DEBUG @@ -3451,11 +3497,8 @@ gsk_gl_renderer_init (GskGLRenderer *self) { gsk_ensure_resources (); - self->render_ops = g_array_new (FALSE, FALSE, sizeof (RenderOp)); - ops_init (&self->op_builder); self->op_builder.renderer = self; - self->op_builder.render_ops = self->render_ops; #ifdef G_ENABLE_DEBUG { diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index 98736bcaca..4c6e2a7b35 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -28,7 +28,6 @@ ops_finish (RenderOpBuilder *builder) g_array_free (builder->clip_stack, TRUE); builder->clip_stack = NULL; - builder->buffer_size = 0; builder->dx = 0; builder->dy = 0; builder->current_modelview = NULL; @@ -57,23 +56,23 @@ ops_dump_framebuffer (RenderOpBuilder *builder, int width, int height) { - RenderOp *op; + OpDumpFrameBuffer *op; op = ops_begin (builder, OP_DUMP_FRAMEBUFFER); - op->dump.filename = g_strdup (filename); - op->dump.width = width; - op->dump.height = height; + op->filename = g_strdup (filename); + op->width = width; + op->height = height; } void ops_push_debug_group (RenderOpBuilder *builder, const char *text) { - RenderOp *op; + OpDebugGroup *op; op = ops_begin (builder, OP_PUSH_DEBUG_GROUP); - strncpy (op->debug_group.text, text, sizeof(op->debug_group.text) - 1); - op->debug_group.text[sizeof(op->debug_group.text) - 1] = 0; /* Ensure zero terminated */ + strncpy (op->text, text, sizeof(op->text) - 1); + op->text[sizeof(op->text) - 1] = 0; /* Ensure zero terminated */ } void @@ -182,6 +181,9 @@ ops_init (RenderOpBuilder *builder) builder->current_opacity = 1.0f; + op_buffer_init (&builder->render_ops); + builder->vertices = g_array_new (FALSE, TRUE, sizeof (GskQuadVertex)); + for (i = 0; i < GL_N_PROGRAMS; i ++) { builder->program_state[i].opacity = 1.0f; @@ -197,6 +199,9 @@ ops_free (RenderOpBuilder *builder) { gsk_transform_unref (builder->program_state[i].modelview); } + + g_array_unref (builder->vertices); + op_buffer_destroy (&builder->render_ops); } void @@ -208,7 +213,7 @@ ops_set_program (RenderOpBuilder *builder, static const GskRoundedRect empty_clip; static const graphene_matrix_t empty_matrix; static const graphene_rect_t empty_rect; - RenderOp *op; + OpProgram *op; ProgramState *program_state; if (builder->current_program == program) @@ -225,16 +230,20 @@ ops_set_program (RenderOpBuilder *builder, if (memcmp (&empty_matrix, &program_state->projection, sizeof (graphene_matrix_t)) == 0 || memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0) { - op = ops_begin (builder, OP_CHANGE_PROJECTION); - op->projection = builder->current_projection; + OpMatrix *opm; + + opm = ops_begin (builder, OP_CHANGE_PROJECTION); + opm->matrix = builder->current_projection; program_state->projection = builder->current_projection; } if (program_state->modelview == NULL || !gsk_transform_equal (builder->current_modelview, program_state->modelview)) { - op = ops_begin (builder, OP_CHANGE_MODELVIEW); - gsk_transform_to_matrix (builder->current_modelview, &op->modelview); + OpMatrix *opm; + + opm = ops_begin (builder, OP_CHANGE_MODELVIEW); + gsk_transform_to_matrix (builder->current_modelview, &opm->matrix); gsk_transform_unref (program_state->modelview); program_state->modelview = gsk_transform_ref (builder->current_modelview); } @@ -242,23 +251,29 @@ ops_set_program (RenderOpBuilder *builder, if (rect_equal (&empty_rect, &program_state->viewport) || !rect_equal (&builder->current_viewport, &program_state->viewport)) { - op = ops_begin (builder, OP_CHANGE_VIEWPORT); - op->viewport = builder->current_viewport; + OpViewport *opv; + + opv = ops_begin (builder, OP_CHANGE_VIEWPORT); + opv->viewport = builder->current_viewport; program_state->viewport = builder->current_viewport; } if (memcmp (&empty_clip, &program_state->clip, sizeof (GskRoundedRect)) == 0 || memcmp (&builder->current_clip, &program_state->clip, sizeof (GskRoundedRect)) != 0) { - op = ops_begin (builder, OP_CHANGE_CLIP); - op->clip = *builder->current_clip; + OpClip *opc; + + opc = ops_begin (builder, OP_CHANGE_CLIP); + opc->clip = *builder->current_clip; program_state->clip = *builder->current_clip; } if (program_state->opacity != builder->current_opacity) { - op = ops_begin (builder, OP_CHANGE_OPACITY); - op->opacity = builder->current_opacity; + OpOpacity *opo; + + opo = ops_begin (builder, OP_CHANGE_OPACITY); + opo->opacity = builder->current_opacity; program_state->opacity = builder->current_opacity; } } @@ -267,29 +282,17 @@ static void ops_set_clip (RenderOpBuilder *builder, const GskRoundedRect *clip) { - RenderOp *last_op; ProgramState *current_program_state = get_current_program_state (builder); + OpClip *op; if (current_program_state && memcmp (¤t_program_state->clip, clip,sizeof (GskRoundedRect)) == 0) return; - if (builder->render_ops->len > 0) - { - last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); + if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_CLIP))) + op = op_buffer_add (&builder->render_ops, OP_CHANGE_CLIP); - if (last_op->op == OP_CHANGE_CLIP) - { - last_op->clip = *clip; - } - else - { - RenderOp *op; - - op = ops_begin (builder, OP_CHANGE_CLIP); - op->clip = *clip; - } - } + op->clip = *clip; if (builder->current_program != NULL) current_program_state->clip = *clip; @@ -343,8 +346,8 @@ ops_set_modelview_internal (RenderOpBuilder *builder, GskTransform *transform) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; graphene_matrix_t matrix; + OpMatrix *op; #if 0 XXX This is not possible if we want pop() to work. @@ -355,24 +358,10 @@ ops_set_modelview_internal (RenderOpBuilder *builder, gsk_transform_to_matrix (transform, &matrix); - if (builder->render_ops->len > 0) - { - RenderOp *last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); - if (last_op->op == OP_CHANGE_MODELVIEW) - { - last_op->modelview = matrix; - } - else - { - op = ops_begin (builder, OP_CHANGE_MODELVIEW); - op->modelview = matrix; - } - } - else - { - op = ops_begin (builder, OP_CHANGE_MODELVIEW); - op->modelview = matrix; - } + if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_MODELVIEW))) + op = op_buffer_add (&builder->render_ops, OP_CHANGE_MODELVIEW); + + op->matrix = matrix; if (builder->current_program != NULL) { @@ -490,27 +479,13 @@ ops_set_projection (RenderOpBuilder *builder, const graphene_matrix_t *projection) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; graphene_matrix_t prev_mv; + OpMatrix *op; - if (builder->render_ops->len > 0) - { - RenderOp *last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); - if (last_op->op == OP_CHANGE_PROJECTION) - { - last_op->projection = *projection; - } - else - { - op = ops_begin (builder, OP_CHANGE_PROJECTION); - op->projection = *projection; - } - } - else - { - op = ops_begin (builder, OP_CHANGE_PROJECTION); - op->projection = *projection; - } + if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_PROJECTION))) + op = op_buffer_add (&builder->render_ops, OP_CHANGE_PROJECTION); + + op->matrix = *projection; if (builder->current_program != NULL) current_program_state->projection = *projection; @@ -526,7 +501,7 @@ ops_set_viewport (RenderOpBuilder *builder, const graphene_rect_t *viewport) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpViewport *op; graphene_rect_t prev_viewport; if (current_program_state != NULL && @@ -549,7 +524,7 @@ void ops_set_texture (RenderOpBuilder *builder, int texture_id) { - RenderOp *op; + OpTexture *op; if (builder->current_texture == texture_id) return; @@ -563,7 +538,7 @@ int ops_set_render_target (RenderOpBuilder *builder, int render_target_id) { - RenderOp *op; + OpRenderTarget *op; int prev_render_target; if (builder->current_render_target == render_target_id) @@ -571,24 +546,10 @@ ops_set_render_target (RenderOpBuilder *builder, prev_render_target = builder->current_render_target; - if (builder->render_ops->len > 0) - { - RenderOp *last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); - if (last_op->op == OP_CHANGE_RENDER_TARGET) - { - last_op->render_target_id = render_target_id; - } - else - { - op = ops_begin (builder, OP_CHANGE_RENDER_TARGET); - op->render_target_id = render_target_id; - } - } - else - { - op = ops_begin (builder, OP_CHANGE_RENDER_TARGET); - op->render_target_id = render_target_id; - } + if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_RENDER_TARGET))) + op = op_buffer_add (&builder->render_ops, OP_CHANGE_RENDER_TARGET); + + op->render_target_id = render_target_id; builder->current_render_target = render_target_id; @@ -600,32 +561,16 @@ ops_set_opacity (RenderOpBuilder *builder, float opacity) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpOpacity *op; float prev_opacity; - RenderOp *last_op; if (builder->current_opacity == opacity) return opacity; - if (builder->render_ops->len > 0) - { - last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); + if (!(op = op_buffer_peek_tail_checked (&builder->render_ops, OP_CHANGE_OPACITY))) + op = op_buffer_add (&builder->render_ops, OP_CHANGE_OPACITY); - if (last_op->op == OP_CHANGE_OPACITY) - { - last_op->opacity = opacity; - } - else - { - op = ops_begin (builder, OP_CHANGE_OPACITY); - op->opacity = opacity; - } - } - else - { - op = ops_begin (builder, OP_CHANGE_OPACITY); - op->opacity = opacity; - } + op->opacity = opacity; prev_opacity = builder->current_opacity; builder->current_opacity = opacity; @@ -641,7 +586,7 @@ ops_set_color (RenderOpBuilder *builder, const GdkRGBA *color) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpColor *op; if (gdk_rgba_equal (color, ¤t_program_state->color)) return; @@ -649,7 +594,7 @@ ops_set_color (RenderOpBuilder *builder, current_program_state->color = *color; op = ops_begin (builder, OP_CHANGE_COLOR); - op->color = color; + op->rgba = *color; } void @@ -658,7 +603,7 @@ ops_set_color_matrix (RenderOpBuilder *builder, const graphene_vec4_t *offset) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpColorMatrix *op; if (memcmp (matrix, ¤t_program_state->color_matrix.matrix, @@ -672,8 +617,8 @@ ops_set_color_matrix (RenderOpBuilder *builder, current_program_state->color_matrix.offset = *offset; op = ops_begin (builder, OP_CHANGE_COLOR_MATRIX); - op->color_matrix.matrix = *matrix; - op->color_matrix.offset = *offset; + op->matrix = *matrix; + op->offset = *offset; } void @@ -681,7 +626,7 @@ ops_set_border (RenderOpBuilder *builder, const GskRoundedRect *outline) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpBorder *op; if (memcmp (¤t_program_state->border.outline, outline, sizeof (GskRoundedRect)) == 0) @@ -690,7 +635,7 @@ ops_set_border (RenderOpBuilder *builder, current_program_state->border.outline = *outline; op = ops_begin (builder, OP_CHANGE_BORDER); - op->border.outline = *outline; + op->outline = *outline; } void @@ -698,7 +643,7 @@ ops_set_border_width (RenderOpBuilder *builder, const float *widths) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp *op; + OpBorder *op; if (memcmp (current_program_state->border.widths, widths, sizeof (float) * 4) == 0) @@ -708,10 +653,10 @@ ops_set_border_width (RenderOpBuilder *builder, widths, sizeof (float) * 4); op = ops_begin (builder, OP_CHANGE_BORDER_WIDTH); - op->border.widths[0] = widths[0]; - op->border.widths[1] = widths[1]; - op->border.widths[2] = widths[2]; - op->border.widths[3] = widths[3]; + op->widths[0] = widths[0]; + op->widths[1] = widths[1]; + op->widths[2] = widths[2]; + op->widths[3] = widths[3]; } void @@ -719,68 +664,37 @@ ops_set_border_color (RenderOpBuilder *builder, const GdkRGBA *color) { ProgramState *current_program_state = get_current_program_state (builder); - RenderOp op; - op.op = OP_CHANGE_BORDER_COLOR; - rgba_to_float (color, op.border.color); + OpBorder *op; + float fcolor[4]; - if (memcmp (&op.border.color, ¤t_program_state->border.color, - sizeof (float) * 4) == 0) + rgba_to_float (color, fcolor); + + if (memcmp (fcolor, ¤t_program_state->border.color, sizeof fcolor) == 0) return; - rgba_to_float (color, current_program_state->border.color); - - g_array_append_val (builder->render_ops, op); + op = op_buffer_add (&builder->render_ops, OP_CHANGE_BORDER_COLOR); + memcpy (op->color, fcolor, sizeof (float[4])); + memcpy (current_program_state->border.color, fcolor, sizeof (float[4])); } void ops_draw (RenderOpBuilder *builder, const GskQuadVertex vertex_data[GL_N_VERTICES]) { - RenderOp *last_op; + OpDraw *op; - last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); - /* If the previous op was a DRAW as well, we didn't change anything between the two calls, - * so these are just 2 subsequent draw calls. Same VAO, same program etc. - * And the offsets into the vao are in order as well, so make it one draw call. */ - if (last_op->op == OP_DRAW) + if ((op = op_buffer_peek_tail_checked (&builder->render_ops, OP_DRAW))) { - /* We allow ourselves a little trick here. We still have to add a CHANGE_VAO op for - * this draw call so we can add our vertex data there, but we want it to be placed before - * the last draw call, so we reorder those. */ - RenderOp *new_draw; - - new_draw = ops_begin (builder, OP_DRAW); - - /* last_op may have moved in memory */ - last_op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 2); - - new_draw->draw.vao_offset = last_op->draw.vao_offset; - new_draw->draw.vao_size = last_op->draw.vao_size + GL_N_VERTICES; - - last_op->op = OP_CHANGE_VAO; - memcpy (&last_op->vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES); + op->vao_size += GL_N_VERTICES; } else { - const gsize n_ops = builder->render_ops->len; - RenderOp *op; - gsize offset = builder->buffer_size / sizeof (GskQuadVertex); - - /* We will add two render ops here. */ - g_array_set_size (builder->render_ops, n_ops + 2); - - op = &g_array_index (builder->render_ops, RenderOp, n_ops); - op->op = OP_CHANGE_VAO; - memcpy (&op->vertex_data, vertex_data, sizeof(GskQuadVertex) * GL_N_VERTICES); - - op = &g_array_index (builder->render_ops, RenderOp, n_ops + 1); - op->op = OP_DRAW; - op->draw.vao_offset = offset; - op->draw.vao_size = GL_N_VERTICES; + op = op_buffer_add (&builder->render_ops, OP_DRAW); + op->vao_offset = builder->vertices->len; + op->vao_size = GL_N_VERTICES; } - /* We added new vertex data in both cases so increase the buffer size */ - builder->buffer_size += sizeof (GskQuadVertex) * GL_N_VERTICES; + g_array_append_vals (builder->vertices, vertex_data, GL_N_VERTICES); } /* The offset is only valid for the current modelview. @@ -795,15 +709,22 @@ ops_offset (RenderOpBuilder *builder, builder->dy += y; } -RenderOp * +gpointer ops_begin (RenderOpBuilder *builder, - guint kind) + OpKind kind) { - RenderOp *op; - - g_array_set_size (builder->render_ops, builder->render_ops->len + 1); - op = &g_array_index (builder->render_ops, RenderOp, builder->render_ops->len - 1); - op->op = kind; - - return op; + return op_buffer_add (&builder->render_ops, kind); +} + +void +ops_reset (RenderOpBuilder *builder) +{ + op_buffer_clear (&builder->render_ops); + g_array_set_size (builder->vertices, 0); +} + +OpBuffer * +ops_get_buffer (RenderOpBuilder *builder) +{ + return &builder->render_ops; } diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index 5f43eace61..e555653617 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -10,6 +10,8 @@ #include "gskglrenderer.h" #include "gskrendernodeprivate.h" +#include "opbuffer.h" + #define GL_N_VERTICES 6 #define GL_N_PROGRAMS 13 @@ -32,38 +34,7 @@ typedef struct OpsMatrixMetadata metadata; } MatrixStackEntry; -enum { - OP_NONE, - OP_CHANGE_OPACITY = 1, - OP_CHANGE_COLOR = 2, - OP_CHANGE_PROJECTION = 3, - OP_CHANGE_MODELVIEW = 4, - OP_CHANGE_PROGRAM = 5, - OP_CHANGE_RENDER_TARGET = 6, - OP_CHANGE_CLIP = 7, - OP_CHANGE_VIEWPORT = 8, - OP_CHANGE_SOURCE_TEXTURE = 9, - OP_CHANGE_VAO = 10, - OP_CHANGE_LINEAR_GRADIENT = 11, - OP_CHANGE_COLOR_MATRIX = 12, - OP_CHANGE_BLUR = 13, - OP_CHANGE_INSET_SHADOW = 14, - OP_CHANGE_OUTSET_SHADOW = 15, - OP_CHANGE_BORDER = 16, - OP_CHANGE_BORDER_COLOR = 17, - OP_CHANGE_BORDER_WIDTH = 18, - OP_CHANGE_CROSS_FADE = 19, - OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 20, - OP_CLEAR = 21, - OP_DRAW = 22, - OP_DUMP_FRAMEBUFFER = 23, - OP_PUSH_DEBUG_GROUP = 24, - OP_POP_DEBUG_GROUP = 25, - OP_CHANGE_BLEND = 26, - OP_CHANGE_REPEAT = 27, -}; - -typedef struct +struct _Program { int index; /* Into the renderer's program array */ @@ -145,101 +116,7 @@ typedef struct int texture_rect_location; } repeat; }; - -} Program; - -typedef struct -{ - guint op; - - union { - float opacity; - graphene_matrix_t modelview; - graphene_matrix_t projection; - const Program *program; - int texture_id; - int render_target_id; - const GdkRGBA *color; - GskQuadVertex vertex_data[6]; - GskRoundedRect clip; - graphene_rect_t viewport; - struct { - int n_color_stops; - float color_offsets[8]; - float color_stops[4 * 8]; - graphene_point_t start_point; - graphene_point_t end_point; - } linear_gradient; - struct { - gsize vao_offset; - gsize vao_size; - } draw; - struct { - graphene_matrix_t matrix; - graphene_vec4_t offset; - } color_matrix; - struct { - float radius; - graphene_size_t size; - float dir[2]; - } blur; - struct { - float outline[4]; - float corner_widths[4]; - float corner_heights[4]; - float radius; - float spread; - float offset[2]; - float color[4]; - } inset_shadow; - struct { - float outline[4]; - float corner_widths[4]; - float corner_heights[4]; - float radius; - float spread; - float offset[2]; - float color[4]; - } outset_shadow; - struct { - float outline[4]; - float corner_widths[4]; - float corner_heights[4]; - float radius; - float spread; - float offset[2]; - float color[4]; - } unblurred_outset_shadow; - struct { - float color[4]; - } shadow; - struct { - float widths[4]; - float color[4]; - GskRoundedRect outline; - } border; - struct { - float progress; - int source2; - } cross_fade; - struct { - int source2; - int mode; - } blend; - struct { - float child_bounds[4]; - float texture_rect[4]; - } repeat; - struct { - char *filename; - int width; - int height; - } dump; - struct { - char text[180]; /* Size of linear_gradient, so 'should be enough' without growing RenderOp */ - } debug_group; - }; -} RenderOp; +}; typedef struct { @@ -276,9 +153,9 @@ typedef struct float current_opacity; float dx, dy; - gsize buffer_size; + OpBuffer render_ops; + GArray *vertices; - GArray *render_ops; GskGLRenderer *renderer; /* Stack of modelview matrices */ @@ -298,6 +175,7 @@ void ops_dump_framebuffer (RenderOpBuilder *builder, int height); void ops_init (RenderOpBuilder *builder); void ops_free (RenderOpBuilder *builder); +void ops_reset (RenderOpBuilder *builder); void ops_push_debug_group (RenderOpBuilder *builder, const char *text); void ops_pop_debug_group (RenderOpBuilder *builder); @@ -358,7 +236,8 @@ void ops_offset (RenderOpBuilder *builder, float x, float y); -RenderOp *ops_begin (RenderOpBuilder *builder, - guint kind); +gpointer ops_begin (RenderOpBuilder *builder, + OpKind kind); +OpBuffer *ops_get_buffer (RenderOpBuilder *builder); #endif diff --git a/gsk/gl/opbuffer.c b/gsk/gl/opbuffer.c new file mode 100644 index 0000000000..b85127b5dd --- /dev/null +++ b/gsk/gl/opbuffer.c @@ -0,0 +1,133 @@ +#include "opbuffer.h" + +#include + +static guint op_sizes[OP_LAST] = { + 0, + sizeof (OpOpacity), + sizeof (OpColor), + sizeof (OpMatrix), + sizeof (OpMatrix), + sizeof (OpProgram), + sizeof (OpRenderTarget), + sizeof (OpClip), + sizeof (OpViewport), + sizeof (OpTexture), + sizeof (OpRepeat), + sizeof (OpLinearGradient), + sizeof (OpColorMatrix), + sizeof (OpBlur), + sizeof (OpShadow), + sizeof (OpShadow), + sizeof (OpBorder), + sizeof (OpBorder), + sizeof (OpBorder), + sizeof (OpCrossFade), + sizeof (OpShadow), + 0, + sizeof (OpDraw), + sizeof (OpDumpFrameBuffer), + sizeof (OpDebugGroup), + 0, + sizeof (OpBlend), +}; + +void +op_buffer_init (OpBuffer *buffer) +{ + static gsize initialized = FALSE; + + if (g_once_init_enter (&initialized)) + { + guint i; + + for (i = 0; i < G_N_ELEMENTS (op_sizes); i++) + { + guint size = op_sizes[i]; + + if (size > 0) + { + /* Round all op entry sizes to the nearest 16 to ensure + * that we guarantee proper alignments for all op entries. + * This is only done once on first use. + */ +#define CHECK_SIZE(s) else if (size < (s)) { size = s; } + if (0) {} + CHECK_SIZE (16) + CHECK_SIZE (32) + CHECK_SIZE (48) + CHECK_SIZE (64) + CHECK_SIZE (80) + CHECK_SIZE (96) + CHECK_SIZE (112) + CHECK_SIZE (128) + CHECK_SIZE (144) + CHECK_SIZE (160) + CHECK_SIZE (176) + CHECK_SIZE (192) + else g_assert_not_reached (); +#undef CHECK_SIZE + + op_sizes[i] = size; + } + } + + g_once_init_leave (&initialized, TRUE); + } + + memset (buffer, 0, sizeof *buffer); + + buffer->buflen = 4096; + buffer->bufpos = 0; + buffer->buf = g_malloc (buffer->buflen); + buffer->index = g_array_new (FALSE, FALSE, sizeof (OpBufferEntry)); + + /* Add dummy entry to guarantee non-empty index */ + op_buffer_add (buffer, OP_NONE); +} + +void +op_buffer_destroy (OpBuffer *buffer) +{ + g_free (buffer->buf); + g_array_unref (buffer->index); +} + +void +op_buffer_clear (OpBuffer *buffer) +{ + if (buffer->index->len > 1) + g_array_remove_range (buffer->index, 1, buffer->index->len - 1); + buffer->bufpos = 0; +} + +static inline void +ensure_buffer_space_for (OpBuffer *buffer, + guint size) +{ + if G_UNLIKELY (buffer->bufpos + size >= buffer->buflen) + { + buffer->buflen *= 2; + buffer->buf = g_realloc (buffer->buf, buffer->buflen); + } +} + +gpointer +op_buffer_add (OpBuffer *buffer, + OpKind kind) +{ + guint size = op_sizes[kind]; + OpBufferEntry entry; + + entry.pos = buffer->bufpos; + entry.kind = kind; + + if (size > 0) + ensure_buffer_space_for (buffer, size); + + g_array_append_val (buffer->index, entry); + + buffer->bufpos += size; + + return &buffer->buf[entry.pos]; +} diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h new file mode 100644 index 0000000000..5124291628 --- /dev/null +++ b/gsk/gl/opbuffer.h @@ -0,0 +1,257 @@ +#ifndef __OP_BUFFER_H__ +#define __OP_BUFFER_H__ + +#include +#include +#include + +#include "gskgldriverprivate.h" + +typedef struct _Program Program; + +typedef enum +{ + OP_NONE = 0, + OP_CHANGE_OPACITY = 1, + OP_CHANGE_COLOR = 2, + OP_CHANGE_PROJECTION = 3, + OP_CHANGE_MODELVIEW = 4, + OP_CHANGE_PROGRAM = 5, + OP_CHANGE_RENDER_TARGET = 6, + OP_CHANGE_CLIP = 7, + OP_CHANGE_VIEWPORT = 8, + OP_CHANGE_SOURCE_TEXTURE = 9, + OP_CHANGE_REPEAT = 10, + OP_CHANGE_LINEAR_GRADIENT = 11, + OP_CHANGE_COLOR_MATRIX = 12, + OP_CHANGE_BLUR = 13, + OP_CHANGE_INSET_SHADOW = 14, + OP_CHANGE_OUTSET_SHADOW = 15, + OP_CHANGE_BORDER = 16, + OP_CHANGE_BORDER_COLOR = 17, + OP_CHANGE_BORDER_WIDTH = 18, + OP_CHANGE_CROSS_FADE = 19, + OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 20, + OP_CLEAR = 21, + OP_DRAW = 22, + OP_DUMP_FRAMEBUFFER = 23, + OP_PUSH_DEBUG_GROUP = 24, + OP_POP_DEBUG_GROUP = 25, + OP_CHANGE_BLEND = 26, + OP_LAST +} OpKind; + +/* OpNode are allocated within OpBuffer.pos, but we keep + * a secondary index into the locations of that buffer + * from OpBuffer.index. This allows peeking at the kind + * and quickly replacing existing entries when necessary. + */ +typedef struct +{ + guint pos; + OpKind kind; +} OpBufferEntry; + +typedef struct +{ + guint8 *buf; + gsize buflen; + gsize bufpos; + GArray *index; +} OpBuffer; + +typedef struct +{ + float opacity; +} OpOpacity; + +typedef struct +{ + graphene_matrix_t matrix; +} OpMatrix; + +typedef struct +{ + const Program *program; +} OpProgram; + +typedef struct +{ + GdkRGBA rgba; +} OpColor; + +typedef struct +{ + int render_target_id; +} OpRenderTarget; + +typedef struct +{ + GskRoundedRect clip; +} OpClip; + +typedef struct +{ + graphene_rect_t viewport; +} OpViewport; + +typedef struct +{ + int texture_id; +} OpTexture; + +typedef struct +{ + gsize vao_offset; + gsize vao_size; +} OpDraw; + +typedef struct +{ + float color_offsets[8]; + float color_stops[4 * 8]; + graphene_point_t start_point; + graphene_point_t end_point; + int n_color_stops; +} OpLinearGradient; + +typedef struct +{ + graphene_matrix_t matrix; + graphene_vec4_t offset; +} OpColorMatrix; + +typedef struct +{ + float radius; + graphene_size_t size; + float dir[2]; +} OpBlur; + +typedef struct +{ + float outline[4]; + float corner_widths[4]; + float corner_heights[4]; + float radius; + float spread; + float offset[2]; + float color[4]; +} OpShadow; + +typedef struct +{ + float widths[4]; + float color[4]; + GskRoundedRect outline; +} OpBorder; + +typedef struct +{ + float progress; + int source2; +} OpCrossFade; + +typedef struct +{ + char *filename; + int width; + int height; +} OpDumpFrameBuffer; + +typedef struct +{ + char text[64]; +} OpDebugGroup; + +typedef struct +{ + int source2; + int mode; +} OpBlend; + +typedef struct +{ + float child_bounds[4]; + float texture_rect[4]; +} OpRepeat; + +void op_buffer_init (OpBuffer *buffer); +void op_buffer_destroy (OpBuffer *buffer); +void op_buffer_clear (OpBuffer *buffer); +gpointer op_buffer_add (OpBuffer *buffer, + OpKind kind); + +typedef struct +{ + GArray *index; + OpBuffer *buffer; + guint pos; +} OpBufferIter; + +static inline void +op_buffer_iter_init (OpBufferIter *iter, + OpBuffer *buffer) +{ + iter->index = buffer->index; + iter->buffer = buffer; + iter->pos = 1; /* Skip first OP_NONE */ +} + +static inline gpointer +op_buffer_iter_next (OpBufferIter *iter, + OpKind *kind) +{ + const OpBufferEntry *entry; + + if (iter->pos == iter->index->len) + return NULL; + + entry = &g_array_index (iter->index, OpBufferEntry, iter->pos); + + iter->pos++; + + *kind = entry->kind; + return &iter->buffer->buf[entry->pos]; +} + +static inline void +op_buffer_pop_tail (OpBuffer *buffer) +{ + /* Never truncate the first OP_NONE */ + if G_LIKELY (buffer->index->len > 0) + buffer->index->len--; +} + +static inline gpointer +op_buffer_peek_tail (OpBuffer *buffer, + OpKind *kind) +{ + const OpBufferEntry *entry; + + entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1); + *kind = entry->kind; + return &buffer->buf[entry->pos]; +} + +static inline gpointer +op_buffer_peek_tail_checked (OpBuffer *buffer, + OpKind kind) +{ + const OpBufferEntry *entry; + + entry = &g_array_index (buffer->index, OpBufferEntry, buffer->index->len - 1); + + if (entry->kind == kind) + return &buffer->buf[entry->pos]; + + return NULL; +} + +static inline guint +op_buffer_n_ops (OpBuffer *buffer) +{ + return buffer->index->len - 1; +} + +#endif /* __OP_BUFFER_H__ */ diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 8c7be01555..c362a6fa53 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -3414,6 +3414,7 @@ struct _GskTextNode GdkRGBA color; graphene_point_t offset; + gpointer render_data; guint num_glyphs; PangoGlyphInfo glyphs[]; }; @@ -3423,6 +3424,7 @@ gsk_text_node_finalize (GskRenderNode *node) { GskTextNode *self = (GskTextNode *) node; + g_free (self->render_data); g_object_unref (self->font); } @@ -3545,6 +3547,7 @@ gsk_text_node_new (PangoFont *font, self->has_color_glyphs = font_has_color_glyphs (font); self->color = *color; self->offset = *offset; + self->render_data = NULL; self->num_glyphs = glyphs->num_glyphs; memcpy (self->glyphs, glyphs->glyphs, sizeof (PangoGlyphInfo) * glyphs->num_glyphs); @@ -3625,6 +3628,24 @@ gsk_text_node_get_offset (GskRenderNode *node) return &self->offset; } +void +gsk_text_node_set_render_data (GskRenderNode *node, + gpointer data) +{ + GskTextNode *self = (GskTextNode *) node; + + self->render_data = data; +} + +gpointer +gsk_text_node_get_render_data (GskRenderNode *node) +{ + GskTextNode *self = (GskTextNode *) node; + + return self->render_data; +} + + /*** GSK_BLUR_NODE ***/ typedef struct _GskBlurNode GskBlurNode; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 2ced79738b..f2fe034444 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -46,6 +46,10 @@ void gsk_render_node_diff (GskRenderNode *nod void gsk_render_node_diff_impossible (GskRenderNode *node1, GskRenderNode *node2, cairo_region_t *region); +void gsk_text_node_set_render_data (GskRenderNode *node, + gpointer data); +gpointer gsk_text_node_get_render_data (GskRenderNode *node); + G_END_DECLS diff --git a/gsk/meson.build b/gsk/meson.build index 6819ac5426..ed621284bb 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -48,6 +48,7 @@ gsk_private_sources = files([ 'gl/gskglnodesample.c', 'gl/gskgltextureatlas.c', 'gl/gskgliconcache.c', + 'gl/opbuffer.c', 'gl/stb_rect_pack.c', ]) diff --git a/gtk/gdkpixbufutilsprivate.h b/gtk/gdkpixbufutilsprivate.h index a11ce9bc96..592bc9ea59 100644 --- a/gtk/gdkpixbufutilsprivate.h +++ b/gtk/gdkpixbufutilsprivate.h @@ -22,13 +22,35 @@ G_BEGIN_DECLS -GdkPixbuf *_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, - gdouble scale, +GdkPixbuf *_gdk_pixbuf_new_from_stream (GInputStream *stream, + const char *format, + GCancellable *cancellable, + GError **error); +GdkPixbuf *_gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream, + const char *format, + int width, + int height, + gboolean aspect, GCancellable *cancellable, GError **error); -GdkPixbuf *_gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path, - gdouble scale, +GdkPixbuf *_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, + const char *format, + double scale, + GCancellable *cancellable, GError **error); +GdkPixbuf *_gdk_pixbuf_new_from_resource (const char *resource_path, + const char *format, + GError **error); +GdkPixbuf *_gdk_pixbuf_new_from_resource_at_scale (const char *resource_path, + const char *format, + int width, + int height, + gboolean preserve_aspect, + GError **error); +GdkPixbuf *_gdk_pixbuf_new_from_resource_scaled (const char *resource_path, + const char *format, + double scale, + GError **error); GdkPixbuf *gtk_make_symbolic_pixbuf_from_data (const char *data, gsize len, diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 8a580fb4ac..e44b953017 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -3276,17 +3276,16 @@ gtk_icon_info_get_filename (GtkIconInfo *icon_info) gboolean gtk_icon_info_is_symbolic (GtkIconInfo *icon_info) { - gchar *icon_uri; + const char *path; gboolean is_symbolic; g_return_val_if_fail (GTK_IS_ICON_INFO (icon_info), FALSE); - icon_uri = NULL; + path = NULL; if (icon_info->icon_file) - icon_uri = g_file_get_uri (icon_info->icon_file); + path = g_file_peek_path (icon_info->icon_file); - is_symbolic = (icon_uri != NULL) && (icon_uri_is_symbolic (icon_uri, -1)); - g_free (icon_uri); + is_symbolic = (path != NULL) && (icon_uri_is_symbolic (path, -1)); return is_symbolic; } @@ -3384,16 +3383,19 @@ icon_info_ensure_scale_and_texture (GtkIconInfo *icon_info) &icon_info->load_error); else if (size == 0) source_pixbuf = _gdk_pixbuf_new_from_resource_scaled (icon_info->filename, + "svg", icon_info->desired_scale, &icon_info->load_error); else - source_pixbuf = gdk_pixbuf_new_from_resource_at_scale (icon_info->filename, - size, size, TRUE, - &icon_info->load_error); + source_pixbuf = _gdk_pixbuf_new_from_resource_at_scale (icon_info->filename, + "svg", + size, size, TRUE, + &icon_info->load_error); } else - source_pixbuf = gdk_pixbuf_new_from_resource (icon_info->filename, - &icon_info->load_error); + source_pixbuf = _gdk_pixbuf_new_from_resource (icon_info->filename, + "png", + &icon_info->load_error); } else { @@ -3425,19 +3427,22 @@ icon_info_ensure_scale_and_texture (GtkIconInfo *icon_info) &icon_info->load_error); else if (size == 0) source_pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, + "svg", icon_info->desired_scale, NULL, &icon_info->load_error); else - source_pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, - size, size, - TRUE, NULL, + source_pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, + "svg", + size, size, + TRUE, NULL, &icon_info->load_error); } else - source_pixbuf = gdk_pixbuf_new_from_stream (stream, - NULL, - &icon_info->load_error); + source_pixbuf = _gdk_pixbuf_new_from_stream (stream, + "png", + NULL, + &icon_info->load_error); g_object_unref (stream); } } @@ -3938,7 +3943,8 @@ gtk_icon_info_load_symbolic_svg (GtkIconInfo *icon_info, g_free (height); stream = g_memory_input_stream_new_from_data (data, -1, g_free); - pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream, + pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, + "svg", gdk_texture_get_width (icon_info->texture), gdk_texture_get_height (icon_info->texture), TRUE, diff --git a/gtk/tools/gdkpixbufutils.c b/gtk/tools/gdkpixbufutils.c index 5f8c19bf87..a572f48a82 100644 --- a/gtk/tools/gdkpixbufutils.c +++ b/gtk/tools/gdkpixbufutils.c @@ -90,6 +90,7 @@ size_prepared_cb (GdkPixbufLoader *loader, */ GdkPixbuf * _gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, + const char *format, gdouble scale, GCancellable *cancellable, GError **error) @@ -97,10 +98,18 @@ _gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, GdkPixbufLoader *loader; GdkPixbuf *pixbuf; - loader = gdk_pixbuf_loader_new (); + if (format) + { + loader = gdk_pixbuf_loader_new_with_type (format, error); + if (!loader) + return NULL; + } + else + loader = gdk_pixbuf_loader_new (); - g_signal_connect (loader, "size-prepared", - G_CALLBACK (size_prepared_cb), &scale); + if (scale != 0) + g_signal_connect (loader, "size-prepared", + G_CALLBACK (size_prepared_cb), &scale); pixbuf = load_from_stream (loader, stream, cancellable, error); @@ -109,14 +118,69 @@ _gdk_pixbuf_new_from_stream_scaled (GInputStream *stream, return pixbuf; } +static void +size_prepared_cb2 (GdkPixbufLoader *loader, + gint width, + gint height, + gpointer data) +{ + int *scales = data; + + gdk_pixbuf_loader_set_size (loader, scales[0], scales[1]); +} + +GdkPixbuf * +_gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream, + const char *format, + int width, + int height, + gboolean aspect, + GCancellable *cancellable, + GError **error) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf; + int scales[2]; + + if (format) + { + loader = gdk_pixbuf_loader_new_with_type (format, error); + if (!loader) + return NULL; + } + else + loader = gdk_pixbuf_loader_new (); + + scales[0] = width; + scales[1] = height; + g_signal_connect (loader, "size-prepared", + G_CALLBACK (size_prepared_cb2), scales); + + pixbuf = load_from_stream (loader, stream, cancellable, error); + + g_object_unref (loader); + + return pixbuf; +} + +GdkPixbuf * +_gdk_pixbuf_new_from_stream (GInputStream *stream, + const char *format, + GCancellable *cancellable, + GError **error) +{ + return _gdk_pixbuf_new_from_stream_scaled (stream, format, 0, cancellable, error); +} + /* Like gdk_pixbuf_new_from_resource_at_scale, but * load the image at its original size times the * given scale. */ GdkPixbuf * -_gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path, - gdouble scale, - GError **error) +_gdk_pixbuf_new_from_resource_scaled (const char *resource_path, + const char *format, + double scale, + GError **error) { GInputStream *stream; GdkPixbuf *pixbuf; @@ -125,12 +189,42 @@ _gdk_pixbuf_new_from_resource_scaled (const gchar *resource_path, if (stream == NULL) return NULL; - pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, scale, NULL, error); + pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, format, scale, NULL, error); g_object_unref (stream); return pixbuf; } +GdkPixbuf * +_gdk_pixbuf_new_from_resource (const char *resource_path, + const char *format, + GError **error) +{ + return _gdk_pixbuf_new_from_resource_scaled (resource_path, format, 0, error); +} + +GdkPixbuf * +_gdk_pixbuf_new_from_resource_at_scale (const char *resource_path, + const char *format, + int width, + int height, + gboolean preserve_aspect, + GError **error) +{ + GInputStream *stream; + GdkPixbuf *pixbuf; + + stream = g_resources_open_stream (resource_path, 0, error); + if (stream == NULL) + return NULL; + + pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, format, width, height, preserve_aspect, NULL, error); + g_object_unref (stream); + + return pixbuf; + +} + static GdkPixbuf * load_symbolic_svg (const char *escaped_file_data, int width, @@ -332,11 +426,11 @@ gtk_make_symbolic_pixbuf_from_resource (const char *path, } GdkPixbuf * -gtk_make_symbolic_pixbuf_from_file (GFile *file, - int width, - int height, - double scale, - GError **error) +gtk_make_symbolic_pixbuf_from_file (GFile *file, + int width, + int height, + double scale, + GError **error) { char *data; gsize size; @@ -373,11 +467,11 @@ gtk_make_symbolic_texture_from_resource (const char *path, } GdkTexture * -gtk_make_symbolic_texture_from_file (GFile *file, - int width, - int height, - double scale, - GError **error) +gtk_make_symbolic_texture_from_file (GFile *file, + int width, + int height, + double scale, + GError **error) { GdkPixbuf *pixbuf; GdkTexture *texture;