From 12611fa1424d6d19540c3d81dd38b1c8b7558fd0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Dec 2020 11:43:43 -0500 Subject: [PATCH 1/2] Revert "gl renderer: Take a out graphene_rect in blur_node()" This reverts commit 7eece7e7690326e99d47e20e4a23a406bbd85779. --- gsk/gl/gskglrenderer.c | 81 +++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 3cb261384c..2076b0ccae 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -466,15 +466,12 @@ load_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], } static void -load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], - const graphene_rect_t *bounds, - RenderOpBuilder *builder) +fill_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], + const float min_x, + const float min_y, + const float max_x, + const float max_y) { - const float min_x = builder->dx + bounds->origin.x; - const float min_y = builder->dy + bounds->origin.y; - const float max_x = min_x + bounds->size.width; - const float max_y = min_y + bounds->size.height; - vertex_data[0].position[0] = min_x; vertex_data[0].position[1] = min_y; vertex_data[0].uv[0] = 0; @@ -506,6 +503,22 @@ load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], vertex_data[5].uv[1] = 1; } +static void +load_offscreen_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; + + fill_vertex_data (vertex_data, + min_x, min_y, + max_x, max_y); +} + + static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self); static bool add_offscreen_ops (GskGLRenderer *self, RenderOpBuilder *builder, @@ -669,7 +682,7 @@ render_fallback_node (GskGLRenderer *self, { ops_set_program (builder, &self->programs->blit_program); ops_set_texture (builder, cached_id); - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); return; } @@ -753,7 +766,7 @@ render_fallback_node (GskGLRenderer *self, ops_set_program (builder, &self->programs->blit_program); ops_set_texture (builder, texture_id); - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } static inline void @@ -1247,7 +1260,7 @@ render_gl_shader_node (GskGLRenderer *self, ops_set_extra_texture (builder, results[i].region.texture_id, i); } - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } else { @@ -1735,7 +1748,7 @@ render_rounded_clip_node (GskGLRenderer *self, ops_set_program (builder, &self->programs->blit_program); ops_set_texture (builder, result.region.texture_id); - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } } @@ -1875,7 +1888,7 @@ blur_node (GskGLRenderer *self, float blur_radius, guint extra_flags, TextureRegion *out_region, - graphene_rect_t *out_rect) + float *out_vertex_data[4]) /* min, max, min, max */ { const float scale_x = builder->scale_x; const float scale_y = builder->scale_y; @@ -1884,7 +1897,6 @@ blur_node (GskGLRenderer *self, int blurred_texture_id; g_assert (blur_radius > 0); - g_assert (out_rect); /* Increase texture size for the given blur radius and scale it */ texture_width = ceilf ((node->bounds.size.width + blur_extra)); @@ -1910,10 +1922,13 @@ blur_node (GskGLRenderer *self, init_full_texture_region (out_region, blurred_texture_id); } - out_rect->origin.x = node->bounds.origin.x - (blur_extra / 2.0f); - out_rect->origin.y = node->bounds.origin.y - (blur_extra / 2.0f); - out_rect->size.width = node->bounds.size.width + (blur_extra / 2.0f); - out_rect->size.height = node->bounds.size.height + (blur_extra / 2.0f); + if (out_vertex_data) + { + *out_vertex_data[0] = builder->dx + node->bounds.origin.x - (blur_extra / 2.0); + *out_vertex_data[1] = builder->dx + node->bounds.origin.x + node->bounds.size.width + (blur_extra / 2.0); + *out_vertex_data[2] = builder->dy + node->bounds.origin.y - (blur_extra / 2.0); + *out_vertex_data[3] = builder->dy + node->bounds.origin.y + node->bounds.size.height + (blur_extra / 2.0); + } } static inline void @@ -1925,7 +1940,7 @@ render_blur_node (GskGLRenderer *self, GskRenderNode *child = gsk_blur_node_get_child (node); TextureRegion blurred_region; GskTextureKey key; - graphene_rect_t result_rect; + float min_x, max_x, min_y, max_y; if (node_is_invisible (child)) return; @@ -1942,14 +1957,16 @@ render_blur_node (GskGLRenderer *self, key.scale_y = builder->scale_y; key.filter = GL_NEAREST; blurred_region.texture_id = gsk_gl_driver_get_texture_for_key (self->gl_driver, &key); - blur_node (self, child, builder, blur_radius, 0, &blurred_region, &result_rect); + blur_node (self, child, builder, blur_radius, 0, &blurred_region, + (float*[4]){&min_x, &max_x, &min_y, &max_y}); g_assert (blurred_region.texture_id != 0); /* Draw the result */ ops_set_program (builder, &self->programs->blit_program); ops_set_texture (builder, blurred_region.texture_id); - load_offscreen_vertex_data (ops_draw (builder, NULL), &result_rect, builder); + fill_vertex_data (ops_draw (builder, NULL), min_x, min_y, max_x, max_y); + /* Add to cache for the blur node */ gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, blurred_region.texture_id); @@ -2549,9 +2566,18 @@ render_shadow_node (GskGLRenderer *self, if (shadow->radius > 0) { + float min_x; + float min_y; + float max_x; + float max_y; + result.region.texture_id = 0; blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, &result.region, - &bounds); + (float*[4]){&min_x, &max_x, &min_y, &max_y}); + bounds.origin.x = min_x - builder->dx; + bounds.origin.y = min_y - builder->dy; + bounds.size.width = max_x - min_x; + bounds.size.height = max_y - min_y; result.is_offscreen = true; } else if (dx == 0 && dy == 0) @@ -2640,7 +2666,7 @@ render_cross_fade_node (GskGLRenderer *self, ops_set_texture (builder, start_result.region.texture_id); - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } static inline void @@ -2681,7 +2707,7 @@ render_blend_node (GskGLRenderer *self, op->source2 = top_result.region.texture_id; op->mode = gsk_blend_node_get_blend_mode (node); - load_offscreen_vertex_data (ops_draw (builder, NULL), &node->bounds, builder); + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } static inline void @@ -4377,11 +4403,8 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer, graphene_matrix_scale (&m, 1, -1, 1); /* Undo the scale init_projection_matrix() does again */ ops_set_projection (&self->op_builder, &m); - g_assert (self->op_builder.dx == 0); - g_assert (self->op_builder.dy == 0); - - load_offscreen_vertex_data (ops_draw (&self->op_builder, NULL), - &GRAPHENE_RECT_INIT (0, 0, width, height), &self->op_builder); + fill_vertex_data (ops_draw (&self->op_builder, NULL), + 0, 0, width, height); ops_pop_clip (&self->op_builder); gsk_gl_renderer_render_ops (self); From d5143a1bf0345fbb40e115a9e2b8a04180b1b0b5 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 19 Dec 2020 11:43:56 -0500 Subject: [PATCH 2/2] Revert "gl renderer: Render too big textures to the clipped area" This reverts commit 7f6608cbedccfe8a9e7d9a211f33be15951ca144. --- gsk/gl/gskglrenderer.c | 391 +++++++++++++++++++++-------------------- 1 file changed, 203 insertions(+), 188 deletions(-) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 2076b0ccae..0b7a45800c 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -81,13 +81,6 @@ typedef enum LINEAR_FILTER = 1 << 6, } OffscreenFlags; -typedef struct -{ - bool is_offscreen; - TextureRegion region; - graphene_rect_t screen_rect; -} OffscreenResult; - static inline void init_full_texture_region (TextureRegion *r, int texture_id) @@ -520,14 +513,13 @@ load_offscreen_vertex_data (GskQuadVertex vertex_data[GL_N_VERTICES], static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self); -static bool add_offscreen_ops (GskGLRenderer *self, +static gboolean add_offscreen_ops (GskGLRenderer *self, RenderOpBuilder *builder, const graphene_rect_t *bounds, GskRenderNode *child_node, - guint flags, - OffscreenResult *out_result) G_GNUC_WARN_UNUSED_RESULT; - - + TextureRegion *region_out, + gboolean *is_offscreen, + guint flags) G_GNUC_WARN_UNUSED_RESULT; static void gsk_gl_renderer_add_render_ops (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder); @@ -1239,12 +1231,16 @@ render_gl_shader_node (GskGLRenderer *self, if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations)) { GBytes *args; - OffscreenResult results[4]; + TextureRegion regions[4]; + gboolean is_offscreen[4]; for (guint i = 0; i < n_children; i++) { GskRenderNode *child = gsk_gl_shader_node_get_child (node, i); - if (!add_offscreen_ops (self, builder, &node->bounds, child, - FORCE_OFFSCREEN | RESET_CLIP, &results[i])) + if (!add_offscreen_ops (self, builder, + &node->bounds, + child, + ®ions[i], &is_offscreen[i], + FORCE_OFFSCREEN | RESET_CLIP)) return; } @@ -1255,9 +1251,9 @@ render_gl_shader_node (GskGLRenderer *self, for (guint i = 0; i < n_children; i++) { if (i == 0) - ops_set_texture (builder, results[i].region.texture_id); + ops_set_texture (builder, regions[i].texture_id); else - ops_set_extra_texture (builder, results[i].region.texture_id, i); + ops_set_extra_texture (builder, regions[i].texture_id, i); } load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); @@ -1343,6 +1339,9 @@ render_transform_node (GskGLRenderer *self, case GSK_TRANSFORM_CATEGORY_ANY: case GSK_TRANSFORM_CATEGORY_UNKNOWN: { + TextureRegion region; + gboolean is_offscreen; + if (node_supports_transform (child)) { ops_push_modelview (builder, node_transform); @@ -1351,14 +1350,16 @@ render_transform_node (GskGLRenderer *self, } else { - OffscreenResult result; int filter_flag = 0; if (!result_is_axis_aligned (node_transform, &child->bounds)) filter_flag = LINEAR_FILTER; - if (add_offscreen_ops (self, builder, &child->bounds, child, - RESET_CLIP | filter_flag, &result)) + if (add_offscreen_ops (self, builder, + &child->bounds, + child, + ®ion, &is_offscreen, + RESET_CLIP | filter_flag)) { /* For non-trivial transforms, we draw everything on a texture and then * draw the texture transformed. */ @@ -1367,13 +1368,13 @@ render_transform_node (GskGLRenderer *self, * for the texture. */ ops_push_modelview (builder, node_transform); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); ops_set_program (builder, &self->programs->blit_program); load_vertex_data_with_region (ops_draw (builder, NULL), &child->bounds, builder, - &result.region, - result.is_offscreen); + ®ion, + is_offscreen); ops_pop_modelview (builder); } } @@ -1397,12 +1398,15 @@ render_opacity_node (GskGLRenderer *self, if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE) { - OffscreenResult result; + gboolean is_offscreen; + TextureRegion region; /* The semantics of an opacity node mandate that when, e.g., two color nodes overlap, * there may not be any blending between them */ - if (!add_offscreen_ops (self, builder, &child->bounds, child, - FORCE_OFFSCREEN | RESET_CLIP, &result)) + if (!add_offscreen_ops (self, builder, &child->bounds, + child, + ®ion, &is_offscreen, + FORCE_OFFSCREEN | RESET_CLIP)) return; prev_opacity = ops_set_opacity (builder, @@ -1411,11 +1415,12 @@ render_opacity_node (GskGLRenderer *self, if (builder->current_opacity >= ((float) 0x00ff / (float) 0xffff)) { ops_set_program (builder, &self->programs->blit_program); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); load_vertex_data_with_region (ops_draw (builder, NULL), &node->bounds, builder, - &result.region, result.is_offscreen); + ®ion, + is_offscreen); } } else @@ -1637,23 +1642,27 @@ render_clipped_child (GskGLRenderer *self, else { /* well fuck */ - const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT_FROM_RECT (transformed_clip); - OffscreenResult result; + const float scale_x = builder->scale_x; + const float scale_y = builder->scale_y; + const GskRoundedRect scaled_clip = GSK_ROUNDED_RECT_INIT (clip->origin.x * scale_x, + clip->origin.y * scale_y, + clip->size.width * scale_x, + clip->size.height * scale_y); + gboolean is_offscreen; + TextureRegion region; ops_push_clip (builder, &scaled_clip); if (!add_offscreen_ops (self, builder, &child->bounds, - child, FORCE_OFFSCREEN, - &result)) + child, + ®ion, &is_offscreen, + FORCE_OFFSCREEN)) g_assert_not_reached (); ops_pop_clip (builder); ops_set_program (builder, &self->programs->blit_program); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); - load_vertex_data_with_region (ops_draw (builder, NULL), - &result.screen_rect, builder, - &result.region, - result.is_offscreen); + load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder); } } @@ -1737,16 +1746,38 @@ render_rounded_clip_node (GskGLRenderer *self, } else { - OffscreenResult result; + GskRoundedRect scaled_clip; + gboolean is_offscreen; + TextureRegion region; + /* NOTE: We are *not* transforming the clip by the current modelview here. + * We instead draw the untransformed clip to a texture and then transform + * that texture. + * + * We do, however, apply the scale factor to the child clip of course. + */ + scaled_clip.bounds.origin.x = clip->bounds.origin.x * scale_x; + scaled_clip.bounds.origin.y = clip->bounds.origin.y * scale_y; + scaled_clip.bounds.size.width = clip->bounds.size.width * scale_x; + scaled_clip.bounds.size.height = clip->bounds.size.height * scale_y; - ops_push_clip (builder, &transformed_clip); - if (!add_offscreen_ops (self, builder, &node->bounds, child, 0, &result)) + /* Increase corner radius size by scale factor */ + for (i = 0; i < 4; i ++) + { + scaled_clip.corner[i].width = clip->corner[i].width * scale_x; + scaled_clip.corner[i].height = clip->corner[i].height * scale_y; + } + + ops_push_clip (builder, &scaled_clip); + if (!add_offscreen_ops (self, builder, &node->bounds, + child, + ®ion, &is_offscreen, + 0)) g_assert_not_reached (); + ops_pop_clip (builder); - ops_set_program (builder, &self->programs->blit_program); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } @@ -1758,13 +1789,17 @@ render_color_matrix_node (GskGLRenderer *self, RenderOpBuilder *builder) { GskRenderNode *child = gsk_color_matrix_node_get_child (node); - OffscreenResult result; + TextureRegion region; + gboolean is_offscreen; if (node_is_invisible (child)) return; - if (!add_offscreen_ops (self, builder, &node->bounds, child, - RESET_CLIP, &result)) + if (!add_offscreen_ops (self, builder, + &node->bounds, + child, + ®ion, &is_offscreen, + RESET_CLIP)) g_assert_not_reached (); ops_set_program (builder, &self->programs->color_matrix_program); @@ -1772,12 +1807,12 @@ render_color_matrix_node (GskGLRenderer *self, gsk_color_matrix_node_get_color_matrix (node), gsk_color_matrix_node_get_color_offset (node)); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); load_vertex_data_with_region (ops_draw (builder, NULL), - &result.screen_rect, builder, - &result.region, - result.is_offscreen); + &node->bounds, builder, + ®ion, + is_offscreen); } static inline int @@ -1894,6 +1929,8 @@ blur_node (GskGLRenderer *self, const float scale_y = builder->scale_y; const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */ float texture_width, texture_height; + gboolean is_offscreen; + TextureRegion region; int blurred_texture_id; g_assert (blur_radius > 0); @@ -1905,17 +1942,17 @@ blur_node (GskGLRenderer *self, /* Only blur this if the out region has no texture id yet */ if (out_region->texture_id == 0) { - OffscreenResult result; if (!add_offscreen_ops (self, builder, &GRAPHENE_RECT_INIT (node->bounds.origin.x - (blur_extra / 2.0), node->bounds.origin.y - (blur_extra / 2.0), texture_width, texture_height), node, - RESET_CLIP | FORCE_OFFSCREEN | extra_flags, &result)) + ®ion, &is_offscreen, + RESET_CLIP | FORCE_OFFSCREEN | extra_flags)) g_assert_not_reached (); blurred_texture_id = blur_texture (self, builder, - &result.region, + ®ion, texture_width * scale_x, texture_height * scale_y, blur_radius * scale_x, blur_radius * scale_y); @@ -2546,8 +2583,9 @@ render_shadow_node (GskGLRenderer *self, const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i); const float dx = shadow->dx; const float dy = shadow->dy; + TextureRegion region; + gboolean is_offscreen; graphene_rect_t bounds; - OffscreenResult result; if (shadow->radius == 0 && gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE) @@ -2571,14 +2609,14 @@ render_shadow_node (GskGLRenderer *self, float max_x; float max_y; - result.region.texture_id = 0; - blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, &result.region, + region.texture_id = 0; + blur_node (self, shadow_child, builder, shadow->radius, NO_CACHE_PLZ, ®ion, (float*[4]){&min_x, &max_x, &min_y, &max_y}); bounds.origin.x = min_x - builder->dx; bounds.origin.y = min_y - builder->dy; bounds.size.width = max_x - min_x; bounds.size.height = max_y - min_y; - result.is_offscreen = true; + is_offscreen = TRUE; } else if (dx == 0 && dy == 0) { @@ -2586,8 +2624,10 @@ render_shadow_node (GskGLRenderer *self, } else { - if (!add_offscreen_ops (self, builder, &shadow_child->bounds, shadow_child, - RESET_CLIP | NO_CACHE_PLZ, &result)) + if (!add_offscreen_ops (self, builder, + &shadow_child->bounds, + shadow_child, ®ion, &is_offscreen, + RESET_CLIP | NO_CACHE_PLZ)) g_assert_not_reached (); bounds = shadow_child->bounds; @@ -2595,13 +2635,13 @@ render_shadow_node (GskGLRenderer *self, ops_set_program (builder, &self->programs->coloring_program); ops_set_color (builder, &shadow->color); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); ops_offset (builder, dx, dy); load_vertex_data_with_region (ops_draw (builder, NULL), &bounds, builder, - &result.region, - result.is_offscreen); + ®ion, + is_offscreen); ops_offset (builder, -dx, -dy); } @@ -2617,8 +2657,9 @@ render_cross_fade_node (GskGLRenderer *self, GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node); GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node); const float progress = gsk_cross_fade_node_get_progress (node); - OffscreenResult start_result; - OffscreenResult end_result; + TextureRegion start_region; + TextureRegion end_region; + gboolean is_offscreen1, is_offscreen2; OpCrossFade *op; if (progress <= 0) @@ -2641,15 +2682,21 @@ render_cross_fade_node (GskGLRenderer *self, /* 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. */ - if (!add_offscreen_ops (self, builder, &node->bounds, start_node, - FORCE_OFFSCREEN | RESET_CLIP, &start_result)) + if (!add_offscreen_ops (self, builder, + &node->bounds, + start_node, + &start_region, &is_offscreen1, + FORCE_OFFSCREEN | RESET_CLIP)) { gsk_gl_renderer_add_render_ops (self, end_node, builder); return; } - if (!add_offscreen_ops (self, builder, &node->bounds, end_node, - FORCE_OFFSCREEN | RESET_CLIP, &end_result)) + if (!add_offscreen_ops (self, builder, + &node->bounds, + end_node, + &end_region, &is_offscreen2, + FORCE_OFFSCREEN | RESET_CLIP)) { const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress); gsk_gl_renderer_add_render_ops (self, start_node, builder); @@ -2662,9 +2709,9 @@ render_cross_fade_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_CROSS_FADE); op->progress = progress; - op->source2 = end_result.region.texture_id; + op->source2 = end_region.texture_id; - ops_set_texture (builder, start_result.region.texture_id); + ops_set_texture (builder, start_region.texture_id); load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); } @@ -2676,35 +2723,42 @@ render_blend_node (GskGLRenderer *self, { GskRenderNode *top_child = gsk_blend_node_get_top_child (node); GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node); - OffscreenResult top_result; - OffscreenResult bottom_result; + TextureRegion top_region; + TextureRegion bottom_region; + gboolean is_offscreen1, is_offscreen2; OpBlend *op; /* 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. */ - if (!add_offscreen_ops (self, builder, &node->bounds, bottom_child, - FORCE_OFFSCREEN | RESET_CLIP, &bottom_result)) + if (!add_offscreen_ops (self, builder, + &node->bounds, + bottom_child, + &bottom_region, &is_offscreen1, + FORCE_OFFSCREEN | RESET_CLIP)) { gsk_gl_renderer_add_render_ops (self, top_child, builder); return; } - if (!add_offscreen_ops (self, builder, &node->bounds, top_child, - FORCE_OFFSCREEN | RESET_CLIP, &top_result)) + if (!add_offscreen_ops (self, builder, + &node->bounds, + top_child, + &top_region, &is_offscreen2, + FORCE_OFFSCREEN | RESET_CLIP)) { load_vertex_data_with_region (ops_draw (builder, NULL), &node->bounds, builder, - &bottom_result.region, + &bottom_region, TRUE); return; } ops_set_program (builder, &self->programs->blend_program); - ops_set_texture (builder, bottom_result.region.texture_id); + ops_set_texture (builder, bottom_region.texture_id); op = ops_begin (builder, OP_CHANGE_BLEND); - op->source2 = top_result.region.texture_id; + op->source2 = top_region.texture_id; op->mode = gsk_blend_node_get_blend_mode (node); load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); @@ -2717,7 +2771,8 @@ render_repeat_node (GskGLRenderer *self, { GskRenderNode *child = gsk_repeat_node_get_child (node); const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node); - OffscreenResult result; + TextureRegion region; + gboolean is_offscreen; OpRepeat *op; if (node_is_invisible (child)) @@ -2740,12 +2795,15 @@ render_repeat_node (GskGLRenderer *self, } /* Draw the entire child on a texture */ - if (!add_offscreen_ops (self, builder, &child->bounds, child, - RESET_CLIP, &result)) + if (!add_offscreen_ops (self, builder, + &child->bounds, + child, + ®ion, &is_offscreen, + RESET_CLIP)) g_assert_not_reached (); ops_set_program (builder, &self->programs->repeat_program); - ops_set_texture (builder, result.region.texture_id); + ops_set_texture (builder, region.texture_id); op = ops_begin (builder, OP_CHANGE_REPEAT); op->child_bounds[0] = (node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width; @@ -2753,24 +2811,24 @@ render_repeat_node (GskGLRenderer *self, 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->texture_rect[0] = result.region.x; - op->texture_rect[2] = result.region.x2; + op->texture_rect[0] = region.x; + op->texture_rect[2] = region.x2; - if (result.is_offscreen) + if (is_offscreen) { - op->texture_rect[1] = result.region.y2; - op->texture_rect[3] = result.region.y; + op->texture_rect[1] = region.y2; + op->texture_rect[3] = region.y; } else { - op->texture_rect[1] = result.region.y; - op->texture_rect[3] = result.region.y2; + op->texture_rect[1] = region.y; + op->texture_rect[3] = region.y2; } load_vertex_data_with_region (ops_draw (builder, NULL), &node->bounds, builder, - &result.region, - result.is_offscreen); + ®ion, + is_offscreen); } static inline void @@ -3757,17 +3815,18 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, } } -static bool +static gboolean add_offscreen_ops (GskGLRenderer *self, RenderOpBuilder *builder, const graphene_rect_t *bounds, GskRenderNode *child_node, - guint flags, - OffscreenResult *result) + TextureRegion *texture_region_out, + gboolean *is_offscreen, + guint flags) { + float width, height; const float dx = builder->dx; const float dy = builder->dy; - float width, height; float scale_x; float scale_y; int render_target; @@ -3780,20 +3839,14 @@ add_offscreen_ops (GskGLRenderer *self, int filter; GskTextureKey key; int cached_id; - graphene_rect_t screen_rect; - int max_texture_size; - GskRoundedRect new_clip; - bool add_to_cache = false; - - g_assert (result); + graphene_rect_t viewport; if (node_is_invisible (child_node)) { /* Just to be safe */ - result->is_offscreen = false; - result->screen_rect = *bounds; - init_full_texture_region (&result->region, 0); - return false; + *is_offscreen = FALSE; + init_full_texture_region (texture_region_out, 0); + return FALSE; } /* We need the child node as a texture. If it already is one, we don't need to draw @@ -3802,11 +3855,9 @@ add_offscreen_ops (GskGLRenderer *self, (flags & FORCE_OFFSCREEN) == 0) { GdkTexture *texture = gsk_texture_node_get_texture (child_node); - - result->is_offscreen = false; - result->screen_rect = *bounds; - upload_texture (self, texture, &result->region); - return true; + upload_texture (self, texture, texture_region_out); + *is_offscreen = FALSE; + return TRUE; } if (flags & LINEAR_FILTER) @@ -3825,76 +3876,38 @@ add_offscreen_ops (GskGLRenderer *self, if (cached_id != 0) { + init_full_texture_region (texture_region_out, cached_id); /* We didn't render it offscreen, but hand out an offscreen texture id */ - result->is_offscreen = true; - result->screen_rect = *bounds; - - init_full_texture_region (&result->region, cached_id); - return true; + *is_offscreen = TRUE; + return TRUE; } + width = bounds->size.width; + height = bounds->size.height; scale_x = builder->scale_x; scale_y = builder->scale_y; - width = ceilf (bounds->size.width * scale_x); - height = ceilf (bounds->size.height * scale_y); - /* We usually return a texture exactly as big as the node we draw, and at the - * same position. Sometimes we don't though, and so we need to adjust the screen_rect, - * which will be used to draw the rendered texture. */ - screen_rect = *bounds; + /* Tweak the scale factor so that the required texture doesn't + * exceed the max texture limit. This will render with a lower + * resolution, but this is better than clipping. + */ + { + const int max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver); - new_clip = GSK_ROUNDED_RECT_INIT ((bounds->origin.x + dx) * scale_x, - (bounds->origin.y + dy) * scale_y, - width, height); + width = ceilf (width * scale_x); + if (width > max_texture_size) + { + scale_x *= (float)max_texture_size / width; + width = max_texture_size; + } - max_texture_size = gsk_gl_driver_get_max_texture_size (self->gl_driver); - if (!(flags & RESET_CLIP) && - G_UNLIKELY (width > max_texture_size || height > max_texture_size)) - { - /* If we are clipped to an acceptable size (lower than the texture max), then - * only draw that part. If not, scale the result down. */ - if (ops_has_clip (builder)) - { - graphene_rect_t transformed_bounds; - - flags |= RESET_CLIP; /* XXX HACK */ - - /* New clip is the intersection between the clip and the node bounds */ - ops_transform_bounds_modelview (builder, bounds, &transformed_bounds); - graphene_rect_intersection (&transformed_bounds, &builder->current_clip->bounds, &new_clip.bounds); - - width = new_clip.bounds.size.width; - height = new_clip.bounds.size.height; - - /* Un-transform sceen_rect as it will be transformed automatically later */ - screen_rect = new_clip.bounds; - screen_rect.origin.x -= (dx * scale_x); - screen_rect.origin.y -= (dy * scale_y); - screen_rect.origin.x /= scale_x; - screen_rect.origin.y /= scale_y; - screen_rect.size.width /= scale_x; - screen_rect.size.height /= scale_y; - - /* We do not add this to the cache as it is likely to quickly change in the - * future */ - add_to_cache = false; - } - else - { - /* As a last resort, scale everything down */ - if (width > max_texture_size) - { - scale_x *= (float)max_texture_size / width; - width = max_texture_size; - } - - if (height > max_texture_size) - { - scale_y *= (float)max_texture_size / height; - height = max_texture_size; - } - } - } + height = ceilf (height * scale_y); + if (height > max_texture_size) + { + scale_y *= (float)max_texture_size / height; + height = max_texture_size; + } + } gsk_gl_driver_create_render_target (self->gl_driver, width, height, @@ -3912,20 +3925,22 @@ add_offscreen_ops (GskGLRenderer *self, render_target); } - init_projection_matrix (&item_proj, &new_clip.bounds); + viewport = GRAPHENE_RECT_INIT (bounds->origin.x * scale_x, + bounds->origin.y * scale_y, + width, height); + init_projection_matrix (&item_proj, &viewport); prev_render_target = ops_set_render_target (builder, render_target); /* Clear since we use this rendertarget for the first time */ ops_begin (builder, OP_CLEAR); prev_projection = ops_set_projection (builder, &item_proj); ops_set_modelview (builder, gsk_transform_scale (NULL, scale_x, scale_y)); - prev_viewport = ops_set_viewport (builder, &new_clip.bounds); + prev_viewport = ops_set_viewport (builder, &viewport); if (flags & RESET_CLIP) - ops_push_clip (builder, &new_clip); + ops_push_clip (builder, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport)); - /* ops_set_modelview() resets the offset to 0, so restore it here. */ - builder->dx = dx; - builder->dy = dy; + builder->dx = 0; + builder->dy = 0; prev_opacity = ops_set_opacity (builder, 1.0); @@ -3936,16 +3951,19 @@ add_offscreen_ops (GskGLRenderer *self, { static int k; ops_dump_framebuffer (builder, - g_strdup_printf ("%d_%s_%p.png", - k++, + g_strdup_printf ("%s_%p_%d.png", g_type_name_from_instance ((GTypeInstance *) child_node), - child_node), + child_node, + k ++), width, height); } #endif ops_set_opacity (builder, prev_opacity); + builder->dx = dx; + builder->dy = dy; + if (flags & RESET_CLIP) ops_pop_clip (builder); @@ -3954,16 +3972,13 @@ add_offscreen_ops (GskGLRenderer *self, ops_set_projection (builder, &prev_projection); ops_set_render_target (builder, prev_render_target); - /*g_message ("offset after: %f, %f", builder->dx, builder->dy);*/ + *is_offscreen = TRUE; + init_full_texture_region (texture_region_out, texture_id); - result->is_offscreen = true; - result->screen_rect = screen_rect; - init_full_texture_region (&result->region, texture_id); - - if ((flags & NO_CACHE_PLZ) == 0 && add_to_cache) + if ((flags & NO_CACHE_PLZ) == 0) gsk_gl_driver_set_texture_for_key (self->gl_driver, &key, texture_id); - return true; + return TRUE; } static void