add a 'stop' param to generate

generate now has a 'stop' param, set this to indicate early successful
termination

this will be used by VipsMin and friends to stop scanning early for
conditions like seen a 0 in a uchar image while searching for min
This commit is contained in:
John Cupitt 2011-08-29 14:29:33 +01:00
parent 1a38d60efb
commit 2909cb93a4
23 changed files with 108 additions and 81 deletions

View File

@ -2,6 +2,7 @@
- version bump for new dev cycle
- im_subtract(), im_avg() redone as classes
- added VIPS_ARGUMENT_APPEND to help control arg ordering
- generate has a 'stop' param to signal successful early termination
10/8/11 started 7.26.3
- don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this

View File

@ -258,7 +258,8 @@ vips__bandalike( const char *domain,
*/
static int
vips_binary_process_region( VipsRegion *or, void *seq, void *a, void *b )
vips_binary_process_region( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRegion **ir = (VipsRegion **) seq;
VipsBinary *binary = VIPS_BINARY( b );

View File

@ -99,7 +99,7 @@ wrapscan_stop( void *seq, void *a, void *b )
}
static int
wrapscan_scan( REGION *reg, void *seq, void *a, void *b )
wrapscan_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Wrapscan *wrapscan = (Wrapscan *) a;
Rect *r = &reg->valid;
@ -124,7 +124,7 @@ wrapscan_scan( REGION *reg, void *seq, void *a, void *b )
*/
int
im__wrapscan( VipsImage *in,
VipsStart start, im__wrapscan_fn scan, VipsStop stop,
VipsStartFn start, im__wrapscan_fn scan, VipsStopFn stop,
void *a, void *b )
{
Wrapscan wrapscan;

View File

@ -161,7 +161,7 @@ maxpos_stop( void *seq, void *a, void *b )
/* Loop over region, adding to seq.
*/
static int
maxpos_scan( REGION *reg, void *seq, void *a, void *b )
maxpos_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
const Rect *r = &reg->valid;
const int sz = IM_REGION_N_ELEMENTS( reg );

View File

@ -158,7 +158,7 @@ maxposavg_stop( void *seq, void *a, void *b )
/* Loop over region, adding to seq.
*/
static int
maxposavg_scan( REGION *reg, void *seq, void *a, void *b )
maxposavg_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
const Rect *r = &reg->valid;
const int sz = IM_REGION_N_ELEMENTS( reg );

View File

@ -74,13 +74,13 @@ static void maxpos_list_free( maxpos_list *list );
static void maxpos_list_init( maxpos_list *list, int n );
static void *maxpos_vec_start( IMAGE *unrequired, void *, void * );
static int maxpos_vec_scan( REGION *reg, void *seq, void *, void * );
static int maxpos_vec_scan( REGION *reg, void *seq, void *, void *, gboolean * );
static void add_to_maxpos_list( maxpos_list *list, int x, int y, double val );
static int maxpos_vec_stop( void *seq, void *, void * );
static void minpos_list_init( maxpos_list *list, int n );
static void *minpos_vec_start( IMAGE *unrequired, void *, void * );
static int minpos_vec_scan( REGION *reg, void *seq, void *, void * );
static int minpos_vec_scan( REGION *reg, void *seq, void *, void *, gboolean * );
static void add_to_minpos_list( maxpos_list *list, int x, int y, double val );
static int minpos_vec_stop( void *seq, void *, void * );
@ -275,7 +275,7 @@ static void *maxpos_vec_start( IMAGE *unrequired, void *a, void *b ){
return list;
}
static int maxpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){
static int maxpos_vec_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop ){
maxpos_list *list = (maxpos_list *) seq;
@ -399,7 +399,7 @@ static void *minpos_vec_start( IMAGE *unrequired, void *a, void *b ){
return list;
}
static int minpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){
static int minpos_vec_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop ){
maxpos_list *list = (maxpos_list *) seq;

View File

@ -145,7 +145,7 @@ minpos_stop( void *seq, void *a, void *b )
/* Loop over region, adding to seq.
*/
static int
minpos_scan( REGION *reg, void *seq, void *a, void *b )
minpos_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
const Rect *r = &reg->valid;
const int sz = IM_REGION_N_ELEMENTS( reg );

View File

@ -74,7 +74,8 @@ vips_statistic_scan_start( VipsImage *in, void *a, void *b )
}
static int
vips_statistic_scan( VipsRegion *region, void *seq, void *a, void *b )
vips_statistic_scan( VipsRegion *region,
void *seq, void *a, void *b, gboolean *stop )
{
VipsStatistic *statistic = VIPS_STATISTIC( a );
VipsStatisticClass *class = VIPS_STATISTIC_GET_CLASS( statistic );

View File

@ -405,7 +405,7 @@ im_iterate( IMAGE *im,
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
void *b, void *c )
{
return( vips_sink( im, start, generate, stop, b, c ) );
return( vips_sink( im, start, (VipsGenerateFn) generate, stop, b, c ) );
}
int

View File

@ -506,7 +506,8 @@ im_wrapmany( IMAGE **in, IMAGE *out, im_wrapmany_fn fn, void *a, void *b )
/* Generate!
*/
if( vips_image_generate( out,
vips_start_many, process_region, vips_stop_many, in, bun ) )
vips_start_many, (VipsGenerateFn) process_region,
vips_stop_many, in, bun ) )
return( -1 );
return( 0 );
@ -954,3 +955,11 @@ im_avg( IMAGE *in, double *out )
{
return( vips_avg( in, out, NULL ) );
}
int im_generate( VipsImage *im,
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
void *a, void *b )
{
return( vips_image_generate( im,
start, (VipsGenerateFn) generate, stop, a, b ) );
}

View File

@ -1020,7 +1020,7 @@ new_tile( PyramidLayer *layer, REGION *tile, Rect *area )
* generated.
*/
static int
write_tif_tile( REGION *out, void *seq, void *a, void *b )
write_tif_tile( REGION *out, void *seq, void *a, void *b, gboolean *stop )
{
TiffWrite *tw = (TiffWrite *) a;

View File

@ -138,7 +138,7 @@ merge_subhist( void *seq, void *a, void *b )
/* Histogram of all bands of a uchar image.
*/
static int
find_uchar_hist( REGION *reg, void *seq, void *a, void *b )
find_uchar_hist( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -170,7 +170,8 @@ find_uchar_hist( REGION *reg, void *seq, void *a, void *b )
/* Histogram of a selected band of a uchar image.
*/
static int
find_uchar_hist_extract( REGION *reg, void *seq, void *a, void *b )
find_uchar_hist_extract( REGION *reg,
void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -202,7 +203,7 @@ find_uchar_hist_extract( REGION *reg, void *seq, void *a, void *b )
/* Histogram of all bands of a ushort image.
*/
static int
find_ushort_hist( REGION *reg, void *seq, void *a, void *b )
find_ushort_hist( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -244,7 +245,8 @@ find_ushort_hist( REGION *reg, void *seq, void *a, void *b )
/* Histogram of all bands of a ushort image.
*/
static int
find_ushort_hist_extract( REGION *reg, void *seq, void *a, void *b )
find_ushort_hist_extract( REGION *reg,
void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -305,7 +307,7 @@ im_histgr( IMAGE *in, IMAGE *out, int bandno )
int size; /* Length of hist */
int bands; /* Number of bands in output */
Histogram *mhist;
im_generate_fn scanfn;
VipsGenerateFn scanfn;
int i, j;
unsigned int *obuffer, *q;

View File

@ -155,7 +155,7 @@ hist_stop( void *seq, void *a, void *b )
/* A uchar index image.
*/
static int
hist_scan_uchar( REGION *reg, void *seq, void *a, void *b )
hist_scan_uchar( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -230,7 +230,7 @@ hist_scan_uchar( REGION *reg, void *seq, void *a, void *b )
/* A ushort index image.
*/
static int
hist_scan_ushort( REGION *reg, void *seq, void *a, void *b )
hist_scan_ushort( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;
@ -327,7 +327,7 @@ im_hist_indexed( IMAGE *index, IMAGE *value, IMAGE *out )
{
int size; /* Length of hist */
Histogram *mhist;
im_generate_fn scanfn;
VipsGenerateFn scanfn;
/* Check images. PIO from in, WIO to out.
*/

View File

@ -154,7 +154,7 @@ merge_subhist( void *seq, void *a, void *b )
}
static int
find_hist( REGION *reg, void *seq, void *a, void *b )
find_hist( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Histogram *hist = (Histogram *) seq;
Rect *r = &reg->valid;

View File

@ -189,7 +189,7 @@ project_merge( void *seq, void *a, void *b )
/* Add a region to a project.
*/
static int
project_scan( REGION *reg, void *seq, void *a, void *b )
project_scan( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
{
Project *project = (Project *) seq;
Rect *r = &reg->valid;

View File

@ -131,7 +131,7 @@ void im_warning( const char *fmt, ... )
__attribute__((format(printf, 1, 2)));
int im_iterate( VipsImage *im,
VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop,
VipsStartFn start, im_generate_fn generate, VipsStopFn stop,
void *a, void *b
);

View File

@ -1,4 +1,4 @@
/* Definitions for partial image regions.
/* Generate pixels.
*
* J.Cupitt, 8/4/93
*/
@ -36,9 +36,30 @@
extern "C" {
#endif /*__cplusplus*/
typedef int (*VipsRegionWrite)( VipsRegion *region, VipsRect *area, void *a );
int vips_sink_disc( VipsImage *im, VipsRegionWrite write_fn, void *a );
typedef void *(*VipsStartFn)( VipsImage *out, void *a, void *b );
typedef int (*VipsGenerateFn)( VipsRegion *out, void *seq, void *a, void *b );
typedef int (*VipsGenerateFn)( VipsRegion *out,
void *seq, void *a, void *b, gboolean *stop );
typedef int (*VipsStopFn)( void *seq, void *a, void *b );
int vips_sink( VipsImage *im,
VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop,
void *a, void *b );
int vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop,
void *a, void *b );
typedef void (*VipsSinkNotify)( VipsImage *im, VipsRect *rect, void *a );
int vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
int tile_width, int tile_height, int max_tiles,
int priority,
VipsSinkNotify notify, void *a );
int vips_image_cache( VipsImage *in, VipsImage *out,
int width, int height, int max );
int vips_sink_memory( VipsImage *im );
void *vips_start_one( VipsImage *out, void *a, void *b );
int vips_stop_one( void *seq, void *a, void *b );

View File

@ -98,58 +98,34 @@ VipsThreadState *vips_thread_state_new( VipsImage *im, void *a );
/* Constructor for per-thread state.
*/
typedef VipsThreadState *(*VipsThreadStart)( VipsImage *im, void *a );
typedef VipsThreadState *(*VipsThreadStartFn)( VipsImage *im, void *a );
/* A work allocate function. This is run single-threaded by a worker to
* set up a new work unit.
* Return non-zero for errors. Set *stop for "no more work to do"
*/
typedef int (*VipsThreadpoolAllocate)( VipsThreadState *state,
typedef int (*VipsThreadpoolAllocateFn)( VipsThreadState *state,
void *a, gboolean *stop );
/* A work function. This does a unit of work (eg. processing a tile or
* whatever). Return non-zero for errors.
*/
typedef int (*VipsThreadpoolWork)( VipsThreadState *state, void *a );
typedef int (*VipsThreadpoolWorkFn)( VipsThreadState *state, void *a );
/* A progress function. This is run by the main thread once for every
* allocation. Return an error to kill computation early.
*/
typedef int (*VipsThreadpoolProgress)( void *a );
typedef int (*VipsThreadpoolProgressFn)( void *a );
int vips_threadpool_run( VipsImage *im,
VipsThreadStart start,
VipsThreadpoolAllocate allocate,
VipsThreadpoolWork work,
VipsThreadpoolProgress progress,
VipsThreadStartFn start,
VipsThreadpoolAllocateFn allocate,
VipsThreadpoolWorkFn work,
VipsThreadpoolProgressFn progress,
void *a );
void vips_get_tile_size( VipsImage *im,
int *tile_width, int *tile_height, int *nlines );
typedef int (*VipsRegionWrite)( VipsRegion *region, VipsRect *area, void *a );
int vips_sink_disc( VipsImage *im, VipsRegionWrite write_fn, void *a );
typedef void *(*VipsStart)( VipsImage *out, void *a, void *b );
typedef int (*VipsGenerate)( VipsRegion *out, void *seq, void *a, void *b );
typedef int (*VipsStop)( void *seq, void *a, void *b );
int vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b );
int vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b );
typedef void (*VipsSinkNotify)( VipsImage *im, VipsRect *rect, void *a );
int vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
int tile_width, int tile_height, int max_tiles,
int priority,
VipsSinkNotify notify, void *a );
int vips_image_cache( VipsImage *in, VipsImage *out,
int width, int height, int max );
int vips_sink_memory( VipsImage *im );
void vips__print_renders( void );
void vips_concurrency_set( int concurrency );

View File

@ -275,9 +275,11 @@ VipsDemandStyle im_char2dhint( const char *str );
#define im_stop_many vips_stop_many
#define im_allocate_input_array vips_allocate_input_array
#define im_start_fn VipsStartFn
#define im_generate_fn VipsGenerateFn
typedef int (*im_generate_fn)( VipsRegion *out, void *seq, void *a, void *b );
#define im_stop_fn VipsStopFn
#define im_generate vips_image_generate
int im_generate( VipsImage *im,
im_start_fn start, im_generate_fn generate, im_stop_fn stop,
void *a, void *b );
#define im__mmap vips__mmap
#define im__munmap vips__munmap

View File

@ -640,7 +640,8 @@ open_lazy_start( VipsImage *out, void *a, void *dummy )
/* Just copy.
*/
static int
open_lazy_generate( VipsRegion *or, void *seq, void *a, void *b )
open_lazy_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRegion *ir = (VipsRegion *) seq;

View File

@ -85,6 +85,10 @@ typedef struct _SinkThreadState {
* parent_object.reg, it's defined on the outer image.
*/
VipsRegion *reg;
/* Set this in work to get the allocate to signal stop.
*/
gboolean stop;
} SinkThreadState;
typedef struct _SinkThreadStateClass {
@ -184,6 +188,7 @@ sink_thread_state_init( SinkThreadState *state )
{
state->seq = NULL;
state->reg = NULL;
state->stop = FALSE;
}
static VipsThreadState *
@ -246,10 +251,19 @@ sink_init( Sink *sink,
int
vips_sink_base_allocate( VipsThreadState *state, void *a, gboolean *stop )
{
SinkThreadState *sstate = (SinkThreadState *) state;
SinkBase *sink_base = (SinkBase *) a;
VipsRect image, tile;
/* Has work requested early termination?
*/
if( sstate->stop ) {
*stop = TRUE;
return( 0 );
}
/* Is the state x/y OK? New line or maybe all done.
*/
if( sink_base->x >= sink_base->im->Xsize ) {
@ -289,7 +303,8 @@ sink_work( VipsThreadState *state, void *a )
Sink *sink = (Sink *) a;
if( vips_region_prepare( sstate->reg, &state->pos ) ||
sink->generate( sstate->reg, sstate->seq, sink->a, sink->b ) )
sink->generate( sstate->reg, sstate->seq,
sink->a, sink->b, &sstate->stop ) )
return( -1 );
return( 0 );
@ -327,8 +342,6 @@ vips_sink_base_progress( void *a )
*
* Loops over an image. @generate is called for every pixel in the image, with
* the @reg argument being a region of pixels for processing.
* vips_sink_tile() is
* used to implement operations like im_avg() which have no image output.
*
* Each set of
* pixels is @tile_width by @tile_height pixels (less at the image edges).
@ -343,7 +356,7 @@ vips_sink_base_progress( void *a )
int
vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStart start, VipsGenerate generate, VipsStop stop,
VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop,
void *a, void *b )
{
Sink sink;
@ -394,7 +407,7 @@ vips_sink_tile( VipsImage *im,
*
* Loops over an image. @generate is called for every pixel in the image, with
* the @reg argument being a region of pixels for processing. vips_sink() is
* used to implement operations like im_avg() which have no image output.
* used to implement operations like #VipsAvg which have no image output.
*
* Each set of pixels is sized according to the requirements of the image
* pipeline that generated @im.
@ -405,7 +418,7 @@ vips_sink_tile( VipsImage *im,
*/
int
vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop,
void *a, void *b )
{
return( vips_sink_tile( im, -1, -1, start, generate, stop, a, b ) );

View File

@ -910,7 +910,7 @@ image_start( IMAGE *out, void *a, void *b )
/* Loop over the output region, filling with data from cache.
*/
static int
image_fill( VipsRegion *out, void *seq, void *a, void *b )
image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
Render *render = (Render *) a;
VipsRegion *reg = (VipsRegion *) seq;
@ -970,7 +970,7 @@ image_stop( void *seq, void *a, void *b )
/* The mask image is 255 / 0 for the state of painted for each tile.
*/
static int
mask_fill( VipsRegion *out, void *seq, void *a, void *b )
mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
#ifdef HAVE_THREADS
Render *render = (Render *) a;

View File

@ -356,9 +356,9 @@ typedef struct _VipsThreadpool {
* a unit of work (serial). Plus the mutex we use to serialize work
* allocation.
*/
VipsThreadStart start;
VipsThreadpoolAllocate allocate;
VipsThreadpoolWork work;
VipsThreadStartFn start;
VipsThreadpoolAllocateFn allocate;
VipsThreadpoolWorkFn work;
GMutex *allocate_lock;
void *a; /* User argument to start / allocate / etc. */
@ -715,7 +715,7 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
}
/**
* VipsThreadpoolStart:
* VipsThreadpoolStartFn:
* @a: client data
* @b: client data
* @c: client data
@ -733,7 +733,7 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
*/
/**
* _VipsThreadpoolAllocate:
* VipsThreadpoolAllocateFn:
* @state: per-thread state
* @a: client data
* @b: client data
@ -756,7 +756,7 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
*/
/**
* _VipsThreadpoolWork:
* VipsThreadpoolWorkFn:
* @state: per-thread state
* @a: client data
* @b: client data
@ -775,7 +775,7 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
*/
/**
* _VipsThreadpoolProgress:
* VipsThreadpoolProgressFn:
* @a: client data
* @b: client data
* @c: client data
@ -819,10 +819,10 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
*/
int
vips_threadpool_run( VipsImage *im,
VipsThreadStart start,
VipsThreadpoolAllocate allocate,
VipsThreadpoolWork work,
VipsThreadpoolProgress progress,
VipsThreadStartFn start,
VipsThreadpoolAllocateFn allocate,
VipsThreadpoolWorkFn work,
VipsThreadpoolProgressFn progress,
void *a )
{
VipsThreadpool *pool;