summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/osd.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2017-09-14 08:04:55 +0200
committerNiklas Haas <git@haasn.xyz>2017-09-21 15:00:55 +0200
commit65979986a923a8f08019b257c3fe72cd5e8ecf68 (patch)
treeb8f4b8c17d583594aef0ca509064f8b2ff7128d4 /video/out/opengl/osd.c
parent20f958c9775652c3213588c2a0824f5353276adc (diff)
downloadmpv-65979986a923a8f08019b257c3fe72cd5e8ecf68.tar.bz2
mpv-65979986a923a8f08019b257c3fe72cd5e8ecf68.tar.xz
vo_opengl: refactor into vo_gpu
This is done in several steps: 1. refactor MPGLContext -> struct ra_ctx 2. move GL-specific stuff in vo_opengl into opengl/context.c 3. generalize context creation to support other APIs, and add --gpu-api 4. rename all of the --opengl- options that are no longer opengl-specific 5. move all of the stuff from opengl/* that isn't GL-specific into gpu/ (note: opengl/gl_utils.h became opengl/utils.h) 6. rename vo_opengl to vo_gpu 7. to handle window screenshots, the short-term approach was to just add it to ra_swchain_fns. Long term (and for vulkan) this has to be moved to ra itself (and vo_gpu altered to compensate), but this was a stop-gap measure to prevent this commit from getting too big 8. move ra->fns->flush to ra_gl_ctx instead 9. some other minor changes that I've probably already forgotten Note: This is one half of a major refactor, the other half of which is provided by rossy's following commit. This commit enables support for all linux platforms, while his version enables support for all non-linux platforms. Note 2: vo_opengl_cb.c also re-uses ra_gl_ctx so it benefits from the --opengl- options like --opengl-early-flush, --opengl-finish etc. Should be a strict superset of the old functionality. Disclaimer: Since I have no way of compiling mpv on all platforms, some of these ports were done blindly. Specifically, the blind ports included context_mali_fbdev.c and context_rpi.c. Since they're both based on egl_helpers, the port should have gone smoothly without any major changes required. But if somebody complains about a compile error on those platforms (assuming anybody actually uses them), you know where to complain.
Diffstat (limited to 'video/out/opengl/osd.c')
-rw-r--r--video/out/opengl/osd.c367
1 files changed, 0 insertions, 367 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c
deleted file mode 100644
index f7c325d1db..0000000000
--- a/video/out/opengl/osd.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * mpv 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <assert.h>
-#include <limits.h>
-
-#include <libavutil/common.h>
-
-#include "common/common.h"
-#include "common/msg.h"
-#include "video/csputils.h"
-#include "video/mp_image.h"
-#include "osd.h"
-
-#define GLSL(x) gl_sc_add(sc, #x "\n");
-
-// glBlendFuncSeparate() arguments
-static const int blend_factors[SUBBITMAP_COUNT][4] = {
- [SUBBITMAP_LIBASS] = {RA_BLEND_SRC_ALPHA, RA_BLEND_ONE_MINUS_SRC_ALPHA,
- RA_BLEND_ONE, RA_BLEND_ONE_MINUS_SRC_ALPHA},
- [SUBBITMAP_RGBA] = {RA_BLEND_ONE, RA_BLEND_ONE_MINUS_SRC_ALPHA,
- RA_BLEND_ONE, RA_BLEND_ONE_MINUS_SRC_ALPHA},
-};
-
-struct vertex {
- float position[2];
- float texcoord[2];
- uint8_t ass_color[4];
-};
-
-static const struct ra_renderpass_input vertex_vao[] = {
- {"position", RA_VARTYPE_FLOAT, 2, 1, offsetof(struct vertex, position)},
- {"texcoord" , RA_VARTYPE_FLOAT, 2, 1, offsetof(struct vertex, texcoord)},
- {"ass_color", RA_VARTYPE_BYTE_UNORM, 4, 1, offsetof(struct vertex, ass_color)},
- {0}
-};
-
-struct mpgl_osd_part {
- enum sub_bitmap_format format;
- int change_id;
- struct ra_tex *texture;
- int w, h;
- int num_subparts;
- int prev_num_subparts;
- struct sub_bitmap *subparts;
- int num_vertices;
- struct vertex *vertices;
-};
-
-struct mpgl_osd {
- struct mp_log *log;
- struct osd_state *osd;
- struct ra *ra;
- struct mpgl_osd_part *parts[MAX_OSD_PARTS];
- const struct ra_format *fmt_table[SUBBITMAP_COUNT];
- bool formats[SUBBITMAP_COUNT];
- bool change_flag; // for reporting to API user only
- // temporary
- int stereo_mode;
- struct mp_osd_res osd_res;
- void *scratch;
-};
-
-struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
- struct osd_state *osd)
-{
- struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx);
- *ctx = (struct mpgl_osd) {
- .log = log,
- .osd = osd,
- .ra = ra,
- .change_flag = true,
- .scratch = talloc_zero_size(ctx, 1),
- };
-
- ctx->fmt_table[SUBBITMAP_LIBASS] = ra_find_unorm_format(ra, 1, 1);
- ctx->fmt_table[SUBBITMAP_RGBA] = ra_find_unorm_format(ra, 1, 4);
-
- for (int n = 0; n < MAX_OSD_PARTS; n++)
- ctx->parts[n] = talloc_zero(ctx, struct mpgl_osd_part);
-
- for (int n = 0; n < SUBBITMAP_COUNT; n++)
- ctx->formats[n] = !!ctx->fmt_table[n];
-
- return ctx;
-}
-
-void mpgl_osd_destroy(struct mpgl_osd *ctx)
-{
- if (!ctx)
- return;
-
- for (int n = 0; n < MAX_OSD_PARTS; n++) {
- struct mpgl_osd_part *p = ctx->parts[n];
- ra_tex_free(ctx->ra, &p->texture);
- }
- talloc_free(ctx);
-}
-
-static int next_pow2(int v)
-{
- 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,
- struct sub_bitmaps *imgs)
-{
- struct ra *ra = ctx->ra;
- bool ok = false;
-
- assert(imgs->packed);
-
- int req_w = next_pow2(imgs->packed_w);
- int req_h = next_pow2(imgs->packed_h);
-
- const struct ra_format *fmt = ctx->fmt_table[imgs->format];
- assert(fmt);
-
- if (!osd->texture || req_w > osd->w || req_h > osd->h ||
- osd->format != imgs->format)
- {
- ra_tex_free(ra, &osd->texture);
-
- osd->format = imgs->format;
- osd->w = FFMAX(32, req_w);
- osd->h = FFMAX(32, req_h);
-
- MP_VERBOSE(ctx, "Reallocating OSD texture to %dx%d.\n", osd->w, osd->h);
-
- if (osd->w > ra->max_texture_wh || osd->h > ra->max_texture_wh) {
- MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum "
- "supported size %dx%d.\n", ra->max_texture_wh,
- ra->max_texture_wh);
- goto done;
- }
-
- struct ra_tex_params params = {
- .dimensions = 2,
- .w = osd->w,
- .h = osd->h,
- .d = 1,
- .format = fmt,
- .render_src = true,
- .src_linear = true,
- .host_mutable = true,
- };
- osd->texture = ra_tex_create(ra, &params);
- if (!osd->texture)
- goto done;
- }
-
- struct ra_tex_upload_params params = {
- .tex = osd->texture,
- .src = imgs->packed->planes[0],
- .invalidate = true,
- .rc = &(struct mp_rect){0, 0, imgs->packed_w, imgs->packed_h},
- .stride = imgs->packed->stride[0],
- };
-
- ok = ra->fns->tex_upload(ra, &params);
-
-done:
- return ok;
-}
-
-static void gen_osd_cb(void *pctx, struct sub_bitmaps *imgs)
-{
- struct mpgl_osd *ctx = pctx;
-
- if (imgs->num_parts == 0 || !ctx->formats[imgs->format])
- return;
-
- 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))
- ok = false;
-
- osd->change_id = imgs->change_id;
- ctx->change_flag = true;
- }
- 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]));
-}
-
-bool mpgl_osd_draw_prepare(struct mpgl_osd *ctx, int index,
- struct gl_shader_cache *sc)
-{
- assert(index >= 0 && index < MAX_OSD_PARTS);
- struct mpgl_osd_part *part = ctx->parts[index];
-
- enum sub_bitmap_format fmt = part->format;
- if (!fmt || !part->num_subparts)
- return false;
-
- gl_sc_uniform_texture(sc, "osdtex", part->texture);
- switch (fmt) {
- case SUBBITMAP_RGBA: {
- GLSL(color = texture(osdtex, texcoord).bgra;)
- break;
- }
- case SUBBITMAP_LIBASS: {
- GLSL(color =
- vec4(ass_color.rgb, ass_color.a * texture(osdtex, texcoord).r);)
- break;
- }
- default:
- abort();
- }
-
- gl_sc_set_vertex_format(sc, vertex_vao, sizeof(struct vertex));
-
- return true;
-}
-
-static void write_quad(struct vertex *va, struct gl_transform t,
- float x0, float y0, float x1, float y1,
- float tx0, float ty0, float tx1, float ty1,
- float tex_w, float tex_h, const uint8_t color[4])
-{
- gl_transform_vec(t, &x0, &y0);
- gl_transform_vec(t, &x1, &y1);
-
-#define COLOR_INIT {color[0], color[1], color[2], color[3]}
- va[0] = (struct vertex){ {x0, y0}, {tx0 / tex_w, ty0 / tex_h}, COLOR_INIT };
- va[1] = (struct vertex){ {x0, y1}, {tx0 / tex_w, ty1 / tex_h}, COLOR_INIT };
- va[2] = (struct vertex){ {x1, y0}, {tx1 / tex_w, ty0 / tex_h}, COLOR_INIT };
- va[3] = (struct vertex){ {x1, y1}, {tx1 / tex_w, ty1 / tex_h}, COLOR_INIT };
- va[4] = va[2];
- va[5] = va[1];
-#undef COLOR_INIT
-}
-
-static void generate_verts(struct mpgl_osd_part *part, struct gl_transform t)
-{
- int num_vertices = part->num_subparts * 6;
- MP_TARRAY_GROW(part, part->vertices, part->num_vertices + num_vertices);
-
- for (int n = 0; n < part->num_subparts; n++) {
- struct sub_bitmap *b = &part->subparts[n];
- struct vertex *va = &part->vertices[part->num_vertices];
-
- // 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[n * 6], t,
- b->x, b->y, b->x + b->dw, b->y + b->dh,
- b->src_x, b->src_y, b->src_x + b->w, b->src_y + b->h,
- part->w, part->h, color);
- }
-
- part->num_vertices += num_vertices;
-}
-
-// number of screen divisions per axis (x=0, y=1) for the current 3D mode
-static void get_3d_side_by_side(int stereo_mode, int div[2])
-{
- div[0] = div[1] = 1;
- switch (stereo_mode) {
- case MP_STEREO3D_SBS2L:
- case MP_STEREO3D_SBS2R: div[0] = 2; break;
- case MP_STEREO3D_AB2R:
- case MP_STEREO3D_AB2L: div[1] = 2; break;
- }
-}
-
-void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int index,
- struct gl_shader_cache *sc, struct fbodst target)
-{
- struct mpgl_osd_part *part = ctx->parts[index];
-
- int div[2];
- get_3d_side_by_side(ctx->stereo_mode, div);
-
- part->num_vertices = 0;
-
- for (int x = 0; x < div[0]; x++) {
- for (int y = 0; y < div[1]; y++) {
- struct gl_transform t;
- gl_transform_ortho_fbodst(&t, target);
-
- float a_x = ctx->osd_res.w * x;
- float a_y = ctx->osd_res.h * y;
- t.t[0] += a_x * t.m[0][0] + a_y * t.m[1][0];
- t.t[1] += a_x * t.m[0][1] + a_y * t.m[1][1];
-
- generate_verts(part, t);
- }
- }
-
- const int *factors = &blend_factors[part->format][0];
- gl_sc_blend(sc, factors[0], factors[1], factors[2], factors[3]);
-
- gl_sc_dispatch_draw(sc, target.tex, part->vertices, part->num_vertices);
-}
-
-static void set_res(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode)
-{
- int div[2];
- get_3d_side_by_side(stereo_mode, div);
-
- res.w /= div[0];
- res.h /= div[1];
- ctx->osd_res = res;
-}
-
-void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
- int stereo_mode, int draw_flags)
-{
- for (int n = 0; n < MAX_OSD_PARTS; n++)
- ctx->parts[n]->num_subparts = 0;
-
- set_res(ctx, res, stereo_mode);
-
- osd_draw(ctx->osd, ctx->osd_res, pts, draw_flags, ctx->formats, gen_osd_cb, ctx);
- ctx->stereo_mode = stereo_mode;
-
- // Parts going away does not necessarily result in gen_osd_cb() being called
- // (not even with num_parts==0), so check this separately.
- for (int n = 0; n < MAX_OSD_PARTS; n++) {
- struct mpgl_osd_part *part = ctx->parts[n];
- if (part->num_subparts != part->prev_num_subparts)
- ctx->change_flag = true;
- part->prev_num_subparts = part->num_subparts;
- }
-}
-
-// See osd_resize() for remarks. This function is an optional optimization too.
-void mpgl_osd_resize(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode)
-{
- set_res(ctx, res, stereo_mode);
- osd_resize(ctx->osd, ctx->osd_res);
-}
-
-bool mpgl_osd_check_change(struct mpgl_osd *ctx, struct mp_osd_res *res,
- double pts)
-{
- ctx->change_flag = false;
- mpgl_osd_generate(ctx, *res, pts, 0, 0);
- return ctx->change_flag;
-}