added a variant of pixel_regions_process_parallel() that takes a progress

2005-02-16  Sven Neumann  <sven@gimp.org>

	* 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.
This commit is contained in:
Sven Neumann 2005-02-16 14:54:56 +00:00 committed by Sven Neumann
parent 6be469171d
commit 82a5329fbf
4 changed files with 251 additions and 142 deletions

View File

@ -1,3 +1,11 @@
2005-02-16 Sven Neumann <sven@gimp.org>
* 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 <sven@gimp.org>
* app/core/gimpimage-contiguous-region.c

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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;
}
}
}