add minimise to insert
This patch makes "insert" issue minimise signals for inputs in sequential mode. This can drop memory use in some programs, for example: ```python import sys import random import pyvips image = pyvips.Image.black(20000, 20000) for filename in sys.argv[2:]: tile = pyvips.Image.new_from_file(filename, access='sequential') x = random.randint(0, image.width - tile.width) y = random.randint(0, image.height - tile.height) image = image.insert(tile, x, y) image.write_to_file(sys.argv[1]) ``` Before this patch: ``` $ for i in {0..1000}; do cp ~/pics/k2.jpg $i.jpg; done $ /usr/bin/time -f %M:%e ../manyjoin.py ../x.jpg *.jpg 5456256:4.34 ``` With this patch: ``` $ /usr/bin/time -f %M:%e ../manyjoin.py ../x.jpg *.jpg 2475324:3.38 ```
This commit is contained in:
parent
41e92b9ada
commit
6f081de0a0
@ -19,6 +19,7 @@
|
||||
- add fail-on to give better control over loader error sensitivity
|
||||
- add hyperbolic functions sinh, cosh, tanh, asinh, acosh, atanh [hroskes]
|
||||
- add untiled jp2k load
|
||||
- "insert" will minimise in seq mode
|
||||
|
||||
16/8/21 started 8.11.4
|
||||
- fix off-by-one error in new rank fast path
|
||||
|
@ -129,13 +129,15 @@ vips_arrayjoin_gen( VipsRegion *or, void *seq,
|
||||
*
|
||||
* We don't lock for minimised[], but it's harmless.
|
||||
*/
|
||||
for( i = 0; i < n; i++ )
|
||||
for( i = 0; i < n; i++ ) {
|
||||
int bottom_edge = VIPS_RECT_BOTTOM( &join->rects[i] );
|
||||
|
||||
if( !join->minimised[i] &&
|
||||
r->top > VIPS_RECT_BOTTOM( &join->rects[i] ) +
|
||||
1024 ) {
|
||||
r->top > bottom_edge + 1024 ) {
|
||||
join->minimised[i] = TRUE;
|
||||
vips_image_minimise_all( in[i] );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -28,6 +28,8 @@
|
||||
* 29/9/11
|
||||
* - rewrite as a class
|
||||
* - add expand, bg options
|
||||
* 5/11/21
|
||||
* - add minimise for seq pipelines
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -93,20 +95,19 @@ typedef struct _VipsInsert {
|
||||
*/
|
||||
VipsPel *ink;
|
||||
|
||||
/* Inputs cast and banded up.
|
||||
/* Inputs cast and banded up, plus a NULL at the end.
|
||||
*/
|
||||
VipsImage *main_processed;
|
||||
VipsImage *sub_processed;
|
||||
VipsImage *processed[3];
|
||||
|
||||
/* Geometry.
|
||||
*/
|
||||
VipsRect rout; /* Output space */
|
||||
VipsRect rmain; /* Position of main in output */
|
||||
VipsRect rsub; /* Position of sub in output */
|
||||
VipsRect rimage[2]; /* Position of main in output */
|
||||
|
||||
/* TRUE if we've minimise sub.
|
||||
/* TRUE if we've minimised an input.
|
||||
*/
|
||||
gboolean sub_minimised;
|
||||
gboolean minimised[2];
|
||||
|
||||
} VipsInsert;
|
||||
|
||||
typedef VipsConversionClass VipsInsertClass;
|
||||
@ -174,47 +175,58 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
VipsRegion **ir = (VipsRegion **) seq;
|
||||
VipsRect *r = &or->valid;
|
||||
VipsInsert *insert = (VipsInsert *) b;
|
||||
VipsConversion *conversion = VIPS_CONVERSION( insert );
|
||||
|
||||
VipsRect ovl;
|
||||
int i;
|
||||
|
||||
/* The part of the subimage we will use.
|
||||
/* First, does this request fall entirely inside one of our inputs? If
|
||||
* it does, we can just redirect the request there. Test sub first.
|
||||
*/
|
||||
vips_rect_intersectrect( &or->valid, &insert->rsub, &ovl );
|
||||
for( i = 1; i >= 0; i-- ) {
|
||||
VipsRect *rimage = &insert->rimage[i];
|
||||
|
||||
/* Three cases: we are generating entirely within the sub-image,
|
||||
* entirely within the main image, or a mixture.
|
||||
if( vips_rect_includesrect( rimage, r ) ) {
|
||||
if( vips__insert_just_one( or, ir[i],
|
||||
rimage->left, rimage->top ) )
|
||||
return( -1 );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, it requires both (or neither) input.
|
||||
*/
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) ) {
|
||||
if( vips__insert_just_one( or, ir[1],
|
||||
insert->rsub.left, insert->rsub.top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
||||
vips_rect_isempty( &ovl ) ) {
|
||||
if( vips__insert_just_one( or, ir[0],
|
||||
insert->rmain.left, insert->rmain.top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( i < 0 ) {
|
||||
/* Output requires both (or neither) input. If it is not
|
||||
* entirely inside both the main and the sub, then there is
|
||||
* going to be some background.
|
||||
*/
|
||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
|
||||
/* Paste from main.
|
||||
/* Paste the background first.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
for( i = 0; i < 2; i++ )
|
||||
if( vips__insert_paste_region( or, ir[i],
|
||||
&insert->rimage[i] ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* See arrayjoin for almost this code again. Move into conversion.c?
|
||||
*/
|
||||
if( vips_image_is_sequential( conversion->out ) )
|
||||
for( i = 0; i < 2; i++ ) {
|
||||
int bottom_edge =
|
||||
VIPS_RECT_BOTTOM( &insert->rimage[i] );
|
||||
|
||||
/* 1024 is a generous margin. 256 is too small.
|
||||
*/
|
||||
if( !insert->minimised[i] &&
|
||||
r->top > bottom_edge + 1024 ) {
|
||||
insert->minimised[i] = TRUE;
|
||||
vips_image_minimise_all( insert->processed[i] );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -351,8 +363,6 @@ vips_insert_build( VipsObject *object )
|
||||
VipsInsert *insert = (VipsInsert *) object;
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 );
|
||||
|
||||
VipsImage **arry;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_insert_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
@ -370,48 +380,46 @@ vips_insert_build( VipsObject *object )
|
||||
if( vips__formatalike( insert->main, insert->sub, &t[0], &t[1] ) ||
|
||||
vips__bandalike( class->nickname, t[0], t[1], &t[2], &t[3] ) )
|
||||
return( -1 );
|
||||
insert->main_processed = t[2];
|
||||
insert->sub_processed = t[3];
|
||||
if( !(arry = vips_allocate_input_array( conversion->out,
|
||||
insert->main_processed, insert->sub_processed, NULL )) )
|
||||
return( -1 );
|
||||
insert->processed[0] = t[2];
|
||||
insert->processed[1] = t[3];
|
||||
|
||||
/* Joins can get very wide (eg. consider joining a set of tiles
|
||||
* horizontally to make a large image), we don't want mem use to shoot
|
||||
* up. SMALLTILE will guarantee we keep small and local.
|
||||
*/
|
||||
if( vips_image_pipeline_array( conversion->out,
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, arry ) )
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, insert->processed ) )
|
||||
return( -1 );
|
||||
|
||||
/* Calculate geometry.
|
||||
*/
|
||||
insert->rmain.left = 0;
|
||||
insert->rmain.top = 0;
|
||||
insert->rmain.width = insert->main_processed->Xsize;
|
||||
insert->rmain.height = insert->main_processed->Ysize;
|
||||
insert->rsub.left = insert->x;
|
||||
insert->rsub.top = insert->y;
|
||||
insert->rsub.width = insert->sub_processed->Xsize;
|
||||
insert->rsub.height = insert->sub_processed->Ysize;
|
||||
insert->rimage[0].left = 0;
|
||||
insert->rimage[0].top = 0;
|
||||
insert->rimage[0].width = insert->processed[0]->Xsize;
|
||||
insert->rimage[0].height = insert->processed[0]->Ysize;
|
||||
|
||||
insert->rimage[1].left = insert->x;
|
||||
insert->rimage[1].top = insert->y;
|
||||
insert->rimage[1].width = insert->processed[1]->Xsize;
|
||||
insert->rimage[1].height = insert->processed[1]->Ysize;
|
||||
|
||||
if( insert->expand ) {
|
||||
/* Expand output to bounding box of these two.
|
||||
*/
|
||||
vips_rect_unionrect( &insert->rmain, &insert->rsub,
|
||||
vips_rect_unionrect( &insert->rimage[0], &insert->rimage[1],
|
||||
&insert->rout );
|
||||
|
||||
/* Translate origin to top LH corner of rout.
|
||||
*/
|
||||
insert->rmain.left -= insert->rout.left;
|
||||
insert->rmain.top -= insert->rout.top;
|
||||
insert->rsub.left -= insert->rout.left;
|
||||
insert->rsub.top -= insert->rout.top;
|
||||
insert->rimage[0].left -= insert->rout.left;
|
||||
insert->rimage[0].top -= insert->rout.top;
|
||||
insert->rimage[1].left -= insert->rout.left;
|
||||
insert->rimage[1].top -= insert->rout.top;
|
||||
insert->rout.left = 0;
|
||||
insert->rout.top = 0;
|
||||
}
|
||||
else
|
||||
insert->rout = insert->rmain;
|
||||
insert->rout = insert->rimage[0];
|
||||
|
||||
conversion->out->Xsize = insert->rout.width;
|
||||
conversion->out->Ysize = insert->rout.height;
|
||||
@ -424,7 +432,7 @@ vips_insert_build( VipsObject *object )
|
||||
|
||||
if( vips_image_generate( conversion->out,
|
||||
vips_start_many, vips_insert_gen, vips_stop_many,
|
||||
arry, insert ) )
|
||||
insert->processed, insert ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
|
Loading…
Reference in New Issue
Block a user