From 3c9c1790fee177cc9c9661475746a92ab6ce9bea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:25:26 +0200 Subject: vo_gl3: support RGBA EOSD This also adds support for multiple EOSD renderers. This capability is unused yet, but important for the following commits. --- libvo/fastmemcpy.h | 13 +++ libvo/gl_common.c | 26 +++++ libvo/gl_common.h | 3 + libvo/vo_gl3.c | 290 +++++++++++++++++++++++++++++++--------------- libvo/vo_gl3_shaders.glsl | 18 ++- 5 files changed, 251 insertions(+), 99 deletions(-) diff --git a/libvo/fastmemcpy.h b/libvo/fastmemcpy.h index 5d05d37043..36fada39fe 100644 --- a/libvo/fastmemcpy.h +++ b/libvo/fastmemcpy.h @@ -64,4 +64,17 @@ static inline void * memcpy_pic2(void * dst, const void * src, return retval; } +static inline void memset_pic(void *dst, int fill, int bytesPerLine, int height, + int stride) +{ + if (bytesPerLine == stride) { + memset(dst, fill, stride * height); + } else { + for (int i = 0; i < height; i++) { + memset(dst, fill, bytesPerLine); + dst = (uint8_t *)dst + stride; + } + } +} + #endif /* MPLAYER_FASTMEMCPY_H */ diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 1ad7017e10..c56b0c8ffc 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -427,6 +427,7 @@ static const extfunc_desc_t extfuncs[] = { DEF_GL3_DESC(FramebufferTexture2D), DEF_GL3_DESC(Uniform1f), DEF_GL3_DESC(Uniform3f), + DEF_GL3_DESC(Uniform4f), DEF_GL3_DESC(Uniform1i), DEF_GL3_DESC(UniformMatrix3fv), DEF_GL3_DESC(UniformMatrix4x3fv), @@ -674,6 +675,31 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, gl->TexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data); } +// Like glUploadTex, but upload a byte array with all elements set to val. +// If scratch is not NULL, points to a resizeable talloc memory block than can +// be freely used by the function (for avoiding temporary memory allocations). +void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, + int x, int y, int w, int h, uint8_t val, void **scratch) +{ + int bpp = glFmt2bpp(format, type); + int stride = w * bpp; + int size = h * stride; + if (size < 1) + return; + void *data = scratch ? *scratch : NULL; + if (talloc_get_size(data) < size) + data = talloc_realloc(NULL, data, char *, size); + memset(data, val, size); + glAdjustAlignment(gl, stride); + gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w); + gl->TexSubImage2D(target, 0, x, y, w, h, format, type, data); + if (scratch) { + *scratch = data; + } else { + talloc_free(data); + } +} + /** * \brief download a texture, handling things like stride and slices * \param target texture target, usually GL_TEXTURE_2D diff --git a/libvo/gl_common.h b/libvo/gl_common.h index f42caa8fd1..fa4b6dbf25 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -60,6 +60,8 @@ int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter, void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, const void *dataptr, int stride, int x, int y, int w, int h, int slice); +void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, + int x, int y, int w, int h, uint8_t val, void **scratch); void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, void *dataptr, int stride); void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, @@ -351,6 +353,7 @@ struct GL { void (GLAPIENTRY *Uniform1f)(GLint, GLfloat); void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); void (GLAPIENTRY *Uniform1i)(GLint, GLint); void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *); diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index ebce32677b..e3d3b9af62 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -37,6 +37,7 @@ #endif #include "talloc.h" +#include "mpcommon.h" #include "bstr.h" #include "mp_msg.h" #include "subopt-helper.h" @@ -46,7 +47,7 @@ #include "geometry.h" #include "osd.h" #include "sub/sub.h" -#include "eosd_packer.h" +#include "bitmap_packer.h" #include "gl_common.h" #include "filter_kernels.h" @@ -111,7 +112,7 @@ struct vertex { #define VERTEX_ATTRIB_TEXCOORD 2 // 2 triangles primitives per quad = 6 vertices per quad -// (GL_QUAD is deprecated, strips can't be used with EOSD image lists) +// (GL_QUAD is deprecated, strips can't be used with OSD image lists) #define VERTICES_PER_QUAD 6 struct texplane { @@ -141,6 +142,17 @@ 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; @@ -171,18 +183,15 @@ struct gl_priv { GLuint vertex_buffer; GLuint vao; - GLuint osd_program, eosd_program; + GLuint osd_programs[SUBBITMAP_COUNT]; GLuint indirect_program, scale_sep_program, final_program; + // old OSD code - should go away GLuint osd_textures[MAX_OSD_PARTS]; int osd_textures_count; struct vertex osd_va[MAX_OSD_PARTS * VERTICES_PER_QUAD]; - GLuint eosd_texture; - int eosd_texture_width, eosd_texture_height; - GLuint eosd_buffer; - struct vertex *eosd_va; - struct eosd_packer *eosd; + struct osd_render *osd[MAX_OSD_PARTS]; GLuint lut_3d_texture; int lut_3d_w, lut_3d_h, lut_3d_d; @@ -231,6 +240,8 @@ struct gl_priv { struct vo_rect dst_rect; // video rectangle on output window int border_x, border_y; // OSD borders int vp_x, vp_y, vp_w, vp_h; // GL viewport + + void *scratch; }; struct fmt_entry { @@ -254,6 +265,25 @@ 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 help_text[]; @@ -464,6 +494,15 @@ static void update_uniforms(struct gl_priv *p, GLuint program) gl->Uniform1f(gl->GetUniformLocation(program, "filter_param1"), isnan(sparam1) ? 0.5f : sparam1); + loc = gl->GetUniformLocation(program, "osd_color"); + if (loc >= 0) { + int r = (p->osd_color >> 16) & 0xff; + int g = (p->osd_color >> 8) & 0xff; + int b = p->osd_color & 0xff; + int a = 0xff - (p->osd_color >> 24); + gl->Uniform4f(loc, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + } + gl->UseProgram(0); debug_check_gl(p, "update_uniforms()"); @@ -471,8 +510,8 @@ static void update_uniforms(struct gl_priv *p, GLuint program) static void update_all_uniforms(struct gl_priv *p) { - update_uniforms(p, p->osd_program); - update_uniforms(p, p->eosd_program); + for (int n = 0; n < SUBBITMAP_COUNT; n++) + update_uniforms(p, p->osd_programs[n]); update_uniforms(p, p->indirect_program); update_uniforms(p, p->scale_sep_program); update_uniforms(p, p->final_program); @@ -636,20 +675,21 @@ static void compile_shaders(struct gl_priv *p) char *vertex_shader = get_section(tmp, src, "vertex_all"); char *shader_prelude = get_section(tmp, src, "prelude"); char *s_video = get_section(tmp, src, "frag_video"); - char *s_eosd = get_section(tmp, src, "frag_eosd"); - char *s_osd = get_section(tmp, src, "frag_osd"); char *header = talloc_asprintf(tmp, "#version %s\n%s", p->shader_version, shader_prelude); - char *header_eosd = talloc_strdup(tmp, header); - shader_def_opt(&header_eosd, "USE_3DLUT", p->use_lut_3d); + char *header_osd = talloc_strdup(tmp, header); + shader_def_opt(&header_osd, "USE_3DLUT", p->use_lut_3d); - p->eosd_program = - create_program(gl, "eosd", header_eosd, vertex_shader, s_eosd); - - p->osd_program = - create_program(gl, "osd", header, vertex_shader, s_osd); + 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); + p->osd_programs[n] = + create_program(gl, fmt.shader, header_osd, vertex_shader, s_osd); + } + } char *header_conv = talloc_strdup(tmp, ""); char *header_final = talloc_strdup(tmp, ""); @@ -750,8 +790,8 @@ static void delete_shaders(struct gl_priv *p) { GL *gl = p->gl; - delete_program(gl, &p->osd_program); - delete_program(gl, &p->eosd_program); + for (int n = 0; n < SUBBITMAP_COUNT; n++) + delete_program(gl, &p->osd_programs[n]); delete_program(gl, &p->indirect_program); delete_program(gl, &p->scale_sep_program); delete_program(gl, &p->final_program); @@ -1449,7 +1489,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) // OSD bitmaps use premultiplied alpha. gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - gl->UseProgram(p->osd_program); + gl->UseProgram(p->osd_programs[SUBBITMAP_OLD]); for (int n = 0; n < p->osd_textures_count; n++) { gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[n]); @@ -1464,80 +1504,111 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) } } -static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs) +static void gen_eosd(struct gl_priv *p, struct osd_render *osd, + struct sub_bitmaps *imgs) { GL *gl = p->gl; - bool need_repos, need_upload, need_allocate; - eosd_packer_generate(p->eosd, imgs, &need_repos, &need_upload, - &need_allocate); + if (imgs->bitmap_pos_id == osd->bitmap_pos_id) + return; + + osd->num_vertices = 0; - if (!need_repos) + if (imgs->format == SUBBITMAP_EMPTY) return; - if (!p->eosd_texture) { - gl->GenTextures(1, &p->eosd_texture); - gl->GenBuffers(1, &p->eosd_buffer); + 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; } - gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture); + osd->bitmap_id = imgs->bitmap_id; + osd->bitmap_pos_id = imgs->bitmap_pos_id; + + 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; + } 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, p->eosd->surface.w, p->eosd->surface.h, - &p->eosd_texture_width, &p->eosd_texture_height); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED, - p->eosd_texture_width, p->eosd_texture_height, 0, - GL_RED, GL_UNSIGNED_BYTE, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer); + 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, - p->eosd->surface.w * p->eosd->surface.h, - NULL, - GL_DYNAMIC_COPY); + osd->width * osd->height * fmt.stride, + NULL, GL_DYNAMIC_COPY); gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } - p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va, - p->eosd->targets_count - * sizeof(struct vertex) - * VERTICES_PER_QUAD); + struct pos bb[2]; + packer_get_bb(osd->packer, bb); if (need_upload && p->use_pbo) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer); + 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! " - "Subtitles will look corrupted.\n"); + "Remove the 'pbo' suboption.\n"); } else { - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; - - void *pdata = data + target->source.y0 * p->eosd->surface.w - + target->source.x0; + 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]; - memcpy_pic(pdata, i->bitmap, i->w, i->h, - p->eosd->surface.w, i->stride); + 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"); - struct eosd_rect rc; - eosd_packer_calculate_source_bb(p->eosd, &rc); - glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, NULL, - p->eosd->surface.w, rc.x0, rc.y0, - rc.x1 - rc.x0, rc.y1 - rc.y0, 0); + 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); - } else if (need_upload) { + } + if (need_upload) { // non-PBO upload - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; + 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, GL_RED, GL_UNSIGNED_BYTE, i->bitmap, - i->stride, target->source.x0, target->source.y0, - i->w, i->h, 0); + glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, + b->bitmap, b->stride, p.x, p.y, b->w, b->h, 0); } } @@ -1545,36 +1616,51 @@ static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs) debug_check_gl(p, "EOSD upload"); - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; - uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff, - (i->color >> 8) & 0xff, 255 - (i->color & 0xff) }; + 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]; - write_quad(&p->eosd_va[n * VERTICES_PER_QUAD], - target->dest.x0, target->dest.y0, - target->dest.x1, target->dest.y1, - target->source.x0, target->source.y0, - target->source.x1, target->source.y1, - p->eosd_texture_width, p->eosd_texture_height, - color, false); + // 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, mp_eosd_images_t *imgs) +static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) { GL *gl = p->gl; - gen_eosd(p, imgs); + struct osd_render *osd = p->osd[imgs->render_index]; + + gen_eosd(p, osd, imgs); - if (p->eosd->targets_count == 0) + if (osd->num_vertices == 0) return; + assert(osd->format != SUBBITMAP_EMPTY); + gl->Enable(GL_BLEND); - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture); - gl->UseProgram(p->eosd_program); - draw_triangles(p, p->eosd_va, p->eosd->targets_count * VERTICES_PER_QUAD); + 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]); + draw_triangles(p, osd->vertices, osd->num_vertices); gl->UseProgram(0); gl->BindTexture(GL_TEXTURE_2D, 0); gl->Disable(GL_BLEND); @@ -1641,7 +1727,18 @@ static int init_gl(struct gl_priv *p) GLint max_texture_size; gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - eosd_packer_reinit(p->eosd, 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); @@ -1667,11 +1764,15 @@ static void uninit_gl(struct gl_priv *p) p->vertex_buffer = 0; clear_osd(p); - gl->DeleteTextures(1, &p->eosd_texture); - p->eosd_texture = 0; - gl->DeleteBuffers(1, &p->eosd_buffer); - p->eosd_buffer = 0; - eosd_packer_reinit(p->eosd, 0, 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; @@ -1753,7 +1854,7 @@ static int query_format(uint32_t format) { int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE | - VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED; + VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED | VFCAP_EOSD_RGBA; if (!init_format(format, NULL)) return 0; return caps; @@ -2244,6 +2345,7 @@ static int preinit(struct vo *vo, const char *arg) { .index = 1, .name = "bilinear" }, }, .scaler_params = {NAN, NAN}, + .scratch = talloc_zero_array(p, char *, 1), }; p->defaults = talloc(p, struct gl_priv); @@ -2323,8 +2425,6 @@ static int preinit(struct vo *vo, const char *arg) p->orig_cmdline = talloc(p, struct gl_priv); *p->orig_cmdline = *p; - p->eosd = eosd_packer_create(vo); - p->glctx = init_mpglcontext(backend, vo); if (!p->glctx) goto err_out; diff --git a/libvo/vo_gl3_shaders.glsl b/libvo/vo_gl3_shaders.glsl index f67e55e6f5..20f8c597ad 100644 --- a/libvo/vo_gl3_shaders.glsl +++ b/libvo/vo_gl3_shaders.glsl @@ -45,7 +45,7 @@ void main() { texcoord = vertex_texcoord; } -#!section frag_eosd +#!section frag_osd_libass uniform sampler2D texture1; in vec2 texcoord; @@ -56,15 +56,25 @@ void main() { out_color = vec4(color.rgb, color.a * texture(texture1, texcoord).r); } -#!section frag_osd +#!section frag_osd_rgba uniform sampler2D texture1; in vec2 texcoord; -in vec4 color; out vec4 out_color; void main() { - out_color = texture(texture1, texcoord).rrrg * color; + out_color = texture(texture1, texcoord); +} + +#!section frag_osd_old +uniform sampler2D texture1; +uniform vec4 osd_color; + +in vec2 texcoord; +out vec4 out_color; + +void main() { + out_color = texture(texture1, texcoord).rrrg * osd_color; } #!section frag_video -- cgit v1.2.3