summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-07-03 19:23:03 +0200
committerwm4 <wm4@nowhere>2016-07-03 19:42:52 +0200
commitbe230d16e57d948a990d16f06d4da11cfea97701 (patch)
tree74a5345cac0506bb97494b79ab7900fb1fbf4a98
parent5b6cce2b735951f82b707c3d3625f99bc6d6da09 (diff)
downloadmpv-be230d16e57d948a990d16f06d4da11cfea97701.tar.bz2
mpv-be230d16e57d948a990d16f06d4da11cfea97701.tar.xz
vo_opengl: move eval_szexpr to user_shaders.c
This moves some of the bulky user-shader specific logic into the file dedicated to it. Rather than expose video.c state, variable lookup is now done via a simulated closure.
-rw-r--r--video/out/opengl/user_shaders.c89
-rw-r--r--video/out/opengl/user_shaders.h5
-rw-r--r--video/out/opengl/video.c132
3 files changed, 124 insertions, 102 deletions
diff --git a/video/out/opengl/user_shaders.c b/video/out/opengl/user_shaders.c
index 8f915a56e3..112012f04f 100644
--- a/video/out/opengl/user_shaders.c
+++ b/video/out/opengl/user_shaders.c
@@ -16,6 +16,7 @@
*/
#include <ctype.h>
+#include <assert.h>
#include "user_shaders.h"
@@ -69,6 +70,94 @@ static bool parse_rpn_szexpr(struct bstr line, struct szexp out[MAX_SZEXP_SIZE])
return true;
}
+// Returns whether successful. 'result' is left untouched on failure
+bool eval_szexpr(struct mp_log *log, void *priv,
+ bool (*lookup)(void *priv, struct bstr var, float size[2]),
+ struct szexp expr[MAX_SZEXP_SIZE], float *result)
+{
+ float stack[MAX_SZEXP_SIZE] = {0};
+ int idx = 0; // points to next element to push
+
+ for (int i = 0; i < MAX_SZEXP_SIZE; i++) {
+ switch (expr[i].tag) {
+ case SZEXP_END:
+ goto done;
+
+ case SZEXP_CONST:
+ // Since our SZEXPs are bound by MAX_SZEXP_SIZE, it should be
+ // impossible to overflow the stack
+ assert(idx < MAX_SZEXP_SIZE);
+ stack[idx++] = expr[i].val.cval;
+ continue;
+
+ case SZEXP_OP1:
+ if (idx < 1) {
+ mp_warn(log, "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(log, "Stack underflow in RPN expression!\n");
+ return false;
+ }
+
+ // Pop the operands in reverse order
+ float op2 = stack[--idx];
+ float op1 = stack[--idx];
+ float res = 0.0;
+ switch (expr[i].val.op) {
+ case SZEXP_OP_ADD: res = op1 + op2; break;
+ 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 (!isfinite(res)) {
+ mp_warn(log, "Illegal operation in RPN expression!\n");
+ return false;
+ }
+
+ stack[idx++] = res;
+ continue;
+
+ case SZEXP_VAR_W:
+ case SZEXP_VAR_H: {
+ struct bstr name = expr[i].val.varname;
+ float size[2];
+
+ if (!lookup(priv, name, size)) {
+ mp_warn(log, "Variable %.*s not found in RPN expression!\n",
+ BSTR_P(name));
+ return false;
+ }
+
+ stack[idx++] = (expr[i].tag == SZEXP_VAR_W) ? size[0] : size[1];
+ continue;
+ }
+ }
+ }
+
+done:
+ // Return the single stack element
+ if (idx != 1) {
+ mp_warn(log, "Malformed stack after RPN expression!\n");
+ return false;
+ }
+
+ *result = stack[0];
+ return true;
+}
+
// Returns false if no more shaders could be parsed
bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
struct gl_user_shader *out)
diff --git a/video/out/opengl/user_shaders.h b/video/out/opengl/user_shaders.h
index b8c287b6bd..7527eb3ba2 100644
--- a/video/out/opengl/user_shaders.h
+++ b/video/out/opengl/user_shaders.h
@@ -71,4 +71,9 @@ struct gl_user_shader {
bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
struct gl_user_shader *out);
+// Evaluate a szexp, given a lookup function for named textures
+bool eval_szexpr(struct mp_log *log, void *priv,
+ bool (*lookup)(void *priv, struct bstr var, float size[2]),
+ struct szexp expr[MAX_SZEXP_SIZE], float *result);
+
#endif
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index a4cc6cfac8..7ae91eed0d 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -1544,112 +1544,40 @@ 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 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
-
- for (int i = 0; i < MAX_SZEXP_SIZE; i++) {
- switch (expr[i].tag) {
- case SZEXP_END:
- goto done;
-
- case SZEXP_CONST:
- // Since our SZEXPs are bound by MAX_SZEXP_SIZE, it should be
- // impossible to overflow the stack
- assert(idx < MAX_SZEXP_SIZE);
- 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 false;
- }
-
- // Pop the operands in reverse order
- float op2 = stack[--idx];
- float op1 = stack[--idx];
- float res = 0.0;
- switch (expr[i].val.op) {
- case SZEXP_OP_ADD: res = op1 + op2; break;
- 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 (!isfinite(res)) {
- MP_WARN(p, "Illegal operation in RPN expression!\n");
- return false;
- }
-
- stack[idx++] = res;
- continue;
-
- case SZEXP_VAR_W:
- case SZEXP_VAR_H: {
- struct bstr name = expr[i].val.varname;
- struct img_tex var_tex;
-
- // The size of OUTPUT is determined. It could be useful for certain
- // user shaders to skip passes.
- if (bstr_equals0(name, "OUTPUT")) {
- int vp_w = p->dst_rect.x1 - p->dst_rect.x0;
- int vp_h = p->dst_rect.y1 - p->dst_rect.y0;
- stack[idx++] = (expr[i].tag == SZEXP_VAR_W) ? vp_w : vp_h;
- continue;
- }
-
- // HOOKED is a special case
- if (bstr_equals0(name, "HOOKED")) {
- var_tex = tex;
- goto found_tex;
- }
+struct szexp_ctx {
+ struct gl_video *p;
+ struct img_tex tex;
+};
- for (int o = 0; o < p->saved_tex_num; o++) {
- if (bstr_equals0(name, p->saved_tex[o].name)) {
- var_tex = p->saved_tex[o].tex;
- goto found_tex;
- }
- }
+static bool szexp_lookup(void *priv, struct bstr var, float size[2])
+{
+ struct szexp_ctx *ctx = priv;
+ struct gl_video *p = ctx->p;
- MP_WARN(p, "Texture %.*s not found in RPN expression!\n", BSTR_P(name));
- return false;
+ // The size of OUTPUT is determined. It could be useful for certain
+ // user shaders to skip passes.
+ if (bstr_equals0(var, "OUTPUT")) {
+ size[0] = p->dst_rect.x1 - p->dst_rect.x0;
+ size[1] = p->dst_rect.y1 - p->dst_rect.y0;
+ return true;
+ }
-found_tex:
- stack[idx++] = (expr[i].tag == SZEXP_VAR_W) ? var_tex.w : var_tex.h;
- continue;
- }
- }
+ // HOOKED is a special case
+ if (bstr_equals0(var, "HOOKED")) {
+ size[0] = ctx->tex.w;
+ size[1] = ctx->tex.h;
+ return true;
}
-done:
- // Return the single stack element
- if (idx != 1) {
- MP_WARN(p, "Malformed stack after RPN expression!\n");
- return false;
+ for (int o = 0; o < p->saved_tex_num; o++) {
+ if (bstr_equals0(var, p->saved_tex[o].name)) {
+ size[0] = p->saved_tex[o].tex.w;
+ size[1] = p->saved_tex[o].tex.h;
+ return true;
+ }
}
- *result = stack[0];
- return true;
+ return false;
}
static bool user_hook_cond(struct gl_video *p, struct img_tex tex, void *priv)
@@ -1658,7 +1586,7 @@ static bool user_hook_cond(struct gl_video *p, struct img_tex tex, void *priv)
assert(shader);
float res = false;
- eval_szexpr(p, tex, shader->cond, &res);
+ eval_szexpr(p->log, &(struct szexp_ctx){p, tex}, szexp_lookup, shader->cond, &res);
return res;
}
@@ -1676,8 +1604,8 @@ static void user_hook(struct gl_video *p, struct img_tex tex,
// 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);
+ eval_szexpr(p->log, &(struct szexp_ctx){p, tex}, szexp_lookup, shader->width, &w);
+ eval_szexpr(p->log, &(struct szexp_ctx){p, tex}, szexp_lookup, shader->height, &h);
*trans = (struct gl_transform){{{w / tex.w, 0}, {0, h / tex.h}}};
gl_transform_trans(shader->offset, trans);