Commit d710e96d authored by Ell's avatar Ell

Issue #3781 - Display artifacts on HiDPI when render cache is invalidated

In GimpDisplayShell, scale the render cache by the window's scale
factor, and render its content in device pixels, instead of scaled
application pixels.  When painting the cache to the screen, unscale
the cairo context by the same factor, so that it's painted in the
native resolution.  Note that the various
gimp_display_shell_render_foo() functions still speak in
application pixels, and the scaling happens internally in
gimp_display_shell_render().

Aside from rendering at native resolution on HiDPI, this also fixes
an issue where grid-like display artifacts would appear when the
render cache was not fully validated due to the non-native scaling.
parent c20a8b73
Pipeline #114088 passed with stages
in 14 minutes and 7 seconds
......@@ -97,6 +97,11 @@ gimp_display_shell_canvas_realize (GtkWidget *canvas,
shell->disp_width = allocation.width;
shell->disp_height = allocation.height;
gimp_display_shell_render_set_scale (
shell,
gdk_window_get_scale_factor (
gtk_widget_get_window (gtk_widget_get_toplevel (canvas))));
/* set up the scrollbar observers */
g_signal_connect (shell->hsbdata, "value-changed",
G_CALLBACK (gimp_display_shell_hadjustment_changed),
......
......@@ -163,17 +163,12 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
chunk_width = shell->render_buf_width;
chunk_height = shell->render_buf_height;
#ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
/* multiply the image scale-factor by the window scale-factor, and divide
* the cairo scale-factor by the same amount (further down), so that we make
* full use of the screen resolution, even on hidpi displays.
*/
scale *=
gdk_window_get_scale_factor (
gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
#endif
scale *= shell->render_scale;
scale = MIN (scale, GIMP_DISPLAY_RENDER_MAX_SCALE);
scale *= MAX (shell->scale_x, shell->scale_y);
if (scale != shell->scale_x)
......@@ -221,6 +216,13 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
x1, y1, x2 - x1, y2 - y1);
}
/* divide the cairo scale-factor by the window scale-factor, since
* the render cache uses device pixels. see comment further up.
*/
cairo_scale (cr,
1.0 / shell->render_scale,
1.0 / shell->render_scale);
/* render from the render cache to screen */
cairo_set_source_surface (cr, shell->render_cache, 0, 0);
cairo_paint (cr);
......
......@@ -40,6 +40,28 @@
#include "gimpdisplayshell-render.h"
#define GIMP_DISPLAY_RENDER_ENABLE_SCALING 1
#define GIMP_DISPLAY_RENDER_MAX_SCALE 4
void
gimp_display_shell_render_set_scale (GimpDisplayShell *shell,
gint scale)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
#if GIMP_DISPLAY_RENDER_ENABLE_SCALING
scale = CLAMP (scale, 1, GIMP_DISPLAY_RENDER_MAX_SCALE);
if (scale != shell->render_scale)
{
shell->render_scale = scale;
gimp_display_shell_render_invalidate_full (shell);
}
#endif
}
void
gimp_display_shell_render_invalidate_full (GimpDisplayShell *shell)
{
......@@ -165,6 +187,11 @@ gimp_display_shell_render (GimpDisplayShell *shell,
g_return_if_fail (width > 0 && width <= shell->render_buf_width);
g_return_if_fail (height > 0 && height <= shell->render_buf_height);
tx *= shell->render_scale;
ty *= shell->render_scale;
twidth *= shell->render_scale;
theight *= shell->render_scale;
display_config = shell->display->config;
if (shell->show_all)
......@@ -199,11 +226,11 @@ gimp_display_shell_render (GimpDisplayShell *shell,
if (! shell->render_cache)
{
shell->render_cache =
cairo_surface_create_similar_image (cairo_get_target (cr),
CAIRO_FORMAT_ARGB32,
shell->disp_width,
shell->disp_height);
shell->render_cache = cairo_surface_create_similar_image (
cairo_get_target (cr),
CAIRO_FORMAT_ARGB32,
shell->disp_width * shell->render_scale,
shell->disp_height * shell->render_scale);
}
if (! shell->render_cache_valid)
......@@ -218,6 +245,7 @@ gimp_display_shell_render (GimpDisplayShell *shell,
cairo_clip (my_cr);
/* transform to scaled image space, and apply uneven scaling */
cairo_scale (my_cr, shell->render_scale, shell->render_scale);
if (shell->rotate_transform)
cairo_transform (my_cr, shell->rotate_transform);
cairo_translate (my_cr, -shell->offset_x, -shell->offset_y);
......
......@@ -19,9 +19,8 @@
#define __GIMP_DISPLAY_SHELL_RENDER_H__
#define GIMP_DISPLAY_RENDER_ENABLE_SCALING 1
#define GIMP_DISPLAY_RENDER_MAX_SCALE 4.0
void gimp_display_shell_render_set_scale (GimpDisplayShell *shell,
gint scale);
void gimp_display_shell_render_invalidate_full (GimpDisplayShell *shell);
void gimp_display_shell_render_invalidate_area (GimpDisplayShell *shell,
......
......@@ -100,11 +100,11 @@ gimp_display_shell_scroll (GimpDisplayShell *shell,
cairo_surface_t *surface;
cairo_t *cr;
surface =
cairo_surface_create_similar_image (shell->render_cache,
CAIRO_FORMAT_ARGB32,
shell->disp_width,
shell->disp_height);
surface = cairo_surface_create_similar_image (
shell->render_cache,
CAIRO_FORMAT_ARGB32,
shell->disp_width * shell->render_scale,
shell->disp_height * shell->render_scale);
cr = cairo_create (surface);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
......@@ -115,7 +115,8 @@ gimp_display_shell_scroll (GimpDisplayShell *shell,
cr = cairo_create (shell->render_cache);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, surface,
-x_offset, -y_offset);
-x_offset * shell->render_scale,
-y_offset * shell->render_scale);
cairo_paint (cr);
cairo_destroy (cr);
......
......@@ -345,6 +345,8 @@ gimp_display_shell_init (GimpDisplayShell *shell)
shell->filter_profile = gimp_babl_get_builtin_color_profile (GIMP_RGB,
GIMP_TRC_NON_LINEAR);
shell->render_scale = 1;
shell->render_buf_width = 256;
shell->render_buf_height = 256;
......
......@@ -171,6 +171,8 @@ struct _GimpDisplayShell
guchar *filter_data; /* filter_buffer's pixels */
gint filter_stride; /* filter_buffer's stride */
gint render_scale;
cairo_surface_t *render_cache;
cairo_region_t *render_cache_valid;
......
......@@ -71,6 +71,8 @@
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-appearance.h"
#include "gimpdisplayshell-close.h"
#include "gimpdisplayshell-expose.h"
#include "gimpdisplayshell-render.h"
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
#include "gimpdisplayshell-tool-events.h"
......@@ -137,6 +139,8 @@ struct _GimpImageWindowPrivate
GdkMonitor *initial_monitor;
gint scale_factor;
gint suspend_keep_pos;
gint update_ui_manager_idle_id;
......@@ -636,10 +640,12 @@ static gboolean
gimp_image_window_configure_event (GtkWidget *widget,
GdkEventConfigure *event)
{
GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
GtkAllocation allocation;
gint current_width;
gint current_height;
GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
GtkAllocation allocation;
gint current_width;
gint current_height;
gint scale_factor;
gtk_widget_get_allocation (widget, &allocation);
......@@ -664,6 +670,23 @@ gimp_image_window_configure_event (GtkWidget *widget,
shell->size_allocate_from_configure_event = TRUE;
}
scale_factor = gdk_window_get_scale_factor (gtk_widget_get_window (widget));
if (scale_factor != private->scale_factor)
{
GList *list;
private->scale_factor = scale_factor;
for (list = private->shells; list; list = g_list_next (list))
{
GimpDisplayShell *shell = list->data;
gimp_display_shell_render_set_scale (shell, scale_factor);
gimp_display_shell_expose_full (shell);
}
}
return TRUE;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment