From 4336e2e52a5bd5dfdc31ccdf2e0594cf93b3ca90 Mon Sep 17 00:00:00 2001 From: Ell Date: Thu, 5 Apr 2018 17:30:51 -0400 Subject: [PATCH] app: parallelize gimpbrushcore-loops.cc Use gimp_parallel_distribute_foo() to parallelize the brush core loops. --- app/paint/gimpbrushcore-loops.cc | 204 +++++++++++++++++++------------ 1 file changed, 126 insertions(+), 78 deletions(-) diff --git a/app/paint/gimpbrushcore-loops.cc b/app/paint/gimpbrushcore-loops.cc index ef3cc069cf..87597e2016 100644 --- a/app/paint/gimpbrushcore-loops.cc +++ b/app/paint/gimpbrushcore-loops.cc @@ -27,6 +27,7 @@ extern "C" #include "paint-types.h" +#include "core/gimp-parallel.h" #include "core/gimptempbuf.h" #include "gimpbrushcore.h" @@ -34,6 +35,10 @@ extern "C" #include "gimpbrushcore-kernels.h" +#define MIN_PARALLEL_SUB_SIZE 64 +#define MIN_PARALLEL_SUB_AREA (MIN_PARALLEL_SUB_SIZE * MIN_PARALLEL_SUB_SIZE) + + static inline void rotate_pointers (gulong **p, guint32 n) @@ -55,34 +60,21 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core, gdouble x, gdouble y) { - GimpTempBuf *dest; - gdouble left; - const guchar *m; - guchar *d; - const gint *k; - gint index1; - gint index2; - gint dest_offset_x = 0; - gint dest_offset_y = 0; - const gint *kernel; - gint i, j; - gint r, s; - gulong *accum[KERNEL_HEIGHT]; - gint offs; - gint mask_width = gimp_temp_buf_get_width (mask); - gint mask_height = gimp_temp_buf_get_height (mask); - gint dest_width; - gint dest_height; - - while (x < 0) - x += mask_width; + GimpTempBuf *dest; + gdouble left; + gint index1; + gint index2; + gint dest_offset_x = 0; + gint dest_offset_y = 0; + const gint *kernel; + gint mask_width = gimp_temp_buf_get_width (mask); + gint mask_height = gimp_temp_buf_get_height (mask); + gint dest_width; + gint dest_height; left = x - floor (x); index1 = (gint) (left * (gdouble) (KERNEL_SUBSAMPLE + 1)); - while (y < 0) - y += mask_height; - left = y - floor (y); index2 = (gint) (left * (gdouble) (KERNEL_SUBSAMPLE + 1)); @@ -109,7 +101,6 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core, } } - kernel = subsample[index2][index1]; if (mask == core->last_subsample_brush_mask && @@ -120,6 +111,8 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core, } else { + gint i, j; + for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++) for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++) g_clear_pointer (&core->subsample_brushes[i][j], gimp_temp_buf_unref); @@ -136,51 +129,88 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core, dest_width = gimp_temp_buf_get_width (dest); dest_height = gimp_temp_buf_get_height (dest); - /* Allocate and initialize the accum buffer */ - for (i = 0; i < KERNEL_HEIGHT ; i++) - accum[i] = g_new0 (gulong, dest_width + 1); - core->subsample_brushes[index2][index1] = dest; - m = gimp_temp_buf_get_data (mask); - for (i = 0; i < mask_height; i++) + gimp_parallel_distribute_range (mask_height, MIN_PARALLEL_SUB_SIZE, + [=] (gint y, gint height) { - for (j = 0; j < mask_width; j++) + const guchar *m; + guchar *d; + const gint *k; + gint y0; + gint i, j; + gint r, s; + gint offs; + gulong *accum[KERNEL_HEIGHT]; + + /* Allocate and initialize the accum buffer */ + for (i = 0; i < KERNEL_HEIGHT ; i++) + accum[i] = g_new0 (gulong, dest_width + 1); + + y0 = MAX (y - (KERNEL_HEIGHT - 1), 0); + + m = gimp_temp_buf_get_data (mask) + y0 * mask_width; + + for (i = y0; i < y; i++) { - k = kernel; - for (r = 0; r < KERNEL_HEIGHT; r++) + for (j = 0; j < mask_width; j++) { - offs = j + dest_offset_x; - s = KERNEL_WIDTH; - while (s--) - accum[r][offs++] += *m * *k++; + k = kernel + KERNEL_WIDTH * (y - i); + for (r = y - i; r < KERNEL_HEIGHT; r++) + { + offs = j + dest_offset_x; + s = KERNEL_WIDTH; + while (s--) + accum[r][offs++] += *m * *k++; + } + m++; } - m++; + + rotate_pointers (accum, KERNEL_HEIGHT); } - /* store the accum buffer into the destination mask */ - d = gimp_temp_buf_get_data (dest) + (i + dest_offset_y) * dest_width; - for (j = 0; j < dest_width; j++) - *d++ = (accum[0][j] + 127) / KERNEL_SUM; + for (i = y; i < y + height; i++) + { + for (j = 0; j < mask_width; j++) + { + k = kernel; + for (r = 0; r < KERNEL_HEIGHT; r++) + { + offs = j + dest_offset_x; + s = KERNEL_WIDTH; + while (s--) + accum[r][offs++] += *m * *k++; + } + m++; + } - rotate_pointers (accum, KERNEL_HEIGHT); + /* store the accum buffer into the destination mask */ + d = gimp_temp_buf_get_data (dest) + (i + dest_offset_y) * dest_width; + for (j = 0; j < dest_width; j++) + *d++ = (accum[0][j] + 127) / KERNEL_SUM; - memset (accum[KERNEL_HEIGHT - 1], 0, sizeof (gulong) * dest_width); - } + rotate_pointers (accum, KERNEL_HEIGHT); - /* store the rest of the accum buffer into the dest mask */ - while (i + dest_offset_y < dest_height) - { - d = gimp_temp_buf_get_data (dest) + (i + dest_offset_y) * dest_width; - for (j = 0; j < dest_width; j++) - *d++ = (accum[0][j] + (KERNEL_SUM / 2)) / KERNEL_SUM; + memset (accum[KERNEL_HEIGHT - 1], 0, sizeof (gulong) * dest_width); + } - rotate_pointers (accum, KERNEL_HEIGHT); - i++; - } + if (y + height == mask_height) + { + /* store the rest of the accum buffer into the dest mask */ + while (i + dest_offset_y < dest_height) + { + d = gimp_temp_buf_get_data (dest) + (i + dest_offset_y) * dest_width; + for (j = 0; j < dest_width; j++) + *d++ = (accum[0][j] + (KERNEL_SUM / 2)) / KERNEL_SUM; - for (i = 0; i < KERNEL_HEIGHT ; i++) - g_free (accum[i]); + rotate_pointers (accum, KERNEL_HEIGHT); + i++; + } + } + + for (i = 0; i < KERNEL_HEIGHT ; i++) + g_free (accum[i]); + }); return dest; } @@ -195,8 +225,6 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core, gdouble pressure) { static guchar mapi[256]; - const guchar *source; - guchar *dest; const GimpTempBuf *subsample_mask; gint i; @@ -292,14 +320,21 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core, /* Now convert the brush */ - source = gimp_temp_buf_get_data (subsample_mask); - dest = gimp_temp_buf_get_data (core->pressure_brush); + gimp_parallel_distribute_range (gimp_temp_buf_get_width (subsample_mask) * + gimp_temp_buf_get_height (subsample_mask), + MIN_PARALLEL_SUB_AREA, + [=] (gint offset, gint size) + { + const guchar *source; + guchar *dest; + gint i; - i = gimp_temp_buf_get_width (subsample_mask) * - gimp_temp_buf_get_height (subsample_mask); + source = gimp_temp_buf_get_data (subsample_mask) + offset; + dest = gimp_temp_buf_get_data (core->pressure_brush) + offset; - while (i--) - *dest++ = mapi[(*source++)]; + for (i = 0; i < size; i++) + *dest++ = mapi[(*source++)]; + }); return core->pressure_brush; } @@ -311,13 +346,10 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core, gdouble y) { GimpTempBuf *dest; - const guchar *m; - gfloat *d; gint dest_offset_x = 0; gint dest_offset_y = 0; gint brush_mask_width = gimp_temp_buf_get_width (brush_mask); gint brush_mask_height = gimp_temp_buf_get_height (brush_mask); - gint i, j; if ((brush_mask_width % 2) == 0) { @@ -345,6 +377,8 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core, } else { + gint i, j; + for (i = 0; i < BRUSH_CORE_SOLID_SUBSAMPLE; i++) for (j = 0; j < BRUSH_CORE_SOLID_SUBSAMPLE; j++) g_clear_pointer (&core->solid_brushes[i][j], gimp_temp_buf_unref); @@ -360,18 +394,32 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core, core->solid_brushes[dest_offset_y][dest_offset_x] = dest; - m = gimp_temp_buf_get_data (brush_mask); - d = ((gfloat *) gimp_temp_buf_get_data (dest) + - ((dest_offset_y + 1) * gimp_temp_buf_get_width (dest) + - (dest_offset_x + 1))); - - for (i = 0; i < brush_mask_height; i++) + gimp_parallel_distribute_area (GEGL_RECTANGLE (0, + 0, + brush_mask_width, + brush_mask_height), + MIN_PARALLEL_SUB_AREA, + [=] (const GeglRectangle *area) { - for (j = 0; j < brush_mask_width; j++) - *d++ = (*m++) ? 1.0 : 0.0; + const guchar *m; + gfloat *d; + gint i, j; - d += 2; - } + m = gimp_temp_buf_get_data (brush_mask) + + area->y * brush_mask_width + area->x; + d = ((gfloat *) gimp_temp_buf_get_data (dest) + + ((dest_offset_y + 1 + area->y) * gimp_temp_buf_get_width (dest) + + (dest_offset_x + 1 + area->x))); + + for (i = 0; i < area->height; i++) + { + for (j = 0; j < area->width; j++) + *d++ = (*m++) ? 1.0 : 0.0; + + m += brush_mask_width - area->width; + d += brush_mask_width + 2 - area->width; + } + }); return dest; }