1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-26 09:02:38 +00:00

vo_opengl: slightly refactor user_shaders code

- Each struct tex_hook now stores multiple hooks, this allows us to
  avoid the awkward way of the current code has to add the same pass
  multiple times.

- As a consequence, SHADER_MAX_HOOKS was split up into SHADER_MAX_PASSES
  (number of tex_hooks) and SHADER_MAX_HOOKS (number of hooked textures
  per tex_hook), and both numbers decreased correspondingly.

- Instead of having a weird free() callback, we can just leverage
  talloc's recursive free behavior. The only user is the user shaders code
  anyway.
This commit is contained in:
Niklas Haas 2017-07-10 22:52:39 +02:00
parent ea76f79e5d
commit f1af6e53f0
3 changed files with 52 additions and 72 deletions

View File

@ -158,7 +158,6 @@ done:
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)
{
@ -166,7 +165,7 @@ bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
return false;
*out = (struct gl_user_shader){
.desc = bstr0("(unknown)"),
.pass_desc = bstr0("(unknown)"),
.offset = identity_trans,
.width = {{ SZEXP_VAR_W, { .varname = bstr0("HOOKED") }}},
.height = {{ SZEXP_VAR_H, { .varname = bstr0("HOOKED") }}},
@ -179,12 +178,12 @@ bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
// Skip all garbage (e.g. comments) before the first header
int pos = bstr_find(*body, bstr0("//!"));
if (pos < 0) {
mp_warn(log, "Shader appears to contain no passes!\n");
mp_warn(log, "Shader appears to contain no headers!\n");
return false;
}
*body = bstr_cut(*body, pos);
// First parse all the headers
// Parse all headers
while (true) {
struct bstr rest;
struct bstr line = bstr_strip(bstr_getline(*body, &rest));
@ -222,7 +221,7 @@ bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
}
if (bstr_eatstart0(&line, "DESC")) {
out->desc = bstr_strip(line);
out->pass_desc = bstr_strip(line);
continue;
}

View File

@ -21,8 +21,8 @@
#include "common.h"
#include "utils.h"
#define SHADER_API 1
#define SHADER_MAX_HOOKS 64
#define SHADER_MAX_PASSES 32
#define SHADER_MAX_HOOKS 16
#define SHADER_MAX_BINDS 6
#define SHADER_MAX_SAVED 64
#define MAX_SZEXP_SIZE 32
@ -56,11 +56,11 @@ struct szexp {
};
struct gl_user_shader {
struct bstr pass_desc;
struct bstr hook_tex[SHADER_MAX_HOOKS];
struct bstr bind_tex[SHADER_MAX_BINDS];
struct bstr save_tex;
struct bstr pass_body;
struct bstr desc;
struct gl_transform offset;
struct szexp width[MAX_SZEXP_SIZE];
struct szexp height[MAX_SZEXP_SIZE];
@ -70,8 +70,8 @@ struct gl_user_shader {
int compute_h;
};
// Parse the next shader pass from 'body'. Returns false if the end of the
// string was reached
// Parse the next shader pass from `body`. The `struct bstr` is modified by the
// function. Returns false if the end of the string was reached (or on error).
bool parse_user_shader_pass(struct mp_log *log, struct bstr *body,
struct gl_user_shader *out);

View File

@ -145,14 +145,13 @@ struct saved_tex {
// A texture hook. This is some operation that transforms a named texture as
// soon as it's generated
struct tex_hook {
char *hook_tex;
char *save_tex;
char *bind_tex[TEXUNIT_VIDEO_NUM];
const char *save_tex;
const char *hook_tex[SHADER_MAX_HOOKS];
const char *bind_tex[TEXUNIT_VIDEO_NUM];
int components; // how many components are relevant (0 = same as input)
void *priv; // this can be set to whatever the hook wants
void *priv; // this gets talloc_freed when the tex_hook is removed
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);
};
@ -174,7 +173,7 @@ struct pass_info {
struct mp_pass_perf perf;
};
#define PASS_INFO_MAX (SHADER_MAX_HOOKS + 32)
#define PASS_INFO_MAX (SHADER_MAX_PASSES + 32)
struct dr_buffer {
struct ra_mapped_buffer *buffer;
@ -276,10 +275,10 @@ struct gl_video {
struct gl_timer *blit_timer;
// hooks and saved textures
struct tex_hook tex_hooks[SHADER_MAX_PASSES];
int tex_hook_num;
struct saved_tex saved_tex[SHADER_MAX_SAVED];
int saved_tex_num;
struct tex_hook tex_hooks[SHADER_MAX_HOOKS];
int tex_hook_num;
struct fbotex hook_fbos[SHADER_MAX_SAVED];
int hook_fbo_num;
@ -501,10 +500,8 @@ static void gl_video_reset_surfaces(struct gl_video *p)
static void gl_video_reset_hooks(struct gl_video *p)
{
for (int i = 0; i < p->tex_hook_num; i++) {
if (p->tex_hooks[i].free)
p->tex_hooks[i].free(&p->tex_hooks[i]);
}
for (int i = 0; i < p->tex_hook_num; i++)
talloc_free(p->tex_hooks[i].priv);
p->tex_hook_num = 0;
}
@ -1395,9 +1392,15 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
for (int i = 0; i < p->tex_hook_num; i++) {
struct tex_hook *hook = &p->tex_hooks[i];
if (strcmp(hook->hook_tex, name) != 0)
continue;
// Figure out if this pass hooks this texture
for (int h = 0; h < SHADER_MAX_HOOKS; h++) {
if (hook->hook_tex[h] && strcmp(hook->hook_tex[h], name) == 0)
goto found;
}
continue;
found:
// 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);
@ -1489,8 +1492,10 @@ static void pass_opt_hook_point(struct gl_video *p, const char *name,
for (int i = 0; i < p->tex_hook_num; i++) {
struct tex_hook *hook = &p->tex_hooks[i];
if (strcmp(hook->hook_tex, name) == 0)
goto found;
for (int h = 0; h < SHADER_MAX_HOOKS; h++) {
if (hook->hook_tex[h] && strcmp(hook->hook_tex[h], name) == 0)
goto found;
}
for (int b = 0; b < TEXUNIT_VIDEO_NUM; b++) {
if (hook->bind_tex[b] && strcmp(hook->bind_tex[b], name) == 0)
@ -1822,25 +1827,11 @@ static bool img_tex_equiv(struct img_tex a, struct img_tex b)
static void pass_add_hook(struct gl_video *p, struct tex_hook hook)
{
if (p->tex_hook_num < SHADER_MAX_HOOKS) {
if (p->tex_hook_num < SHADER_MAX_PASSES) {
p->tex_hooks[p->tex_hook_num++] = hook;
} else {
MP_ERR(p, "Too many hooks! Limit is %d.\n", SHADER_MAX_HOOKS);
if (hook.free)
hook.free(&hook);
}
}
// Adds a hook multiple times, one per name. The last name must be NULL to
// signal the end of the argument list.
#define HOOKS(...) ((char*[]){__VA_ARGS__, NULL})
static void pass_add_hooks(struct gl_video *p, struct tex_hook hook,
char **names)
{
for (int i = 0; names[i] != NULL; i++) {
hook.hook_tex = names[i];
pass_add_hook(p, hook);
MP_ERR(p, "Too many passes! Limit is %d.\n", SHADER_MAX_PASSES);
talloc_free(hook.priv);
}
}
@ -1919,7 +1910,7 @@ static void user_hook(struct gl_video *p, struct img_tex tex,
struct gl_user_shader *shader = priv;
assert(shader);
pass_describe(p, "user shader: %.*s (%s)", BSTR_P(shader->desc),
pass_describe(p, "user shader: %.*s (%s)", BSTR_P(shader->pass_desc),
plane_names[tex.type]);
compute_size_minimum(p, shader->compute_w, shader->compute_h);
@ -1937,15 +1928,6 @@ static void user_hook(struct gl_video *p, struct img_tex tex,
gl_transform_trans(shader->offset, trans);
}
static void user_hook_free(struct tex_hook *hook)
{
talloc_free(hook->hook_tex);
talloc_free(hook->save_tex);
for (int i = 0; i < TEXUNIT_VIDEO_NUM; i++)
talloc_free(hook->bind_tex[i]);
talloc_free(hook->priv);
}
static void pass_hook_user_shaders(struct gl_video *p, char **shaders)
{
if (!shaders)
@ -1955,26 +1937,23 @@ static void pass_hook_user_shaders(struct gl_video *p, char **shaders)
struct bstr file = load_cached_file(p, shaders[n]);
struct gl_user_shader out;
while (parse_user_shader_pass(p->log, &file, &out)) {
struct tex_hook hook = {
.components = out.components,
struct gl_user_shader *hook = talloc_ptrtype(p, hook);
*hook = out;
struct tex_hook texhook = {
.save_tex = bstrdup0(hook, hook->save_tex),
.components = hook->components,
.hook = user_hook,
.free = user_hook_free,
.cond = user_hook_cond,
.priv = hook,
};
for (int i = 0; i < SHADER_MAX_HOOKS; i++) {
hook.hook_tex = bstrdup0(p, out.hook_tex[i]);
if (!hook.hook_tex)
continue;
for (int h = 0; h < SHADER_MAX_HOOKS; h++)
texhook.hook_tex[h] = bstrdup0(hook, hook->hook_tex[h]);
for (int h = 0; h < SHADER_MAX_BINDS; h++)
texhook.bind_tex[h] = bstrdup0(hook, hook->bind_tex[h]);
struct gl_user_shader *out_copy = talloc_ptrtype(p, out_copy);
*out_copy = out;
hook.priv = out_copy;
for (int o = 0; o < SHADER_MAX_BINDS; o++)
hook.bind_tex[o] = bstrdup0(p, out.bind_tex[o]);
hook.save_tex = bstrdup0(p, out.save_tex),
pass_add_hook(p, hook);
}
pass_add_hook(p, texhook);
}
}
}
@ -1984,14 +1963,16 @@ static void gl_video_setup_hooks(struct gl_video *p)
gl_video_reset_hooks(p);
if (p->opts.deband) {
pass_add_hooks(p, (struct tex_hook) {.hook = deband_hook,
.bind_tex = {"HOOKED"}},
HOOKS("LUMA", "CHROMA", "RGB", "XYZ"));
pass_add_hook(p, (struct tex_hook) {
.hook_tex = {"LUMA", "CHROMA", "RGB", "XYZ"},
.bind_tex = {"HOOKED"},
.hook = deband_hook,
});
}
if (p->opts.unsharp != 0.0) {
pass_add_hook(p, (struct tex_hook) {
.hook_tex = "MAIN",
.hook_tex = {"MAIN"},
.bind_tex = {"HOOKED"},
.hook = unsharp_hook,
});