diff options
Diffstat (limited to 'video/out/opengl')
-rw-r--r-- | video/out/opengl/common.h | 3 | ||||
-rw-r--r-- | video/out/opengl/context.c | 2 | ||||
-rw-r--r-- | video/out/opengl/context_rpi.c | 2 | ||||
-rw-r--r-- | video/out/opengl/header_fixes.h | 17 | ||||
-rw-r--r-- | video/out/opengl/video.c | 103 | ||||
-rw-r--r-- | video/out/opengl/video.h | 1 |
6 files changed, 93 insertions, 35 deletions
diff --git a/video/out/opengl/common.h b/video/out/opengl/common.h index 5abe839b8d..afb5b61f7e 100644 --- a/video/out/opengl/common.h +++ b/video/out/opengl/common.h @@ -36,6 +36,9 @@ #include <OpenGL/gl.h> #include <OpenGL/gl3.h> #include <OpenGL/glext.h> +#elif HAVE_IOS_GL +#include <OpenGLES/ES2/glext.h> +#include <OpenGLES/ES3/glext.h> #elif HAVE_ANDROID_GL #include <GLES3/gl3.h> #else diff --git a/video/out/opengl/context.c b/video/out/opengl/context.c index 0f5b61e37c..fb3471cd3b 100644 --- a/video/out/opengl/context.c +++ b/video/out/opengl/context.c @@ -125,7 +125,7 @@ int mpgl_validate_backend_opt(struct mp_log *log, const struct m_option *opt, #if HAVE_C11_TLS #define MP_TLS _Thread_local -#elif defined(__GNUC__) +#elif HAVE_GCC_TLS #define MP_TLS __thread #endif diff --git a/video/out/opengl/context_rpi.c b/video/out/opengl/context_rpi.c index 96c8199ef4..fa19a6c205 100644 --- a/video/out/opengl/context_rpi.c +++ b/video/out/opengl/context_rpi.c @@ -42,7 +42,7 @@ struct priv { EGL_DISPMANX_WINDOW_T egl_window; int x, y, w, h; double display_fps; - atomic_bool reload_display; + atomic_int reload_display; int win_params[4]; }; diff --git a/video/out/opengl/header_fixes.h b/video/out/opengl/header_fixes.h index 9953f7e497..9a7108dcda 100644 --- a/video/out/opengl/header_fixes.h +++ b/video/out/opengl/header_fixes.h @@ -92,6 +92,23 @@ #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif +#if HAVE_IOS_GL +#define GL_WRITE_ONLY GL_WRITE_ONLY_OES +#define GL_TEXTURE_1D 0x0DE0 +#define GL_R16 0x822A +#define GL_RG16 0x822C +#define GL_RGB10 0x8052 +#define GL_RGB16 0x8054 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_LUMINANCE8 GL_LUMINANCE8_EXT +#define GL_LUMINANCE8_ALPHA8 GL_LUMINANCE8_ALPHA8_EXT +#define GL_LUMINANCE16 0x8042 +#define GL_LUMINANCE16_ALPHA16 0x8048 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_LUMINANCE_SIZE 0x8060 +#endif + // GL_ARB_timer_query and EXT_disjoint_timer_query #ifndef GL_TIME_ELAPSED // Same as GL_TIME_ELAPSED_EXT diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 9461153615..498d89259e 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -104,6 +104,7 @@ struct texplane { struct video_image { struct texplane planes[4]; struct mp_image *mpi; // original input image + uint64_t id; // unique ID identifying mpi contents bool hwdec_mapped; }; @@ -153,6 +154,7 @@ struct tex_hook { struct fbosurface { struct fbotex fbotex; + uint64_t id; double pts; }; @@ -322,6 +324,7 @@ static const struct gl_video_opts gl_video_opts_def = { .target_brightness = 250, .hdr_tone_mapping = TONE_MAPPING_HABLE, .tone_mapping_param = NAN, + .early_flush = -1, }; static int validate_scaler_opt(struct mp_log *log, const m_option_t *opt, @@ -337,7 +340,10 @@ static int validate_window_opt(struct mp_log *log, const m_option_t *opt, OPT_FLOAT(n"-param1", scaler[i].kernel.params[0], 0), \ OPT_FLOAT(n"-param2", scaler[i].kernel.params[1], 0), \ OPT_FLOAT(n"-blur", scaler[i].kernel.blur, 0), \ + OPT_FLOATRANGE(n"-taper", scaler[i].kernel.taper, 0, 0.0, 1.0), \ OPT_FLOAT(n"-wparam", scaler[i].window.params[0], 0), \ + OPT_FLOAT(n"-wblur", scaler[i].window.blur, 0), \ + OPT_FLOATRANGE(n"-wtaper", scaler[i].window.taper, 0, 0.0, 1.0), \ OPT_FLAG(n"-clamp", scaler[i].clamp, 0), \ OPT_FLOATRANGE(n"-radius", scaler[i].radius, 0, 0.5, 16.0), \ OPT_FLOATRANGE(n"-antiring", scaler[i].antiring, 0, 0.0, 1.0), \ @@ -412,7 +418,8 @@ const struct m_sub_options gl_video_conf = { OPT_INTRANGE("opengl-tex-pad-x", tex_pad_x, 0, 0, 4096), OPT_INTRANGE("opengl-tex-pad-y", tex_pad_y, 0, 0, 4096), OPT_SUBSTRUCT("", icc_opts, mp_icc_conf, 0), - OPT_FLAG("opengl-early-flush", early_flush, 0), + OPT_CHOICE("opengl-early-flush", early_flush, 0, + ({"no", 0}, {"yes", 1}, {"auto", -1})), {0} }, @@ -515,7 +522,8 @@ static void uninit_scaler(struct gl_video *p, struct scaler *scaler); static void check_gl_features(struct gl_video *p); static bool init_format(struct gl_video *p, int fmt, bool test_only); static void init_image_desc(struct gl_video *p, int fmt); -static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi); +static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi, + uint64_t id); static const char *handle_scaler_opt(const char *name, bool tscale); static void reinit_from_options(struct gl_video *p); static void get_scale_factors(struct gl_video *p, bool transpose_rot, double xy[2]); @@ -563,8 +571,10 @@ void gl_video_set_debug(struct gl_video *p, bool enable) static void gl_video_reset_surfaces(struct gl_video *p) { - for (int i = 0; i < FBOSURFACES_MAX; i++) + for (int i = 0; i < FBOSURFACES_MAX; i++) { + p->surfaces[i].id = 0; p->surfaces[i].pts = MP_NOPTS_VALUE; + } p->surface_idx = 0; p->surface_now = 0; p->frames_drawn = 0; @@ -951,6 +961,7 @@ static void unmap_current_image(struct gl_video *p) p->hwdec->driver->unmap(p->hwdec); memset(vimg->planes, 0, sizeof(vimg->planes)); vimg->hwdec_mapped = false; + vimg->id = 0; // needs to be mapped again } } @@ -958,6 +969,7 @@ static void unref_current_image(struct gl_video *p) { unmap_current_image(p); mp_image_unrefp(&p->image.mpi); + p->image.id = 0; } static void uninit_video(struct gl_video *p) @@ -1349,7 +1361,8 @@ static bool scaler_fun_eq(struct scaler_fun a, struct scaler_fun b) return ((!a.name && !b.name) || strcmp(a.name, b.name) == 0) && double_seq(a.params[0], b.params[0]) && double_seq(a.params[1], b.params[1]) && - a.blur == b.blur; + a.blur == b.blur && + a.taper == b.taper; } static bool scaler_conf_eq(struct scaler_config a, struct scaler_config b) @@ -1410,6 +1423,11 @@ static void reinit_scaler(struct gl_video *p, struct scaler *scaler, if (conf->window.blur > 0.0) scaler->kernel->w.blur = conf->window.blur; + if (conf->kernel.taper > 0.0) + scaler->kernel->f.taper = conf->kernel.taper; + if (conf->window.taper > 0.0) + scaler->kernel->w.taper = conf->window.taper; + if (scaler->kernel->f.resizable && conf->radius > 0.0) scaler->kernel->f.radius = conf->radius; @@ -1995,8 +2013,6 @@ static void pass_convert_yuv(struct gl_video *p) p->components = 3; if (!p->has_alpha || p->opts.alpha_mode == ALPHA_NO) { GLSL(color.a = 1.0;) - } else if (p->opts.alpha_mode == ALPHA_BLEND) { - GLSL(color = vec4(color.rgb * color.a, 1.0);) } else { // alpha present in image p->components = 4; GLSL(color = vec4(color.rgb * color.a, color.a);) @@ -2519,12 +2535,20 @@ static void pass_draw_to_screen(struct gl_video *p, int fbo) pass_colormanage(p, p->image_params.color, false); - // Draw checkerboard pattern to indicate transparency - if (p->has_alpha && p->opts.alpha_mode == ALPHA_BLEND_TILES) { - GLSLF("// transparency checkerboard\n"); - GLSL(bvec2 tile = lessThan(fract(gl_FragCoord.xy / 32.0), vec2(0.5));) - GLSL(vec3 background = vec3(tile.x == tile.y ? 1.0 : 0.75);) - GLSL(color.rgb = mix(background, color.rgb, color.a);) + if (p->has_alpha){ + if (p->opts.alpha_mode == ALPHA_BLEND_TILES) { + // Draw checkerboard pattern to indicate transparency + GLSLF("// transparency checkerboard\n"); + GLSL(bvec2 tile = lessThan(fract(gl_FragCoord.xy / 32.0), vec2(0.5));) + GLSL(vec3 background = vec3(tile.x == tile.y ? 1.0 : 0.75);) + GLSL(color.rgb = mix(background, color.rgb, color.a);) + } else if (p->opts.alpha_mode == ALPHA_BLEND) { + // Blend into background color (usually black) + struct m_color c = p->opts.background; + GLSLF("vec4 background = vec4(%f, %f, %f, %f);\n", + c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0); + GLSL(color = mix(background, vec4(color.rgb, 1.0), color.a);) + } } pass_opt_hook_point(p, "OUTPUT", NULL); @@ -2550,22 +2574,23 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t, // First of all, figure out if we have a frame available at all, and draw // it manually + reset the queue if not - if (p->surfaces[p->surface_now].pts == MP_NOPTS_VALUE) { - if (!gl_video_upload_image(p, t->current)) + if (p->surfaces[p->surface_now].id == 0) { + if (!gl_video_upload_image(p, t->current, t->frame_id)) return; pass_render_frame(p); finish_pass_fbo(p, &p->surfaces[p->surface_now].fbotex, vp_w, vp_h, FBOTEX_FUZZY); + p->surfaces[p->surface_now].id = p->image.id; p->surfaces[p->surface_now].pts = p->image.mpi->pts; p->surface_idx = p->surface_now; } // Find the right frame for this instant - if (t->current && t->current->pts != MP_NOPTS_VALUE) { + if (t->current) { int next = fbosurface_wrap(p->surface_now + 1); - while (p->surfaces[next].pts != MP_NOPTS_VALUE && - p->surfaces[next].pts > p->surfaces[p->surface_now].pts && - p->surfaces[p->surface_now].pts < t->current->pts) + while (p->surfaces[next].id && + p->surfaces[next].id > p->surfaces[p->surface_now].id && + p->surfaces[p->surface_now].id < t->frame_id) { p->surface_now = next; next = fbosurface_wrap(next + 1); @@ -2607,16 +2632,17 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t, break; struct mp_image *f = t->frames[i]; - if (!mp_image_params_equal(&f->params, &p->real_image_params) || - f->pts == MP_NOPTS_VALUE) + uint64_t f_id = t->frame_id + i; + if (!mp_image_params_equal(&f->params, &p->real_image_params)) continue; - if (f->pts > p->surfaces[p->surface_idx].pts) { - if (!gl_video_upload_image(p, f)) + if (f_id > p->surfaces[p->surface_idx].id) { + if (!gl_video_upload_image(p, f, f_id)) return; pass_render_frame(p); finish_pass_fbo(p, &p->surfaces[surface_dst].fbotex, vp_w, vp_h, FBOTEX_FUZZY); + p->surfaces[surface_dst].id = f_id; p->surfaces[surface_dst].pts = f->pts; p->surface_idx = surface_dst; surface_dst = fbosurface_wrap(surface_dst + 1); @@ -2631,11 +2657,9 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t, bool valid = true; for (int i = surface_bse, ii; valid && i != surface_end; i = ii) { ii = fbosurface_wrap(i + 1); - if (p->surfaces[i].pts == MP_NOPTS_VALUE || - p->surfaces[ii].pts == MP_NOPTS_VALUE) - { + if (p->surfaces[i].id == 0 || p->surfaces[ii].id == 0) { valid = false; - } else if (p->surfaces[ii].pts < p->surfaces[i].pts) { + } else if (p->surfaces[ii].id < p->surfaces[i].id) { valid = false; MP_DBG(p, "interpolation queue underrun\n"); } @@ -2656,8 +2680,8 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t, // (which requires some extra checking to make sure it's valid) if (mix < 0.0) { int prev = fbosurface_wrap(surface_bse - 1); - if (p->surfaces[prev].pts != MP_NOPTS_VALUE && - p->surfaces[prev].pts < p->surfaces[surface_bse].pts) + if (p->surfaces[prev].id != 0 && + p->surfaces[prev].id < p->surfaces[surface_bse].id) { mix += 1.0; surface_bse = prev; @@ -2736,7 +2760,6 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo) gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); bool has_frame = !!frame->current; - bool is_new = has_frame && !frame->redraw && !frame->repeat; if (!has_frame || p->dst_rect.x0 > 0 || p->dst_rect.y0 > 0 || p->dst_rect.x1 < p->vp_w || p->dst_rect.y1 < abs(p->vp_h)) @@ -2758,7 +2781,7 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo) gl->Disable(GL_SCISSOR_TEST); } - if (is_new || !frame->current) + if (frame->frame_id != p->image.id || !frame->current) p->hwdec->driver->overlay_frame(p->hwdec, frame->current); if (frame->current) @@ -2782,10 +2805,16 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo) if (interpolate) { gl_video_interpolate_frame(p, frame, fbo); } else { + bool is_new = frame->frame_id != p->image.id; + + // Redrawing a frame might update subtitles. + if (frame->still && p->opts.blend_subs) + is_new = true; + if (is_new || !p->output_fbo_valid) { p->output_fbo_valid = false; - if (!gl_video_upload_image(p, frame->current)) + if (!gl_video_upload_image(p, frame->current, frame->frame_id)) goto done; pass_render_frame(p); @@ -2849,8 +2878,11 @@ done: // The playloop calls this last before waiting some time until it decides // to call flip_page(). Tell OpenGL to start execution of the GPU commands // while we sleep (this happens asynchronously). - if (p->opts.early_flush) + if ((p->opts.early_flush == -1 && !frame->display_synced) || + p->opts.early_flush == 1) + { gl->Flush(); + } p->frames_rendered++; @@ -2944,11 +2976,15 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame) } // Returns false on failure. -static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) +static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi, + uint64_t id) { GL *gl = p->gl; struct video_image *vimg = &p->image; + if (vimg->id == id) + return true; + unref_current_image(p); mpi = mp_image_new_ref(mpi); @@ -2956,6 +2992,7 @@ static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) goto error; vimg->mpi = mpi; + vimg->id = id; p->osd_pts = mpi->pts; p->frames_uploaded++; diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h index 5011af83d1..54b7022f27 100644 --- a/video/out/opengl/video.h +++ b/video/out/opengl/video.h @@ -35,6 +35,7 @@ struct scaler_fun { char *name; float params[2]; float blur; + float taper; }; struct scaler_config { |