X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fpicture_pool.c;h=e899f9eabbc5e46ea945822500a438a384c83dfc;hb=37be0f0eef36f2c32a8746810950c921fcc4dd28;hp=23225c264e420b2cfdab3283963910832c582c65;hpb=2deed367f004bc8db10370bb2f91be477b1d0ad7;p=vlc diff --git a/src/misc/picture_pool.c b/src/misc/picture_pool.c index 23225c264e..e899f9eabb 100644 --- a/src/misc/picture_pool.c +++ b/src/misc/picture_pool.c @@ -1,25 +1,25 @@ /***************************************************************************** * picture_pool.c : picture pool functions ***************************************************************************** - * Copyright (C) 2009 the VideoLAN team + * Copyright (C) 2009 VLC authors and VideoLAN * Copyright (C) 2009 Laurent Aimar * $Id$ * * Authors: Laurent Aimar * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -37,182 +37,296 @@ /***************************************************************************** * *****************************************************************************/ -struct picture_release_sys_t -{ - /* Saved release */ - void (*pf_release)( picture_t * ); - picture_release_sys_t *p_release_sys; +struct picture_gc_sys_t { + picture_pool_t *pool; + picture_t *picture; + bool in_use; + uint64_t tick; +}; +struct picture_pool_t { + uint64_t tick; /* */ - int (*pf_lock)( picture_t * ); - void (*pf_unlock)( picture_t * ); + unsigned picture_count; + picture_t **picture; - /* */ - int64_t i_tick; + int (*pic_lock)(picture_t *); + void (*pic_unlock)(picture_t *); + unsigned refs; + vlc_mutex_t lock; }; -struct picture_pool_t +void picture_pool_Release(picture_pool_t *pool) { - int64_t i_tick; + bool destroy; - int i_picture; - picture_t **pp_picture; -}; + vlc_mutex_lock(&pool->lock); + assert(pool->refs > 0); + destroy = --pool->refs == 0; + vlc_mutex_unlock(&pool->lock); + + if (likely(!destroy)) + return; + + for (unsigned i = 0; i < pool->picture_count; i++) { + picture_t *picture = pool->picture[i]; + picture_gc_sys_t *sys = picture->gc.p_sys; + + picture_Release(sys->picture); + free(sys); + free(picture); + } + + vlc_mutex_destroy(&pool->lock); + free(pool->picture); + free(pool); +} + +static void picture_pool_ReleasePicture(picture_t *picture) +{ + picture_gc_sys_t *sys = picture->gc.p_sys; + picture_pool_t *pool = sys->pool; + + if (pool->pic_unlock != NULL) + pool->pic_unlock(picture); -static void PicturePoolPictureRelease( picture_t * ); + vlc_mutex_lock(&pool->lock); + assert(sys->in_use); + sys->in_use = false; + vlc_mutex_unlock(&pool->lock); -picture_pool_t *picture_pool_NewExtended( const picture_pool_configuration_t *cfg ) + picture_pool_Release(pool); +} + +static picture_t *picture_pool_ClonePicture(picture_pool_t *pool, + picture_t *picture) +{ + picture_gc_sys_t *sys = malloc(sizeof(*sys)); + if (unlikely(sys == NULL)) + return NULL; + + sys->pool = pool; + sys->picture = picture; + sys->in_use = false; + sys->tick = 0; + + picture_resource_t res = { + .p_sys = picture->p_sys, + .pf_destroy = picture_pool_ReleasePicture, + }; + + for (int i = 0; i < picture->i_planes; i++) { + res.p[i].p_pixels = picture->p[i].p_pixels; + res.p[i].i_lines = picture->p[i].i_lines; + res.p[i].i_pitch = picture->p[i].i_pitch; + } + + picture_t *clone = picture_NewFromResource(&picture->format, &res); + if (likely(clone != NULL)) + clone->gc.p_sys = sys; + else + free(sys); + + return clone; +} + +static picture_pool_t *Create(int picture_count) { - picture_pool_t *p_pool = calloc( 1, sizeof(*p_pool) ); - if( !p_pool ) + picture_pool_t *pool = calloc(1, sizeof(*pool)); + if (!pool) return NULL; - p_pool->i_tick = 1; - p_pool->i_picture = cfg->picture_count; - p_pool->pp_picture = calloc( p_pool->i_picture, sizeof(*p_pool->pp_picture) ); - if( !p_pool->pp_picture ) - { - free( p_pool ); + pool->tick = 1; + pool->picture_count = picture_count; + pool->picture = calloc(pool->picture_count, sizeof(*pool->picture)); + if (!pool->picture) { + free(pool->picture); + free(pool); return NULL; } + pool->refs = 1; + vlc_mutex_init(&pool->lock); + return pool; +} - for( int i = 0; i < cfg->picture_count; i++ ) - { - picture_t *p_picture = cfg->picture[i]; +picture_pool_t *picture_pool_NewExtended(const picture_pool_configuration_t *cfg) +{ + picture_pool_t *pool = Create(cfg->picture_count); + if (!pool) + return NULL; - /* The pool must be the only owner of the picture */ - assert( p_picture->i_refcount == 1 ); + pool->pic_lock = cfg->lock; + pool->pic_unlock = cfg->unlock; - /* Install the new release callback */ - picture_release_sys_t *p_release_sys = malloc( sizeof(*p_release_sys) ); - if( !p_release_sys ) + for (unsigned i = 0; i < cfg->picture_count; i++) { + picture_t *picture = picture_pool_ClonePicture(pool, cfg->picture[i]); + if (unlikely(picture == NULL)) abort(); - p_release_sys->pf_release = p_picture->pf_release; - p_release_sys->p_release_sys = p_picture->p_release_sys; - p_release_sys->pf_lock = cfg->lock; - p_release_sys->pf_unlock = cfg->unlock; - p_release_sys->i_tick = 0; - - p_picture->i_refcount = 0; - p_picture->pf_release = PicturePoolPictureRelease; - p_picture->p_release_sys = p_release_sys; - - /* */ - p_pool->pp_picture[i] = p_picture; + + atomic_init(&picture->gc.refcount, 0); + + pool->picture[i] = picture; } - return p_pool; + return pool; } -picture_pool_t *picture_pool_New( int i_picture, picture_t *pp_picture[] ) +picture_pool_t *picture_pool_New(unsigned count, picture_t *const *tab) { picture_pool_configuration_t cfg; - memset( &cfg, 0, sizeof(cfg) ); - cfg.picture_count = i_picture; - cfg.picture = pp_picture; + memset(&cfg, 0, sizeof(cfg)); + cfg.picture_count = count; + cfg.picture = tab; - return picture_pool_NewExtended( &cfg ); + return picture_pool_NewExtended(&cfg); } -picture_pool_t *picture_pool_NewFromFormat( const video_format_t *p_fmt, int i_picture ) +picture_pool_t *picture_pool_NewFromFormat(const video_format_t *fmt, + unsigned count) { - picture_t *pp_picture[i_picture]; - - for( int i = 0; i < i_picture; i++ ) - { - pp_picture[i] = picture_New( p_fmt->i_chroma, - p_fmt->i_width, p_fmt->i_height, - p_fmt->i_aspect ); - if( !pp_picture[i] ) + picture_t *picture[count ? count : 1]; + unsigned i; + + for (i = 0; i < count; i++) { + picture[i] = picture_NewFromFormat(fmt); + if (picture[i] == NULL) goto error; } - picture_pool_t *p_pool = picture_pool_New( i_picture, pp_picture ); - if( !p_pool ) + + picture_pool_t *pool = picture_pool_New(count, picture); + if (!pool) goto error; - return p_pool; + return pool; error: - for( int i = 0; i < i_picture; i++ ) - { - if( !pp_picture[i] ) - break; - picture_Release( pp_picture[i] ); - } + while (i > 0) + picture_Release(picture[--i]); return NULL; } -void picture_pool_Delete( picture_pool_t *p_pool ) +picture_pool_t *picture_pool_Reserve(picture_pool_t *master, unsigned count) { - for( int i = 0; i < p_pool->i_picture; i++ ) - { - picture_t *p_picture = p_pool->pp_picture[i]; - picture_release_sys_t *p_release_sys = p_picture->p_release_sys; + picture_t *picture[count ? count : 1]; + unsigned i; - assert( p_picture->i_refcount == 0 ); + for (i = 0; i < count; i++) { + picture[i] = picture_pool_Get(master); + if (picture[i] == NULL) + goto error; + } - /* Restore old release callback */ - p_picture->i_refcount = 1; - p_picture->pf_release = p_release_sys->pf_release; - p_picture->p_release_sys = p_release_sys->p_release_sys; + picture_pool_t *pool = picture_pool_New(count, picture); + if (!pool) + goto error; - picture_Release( p_picture ); + pool->pic_lock = master->pic_lock; + pool->pic_unlock = master->pic_unlock; + return pool; - free( p_release_sys ); - } - free( p_pool->pp_picture ); - free( p_pool ); +error: + while (i > 0) + picture_Release(picture[--i]); + return NULL; } -picture_t *picture_pool_Get( picture_pool_t *p_pool ) +picture_t *picture_pool_Get(picture_pool_t *pool) { - for( int i = 0; i < p_pool->i_picture; i++ ) - { - picture_t *p_picture = p_pool->pp_picture[i]; - if( p_picture->i_refcount > 0 ) + vlc_mutex_lock(&pool->lock); + assert(pool->refs > 0); + + for (unsigned i = 0; i < pool->picture_count; i++) { + picture_t *picture = pool->picture[i]; + picture_gc_sys_t *sys = picture->gc.p_sys; + uint64_t tick; + + if (sys->in_use) continue; - picture_release_sys_t *p_release_sys = p_picture->p_release_sys; - if( p_release_sys->pf_lock && p_release_sys->pf_lock(p_picture) ) + pool->refs++; + tick = ++pool->tick; + sys->in_use = true; + vlc_mutex_unlock(&pool->lock); + + if (pool->pic_lock != NULL && pool->pic_lock(picture) != 0) { + vlc_mutex_lock(&pool->lock); + sys->in_use = false; + pool->refs--; + vlc_mutex_unlock(&pool->lock); continue; + } + + sys->tick = tick; - /* */ - p_picture->p_release_sys->i_tick = p_pool->i_tick++; - picture_Hold( p_picture ); - return p_picture; + assert(atomic_load(&picture->gc.refcount) == 0); + atomic_init(&picture->gc.refcount, 1); + picture->p_next = NULL; + return picture; } + + vlc_mutex_unlock(&pool->lock); return NULL; } -void picture_pool_NonEmpty( picture_pool_t *p_pool, bool b_reset ) +unsigned picture_pool_Reset(picture_pool_t *pool) { - picture_t *p_old = NULL; - - for( int i = 0; i < p_pool->i_picture; i++ ) - { - picture_t *p_picture = p_pool->pp_picture[i]; - - if( b_reset ) - p_picture->i_refcount = 0; - else if( p_picture->i_refcount == 0 ) - return; - else if( !p_old || p_picture->p_release_sys->i_tick < p_old->p_release_sys->i_tick ) - p_old = p_picture; + unsigned ret = 0; +retry: + vlc_mutex_lock(&pool->lock); + assert(pool->refs > 0); + + for (unsigned i = 0; i < pool->picture_count; i++) { + picture_t *picture = pool->picture[i]; + picture_gc_sys_t *sys = picture->gc.p_sys; + + if (sys->in_use) { + vlc_mutex_unlock(&pool->lock); + picture_Release(picture); + ret++; + goto retry; + } } - if( !b_reset && p_old ) - p_old->i_refcount = 0; + vlc_mutex_unlock(&pool->lock); + + return ret; } -static void PicturePoolPictureRelease( picture_t *p_picture ) +void picture_pool_NonEmpty(picture_pool_t *pool) { - assert( p_picture->i_refcount > 0 ); + picture_t *oldest = NULL; + uint64_t tick = 0; - if( --p_picture->i_refcount > 0 ) - return; + vlc_mutex_lock(&pool->lock); + assert(pool->refs > 0); + + for (unsigned i = 0; i < pool->picture_count; i++) { + picture_t *picture = pool->picture[i]; + picture_gc_sys_t *sys = picture->gc.p_sys; + + if (!sys->in_use) { + vlc_mutex_unlock(&pool->lock); + return; /* Nothing to do */ + } - picture_release_sys_t *p_release_sys = p_picture->p_release_sys; - if( p_release_sys->pf_unlock ) - p_release_sys->pf_unlock( p_picture ); + if (picture->gc.p_sys->tick < tick) { + oldest = picture; + tick = picture->gc.p_sys->tick; + } + } + + if (oldest != NULL) { + while (oldest->gc.p_sys->in_use) { + vlc_mutex_unlock(&pool->lock); + picture_Release(oldest); + vlc_mutex_lock(&pool->lock); + } + } + + vlc_mutex_unlock(&pool->lock); } +unsigned picture_pool_GetSize(const picture_pool_t *pool) +{ + return pool->picture_count; +}