From cadff3eec75bdd81fb0d18cd0ac029faa3c318d2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 3 Oct 2012 18:25:41 +0200 Subject: vo_gl3: move OSD code to gl_osd.c Other OpenGL-using VOs can use this. gl_osd.c includes some code for vo_gl.c. The next commit actually makes use of it. --- Makefile | 2 +- libvo/bitmap_packer.c | 25 ++++ libvo/bitmap_packer.h | 10 ++ libvo/gl_common.c | 3 + libvo/gl_osd.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++ libvo/gl_osd.h | 41 +++++++ libvo/vo_gl3.c | 247 ++++++++------------------------------ 7 files changed, 449 insertions(+), 201 deletions(-) create mode 100644 libvo/gl_osd.c create mode 100644 libvo/gl_osd.h diff --git a/Makefile b/Makefile index 27aa1997dd..9c782e27fe 100644 --- a/Makefile +++ b/Makefile @@ -284,7 +284,7 @@ SRCS_MPLAYER-$(COREAUDIO) += libao2/ao_coreaudio.c SRCS_MPLAYER-$(COREVIDEO) += libvo/vo_corevideo.m SRCS_MPLAYER-$(DIRECT3D) += libvo/vo_direct3d.c libvo/w32_common.c SRCS_MPLAYER-$(GL) += libvo/gl_common.c libvo/vo_gl.c libvo/vo_gl3.c \ - pnm_loader.c + pnm_loader.c libvo/gl_osd.c SRCS_MPLAYER-$(ENCODING) += libvo/vo_lavc.c libao2/ao_lavc.c encode_lavc.c SRCS_MPLAYER-$(GL_WIN32) += libvo/w32_common.c SRCS_MPLAYER-$(GL_X11) += libvo/x11_common.c diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c index 5e5bafea0c..9d3df70c34 100644 --- a/libvo/bitmap_packer.c +++ b/libvo/bitmap_packer.c @@ -20,6 +20,7 @@ */ #include +#include #include @@ -29,6 +30,9 @@ #include "mpcommon.h" #include "sub/ass_mp.h" #include "sub/dec_sub.h" +#include "fastmemcpy.h" + +#define IS_POWER_OF_2(x) (((x) > 0) && !(((x) - 1) & (x))) void packer_reset(struct bitmap_packer *packer) { @@ -160,6 +164,8 @@ int packer_pack(struct bitmap_packer *packer) // No padding at edges packer->used_width = FFMIN(used_width, packer->w); packer->used_height = FFMIN(y, packer->h); + assert(packer->w == 0 || IS_POWER_OF_2(packer->w)); + assert(packer->h == 0 || IS_POWER_OF_2(packer->h)); return packer->w != w_orig || packer->h != h_orig; } if (packer->w <= packer->h && packer->w != packer->w_max) @@ -201,3 +207,22 @@ int packer_pack_from_subbitmaps(struct bitmap_packer *packer, packer->in[i] = (struct pos){b->parts[i].w + a, b->parts[i].h + a}; return packer_pack(packer); } + +void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, + void *data, int pixel_stride, int stride) +{ + assert(packer->count == b->num_parts); + if (packer->padding) { + struct pos bb[2]; + packer_get_bb(packer, bb); + memset_pic(data, 0, bb[1].x * pixel_stride, bb[1].y, stride); + } + for (int n = 0; n < packer->count; n++) { + struct sub_bitmap *s = &b->parts[n]; + struct pos p = packer->result[n]; + + void *pdata = (uint8_t *)data + p.y * stride + p.x * pixel_stride; + memcpy_pic(pdata, s->bitmap, s->w * pixel_stride, s->h, + stride, s->stride); + } +} diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h index 99c7b514b4..b86c3ec4f9 100644 --- a/libvo/bitmap_packer.h +++ b/libvo/bitmap_packer.h @@ -43,6 +43,7 @@ void packer_set_size(struct bitmap_packer *packer, int size); * 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. + * There is a strong guarantee that w and h will be powers of 2 (or set to 0). * 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. */ @@ -55,4 +56,13 @@ int packer_pack(struct bitmap_packer *packer); int packer_pack_from_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b); +// Copy the (already packed) sub-bitmaps from b to the image in data. +// data must point to an image that is at least (packer->w, packer->h) big. +// The image has the given stride (bytes between (x, y) to (x, y + 1)), and the +// pixel format used by both the sub-bitmaps and the image uses pixel_stride +// bytes per pixel (bytes between (x, y) to (x + 1, y)). +// If packer->padding is set, the padding borders are cleared with 0. +void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, + void *data, int pixel_stride, int stride); + #endif diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 8ae94f56f3..4bffc1521f 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "talloc.h" #include "gl_common.h" @@ -45,6 +46,8 @@ #include "aspect.h" #include "pnm_loader.h" #include "options.h" +#include "sub/sub.h" +#include "bitmap_packer.h" //! \defgroup glgeneral OpenGL general helper functions diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c new file mode 100644 index 0000000000..0e99d13652 --- /dev/null +++ b/libvo/gl_osd.c @@ -0,0 +1,322 @@ +/* + * This file is part of mplayer. + * + * mplayer 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. + * + * mplayer 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 mplayer. If not, see . + */ + +#include +#include +#include + +#include "bitmap_packer.h" + +#include "gl_osd.h" + +struct osd_fmt_entry { + GLint internal_format; + GLint format; + GLenum type; +}; + +// glBlendFunc() arguments +static const int blend_factors[SUBBITMAP_COUNT][2] = { + [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [SUBBITMAP_RGBA] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [SUBBITMAP_OLD] = {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_BGRA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_OLD] = {GL_RG, GL_RG, GL_UNSIGNED_BYTE}, +}; + +static const struct osd_fmt_entry osd_to_gl_legacy_formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_OLD] = + {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, +}; + +struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy) +{ + 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) { + .gl = gl, + .fmt_table = legacy ? osd_to_gl_legacy_formats : osd_to_gl3_formats, + .scratch = talloc_zero_size(ctx, 1), + }; + + 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, + }), + }; + ctx->parts[n] = p; + } + + return ctx; +} + +void mpgl_osd_destroy(struct mpgl_osd *ctx) +{ + GL *gl = ctx->gl; + + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct mpgl_osd_part *p = ctx->parts[n]; + gl->DeleteTextures(1, &p->texture); + if (gl->DeleteBuffers) + gl->DeleteBuffers(1, &p->buffer); + } + talloc_free(ctx); +} + +bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format) +{ + return ctx->fmt_table[osd_format].type != 0; +} + +static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + 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); + + 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); + } + + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); + char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (!data) { + success = false; + } else { + struct pos bb[2]; + packer_get_bb(osd->packer, bb); + size_t stride = osd->w * pix_stride; + packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride); + 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); + } + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + if (!success) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " + "Remove the 'pbo' suboption.\n"); + } + + return success; +} + +static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + 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); + } +} + +static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + GL *gl = ctx->gl; + + osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + int r = packer_pack_from_subbitmaps(osd->packer, imgs); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD 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; + } + + struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; + assert(fmt.type != 0); + + 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) + { + osd->format = imgs->format; + osd->w = FFMAX(32, osd->packer->w); + osd->h = FFMAX(32, osd->packer->h); + + 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); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (gl->DeleteBuffers) + gl->DeleteBuffers(1, &osd->buffer); + osd->buffer = 0; + } + + bool uploaded = false; + if (ctx->use_pbo) + uploaded = upload_pbo(ctx, osd, imgs); + if (!uploaded) + upload_tex(ctx, osd, imgs); + + gl->BindTexture(GL_TEXTURE_2D, 0); + + return true; +} + +struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, + struct sub_bitmaps *imgs) +{ + if (imgs->num_parts == 0 || !mpgl_osd_query_format(ctx, imgs->format)) + return NULL; + + struct mpgl_osd_part *osd = ctx->parts[imgs->render_index]; + + if (imgs->bitmap_pos_id != osd->bitmap_pos_id) { + if (imgs->bitmap_id != osd->bitmap_id) { + if (!upload_osd(ctx, osd, imgs)) + osd->packer->count = 0; + } + + osd->bitmap_id = imgs->bitmap_id; + osd->bitmap_pos_id = imgs->bitmap_pos_id; + osd->num_vertices = 0; + } + + return osd->packer->count ? osd : NULL; +} + +void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +{ + GL *gl = ctx->gl; + + gl->BindTexture(GL_TEXTURE_2D, p->texture); + gl->Enable(GL_BLEND); + gl->BlendFunc(blend_factors[p->format][0], blend_factors[p->format][1]); +} + +void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +{ + GL *gl = ctx->gl; + + gl->Disable(GL_BLEND); + gl->BindTexture(GL_TEXTURE_2D, 0); +} + +struct vertex { + float position[2]; + uint8_t color[4]; + float texcoord[2]; +}; + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *imgs) +{ + struct mpgl_osd_part *osd = mpgl_osd_generate(ctx, imgs); + if (!osd) + return; + + if (!osd->num_vertices) { + // 2 triangles primitives per quad = 6 vertices per quad + // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later + osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, + osd->packer->count * 6); + + struct vertex *va = osd->vertices; + float tex_w = osd->w; + float tex_h = osd->h; + + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; + + uint32_t c = imgs->format == SUBBITMAP_LIBASS + ? b->libass.color : 0xFFFFFF00; + uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, 255 - (c & 0xff) }; + + float x0 = b->x; + float y0 = b->y; + float x1 = b->x + b->dw; + float y1 = b->y + b->dh; + float tx0 = p.x / tex_w; + float ty0 = p.y / tex_h; + float tx1 = (p.x + b->w) / tex_w; + float ty1 = (p.y + b->h) / tex_h; + +#define COLOR_INIT {color[0], color[1], color[2], color[3]} + struct vertex *v = &va[osd->num_vertices]; + v[0] = (struct vertex) { {x0, y0}, COLOR_INIT, {tx0, ty0} }; + v[1] = (struct vertex) { {x0, y1}, COLOR_INIT, {tx0, ty1} }; + v[2] = (struct vertex) { {x1, y0}, COLOR_INIT, {tx1, ty0} }; + v[3] = (struct vertex) { {x1, y1}, COLOR_INIT, {tx1, ty1} }; + v[4] = v[2]; + v[5] = v[1]; +#undef COLOR_INIT + osd->num_vertices += 6; + } + } + + GL *gl = ctx->gl; + + struct vertex *va = osd->vertices; + size_t stride = sizeof(va[0]); + + gl->VertexPointer(2, GL_FLOAT, stride, &va[0].position[0]); + gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]); + gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].texcoord[0]); + + gl->EnableClientState(GL_VERTEX_ARRAY); + gl->EnableClientState(GL_TEXTURE_COORD_ARRAY); + gl->EnableClientState(GL_COLOR_ARRAY); + + mpgl_osd_gl_set_state(ctx, osd); + gl->DrawArrays(GL_TRIANGLES, 0, osd->num_vertices); + mpgl_osd_gl_unset_state(ctx, osd); + + gl->DisableClientState(GL_VERTEX_ARRAY); + gl->DisableClientState(GL_TEXTURE_COORD_ARRAY); + gl->DisableClientState(GL_COLOR_ARRAY); +} diff --git a/libvo/gl_osd.h b/libvo/gl_osd.h new file mode 100644 index 0000000000..baebc3311c --- /dev/null +++ b/libvo/gl_osd.h @@ -0,0 +1,41 @@ +#ifndef MPLAYER_GL_OSD_H +#define MPLAYER_GL_OSD_H + +#include +#include + +#include "gl_common.h" +#include "sub/sub.h" + +struct mpgl_osd_part { + enum sub_bitmap_format format; + int bitmap_id, bitmap_pos_id; + GLuint texture; + int w, h; + GLuint buffer; + int num_vertices; + void *vertices; + struct bitmap_packer *packer; +}; + +struct mpgl_osd { + GL *gl; + bool use_pbo; + struct mpgl_osd_part *parts[MAX_OSD_PARTS]; + const struct osd_fmt_entry *fmt_table; + void *scratch; +}; + +struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy); +void mpgl_osd_destroy(struct mpgl_osd *ctx); + +bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format); + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *b); +struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, + struct sub_bitmaps *b); + +void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); +void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); + +#endif diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 5fd4f62af0..934d8f394d 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -50,6 +50,7 @@ #include "bitmap_packer.h" #include "gl_common.h" +#include "gl_osd.h" #include "filter_kernels.h" #include "aspect.h" #include "fastmemcpy.h" @@ -142,17 +143,6 @@ struct fbotex { int vp_w, vp_h; // viewport of fbo / used part of the texture }; -struct osd_render { - enum sub_bitmap_format format; - int bitmap_id, bitmap_pos_id; - GLuint texture; - int width, height; - GLuint buffer; - int num_vertices; - struct vertex *vertices; - struct bitmap_packer *packer; -}; - struct gl_priv { struct vo *vo; MPGLContext *glctx; @@ -186,7 +176,7 @@ struct gl_priv { GLuint osd_programs[SUBBITMAP_COUNT]; GLuint indirect_program, scale_sep_program, final_program; - struct osd_render *osd[MAX_OSD_PARTS]; + struct mpgl_osd *osd; GLuint lut_3d_texture; int lut_3d_w, lut_3d_h, lut_3d_d; @@ -260,23 +250,10 @@ static const struct fmt_entry mp_to_gl_formats[] = { {0}, }; -struct osd_fmt_entry { - GLint internal_format; - GLint format; - int stride; // bytes per pixel - GLenum type; - const char *shader; // shader entry in the .glsl file -}; - -static const struct osd_fmt_entry osd_to_gl_formats[] = { - [SUBBITMAP_LIBASS] - = {GL_RED, GL_RED, 1, GL_UNSIGNED_BYTE, "frag_osd_libass"}, - [SUBBITMAP_RGBA] - = {GL_RGBA, GL_BGRA, 4, GL_UNSIGNED_BYTE, "frag_osd_rgba"}, - [SUBBITMAP_OLD] - = {GL_RG, GL_RG, 2, GL_UNSIGNED_BYTE, "frag_osd_old"}, - // Make array long enough to contain all formats - [SUBBITMAP_COUNT] = {0} +static const char *osd_shaders[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = "frag_osd_libass", + [SUBBITMAP_RGBA] = "frag_osd_rgba", + [SUBBITMAP_OLD] = "frag_osd_old", }; @@ -678,11 +655,11 @@ static void compile_shaders(struct gl_priv *p) shader_def_opt(&header_osd, "USE_3DLUT", p->use_lut_3d); for (int n = 0; n < SUBBITMAP_COUNT; n++) { - struct osd_fmt_entry fmt = osd_to_gl_formats[n]; - if (fmt.shader) { - char *s_osd = get_section(tmp, src, fmt.shader); + const char *name = osd_shaders[n]; + if (name) { + char *s_osd = get_section(tmp, src, name); p->osd_programs[n] = - create_program(gl, fmt.shader, header_osd, vertex_shader, s_osd); + create_program(gl, name, header_osd, vertex_shader, s_osd); } } @@ -947,6 +924,11 @@ static void reinit_rendering(struct gl_priv *p) if (p->indirect_program && !p->indirect_fbo.fbo) fbotex_init(p, &p->indirect_fbo, p->texture_width, p->texture_height); + + if (!p->osd) { + p->osd = mpgl_osd_init(p->gl, false); + p->osd->use_pbo = p->use_pbo; + } } static void uninit_rendering(struct gl_priv *p) @@ -964,6 +946,10 @@ static void uninit_rendering(struct gl_priv *p) gl->DeleteTextures(1, &p->dither_texture); p->dither_texture = 0; + + if (p->osd) + mpgl_osd_destroy(p->osd); + p->osd = NULL; } static void init_lut_3d(struct gl_priv *p) @@ -1409,166 +1395,51 @@ static mp_image_t *get_window_screenshot(struct gl_priv *p) return image; } -static void gen_eosd(struct gl_priv *p, struct osd_render *osd, - struct sub_bitmaps *imgs) +static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) { GL *gl = p->gl; - if (imgs->bitmap_pos_id == osd->bitmap_pos_id) - return; - - osd->num_vertices = 0; - - if (imgs->format == SUBBITMAP_EMPTY || imgs->num_parts == 0) - return; - - bool need_upload = imgs->bitmap_id != osd->bitmap_id; - bool need_allocate = false; - - if (imgs->format != osd->format) { - packer_reset(osd->packer); - osd->format = imgs->format; - need_allocate = true; - } - - osd->bitmap_id = imgs->bitmap_id; - osd->bitmap_pos_id = imgs->bitmap_pos_id; + assert(p->osd); - osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling - int r = packer_pack_from_subbitmaps(osd->packer, imgs); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " - "a surface with the maximum supported size %dx%d.\n", - osd->packer->w_max, osd->packer->h_max); + struct mpgl_osd_part *osd = mpgl_osd_generate(p->osd, imgs); + if (!osd) return; - } else if (r > 0) { - need_allocate = true; - } - - struct osd_fmt_entry fmt = osd_to_gl_formats[imgs->format]; - assert(fmt.shader); - - if (!osd->texture) { - gl->GenTextures(1, &osd->texture); - gl->GenBuffers(1, &osd->buffer); - } - gl->BindTexture(GL_TEXTURE_2D, osd->texture); - - if (need_allocate) { - tex_size(p, osd->packer->w, osd->packer->h, &osd->width, &osd->height); - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->width, - osd->height, 0, fmt.format, fmt.type, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, - osd->width * osd->height * fmt.stride, - NULL, GL_DYNAMIC_COPY); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } + assert(osd->format != SUBBITMAP_EMPTY); - struct pos bb[2]; - packer_get_bb(osd->packer, bb); + if (!osd->num_vertices) { + osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, + osd->packer->count * VERTICES_PER_QUAD); - if (need_upload && p->use_pbo) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - size_t stride = osd->width * fmt.stride; - if (!data) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " - "Remove the 'pbo' suboption.\n"); - } else { - if (imgs->scaled) { - int w = bb[1].x - bb[0].x; - int h = bb[1].y - bb[0].y; - memset_pic(data, 0, w * fmt.stride, h, stride); - } - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; + struct vertex *va = osd->vertices; - void *pdata = data + p.y * stride + p.x * fmt.stride; - memcpy_pic(pdata, b->bitmap, b->w * fmt.stride, b->h, - stride, b->stride); - } - if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] EOSD PBO upload failed. " - "Remove the 'pbo' suboption.\n"); - 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); - need_upload = false; - } - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - if (need_upload) { - // non-PBO upload - if (imgs->scaled) { - glClearTex(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, &p->scratch); - } for (int n = 0; n < osd->packer->count; n++) { struct sub_bitmap *b = &imgs->parts[n]; struct pos p = osd->packer->result[n]; - glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, - b->bitmap, b->stride, p.x, p.y, b->w, b->h, 0); + // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it + // doesn't matter that we upload garbage for the other formats + uint32_t c = b->libass.color; + uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, 255 - (c & 0xff) }; + + write_quad(&va[osd->num_vertices], + b->x, b->y, b->x + b->dw, b->y + b->dh, + p.x, p.y, p.x + b->w, p.y + b->h, + osd->w, osd->h, color, false); + osd->num_vertices += VERTICES_PER_QUAD; } } - gl->BindTexture(GL_TEXTURE_2D, 0); - - debug_check_gl(p, "EOSD upload"); - - osd->vertices = talloc_realloc_size(osd, osd->vertices, - osd->packer->count - * sizeof(struct vertex) - * VERTICES_PER_QUAD); - - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it - // doesn't matter that we upload garbage for the other formats - uint32_t c = b->libass.color; - uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, - (c >> 8) & 0xff, 255 - (c & 0xff) }; - - write_quad(&osd->vertices[osd->num_vertices], - b->x, b->y, b->x + b->dw, b->y + b->dh, - p.x, p.y, p.x + b->w, p.y + b->h, - osd->width, osd->height, color, false); - osd->num_vertices += VERTICES_PER_QUAD; - } -} - -static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) -{ - GL *gl = p->gl; - - struct osd_render *osd = p->osd[imgs->render_index]; - - gen_eosd(p, osd, imgs); - - if (osd->num_vertices == 0) - return; - - assert(osd->format != SUBBITMAP_EMPTY); + debug_check_gl(p, "before drawing osd"); - gl->Enable(GL_BLEND); - if (osd->format == SUBBITMAP_OLD) { - gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - gl->BindTexture(GL_TEXTURE_2D, osd->texture); gl->UseProgram(p->osd_programs[osd->format]); + mpgl_osd_gl_set_state(p->osd, osd); draw_triangles(p, osd->vertices, osd->num_vertices); + mpgl_osd_gl_unset_state(p->osd, osd); gl->UseProgram(0); - gl->BindTexture(GL_TEXTURE_2D, 0); - gl->Disable(GL_BLEND); + + debug_check_gl(p, "after drawing osd"); } static void setup_vertex_array(GL *gl) @@ -1630,21 +1501,6 @@ static int init_gl(struct gl_priv *p) gl->BindBuffer(GL_ARRAY_BUFFER, 0); gl->BindVertexArray(0); - GLint max_texture_size; - gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - assert(!p->osd[n]); - struct osd_render *osd = talloc_ptrtype(p, osd); - *osd = (struct osd_render) { - .packer = talloc_struct(osd, struct bitmap_packer, { - .w_max = max_texture_size, - .h_max = max_texture_size, - }), - }; - p->osd[n] = osd; - } - gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl->Clear(GL_COLOR_BUFFER_BIT); @@ -1668,16 +1524,6 @@ static void uninit_gl(struct gl_priv *p) gl->DeleteBuffers(1, &p->vertex_buffer); p->vertex_buffer = 0; - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_render *osd = p->osd[n]; - if (!osd) - continue; - gl->DeleteTextures(1, &osd->texture); - gl->DeleteBuffers(1, &osd->buffer); - talloc_free(osd); - p->osd[n] = NULL; - } - gl->DeleteTextures(1, &p->lut_3d_texture); p->lut_3d_texture = 0; } @@ -1852,8 +1698,9 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_TRUE; } case VOCTRL_QUERY_EOSD_FORMAT: { - int *p = data; - return osd_to_gl_formats[*p].shader ? VO_TRUE : VO_NOTIMPL; + int f = *(int *)data; + return (mpgl_osd_query_format(p->osd, f) && osd_shaders[f]) + ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_ONTOP: if (!p->glctx->ontop) -- cgit v1.2.3