mirror of https://github.com/GNOME/gimp.git
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.
This commit is contained in:
parent
c20a8b732c
commit
d710e96d81
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue