diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index a2ffcb6..f785338 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -50,6 +50,9 @@ #include "libavutil/common.h" +#include "libass/ass.h" +#include "libass/ass_mp.h" + static vo_info_t info = { "VDPAU with X11", "vdpau", @@ -78,6 +81,12 @@ LIBVO_EXTERN(vdpau) /* number of palette entries */ #define PALETTE_SIZE 256 +/* Round up to the next power of two */ +#define ROUND_POT(x) pow(2, ceil(log(x)/log(2))) + +/* Maximum number of surfaces allocated for EOSD */ +#define EOSD_MAX_SURFACES 2000 + /* * Global variable declaration - VDPAU specific */ @@ -125,6 +134,11 @@ static VdpPresentationQueueTargetCreateX11 *vdp_presentation_queue_target_ /* output_surfaces[2] is used in composite-picture. */ static VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface; static VdpOutputSurfacePutBitsIndexed *vdp_output_surface_put_bits_indexed; +static VdpOutputSurfaceRenderBitmapSurface *vdp_output_surface_render_bitmap_surface; + +static VdpBitmapSurfaceCreate *vdp_bitmap_surface_create; +static VdpBitmapSurfaceDestroy *vdp_bitmap_surface_destroy; +static VdpBitmapSurfacePutBitsNative *vdp_bitmap_surface_putbits_native; static VdpDecoderCreate *vdp_decoder_create; static VdpDecoderDestroy *vdp_decoder_destroy; @@ -159,6 +173,26 @@ static unsigned char *index_data; static int index_data_size; static uint32_t palette[PALETTE_SIZE]; +// EOSD +// Pool of surfaces +static struct { + VdpBitmapSurface surface; + int w; + int h; + char in_use; +} eosd_surfaces[EOSD_MAX_SURFACES]; + +// List of surfaces to be rendered +static struct { + VdpBitmapSurface surface; + VdpRect source; + VdpRect dest; + VdpColor color; +} eosd_targets[EOSD_MAX_SURFACES]; + +static int eosd_render_count = 0; +static char eosd_initialized = 0; + /* * X11 specific */ @@ -286,6 +320,10 @@ static int win_x11_init_vdpau_procs(void) {VDP_FUNC_ID_DECODER_CREATE, &vdp_decoder_create}, {VDP_FUNC_ID_DECODER_RENDER, &vdp_decoder_render}, {VDP_FUNC_ID_DECODER_DESTROY, &vdp_decoder_destroy}, + {VDP_FUNC_ID_BITMAP_SURFACE_CREATE, &vdp_bitmap_surface_create}, + {VDP_FUNC_ID_BITMAP_SURFACE_DESTROY, &vdp_bitmap_surface_destroy}, + {VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE, &vdp_bitmap_surface_putbits_native}, + {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE, &vdp_output_surface_render_bitmap_surface}, {0, NULL} }; @@ -563,10 +601,144 @@ static void draw_osd_I8A8(int x0,int y0, int w,int h, unsigned char *src, CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface") } +static void draw_eosd(void) { + VdpStatus vdp_st; + VdpOutputSurface output_surface = output_surfaces[surface_num]; + VdpOutputSurfaceRenderBlendState blendState; + int i; + + blendState.struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION; + blendState.blend_factor_source_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA; + blendState.blend_factor_source_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE; + blendState.blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendState.blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA; + blendState.blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD; + blendState.blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD; + + for (i=0; iimgs; + ass_image_t *i; + + if (!eosd_initialized) + eosd_init(); + + // Nothing changed, no need to redraw + if (imgs->changed == 0) + return; + eosd_render_count = 0; + // There's nothing to render! + if (!img) + return; + + if (imgs->changed == 1) + goto eosd_skip_upload; + else + for (j=0; jnext) { + // Try to reuse a suitable surface + found = 0; + for (j=0; j= i->w + && eosd_surfaces[j].h >= i->h) { + found = 1; + eosd_targets[eosd_render_count].surface = eosd_surfaces[j].surface; + eosd_surfaces[j].in_use = 1; + break; + } + } + // None found, allocate a new surface + if (!found) { + ax = ROUND_POT(i->w); + ay = ROUND_POT(i->h); + for (j=0; jw; + destRect.y1 = i->h; + vdp_st = vdp_bitmap_surface_putbits_native(eosd_targets[eosd_render_count].surface, + (const void *) &(i->bitmap), &(i->stride), &destRect); + CHECK_ST_WARNING("EOSD: putbits failed") + eosd_render_count++; + } + +eosd_skip_upload: + eosd_render_count = 0; + for (i = img; i; i = i->next) { + // Render dest, color, etc. + eosd_targets[eosd_render_count].color.alpha = 1.0 - ((i->color >> 0) & 0xff) / 255.0; + eosd_targets[eosd_render_count].color.blue = ((i->color >> 8) & 0xff) / 255.0; + eosd_targets[eosd_render_count].color.green = ((i->color >> 16) & 0xff) / 255.0; + eosd_targets[eosd_render_count].color.red = ((i->color >> 24) & 0xff) / 255.0; + eosd_targets[eosd_render_count].dest.x0 = i->dst_x; + eosd_targets[eosd_render_count].dest.y0 = i->dst_y; + eosd_targets[eosd_render_count].dest.x1 = i->w + i->dst_x; + eosd_targets[eosd_render_count].dest.y1 = i->h + i->dst_y; + eosd_targets[eosd_render_count].source.x0 = 0; + eosd_targets[eosd_render_count].source.y0 = 0; + eosd_targets[eosd_render_count].source.x1 = i->w; + eosd_targets[eosd_render_count].source.y1 = i->h; + eosd_render_count++; + + if (eosd_render_count >= EOSD_MAX_SURFACES) { + mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] EOSD: too many surfaces!\n"); + break; + } + } +} + static void draw_osd(void) { mp_msg(MSGT_VO, MSGL_DBG2, "DRAW_OSD\n"); + draw_eosd(); vo_draw_text_ext(vo_dwidth, vo_dheight, border_x, border_y, border_x, border_y, vid_width, vid_height, draw_osd_I8A8); } @@ -695,7 +867,7 @@ static uint32_t get_image(mp_image_t *mpi) static int query_format(uint32_t format) { - int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD; + int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED; switch (format) { case IMGFMT_YV12: return default_flags | VOCAP_NOSLICES; @@ -878,6 +1050,23 @@ static int control(uint32_t request, void *data, ...) case VOCTRL_UPDATE_SCREENINFO: update_xinerama_info(); return VO_TRUE; + case VOCTRL_DRAW_EOSD: + if (!data) + return VO_FALSE; + generate_eosd(data); + return VO_TRUE; + case VOCTRL_GET_EOSD_RES: { + mp_eosd_res_t *r = data; + r->mt = r->mb = r->ml = r->mr = 0; + if (vo_fs) { + r->w = vo_screenwidth; + r->h = vo_screenheight; + r->ml = r->mr = border_x; + r->mt = r->mb = border_y; + } else + r->w = vo_dwidth; r->h = vo_dheight; + return VO_TRUE; + } } return VO_NOTIMPL; }