[vlc-devel] [PATCH 3/3] avcodec: va: use a vlc_sem_t to manage the available surfaces

Steve Lhomme robux4 at ycbcr.xyz
Thu Jul 9 17:40:36 CEST 2020


On 2020-07-09 16:33, Rémi Denis-Courmont wrote:
> Le jeudi 9 juillet 2020, 14:42:02 EEST Steve Lhomme a écrit :
>> This is cleaner than using a loop of vlc_tick_sleep(VOUT_OUTMEM_SLEEP);
>>
>> We don't potentially wait 19.9999ms before giving a surface to the decoder.
>> ---
>>   modules/codec/avcodec/va_surface.c | 27 +++++++++++++++++----------
>>   1 file changed, 17 insertions(+), 10 deletions(-)
>>
>> diff --git a/modules/codec/avcodec/va_surface.c
>> b/modules/codec/avcodec/va_surface.c index 9045273fa3f..bbf3f6b06cb 100644
>> --- a/modules/codec/avcodec/va_surface.c
>> +++ b/modules/codec/avcodec/va_surface.c
>> @@ -56,6 +56,7 @@ struct va_pool_t
>>       struct va_pool_cfg callbacks;
>>
>>       atomic_uintptr_t  poolrefs; // 1 ref for the pool creator, 1 ref per
>> surface alive +    vlc_sem_t    available_surfaces;
>>   };
>>
>>   static void va_pool_AddRef(va_pool_t *va_pool)
>> @@ -102,6 +103,8 @@ int va_pool_SetupDecoder(vlc_va_t *va, va_pool_t
>> *va_pool, AVCodecContext *avctx va_pool->surface_height = fmt->i_height;
>>       va_pool->surface_count = count;
>>
>> +    vlc_sem_init(&va_pool->available_surfaces, count);
>> +
>>       for (size_t i = 0; i < va_pool->surface_count; i++) {
>>           vlc_va_surface_t *surface = &va_pool->surface[i];
>>           atomic_init(&surface->refcount, 1);
>> @@ -139,12 +142,9 @@ vlc_va_surface_t *va_pool_Get(va_pool_t *va_pool)
>>       if (va_pool->surface_count == 0)
>>           return NULL;
>>
>> -    while ((surface = GetSurface(va_pool)) == NULL)
>> -    {
>> -        /* Pool empty. Wait for some time as in src/input/decoder.c.
>> -         * XXX: Both this and the core should use a semaphore or a CV. */
>> -        vlc_tick_sleep(VOUT_OUTMEM_SLEEP);
>> -    }
>> +    vlc_sem_wait(&va_pool->available_surfaces);
>> +    surface = GetSurface(va_pool);
>> +    assert(surface != NULL);
>>       return surface;
>>   }
>>
>> @@ -155,10 +155,17 @@ void va_surface_AddRef(vlc_va_surface_t *surface)
>>
>>   void va_surface_Release(vlc_va_surface_t *surface)
>>   {
>> -    if (atomic_fetch_sub(&surface->refcount, 1) != 1)
>> -        return;
>> -
>> -    va_pool_Release(surface->va_pool);
>> +    uintptr_t had_refcount = atomic_fetch_sub(&surface->refcount, 1);
>> +    if (had_refcount == 2)
>> +    {
>> +        // the surface is not used anymore
>> +        vlc_sem_post(&surface->va_pool->available_surfaces);
>> +    }
>> +    else if (had_refcount == 1)
>> +    {
>> +        // the surface has been released
>> +        va_pool_Release(surface->va_pool);
>> +    }
>>   }
>>
>>   size_t va_surface_GetIndex(const vlc_va_surface_t *surface)
> 
> I don't follow the logic. There's no guarantees that the last reference
> belongs to any thing or other. The pool could be destroyed before the
> pictures.

This is how it's designed to work:

refcount; // 1 ref for the surface existence, 1 per surface/clone in-flight

If you end up with a reference of 0 (so had_refcount=1) you are sure 
after that the surface cannot be used anymore. (code is equivalent as 
before).

If you end up with a reference of 1 (so had_refcount=2) that means the 
surface was queried by the decoder and most likely pushed for 
playback/filtering/use.
If you are in a rare case that the decoder asks for the picture but ends 
up releasing it early, you still release it for the decoder to use it 
for the next time.
There's also the case of draining pictures at the end of a stream. In 
this case the pool is released before the last picture. It's true that 
we'll reach had_refcount = 2 when the surface is still pending for 
display. But the decoder is not going to query for one anymore until the 
last picture is used.

I don't know if there's another draining case where it starts draining 
and before the draining is done it starts using new pictures. Even 
though the reference help by the pool wouldn't change if the pool is not 
released. So it would just end up in the case where it gets/releases 
references only for the decoder.


More information about the vlc-devel mailing list