From ce03da8c71836965237b756dc98dd8e135a5b871 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sat, 2 Apr 2011 16:39:20 +0100 Subject: [PATCH] now compiles with new add.c compiles, but not tested --- libvips/arithmetic/Makefile.am | 1 + libvips/arithmetic/add.c | 97 ++++++++++----------------------- libvips/arithmetic/arithmetic.c | 84 +++++++++++++++++++++++++++- libvips/arithmetic/arithmetic.h | 26 +++++++-- libvips/arithmetic/binary.c | 34 ++++++------ libvips/arithmetic/binary.h | 12 ++-- 6 files changed, 160 insertions(+), 94 deletions(-) diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am index d5498ef0..a98ae8e2 100644 --- a/libvips/arithmetic/Makefile.am +++ b/libvips/arithmetic/Makefile.am @@ -27,6 +27,7 @@ libarithmetic_la_SOURCES = \ math.c \ arithmetic.c \ binary.c \ + add.c \ power.c \ round.c diff --git a/libvips/arithmetic/add.c b/libvips/arithmetic/add.c index 15e52a29..6805181d 100644 --- a/libvips/arithmetic/add.c +++ b/libvips/arithmetic/add.c @@ -34,7 +34,7 @@ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ -#include +#include #include #include @@ -73,33 +73,33 @@ typedef VipsBinaryClass VipsAddClass; G_DEFINE_TYPE( VipsAdd, vips_add, VIPS_TYPE_BINARY ); #define LOOP( IN, OUT ) { \ - IN *p1 = (IN *) in[0]; \ - IN *p2 = (IN *) in[1]; \ + IN *p1 = (IN *) left; \ + IN *p2 = (IN *) right; \ OUT *q = (OUT *) out; \ \ for( x = 0; x < sz; x++ ) \ q[x] = p1[x] + p2[x]; \ } -static VipsVector *add_vectors[VIPS_FORMAT_LAST] = { NULL }; - static void -add_buffer( PEL **in, PEL *out, int width, IMAGE *im ) +add_buffer( VipsBinary *binary, PEL *out, PEL *left, PEL *right, int width ) { + VipsArithmeticClass *class = VIPS_ARITHMETIC_GET_CLASS( binary ); + VipsImage *im = binary->left_processed; + /* Complex just doubles the size. */ const int sz = width * im->Bands * - (vips_bandfmt_iscomplex( im->BandFmt ) ? 2 : 1); + (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); - if( vips_vector_get_enabled() && - add_vectors[im->BandFmt] ) { - VipsVector *vector = add_vectors[im->BandFmt]; + VipsVector *v; + if( (v = vips_arithmetic_get_vector( class, im->BandFmt )) ) { VipsExecutor ex; - vips_executor_set_program( &ex, vector, sz ); - vips_executor_set_array( &ex, vector->s[0], in[0] ); - vips_executor_set_array( &ex, vector->s[1], in[1] ); + vips_executor_set_program( &ex, v, sz ); + vips_executor_set_array( &ex, v->s[0], left ); + vips_executor_set_array( &ex, v->s[1], right ); vips_executor_set_destination( &ex, out ); vips_executor_run( &ex ); @@ -151,47 +151,6 @@ add_buffer( PEL **in, PEL *out, int width, IMAGE *im ) #define D IM_BANDFMT_DOUBLE #define DX IM_BANDFMT_DPCOMPLEX -VipsVector * -im__init_program( VipsVector *vectors[IM_BANDFMT_LAST], - VipsBandFmt format_table[IM_BANDFMT_LAST], VipsBandFmt fmt ) -{ - int isize = im__sizeof_bandfmt[fmt]; - int osize = im__sizeof_bandfmt[format_table[fmt]]; - - VipsVector *v; - - v = vips_vector_new( "binary arith", osize ); - - vips_vector_source_name( v, "s1", isize ); - vips_vector_source_name( v, "s2", isize ); - vips_vector_temporary( v, "t1", osize ); - vips_vector_temporary( v, "t2", osize ); - - vectors[fmt] = v; - - return( v ); -} - -void -im__compile_programs( VipsVector *vectors[IM_BANDFMT_LAST] ) -{ - int fmt; - - for( fmt = 0; fmt < IM_BANDFMT_LAST; fmt++ ) { - if( vectors[fmt] && - !vips_vector_compile( vectors[fmt] ) ) - IM_FREEF( vips_vector_free, vectors[fmt] ); - } - -#ifdef DEBUG - printf( "im__compile_programs: " ); - for( fmt = 0; fmt < IM_BANDFMT_LAST; fmt++ ) - if( vectors[fmt] ) - printf( "%s ", im_BandFmt2char( fmt ) ); - printf( "\n" ); -#endif /*DEBUG*/ -} - /* Type promotion for addition. Sign and value preserving. Make sure these * match the case statement in add_buffer() above. */ @@ -201,32 +160,30 @@ static int bandfmt_add[10] = { }; static void -build_programs( void ) +vips_add_class_init( VipsAddClass *class ) { - static gboolean done = FALSE; - + VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS( class ); + VipsBinaryClass *bclass = VIPS_BINARY_CLASS( class ); VipsVector *v; - if( done ) - return; - done = TRUE; + vips_arithmetic_set_format_table( aclass, bandfmt_add ); - v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_UCHAR ); + v = vips_arithmetic_get_program( aclass, VIPS_FORMAT_UCHAR ); vips_vector_asm2( v, "convubw", "t1", "s1" ); vips_vector_asm2( v, "convubw", "t2", "s2" ); vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); - v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_CHAR ); + v = vips_arithmetic_get_program( aclass, VIPS_FORMAT_CHAR ); vips_vector_asm2( v, "convsbw", "t1", "s1" ); vips_vector_asm2( v, "convsbw", "t2", "s2" ); vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); - v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_USHORT ); + v = vips_arithmetic_get_program( aclass, VIPS_FORMAT_USHORT ); vips_vector_asm2( v, "convuwl", "t1", "s1" ); vips_vector_asm2( v, "convuwl", "t2", "s2" ); vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); - v = im__init_program( add_vectors, bandfmt_add, IM_BANDFMT_SHORT ); + v = vips_arithmetic_get_program( aclass, VIPS_FORMAT_SHORT ); vips_vector_asm2( v, "convswl", "t1", "s1" ); vips_vector_asm2( v, "convswl", "t2", "s2" ); vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); @@ -237,14 +194,20 @@ build_programs( void ) float/double/complex are not handled well - v = im__init_program( add_vectors, IM_BANDFMT_UINT ); + v = vips_arithmetic_get_vector( aclass, VIPS_FORMAT_UINT ); vips_vector_asm3( v, "addl", "d1", "s1", "s2" ); - v = im__init_program( add_vectors, IM_BANDFMT_INT ); + v = vips_arithmetic_get_vector( aclass, VIPS_FORMAT_INT ); vips_vector_asm3( v, "addl", "d1", "s1", "s2" ); */ - im__compile_programs( add_vectors ); + vips_arithmetic_compile( aclass ); + + bclass->process_line = add_buffer; } +static void +vips_add_init( VipsAdd *add ) +{ +} diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index 79f43c7f..fec0a8d6 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -43,7 +43,7 @@ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ -#include +#include #include #include @@ -69,8 +69,6 @@ G_DEFINE_ABSTRACT_TYPE( VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION ); static int vips_arithmetic_build( VipsObject *object ) { - VipsArithmetic *arithmetic = VIPS_ARITHMETIC (object); - if( VIPS_OBJECT_CLASS( vips_arithmetic_parent_class )->build( object ) ) return( -1 ); @@ -110,6 +108,85 @@ vips_arithmetic_init( VipsArithmetic *arithmetic ) { } +void +vips_arithmetic_set_format_table( VipsArithmeticClass *class, + VipsBandFormat *format_table ) +{ + int i; + + g_assert( !class->format_table ); + + class->format_table = format_table; + + for( i = 0; i < VIPS_FORMAT_LAST; i++ ) { + int isize = vips_format_sizeof( i ); + int osize = vips_format_sizeof( (int) format_table[i] ); + + VipsVector *v; + + v = vips_vector_new( "arithmetic", osize ); + + vips_vector_source_name( v, "s1", isize ); + vips_vector_source_name( v, "s2", isize ); + vips_vector_temporary( v, "t1", osize ); + vips_vector_temporary( v, "t2", osize ); + + class->vectors[i] = v; + } +} + +/* Get the stub for this program ... use _get_vector() to get the compiled + * code. + */ +VipsVector * +vips_arithmetic_get_program( VipsArithmeticClass *class, VipsBandFormat fmt ) +{ + g_assert( (int) fmt >= 0 && (int) fmt < VIPS_FORMAT_LAST ); + g_assert( !class->vector_program[fmt] ); + + class->vector_program[fmt] = TRUE; + + return( class->vectors[fmt] ); +} + +/* Get the compiled code for this type, if available. + */ +VipsVector * +vips_arithmetic_get_vector( VipsArithmeticClass *class, VipsBandFormat fmt ) +{ + g_assert( fmt >= 0 && fmt < VIPS_FORMAT_LAST ); + + if( !vips_vector_get_enabled() || + !class->vector_program[fmt] ) + return( NULL ); + + return( class->vectors[fmt] ); +} + +void +vips_arithmetic_compile( VipsArithmeticClass *class ) +{ + int i; + + g_assert( class->format_table ); + + for( i = 0; i < VIPS_FORMAT_LAST; i++ ) + if( class->vector_program[i] && + !vips_vector_compile( class->vectors[i] ) ) + /* If compilation fails, turn off the vector for this + * type. + */ + class->vector_program[i] = FALSE; + +#ifdef DEBUG + printf( "vips_arithmetic_compile: " ); + for( i = 0; i < IM_BANDFMT_LAST; i++ ) + if( class->vector_program[i] ) + printf( "%s ", VIPS_ENUM_NICK( VIPS_TYPE_FORMAT, i ) ); + printf( "\n" ); +#endif /*DEBUG*/ +} + /* Called from iofuncs to init all operations in this dir. Use a plugin system * instead? */ @@ -120,3 +197,4 @@ vips_arithmetic_operation_init( void ) vips_add_get_type(); } + diff --git a/libvips/arithmetic/arithmetic.h b/libvips/arithmetic/arithmetic.h index 50bc233e..2ac83b9c 100644 --- a/libvips/arithmetic/arithmetic.h +++ b/libvips/arithmetic/arithmetic.h @@ -34,6 +34,8 @@ extern "C" { #endif /*__cplusplus*/ +#include + #define VIPS_TYPE_ARITHMETIC (vips_arithmetic_get_type()) #define VIPS_ARITHMETIC( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ @@ -56,19 +58,35 @@ typedef struct _VipsArithmetic { */ VipsImage *output; - /* For each input format, what output format. Used for arithmetic - * too, since we cast inputs to match. - */ - VipsFormat *cast_table; } VipsArithmetic; typedef struct _VipsArithmeticClass { VipsOperationClass parent_class; + /* For each input format, what output format. Used for arithmetic + * too, since we cast inputs to match. + */ + VipsBandFormat *format_table; + + /* A vector program for each input type. + */ + VipsVector *vectors[VIPS_FORMAT_LAST]; + + /* ... and if we've set a program for this format. + */ + gboolean vector_program[VIPS_FORMAT_LAST]; } VipsArithmeticClass; GType vips_arithmetic_get_type( void ); +void vips_arithmetic_set_format_table( VipsArithmeticClass *klass, + VipsBandFormat *format_table ); +VipsVector *vips_arithmetic_get_vector( VipsArithmeticClass *klass, + VipsBandFormat fmt ); +void vips_arithmetic_compile( VipsArithmeticClass *klass ); +VipsVector *vips_arithmetic_get_program( VipsArithmeticClass *klass, + VipsBandFormat fmt ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/arithmetic/binary.c b/libvips/arithmetic/binary.c index 84a3d828..c65f3e34 100644 --- a/libvips/arithmetic/binary.c +++ b/libvips/arithmetic/binary.c @@ -34,7 +34,7 @@ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ -#include +#include #include #include @@ -75,7 +75,7 @@ G_DEFINE_ABSTRACT_TYPE( VipsBinary, vips_binary, VIPS_TYPE_ARITHMETIC ); /* For two integer types, the "largest", ie. one which can represent the * full range of both. */ -static VipsFormat format_largest[6][6] = { +static VipsBandFormat format_largest[6][6] = { /* UC C US S UI I */ /* UC */ { UC, S, US, S, UI, I }, /* C */ { S, C, I, S, I, I }, @@ -87,11 +87,11 @@ static VipsFormat format_largest[6][6] = { /* For two formats, find one which can represent the full range of both. */ -static VipsFormat -vips_format_common( VipsFormat a, VipsFormat b ) +static VipsBandFormat +vips_format_common( VipsBandFormat a, VipsBandFormat b ) { - if( vips_format_iscomplex( a ) || - vips_format_iscomplex( b ) ) { + if( vips_band_format_iscomplex( a ) || + vips_band_format_iscomplex( b ) ) { if( a == VIPS_FORMAT_DPCOMPLEX || b == VIPS_FORMAT_DPCOMPLEX ) return( VIPS_FORMAT_DPCOMPLEX ); @@ -99,8 +99,8 @@ vips_format_common( VipsFormat a, VipsFormat b ) return( VIPS_FORMAT_COMPLEX ); } - else if( vips_format_isfloat( a ) || - vips_format_isfloat( b ) ) { + else if( vips_band_format_isfloat( a ) || + vips_band_format_isfloat( b ) ) { if( a == VIPS_FORMAT_DOUBLE || b == VIPS_FORMAT_DOUBLE ) return( VIPS_FORMAT_DOUBLE ); @@ -115,13 +115,13 @@ int vips__formatalike_vec( VipsImage **in, VipsImage **out, int n ) { int i; - VipsFormat format; + VipsBandFormat format; g_assert( n >= 1 ); format = in[0]->BandFmt; for( i = 1; i < n; i++ ) - fmt = vips_format_common( format, in[i]->BandFmt ); + format = vips_format_common( format, in[i]->BandFmt ); for( i = 0; i < n; i++ ) if( im_clip2fmt( in[i], out[i], format ) ) @@ -219,6 +219,7 @@ vips_binary_process_region( VipsRegion *or, void *seq, void *a, void *b ) { VipsRegion **ir = (VipsRegion **) seq; VipsBinary *binary = VIPS_BINARY( b ); + VipsBinaryClass *class = VIPS_BINARY_GET_CLASS( binary ); PEL *p[MAX_INPUT_IMAGES], *q; int i, y; @@ -237,7 +238,7 @@ vips_binary_process_region( VipsRegion *or, void *seq, void *a, void *b ) for( y = 0; y < or->valid.height; y++ ) { /* Bizarre double-cast stops a bogus gcc 4.1 compiler warning. */ - binary->process_line( binary, q, p[0], p[1], or->valid.width ); + class->process_line( binary, q, p[0], p[1], or->valid.width ); for( i = 0; ir[i]; i++ ) p[i] += VIPS_REGION_LSKIP( ir[i] ); @@ -253,6 +254,7 @@ vips_binary_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); const char *domain = class->description; VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); + VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); VipsBinary *binary = VIPS_BINARY( object ); VipsImage *t[5]; @@ -284,15 +286,15 @@ vips_binary_build( VipsObject *object ) /* Hint demand style. Being a buffer processor, we are happiest with * thin strips. */ - if( vips_demand_hint_array( binary->output, + if( vips_demand_hint_array( arithmetic->output, VIPS_DEMAND_STYLE_THINSTRIP, t + 2 ) || - vips_image_copy_fields_array( binary->output, t + 2 ) ) + vips_image_copy_fields_array( arithmetic->output, t + 2 ) ) return( -1 ); - binary->output->Bands = t[2]->Bands; - binary->output->BandFmt = arithmetic->cast_table[t[2]->BandFmt]; + arithmetic->output->Bands = t[2]->Bands; + arithmetic->output->BandFmt = aclass->format_table[t[2]->BandFmt]; - if( vips_image_generate( binary->output, + if( vips_image_generate( arithmetic->output, vips_start_many, vips_binary_process_region, vips_stop_many, t + 2, binary ) ) diff --git a/libvips/arithmetic/binary.h b/libvips/arithmetic/binary.h index 88fbd893..6d0e1a46 100644 --- a/libvips/arithmetic/binary.h +++ b/libvips/arithmetic/binary.h @@ -46,8 +46,9 @@ extern "C" { #define VIPS_BINARY_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_BINARY, VipsBinaryClass )) -typedef void (*VipsBinaryProcessFn)( VipsBinary *binary, - void *out, void *left, void *right, int width ); +struct _VipsBinary; +typedef void (*VipsBinaryProcessFn)( struct _VipsBinary *binary, + PEL *out, PEL *left, PEL *right, int width ); typedef struct _VipsBinary { VipsArithmetic parent_instance; @@ -66,9 +67,8 @@ typedef struct _VipsBinary { VipsImage *left_processed; VipsImage *right_processed; - /* The line processor, plus some client data. + /* Some client data for the line processor, if it wants it. */ - VipsBinaryProcessFn process_line; void *a; void *b; } VipsBinary; @@ -76,6 +76,10 @@ typedef struct _VipsBinary { typedef struct _VipsBinaryClass { VipsArithmeticClass parent_class; + /* The line processor. + */ + VipsBinaryProcessFn process_line; + } VipsBinaryClass; GType vips_binary_get_type( void );