paintbox fixes

This commit is contained in:
John Cupitt 2010-01-22 16:17:23 +00:00
parent c5e3ce4408
commit a4cdba13b2
2 changed files with 88 additions and 64 deletions

6
TODO
View File

@ -1,7 +1,5 @@
- close callbacks could use invalidate's trick and give close callbacks more - how about im_invalidate_area()? we currently repaint the whole window on
safety every paint action in nip2 :-(
could get rid of a couple of image flags too
- flood blob with ink == initial click loops - flood blob with ink == initial click loops

View File

@ -39,6 +39,8 @@
* 12/10/09 * 12/10/09
* - gtkdoc comment * - gtkdoc comment
* - im_render(), im_render_fade() moved to deprecated * - im_render(), im_render_fade() moved to deprecated
* 22/1/10
* - drop painted tiles on invalidate
*/ */
/* /*
@ -69,10 +71,10 @@
/* Turn on debugging output. /* Turn on debugging output.
#define DEBUG #define DEBUG
#define DEBUG_REUSE
#define DEBUG_PAINT #define DEBUG_PAINT
#define DEBUG_TG #define DEBUG_TG
#define DEBUG_MAKE #define DEBUG_MAKE
#define DEBUG_REUSE
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -83,7 +85,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <math.h> #include <math.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
@ -234,11 +235,7 @@ tile_free( Tile *tile )
printf( "tile_free\n" ); printf( "tile_free\n" );
#endif /*DEBUG_MAKE*/ #endif /*DEBUG_MAKE*/
if( tile->region ) { IM_FREEF( im_region_free, tile->region );
(void) im_region_free( tile->region );
tile->region = NULL;
}
im_free( tile ); im_free( tile );
return( NULL ); return( NULL );
@ -251,7 +248,7 @@ render_free( Render *render )
printf( "render_free: %p\n", render ); printf( "render_free: %p\n", render );
#endif /*DEBUG_MAKE*/ #endif /*DEBUG_MAKE*/
assert( render->ref_count == 0 ); g_assert( render->ref_count == 0 );
render_dirty_remove( render ); render_dirty_remove( render );
@ -280,7 +277,7 @@ static int
render_ref( Render *render ) render_ref( Render *render )
{ {
g_mutex_lock( render->ref_count_lock ); g_mutex_lock( render->ref_count_lock );
assert( render->ref_count != 0 ); g_assert( render->ref_count != 0 );
render->ref_count += 1; render->ref_count += 1;
g_mutex_unlock( render->ref_count_lock ); g_mutex_unlock( render->ref_count_lock );
@ -293,7 +290,7 @@ render_unref( Render *render )
int kill; int kill;
g_mutex_lock( render->ref_count_lock ); g_mutex_lock( render->ref_count_lock );
assert( render->ref_count > 0 ); g_assert( render->ref_count > 0 );
render->ref_count -= 1; render->ref_count -= 1;
kill = render->ref_count == 0; kill = render->ref_count == 0;
g_mutex_unlock( render->ref_count_lock ); g_mutex_unlock( render->ref_count_lock );
@ -325,7 +322,7 @@ render_dirty_get( void )
if( render_dirty_all ) { if( render_dirty_all ) {
render = (Render *) render_dirty_all->data; render = (Render *) render_dirty_all->data;
assert( render->ref_count == 1 ); g_assert( render->ref_count == 1 );
/* Ref the render to make sure it can't die while we're /* Ref the render to make sure it can't die while we're
* working on it. * working on it.
@ -353,7 +350,7 @@ render_dirty_process( Render *render )
g_mutex_lock( render->dirty_lock ); g_mutex_lock( render->dirty_lock );
if( render->dirty ) { if( render->dirty ) {
tile = (Tile *) render->dirty->data; tile = (Tile *) render->dirty->data;
assert( tile->state == TILE_DIRTY ); g_assert( tile->state == TILE_DIRTY );
render->dirty = g_slist_remove( render->dirty, tile ); render->dirty = g_slist_remove( render->dirty, tile );
tile->state = TILE_WORKING; tile->state = TILE_WORKING;
} }
@ -479,7 +476,7 @@ render_thread_main( void *client )
render_dirty_put( render ); render_dirty_put( render );
assert( render->ref_count == 1 || g_assert( render->ref_count == 1 ||
render->ref_count == 2 ); render->ref_count == 2 );
/* _get() does a ref to make sure we keep the render /* _get() does a ref to make sure we keep the render
@ -543,7 +540,7 @@ tile_state_name( TileState state )
case TILE_PAINTED: return( "TILE_PAINTED" ); case TILE_PAINTED: return( "TILE_PAINTED" );
default: default:
assert( FALSE ); g_assert( FALSE );
} }
} }
@ -560,6 +557,73 @@ tile_print( Tile *tile )
} }
#endif /*DEBUG*/ #endif /*DEBUG*/
static void *
tile_test_clean_ticks( Tile *this, Tile **best )
{
if( this->state == TILE_PAINTED )
if( !*best || this->access_ticks < (*best)->access_ticks )
*best = this;
return( NULL );
}
/* Pick a painted tile to reuse. Search for LRU (slow!).
*/
static Tile *
render_tile_get_painted( Render *render )
{
Tile *tile;
tile = NULL;
im_slist_map2( render->cache,
(VSListMap2Fn) tile_test_clean_ticks, &tile, NULL );
if( tile ) {
g_assert( tile->state == TILE_PAINTED );
#ifdef DEBUG_REUSE
printf( "render_tile_get_painted: reusing painted %p\n", tile );
g_mutex_lock( render->dirty_lock );
g_assert( !g_slist_find( render->dirty, tile ) );
g_mutex_unlock( render->dirty_lock );
#endif /*DEBUG_REUSE*/
tile->state = TILE_WORKING;
}
return( tile );
}
/* Free all painted tiles. This is triggered on "invalidate".
*/
static int
render_invalidate( Render *render )
{
Tile *tile;
/* Conceptually we work like region_fill(): we free all painted tiles.
*/
g_mutex_lock( render->read_lock );
while( (tile = render_tile_get_painted( render )) ) {
render->cache = g_slist_remove( render->cache, tile );
#ifdef DEBUG_REUSE
g_mutex_lock( render->dirty_lock );
g_assert( !g_slist_find( render->dirty, tile ) );
g_mutex_unlock( render->dirty_lock );
#endif /*DEBUG_REUSE*/
tile->render->ntiles -= 1;
tile_free( tile );
}
g_mutex_unlock( render->read_lock );
return( 0 );
}
static Render * static Render *
render_new( IMAGE *in, IMAGE *out, IMAGE *mask, render_new( IMAGE *in, IMAGE *out, IMAGE *mask,
int width, int height, int max, int width, int height, int max,
@ -605,6 +669,10 @@ render_new( IMAGE *in, IMAGE *out, IMAGE *mask,
return( NULL ); return( NULL );
} }
if( im_add_invalidate_callback( in,
(im_callback_fn) render_invalidate, render, NULL ) )
return( NULL );
return( render ); return( render );
} }
@ -700,7 +768,7 @@ tile_set_dirty( Tile *tile, Rect *area )
area->left, area->top ); area->left, area->top );
#endif /*DEBUG_PAINT*/ #endif /*DEBUG_PAINT*/
assert( tile->state == TILE_WORKING ); g_assert( tile->state == TILE_WORKING );
/* Touch the ticks ... we want to make sure this tile will not be /* Touch the ticks ... we want to make sure this tile will not be
* reused too soon, so it gets a chance to get painted. * reused too soon, so it gets a chance to get painted.
@ -755,48 +823,6 @@ tile_set_dirty( Tile *tile, Rect *area )
g_mutex_unlock( render->dirty_lock ); g_mutex_unlock( render->dirty_lock );
} }
static void *
tile_test_clean_ticks( Tile *this, Tile **best )
{
if( this->state == TILE_PAINTED )
if( !*best || this->access_ticks < (*best)->access_ticks )
*best = this;
return( NULL );
}
/* Pick a painted tile to reuse. Search for LRU (slow!).
*/
static Tile *
render_tile_get_painted( Render *render )
{
Tile *tile;
tile = NULL;
im_slist_map2( render->cache,
(VSListMap2Fn) tile_test_clean_ticks, &tile, NULL );
if( tile ) {
assert( tile->state == TILE_PAINTED );
#ifdef DEBUG_REUSE
printf( "render_tile_get_painted: reusing painted %p\n", tile );
g_mutex_lock( render->dirty_lock );
assert( !g_slist_find( render->dirty, tile ) );
g_mutex_unlock( render->dirty_lock );
g_mutex_lock( render->fade_lock );
assert( !g_slist_find( render->fade, tile ) );
g_mutex_unlock( render->fade_lock );
#endif /*DEBUG_REUSE*/
tile->state = TILE_WORKING;
}
return( tile );
}
/* Take a tile off the end of the dirty list. /* Take a tile off the end of the dirty list.
*/ */
static Tile * static Tile *
@ -881,7 +907,7 @@ tile_copy( Tile *tile, REGION *to )
/* Find common pixels. /* Find common pixels.
*/ */
im_rect_intersectrect( &tile->area, &to->valid, &ovlap ); im_rect_intersectrect( &tile->area, &to->valid, &ovlap );
assert( !im_rect_isempty( &ovlap ) ); g_assert( !im_rect_isempty( &ovlap ) );
len = IM_IMAGE_SIZEOF_PEL( to->im ) * ovlap.width; len = IM_IMAGE_SIZEOF_PEL( to->im ) * ovlap.width;
/* If the tile is painted, copy over the pixels. Otherwise, fill with /* If the tile is painted, copy over the pixels. Otherwise, fill with
@ -975,7 +1001,7 @@ tile_paint_mask( Tile *tile, REGION *to )
/* Find common pixels. /* Find common pixels.
*/ */
im_rect_intersectrect( &tile->area, &to->valid, &ovlap ); im_rect_intersectrect( &tile->area, &to->valid, &ovlap );
assert( !im_rect_isempty( &ovlap ) ); g_assert( !im_rect_isempty( &ovlap ) );
len = IM_IMAGE_SIZEOF_PEL( to->im ) * ovlap.width; len = IM_IMAGE_SIZEOF_PEL( to->im ) * ovlap.width;
for( y = ovlap.top; y < IM_RECT_BOTTOM( &ovlap ); y++ ) { for( y = ovlap.top; y < IM_RECT_BOTTOM( &ovlap ); y++ ) {
@ -985,7 +1011,7 @@ tile_paint_mask( Tile *tile, REGION *to )
} }
} }
/* The mask image is 255 .. 0 for the state of painted for each tile. /* The mask image is 255 / 0 for the state of painted for each tile.
*/ */
static int static int
mask_fill( REGION *out, void *seq, void *a, void *b ) mask_fill( REGION *out, void *seq, void *a, void *b )