Bug 681968 - Disabling 'Dot for Dot' glitches display

Enhance the existing but unused display scaling (hidpi/retina) support
to work independently in x and y direction, and adjust the scaling
factors accordingly when dot-for-dot is off and xres != yres.

Increase GIMP_DISPLAY_RENDER_MAX_SCALE from 2.0 to 4.0 and adjust the
rendering chunk size dynamically so we never render chunks that do
not fit into the GimpDisplayXfer buffers.
This commit is contained in:
Michael Natterer
2014-04-20 18:06:52 +02:00
parent 1a674374d3
commit 051a3e4af4
3 changed files with 82 additions and 44 deletions

View File

@ -137,6 +137,8 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
{
gint x1, y1, x2, y2;
gint i, j;
gint chunk_width;
gint chunk_height;
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (gimp_display_get_image (shell->display));
@ -180,14 +182,28 @@ gimp_display_shell_draw_image (GimpDisplayShell *shell,
/* display the image in RENDER_BUF_WIDTH x RENDER_BUF_HEIGHT
* sized chunks
*/
for (i = y1; i < y2; i += GIMP_DISPLAY_RENDER_BUF_HEIGHT)
chunk_width = GIMP_DISPLAY_RENDER_BUF_WIDTH;
chunk_height = GIMP_DISPLAY_RENDER_BUF_HEIGHT;
if ((shell->scale_x / shell->scale_y) > 2.0)
{
for (j = x1; j < x2; j += GIMP_DISPLAY_RENDER_BUF_WIDTH)
while ((chunk_width / chunk_height) < (shell->scale_x / shell->scale_y))
chunk_height /= 2;
}
else if ((shell->scale_y / shell->scale_x) > 2.0)
{
while ((chunk_height / chunk_width) < (shell->scale_y / shell->scale_x))
chunk_width /= 2;
}
for (i = y1; i < y2; i += chunk_height)
{
for (j = x1; j < x2; j += chunk_width)
{
gint dx, dy;
dx = MIN (x2 - j, GIMP_DISPLAY_RENDER_BUF_WIDTH);
dy = MIN (y2 - i, GIMP_DISPLAY_RENDER_BUF_HEIGHT);
dx = MIN (x2 - j, chunk_width);
dy = MIN (y2 - i, chunk_height);
gimp_display_shell_render (shell, cr, j, i, dx, dy);
}

View File

@ -20,6 +20,7 @@
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpwidgets/gimpwidgets.h"
@ -44,6 +45,9 @@
#include "gimpdisplayxfer.h"
/* #define GIMP_DISPLAY_RENDER_ENABLE_SCALING 1 */
void
gimp_display_shell_render (GimpDisplayShell *shell,
cairo_t *cr,
@ -55,11 +59,17 @@ gimp_display_shell_render (GimpDisplayShell *shell,
GimpImage *image;
GimpProjection *projection;
GeglBuffer *buffer;
gdouble window_scale = 1.0;
gdouble scale_x = 1.0;
gdouble scale_y = 1.0;
gdouble buffer_scale = 1.0;
gint viewport_offset_x;
gint viewport_offset_y;
gint viewport_width;
gint viewport_height;
gint scaled_x;
gint scaled_y;
gint scaled_width;
gint scaled_height;
cairo_surface_t *xfer;
gint xfer_src_x;
gint xfer_src_y;
@ -78,22 +88,46 @@ gimp_display_shell_render (GimpDisplayShell *shell,
#ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
/* if we had this future API, things would look pretty on hires (retina) */
window_scale = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell))));
#endif
window_scale = MIN (window_scale, GIMP_DISPLAY_RENDER_MAX_SCALE);
scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE);
scale_y = scale_x;
if (shell->scale_x > shell->scale_y)
{
scale_y *= (shell->scale_x / shell->scale_y);
buffer_scale = shell->scale_y * scale_y;
}
else if (shell->scale_y > shell->scale_x)
{
scale_x *= (shell->scale_y / shell->scale_x);
buffer_scale = shell->scale_x * scale_x;
}
else
{
buffer_scale = shell->scale_x * scale_x;
}
gimp_display_shell_scroll_get_scaled_viewport (shell,
&viewport_offset_x,
&viewport_offset_y,
&viewport_width,
&viewport_height);
scaled_x = floor ((x + viewport_offset_x) * scale_x);
scaled_y = floor ((y + viewport_offset_y) * scale_y);
scaled_width = ceil (w * scale_x);
scaled_height = ceil (h * scale_y);
if (shell->rotate_transform)
{
xfer = cairo_surface_create_similar_image (cairo_get_target (cr),
CAIRO_FORMAT_ARGB32,
w * window_scale,
h * window_scale);
scaled_width,
scaled_height);
cairo_surface_mark_dirty (xfer);
xfer_src_x = 0;
xfer_src_y = 0;
@ -101,8 +135,8 @@ gimp_display_shell_render (GimpDisplayShell *shell,
else
{
xfer = gimp_display_xfer_get_surface (shell->xfer,
w * window_scale,
h * window_scale,
scaled_width,
scaled_height,
&xfer_src_x,
&xfer_src_y);
}
@ -136,11 +170,9 @@ gimp_display_shell_render (GimpDisplayShell *shell,
}
gegl_buffer_get (buffer,
GEGL_RECTANGLE ((x + viewport_offset_x) * window_scale,
(y + viewport_offset_y) * window_scale,
w * window_scale,
h * window_scale),
shell->scale_x * window_scale,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
buffer_scale,
filter_format, shell->filter_data,
shell->filter_stride, GEGL_ABYSS_CLAMP);
@ -148,13 +180,13 @@ gimp_display_shell_render (GimpDisplayShell *shell,
gimp_color_display_stack_convert_buffer (shell->filter_stack,
shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
w * window_scale,
h * window_scale));
scaled_width,
scaled_height));
gegl_buffer_get (shell->filter_buffer,
GEGL_RECTANGLE (0, 0,
w * window_scale,
h * window_scale),
scaled_width,
scaled_height),
1.0,
babl_format ("cairo-ARGB32"),
data, stride,
@ -163,11 +195,9 @@ gimp_display_shell_render (GimpDisplayShell *shell,
else
{
gegl_buffer_get (buffer,
GEGL_RECTANGLE ((x + viewport_offset_x) * window_scale,
(y + viewport_offset_y) * window_scale,
w * window_scale,
h * window_scale),
shell->scale_x * window_scale,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
buffer_scale,
babl_format ("cairo-ARGB32"),
data, stride,
GEGL_ABYSS_CLAMP);
@ -194,20 +224,18 @@ gimp_display_shell_render (GimpDisplayShell *shell,
data += mask_src_y * stride + mask_src_x * 4;
gegl_buffer_get (shell->mask,
GEGL_RECTANGLE ((x + viewport_offset_x) * window_scale,
(y + viewport_offset_y) * window_scale,
w * window_scale,
h * window_scale),
shell->scale_x * window_scale,
GEGL_RECTANGLE (scaled_x, scaled_y,
scaled_width, scaled_height),
buffer_scale,
babl_format ("Y u8"),
data, stride,
GEGL_ABYSS_CLAMP);
/* invert the mask so what is *not* the foreground object is masked */
mask_height = h * window_scale;
mask_height = scaled_height;
while (mask_height--)
{
gint mask_width = w * window_scale;
gint mask_width = scaled_width;
guchar *d = data;
while (mask_width--)
@ -226,11 +254,11 @@ gimp_display_shell_render (GimpDisplayShell *shell,
cairo_rectangle (cr, x, y, w, h);
cairo_scale (cr, 1.0 / window_scale, 1.0 / window_scale);
cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y);
cairo_set_source_surface (cr, xfer,
(x - xfer_src_x) * window_scale,
(y - xfer_src_y) * window_scale);
x * scale_x - xfer_src_x,
y * scale_y - xfer_src_y);
if (shell->rotate_transform)
{
@ -252,8 +280,8 @@ gimp_display_shell_render (GimpDisplayShell *shell,
{
gimp_cairo_set_source_rgba (cr, &shell->mask_color);
cairo_mask_surface (cr, shell->mask_surface,
(x - mask_src_x) * window_scale,
(y - mask_src_y) * window_scale);
(x - mask_src_x) * scale_x,
(y - mask_src_y) * scale_y);
}
cairo_restore (cr);

View File

@ -19,16 +19,10 @@
#define __GIMP_DISPLAY_XFER_H__
/* #define GIMP_DISPLAY_RENDER_ENABLE_SCALING 1 */
#define GIMP_DISPLAY_RENDER_BUF_WIDTH 256
#define GIMP_DISPLAY_RENDER_BUF_HEIGHT 256
#ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING
#define GIMP_DISPLAY_RENDER_MAX_SCALE 2.0
#else
#define GIMP_DISPLAY_RENDER_MAX_SCALE 1.0
#endif
#define GIMP_DISPLAY_RENDER_MAX_SCALE 4.0
GimpDisplayXfer * gimp_display_xfer_realize (GtkWidget *widget);