diff options
Diffstat (limited to 'video/out/opengl/osd.c')
-rw-r--r-- | video/out/opengl/osd.c | 211 |
1 files changed, 122 insertions, 89 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c index c554425e0f..7b1ec162fd 100644 --- a/video/out/opengl/osd.c +++ b/video/out/opengl/osd.c @@ -17,19 +17,16 @@ #include <stdlib.h> #include <assert.h> +#include <limits.h> + #include <libavutil/common.h> #include "video/out/bitmap_packer.h" +#include "formats.h" #include "utils.h" #include "osd.h" -struct osd_fmt_entry { - GLint internal_format; - GLint format; - GLenum type; -}; - // glBlendFuncSeparate() arguments static const int blend_factors[SUBBITMAP_COUNT][4] = { [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, @@ -38,21 +35,6 @@ static const int blend_factors[SUBBITMAP_COUNT][4] = { GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, }; -static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE}, - [SUBBITMAP_RGBA] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, -}; - -static const struct osd_fmt_entry osd_to_gles3_formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, - [SUBBITMAP_RGBA] = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, -}; - -static const struct osd_fmt_entry osd_to_gl2_formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE}, - [SUBBITMAP_RGBA] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, -}; - struct vertex { float position[2]; float texcoord[2]; @@ -77,16 +59,17 @@ struct mpgl_osd_part { struct sub_bitmap *subparts; struct vertex *vertices; struct bitmap_packer *packer; + void *upload; }; struct mpgl_osd { struct mp_log *log; struct osd_state *osd; GL *gl; + GLint max_tex_wh; bool use_pbo; - bool scaled; struct mpgl_osd_part *parts[MAX_OSD_PARTS]; - const struct osd_fmt_entry *fmt_table; + const struct gl_format *fmt_table[SUBBITMAP_COUNT]; bool formats[SUBBITMAP_COUNT]; struct gl_vao vao; int64_t change_counter; @@ -98,37 +81,32 @@ struct mpgl_osd { struct mpgl_osd *mpgl_osd_init(GL *gl, struct mp_log *log, struct osd_state *osd) { - GLint max_texture_size; - gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx); *ctx = (struct mpgl_osd) { .log = log, .osd = osd, .gl = gl, - .fmt_table = osd_to_gl3_formats, .scratch = talloc_zero_size(ctx, 1), }; - if (gl->es >= 300) { - ctx->fmt_table = osd_to_gles3_formats; - } else if (!(gl->mpgl_caps & MPGL_CAP_TEX_RG)) { - ctx->fmt_table = osd_to_gl2_formats; - } + gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &ctx->max_tex_wh); + + ctx->fmt_table[SUBBITMAP_LIBASS] = gl_find_unorm_format(gl, 1, 1); + ctx->fmt_table[SUBBITMAP_RGBA] = gl_find_unorm_format(gl, 1, 4); for (int n = 0; n < MAX_OSD_PARTS; n++) { struct mpgl_osd_part *p = talloc_ptrtype(ctx, p); *p = (struct mpgl_osd_part) { .packer = talloc_struct(p, struct bitmap_packer, { - .w_max = max_texture_size, - .h_max = max_texture_size, + .w_max = ctx->max_tex_wh, + .h_max = ctx->max_tex_wh, }), }; ctx->parts[n] = p; } for (int n = 0; n < SUBBITMAP_COUNT; n++) - ctx->formats[n] = ctx->fmt_table[n].type != 0; + ctx->formats[n] = !!ctx->fmt_table[n]; gl_vao_init(&ctx->vao, gl, sizeof(struct vertex), vertex_vao); @@ -149,6 +127,7 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx) gl->DeleteTextures(1, &p->texture); if (gl->DeleteBuffers) gl->DeleteBuffers(1, &p->buffer); + talloc_free(p->upload); } talloc_free(ctx); } @@ -158,38 +137,79 @@ void mpgl_osd_set_options(struct mpgl_osd *ctx, bool pbo) ctx->use_pbo = pbo; } -static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, - struct sub_bitmaps *imgs) +static bool upload(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs, bool pbo) { GL *gl = ctx->gl; bool success = true; - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - int pix_stride = glFmt2bpp(fmt.format, fmt.type); + const struct gl_format *fmt = ctx->fmt_table[imgs->format]; + size_t pix_stride = gl_bytes_per_pixel(fmt->format, fmt->type); + size_t buffer_size = pix_stride * osd->h * osd->w; + + char *data = NULL; + void *texdata = NULL; + + if (pbo) { + if (!osd->buffer) { + gl->GenBuffers(1, &osd->buffer); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); + gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL, + GL_DYNAMIC_COPY); + } - if (!osd->buffer) { - gl->GenBuffers(1, &osd->buffer); gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, osd->w * osd->h * pix_stride, - NULL, GL_DYNAMIC_COPY); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + data = gl->MapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buffer_size, + GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + if (!data) { + success = false; + goto done; + } + } else { + if (!imgs->packed) { + if (!osd->upload) + osd->upload = talloc_size(NULL, buffer_size); + data = osd->upload; + texdata = data; + } } - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - if (!data) { - success = false; + int copy_w = 0; + int copy_h = 0; + size_t stride = 0; + if (imgs->packed) { + copy_w = imgs->packed_w; + copy_h = imgs->packed_h; + stride = imgs->packed->stride[0]; + texdata = imgs->packed->planes[0]; + if (pbo) { + memcpy_pic(data, texdata, pix_stride * copy_w, copy_h, + osd->w * pix_stride, stride); + stride = osd->w * pix_stride; + texdata = NULL; + } } else { struct pos bb[2]; packer_get_bb(osd->packer, bb); - size_t stride = osd->w * pix_stride; + copy_w = bb[1].x; + copy_h = bb[1].y; + stride = osd->w * pix_stride; packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride); - if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) + } + + if (pbo) { + if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) { success = false; - glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride, - bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, 0); + goto done; + } } - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + gl_upload_tex(gl, GL_TEXTURE_2D, fmt->format, fmt->type, texdata, stride, + 0, 0, copy_w, copy_h); + + if (pbo) + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + +done: if (!success) { MP_FATAL(ctx, "Error: can't upload subtitles! " "Remove the 'pbo' suboption.\n"); @@ -198,24 +218,13 @@ static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, return success; } -static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, - struct sub_bitmaps *imgs) +static int next_pow2(int v) { - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - if (osd->packer->padding) { - struct pos bb[2]; - packer_get_bb(osd->packer, bb); - glClearTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, - bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y, - 0, &ctx->scratch); - } - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *s = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, - s->bitmap, s->stride, p.x, p.y, s->w, s->h, 0); + for (int x = 0; x < 30; x++) { + if ((1 << x) >= v) + return 1 << x; } + return INT_MAX; } static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, @@ -223,32 +232,46 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, { GL *gl = ctx->gl; - // assume 2x2 filter on scaling - osd->packer->padding = ctx->scaled || imgs->scaled; - int r = packer_pack_from_subbitmaps(osd->packer, imgs); - if (r < 0) { + int req_w = 0; + int req_h = 0; + + if (imgs->packed) { + req_w = next_pow2(imgs->packed_w); + req_h = next_pow2(imgs->packed_h); + } else { + // assume 2x2 filter on scaling + osd->packer->padding = imgs->scaled; + int r = packer_pack_from_subbitmaps(osd->packer, imgs); + if (r < 0) { + MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum " + "supported size %dx%d.\n", osd->packer->w_max, osd->packer->h_max); + return false; + } + req_w = osd->packer->w; + req_h = osd->packer->h; + } + + if (req_w > ctx->max_tex_wh || req_h > ctx->max_tex_wh) { MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum " - "supported size %dx%d.\n", osd->packer->w_max, osd->packer->h_max); + "supported size %dx%d.\n", ctx->max_tex_wh, ctx->max_tex_wh); return false; } - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - assert(fmt.type != 0); + const struct gl_format *fmt = ctx->fmt_table[imgs->format]; + assert(fmt); if (!osd->texture) gl->GenTextures(1, &osd->texture); gl->BindTexture(GL_TEXTURE_2D, osd->texture); - if (osd->packer->w > osd->w || osd->packer->h > osd->h - || osd->format != imgs->format) - { + if (req_w > osd->w || req_h > osd->h || osd->format != imgs->format) { osd->format = imgs->format; - osd->w = FFMAX(32, osd->packer->w); - osd->h = FFMAX(32, osd->packer->h); + osd->w = FFMAX(32, req_w); + osd->h = FFMAX(32, req_h); - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->w, osd->h, - 0, fmt.format, fmt.type, NULL); + gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format, osd->w, osd->h, + 0, fmt->format, fmt->type, NULL); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -258,13 +281,16 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, if (gl->DeleteBuffers) gl->DeleteBuffers(1, &osd->buffer); osd->buffer = 0; + + talloc_free(osd->upload); + osd->upload = NULL; } bool uploaded = false; if (ctx->use_pbo) - uploaded = upload_pbo(ctx, osd, imgs); + uploaded = upload(ctx, osd, imgs, true); if (!uploaded) - upload_tex(ctx, osd, imgs); + upload(ctx, osd, imgs, false); gl->BindTexture(GL_TEXTURE_2D, 0); @@ -280,18 +306,26 @@ static void gen_osd_cb(void *pctx, struct sub_bitmaps *imgs) struct mpgl_osd_part *osd = ctx->parts[imgs->render_index]; + bool ok = true; if (imgs->change_id != osd->change_id) { if (!upload_osd(ctx, osd, imgs)) - osd->packer->count = 0; + ok = false; osd->change_id = imgs->change_id; ctx->change_counter += 1; } - osd->num_subparts = osd->packer->count; + osd->num_subparts = ok ? imgs->num_parts : 0; MP_TARRAY_GROW(osd, osd->subparts, osd->num_subparts); memcpy(osd->subparts, imgs->parts, osd->num_subparts * sizeof(osd->subparts[0])); + + if (!imgs->packed) { + for (int n = 0; n < osd->num_subparts; n++) { + osd->subparts[n].src_x = osd->packer->result[n].x; + osd->subparts[n].src_y = osd->packer->result[n].y; + } + } } static void write_quad(struct vertex *va, struct gl_transform t, @@ -319,7 +353,6 @@ static int generate_verts(struct mpgl_osd_part *part, struct gl_transform t) for (int n = 0; n < part->num_subparts; n++) { struct sub_bitmap *b = &part->subparts[n]; - struct pos pos = part->packer->result[n]; struct vertex *va = part->vertices; // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it @@ -330,7 +363,7 @@ static int generate_verts(struct mpgl_osd_part *part, struct gl_transform t) write_quad(&va[n * 6], t, b->x, b->y, b->x + b->dw, b->y + b->dh, - pos.x, pos.y, pos.x + b->w, pos.y + b->h, + b->src_x, b->src_y, b->src_x + b->w, b->src_y + b->h, part->w, part->h, color); } |