summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/opengl/video.c223
-rw-r--r--video/out/opengl/video_shaders.c5
-rw-r--r--video/out/opengl/video_shaders.h2
3 files changed, 140 insertions, 90 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index f7acabf0b6..e524bb5cf9 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -51,7 +51,7 @@
// Maximal number of saved textures (for user script purposes)
#define MAX_TEXTURE_HOOKS 16
-#define MAX_SAVED_TEXTURES 16
+#define MAX_SAVED_TEXTURES 32
// scale/cscale arguments that map directly to shader filter routines.
// Note that the convolution filters are not included in this list.
@@ -209,20 +209,12 @@ struct gl_video {
bool forced_dumb_mode;
struct fbotex merge_fbo[4];
- struct fbotex deband_fbo[4];
struct fbotex scale_fbo[4];
struct fbotex integer_fbo[4];
struct fbotex indirect_fbo;
struct fbotex blend_subs_fbo;
- struct fbotex unsharp_fbo;
struct fbotex output_fbo;
struct fbosurface surfaces[FBOSURFACES_MAX];
-
- // these are duplicated so we can keep rendering back and forth between
- // them to support an unlimited number of shader passes per step
- struct fbotex pre_fbo[2];
- struct fbotex post_fbo[2];
-
struct fbotex prescale_fbo[MAX_PRESCALE_PASSES];
int surface_idx;
@@ -253,9 +245,10 @@ struct gl_video {
// hooks and saved textures
struct saved_tex saved_tex[MAX_SAVED_TEXTURES];
int saved_tex_num;
- struct fbotex hook_fbos[MAX_TEXTURE_HOOKS];
struct tex_hook tex_hooks[MAX_TEXTURE_HOOKS];
int tex_hook_num;
+ struct fbotex hook_fbos[MAX_SAVED_TEXTURES];
+ int hook_fbo_num;
int frames_uploaded;
int frames_rendered;
@@ -586,19 +579,12 @@ static void uninit_rendering(struct gl_video *p)
for (int n = 0; n < 4; n++) {
fbotex_uninit(&p->merge_fbo[n]);
- fbotex_uninit(&p->deband_fbo[n]);
fbotex_uninit(&p->scale_fbo[n]);
fbotex_uninit(&p->integer_fbo[n]);
}
fbotex_uninit(&p->indirect_fbo);
fbotex_uninit(&p->blend_subs_fbo);
- fbotex_uninit(&p->unsharp_fbo);
-
- for (int n = 0; n < 2; n++) {
- fbotex_uninit(&p->pre_fbo[n]);
- fbotex_uninit(&p->post_fbo[n]);
- }
for (int pass = 0; pass < MAX_PRESCALE_PASSES; pass++)
fbotex_uninit(&p->prescale_fbo[pass]);
@@ -606,6 +592,9 @@ static void uninit_rendering(struct gl_video *p)
for (int n = 0; n < FBOSURFACES_MAX; n++)
fbotex_uninit(&p->surfaces[n].fbotex);
+ for (int n = 0; n < MAX_SAVED_TEXTURES; n++)
+ fbotex_uninit(&p->hook_fbos[n]);
+
gl_video_reset_surfaces(p);
}
@@ -993,6 +982,34 @@ static void finish_pass_fbo(struct gl_video *p, struct fbotex *dst_fbo,
&(struct mp_rect){0, 0, w, h});
}
+// Copy a texture to the vec4 color, while increasing offset. Also applies
+// the texture multiplier to the sampled color
+static void copy_img_tex(struct gl_video *p, int *offset, struct img_tex img)
+{
+ int count = img.components;
+ assert(*offset + count <= 4);
+
+ int id = pass_bind(p, img);
+ char src[5] = {0};
+ char dst[5] = {0};
+ const char *tex_fmt = img.swizzle[0] ? img.swizzle : "rgba";
+ const char *dst_fmt = "rgba";
+ for (int i = 0; i < count; i++) {
+ src[i] = tex_fmt[i];
+ dst[i] = dst_fmt[*offset + i];
+ }
+
+ if (img.use_integer) {
+ uint64_t tex_max = 1ull << p->image_desc.component_full_bits;
+ img.multiplier *= 1.0 / (tex_max - 1);
+ }
+
+ GLSLF("color.%s = %f * vec4(texture(texture%d, texcoord%d)).%s;\n",
+ dst, img.multiplier, id, id, src);
+
+ *offset += count;
+}
+
static void skip_unused(struct gl_video *p, int num_components)
{
for (int i = num_components; i < 4; i++)
@@ -1110,10 +1127,13 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
gl_transform_rect(hook_off, &sz);
int w = lroundf(fabs(sz.x1 - sz.x0));
int h = lroundf(fabs(sz.y1 - sz.y0));
- finish_pass_fbo(p, &p->hook_fbos[i], w, h, 0);
+
+ assert(p->hook_fbo_num < MAX_SAVED_TEXTURES);
+ struct fbotex *fbo = &p->hook_fbos[p->hook_fbo_num++];
+ finish_pass_fbo(p, fbo, w, h, 0);
const char *store_name = hook->save_tex ? hook->save_tex : name;
- struct img_tex saved_tex = img_tex_fbo(&p->hook_fbos[i], tex.type, comps);
+ struct img_tex saved_tex = img_tex_fbo(fbo, tex.type, comps);
// If the texture we're saving overwrites the "current" texture, also
// update the tex parameter so that the future loop cycles will use the
@@ -1136,6 +1156,37 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
return tex;
}
+// This can be used at any time in the middle of rendering to specify an
+// optional hook point, which if triggered will render out to a new FBO and
+// load the result back into vec4 color. Offsets applied by the hooks are
+// accumulated in tex_trans, and the FBO is dimensioned according
+// to p->texture_w/h
+static void pass_opt_hook_point(struct gl_video *p, const char *name,
+ struct gl_transform *tex_trans)
+{
+ if (!name)
+ return;
+
+ int i;
+ for (i = 0; i < p->tex_hook_num; i++) {
+ if (strcmp(p->tex_hooks[i].hook_tex, name) == 0)
+ break;
+ }
+
+ if (i == p->tex_hook_num)
+ return;
+
+ assert(p->hook_fbo_num < MAX_SAVED_TEXTURES);
+ struct fbotex *fbo = &p->hook_fbos[p->hook_fbo_num++];
+
+ finish_pass_fbo(p, fbo, p->texture_w, p->texture_h, 0);
+ struct img_tex img = img_tex_fbo(fbo, PLANE_RGB, p->components);
+ img = pass_hook(p, name, img, tex_trans);
+ copy_img_tex(p, &(int){0}, img);
+ p->texture_w = img.w;
+ p->texture_h = img.h;
+ p->components = img.components;
+}
static void load_shader(struct gl_video *p, const char *body)
{
@@ -1159,34 +1210,6 @@ static const char *get_custom_shader_fn(struct gl_video *p, const char *body)
return "sample_pixel";
}
-// Applies an arbitrary number of shaders in sequence, using the given pair
-// of FBOs as intermediate buffers. Returns whether any shaders were applied.
-static bool apply_shaders(struct gl_video *p, char **shaders, int w, int h,
- struct fbotex textures[2])
-{
- if (!shaders)
- return false;
- bool success = false;
- int tex = 0;
- for (int n = 0; shaders[n]; n++) {
- const char *body = load_cached_file(p, shaders[n]);
- if (!body)
- continue;
- finish_pass_fbo(p, &textures[tex], w, h, 0);
- int id = pass_bind(p, img_tex_fbo(&textures[tex], PLANE_RGB,
- p->components));
- GLSLHF("#define pixel_size pixel_size%d\n", id);
- load_shader(p, body);
- const char *fn_name = get_custom_shader_fn(p, body);
- GLSLF("// custom shader\n");
- GLSLF("color = %s(texture%d, texcoord%d, texture_size%d);\n",
- fn_name, id, id, id);
- tex = (tex+1) % 2;
- success = true;
- }
- return success;
-}
-
// Semantic equality
static bool double_seq(double a, double b)
{
@@ -1496,34 +1519,6 @@ static bool img_tex_equiv(struct img_tex a, struct img_tex b)
strcmp(a.swizzle, b.swizzle) == 0;
}
-// Copy a texture to the vec4 color, while increasing offset. Also applies
-// the texture multiplier to the sampled color
-static void copy_img_tex(struct gl_video *p, int *offset, struct img_tex img)
-{
- int count = img.components;
- assert(*offset + count <= 4);
-
- int id = pass_bind(p, img);
- char src[5] = {0};
- char dst[5] = {0};
- const char *tex_fmt = img.swizzle[0] ? img.swizzle : "rgba";
- const char *dst_fmt = "rgba";
- for (int i = 0; i < count; i++) {
- src[i] = tex_fmt[i];
- dst[i] = dst_fmt[*offset + i];
- }
-
- if (img.use_integer) {
- uint64_t tex_max = 1ull << p->image_desc.component_full_bits;
- img.multiplier *= 1.0 / (tex_max - 1);
- }
-
- GLSLF("color.%s = %f * vec4(texture(texture%d, texcoord%d)).%s;\n",
- dst, img.multiplier, id, id, src);
-
- *offset += count;
-}
-
static void pass_add_hook(struct gl_video *p, struct tex_hook hook)
{
if (p->tex_hook_num < MAX_TEXTURE_HOOKS) {
@@ -1577,6 +1572,48 @@ static void prescale_hook(struct gl_video *p, struct img_tex tex,
gl_transform_trans(step_trans, trans);
}
+static void unsharp_hook(struct gl_video *p, struct img_tex tex,
+ struct gl_transform *trans, void *priv)
+{
+ GLSLF("#define tex HOOKED\n");
+ GLSLF("#define pos HOOKED_pos\n");
+ GLSLF("#define pt HOOKED_pt\n");
+ pass_sample_unsharp(p->sc, p->opts.unsharp);
+}
+
+static void user_shader_hook(struct gl_video *p, struct img_tex tex,
+ struct gl_transform *trans, void *priv)
+{
+ const char *body = priv;
+ assert(body);
+
+ GLSLHF("#define pixel_size HOOKED_pt\n");
+ load_shader(p, body);
+ const char *fn_name = get_custom_shader_fn(p, body);
+ GLSLF("// custom shader\n");
+ GLSLF("color = %s(HOOKED, HOOKED_pos, HOOKED_size);\n", fn_name);
+}
+
+static void pass_hook_user_shaders(struct gl_video *p, const char *name,
+ char **shaders)
+{
+ assert(name);
+ if (!shaders)
+ return;
+
+ for (int n = 0; shaders[n] != NULL; n++) {
+ const char *body = load_cached_file(p, shaders[n]);
+ if (body) {
+ pass_add_hook(p, (struct tex_hook) {
+ .hook_tex = name,
+ .bind_tex = {"HOOKED"},
+ .hook = user_shader_hook,
+ .priv = (void *)body,
+ });
+ }
+ }
+}
+
static void pass_setup_hooks(struct gl_video *p)
{
// Reset any existing hooks
@@ -1596,6 +1633,17 @@ static void pass_setup_hooks(struct gl_video *p)
.priv = &p->prescale_fbo[i],
});
}
+
+ if (p->opts.unsharp != 0.0) {
+ pass_add_hook(p, (struct tex_hook) {
+ .hook_tex = "MAIN",
+ .bind_tex = {"HOOKED"},
+ .hook = unsharp_hook,
+ });
+ }
+
+ pass_hook_user_shaders(p, "MAIN", p->opts.pre_shaders);
+ pass_hook_user_shaders(p, "SCALED", p->opts.post_shaders);
}
// sample from video textures, set "color" variable to yuv value
@@ -1940,8 +1988,10 @@ static void pass_scale_main(struct gl_video *p)
// Pre-conversion, like linear light/sigmoidization
GLSLF("// scaler pre-conversion\n");
- if (p->use_linear)
+ if (p->use_linear) {
pass_linearize(p->sc, p->image_params.gamma);
+ pass_opt_hook_point(p, "LINEAR", NULL);
+ }
bool use_sigmoid = p->use_linear && p->opts.sigmoid_upscaling && upscaling;
float sig_center, sig_slope, sig_offset, sig_scale;
@@ -1956,8 +2006,11 @@ static void pass_scale_main(struct gl_video *p)
sig_scale = 1.0/(1+expf(sig_slope * (sig_center-1))) - sig_offset;
GLSLF("color.rgb = %f - log(1.0/(color.rgb * %f + %f) - 1.0)/%f;\n",
sig_center, sig_scale, sig_offset, sig_slope);
+ pass_opt_hook_point(p, "SIGMOID", NULL);
}
+ pass_opt_hook_point(p, "PREKERNEL", NULL);
+
int vp_w = p->dst_rect.x1 - p->dst_rect.x0;
int vp_h = p->dst_rect.y1 - p->dst_rect.y0;
struct gl_transform transform;
@@ -1973,6 +2026,8 @@ static void pass_scale_main(struct gl_video *p)
p->texture_w = vp_w;
p->texture_h = vp_h;
+ pass_opt_hook_point(p, "POSTKERNEL", NULL);
+
GLSLF("// scaler post-conversion\n");
if (use_sigmoid) {
// Inverse of the transformation above
@@ -2215,6 +2270,7 @@ static void pass_render_frame(struct gl_video *p)
p->texture_offset = identity_trans;
p->components = 0;
p->saved_tex_num = 0;
+ p->hook_fbo_num = 0;
if (p->image_params.rotate % 180 == 90)
MPSWAP(int, p->texture_w, p->texture_h);
@@ -2226,7 +2282,9 @@ static void pass_render_frame(struct gl_video *p)
p->use_linear = p->opts.linear_scaling || p->opts.sigmoid_upscaling;
pass_read_video(p);
+ pass_opt_hook_point(p, "NATIVE", &p->texture_offset);
pass_convert_yuv(p);
+ pass_opt_hook_point(p, "MAINPRESUB", &p->texture_offset);
// For subtitles
double vpts = p->image.mpi->pts;
@@ -2246,14 +2304,7 @@ static void pass_render_frame(struct gl_video *p)
GLSL(color = texture(texture0, texcoord0);)
pass_read_fbo(p, &p->blend_subs_fbo);
}
-
- apply_shaders(p, p->opts.pre_shaders, p->texture_w, p->texture_h, p->pre_fbo);
-
- if (p->opts.unsharp != 0.0) {
- finish_pass_fbo(p, &p->unsharp_fbo, p->texture_w, p->texture_h, 0);
- int id = pass_read_fbo(p, &p->unsharp_fbo);
- pass_sample_unsharp(p->sc, id, p->opts.unsharp);
- }
+ pass_opt_hook_point(p, "MAIN", &p->texture_offset);
pass_scale_main(p);
@@ -2284,7 +2335,7 @@ static void pass_render_frame(struct gl_video *p)
pass_linearize(p->sc, p->image_params.gamma);
}
- apply_shaders(p, p->opts.post_shaders, p->texture_w, p->texture_h, p->post_fbo);
+ pass_opt_hook_point(p, "SCALED", NULL);
}
static void pass_draw_to_screen(struct gl_video *p, int fbo)
@@ -2310,6 +2361,8 @@ static void pass_draw_to_screen(struct gl_video *p, int fbo)
GLSL(color.rgb = mix(background, color.rgb, color.a);)
}
+ pass_opt_hook_point(p, "OUTPUT", NULL);
+
pass_dither(p);
finish_pass_direct(p, fbo, p->vp_w, p->vp_h, &p->dst_rect);
}
diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c
index a31088edc9..8d3b1e0e40 100644
--- a/video/out/opengl/video_shaders.c
+++ b/video/out/opengl/video_shaders.c
@@ -383,11 +383,8 @@ void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
GLSLF("}\n");
}
-void pass_sample_unsharp(struct gl_shader_cache *sc, int tex_num, float param)
-{
+void pass_sample_unsharp(struct gl_shader_cache *sc, float param) {
GLSLF("// unsharp\n");
- sampler_prelude(sc, tex_num);
-
GLSLF("{\n");
GLSL(vec2 st1 = pt * 1.2;)
GLSL(vec4 p = texture(tex, pos);)
diff --git a/video/out/opengl/video_shaders.h b/video/out/opengl/video_shaders.h
index e010fdba55..bbfeebb576 100644
--- a/video/out/opengl/video_shaders.h
+++ b/video/out/opengl/video_shaders.h
@@ -41,6 +41,6 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc);
void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
int tex_num, float tex_mul, GLenum tex_target, AVLFG *lfg);
-void pass_sample_unsharp(struct gl_shader_cache *sc, int tex_num, float param);
+void pass_sample_unsharp(struct gl_shader_cache *sc, float param);
#endif