summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libvo/vo_vdpau.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c
index daf442be2d..26d643f42a 100644
--- a/libvo/vo_vdpau.c
+++ b/libvo/vo_vdpau.c
@@ -142,6 +142,7 @@ static VdpDecoderDestroy *vdp_decoder_destroy;
static VdpDecoderRender *vdp_decoder_render;
static VdpGenerateCSCMatrix *vdp_generate_csc_matrix;
+static VdpPreemptionCallbackRegister *vdp_preemption_callback_register;
static void *vdpau_lib_handle;
/* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
@@ -178,6 +179,8 @@ static uint32_t image_format;
static VdpChromaType vdp_chroma_type;
static VdpYCbCrFormat vdp_pixel_format;
+static volatile int is_preempted;
+
/* draw_osd */
static unsigned char *index_data;
static int index_data_size;
@@ -311,6 +314,12 @@ static void resize(void)
flip_page();
}
+static void preemption_callback(VdpDevice device, void *context)
+{
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Display preemption detected\n");
+ is_preempted = 1;
+}
+
/* Initialize vdp_get_proc_address, called from preinit() */
static int win_x11_init_vdpau_procs(void)
{
@@ -366,6 +375,8 @@ static int win_x11_init_vdpau_procs(void)
{VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE,
&vdp_output_surface_render_bitmap_surface},
{VDP_FUNC_ID_GENERATE_CSC_MATRIX, &vdp_generate_csc_matrix},
+ {VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER,
+ &vdp_preemption_callback_register},
{0, NULL}
};
@@ -385,6 +396,10 @@ static int win_x11_init_vdpau_procs(void)
return -1;
}
}
+ vdp_st = vdp_preemption_callback_register(vdp_device,
+ preemption_callback, NULL);
+ CHECK_ST_ERROR("Error when calling vdp_preemption_callback_register")
+
return 0;
}
@@ -559,6 +574,51 @@ static int create_vdp_decoder(int max_refs)
return 1;
}
+static void mark_vdpau_objects_uninitialized(void)
+{
+ int i;
+
+ decoder = VDP_INVALID_HANDLE;
+ for (i = 0; i < MAX_VIDEO_SURFACES; i++)
+ surface_render[i].surface = VDP_INVALID_HANDLE;
+ for (i = 0; i < 3; i++) {
+ deint_surfaces[i] = VDP_INVALID_HANDLE;
+ if (i < 2 && deint_mpi[i])
+ deint_mpi[i]->usage_count--;
+ deint_mpi[i] = NULL;
+ }
+ video_mixer = VDP_INVALID_HANDLE;
+ vdp_flip_queue = VDP_INVALID_HANDLE;
+ vdp_flip_target = VDP_INVALID_HANDLE;
+ for (i = 0; i <= NUM_OUTPUT_SURFACES; i++)
+ output_surfaces[i] = VDP_INVALID_HANDLE;
+ vdp_device = VDP_INVALID_HANDLE;
+ for (i = 0; i < eosd_surface_count; i++)
+ eosd_surfaces[i].surface = VDP_INVALID_HANDLE;
+ output_surface_width = output_surface_height = -1;
+ eosd_render_count = 0;
+ visible_buf = 0;
+}
+
+static int handle_preemption(void)
+{
+ if (!is_preempted)
+ return 0;
+ is_preempted = 0;
+ mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Attempting to recover from preemption.\n");
+ mark_vdpau_objects_uninitialized();
+ if (win_x11_init_vdpau_procs() < 0 ||
+ win_x11_init_vdpau_flip_queue() < 0 ||
+ create_vdp_mixer(vdp_chroma_type) < 0) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Recovering from preemption failed\n");
+ is_preempted = 1;
+ return -1;
+ }
+ resize();
+ mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Recovered from display preemption.\n");
+ return 1;
+}
+
/*
* connect to X server, create and map window, initialize all
* VDPAU objects, create different surfaces etc.
@@ -665,6 +725,9 @@ static void check_events(void)
{
int e = vo_x11_check_events(mDisplay);
+ if (handle_preemption() < 0)
+ return;
+
if (e & VO_EVENT_RESIZE)
resize();
@@ -864,6 +927,9 @@ static void draw_osd(void)
{
mp_msg(MSGT_VO, MSGL_DBG2, "DRAW_OSD\n");
+ if (handle_preemption() < 0)
+ return;
+
vo_draw_text_ext(vo_dwidth, vo_dheight, border_x, border_y, border_x, border_y,
vid_width, vid_height, draw_osd_I8A8);
}
@@ -874,6 +940,9 @@ static void flip_page(void)
mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
surface_render[vid_surface_num].surface, output_surfaces[surface_num]);
+ if (handle_preemption() < 0)
+ return;
+
vdp_st = vdp_presentation_queue_display(vdp_flip_queue, output_surfaces[surface_num],
vo_dwidth, vo_dheight,
0);
@@ -889,6 +958,10 @@ static int draw_slice(uint8_t *image[], int stride[], int w, int h,
VdpStatus vdp_st;
struct vdpau_render_state *rndr = (struct vdpau_render_state *)image[0];
int max_refs = image_format == IMGFMT_VDPAU_H264 ? rndr->info.h264.num_ref_frames : 2;
+
+ if (handle_preemption() < 0)
+ return VO_TRUE;
+
if (!IMGFMT_IS_VDPAU(image_format))
return VO_FALSE;
if ((decoder == VDP_INVALID_HANDLE || decoder_max_refs < max_refs)
@@ -1203,6 +1276,9 @@ static int set_equalizer(char *name, int value)
static int control(uint32_t request, void *data, ...)
{
+ if (handle_preemption() < 0)
+ return VO_FALSE;
+
switch (request) {
case VOCTRL_GET_DEINTERLACE:
*(int*)data = deint;