diff options
author | Matthias Clasen <mclasen@redhat.com> | 2023-05-01 13:39:23 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2023-05-01 13:43:33 -0400 |
commit | d9a2b74b4a16c0dbe70a71d1c84d4f08de20f3a3 (patch) | |
tree | 70c04ef04c64c9833f7061845aa0cdc302e72db7 /gsk | |
parent | 21df62f4287cea0f9264228a5d5afe1237425369 (diff) | |
download | gtk+-d9a2b74b4a16c0dbe70a71d1c84d4f08de20f3a3.tar.gz |
gsk: More fixes
Work towards handling negative scales and
denormalized rects everywhere.
Diffstat (limited to 'gsk')
-rw-r--r-- | gsk/gl/gskglrenderjob.c | 161 |
1 files changed, 100 insertions, 61 deletions
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index ec42a0a8a7..01fa435413 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -918,47 +918,64 @@ gsk_gl_render_job_untransform_bounds (GskGLRenderJob *job, } static inline void -gsk_gl_render_job_transform_rounded_rect (GskGLRenderJob *job, +gsk_gl_render_job_translate_rounded_rect (GskGLRenderJob *job, const GskRoundedRect *rect, - GskRoundedRect *out) -{ - float scale_x = job->scale_x; - float scale_y = job->scale_y; - - gsk_gl_render_job_transform_bounds (job, &rect->bounds, &out->bounds); + GskRoundedRect *out_rect) + { + out_rect->bounds.origin.x = job->offset_x + rect->bounds.origin.x; + out_rect->bounds.origin.y = job->offset_y + rect->bounds.origin.y; + out_rect->bounds.size.width = rect->bounds.size.width; + out_rect->bounds.size.height = rect->bounds.size.height; + memcpy (out_rect->corner, rect->corner, sizeof rect->corner); +} - for (guint i = 0; i < G_N_ELEMENTS (out->corner); i++) +static inline void +rounded_rect_scale_corners (const GskRoundedRect *rect, + GskRoundedRect *out_rect, + float scale_x, + float scale_y) +{ + for (guint i = 0; i < G_N_ELEMENTS (out_rect->corner); i++) { - out->corner[i].width = rect->corner[i].width * fabs (scale_x); - out->corner[i].height = rect->corner[i].height * fabs (scale_y); + out_rect->corner[i].width = rect->corner[i].width * fabs (scale_x); + out_rect->corner[i].height = rect->corner[i].height * fabs (scale_y); } if (scale_x < 0) { graphene_size_t p; - p = out->corner[GSK_CORNER_TOP_LEFT]; - out->corner[GSK_CORNER_TOP_LEFT] = out->corner[GSK_CORNER_TOP_RIGHT]; - out->corner[GSK_CORNER_TOP_RIGHT] = p; - p = out->corner[GSK_CORNER_BOTTOM_LEFT]; - out->corner[GSK_CORNER_BOTTOM_LEFT] = out->corner[GSK_CORNER_BOTTOM_RIGHT]; - out->corner[GSK_CORNER_BOTTOM_RIGHT] = p; + p = out_rect->corner[GSK_CORNER_TOP_LEFT]; + out_rect->corner[GSK_CORNER_TOP_LEFT] = out_rect->corner[GSK_CORNER_TOP_RIGHT]; + out_rect->corner[GSK_CORNER_TOP_RIGHT] = p; + p = out_rect->corner[GSK_CORNER_BOTTOM_LEFT]; + out_rect->corner[GSK_CORNER_BOTTOM_LEFT] = out_rect->corner[GSK_CORNER_BOTTOM_RIGHT]; + out_rect->corner[GSK_CORNER_BOTTOM_RIGHT] = p; } if (scale_y < 0) { graphene_size_t p; - p = out->corner[GSK_CORNER_TOP_LEFT]; - out->corner[GSK_CORNER_TOP_LEFT] = out->corner[GSK_CORNER_BOTTOM_LEFT]; - out->corner[GSK_CORNER_BOTTOM_LEFT] = p; - p = out->corner[GSK_CORNER_TOP_RIGHT]; - out->corner[GSK_CORNER_TOP_RIGHT] = out->corner[GSK_CORNER_BOTTOM_RIGHT]; - out->corner[GSK_CORNER_BOTTOM_RIGHT] = p; + p = out_rect->corner[GSK_CORNER_TOP_LEFT]; + out_rect->corner[GSK_CORNER_TOP_LEFT] = out_rect->corner[GSK_CORNER_BOTTOM_LEFT]; + out_rect->corner[GSK_CORNER_BOTTOM_LEFT] = p; + p = out_rect->corner[GSK_CORNER_TOP_RIGHT]; + out_rect->corner[GSK_CORNER_TOP_RIGHT] = out_rect->corner[GSK_CORNER_BOTTOM_RIGHT]; + out_rect->corner[GSK_CORNER_BOTTOM_RIGHT] = p; } } static inline void +gsk_gl_render_job_transform_rounded_rect (GskGLRenderJob *job, + const GskRoundedRect *rect, + GskRoundedRect *out_rect) +{ + gsk_gl_render_job_transform_bounds (job, &rect->bounds, &out_rect->bounds); + rounded_rect_scale_corners (rect, out_rect, job->scale_x, job->scale_y); +} + +static inline void rounded_rect_get_inner (const GskRoundedRect *rect, graphene_rect_t *inner) { @@ -1260,13 +1277,12 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, { float scale_x = job->scale_x; float scale_y = job->scale_y; - int surface_width = ceilf (node->bounds.size.width * scale_x); - int surface_height = ceilf (node->bounds.size.height * scale_y); + int surface_width = ceilf (node->bounds.size.width * fabs (scale_x)); + int surface_height = ceilf (node->bounds.size.height * fabs (scale_y)); GdkTexture *texture; cairo_surface_t *surface; cairo_surface_t *rendered_surface; cairo_t *cr; - int cached_id; int texture_id; GskTextureKey key; @@ -1278,18 +1294,10 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, key.scale_x = scale_x; key.scale_y = scale_y; - cached_id = gsk_gl_driver_lookup_texture (job->driver, &key); + texture_id = gsk_gl_driver_lookup_texture (job->driver, &key); - if (cached_id != 0) - { - gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)); - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, GL_TEXTURE0, cached_id); - gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - return; - } + if (texture_id != 0) + goto done; /* We first draw the recording surface on an image surface, * just because the scaleY(-1) later otherwise screws up the @@ -1299,7 +1307,7 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, surface_width, surface_height); - cairo_surface_set_device_scale (rendered_surface, scale_x, scale_y); + cairo_surface_set_device_scale (rendered_surface, fabs (scale_x), fabs (scale_y)); cr = cairo_create (rendered_surface); cairo_save (cr); @@ -1313,15 +1321,16 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, surface_width, surface_height); - cairo_surface_set_device_scale (surface, scale_x, scale_y); + cairo_surface_set_device_scale (surface, fabs (scale_x), fabs (scale_y)); cr = cairo_create (surface); /* We draw upside down here, so it matches what GL does. */ cairo_save (cr); - cairo_scale (cr, 1, -1); - cairo_translate (cr, 0, - surface_height / scale_y); + cairo_scale (cr, scale_x < 0 ? -1 : 1, scale_y < 0 ? 1 : -1); + cairo_translate (cr, scale_x < 0 ? - surface_width / fabs (scale_x) : 0, + scale_y < 0 ? 0 : - surface_height / fabs (scale_y)); cairo_set_source_surface (cr, rendered_surface, 0, 0); - cairo_rectangle (cr, 0, 0, surface_width / scale_x, surface_height / scale_y); + cairo_rectangle (cr, 0, 0, surface_width / fabs (scale_x), surface_height / fabs (scale_y)); cairo_fill (cr); cairo_restore (cr); @@ -1360,6 +1369,16 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, gsk_gl_driver_cache_texture (job->driver, &key, texture_id); +done: + if (scale_x < 0 || scale_y < 0) + { + GskTransform *transform = gsk_transform_translate (NULL, + &GRAPHENE_POINT_INIT (scale_x < 0 ? - surface_width : 0, + scale_y < 0 ? - surface_height : 0)); + gsk_gl_render_job_push_modelview (job, transform); + gsk_transform_unref (transform); + } + gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)); gsk_gl_program_set_uniform_texture (job->current_program, UNIFORM_SHARED_SOURCE, 0, @@ -1368,6 +1387,9 @@ gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, texture_id); gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); gsk_gl_render_job_end_draw (job); + + if (scale_x < 0 || scale_y < 0) + gsk_gl_render_job_pop_modelview (job); } static guint @@ -1522,10 +1544,10 @@ blur_node (GskGLRenderJob *job, offscreen->texture_id = blur_offscreen (job, offscreen, - texture_width * scale_x, - texture_height * scale_y, - blur_radius * scale_x, - blur_radius * scale_y); + texture_width * fabs (scale_x), + texture_height * fabs (scale_y), + blur_radius * fabs (scale_x), + blur_radius * fabs (scale_y)); init_full_texture_region (offscreen); } @@ -1935,7 +1957,7 @@ gsk_gl_render_job_visit_border_node (GskGLRenderJob *job, sizes[3].w = MAX (widths[3], rounded_outline->corner[3].width); } - gsk_gl_render_job_transform_rounded_rect (job, rounded_outline, &outline); + gsk_gl_render_job_translate_rounded_rect (job, rounded_outline, &outline); gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, border)); @@ -2039,7 +2061,7 @@ gsk_gl_render_job_visit_css_background (GskGLRenderJob *job, rgba_to_half (&gsk_border_node_get_colors (node2)[0], color); rgba_to_half (gsk_color_node_get_color (child), color2); - gsk_gl_render_job_transform_rounded_rect (job, rounded_outline, &outline); + gsk_gl_render_job_translate_rounded_rect (job, rounded_outline, &outline); gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, filled_border)); @@ -2180,6 +2202,7 @@ gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job, scale = gsk_transform_translate (gsk_transform_scale (NULL, sx, sy), &GRAPHENE_POINT_INIT (tx, ty)); gsk_gl_render_job_push_modelview (job, scale); transform = gsk_transform_transform (gsk_transform_invert (scale), transform); + gsk_transform_unref (scale); } } @@ -2230,7 +2253,7 @@ gsk_gl_render_job_visit_unblurred_inset_shadow_node (GskGLRenderJob *job, GskRoundedRect transformed_outline; guint16 color[4]; - gsk_gl_render_job_transform_rounded_rect (job, outline, &transformed_outline); + gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow)); gsk_gl_program_set_uniform_rounded_rect (job->current_program, @@ -2330,7 +2353,7 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job, prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id); gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - gsk_gl_render_job_transform_rounded_rect (job, &outline_to_blur, &transformed_outline); + gsk_gl_render_job_translate_rounded_rect (job, &outline_to_blur, &transformed_outline); /* Actual inset shadow outline drawing */ gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow)); @@ -2363,8 +2386,8 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job, &offscreen, texture_width, texture_height, - blur_radius * scale_x, - blur_radius * scale_y); + blur_radius * fabs (scale_x), + blur_radius * fabs (scale_y)); gsk_gl_driver_release_render_target (job->driver, render_target, TRUE); @@ -2386,7 +2409,7 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job, { GskRoundedRect node_clip; - gsk_gl_render_job_transform_rounded_rect (job, node_outline, &node_clip); + gsk_gl_render_job_translate_rounded_rect (job, node_outline, &node_clip); gsk_gl_render_job_push_clip (job, &node_clip); } @@ -2436,7 +2459,7 @@ gsk_gl_render_job_visit_unblurred_outset_shadow_node (GskGLRenderJob *job, rgba_to_half (gsk_outset_shadow_node_get_color (node), color); - gsk_gl_render_job_transform_rounded_rect (job, outline, &transformed_outline); + gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, unblurred_outset_shadow)); gsk_gl_program_set_uniform_rounded_rect (job->current_program, @@ -2629,8 +2652,8 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job, &offscreen, texture_width, texture_height, - blur_radius * scale_x, - blur_radius * scale_y); + blur_radius * fabs (scale_x), + blur_radius * fabs (scale_y)); gsk_gl_shadow_library_insert (job->driver->shadows_library, &scaled_outline, @@ -2644,7 +2667,7 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job, blurred_texture_id = cached_tid; } - gsk_gl_render_job_transform_rounded_rect (job, outline, &transformed_outline); + gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); if (!do_slicing) { @@ -3601,8 +3624,8 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job, float scale_y = bounds->size.height / texture->height; gboolean use_mipmap; - use_mipmap = (scale_x * job->scale_x) < 0.5 || - (scale_y * job->scale_y) < 0.5; + use_mipmap = (scale_x * fabs (job->scale_x)) < 0.5 || + (scale_y * fabs (job->scale_y)) < 0.5; if G_LIKELY (texture->width <= max_texture_size && texture->height <= max_texture_size) @@ -4134,7 +4157,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, } if (gsk_render_node_get_node_type (node) == GSK_TEXTURE_NODE && - offscreen->force_offscreen == FALSE) + !offscreen->force_offscreen) { GdkTexture *texture = gsk_texture_node_get_texture (node); gsk_gl_render_job_upload_texture (job, texture, FALSE, offscreen); @@ -4152,6 +4175,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, gboolean flipped_x = job->scale_x < 0; gboolean flipped_y = job->scale_y < 0; graphene_rect_t viewport; + gboolean reset_clip = FALSE; if (flipped_x || flipped_y) { @@ -4199,6 +4223,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, gsk_gl_render_job_push_modelview (job, transform); gsk_transform_unref (transform); gsk_gl_render_job_transform_bounds (job, offscreen->bounds, &viewport); + graphene_rect_scale (&viewport, downscale_x, downscale_y, &viewport); } if (downscale_x == 1) @@ -4282,11 +4307,25 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); if (offscreen->reset_clip) - gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (job->viewport)); + { + gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (job->viewport)); + reset_clip = TRUE; + } + else if (flipped_x || flipped_y || downscale_x != 1 || downscale_y != 1) + { + GskRoundedRect new_clip; + float scale_x = flipped_x ? - downscale_x : downscale_x; + float scale_y = flipped_y ? - downscale_y : downscale_y; + + graphene_rect_scale (&job->current_clip->rect.bounds, scale_x, scale_y, &new_clip.bounds); + rounded_rect_scale_corners (&job->current_clip->rect, &new_clip, scale_x, scale_y); + gsk_gl_render_job_push_clip (job, &new_clip); + reset_clip = TRUE; + } gsk_gl_render_job_visit_node (job, node); - if (offscreen->reset_clip) + if (reset_clip) gsk_gl_render_job_pop_clip (job); if (downscale_x != 1 || downscale_y != 1) |