diff --git a/ChangeLog b/ChangeLog index c9fb6b038d..689749d2a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-02-16 Sven Neumann + + * app/base/pixel-processor.[ch]: added a variant of + pixel_regions_process_parallel() that takes a progress callback and + progress data. Does only work for the single-threaded case yet. + + * app/core/gimpdrawable-blend.c (gradient_fill_region): parallelized. + 2005-02-16 Sven Neumann * app/core/gimpimage-contiguous-region.c diff --git a/app/base/pixel-processor.c b/app/base/pixel-processor.c index 2c8180be07..61ec34493d 100644 --- a/app/base/pixel-processor.c +++ b/app/base/pixel-processor.c @@ -37,6 +37,10 @@ #include "tile.h" #endif + +#define PROGRESS_TIMEOUT 64 + + static gint max_threads = 0; @@ -60,17 +64,19 @@ typedef struct _PixelProcessor PixelProcessor; struct _PixelProcessor { - gpointer data; PixelProcessorFunc func; - PixelRegionIterator *PRI; + gpointer data; #ifdef ENABLE_MP GStaticMutex mutex; gint threads; #endif + PixelRegionIterator *PRI; gint num_regions; PixelRegion *regions[4]; + + gulong progress; }; @@ -98,6 +104,9 @@ do_parallel_regions (PixelProcessor *processor) do { + guint pixels = (processor->PRI->portion_width * + processor->PRI->portion_height); + for (i = 0; i < processor->num_regions; i++) if (processor->regions[i]) { @@ -141,18 +150,19 @@ do_parallel_regions (PixelProcessor *processor) g_warning ("do_parallel_regions: Bad number of regions %d\n", processor->num_regions); break; + } + + g_static_mutex_lock (&processor->mutex); + + for (i = 0; i < processor->num_regions; i++) + if (processor->regions[i]) + { + if (tr[i].tiles) + tile_release (tr[i].curtile, tr[i].dirty); + } + + processor->progress += pixels; } - - g_static_mutex_lock (&processor->mutex); - - for (i = 0; i < processor->num_regions; i++) - if (processor->regions[i]) - { - if (tr[i].tiles) - tile_release (tr[i].curtile, tr[i].dirty); - } - } - while (processor->PRI && (processor->PRI = pixel_regions_process (processor->PRI))); @@ -169,8 +179,16 @@ do_parallel_regions (PixelProcessor *processor) */ static gpointer -do_parallel_regions_single (PixelProcessor *processor) +do_parallel_regions_single (PixelProcessor *processor, + PixelProcessorProgressFunc progress_func, + gpointer progress_data, + gulong total) { + GTimeVal last_time; + + if (progress_func) + g_get_current_time (&last_time); + do { switch (processor->num_regions) @@ -205,8 +223,26 @@ do_parallel_regions_single (PixelProcessor *processor) g_warning ("do_parallel_regions_single: Bad number of regions %d\n", processor->num_regions); } - } + if (progress_func) + { + GTimeVal now; + + processor->progress += (processor->PRI->portion_width * + processor->PRI->portion_height); + + g_get_current_time (&now); + + if (((now.tv_sec - last_time.tv_sec) * 1024 + + (now.tv_usec - last_time.tv_usec) / 1024) > PROGRESS_TIMEOUT) + { + progress_func (progress_data, + (gdouble) processor->progress / (gdouble) total); + + last_time = now; + } + } + } while (processor->PRI && (processor->PRI = pixel_regions_process (processor->PRI))); @@ -217,11 +253,15 @@ do_parallel_regions_single (PixelProcessor *processor) #define TILES_PER_THREAD 8 static void -pixel_regions_do_parallel (PixelProcessor *processor) +pixel_regions_do_parallel (PixelProcessor *processor, + PixelProcessorProgressFunc progress_func, + gpointer progress_data) { + gulong pixels = (processor->PRI->region_width * + processor->PRI->region_height); + #ifdef ENABLE_MP - glong tiles = (processor->PRI->region_width * - processor->PRI->region_height) / (TILE_WIDTH * TILE_HEIGHT); + gulong tiles = pixels / (TILE_WIDTH * TILE_HEIGHT); if (max_threads > 1 && tiles > TILES_PER_THREAD) { @@ -255,15 +295,18 @@ pixel_regions_do_parallel (PixelProcessor *processor) else #endif { - do_parallel_regions_single (processor); + do_parallel_regions_single (processor, + progress_func, progress_data, pixels); } } static void -pixel_regions_process_parallel_valist (PixelProcessorFunc func, - gpointer data, - gint num_regions, - va_list ap) +pixel_regions_process_parallel_valist (PixelProcessorFunc func, + gpointer data, + PixelProcessorProgressFunc progress_func, + gpointer progress_data, + gint num_regions, + va_list ap) { PixelProcessor processor = { NULL, }; gint i; @@ -271,7 +314,7 @@ pixel_regions_process_parallel_valist (PixelProcessorFunc func, for (i = 0; i < num_regions; i++) processor.regions[i] = va_arg (ap, PixelRegion *); - switch(num_regions) + switch (num_regions) { case 1: processor.PRI = pixel_regions_register (num_regions, @@ -300,8 +343,8 @@ pixel_regions_process_parallel_valist (PixelProcessorFunc func, break; default: - g_warning ("pixel_regions_process_parallel:" - "Bad number of regions %d\n", processor.num_regions); + g_warning ("pixel_regions_process_parallel: " + "bad number of regions (%d)\n", processor.num_regions); } if (! processor.PRI) @@ -317,7 +360,9 @@ pixel_regions_process_parallel_valist (PixelProcessorFunc func, processor.threads = 0; #endif - pixel_regions_do_parallel (&processor); + processor.progress = 0; + + pixel_regions_do_parallel (&processor, progress_func, progress_data); } void @@ -332,6 +377,8 @@ pixel_processor_set_num_threads (gint num_threads) g_return_if_fail (num_threads > 0); max_threads = CLAMP (num_threads, 1, GIMP_MAX_NUM_THREADS); + + g_printerr ("max_threads: %d\n", max_threads); } void @@ -350,7 +397,28 @@ pixel_regions_process_parallel (PixelProcessorFunc func, va_start (va, num_regions); - pixel_regions_process_parallel_valist (func, data, num_regions, va); + pixel_regions_process_parallel_valist (func, data, + NULL, NULL, + num_regions, va); + + va_end (va); +} + +void +pixel_regions_process_parallel_progress (PixelProcessorFunc func, + gpointer data, + PixelProcessorProgressFunc progress_func, + gpointer progress_data, + gint num_regions, + ...) +{ + va_list va; + + va_start (va, num_regions); + + pixel_regions_process_parallel_valist (func, data, + progress_func, progress_data, + num_regions, va); va_end (va); } diff --git a/app/base/pixel-processor.h b/app/base/pixel-processor.h index 03ffcf3992..0ce33acd11 100644 --- a/app/base/pixel-processor.h +++ b/app/base/pixel-processor.h @@ -25,7 +25,9 @@ #define GIMP_MAX_NUM_THREADS 16 -typedef void (* PixelProcessorFunc) (void); +typedef void (* PixelProcessorFunc) (void); +typedef void (* PixelProcessorProgressFunc) (gpointer progress_data, + gdouble fraction); void pixel_processor_init (gint num_threads); @@ -37,5 +39,13 @@ void pixel_regions_process_parallel (PixelProcessorFunc func, gint num_regions, ...); +void pixel_regions_process_parallel_progress + (PixelProcessorFunc func, + gpointer data, + PixelProcessorProgressFunc progress_func, + gpointer progress_data, + gint num_regions, + ...); + #endif /* __PIXEL_PROCESSOR_H__ */ diff --git a/app/core/gimpdrawable-blend.c b/app/core/gimpdrawable-blend.c index 979b649a0f..e97f254f14 100644 --- a/app/core/gimpdrawable-blend.c +++ b/app/core/gimpdrawable-blend.c @@ -28,6 +28,7 @@ #include "core-types.h" +#include "base/pixel-processor.h" #include "base/pixel-region.h" #include "base/tile.h" #include "base/tile-manager.h" @@ -57,6 +58,7 @@ typedef struct gdouble dist; gdouble vec[2]; GimpRepeatMode repeat; + GRand *dither_rand; } RenderBlendData; typedef struct @@ -65,7 +67,6 @@ typedef struct guchar *row_data; gint bytes; gint width; - gboolean dither; GRand *dither_rand; } PutPixelData; @@ -150,6 +151,11 @@ static void gradient_fill_region (GimpImage *gimage, gdouble ey, GimpProgress *progress); +static void gradient_fill_single_region_rgb (RenderBlendData *rbd, + PixelRegion *PR); +static void gradient_fill_single_region_gray (RenderBlendData *rbd, + PixelRegion *PR); + /* variables for the shapeburst algs */ @@ -803,7 +809,7 @@ gradient_put_pixel (gint x, if (ppd->bytes >= 3) { - if (ppd->dither) + if (ppd->dither_rand) { gdouble dither_prob; gdouble ftmp; @@ -853,7 +859,7 @@ gradient_put_pixel (gint x, /* Convert to grayscale */ gdouble gray = gimp_rgb_intensity (color); - if (ppd->dither) + if (ppd->dither_rand) { gdouble dither_prob; gdouble ftmp; @@ -910,11 +916,6 @@ gradient_fill_region (GimpImage *gimage, GimpProgress *progress) { RenderBlendData rbd; - gint x, y; - gint endx, endy; - gpointer pr; - guchar *data; - GimpRGB color; GRand *dither_rand = NULL; rbd.gradient = gimp_context_get_gradient (context); @@ -1019,7 +1020,6 @@ gradient_fill_region (GimpImage *gimage, ppd.row_data = g_malloc (width * PR->bytes); ppd.bytes = PR->bytes; ppd.width = width; - ppd.dither = dither; ppd.dither_rand = dither_rand; gimp_adaptive_supersample_area (0, 0, (width - 1), (height - 1), @@ -1034,116 +1034,139 @@ gradient_fill_region (GimpImage *gimage, } else { - gint max_progress = PR->w * PR->h; - gint curr_progress = 0; + PixelProcessorFunc func; + PixelProcessorProgressFunc progress_func = NULL; - for (pr = pixel_regions_register (1, PR); - pr != NULL; - pr = pixel_regions_process (pr)) - { - data = PR->data; - endx = PR->x + PR->w; - endy = PR->y + PR->h; + rbd.dither_rand = dither_rand; - for (y = PR->y; y < endy; y++) - { - for (x = PR->x; x < endx; x++) - { - gradient_render_pixel (x, y, &color, &rbd); + if (PR->bytes >= 3) + func = (PixelProcessorFunc) gradient_fill_single_region_rgb; + else + func = (PixelProcessorFunc) gradient_fill_single_region_gray; - if (PR->bytes >= 3) - { - if (dither) - { - gdouble dither_prob; - gdouble ftmp; - gint itmp; + if (progress) + progress_func = (PixelProcessorProgressFunc) gimp_progress_set_value; - ftmp = color.r * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - color.r += (1.0 / 255.0); - - ftmp = color.g * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - color.g += (1.0 / 255.0); - - ftmp = color.b * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - color.b += (1.0 / 255.0); - - ftmp = color.a * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - color.a += (1.0 / 255.0); - - if (color.r > 1.0) color.r = 1.0; - if (color.g > 1.0) color.g = 1.0; - if (color.b > 1.0) color.b = 1.0; - if (color.a > 1.0) color.a = 1.0; - } - - *data++ = color.r * 255.0; - *data++ = color.g * 255.0; - *data++ = color.b * 255.0; - *data++ = color.a * 255.0; - } - else - { - /* Convert to grayscale */ - gdouble gray = gimp_rgb_intensity (&color); - - if (dither) - { - gdouble dither_prob; - gdouble ftmp; - gint itmp; - - ftmp = gray * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - gray += (1.0 / 255.0); - - ftmp = color.a * 255.0; - itmp = ftmp; - dither_prob = ftmp - itmp; - - if (g_rand_double (dither_rand) < dither_prob) - color.a += (1.0 / 255.0); - - if (gray > 1.0) gray = 1.0; - if (color.a > 1.0) color.a = 1.0; - } - - *data++ = gray * 255.0; - *data++ = color.a * 255.0; - } - } - } - - if (progress) - { - curr_progress += PR->w * PR->h; - - gimp_progress_set_value (progress, - (gdouble) curr_progress / - (gdouble) max_progress); - } - } + pixel_regions_process_parallel_progress (func, &rbd, + progress_func, progress, + 1, PR); } if (dither) g_rand_free (dither_rand); } + +static void +gradient_fill_single_region_rgb (RenderBlendData *rbd, + PixelRegion *PR) +{ + guchar *data = PR->data; + gint endx = PR->x + PR->w; + gint endy = PR->y + PR->h; + gint x, y; + + for (y = PR->y; y < endy; y++) + { + for (x = PR->x; x < endx; x++) + { + GimpRGB color; + + gradient_render_pixel (x, y, &color, rbd); + + if (rbd->dither_rand) + { + gdouble dither_prob; + gdouble ftmp; + gint itmp; + + ftmp = color.r * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + color.r += (1.0 / 255.0); + + ftmp = color.g * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + color.g += (1.0 / 255.0); + + ftmp = color.b * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + color.b += (1.0 / 255.0); + + ftmp = color.a * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + color.a += (1.0 / 255.0); + + if (color.r > 1.0) color.r = 1.0; + if (color.g > 1.0) color.g = 1.0; + if (color.b > 1.0) color.b = 1.0; + if (color.a > 1.0) color.a = 1.0; + } + + *data++ = color.r * 255.0; + *data++ = color.g * 255.0; + *data++ = color.b * 255.0; + *data++ = color.a * 255.0; + } + } +} + +static void +gradient_fill_single_region_gray (RenderBlendData *rbd, + PixelRegion *PR) +{ + guchar *data = PR->data; + gint endx = PR->x + PR->w; + gint endy = PR->y + PR->h; + gint x, y; + + for (y = PR->y; y < endy; y++) + { + for (x = PR->x; x < endx; x++) + { + GimpRGB color; + gdouble gray; + + gradient_render_pixel (x, y, &color, rbd); + + gray = gimp_rgb_intensity (&color); + + if (rbd->dither_rand) + { + gdouble dither_prob; + gdouble ftmp; + gint itmp; + + ftmp = gray * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + gray += (1.0 / 255.0); + + ftmp = color.a * 255.0; + itmp = ftmp; + dither_prob = ftmp - itmp; + + if (g_rand_double (rbd->dither_rand) < dither_prob) + color.a += (1.0 / 255.0); + + if (gray > 1.0) gray = 1.0; + if (color.a > 1.0) color.a = 1.0; + } + + *data++ = gray * 255.0; + *data++ = color.a * 255.0; + } + } +}