From 62ccf6c5cccdf1a34a4b85f91615f0f8305b5279 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 26 Aug 2012 19:00:26 +0300 Subject: [PATCH] vo_vdpau: split bitmap packing code into a separate file Split the vo_vdpau code that calculates how to pack all subtitle bitmaps into a larger surface into a separate file. This will allow using it in other VOs. Conflicts: Makefile libvo/vo_vdpau.c Note: this commit does the same as an earlier commit by me (4010dd0b1a27e3996). My commit added the vo_vdpau packer code as eosd_packer.c, while this commit by uau uses bitmap_packer.c. Since bitmap_packer.c has a different interface, and because there are more commits changing OSD rendering coming, I will pick uau's version. However, vo_gl, vo_gl3 and vo_direct3d are still using eosd_packer.c, so to make the transition easier, don't delete eosd_packer.c yet. --- Makefile | 1 + libvo/bitmap_packer.c | 174 ++++++++++++++++++ libvo/bitmap_packer.h | 47 +++++ libvo/vo_vdpau.c | 408 +++++++++++++++++++++++++++--------------- 4 files changed, 484 insertions(+), 146 deletions(-) create mode 100644 libvo/bitmap_packer.c create mode 100644 libvo/bitmap_packer.h diff --git a/Makefile b/Makefile index 4c4027787e..04806786e4 100644 --- a/Makefile +++ b/Makefile @@ -241,6 +241,7 @@ SRCS_COMMON = asxparser.c \ libmpdemux/video.c \ libvo/osd.c \ libvo/eosd_packer.c \ + libvo/bitmap_packer.c \ osdep/numcores.c \ osdep/io.c \ osdep/$(GETCH) \ diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c new file mode 100644 index 0000000000..2ae8a1eee0 --- /dev/null +++ b/libvo/bitmap_packer.c @@ -0,0 +1,174 @@ +/* + * Calculate how to pack bitmap rectangles into a larger surface + * + * Copyright 2009, 2012 Uoti Urpala + * + * This file is part of mplayer2. + * + * mplayer2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mplayer2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mplayer2. If not, see . + */ + +#include + +#include + +#include "talloc.h" +#include "bitmap_packer.h" +#include "mp_msg.h" +#include "mpcommon.h" +#include "sub/ass_mp.h" + + +#define HEIGHT_SORT_BITS 4 +static int size_index(int s) +{ + int n = av_log2_16bit(s); + return (n << HEIGHT_SORT_BITS) + + (- 1 - (s << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1); +} + +/* Pack the given rectangles into an area of size w * h. + * The size of each rectangle is read from in[i].x / in[i].y. + * The height of each rectangle must be less than 65536. + * 'scratch' must point to work memory for num_rects+16 ints. + * The packed position for rectangle number i is set in out[i]. + * Return 0 on success, -1 if the rectangles did not fit in w*h. + * + * The rectangles are placed in rows in order approximately sorted by + * height (the approximate sorting is simpler than a full one would be, + * and allows the algorithm to work in linear time). Additionally, to + * reduce wasted space when there are a few tall rectangles, empty + * lower-right parts of rows are filled recursively when the size of + * rectangles in the row drops past a power-of-two threshold. So if a + * row starts with rectangles of size 3x50, 10x40 and 5x20 then the + * free rectangle with corners (13, 20)-(w, 50) is filled recursively. + */ +static int pack_rectangles(struct pos *in, struct pos *out, int num_rects, + int w, int h, int *scratch) +{ + int bins[16 << HEIGHT_SORT_BITS]; + int sizes[16 << HEIGHT_SORT_BITS] = { 0 }; + for (int i = 0; i < num_rects; i++) + sizes[size_index(in[i].y)]++; + int idx = 0; + for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) { + for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) { + bins[i + j] = idx; + idx += sizes[i + j]; + } + scratch[idx++] = -1; + } + for (int i = 0; i < num_rects; i++) + scratch[bins[size_index(in[i].y)]++] = i; + for (int i = 0; i < 16; i++) + bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS]; + struct { + int size, x, bottom; + } stack[16] = {{15, 0, h}}, s = {}; + int stackpos = 1; + int y; + while (stackpos) { + y = s.bottom; + s = stack[--stackpos]; + s.size++; + while (s.size--) { + int maxy = -1; + int obj; + while ((obj = scratch[bins[s.size]]) >= 0) { + int bottom = y + in[obj].y; + if (bottom > s.bottom) + break; + int right = s.x + in[obj].x; + if (right > w) + break; + bins[s.size]++; + out[obj] = (struct pos){s.x, y}; + num_rects--; + if (maxy < 0) + stack[stackpos++] = s; + s.x = right; + maxy = FFMAX(maxy, bottom); + } + if (maxy > 0) + s.bottom = maxy; + } + } + return num_rects ? -1 : 0; +} + +int packer_pack(struct bitmap_packer *packer) +{ + if (packer->count == 0) + return 0; + int w_orig = packer->w, h_orig = packer->h; + struct pos *in = packer->in; + int xmax = 0, ymax = 0; + for (int i = 0; i < packer->count; i++) { + if (in[i].x == 0 || in[i].y == 0) + in[i] = (struct pos){0, 0}; + if (in[i].x < 0 || in [i].x > 65535 || in[i].y < 0 || in[i].y > 65535) { + mp_msg(MSGT_VO, MSGL_FATAL, "Invalid OSD / subtitle bitmap size\n"); + abort(); + } + xmax = FFMAX(xmax, in[i].x); + ymax = FFMAX(ymax, in[i].y); + } + if (xmax > packer->w) + packer->w = 1 << av_log2(xmax - 1) + 1; + if (ymax > packer->h) + packer->h = 1 << av_log2(ymax - 1) + 1; + while (1) { + if (pack_rectangles(in, packer->result, packer->count, packer->w, + packer->h, packer->scratch) >= 0) + return packer->w != w_orig || packer->h != h_orig; + if (packer->w <= packer->h && packer->w != packer->w_max) + packer->w = FFMIN(packer->w * 2, packer->w_max); + else if (packer->h != packer->h_max) + packer->h = FFMIN(packer->h * 2, packer->h_max); + else + return -1; + } +} + +void packer_set_size(struct bitmap_packer *packer, int size) +{ + packer->count = size; + if (size <= packer->asize) + return; + packer->asize = FFMAX(packer->asize * 2, size); + talloc_free(packer->result); + talloc_free(packer->scratch); + packer->in = talloc_realloc(packer, packer->in, struct pos, packer->asize); + packer->result = talloc_array_ptrtype(packer, packer->result, + packer->asize); + packer->scratch = talloc_array_ptrtype(packer, packer->scratch, + packer->asize + 16); +} + +int packer_pack_from_assimg(struct bitmap_packer *packer, + struct ass_image *imglist) +{ + int count = 0; + struct ass_image *img = imglist; + while (img) { + if (count >= packer->asize) + packer_set_size(packer, FFMAX(packer->asize * 2, 32)); + packer->in[count].x = img->w; + packer->in[count].y = img->h; + img = img->next; + count++; + } + packer->count = count; + return packer_pack(packer); +} diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h new file mode 100644 index 0000000000..45b6fbc4ae --- /dev/null +++ b/libvo/bitmap_packer.h @@ -0,0 +1,47 @@ +#ifndef MPLAYER_PACK_RECTANGLES_H +#define MPLAYER_PACK_RECTANGLES_H + +struct pos { + int x; + int y; +}; + +struct bitmap_packer { + int w; + int h; + int w_max; + int h_max; + int count; + struct pos *in; + struct pos *result; + + // internal + int *scratch; + int asize; +}; + +struct ass_image; + +/* Reallocate packer->in for at least to desired number of items. + * Also sets packer->count to the same value. + */ +void packer_set_size(struct bitmap_packer *packer, int size); + +/* To use this, set packer->count to number of rectangles, w_max and h_max + * to maximum output rectangle size, and w and h to start size (may be 0). + * Write input sizes in packer->in. + * Resulting packing will be written in packer->result. + * w and h will be increased if necessary for successful packing. + * Return value is -1 if packing failed because w and h were set to max + * values but that wasn't enough, 1 if w or h was increased, and 0 otherwise. + */ +int packer_pack(struct bitmap_packer *packer); + +/* Like above, but packer->count will be automatically set and + * packer->in will be reallocated if needed and filled from the + * given image list. + */ +int packer_pack_from_assimg(struct bitmap_packer *packer, + struct ass_image *imglist); + +#endif diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 52e7abaa0c..d9b59c7dbe 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -33,6 +33,10 @@ #include #include #include +#include + +#include +#include #include "config.h" #include "mp_msg.h" @@ -47,14 +51,8 @@ #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" #include "osdep/timer.h" - -#include "libavcodec/vdpau.h" - -#include "libavutil/common.h" -#include "libavutil/mathematics.h" - #include "sub/ass_mp.h" -#include "eosd_packer.h" +#include "bitmap_packer.h" #define WRAP_ADD(x, a, m) ((a) < 0 \ ? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \ @@ -81,9 +79,6 @@ #define MAX_VIDEO_SURFACES 50 #define NUM_BUFFERED_VIDEO 5 -/* number of palette entries */ -#define PALETTE_SIZE 256 - /* Pixelformat used for output surfaces */ #define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8 @@ -97,6 +92,8 @@ struct vdp_functions { #undef VDP_FUNCTION }; +#define MAX_OLD_OSD_BITMAPS 6 + struct vdpctx { struct vdp_functions *vdp; @@ -113,7 +110,7 @@ struct vdpctx { unsigned int last_sync_update; /* an extra last output surface is used for OSD and screenshots */ - VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES + 1]; + VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES]; int num_output_surfaces; struct buffered_video_surface { VdpVideoSurface surface; @@ -164,14 +161,31 @@ struct vdpctx { VdpYCbCrFormat vdp_pixel_format; /* draw_osd */ - unsigned char *index_data; - int index_data_size; - uint32_t palette[PALETTE_SIZE]; + struct old_osd { + int x0, y0, w, h; + unsigned char *src, *srca; + int stride; + } old_osd_elements[MAX_OLD_OSD_BITMAPS]; + int old_osd_count; + unsigned char *osd_data_temp; + int osd_data_size; // EOSD - // Pool of surfaces - VdpBitmapSurface eosd_surface; - struct eosd_packer *eosd_packer; + struct eosd_bitmap_surface { + VdpBitmapSurface surface; + uint32_t max_width; + uint32_t max_height; + struct bitmap_packer *packer; + } eosd_surface, osd_surface; + + // List of surfaces to be rendered + struct eosd_target { + VdpRect source; + VdpRect dest; + VdpColor color; + } *eosd_targets, osd_targets[MAX_OLD_OSD_BITMAPS][2]; + int eosd_targets_size; + int eosd_render_count; // Video equalizer struct mp_csp_equalizer video_eq; @@ -366,7 +380,6 @@ static void resize(struct vo *vo) struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; - int i; struct vo_rect src_rect; struct vo_rect dst_rect; struct vo_rect borders; @@ -402,12 +415,13 @@ static void resize(struct vo *vo) min_output_height); } // Creation of output_surfaces - for (i = 0; i <= vc->num_output_surfaces; i++) { + for (int i = 0; i < vc->num_output_surfaces; i++) if (vc->output_surfaces[i] != VDP_INVALID_HANDLE) { vdp_st = vdp->output_surface_destroy(vc->output_surfaces[i]); CHECK_ST_WARNING("Error when calling " "vdp_output_surface_destroy"); } + for (int i = 0; i < vc->num_output_surfaces; i++) { vdp_st = vdp->output_surface_create(vc->vdp_device, OUTPUT_RGBA_FORMAT, vc->output_surface_width, @@ -752,8 +766,6 @@ static int create_vdp_decoder(struct vo *vo, int max_refs) static int initialize_vdpau_objects(struct vo *vo) { struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; vc->vdp_chroma_type = VDP_CHROMA_TYPE_420; switch (vc->image_format) { @@ -779,16 +791,6 @@ static int initialize_vdpau_objects(struct vo *vo) if (create_vdp_mixer(vo, vc->vdp_chroma_type) < 0) return -1; - int max_width = 0, max_height = 0; - vdp_st = vdp-> - bitmap_surface_query_capabilities(vc->vdp_device, - VDP_RGBA_FORMAT_A8, - &(VdpBool){0}, - &max_width, - &max_height); - CHECK_ST_WARNING("Query to get max EOSD surface size failed"); - eosd_packer_reinit(vc->eosd_packer, max_width, max_height); - forget_frames(vo); resize(vo); return 0; @@ -805,12 +807,16 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) vc->video_mixer = VDP_INVALID_HANDLE; vc->flip_queue = VDP_INVALID_HANDLE; vc->flip_target = VDP_INVALID_HANDLE; - for (int i = 0; i <= MAX_OUTPUT_SURFACES; i++) + for (int i = 0; i < MAX_OUTPUT_SURFACES; i++) vc->output_surfaces[i] = VDP_INVALID_HANDLE; vc->vdp_device = VDP_INVALID_HANDLE; - vc->eosd_surface = VDP_INVALID_HANDLE; - eosd_packer_reinit(vc->eosd_packer, 0, 0); + talloc_free(vc->osd_surface.packer); + talloc_free(vc->eosd_surface.packer); + vc->osd_surface = vc->eosd_surface = (struct eosd_bitmap_surface){ + .surface = VDP_INVALID_HANDLE, + }; vc->output_surface_width = vc->output_surface_height = -1; + vc->eosd_render_count = 0; } static int handle_preemption(struct vo *vo) @@ -934,80 +940,22 @@ static void check_events(struct vo *vo) } } -static void draw_osd_I8A8(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, int stride) +static struct bitmap_packer *make_packer(struct vo *vo, VdpRGBAFormat format) { - struct vo *vo = ctx; struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; - VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; - VdpStatus vdp_st; - int i; - int pitch; - int index_data_size_required; - VdpRect output_indexed_rect_vid; - if (!w || !h) - return; - - index_data_size_required = 2*w*h; - if (vc->index_data_size < index_data_size_required) { - vc->index_data = talloc_realloc_size(vc, vc->index_data, - index_data_size_required); - vc->index_data_size = index_data_size_required; - } - - // index_data creation, component order - I, A, I, A, ..... - for (i = 0; i < h; i++) - for (int j = 0; j < w; j++) { - vc->index_data[i*2*w + j*2] = src [i*stride+j]; - vc->index_data[i*2*w + j*2 + 1] = -srca[i*stride+j]; - } - - output_indexed_rect_vid.x0 = x0; - output_indexed_rect_vid.y0 = y0; - output_indexed_rect_vid.x1 = x0 + w; - output_indexed_rect_vid.y1 = y0 + h; - - pitch = w*2; - - // write source_data to osd_surface. - VdpOutputSurface osd_surface = vc->output_surfaces[vc->num_output_surfaces]; - vdp_st = vdp-> - output_surface_put_bits_indexed(osd_surface, VDP_INDEXED_FORMAT_I8A8, - (const void *const*)&vc->index_data, - &pitch, &output_indexed_rect_vid, - VDP_COLOR_TABLE_FORMAT_B8G8R8X8, - (void *)vc->palette); - CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed"); - - VdpOutputSurfaceRenderBlendState blend_state = { - .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, - .blend_factor_source_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, - .blend_factor_source_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, - .blend_factor_destination_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .blend_factor_destination_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - }; - - vdp_st = vdp-> - output_surface_render_output_surface(output_surface, - &output_indexed_rect_vid, - osd_surface, - &output_indexed_rect_vid, - NULL, &blend_state, - VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); - CHECK_ST_WARNING("Error when calling " - "vdp_output_surface_render_output_surface"); + struct bitmap_packer *packer = talloc_zero(vo, struct bitmap_packer); + uint32_t w_max = 0, h_max = 0; + VdpStatus vdp_st = vdp-> + bitmap_surface_query_capabilities(vc->vdp_device, format, + &(VdpBool){0}, &w_max, &h_max); + CHECK_ST_WARNING("Query to get max EOSD surface size failed"); + packer->w_max = w_max; + packer->h_max = h_max; + return packer; } -#define EOSD_VDP_RC(r) &(VdpRect){r.x0, r.y0, r.x1, r.y1} - static void draw_eosd(struct vo *vo) { struct vdpctx *vc = vo->priv; @@ -1030,20 +978,13 @@ static void draw_eosd(struct vo *vo) .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, }; - for (i = 0; i < vc->eosd_packer->targets_count; i++) { - struct eosd_target *target = &vc->eosd_packer->targets[i]; - VdpColor color = { - .alpha = 1.0 - ((target->color >> 0) & 0xff) / 255.0, - .blue = ((target->color >> 8) & 0xff) / 255.0, - .green = ((target->color >> 16) & 0xff) / 255.0, - .red = ((target->color >> 24) & 0xff) / 255.0, - }; + for (i = 0; i < vc->eosd_render_count; i++) { vdp_st = vdp-> output_surface_render_bitmap_surface(output_surface, - EOSD_VDP_RC(target->dest), - vc->eosd_surface, - EOSD_VDP_RC(target->source), - &color, + &vc->eosd_targets[i].dest, + vc->eosd_surface.surface, + &vc->eosd_targets[i].source, + &vc->eosd_targets[i].color, &blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); CHECK_ST_WARNING("EOSD: Error when rendering"); @@ -1055,41 +996,215 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; - struct eosd_packer *packer = vc->eosd_packer; - int i; + struct eosd_bitmap_surface *sfc = &vc->eosd_surface; + bool need_upload = false; - bool need_repos, need_upload, need_resize; - eosd_packer_generate(packer, imgs, &need_repos, &need_upload, &need_resize); + if (imgs->changed == 0 && sfc->packer) + return; // Nothing changed and we still have the old data - if (!need_upload) + vc->eosd_render_count = 0; + + if (!imgs->imgs) + return; // There's nothing to render! + + if (imgs->changed == 1) + goto eosd_skip_upload; + + need_upload = true; + if (!sfc->packer) + sfc->packer = make_packer(vo, VDP_RGBA_FORMAT_A8); + int r = packer_pack_from_assimg(sfc->packer, imgs->imgs); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on " + "a surface with the maximum supported size\n"); return; - - if (need_resize) { - if (vc->eosd_surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface); + } else if (r == 1) { + if (sfc->surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->bitmap_surface_destroy(sfc->surface); CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); } + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for " + "EOSD bitmaps.\n", sfc->packer->w, sfc->packer->h); vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8, - packer->surface.w, packer->surface.h, - true, &vc->eosd_surface); + sfc->packer->w, sfc->packer->h, + true, &sfc->surface); if (vdp_st != VDP_STATUS_OK) - vc->eosd_surface = VDP_INVALID_HANDLE; + sfc->surface = VDP_INVALID_HANDLE; CHECK_ST_WARNING("EOSD: error when creating surface"); } - if (vc->eosd_surface == VDP_INVALID_HANDLE) +eosd_skip_upload: + if (sfc->surface == VDP_INVALID_HANDLE) return; + if (sfc->packer->count > vc->eosd_targets_size) { + talloc_free(vc->eosd_targets); + vc->eosd_targets_size = sfc->packer->count; + vc->eosd_targets = talloc_size(vc, vc->eosd_targets_size + * sizeof(*vc->eosd_targets)); + } - for (i = 0; i < vc->eosd_packer->targets_count; i++) { - struct eosd_target *target = &vc->eosd_packer->targets[i]; - ASS_Image *p = target->ass_img; + int i = 0; + for (ASS_Image *p = imgs->imgs; p; p = p->next, i++) { + if (p->w == 0 || p->h == 0) + continue; + struct eosd_target *target = &vc->eosd_targets[vc->eosd_render_count]; + int x = sfc->packer->result[i].x; + int y = sfc->packer->result[i].y; + target->source = (VdpRect){x, y, x + p->w, y + p->h}; + if (need_upload) { + vdp_st = vdp-> + bitmap_surface_put_bits_native(sfc->surface, + (const void *) &p->bitmap, + &p->stride, &target->source); + CHECK_ST_WARNING("EOSD: putbits failed"); + } + // Render dest, color, etc. + target->color.alpha = 1.0 - ((p->color >> 0) & 0xff) / 255.0; + target->color.blue = ((p->color >> 8) & 0xff) / 255.0; + target->color.green = ((p->color >> 16) & 0xff) / 255.0; + target->color.red = ((p->color >> 24) & 0xff) / 255.0; + target->dest.x0 = p->dst_x; + target->dest.y0 = p->dst_y; + target->dest.x1 = p->w + p->dst_x; + target->dest.y1 = p->h + p->dst_y; + vc->eosd_render_count++; + } +} + +static void record_osd(void *ctx, int x0, int y0, int w, int h, + unsigned char *src, unsigned char *srca, int stride) +{ + struct vo *vo = ctx; + struct vdpctx *vc = vo->priv; + + assert(vc->old_osd_count < MAX_OLD_OSD_BITMAPS); + if (!w || !h) + return; + vc->old_osd_elements[vc->old_osd_count++] = (struct old_osd){ + x0, y0, w, h, src, srca, stride}; +} + +static void render_old_osd(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; + VdpStatus vdp_st; + struct eosd_bitmap_surface *sfc = &vc->osd_surface; + + if (!sfc->packer) + sfc->packer = make_packer(vo, VDP_RGBA_FORMAT_A8); + + packer_set_size(sfc->packer, vc->old_osd_count * 2); + for (int i = 0; i < vc->old_osd_count; i++) { + struct old_osd *o = &vc->old_osd_elements[i]; + sfc->packer->in[i*2] = sfc->packer->in[i*2 + 1] = + (struct pos){o->w, o->h}; + }; + int r = packer_pack(sfc->packer); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] OSD bitmaps do not fit on " + "a surface with the maximum supported size\n"); + vc->old_osd_count = 0; + return; + } else if (r == 1) { + if (sfc->surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->bitmap_surface_destroy(sfc->surface); + CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); + } + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for " + "OSD bitmaps.\n", sfc->packer->w, sfc->packer->h); + vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8, + sfc->packer->w, sfc->packer->h, + true, &sfc->surface); + if (vdp_st != VDP_STATUS_OK) + sfc->surface = VDP_INVALID_HANDLE; + CHECK_ST_WARNING("OSD: error when creating surface"); + } + + for (int i = 0; i < vc->old_osd_count; i++) { + struct old_osd *o = &vc->old_osd_elements[i]; + struct eosd_target *target1 = &vc->osd_targets[i][0]; + struct eosd_target *target2 = &vc->osd_targets[i][1]; + int w = o->w, h = o->h; + int sx = sfc->packer->result[i * 2].x; + int sy = sfc->packer->result[i * 2].y; + target1->source = (VdpRect){ sx, sy, sx + w, sy + h }; + target1->dest = (VdpRect){ o->x0, o->y0, o->x0 + w, o->y0 + h }; + sx = sfc->packer->result[i * 2 + 1].x; + sy = sfc->packer->result[i * 2 + 1].y; + target2->source = (VdpRect){ sx, sy, sx + w, sy + h }; + target2->dest = target1->dest; + vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface, + &(const void *){o->src}, + &(uint32_t){o->stride}, + &target1->source); + CHECK_ST_WARNING("OSD: putbits failed"); + int size_required = w * h; + if (vc->osd_data_size < size_required) { + talloc_free(vc->osd_data_temp); + vc->osd_data_temp = talloc_size(vc, size_required); + vc->osd_data_size = size_required; + } + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) + vc->osd_data_temp[y * w + x] = -o->srca[y * o->stride + x]; + vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface, + &(const void *){vc->osd_data_temp}, + &(uint32_t){w}, + &target2->source); + CHECK_ST_WARNING("OSD: putbits failed"); + } + + VdpOutputSurfaceRenderBlendState blend_state_alpha = { + .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, + .blend_factor_source_color = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO, + .blend_factor_source_alpha = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO, + .blend_factor_destination_color = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .blend_factor_destination_alpha = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + }; + + VdpOutputSurfaceRenderBlendState blend_state_gray = { + .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, + .blend_factor_source_color = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, + .blend_factor_source_alpha = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, + .blend_factor_destination_color = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, + .blend_factor_destination_alpha = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, + .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + }; + + for (int i = 0; i < vc->old_osd_count; i++) { + struct eosd_target *target1 = &vc->osd_targets[i][0]; + struct eosd_target *target2 = &vc->osd_targets[i][1]; vdp_st = vdp-> - bitmap_surface_put_bits_native(vc->eosd_surface, - (const void *) &p->bitmap, - &p->stride, - EOSD_VDP_RC(target->source)); - CHECK_ST_WARNING("EOSD: putbits failed"); - target->ass_img = NULL; + output_surface_render_bitmap_surface(output_surface, + &target2->dest, + vc->osd_surface.surface, + &target2->source, + &(VdpColor){1, 1, 1, 1}, + &blend_state_alpha, + VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); + CHECK_ST_WARNING("OSD: Error when rendering"); + vdp_st = vdp-> + output_surface_render_bitmap_surface(output_surface, + &target1->dest, + vc->osd_surface.surface, + &target1->source, + &(VdpColor){1, 1, 1, 1}, + &blend_state_gray, + VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); + CHECK_ST_WARNING("OSD: Error when rendering"); } } @@ -1100,9 +1215,11 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) if (handle_preemption(vo) < 0) return; + vc->old_osd_count = 0; osd_draw_text_ext(osd, vo->dwidth, vo->dheight, vc->border_x, vc->border_y, vc->border_x, vc->border_y, vc->vid_width, - vc->vid_height, draw_osd_I8A8, vo); + vc->vid_height, record_osd, vo); + render_old_osd(vo); } static int update_presentation_queue_status(struct vo *vo) @@ -1448,15 +1565,20 @@ static void destroy_vdpau_objects(struct vo *vo) "vdp_presentation_queue_target_destroy"); } - for (i = 0; i <= vc->num_output_surfaces; i++) { + for (i = 0; i < vc->num_output_surfaces; i++) { if (vc->output_surfaces[i] == VDP_INVALID_HANDLE) continue; vdp_st = vdp->output_surface_destroy(vc->output_surfaces[i]); CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy"); } - if (vc->eosd_surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface); + if (vc->eosd_surface.surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface.surface); + CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); + } + + if (vc->osd_surface.surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->bitmap_surface_destroy(vc->osd_surface.surface); CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); } @@ -1486,8 +1608,6 @@ static int preinit(struct vo *vo, const char *arg) { struct vdpctx *vc = vo->priv; - vc->eosd_packer = eosd_packer_create(vo); - // Mark everything as invalid first so uninit() can tell what has been // allocated mark_vdpau_objects_uninitialized(vo); @@ -1511,10 +1631,6 @@ static int preinit(struct vo *vo, const char *arg) return -1; } - // full grayscale palette. - for (int i = 0; i < PALETTE_SIZE; ++i) - vc->palette[i] = (i << 16) | (i << 8) | i; - return 0; }