added sinkmemory, started removing threadgroup

This commit is contained in:
John Cupitt 2010-04-16 16:09:48 +00:00
parent 54730feadc
commit f1ebc12fb1
3 changed files with 201 additions and 76 deletions

4
TODO
View File

@ -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

View File

@ -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 );
}

View File

@ -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 <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/thread.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#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 );
}