Commit a9b21ce7 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

vdpau: preallocate pool of video surfaces

That should help failing safe to software decoding if the graphic card
has too little free memory. Old cards with only 256 MiB are commonly
affected by that problem.

(cherry picked from commit f6da7e32f09d9671e92d90d98b7a2c51c28290b5)

Conflicts:
	modules/hw/vdpau/avcodec.c
parent 77db2e04
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_fourcc.h> #include <vlc_fourcc.h>
#include <vlc_picture.h> #include <vlc_picture.h>
#include <vlc_atomic.h>
#include <vlc_xlib.h> #include <vlc_xlib.h>
#include "vlc_vdpau.h" #include "vlc_vdpau.h"
#include "../../codec/avcodec/va.h" #include "../../codec/avcodec/va.h"
...@@ -58,6 +59,7 @@ struct vlc_va_sys_t ...@@ -58,6 +59,7 @@ struct vlc_va_sys_t
VdpDecoderProfile profile; VdpDecoderProfile profile;
uint16_t width; uint16_t width;
uint16_t height; uint16_t height;
vlc_vdp_video_field_t **pool;
}; };
static vlc_vdp_video_field_t *CreateSurface(vlc_va_t *va) static vlc_vdp_video_field_t *CreateSurface(vlc_va_t *va)
...@@ -81,11 +83,46 @@ static vlc_vdp_video_field_t *CreateSurface(vlc_va_t *va) ...@@ -81,11 +83,46 @@ static vlc_vdp_video_field_t *CreateSurface(vlc_va_t *va)
return field; return field;
} }
static void DestroySurface(vlc_vdp_video_field_t *field)
{
assert(field != NULL);
field->destroy(field);
}
static vlc_vdp_video_field_t *GetSurface(vlc_va_t *va)
{
vlc_va_sys_t *sys = va->sys;
vlc_vdp_video_field_t *f;
for (unsigned i = 0; (f = sys->pool[i]) != NULL; i++)
{
uintptr_t expected = 1;
if (atomic_compare_exchange_strong(&f->frame->refs, &expected, 2))
{
vlc_vdp_video_field_t *field = vlc_vdp_video_copy(f);
atomic_fetch_sub(&f->frame->refs, 1);
return field;
}
}
/* All pictures in the pool are referenced. Try to make a new one. */
return CreateSurface(va);
}
static int Lock(vlc_va_t *va, void **opaque, uint8_t **data) static int Lock(vlc_va_t *va, void **opaque, uint8_t **data)
{ {
vlc_vdp_video_field_t *field = CreateSurface(va); vlc_vdp_video_field_t *field;
if (unlikely(field == NULL)) unsigned tries = (CLOCK_FREQ + VOUT_OUTMEM_SLEEP) / VOUT_OUTMEM_SLEEP;
return VLC_ENOMEM;
while ((field = GetSurface(va)) == NULL)
{
if (--tries == 0)
return VLC_ENOMEM;
/* Out of video RAM, wait for some time as in src/input/decoder.c.
* XXX: Both this and the core should use a semaphore or a CV. */
msleep(VOUT_OUTMEM_SLEEP);
}
*opaque = field; *opaque = field;
*data = (void *)(uintptr_t)field->frame->surface; *data = (void *)(uintptr_t)field->frame->surface;
...@@ -96,8 +133,7 @@ static void Unlock(void *opaque, uint8_t *data) ...@@ -96,8 +133,7 @@ static void Unlock(void *opaque, uint8_t *data)
{ {
vlc_vdp_video_field_t *field = opaque; vlc_vdp_video_field_t *field = opaque;
assert(field != NULL); DestroySurface(field);
field->destroy(field);
(void) data; (void) data;
} }
...@@ -137,12 +173,39 @@ static int Init(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap, ...@@ -137,12 +173,39 @@ static int Init(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
break; break;
} }
vlc_vdp_video_field_t **pool = malloc(sizeof (*pool) * (surfaces + 6));
if (unlikely(pool == NULL))
return VLC_ENOMEM;
unsigned i = 0;
while (i < surfaces + 5)
{
pool[i] = CreateSurface(va);
if (pool[i] == NULL)
break;
i++;
}
pool[i] = NULL;
if (i < surfaces + 3)
{
msg_Err(va, "not enough video RAM");
while (i > 0)
DestroySurface(pool[--i]);
free(pool);
return VLC_ENOMEM;
}
sys->pool = pool;
err = vdp_decoder_create(sys->vdp, sys->device, sys->profile, width, err = vdp_decoder_create(sys->vdp, sys->device, sys->profile, width,
height, surfaces, &sys->context->decoder); height, surfaces, &sys->context->decoder);
if (err != VDP_STATUS_OK) if (err != VDP_STATUS_OK)
{ {
msg_Err(va, "%s creation failure: %s", "decoder", msg_Err(va, "%s creation failure: %s", "decoder",
vdp_get_error_string(sys->vdp, err)); vdp_get_error_string(sys->vdp, err));
while (i > 0)
DestroySurface(pool[--i]);
free(pool);
sys->context->decoder = VDP_INVALID_HANDLE; sys->context->decoder = VDP_INVALID_HANDLE;
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -159,6 +222,9 @@ static void Deinit(vlc_va_t *va) ...@@ -159,6 +222,9 @@ static void Deinit(vlc_va_t *va)
assert(sys->context->decoder != VDP_INVALID_HANDLE); assert(sys->context->decoder != VDP_INVALID_HANDLE);
vdp_decoder_destroy(sys->vdp, sys->context->decoder); vdp_decoder_destroy(sys->vdp, sys->context->decoder);
for (unsigned i = 0; sys->pool[i] != NULL; i++)
sys->pool[i]->destroy(sys->pool[i]);
free(sys->pool);
} }
static int Setup(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap, static int Setup(vlc_va_t *va, void **ctxp, vlc_fourcc_t *chromap,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment