changeset 28675:5cc6dc932017

EOSD/ASS support for vo_vdpau.c Patch by Grigori G (greg <at> chown ath cx) with minor cosmetic changes by me.
author reimar
date Mon, 23 Feb 2009 09:21:57 +0000
parents 7afa172a9643
children d5c295360163
files libvo/vo_vdpau.c
diffstat 1 files changed, 187 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/vo_vdpau.c	Mon Feb 23 05:47:40 2009 +0000
+++ b/libvo/vo_vdpau.c	Mon Feb 23 09:21:57 2009 +0000
@@ -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,9 @@
 /* number of palette entries */
 #define PALETTE_SIZE 256
 
+/* Initial maximum number of EOSD surfaces */
+#define EOSD_SURFACES_INITIAL 512
+
 /*
  * Global variable declaration - VDPAU specific
  */
@@ -125,6 +131,11 @@
 /* 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 +170,26 @@
 static int                                index_data_size;
 static uint32_t                           palette[PALETTE_SIZE];
 
+// EOSD
+// Pool of surfaces
+struct {
+    VdpBitmapSurface surface;
+    int w;
+    int h;
+    char in_use;
+} *eosd_surfaces;
+
+// List of surfaces to be rendered
+struct {
+    VdpBitmapSurface surface;
+    VdpRect source;
+    VdpRect dest;
+    VdpColor color;
+} *eosd_targets;
+
+static int eosd_render_count;
+static int eosd_surface_count;
+
 /*
  * X11 specific
  */
@@ -286,6 +317,12 @@
         {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 +600,125 @@
     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 blend_state;
+    int i;
+
+    blend_state.struct_version                 = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION;
+    blend_state.blend_factor_source_color      = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA;
+    blend_state.blend_factor_source_alpha      = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE;
+    blend_state.blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+    blend_state.blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA;
+    blend_state.blend_equation_color           = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
+    blend_state.blend_equation_alpha           = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
+
+    for (i=0; i<eosd_render_count; i++) {
+        vdp_st = vdp_output_surface_render_bitmap_surface(
+            output_surface, &eosd_targets[i].dest,
+            eosd_targets[i].surface, &eosd_targets[i].source,
+            &eosd_targets[i].color, &blend_state,
+            VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
+        CHECK_ST_WARNING("EOSD: Error when rendering")
+    }
+}
+
+static void generate_eosd(mp_eosd_images_t *imgs) {
+    VdpStatus vdp_st;
+    VdpRect destRect;
+    int j, found;
+    ass_image_t *img = imgs->imgs;
+    ass_image_t *i;
+
+    // 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;
+
+    for (j=0; j<eosd_surface_count; j++)
+        eosd_surfaces[j].in_use = 0;
+
+    for (i = img; i; i = i->next) {
+        // Try to reuse a suitable surface
+        found = -1;
+        for (j=0; j<eosd_surface_count; j++) {
+            if (eosd_surfaces[j].surface != VDP_INVALID_HANDLE && !eosd_surfaces[j].in_use &&
+                eosd_surfaces[j].w >= i->w && eosd_surfaces[j].h >= i->h) {
+                found = j;
+                break;
+            }
+        }
+        // None found, allocate a new surface
+        if (found < 0) {
+            for (j=0; j<eosd_surface_count; j++) {
+                if (!eosd_surfaces[j].in_use) {
+                    if (eosd_surfaces[j].surface != VDP_INVALID_HANDLE)
+                        vdp_bitmap_surface_destroy(eosd_surfaces[j].surface);
+                    found = j;
+                    break;
+                }
+            }
+            // Allocate new space for surface/target arrays
+            if (found < 0) {
+                j = found = eosd_surface_count;
+                eosd_surface_count = eosd_surface_count ? eosd_surface_count*2 : EOSD_SURFACES_INITIAL;
+                eosd_surfaces = realloc(eosd_surfaces, eosd_surface_count * sizeof(*eosd_surfaces));
+                eosd_targets  = realloc(eosd_targets,  eosd_surface_count * sizeof(*eosd_targets));
+                for(j=found; j<eosd_surface_count; j++) {
+                    eosd_surfaces[j].surface = VDP_INVALID_HANDLE;
+                    eosd_surfaces[j].in_use = 0;
+                }
+            }
+            vdp_st = vdp_bitmap_surface_create(vdp_device, VDP_RGBA_FORMAT_A8,
+                i->w, i->h, VDP_TRUE, &eosd_surfaces[found].surface);
+            CHECK_ST_WARNING("EOSD: error when creating surface")
+            eosd_surfaces[found].w = i->w;
+            eosd_surfaces[found].h = i->h;
+        }
+        eosd_surfaces[found].in_use = 1;
+        eosd_targets[eosd_render_count].surface = eosd_surfaces[found].surface;
+        destRect.x0 = 0;
+        destRect.y0 = 0;
+        destRect.x1 = i->w;
+        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++;
+    }
+}
+
 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 +847,7 @@
 
 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;
@@ -728,6 +880,14 @@
         CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
     }
 
+    for (i = 0; i<eosd_surface_count; i++) {
+        if (eosd_surfaces[i].surface != VDP_INVALID_HANDLE) {
+            vdp_st = vdp_bitmap_surface_destroy(eosd_surfaces[i].surface);
+            CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy")
+        }
+        eosd_surfaces[i].surface = VDP_INVALID_HANDLE;
+    }
+
     vdp_st = vdp_device_destroy(vdp_device);
     CHECK_ST_WARNING("Error when calling vdp_device_destroy")
 }
@@ -744,6 +904,11 @@
     free(index_data);
     index_data = NULL;
 
+    free(eosd_surfaces);
+    eosd_surfaces = NULL;
+    free(eosd_targets);
+    eosd_targets = NULL;
+
 #ifdef CONFIG_XF86VM
     vo_vm_close();
 #endif
@@ -821,6 +986,10 @@
     index_data = NULL;
     index_data_size = 0;
 
+    eosd_surface_count = eosd_render_count = 0;
+    eosd_surfaces = NULL;
+    eosd_targets  = NULL;
+
     return 0;
 }
 
@@ -878,6 +1047,23 @@
         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;
 }