summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/video.c
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-06-08 15:05:28 +0200
committerwm4 <wm4@nowhere>2016-06-08 20:50:19 +0200
commit54c48bd80120a3085e6d23f7cf6124b0657436e7 (patch)
treed060ec1b942d4d544597c1e7c5fa5898d921edb1 /video/out/opengl/video.c
parenta15181e5df5ba8a21e6a5b953213f4a72690c47f (diff)
downloadmpv-54c48bd80120a3085e6d23f7cf6124b0657436e7.tar.bz2
mpv-54c48bd80120a3085e6d23f7cf6124b0657436e7.tar.xz
vo_opengl: make user hook passes optional
User hooks can now use an extra WHEN expression to specify when the shader should be run. For example, this can be used to only run a chroma scaling shader `WHEN CHROMA.w LUMA.w <`. There's a slight semantics change to user shaders: When trying to bind a texture that does not exist, a shader will now be silently skipped (similar to when the condition is false) instead of generating an error. This allows shader stages to depend on an optional earlier stage without having to copy/paste the same condition everywhere. (In other words: there's an implicit condition on all of the bound textures existing)
Diffstat (limited to 'video/out/opengl/video.c')
-rw-r--r--video/out/opengl/video.c71
1 files changed, 55 insertions, 16 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 52dbe19961..e23bfb4edf 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -154,6 +154,7 @@ struct tex_hook {
void (*hook)(struct gl_video *p, struct img_tex tex, // generates GLSL
struct gl_transform *trans, void *priv);
void (*free)(struct tex_hook *hook);
+ bool (*cond)(struct gl_video *p, struct img_tex tex, void *priv);
};
struct fbosurface {
@@ -1132,6 +1133,12 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
if (strcmp(hook->hook_tex, name) != 0)
continue;
+ // Check the hook's condition
+ if (hook->cond && !hook->cond(p, tex, hook->priv)) {
+ MP_DBG(p, "Skipping hook on %s due to condition.\n", name);
+ continue;
+ }
+
// Bind all necessary textures and add them to the prelude
for (int t = 0; t < TEXUNIT_VIDEO_NUM; t++) {
const char *bind_name = hook->bind_tex[t];
@@ -1149,12 +1156,11 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
}
if (!saved_tex_find(p, bind_name, &bind_tex)) {
- // Clean up texture bindings and just return as-is, stop
- // all further processing of this hook
- MP_ERR(p, "Failed running hook for %s: No saved texture named"
- " %s!\n", name, bind_name);
+ // Clean up texture bindings and move on to the next hook
+ MP_DBG(p, "Skipping hook on %s due to no texture named %s.\n",
+ name, bind_name);
p->pass_tex_num -= t;
- return tex;
+ goto next_hook;
}
hook_prelude(p, bind_name, pass_bind(p, bind_tex), bind_tex);
@@ -1197,6 +1203,8 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
}
saved_tex_store(p, store_name, saved_tex);
+
+next_hook: ;
}
return tex;
@@ -1615,9 +1623,10 @@ static void user_hook_old(struct gl_video *p, struct img_tex tex,
GLSLF("color = %s(HOOKED_raw, HOOKED_pos, HOOKED_size);\n", fn_name);
}
-// Returns 1.0 on failure to at least create a legal FBO
-static float eval_szexpr(struct gl_video *p, struct img_tex tex,
- struct szexp expr[MAX_SZEXP_SIZE])
+// Returns whether successful. 'result' is left untouched on failure
+static bool eval_szexpr(struct gl_video *p, struct img_tex tex,
+ struct szexp expr[MAX_SZEXP_SIZE],
+ float *result)
{
float stack[MAX_SZEXP_SIZE] = {0};
int idx = 0; // points to next element to push
@@ -1634,10 +1643,22 @@ static float eval_szexpr(struct gl_video *p, struct img_tex tex,
stack[idx++] = expr[i].val.cval;
continue;
+ case SZEXP_OP1:
+ if (idx < 1) {
+ MP_WARN(p, "Stack underflow in RPN expression!\n");
+ return false;
+ }
+
+ switch (expr[i].val.op) {
+ case SZEXP_OP_NOT: stack[idx-1] = !stack[idx-1]; break;
+ default: abort();
+ }
+ continue;
+
case SZEXP_OP2:
if (idx < 2) {
MP_WARN(p, "Stack underflow in RPN expression!\n");
- return 1.0;
+ return false;
}
// Pop the operands in reverse order
@@ -1649,12 +1670,14 @@ static float eval_szexpr(struct gl_video *p, struct img_tex tex,
case SZEXP_OP_SUB: res = op1 - op2; break;
case SZEXP_OP_MUL: res = op1 * op2; break;
case SZEXP_OP_DIV: res = op1 / op2; break;
+ case SZEXP_OP_GT: res = op1 > op2; break;
+ case SZEXP_OP_LT: res = op1 < op2; break;
default: abort();
}
- if (isnan(res)) {
+ if (!isfinite(res)) {
MP_WARN(p, "Illegal operation in RPN expression!\n");
- return 1.0;
+ return false;
}
stack[idx++] = res;
@@ -1679,7 +1702,7 @@ static float eval_szexpr(struct gl_video *p, struct img_tex tex,
}
MP_WARN(p, "Texture %.*s not found in RPN expression!\n", BSTR_P(name));
- return 1.0;
+ return false;
found_tex:
stack[idx++] = (expr[i].tag == SZEXP_VAR_W) ? var_tex.w : var_tex.h;
@@ -1692,10 +1715,21 @@ done:
// Return the single stack element
if (idx != 1) {
MP_WARN(p, "Malformed stack after RPN expression!\n");
- return 1.0;
+ return false;
}
- return stack[0];
+ *result = stack[0];
+ return true;
+}
+
+static bool user_hook_cond(struct gl_video *p, struct img_tex tex, void *priv)
+{
+ struct gl_user_shader *shader = priv;
+ assert(shader);
+
+ float res = false;
+ eval_szexpr(p, tex, shader->cond, &res);
+ return res;
}
static void user_hook(struct gl_video *p, struct img_tex tex,
@@ -1708,8 +1742,12 @@ static void user_hook(struct gl_video *p, struct img_tex tex,
GLSLF("// custom hook\n");
GLSLF("color = hook();\n");
- float w = eval_szexpr(p, tex, shader->width);
- float h = eval_szexpr(p, tex, shader->height);
+ // Make sure we at least create a legal FBO on failure, since it's better
+ // to do this and display an error message than just crash OpenGL
+ float w = 1.0, h = 1.0;
+
+ eval_szexpr(p, tex, shader->width, &w);
+ eval_szexpr(p, tex, shader->height, &h);
*trans = (struct gl_transform){{{w / tex.w, 0}, {0, h / tex.h}}};
gl_transform_trans(shader->offset, trans);
@@ -1757,6 +1795,7 @@ static void pass_hook_user_shaders(struct gl_video *p, char **shaders)
.components = out.components,
.hook = user_hook,
.free = user_hook_free,
+ .cond = user_hook_cond,
};
for (int i = 0; i < SHADER_MAX_HOOKS; i++) {