From a8d04a7dd19ea8057ad01c284c7baa91a0726505 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 12 Jun 2014 09:22:28 +0100 Subject: [PATCH] add op invalidate stuff still need to test and link to cache --- ChangeLog | 1 + TODO | 8 +++++ libvips/include/vips/object.h | 5 +++ libvips/include/vips/operation.h | 6 ++++ libvips/iofuncs/object.c | 56 +++++++++++++++++++++++--------- libvips/iofuncs/operation.c | 26 +++++++++++++++ 6 files changed, 86 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f0b3c80..d14b06c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,7 @@ im_*mosaic1(), im_*merge1() redone as classes - better filename tracking for globalbalance - revised vips8 image load/save API, now simpler and more logical +- operations emit "invalidate" if any of their input images invalidate 6/3/14 started 7.38.6 - grey ramp minimum was wrong diff --git a/TODO b/TODO index 0f9a9b91..733c2be3 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,11 @@ +- test operation invalidate + + enable cache in nip2, find max using vips_call, try painting on the input + +- cache needs to listen for invalidate + + + - can we use postbuild elsewhere? look at use of "preclose" / "written", etc. diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index d16d16f5..e94c7de8 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -283,6 +283,11 @@ typedef struct _VipsArgumentInstance { * here. */ gulong close_id; + + /* We need to listen for "invalidate" on input images and send our own + * "invalidate" out. If we go, we need to disconnect. + */ + gulong invalidate_id; } VipsArgumentInstance; /* Need to look up our VipsArgument structs from a pspec. Just hash the diff --git a/libvips/include/vips/operation.h b/libvips/include/vips/operation.h index 0afb9a9d..acc9f354 100644 --- a/libvips/include/vips/operation.h +++ b/libvips/include/vips/operation.h @@ -92,12 +92,18 @@ typedef struct _VipsOperationClass { */ VipsOperationFlags (*get_flags)( VipsOperation * ); VipsOperationFlags flags; + + /* One of our input images has signalled "invalidate". The cache uses + * VipsOperation::invalidate to drop dirty ops. + */ + void (*invalidate)( VipsOperation * ); } VipsOperationClass; GType vips_operation_get_type( void ); VipsOperationFlags vips_operation_get_flags( VipsOperation *operation ); void vips_operation_class_print_usage( VipsOperationClass *operation_class ); +void vips_operation_invalidate( VipsOperation *operation ); int vips_operation_call_valist( VipsOperation *operation, va_list ap ); VipsOperation *vips_operation_new( const char *name ); diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index cf4176eb..1b2136be 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -392,16 +392,34 @@ vips_object_rewind( VipsObject *object ) /* Extra stuff we track for properties to do our argument handling. */ +static void +vips_argument_instance_detach( VipsArgumentInstance *argument_instance ) +{ + VipsObject *object = argument_instance->object; + + if( argument_instance->close_id ) { + if( g_signal_handler_is_connected( object, + argument_instance->close_id ) ) + g_signal_handler_disconnect( object, + argument_instance->close_id ); + argument_instance->close_id = 0; + } + + if( argument_instance->invalidate_id ) { + if( g_signal_handler_is_connected( object, + argument_instance->invalidate_id ) ) + g_signal_handler_disconnect( object, + argument_instance->invalidate_id ); + argument_instance->invalidate_id = 0; + } +} + /* Free a VipsArgumentInstance ... VipsArgumentClass can just be g_free()d. */ static void vips_argument_instance_free( VipsArgumentInstance *argument_instance ) { - if( argument_instance->close_id ) { - g_signal_handler_disconnect( argument_instance->object, - argument_instance->close_id ); - argument_instance->close_id = 0; - } + vips_argument_instance_detach( argument_instance ); g_free( argument_instance ); } @@ -580,6 +598,7 @@ vips_argument_init( VipsObject *object ) argument_class->flags & VIPS_ARGUMENT_SET_ALWAYS; argument_instance->close_id = 0; + argument_instance->invalidate_id = 0; vips_argument_table_replace( object->argument_table, (VipsArgument *) argument_instance ); @@ -729,6 +748,8 @@ vips_object_clear_member( VipsObject *object, GParamSpec *pspec, VipsArgumentInstance *argument_instance = vips__argument_get_instance( argument_class, object ); + vips_argument_instance_detach( argument_instance ); + if( *member ) { if( argument_class->flags & VIPS_ARGUMENT_INPUT ) { #ifdef DEBUG_REF @@ -754,17 +775,6 @@ vips_object_clear_member( VipsObject *object, GParamSpec *pspec, G_OBJECT( object )->ref_count - 1 ); #endif /*DEBUG_REF*/ - /* The object reffed us. Stop listening link to the - * object's "close" signal. We can come here from - * object being closed, in which case the handler - * will already have been disconnected for us. - */ - if( g_signal_handler_is_connected( object, - argument_instance->close_id ) ) - g_signal_handler_disconnect( object, - argument_instance->close_id ); - argument_instance->close_id = 0; - g_object_unref( object ); } @@ -919,6 +929,13 @@ vips_object_finalize( GObject *gobject ) G_OBJECT_CLASS( vips_object_parent_class )->finalize( gobject ); } +static void +vips_object_arg_invalidate( GObject *argument, + VipsArgumentInstance *argument_instance ) +{ + vips_operation_invalidate( VIPS_OPERATION( argument ) ); +} + static void vips_object_arg_close( GObject *argument, VipsArgumentInstance *argument_instance ) @@ -968,6 +985,13 @@ vips__object_set_member( VipsObject *object, GParamSpec *pspec, /* Ref the argument. */ g_object_ref( *member ); + + g_assert( !argument_instance->invalidate_id ); + argument_instance->invalidate_id = + g_signal_connect( *member, "invalidate", + G_CALLBACK( + vips_object_arg_invalidate ), + argument_instance ); } else if( argument_class->flags & VIPS_ARGUMENT_OUTPUT ) { #ifdef DEBUG_REF diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index cdfd4285..9cc4ab92 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -92,6 +92,15 @@ /* Abstract base class for operations. */ +/* Our signals. + */ +enum { + SIG_INVALIDATE, + SIG_LAST +}; + +static guint vips_operation_signals[SIG_LAST] = { 0 }; + G_DEFINE_ABSTRACT_TYPE( VipsOperation, vips_operation, VIPS_TYPE_OBJECT ); static void @@ -380,6 +389,14 @@ vips_operation_class_init( VipsOperationClass *class ) class->usage = vips_operation_usage; class->get_flags = vips_operation_real_get_flags; + + vips_operation_signals[SIG_INVALIDATE] = g_signal_new( "invalidate", + G_TYPE_FROM_CLASS( class ), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET( VipsOperationClass, invalidate ), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0 ); } static void @@ -419,6 +436,15 @@ vips_operation_class_print_usage( VipsOperationClass *operation_class ) printf( "%s", vips_buf_all( &buf ) ); } +void +vips_operation_invalidate( VipsOperation *operation ) +{ + printf( "vips_operation_invalidate: %p\n", operation ); + vips_object_print_summary( VIPS_OBJECT( operation ) ); + + g_signal_emit( operation, vips_operation_signals[SIG_INVALIDATE], 0 ); +} + VipsOperation * vips_operation_new( const char *name ) {