oops, keep Render alive for longer

This commit is contained in:
John Cupitt 2010-03-10 21:26:45 +00:00
parent f652e56abe
commit ced43ce70e
1 changed files with 36 additions and 14 deletions

View File

@ -42,7 +42,7 @@
* 22/1/10 * 22/1/10
* - drop painted tiles on invalidate * - drop painted tiles on invalidate
* 10/3/10 * 10/3/10
* - keep render alive until both in and out close * - better lifetime management for im_invalidate() callbacks
*/ */
/* /*
@ -153,6 +153,13 @@ typedef struct {
*/ */
/* Invalidate proxy. The im_invalidate() callback comes here, render can null
* out the pointer when it's not interested.
*/
typedef struct _RenderProxy {
struct _Render *render;
} RenderProxy;
/* Per-call state. /* Per-call state.
*/ */
typedef struct _Render { typedef struct _Render {
@ -174,6 +181,10 @@ typedef struct _Render {
notify_fn notify; /* Tell caller about paints here */ notify_fn notify; /* Tell caller about paints here */
void *client; void *client;
/* The invalidate proxy: NULL this out to stop the callback.
*/
RenderProxy *proxy;
/* Make readers single thread with this. No point allowing /* Make readers single thread with this. No point allowing
* multi-thread read. * multi-thread read.
*/ */
@ -252,6 +263,10 @@ render_free( Render *render )
g_assert( render->ref_count == 0 ); g_assert( render->ref_count == 0 );
/* Block the invalidate callback.
*/
render->proxy->render = NULL;
render_dirty_remove( render ); render_dirty_remove( render );
IM_FREEF( im_threadgroup_free, render->tg ); IM_FREEF( im_threadgroup_free, render->tg );
@ -600,10 +615,17 @@ render_tile_get_painted( Render *render )
/* Free all painted tiles. This is triggered on "invalidate". /* Free all painted tiles. This is triggered on "invalidate".
*/ */
static int static int
render_invalidate( Render *render ) render_invalidate( RenderProxy *proxy )
{ {
Render *render = proxy->render;
Tile *tile; Tile *tile;
/* Has render been freed?
*/
if( !render )
return( 0 );
/* Conceptually we work like region_fill(): we free all painted tiles. /* Conceptually we work like region_fill(): we free all painted tiles.
*/ */
g_mutex_lock( render->read_lock ); g_mutex_lock( render->read_lock );
@ -640,10 +662,7 @@ render_new( IMAGE *in, IMAGE *out, IMAGE *mask,
if( !(render = IM_NEW( NULL, Render )) ) if( !(render = IM_NEW( NULL, Render )) )
return( NULL ); return( NULL );
/* Both in and out need to close before we can go, so ref_count starts render->ref_count = 1;
* at 2.
*/
render->ref_count = 2;
render->ref_count_lock = g_mutex_new(); render->ref_count_lock = g_mutex_new();
render->in = in; render->in = in;
@ -656,6 +675,11 @@ render_new( IMAGE *in, IMAGE *out, IMAGE *mask,
render->notify = notify; render->notify = notify;
render->client = client; render->client = client;
/* This needs the same lifetime as in, since it's the arg to the
* invalidate callbcak.
*/
render->proxy = IM_NEW( in, RenderProxy );
render->read_lock = g_mutex_new(); render->read_lock = g_mutex_new();
render->cache = NULL; render->cache = NULL;
@ -668,19 +692,17 @@ render_new( IMAGE *in, IMAGE *out, IMAGE *mask,
render->tg = NULL; render->tg = NULL;
render->render_kill = FALSE; render->render_kill = FALSE;
if( im_add_close_callback( out, if( !render->proxy ||
(im_callback_fn) render_unref, render, NULL ) ) { im_add_close_callback( out,
(void) render_unref( render ); (im_callback_fn) render_unref, render, NULL ) ) {
return( NULL );
}
if( im_add_close_callback( in,
(im_callback_fn) render_unref, render, NULL ) ) {
(void) render_unref( render ); (void) render_unref( render );
return( NULL ); return( NULL );
} }
render->proxy->render = render;
if( im_add_invalidate_callback( in, if( im_add_invalidate_callback( in,
(im_callback_fn) render_invalidate, render, NULL ) ) (im_callback_fn) render_invalidate, render->proxy, NULL ) )
return( NULL ); return( NULL );
return( render ); return( render );