244 lines
5.0 KiB
C
244 lines
5.0 KiB
C
/* Manage pipelines of partial images.
|
|
*
|
|
* J.Cupitt, 17/4/93.
|
|
* 1/7/93 JC
|
|
* - adapted for partial v2
|
|
* 9/5/94
|
|
* - new thread stuff added, with a define to turn it off
|
|
* 21/11/94 JC
|
|
* - pw and ph wrong way round!
|
|
* 24/5/95 JC
|
|
* - redone, now works in pipelines!
|
|
* 30/8/96 JC
|
|
* - more sharing with im_generate()
|
|
* 2/3/98 JC
|
|
* - IM_ANY added
|
|
* 19/1/99 JC
|
|
* - oops, threads were broken :(
|
|
* 30/7/99 RP JC
|
|
* - threads reorganised for POSIX
|
|
* 25/10/03 JC
|
|
* - read via a buffer image so we work with mmap window images
|
|
* 27/11/06
|
|
* - merge threadgroup stuff
|
|
* 7/11/07
|
|
* - new eval start/progress/end system
|
|
*/
|
|
|
|
/*
|
|
|
|
This file is part of VIPS.
|
|
|
|
VIPS is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
|
|
|
*/
|
|
|
|
/*
|
|
#define DEBUG_IO
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif /*HAVE_CONFIG_H*/
|
|
#include <vips/intl.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <vips/vips.h>
|
|
#include <vips/internal.h>
|
|
|
|
#ifdef WITH_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif /*WITH_DMALLOC*/
|
|
|
|
/* Loop over an image, preparing in parts with threads.
|
|
*/
|
|
static int
|
|
eval_to_image( im_threadgroup_t *tg, IMAGE *im )
|
|
{
|
|
int x, y;
|
|
Rect image;
|
|
|
|
/* Set up.
|
|
*/
|
|
tg->inplace = 0;
|
|
|
|
image.left = 0;
|
|
image.top = 0;
|
|
image.width = im->Xsize;
|
|
image.height = im->Ysize;
|
|
|
|
/* Loop over or, attaching to all sub-parts in turn.
|
|
*/
|
|
for( y = 0; y < im->Ysize; y += tg->ph )
|
|
for( x = 0; x < im->Xsize; x += tg->pw ) {
|
|
im_thread_t *thr;
|
|
Rect pos;
|
|
Rect clipped;
|
|
|
|
/* thrs appear on idle when the child thread does
|
|
* threadgroup_idle_add and hits the 'go' semaphore.
|
|
*/
|
|
thr = im_threadgroup_get( tg );
|
|
|
|
/* Set the position we want to generate with this
|
|
* thread.
|
|
*/
|
|
pos.left = x;
|
|
pos.top = y;
|
|
pos.width = tg->pw;
|
|
pos.height = tg->ph;
|
|
im_rect_intersectrect( &image, &pos, &clipped );
|
|
|
|
thr->pos = clipped;
|
|
|
|
/* Start worker going.
|
|
*/
|
|
im_threadgroup_trigger( thr );
|
|
|
|
/* Trigger any eval callbacks on our source image.
|
|
*/
|
|
im__handle_eval( im, tg->pw, tg->ph );
|
|
|
|
/* Check for errors.
|
|
*/
|
|
if( im_threadgroup_iserror( tg ) ) {
|
|
/* Don't kill threads yet ... we may want to
|
|
* get some error stuff out of them.
|
|
*/
|
|
im_threadgroup_wait( tg );
|
|
return( -1 );
|
|
}
|
|
}
|
|
|
|
/* Wait for all threads to hit 'go' again.
|
|
*/
|
|
im_threadgroup_wait( tg );
|
|
|
|
/* Test for any errors.
|
|
*/
|
|
if( im_threadgroup_iserror( tg ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
iterate( im_threadgroup_t *tg, IMAGE *im,
|
|
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
|
|
void *b, void *c )
|
|
{
|
|
int i;
|
|
int res;
|
|
|
|
#ifdef DEBUG_IO
|
|
if( tg && tg->nthr > 1 )
|
|
im_diagnostics( "im_iterate: using %d threads", tg->nthr );
|
|
#endif /*DEBUG_IO*/
|
|
|
|
/* Call all the start functions, and pop in the sequence values.
|
|
*/
|
|
for( i = 0; i < tg->nthr; i++ ) {
|
|
if( start && !(tg->thr[i]->a = start( im, b, c )) ) {
|
|
im_error( "im_iterate",
|
|
_( "start function failed for image \"%s\"" ),
|
|
im->filename );
|
|
return( -1 );
|
|
}
|
|
tg->thr[i]->b = b;
|
|
tg->thr[i]->c = c;
|
|
}
|
|
|
|
/* Loop and generate multi-thread.
|
|
*/
|
|
res = eval_to_image( tg, im );
|
|
|
|
/* Call all stop functions.
|
|
*/
|
|
for( i = 0; i < tg->nthr; i++ ) {
|
|
if( tg->thr[i]->a && stop ) {
|
|
/* Trigger the stop function.
|
|
*/
|
|
if( stop( tg->thr[i]->a, b, c ) )
|
|
/* Drastic!
|
|
*/
|
|
im_error( "im_iterate",
|
|
_( "stop function failed "
|
|
"for image \"%s\"" ),
|
|
im->filename );
|
|
tg->thr[i]->a = NULL;
|
|
}
|
|
}
|
|
|
|
return( res );
|
|
}
|
|
|
|
/* Scan region over image in small pieces.
|
|
*/
|
|
int
|
|
im_iterate( IMAGE *im,
|
|
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
|
|
void *b, void *c )
|
|
{
|
|
IMAGE *t;
|
|
im_threadgroup_t *tg;
|
|
int result;
|
|
|
|
if( im_image_sanity( im ) )
|
|
return( -1 );
|
|
|
|
if( !(t = im_open( "iterate", "p" )) )
|
|
return( -1 );
|
|
if( im_copy( im, t ) ) {
|
|
im_close( t );
|
|
return( -1 );
|
|
}
|
|
|
|
if( !(tg = im_threadgroup_create( t )) ) {
|
|
im_close( t );
|
|
return( -1 );
|
|
}
|
|
tg->work = generate;
|
|
tg->inplace = 0;
|
|
|
|
#ifdef DEBUG_IO
|
|
if( tg && tg->nthr > 1 )
|
|
im_diagnostics( "im_iterate: using %d threads", tg->nthr );
|
|
#endif /*DEBUG_IO*/
|
|
|
|
/* Signal start of eval.
|
|
*/
|
|
if( im__start_eval( t ) )
|
|
return( -1 );
|
|
|
|
result = iterate( tg, t, start, generate, stop, b, c );
|
|
|
|
/* Signal end of eval.
|
|
*/
|
|
result |= im__end_eval( t );
|
|
|
|
im_threadgroup_free( tg );
|
|
im_close( t );
|
|
|
|
return( result );
|
|
}
|