From f1ebc12fb190c135a44c67702adc7de4c917cb3c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 16 Apr 2010 16:09:48 +0000 Subject: [PATCH] added sinkmemory, started removing threadgroup --- TODO | 4 + libvips/iofuncs/im_generate.c | 84 ++------------- libvips/iofuncs/sinkmemory.c | 189 ++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 76 deletions(-) create mode 100644 libvips/iofuncs/sinkmemory.c diff --git a/TODO b/TODO index 9369ebd7..50867868 100644 --- a/TODO +++ b/TODO @@ -5,6 +5,10 @@ - get rid of threadgroup too (deprecate?) +- can eval_to_region() go? I guess + +- need an eval_to_memory for generate to use to write to "t" images + - expose more of the tone funcs in nip2 diff --git a/libvips/iofuncs/im_generate.c b/libvips/iofuncs/im_generate.c index 17e3ca6c..08b2bc8a 100644 --- a/libvips/iofuncs/im_generate.c +++ b/libvips/iofuncs/im_generate.c @@ -508,14 +508,14 @@ write_vips( REGION *region, Rect *area, void *a, void *b ) * For images opened with "p", im_generate() just attaches the * start/generate/stop callbacks and returns. * - * For "t" images, memory is allocated for the image and im_prepare_thread() - * used to fill it with pixels. + * For "t" images, memory is allocated for the whole image and it is entirely + * generated using vips_sink(). * * For "w" images, memory for a few scanlines is allocated and - * im_prepare_thread() used to generate the image in small chunks. As each + * vips_sink_disc() used to generate the image in small chunks. As each * chunk is generated, it is written to disc. * - * See also: im_iterate(), im_open(), im_prepare(), im_wrapone(). + * See also: vips_sink(), im_open(), im_prepare(), im_wrapone(). * * Returns: 0 on success, or -1 on error. */ @@ -525,8 +525,6 @@ im_generate( IMAGE *im, void *a, void *b ) { int res; - REGION *or; - im_threadgroup_t *tg; g_assert( !im_image_sanity( im ) ); @@ -596,24 +594,13 @@ im_generate( IMAGE *im, im->client1 = a; im->client2 = b; - /* Evaluate. Two output styles: to memory area (im_setbuf() - * or im_mmapinrw()) or to file (im_openout()). - */ - if( !(or = im_region_create( im )) ) - return( -1 ); - if( !(tg = im_threadgroup_create( im )) ) { - im_region_free( or ); - return( -1 ); - } if( im->dtype == IM_OPENOUT ) - res = im_wbuffer( tg, write_vips, NULL, NULL ); + res = vips_sink_disc( im, + (VipsRegionWrite) write_vips, NULL ); + /* else res = eval_to_memory( tg, or ); - - /* Clean up. - */ - im_threadgroup_free( tg ); - im_region_free( or ); + */ /* Error? */ @@ -638,58 +625,3 @@ im_generate( IMAGE *im, return( 0 ); } -/** - * im_prepare_thread: - * @tg: group of threads to evaluate with - * @reg: region to prepare - * @r: #Rect of pixels you need to be able to address - * - * im_prepare_thread() fills @reg with pixels. After calling, you can address - * at - * least the area @r with IM_REGION_ADDR() and get valid pixels. - * - * im_prepare_thread() uses @tg, a group of threads, to calculate pixels. - * Computation blocks until the pixels are ready. - * - * Use im_prepare() to calculate an area of pixels in-line. - * Use im_render_priority() to calculate an area of pixels in the background. - * - * See also: im_prepare(), im_render_priority(), im_prepare_to(). - * - * Returns: 0 on success, or -1 on error - */ -int -im_prepare_thread( im_threadgroup_t *tg, REGION *or, Rect *r ) -{ - IMAGE *im = or->im; - - g_assert( !im_image_sanity( im ) ); - - switch( im->dtype ) { - case IM_PARTIAL: - if( im_region_fill( or, r, - (im_region_fill_fn) eval_to_region, tg ) ) - return( -1 ); - - break; - - case IM_OPENIN: - case IM_SETBUF: - case IM_SETBUF_FOREIGN: - case IM_MMAPIN: - case IM_MMAPINRW: - /* Attach to existing buffer. - */ - if( im_region_image( or, r ) ) - return( -1 ); - - break; - - default: - im_error( "im_prepare_thread", _( "unable to input from a %s " - "image" ), im_dtype2char( im->dtype ) ); - return( -1 ); - } - - return( 0 ); -} diff --git a/libvips/iofuncs/sinkmemory.c b/libvips/iofuncs/sinkmemory.c new file mode 100644 index 00000000..35d20a88 --- /dev/null +++ b/libvips/iofuncs/sinkmemory.c @@ -0,0 +1,189 @@ +/* Write an image to a memory buffer. + * + * 16/4/10 + * - from vips_sink() + */ + +/* + + 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 VIPS_DEBUG + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef WITH_DMALLOC +#include +#endif /*WITH_DMALLOC*/ + +/* Per-call state. + */ +typedef struct _Sink { + VipsImage *im; + + /* The position we're at in the image. + */ + int x; + int y; + + /* The tilesize we've picked. + */ + int tile_width; + int tile_height; + int nlines; +} Sink; + +static int +sink_init( Sink *sink, VipsImage *im ) +{ + sink->im = im; + sink->x = 0; + sink->y = 0; + + vips_get_tile_size( im, + &sink->tile_width, &sink->tile_height, &sink->nlines ); + + return( 0 ); +} + +static int +sink_allocate( VipsThreadState *state, void *a, gboolean *stop ) +{ + Sink *sink = (Sink *) a; + + Rect image, tile; + + /* Is the state x/y OK? New line or maybe all done. + */ + if( sink->x >= sink->im->Xsize ) { + sink->x = 0; + sink->y += sink->tile_height; + + if( sink->y >= sink->im->Ysize ) { + *stop = TRUE; + + return( 0 ); + } + } + + /* x, y and buf are good: save params for thread. + */ + image.left = 0; + image.top = 0; + image.width = sink->im->Xsize; + image.height = sink->im->Ysize; + tile.left = sink->x; + tile.top = sink->y; + tile.width = sink->tile_width; + tile.height = sink->tile_height; + im_rect_intersectrect( &image, &tile, &state->pos ); + + /* Move state on. + */ + sink->x += sink->tile_width; + + return( 0 ); +} + +static int +sink_work( VipsThreadState *state, void *a ) +{ + Sink *sink = (Sink *) a; + + if( im_prepare_to( state->reg, &state->pos ) ) + return( -1 ); + + return( 0 ); +} + +static int +sink_progress( void *a ) +{ + Sink *sink = (Sink *) a; + + /* Trigger any eval callbacks on our source image and + * check for errors. + */ + if( im__handle_eval( sink->im, + sink->tile_width, sink->tile_height ) ) + return( -1 ); + + return( 0 ); +} + +/** + * vips_sink_memory: + * @im: generate this image to memory + * + * Loops over an image, generating it to a memory buffer attached to the + * image. + * + * See also: vips_sink(), vips_get_tile_size(). + * + * Returns: 0 on success, or -1 on error. + */ +int +vips_sink_memory( VipsImage *im ) +{ + Sink sink; + int result; + + g_assert( !im_image_sanity( im ) ); + + /* We don't use this, but make sure it's set in case any old binaries + * are expecting it. + */ + im->Bbits = im_bits_of_fmt( im->BandFmt ); + + if( sink_init( &sink ) ) + return( -1 ); + + if( im__start_eval( im ) ) + return( -1 ); + + result = vips_threadpool_run( im, + vips_thread_state_new, + sink_allocate, + sink_work, + sink_progress, + &sink ); + + im__end_eval( im ); + + return( result ); +}