[Rawstudio-commit] r2203 - trunk/plugins/resample
Anders Brander
anders at brander.dk
Sat Feb 14 20:09:09 CET 2009
Author: abrander
Date: 2009-02-14 20:09:09 +0100 (Sat, 14 Feb 2009)
New Revision: 2203
Modified:
trunk/plugins/resample/resample.c
Log:
Made RSResample threaded (Patch by Klaus Post).
Modified: trunk/plugins/resample/resample.c
===================================================================
--- trunk/plugins/resample/resample.c 2009-02-14 11:49:20 UTC (rev 2202)
+++ trunk/plugins/resample/resample.c 2009-02-14 19:09:09 UTC (rev 2203)
@@ -41,6 +41,19 @@
RSFilterClass parent_class;
};
+typedef struct {
+ RS_IMAGE16 *input; /* Input Image to Resampler */
+ RS_IMAGE16 *output; /* Output Image from Resampler */
+ guint old_size; /* Old dimension in the direction of the resampler*/
+ guint new_size; /* New size in the direction of the resampler */
+ guint dest_offset_other; /* Where in the unchanged direction should we begin writing? */
+ guint dest_end_other; /* Where in the unchanged direction should we stop writing? */
+ guint (*resample_support)();
+ gdouble (*resample_func)(gdouble);
+ GThread *threadid;
+ gboolean use_compatible;
+} ResampleInfo;
+
RS_DEFINE_FILTER(rs_resample, RSResample)
enum {
@@ -54,10 +67,10 @@
static RS_IMAGE16 *get_image(RSFilter *filter);
static gint get_width(RSFilter *filter);
static gint get_height(RSFilter *filter);
-static RS_IMAGE16 *ResizeH(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y);
-static RS_IMAGE16 *ResizeV(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x);
-static RS_IMAGE16 *ResizeH_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y);
-static RS_IMAGE16 *ResizeV_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x);
+static void ResizeH(ResampleInfo *info);
+static void ResizeV(ResampleInfo *info);
+static void ResizeH_compatible(ResampleInfo *info);
+static void ResizeV_compatible(ResampleInfo *info);
static RSFilterClass *rs_resample_parent_class = NULL;
inline guint clampbits(gint x, guint n) { guint32 _y_temp; if( (_y_temp=x>>n) ) x = ~_y_temp >> (32-n); return x;}
@@ -141,11 +154,33 @@
}
}
+gpointer
+start_thread_resampler(gpointer _thread_info)
+{
+ ResampleInfo* t = _thread_info;
+
+ if (t->input->w == t->output->w)
+ {
+ if (t->use_compatible)
+ ResizeV_compatible(t);
+ else
+ ResizeV(t);
+ } else {
+ if (t->use_compatible)
+ ResizeH_compatible(t);
+ else
+ ResizeH(t);
+ }
+ g_thread_exit(NULL);
+
+ return NULL; /* Make the compiler shut up - we'll never return */
+}
+
static RS_IMAGE16 *
get_image(RSFilter *filter)
{
RSResample *resample = RS_RESAMPLE(filter);
- RS_IMAGE16 *temp;
+ RS_IMAGE16 *afterHorizontal;
RS_IMAGE16 *input;
RS_IMAGE16 *output = NULL;
gint input_width = rs_filter_get_width(filter->previous);
@@ -159,20 +194,79 @@
/* Use compatible (and slow) version if input isn't 3 channels and pixelsize 4 */
gboolean use_compatible = ( ! ( input->pixelsize == 4 && input->channels == 3));
+ guint threads = rs_get_number_of_processor_cores();
- if (use_compatible)
+ ResampleInfo* h_resample = g_new(ResampleInfo, threads);
+ ResampleInfo* v_resample = g_new(ResampleInfo, threads);
+
+ /* Create intermediate and output images*/
+ afterHorizontal = rs_image16_new(resample->new_width, input_height, input->channels, input->pixelsize);
+
+ guint input_y_offset = 0;
+ guint input_y_per_thread = (input_height+threads-1) / threads;
+
+ guint i;
+ for (i = 0; i < threads; i++)
{
- temp = ResizeH_compatible(input, input_width, resample->new_width, input_height);
- output = ResizeV_compatible(temp, input_height, resample->new_height, temp->w);
+ /* Set info for Horizontal resampler */
+ ResampleInfo *h = &h_resample[i];
+ h->input = input;
+ h->output = afterHorizontal;
+ h->old_size = input_width;
+ h->new_size = resample->new_width;
+ h->dest_offset_other = input_y_offset;
+ h->dest_end_other = MIN(input_y_offset+input_y_per_thread, input_height);
+ h->use_compatible = use_compatible;
+
+ /* Start it up */
+ h->threadid = g_thread_create(start_thread_resampler, h, TRUE, NULL);
+
+ /* Update offset */
+ input_y_offset = h->dest_end_other;
+
}
- else
+
+ /* Wait for horizontal threads to finish */
+ for(i = 0; i < threads; i++)
+ g_thread_join(h_resample[i].threadid);
+
+ /* input no longer needed */
+ g_object_unref(input);
+
+ /* create output */
+ output = rs_image16_new(resample->new_width, resample->new_height, input->channels, input->pixelsize);
+
+ guint output_x_offset = 0;
+ guint output_x_per_thread = (resample->new_width+threads-1) / threads;
+
+ for (i = 0; i < threads; i++)
{
- temp = ResizeH(input, input_width, resample->new_width, input_height);
- output = ResizeV(temp, input_height, resample->new_height, temp->w);
+ /* Set info for Vertical resampler */
+ ResampleInfo *v = &v_resample[i];
+ v->input = afterHorizontal;
+ v->output = output;
+ v->old_size = input_height;
+ v->new_size = resample->new_height;
+ v->dest_offset_other = output_x_offset;
+ v->dest_end_other = MIN(output_x_offset + output_x_per_thread, resample->new_width);
+ v->use_compatible = use_compatible;
+
+ /* Start it up */
+ v->threadid = g_thread_create(start_thread_resampler, v, TRUE, NULL);
+
+ /* Update offset */
+ output_x_offset = v->dest_end_other;
}
- g_object_unref(temp);
- g_object_unref(input);
+ /* Wait for vertical threads to finish */
+ for(i = 0; i < threads; i++)
+ g_thread_join(v_resample[i].threadid);
+
+ /* Clean up */
+ g_free(h_resample);
+ g_free(v_resample);
+ g_object_unref(afterHorizontal);
+
return output;
}
@@ -225,9 +319,14 @@
const static gint FPScale = 16384; /* fixed point scaler */
const static gint FPScaleShift = 14; /* fixed point scaler */
-static RS_IMAGE16 *
-ResizeH(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y)
+static void
+ResizeH(ResampleInfo *info)
{
+ const RS_IMAGE16 *input = info->input;
+ const RS_IMAGE16 *output = info->output;
+ const guint old_size = info->old_size;
+ const guint new_size = info->new_size;
+
gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
gdouble filter_step = MIN(1.0 / pos_step, 1.0);
gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
@@ -235,8 +334,6 @@
gint *weights = g_new(gint, new_size * fir_filter_size);
gint *offsets = g_new(gint, new_size);
- RS_IMAGE16 *output = rs_image16_new(new_size, insize_y, 3, 4);
-
g_assert(new_size > fir_filter_size);
gdouble pos = 0.0;
@@ -285,7 +382,7 @@
g_assert(input->channels == 3);
guint y,x;
- for (y = 0; y < insize_y ; y++)
+ for (y = info->dest_offset_other; y < info->dest_end_other ; y++)
{
gushort *in_line = GET_PIXEL(input, 0, y);
gushort *out = GET_PIXEL(output, 0, y);
@@ -315,12 +412,18 @@
g_free(weights);
g_free(offsets);
- return output;
}
-static RS_IMAGE16 *
-ResizeV(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x)
+static void
+ResizeV(ResampleInfo *info)
{
+ const RS_IMAGE16 *input = info->input;
+ const RS_IMAGE16 *output = info->output;
+ const guint old_size = info->old_size;
+ const guint new_size = info->new_size;
+ const guint start_x = info->dest_offset_other;
+ const guint end_x = info->dest_end_other;
+
gdouble pos_step = ((gdouble) old_size) / ((gdouble)new_size);
gdouble filter_step = MIN(1.0 / pos_step, 1.0);
gdouble filter_support = (gdouble) lanczos_taps() / filter_step;
@@ -328,8 +431,6 @@
gint *weights = g_new(gint, new_size * fir_filter_size);
gint *offsets = g_new(gint, new_size);
- RS_IMAGE16 *output = rs_image16_new(insize_x, new_size, 3, 4);
-
g_assert(new_size > fir_filter_size);
gdouble pos = 0.0;
@@ -382,9 +483,9 @@
for (y = 0; y < new_size ; y++)
{
- gushort *in = GET_PIXEL(input, 0, offsets[y]);
+ gushort *in = GET_PIXEL(input, start_x, offsets[y]);
gushort *out = GET_PIXEL(output, 0, y);
- for (x = 0; x < insize_x; x++)
+ for (x = start_x; x < end_x; x++)
{
gint acc1 = 0;
gint acc2 = 0;
@@ -406,11 +507,16 @@
g_free(weights);
g_free(offsets);
- return output;
}
-static RS_IMAGE16 *
-ResizeH_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_y)
+
+static void
+ResizeH_compatible(ResampleInfo *info)
{
+ const RS_IMAGE16 *input = info->input;
+ const RS_IMAGE16 *output = info->output;
+ const guint old_size = info->old_size;
+ const guint new_size = info->new_size;
+
gint pixelsize = input->pixelsize;
gint ch = input->channels;
@@ -421,8 +527,6 @@
gint *weights = g_new(gint, new_size * fir_filter_size);
gint *offsets = g_new(gint, new_size);
- RS_IMAGE16 *output = rs_image16_new(new_size, insize_y, ch, pixelsize);
-
g_assert(new_size > fir_filter_size);
gdouble pos = 0.0;
@@ -469,7 +573,7 @@
guint y,x,c;
- for (y = 0; y < insize_y ; y++)
+ for (y = info->dest_offset_other; y < info->dest_end_other ; y++)
{
gint *wg = weights;
gushort *in_line = GET_PIXEL(input, 0, y);
@@ -496,12 +600,18 @@
g_free(weights);
g_free(offsets);
- return output;
}
-static RS_IMAGE16 *
-ResizeV_compatible(RS_IMAGE16 *input, guint old_size, guint new_size, guint insize_x)
+static void
+ResizeV_compatible(ResampleInfo *info)
{
+ const RS_IMAGE16 *input = info->input;
+ const RS_IMAGE16 *output = info->output;
+ const guint old_size = info->old_size;
+ const guint new_size = info->new_size;
+ const guint start_x = info->dest_offset_other;
+ const guint end_x = info->dest_end_other;
+
gint pixelsize = input->pixelsize;
gint ch = input->channels;
@@ -512,8 +622,6 @@
gint *weights = g_new(gint, new_size * fir_filter_size);
gint *offsets = g_new(gint, new_size);
- RS_IMAGE16 *output = rs_image16_new(insize_x, new_size, ch, pixelsize);
-
g_assert(new_size > fir_filter_size);
gdouble pos = 0.0;
@@ -564,7 +672,7 @@
for (y = 0; y < new_size ; y++)
{
gushort *out = GET_PIXEL(output, 0, y);
- for (x = 0; x < insize_x; x++)
+ for (x = start_x; x < end_x; x++)
{
gushort *in = GET_PIXEL(input, x, offsets[y]);
for (c = 0; c < ch; c++)
@@ -583,6 +691,4 @@
g_free(weights);
g_free(offsets);
-
- return output;
}
More information about the Rawstudio-commit
mailing list