summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/user_shaders.c
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 /video/out/opengl/user_shaders.c
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.
Diffstat (limited to 'video/out/opengl/user_shaders.c')
-rw-r--r--video/out/opengl/user_shaders.c89
1 files changed, 89 insertions, 0 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)