new subimage code for composite done!

seems to work, passes all tests
This commit is contained in:
John Cupitt 2018-12-07 16:11:58 +00:00
parent 58776970ec
commit 2a32a95be9
2 changed files with 84 additions and 21 deletions

View File

@ -123,6 +123,11 @@ typedef struct _VipsCompositeBase {
*/
double max_band[MAX_BANDS + 1];
/* TRUE if all our modes are skippable, ie. we can avoid compositing
* the whole stack for every pixel request.
*/
gboolean skippable;
#ifdef HAVE_VECTOR_ARITH
/* max_band as a vector, for the RGBA case.
*/
@ -363,6 +368,25 @@ vips_composite_base_max_band( VipsCompositeBase *composite, double *max_band )
return( 0 );
}
/* Find the subset of our input images which intersect this region. If we are
* not in skippable mode, we must enable all layers.
*/
static void
vips_composite_base_select( VipsCompositeSequence *seq, VipsRect *r )
{
VipsCompositeBase *composite = seq->composite;
int n = composite->in->area.n;
seq->n = 0;
for( int i = 0; i < n; i++ )
if( !composite->skippable ||
vips_rect_overlapsrect( r,
&composite->subimages[i] ) ) {
seq->enabled[seq->n] = i;
seq->n += 1;
}
}
/* Cairo naming conventions:
*
* aR alpha of result
@ -967,22 +991,27 @@ vips_composite_base_gen( VipsRegion *output_region,
VipsCompositeBase *composite = (VipsCompositeBase *) b;
VipsRect *r = &output_region->valid;
int ps = VIPS_IMAGE_SIZEOF_PEL( output_region->im );
int n = composite->in->area.n;
/* Find the subset of our input images which intersect this region.
*/
seq->n = 0;
for( int i = 0; i < n; i++ )
if( vips_rect_overlapsrect( r, &composite->subimages[i] ) ) {
seq->enabled[seq->n] = i;
seq->n += 1;
}
vips_composite_base_select( seq, r );
/* FIXME ... just one? prepare directly to output and return.
/* Is there just one? We can prepare directly to output and return.
*/
if( seq->n == 1 ) {
/* This can only be the background image, since it's the only
* image which exactly fills the whole output.
*/
g_assert( seq->enabled[0] == 0 );
/* FIXME ... can use vips_rect_overlapsrect() elsewhere?
*/
if( vips_region_prepare( seq->input_regions[0], r ) )
return( -1 );
if( vips_region_region( output_region, seq->input_regions[0],
r, r->left, r->top ) )
return( -1 );
return( 0 );
}
/* Prepare the appropriate parts into our set of composite
* regions.
@ -990,14 +1019,17 @@ vips_composite_base_gen( VipsRegion *output_region,
for( int i = 0; i < seq->n; i++ ) {
int j = seq->enabled[i];
VipsRect hit;
VipsRect request;
/* Translate the request to the input image space, clipping as
* required.
/* Clip against this subimage position and size.
*/
request = *r;
vips_rect_intersectrect( &request, &composite->subimages[j],
&request );
hit = *r;
vips_rect_intersectrect( &hit, &composite->subimages[j], &hit );
/* Translate request to subimage coordinates.
*/
request = hit;
request.left -= composite->subimages[j].left;
request.top -= composite->subimages[j].top;
@ -1016,10 +1048,14 @@ vips_composite_base_gen( VipsRegion *output_region,
/* And render the right part of the input image to the
* composite region.
*
* If we are not in skippable mode, we can be completely
* outside the subimage area.
*/
if( vips_region_prepare_to( seq->input_regions[j],
seq->composite_regions[j], &request,
r->left, r->top ) )
if( !vips_rect_isempty( &request ) &&
vips_region_prepare_to( seq->input_regions[j],
seq->composite_regions[j], &request,
hit.left, hit.top ) )
return( -1 );
}
@ -1034,7 +1070,6 @@ vips_composite_base_gen( VipsRegion *output_region,
seq->p[i] = VIPS_REGION_ADDR( seq->composite_regions[j],
r->left, r->top + y );
}
seq->p[n] = NULL;
q = VIPS_REGION_ADDR( output_region, r->left, r->top + y );
for( int x = 0; x < r->width; x++ ) {
@ -1124,6 +1159,31 @@ vips_composite_base_gen( VipsRegion *output_region,
return( 0 );
}
/* Is a mode "skippable"?
*
* Skippable modes are ones where a black (0, 0, 0, 0) layer placed over the
* base image and composited has no effect.
*
* If all the modes in our stack are skippable, we can avoid compositing the
* whole stack for every request.
*/
static gboolean
vips_composite_mode_skippable( VipsBlendMode mode )
{
switch( mode ) {
case VIPS_BLEND_MODE_CLEAR:
case VIPS_BLEND_MODE_SOURCE:
case VIPS_BLEND_MODE_IN:
case VIPS_BLEND_MODE_OUT:
case VIPS_BLEND_MODE_DEST_IN:
case VIPS_BLEND_MODE_DEST_ATOP:
return( FALSE );
default:
return( TRUE );
}
}
static int
vips_composite_base_build( VipsObject *object )
{
@ -1155,6 +1215,7 @@ vips_composite_base_build( VipsObject *object )
return( -1 );
}
mode = (VipsBlendMode *) composite->mode->area.data;
composite->skippable = TRUE;
for( int i = 0; i < composite->mode->area.n; i++ ) {
if( mode[i] < 0 ||
mode[i] >= VIPS_BLEND_MODE_LAST ) {
@ -1163,6 +1224,9 @@ vips_composite_base_build( VipsObject *object )
i, mode[i] );
return( -1 );
}
if( !vips_composite_mode_skippable( mode[i] ) )
composite->skippable = FALSE;
}
in = (VipsImage **) composite->in->area.data;

View File

@ -1144,8 +1144,7 @@ strip_work( VipsThreadState *state, void *a )
tile.top = state->y;
tile.width = dz->tile_size;
tile.height = dz->tile_size;
vips_rect_intersectrect( &tile, &layer->real_pixels, &tile );
if( vips_rect_isempty( &tile ) ) {
if( !vips_rect_overlapsrect( &tile, &layer->real_pixels ) ) {
#ifdef DEBUG_VERBOSE
printf( "strip_work: skipping tile %d x %d\n",
state->x / dz->tile_size,