im_vips2tiff() uses vips_sink() instead of threadgroup

This commit is contained in:
John Cupitt 2010-04-16 15:48:30 +00:00
parent 31b06dbc5a
commit 54730feadc
6 changed files with 108 additions and 102 deletions

View File

@ -12,6 +12,7 @@
- set G_LOG_DOMAIN to VIPS so we can use g_warning etc. - set G_LOG_DOMAIN to VIPS so we can use g_warning etc.
- added VIPS_DEBUG_MSG() macro - added VIPS_DEBUG_MSG() macro
- --vips-wbuffer2 turns on threadpool for im_iterate as well - --vips-wbuffer2 turns on threadpool for im_iterate as well
- im_vips2tiff() uses vips_sink() instead of threadgroup
16/1/10 started 7.21.2 16/1/10 started 7.21.2
- "invalidate" is careful to keep images alive, so invalidate callbacks can do - "invalidate" is careful to keep images alive, so invalidate callbacks can do

2
TODO
View File

@ -3,8 +3,6 @@
- im_prepare_thread() can go? I think it was only used by im_render() - im_prepare_thread() can go? I think it was only used by im_render()
wtf, im_vips2tiff.c seems to be using it, what's wrong with im_wbuffer()?
- get rid of threadgroup too (deprecate?) - get rid of threadgroup too (deprecate?)

View File

@ -110,6 +110,8 @@
* - gtkdoc * - gtkdoc
* 26/2/10 * 26/2/10
* - option to turn on bigtiff output * - option to turn on bigtiff output
* 16/4/10
* - use vips_sink_*() instead of threadgroup and friends
*/ */
/* /*
@ -230,7 +232,6 @@ typedef struct tiff_write {
/* Read from im with these. /* Read from im with these.
*/ */
REGION *reg; REGION *reg;
im_threadgroup_t *tg;
char *bname; /* Name for base layer */ char *bname; /* Name for base layer */
TIFF *tif; /* Image we write to */ TIFF *tif; /* Image we write to */
@ -252,6 +253,8 @@ typedef struct tiff_write {
int embed; /* Embed ICC profile */ int embed; /* Embed ICC profile */
char *icc_profile; /* Profile to embed */ char *icc_profile; /* Profile to embed */
int bigtiff; /* True for bigtiff write */ int bigtiff; /* True for bigtiff write */
GMutex *write_lock; /* Lock TIFF*() calls with this */
} TiffWrite; } TiffWrite;
/* Use these from im_tiff2vips(). /* Use these from im_tiff2vips().
@ -570,14 +573,8 @@ free_layer( PyramidLayer *layer )
/* And close the TIFF file we are writing to. /* And close the TIFF file we are writing to.
*/ */
if( layer->tbuf ) { IM_FREEF( im_free, layer->tbuf );
im_free( layer->tbuf ); IM_FREEF( TIFFClose, layer->tif );
layer->tbuf = NULL;
}
if( layer->tif ) {
TIFFClose( layer->tif );
layer->tif = NULL;
}
} }
/* Free an entire pyramid. /* Free an entire pyramid.
@ -1032,18 +1029,50 @@ new_tile( PyramidLayer *layer, REGION *tile, Rect *area )
return( 0 ); return( 0 );
} }
/* Write as tiles. This is called by vips_sink_tile() for every tile
* generated.
*/
static int
write_tif_tile( REGION *out, void *seq, void *a, void *b )
{
TiffWrite *tw = (TiffWrite *) a;
g_mutex_lock( tw->write_lock );
/* Write to TIFF.
*/
if( save_tile( tw, tw->tif, tw->tbuf, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
/* Is there a pyramid? Write to that too.
*/
if( tw->layer &&
new_tile( tw->layer, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
g_mutex_unlock( tw->write_lock );
return( 0 );
}
/* Write as tiles. /* Write as tiles.
*/ */
static int static int
write_tif_tile( TiffWrite *tw ) write_tif_tilewise( TiffWrite *tw )
{ {
IMAGE *im = tw->im; IMAGE *im = tw->im;
Rect area;
int x, y;
g_assert( !tw->tbuf );
if( !(tw->tbuf = im_malloc( NULL, TIFFTileSize( tw->tif ) )) ) if( !(tw->tbuf = im_malloc( NULL, TIFFTileSize( tw->tif ) )) )
return( -1 ); return( -1 );
g_assert( !tw->write_lock );
tw->write_lock = g_mutex_new();
/* Write pyramid too? Only bother if bigger than tile size. /* Write pyramid too? Only bother if bigger than tile size.
*/ */
if( tw->pyramid && if( tw->pyramid &&
@ -1051,41 +1080,15 @@ write_tif_tile( TiffWrite *tw )
build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) ) build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) )
return( -1 ); return( -1 );
for( y = 0; y < im->Ysize; y += tw->tileh ) if( vips_sink_tile( im, tw->tilew, tw->tileh,
for( x = 0; x < im->Xsize; x += tw->tilew ) { NULL, write_tif_tile, NULL, tw, NULL ) )
/* Set up rect we write. return( -1 );
*/
area.left = x;
area.top = y;
area.width = IM_MIN( tw->tilew, im->Xsize - x );
area.height = IM_MIN( tw->tileh, im->Ysize - y );
if( im_prepare_thread( tw->tg, tw->reg, &area ) )
return( -1 );
/* Write to TIFF.
*/
if( save_tile( tw, tw->tif, tw->tbuf, tw->reg, &area ) )
return( -1 );
/* Is there a pyramid? Write to that too.
*/
if( tw->layer && new_tile( tw->layer, tw->reg, &area ) )
return( -1 );
/* Trigger any eval callbacks on our source image and
* check for errors.
*/
if( im__handle_eval( im, area.width, area.height ) ||
im_threadgroup_iserror( tw->tg ) )
return( -1 );
}
return( 0 ); return( 0 );
} }
static int static int
write_tif_block( REGION *region, Rect *area, void *a, void *b ) write_tif_block( REGION *region, Rect *area, void *a )
{ {
TiffWrite *tw = (TiffWrite *) a; TiffWrite *tw = (TiffWrite *) a;
IMAGE *im = tw->im; IMAGE *im = tw->im;
@ -1121,14 +1124,14 @@ write_tif_block( REGION *region, Rect *area, void *a, void *b )
/* Write as scan-lines. /* Write as scan-lines.
*/ */
static int static int
write_tif_strip( TiffWrite *tw ) write_tif_stripwise( TiffWrite *tw )
{ {
g_assert( !tw->tbuf ); g_assert( !tw->tbuf );
if( !(tw->tbuf = im_malloc( NULL, TIFFScanlineSize( tw->tif ) )) ) if( !(tw->tbuf = im_malloc( NULL, TIFFScanlineSize( tw->tif ) )) )
return( -1 ); return( -1 );
if( im_wbuffer( tw->tg, write_tif_block, tw, NULL ) ) if( vips_sink_disc( tw->im, write_tif_block, tw ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
@ -1162,28 +1165,11 @@ free_tiff_write( TiffWrite *tw )
delete_files( tw ); delete_files( tw );
#endif /*DEBUG*/ #endif /*DEBUG*/
if( tw->tg ) { IM_FREEF( TIFFClose, tw->tif );
im_threadgroup_free( tw->tg ); IM_FREEF( im_free, tw->tbuf );
tw->tg = NULL; IM_FREEF( g_mutex_free, tw->write_lock );
} IM_FREEF( free_pyramid, tw->layer );
if( tw->reg ) { IM_FREEF( im_free, tw->icc_profile );
im_region_free( tw->reg );
tw->reg = NULL;
}
if( tw->tif ) {
TIFFClose( tw->tif );
tw->tif = NULL;
}
if( tw->tbuf ) {
im_free( tw->tbuf );
tw->tbuf = NULL;
}
if( tw->layer )
free_pyramid( tw->layer );
if( tw->icc_profile ) {
im_free( tw->icc_profile );
tw->icc_profile = NULL;
}
} }
/* Round N down to P boundary. /* Round N down to P boundary.
@ -1211,8 +1197,6 @@ make_tiff_write( IMAGE *im, const char *filename )
im_filename_split( filename, name, mode ); im_filename_split( filename, name, mode );
tw->name = im_strdup( im, name ); tw->name = im_strdup( im, name );
tw->mode = im_strdup( im, mode ); tw->mode = im_strdup( im, mode );
tw->tg = NULL;
tw->reg = NULL;
tw->bname = NULL; tw->bname = NULL;
tw->tif = NULL; tw->tif = NULL;
tw->layer = NULL; tw->layer = NULL;
@ -1228,6 +1212,7 @@ make_tiff_write( IMAGE *im, const char *filename )
tw->embed = 0; tw->embed = 0;
tw->icc_profile = NULL; tw->icc_profile = NULL;
tw->bigtiff = 0; tw->bigtiff = 0;
tw->write_lock = NULL;
/* Output resolution settings ... default to VIPS-alike. /* Output resolution settings ... default to VIPS-alike.
*/ */
@ -1434,14 +1419,6 @@ make_tiff_write( IMAGE *im, const char *filename )
tw->compression = COMPRESSION_NONE; tw->compression = COMPRESSION_NONE;
} }
/* Make region and threadgroup.
*/
if( !(tw->reg = im_region_create( tw->im )) ||
!(tw->tg = im_threadgroup_create( tw->im )) ) {
free_tiff_write( tw );
return( NULL );
}
/* Sizeof a line of bytes in the TIFF tile. /* Sizeof a line of bytes in the TIFF tile.
*/ */
if( im->Coding == IM_CODING_LABQ ) if( im->Coding == IM_CODING_LABQ )
@ -1766,20 +1743,10 @@ im_vips2tiff( IMAGE *in, const char *filename )
} }
if( tw->tile ) { if( tw->tile )
/* The strip writer uses wbuffer and does start/end for us, we res = write_tif_tilewise( tw );
* have our own loop for tile writing and so we need to call
* ourselves.
*/
if( im__start_eval( in ) ) {
free_tiff_write( tw );
return( -1 );
}
res = write_tif_tile( tw );
im__end_eval( in );
}
else else
res = write_tif_strip( tw ); res = write_tif_stripwise( tw );
if( res ) { if( res ) {
free_tiff_write( tw ); free_tiff_write( tw );
return( -1 ); return( -1 );

View File

@ -133,6 +133,10 @@ typedef int (*VipsStop)( void *seq, void *a, void *b );
int vips_sink( VipsImage *im, int vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop, VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b ); 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, Rect *rect, void *a ); typedef void (*VipsSinkNotify)( VipsImage *im, Rect *rect, void *a );
int vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask, int vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,

View File

@ -301,8 +301,10 @@ sink_progress( void *a )
} }
/** /**
* vips_sink: * vips_sink_tile:
* @im: scan over this image * @im: scan over this image
* @tile_width: tile width
* @tile_height: tile height
* @start: start sequences with this function * @start: start sequences with this function
* @generate: generate pixels with this function * @generate: generate pixels with this function
* @stop: stop sequences with this function * @stop: stop sequences with this function
@ -310,15 +312,23 @@ sink_progress( void *a )
* @b: user data * @b: user data
* *
* Loops over an image. @generate is called for every pixel in the image, with * 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 * 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. * used to implement operations like im_avg() which have no image output.
* *
* See also: im_generate(), im_open(). * Each set of
* pixels is @tile_width by @tile_height pixels (less at the image edges).
* This is handy for things like
* writing a tiled TIFF image, where tiles have to be generated with a certain
* size.
*
* See also: vips_sink(), vips_get_tile_size().
* *
* Returns: 0 on success, or -1 on error. * Returns: 0 on success, or -1 on error.
*/ */
int int
vips_sink( VipsImage *im, vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStart start, VipsGenerate generate, VipsStop stop, VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b ) void *a, void *b )
{ {
@ -335,6 +345,11 @@ vips_sink( VipsImage *im,
if( sink_init( &sink, im, start, generate, stop, a, b ) ) if( sink_init( &sink, im, start, generate, stop, a, b ) )
return( -1 ); return( -1 );
if( tile_width > 0 ) {
sink.tile_width = tile_width;
sink.tile_height = tile_height;
}
if( im__start_eval( sink.t ) ) { if( im__start_eval( sink.t ) ) {
sink_free( &sink ); sink_free( &sink );
return( -1 ); return( -1 );
@ -353,3 +368,31 @@ vips_sink( VipsImage *im,
return( result ); return( result );
} }
/**
* vips_sink:
* @im: scan over this image
* @start: start sequences with this function
* @generate: generate pixels with this function
* @stop: stop sequences with this function
* @a: user data
* @b: user data
*
* 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.
*
* Each set of pixels is sized according to the requirements of the image
* pipeline that generated @im.
*
* See also: im_generate(), im_open().
*
* Returns: 0 on success, or -1 on error.
*/
int
vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b )
{
return( vips_sink_tile( im, -1, -1, start, generate, stop, a, b ) );
}

View File

@ -516,14 +516,7 @@ vips_sink_disc( VipsImage *im, VipsRegionWrite write_fn, void *a )
write_init( &write, im, write_fn, a ); write_init( &write, im, write_fn, a );
printf( "initing thread state\n" );
vips_thread_state_get_type();
printf( "made thread state\n" );
result = 0; result = 0;
if( !write.buf || if( !write.buf ||
!write.buf_back || !write.buf_back ||
wbuffer_position( write.buf, 0, write.nlines ) || wbuffer_position( write.buf, 0, write.nlines ) ||