now compiles with new add.c

compiles, but not tested
This commit is contained in:
John Cupitt 2011-04-02 16:39:20 +01:00
parent 370641d25b
commit ce03da8c71
6 changed files with 160 additions and 94 deletions

View File

@ -27,6 +27,7 @@ libarithmetic_la_SOURCES = \
math.c \ math.c \
arithmetic.c \ arithmetic.c \
binary.c \ binary.c \
add.c \
power.c \ power.c \
round.c round.c

View File

@ -34,7 +34,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips8/intl.h> #include <vips/intl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -73,33 +73,33 @@ typedef VipsBinaryClass VipsAddClass;
G_DEFINE_TYPE( VipsAdd, vips_add, VIPS_TYPE_BINARY ); G_DEFINE_TYPE( VipsAdd, vips_add, VIPS_TYPE_BINARY );
#define LOOP( IN, OUT ) { \ #define LOOP( IN, OUT ) { \
IN *p1 = (IN *) in[0]; \ IN *p1 = (IN *) left; \
IN *p2 = (IN *) in[1]; \ IN *p2 = (IN *) right; \
OUT *q = (OUT *) out; \ OUT *q = (OUT *) out; \
\ \
for( x = 0; x < sz; x++ ) \ for( x = 0; x < sz; x++ ) \
q[x] = p1[x] + p2[x]; \ q[x] = p1[x] + p2[x]; \
} }
static VipsVector *add_vectors[VIPS_FORMAT_LAST] = { NULL };
static void 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. /* Complex just doubles the size.
*/ */
const int sz = width * im->Bands * 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() && VipsVector *v;
add_vectors[im->BandFmt] ) {
VipsVector *vector = add_vectors[im->BandFmt];
if( (v = vips_arithmetic_get_vector( class, im->BandFmt )) ) {
VipsExecutor ex; VipsExecutor ex;
vips_executor_set_program( &ex, vector, sz ); vips_executor_set_program( &ex, v, sz );
vips_executor_set_array( &ex, vector->s[0], in[0] ); vips_executor_set_array( &ex, v->s[0], left );
vips_executor_set_array( &ex, vector->s[1], in[1] ); vips_executor_set_array( &ex, v->s[1], right );
vips_executor_set_destination( &ex, out ); vips_executor_set_destination( &ex, out );
vips_executor_run( &ex ); vips_executor_run( &ex );
@ -151,47 +151,6 @@ add_buffer( PEL **in, PEL *out, int width, IMAGE *im )
#define D IM_BANDFMT_DOUBLE #define D IM_BANDFMT_DOUBLE
#define DX IM_BANDFMT_DPCOMPLEX #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 /* Type promotion for addition. Sign and value preserving. Make sure these
* match the case statement in add_buffer() above. * match the case statement in add_buffer() above.
*/ */
@ -201,32 +160,30 @@ static int bandfmt_add[10] = {
}; };
static void 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; VipsVector *v;
if( done ) vips_arithmetic_set_format_table( aclass, bandfmt_add );
return;
done = TRUE;
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", "t1", "s1" );
vips_vector_asm2( v, "convubw", "t2", "s2" ); vips_vector_asm2( v, "convubw", "t2", "s2" );
vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); 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", "t1", "s1" );
vips_vector_asm2( v, "convsbw", "t2", "s2" ); vips_vector_asm2( v, "convsbw", "t2", "s2" );
vips_vector_asm3( v, "addw", "d1", "t1", "t2" ); 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", "t1", "s1" );
vips_vector_asm2( v, "convuwl", "t2", "s2" ); vips_vector_asm2( v, "convuwl", "t2", "s2" );
vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); 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", "t1", "s1" );
vips_vector_asm2( v, "convswl", "t2", "s2" ); vips_vector_asm2( v, "convswl", "t2", "s2" );
vips_vector_asm3( v, "addl", "d1", "t1", "t2" ); vips_vector_asm3( v, "addl", "d1", "t1", "t2" );
@ -237,14 +194,20 @@ build_programs( void )
float/double/complex are not handled well 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" ); 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" ); 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 )
{
}

View File

@ -43,7 +43,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips8/intl.h> #include <vips/intl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -69,8 +69,6 @@ G_DEFINE_ABSTRACT_TYPE( VipsArithmetic, vips_arithmetic, VIPS_TYPE_OPERATION );
static int static int
vips_arithmetic_build( VipsObject *object ) vips_arithmetic_build( VipsObject *object )
{ {
VipsArithmetic *arithmetic = VIPS_ARITHMETIC (object);
if( VIPS_OBJECT_CLASS( vips_arithmetic_parent_class )->build( object ) ) if( VIPS_OBJECT_CLASS( vips_arithmetic_parent_class )->build( object ) )
return( -1 ); 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 /* Called from iofuncs to init all operations in this dir. Use a plugin system
* instead? * instead?
*/ */
@ -120,3 +197,4 @@ vips_arithmetic_operation_init( void )
vips_add_get_type(); vips_add_get_type();
} }

View File

@ -34,6 +34,8 @@
extern "C" { extern "C" {
#endif /*__cplusplus*/ #endif /*__cplusplus*/
#include <vips/vector.h>
#define VIPS_TYPE_ARITHMETIC (vips_arithmetic_get_type()) #define VIPS_TYPE_ARITHMETIC (vips_arithmetic_get_type())
#define VIPS_ARITHMETIC( obj ) \ #define VIPS_ARITHMETIC( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \
@ -56,19 +58,35 @@ typedef struct _VipsArithmetic {
*/ */
VipsImage *output; VipsImage *output;
/* For each input format, what output format. Used for arithmetic
* too, since we cast inputs to match.
*/
VipsFormat *cast_table;
} VipsArithmetic; } VipsArithmetic;
typedef struct _VipsArithmeticClass { typedef struct _VipsArithmeticClass {
VipsOperationClass parent_class; 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; } VipsArithmeticClass;
GType vips_arithmetic_get_type( void ); 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 #ifdef __cplusplus
} }
#endif /*__cplusplus*/ #endif /*__cplusplus*/

View File

@ -34,7 +34,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips8/intl.h> #include <vips/intl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -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 /* For two integer types, the "largest", ie. one which can represent the
* full range of both. * full range of both.
*/ */
static VipsFormat format_largest[6][6] = { static VipsBandFormat format_largest[6][6] = {
/* UC C US S UI I */ /* UC C US S UI I */
/* UC */ { UC, S, US, S, UI, I }, /* UC */ { UC, S, US, S, UI, I },
/* C */ { S, C, I, S, I, 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. /* For two formats, find one which can represent the full range of both.
*/ */
static VipsFormat static VipsBandFormat
vips_format_common( VipsFormat a, VipsFormat b ) vips_format_common( VipsBandFormat a, VipsBandFormat b )
{ {
if( vips_format_iscomplex( a ) || if( vips_band_format_iscomplex( a ) ||
vips_format_iscomplex( b ) ) { vips_band_format_iscomplex( b ) ) {
if( a == VIPS_FORMAT_DPCOMPLEX || if( a == VIPS_FORMAT_DPCOMPLEX ||
b == VIPS_FORMAT_DPCOMPLEX ) b == VIPS_FORMAT_DPCOMPLEX )
return( VIPS_FORMAT_DPCOMPLEX ); return( VIPS_FORMAT_DPCOMPLEX );
@ -99,8 +99,8 @@ vips_format_common( VipsFormat a, VipsFormat b )
return( VIPS_FORMAT_COMPLEX ); return( VIPS_FORMAT_COMPLEX );
} }
else if( vips_format_isfloat( a ) || else if( vips_band_format_isfloat( a ) ||
vips_format_isfloat( b ) ) { vips_band_format_isfloat( b ) ) {
if( a == VIPS_FORMAT_DOUBLE || if( a == VIPS_FORMAT_DOUBLE ||
b == VIPS_FORMAT_DOUBLE ) b == VIPS_FORMAT_DOUBLE )
return( VIPS_FORMAT_DOUBLE ); return( VIPS_FORMAT_DOUBLE );
@ -115,13 +115,13 @@ int
vips__formatalike_vec( VipsImage **in, VipsImage **out, int n ) vips__formatalike_vec( VipsImage **in, VipsImage **out, int n )
{ {
int i; int i;
VipsFormat format; VipsBandFormat format;
g_assert( n >= 1 ); g_assert( n >= 1 );
format = in[0]->BandFmt; format = in[0]->BandFmt;
for( i = 1; i < n; i++ ) 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++ ) for( i = 0; i < n; i++ )
if( im_clip2fmt( in[i], out[i], format ) ) 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; VipsRegion **ir = (VipsRegion **) seq;
VipsBinary *binary = VIPS_BINARY( b ); VipsBinary *binary = VIPS_BINARY( b );
VipsBinaryClass *class = VIPS_BINARY_GET_CLASS( binary );
PEL *p[MAX_INPUT_IMAGES], *q; PEL *p[MAX_INPUT_IMAGES], *q;
int i, y; 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++ ) { for( y = 0; y < or->valid.height; y++ ) {
/* Bizarre double-cast stops a bogus gcc 4.1 compiler warning. /* 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++ ) for( i = 0; ir[i]; i++ )
p[i] += VIPS_REGION_LSKIP( ir[i] ); p[i] += VIPS_REGION_LSKIP( ir[i] );
@ -253,6 +254,7 @@ vips_binary_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
const char *domain = class->description; const char *domain = class->description;
VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object );
VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic );
VipsBinary *binary = VIPS_BINARY( object ); VipsBinary *binary = VIPS_BINARY( object );
VipsImage *t[5]; VipsImage *t[5];
@ -284,15 +286,15 @@ vips_binary_build( VipsObject *object )
/* Hint demand style. Being a buffer processor, we are happiest with /* Hint demand style. Being a buffer processor, we are happiest with
* thin strips. * thin strips.
*/ */
if( vips_demand_hint_array( binary->output, if( vips_demand_hint_array( arithmetic->output,
VIPS_DEMAND_STYLE_THINSTRIP, t + 2 ) || 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 ); return( -1 );
binary->output->Bands = t[2]->Bands; arithmetic->output->Bands = t[2]->Bands;
binary->output->BandFmt = arithmetic->cast_table[t[2]->BandFmt]; 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_start_many, vips_binary_process_region,
vips_stop_many, vips_stop_many,
t + 2, binary ) ) t + 2, binary ) )

View File

@ -46,8 +46,9 @@ extern "C" {
#define VIPS_BINARY_GET_CLASS( obj ) \ #define VIPS_BINARY_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_BINARY, VipsBinaryClass )) (G_TYPE_INSTANCE_GET_CLASS( (obj), VIPS_TYPE_BINARY, VipsBinaryClass ))
typedef void (*VipsBinaryProcessFn)( VipsBinary *binary, struct _VipsBinary;
void *out, void *left, void *right, int width ); typedef void (*VipsBinaryProcessFn)( struct _VipsBinary *binary,
PEL *out, PEL *left, PEL *right, int width );
typedef struct _VipsBinary { typedef struct _VipsBinary {
VipsArithmetic parent_instance; VipsArithmetic parent_instance;
@ -66,9 +67,8 @@ typedef struct _VipsBinary {
VipsImage *left_processed; VipsImage *left_processed;
VipsImage *right_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 *a;
void *b; void *b;
} VipsBinary; } VipsBinary;
@ -76,6 +76,10 @@ typedef struct _VipsBinary {
typedef struct _VipsBinaryClass { typedef struct _VipsBinaryClass {
VipsArithmeticClass parent_class; VipsArithmeticClass parent_class;
/* The line processor.
*/
VipsBinaryProcessFn process_line;
} VipsBinaryClass; } VipsBinaryClass;
GType vips_binary_get_type( void ); GType vips_binary_get_type( void );