summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-05-14 07:05:04 +0200
committerNiklas Haas <git@nand.wakku.to>2016-05-15 20:42:08 +0200
commit362015cd770de486c5dea218d3609450682756ca (patch)
treecd0539b4f10cd09444f74ed0aeb6fb1c7b16533b
parentdfc7b59909588985ee1be19f313f8bfb858ab8b0 (diff)
downloadmpv-362015cd770de486c5dea218d3609450682756ca.tar.bz2
mpv-362015cd770de486c5dea218d3609450682756ca.tar.xz
vo_opengl: abstract hook texture access behind macro
This macro takes care of rotation, swizzling, integer conversion and normalization automatically. I found the performance impact to be nonexistant for superxbr and debanding, although rotation *did* have an impact due to the extra matrix multiplication. (So it gets skipped where possible) All of the internal hooks have been rewritten to use this new mechanism, and the prescaler hooks have finally been separated from each other. This also means the prescale FBO kludge is no longer required. This fixes image corruption for image formats like 0bgr, and also fixes prescaling under rotation. (As well as other user hooks that have orientation-dependent access) The "raw" attributes (tex, tex_pos, pixel_size) are still un-rotated, in case something needs them, but ideally the hooks should be rewritten to use the new API as much as possible. The hooked texture has been renamed from just NAME to NAME_raw to make script authors notice the change (and also deemphasize direct texture access). This is also a step towards getting rid of the use_integer pass.
-rw-r--r--DOCS/man/vo.rst16
-rw-r--r--video/out/opengl/nnedi3.c33
-rw-r--r--video/out/opengl/nnedi3.h6
-rw-r--r--video/out/opengl/superxbr.c29
-rw-r--r--video/out/opengl/superxbr.h2
-rw-r--r--video/out/opengl/video.c129
-rw-r--r--video/out/opengl/video_shaders.c57
-rw-r--r--video/out/opengl/video_shaders.h3
8 files changed, 138 insertions, 137 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 4d6972e5a3..7892761581 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -763,14 +763,26 @@ Available video output drivers are:
definitions to that shader pass, where NAME is the name of the bound
texture:
- sampler NAME
- The bound texture itself.
+ vec4 NAME_tex(vec2 pos)
+ The sampling function to use to access the texture at a certain
+ spot (in texture coordinate space, range [0,1]). This takes care
+ of any necessary normalization conversions.
+ vec4 NAME_texOff(vec2 offset)
+ Sample the texture at a certain offset in pixels. This works like
+ NAME_tex but additionally takes care of necessary rotations, so
+ that sampling at e.g. vec2(-1,0) is always one pixel to the left.
vec2 NAME_pos
The local texture coordinate of that texture, range [0,1].
vec2 NAME_size
The (rotated) size in pixels of the texture.
+ mat2 NAME_rot
+ The rotation matrix associated with this texture. (Rotates
+ pixel space to texture coordinates)
vec2 NAME_pt
The (unrotated) size of a single pixel, range [0,1].
+ sampler NAME_raw
+ The raw bound texture itself. The use of this should be
+ avoided unless absolutely necessary.
In addition, the global uniforms described in ``post-shaders`` are
also available.
diff --git a/video/out/opengl/nnedi3.c b/video/out/opengl/nnedi3.c
index 3c12fcc623..74eb083786 100644
--- a/video/out/opengl/nnedi3.c
+++ b/video/out/opengl/nnedi3.c
@@ -96,9 +96,9 @@ const float* get_nnedi3_weights(const struct nnedi3_opts *conf, int *size)
return (const float*)(nnedi3_weights + offset * 4);
}
-void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num,
- int step, float tex_mul, const struct nnedi3_opts *conf,
- struct gl_transform *transform, GLenum tex_target)
+void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int step,
+ const struct nnedi3_opts *conf,
+ struct gl_transform *transform)
{
assert(0 <= step && step < 2);
@@ -131,23 +131,23 @@ void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num,
GLSLH(#pragma optionNV(fastprecision on))
}
- GLSLHF("float nnedi3(%s tex, vec2 pos, vec2 tex_size, vec2 pixel_size, int plane, float tex_mul) {\n", mp_sampler_type(tex_target));
+ GLSLHF("float nnedi3() {\n");
if (step == 0) {
*transform = (struct gl_transform){{{1.0,0.0}, {0.0,2.0}}, {0.0,-0.5}};
- GLSLH(if (fract(pos.y * tex_size.y) < 0.5)
- return texture(tex, pos + vec2(0, 0.25) * pixel_size)[plane] * tex_mul;)
+ GLSLH(if ((transpose(HOOKED_rot) * fract(HOOKED_pos * HOOKED_size)).y < 0.5)
+ return HOOKED_texOff(vec2(0, 0.25)).x;)
GLSLHF("#define GET(i, j) "
- "(texture(tex, pos+vec2((i)-(%f),(j)-(%f)+0.25) * pixel_size)[plane]*tex_mul)\n",
+ "HOOKED_texOff(vec2((i)-(%f),(j)-(%f)+0.25)).x\n",
width / 2.0 - 1, (height - 1) / 2.0);
} else {
*transform = (struct gl_transform){{{2.0,0.0}, {0.0,1.0}}, {-0.5,0.0}};
- GLSLH(if (fract(pos.x * tex_size.x) < 0.5)
- return texture(tex, pos + vec2(0.25, 0) * pixel_size)[plane] * tex_mul;)
+ GLSLH(if (fract(HOOKED_pos.x * HOOKED_size.x) < 0.5)
+ return HOOKED_texOff(vec2(0.25, 0)).x;)
GLSLHF("#define GET(i, j) "
- "(texture(tex, pos+vec2((j)-(%f)+0.25,(i)-(%f)) * pixel_size)[plane]*tex_mul)\n",
+ "HOOKED_texOff(vec2((j)-(%f)+0.25,(i)-(%f))).x\n",
(height - 1) / 2.0, width / 2.0 - 1);
}
@@ -226,12 +226,7 @@ void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num,
GLSLHF("}\n"); // nnedi3
- GLSL(color = vec4(1.0);)
-
- for (int i = 0; i < planes; i++) {
- GLSLF("color[%d] = nnedi3(texture%d, texcoord%d, texture_size%d, pixel_size%d, %d, %f);\n",
- i, tex_num, tex_num, tex_num, tex_num, i, tex_mul);
- }
+ GLSL(color.x = nnedi3();)
}
#else
@@ -244,9 +239,9 @@ const float* get_nnedi3_weights(const struct nnedi3_opts *conf, int *size)
return NULL;
}
-void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num,
- int step, float tex_mul, const struct nnedi3_opts *conf,
- struct gl_transform *transform, GLenum tex_target)
+void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int step,
+ const struct nnedi3_opts *conf,
+ struct gl_transform *transform)
{
}
diff --git a/video/out/opengl/nnedi3.h b/video/out/opengl/nnedi3.h
index c3895a0773..8cd1a65815 100644
--- a/video/out/opengl/nnedi3.h
+++ b/video/out/opengl/nnedi3.h
@@ -38,8 +38,8 @@ extern const struct m_sub_options nnedi3_conf;
const float* get_nnedi3_weights(const struct nnedi3_opts *conf, int *size);
-void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num,
- int step, float tex_mul, const struct nnedi3_opts *conf,
- struct gl_transform *transform, GLenum tex_target);
+void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int step,
+ const struct nnedi3_opts *conf,
+ struct gl_transform *transform);
#endif
diff --git a/video/out/opengl/superxbr.c b/video/out/opengl/superxbr.c
index 323ed18513..b7b9a53afd 100644
--- a/video/out/opengl/superxbr.c
+++ b/video/out/opengl/superxbr.c
@@ -174,7 +174,7 @@ static void superxbr_step_h(struct gl_shader_cache *sc,
}
// Pick the two best directions and mix them together
- GLSLHF("float str = smoothstep(0.0, %f + 1e-6, abs(tex_mul*d_edge));\n",
+ GLSLHF("float str = smoothstep(0.0, %f + 1e-6, abs(d_edge));\n",
conf->edge_strength);
GLSLH(res = mix(mix(d2c, d1c, step(0.0, d_edge)), \
mix(hc, vc, step(0.0, o_edge)), 1.0 - str);)
@@ -187,7 +187,7 @@ static void superxbr_step_h(struct gl_shader_cache *sc,
GLSLHF("} // step\n");
}
-void pass_superxbr(struct gl_shader_cache *sc, int id, int step, float tex_mul,
+void pass_superxbr(struct gl_shader_cache *sc, int step,
const struct superxbr_opts *conf,
struct gl_transform *transform)
{
@@ -196,49 +196,48 @@ void pass_superxbr(struct gl_shader_cache *sc, int id, int step, float tex_mul,
assert(0 <= step && step < 2);
GLSLF("// superxbr (step %d)\n", step);
- GLSLHF("#define tex texture%d\n", id);
- GLSLHF("#define tex_size texture_size%d\n", id);
- GLSLHF("#define tex_mul %f\n", tex_mul);
- GLSLHF("#define pt pixel_size%d\n", id);
// We use a sub-function in the header so we can return early
- GLSLHF("float superxbr(vec2 pos) {\n");
+ GLSLHF("float superxbr() {\n");
GLSLH(float i[4*4];)
GLSLH(float res;)
GLSLH(#define i(x,y) i[(x)*4+(y)])
if (step == 0) {
*transform = (struct gl_transform){{{2.0,0.0}, {0.0,2.0}}, {-0.5,-0.5}};
- GLSLH(vec2 dir = fract(pos * tex_size) - 0.5;)
+ GLSLH(vec2 dir = fract(HOOKED_pos * HOOKED_size) - 0.5;)
+ GLSLH(dir = transpose(HOOKED_rot) * dir;)
// Optimization: Discard (skip drawing) unused pixels, except those
// at the edge.
- GLSLH(vec2 dist = tex_size * min(pos, vec2(1.0) - pos);)
+ GLSLH(vec2 dist = HOOKED_size * min(HOOKED_pos, vec2(1.0) - HOOKED_pos);)
GLSLH(if (dir.x * dir.y < 0.0 && dist.x > 1.0 && dist.y > 1.0)
return 0.0;)
GLSLH(if (dir.x < 0.0 || dir.y < 0.0 || dist.x < 1.0 || dist.y < 1.0)
- return texture(tex, pos - pt * dir).x;)
+ return HOOKED_texOff(-dir).x;)
// Load the input samples
GLSLH(for (int x = 0; x < 4; x++))
GLSLH(for (int y = 0; y < 4; y++))
- GLSLH(i(x,y) = texture(tex, pos + pt * vec2(x-1.25, y-1.25)).x;)
+ GLSLH(i(x,y) = HOOKED_texOff(vec2(x-1.25, y-1.25)).x;)
} else {
*transform = (struct gl_transform){{{1.0,0.0}, {0.0,1.0}}, {0.0,0.0}};
- GLSLH(vec2 dir = fract(pos * tex_size / 2.0) - 0.5;)
+ // This is the second pass, so it will never be rotated
+ GLSLH(vec2 dir = fract(HOOKED_pos * HOOKED_size / 2.0) - 0.5;)
+
GLSLH(if (dir.x * dir.y > 0.0)
- return texture(tex, pos).x;)
+ return HOOKED_texOff(0).x;)
GLSLH(for (int x = 0; x < 4; x++))
GLSLH(for (int y = 0; y < 4; y++))
- GLSLH(i(x,y) = texture(tex, pos + pt * vec2(x+y-3, y-x)).x;)
+ GLSLH(i(x,y) = HOOKED_texOff(vec2(x+y-3, y-x)).x;)
}
superxbr_step_h(sc, conf, &params[step]);
GLSLH(return res;)
GLSLHF("}\n");
- GLSLF("color.x = tex_mul * superxbr(texcoord%d);\n", id);
+ GLSL(color.x = superxbr();)
}
diff --git a/video/out/opengl/superxbr.h b/video/out/opengl/superxbr.h
index 7aa46eff7c..f9888d37e4 100644
--- a/video/out/opengl/superxbr.h
+++ b/video/out/opengl/superxbr.h
@@ -24,7 +24,7 @@
extern const struct superxbr_opts superxbr_opts_def;
extern const struct m_sub_options superxbr_conf;
-void pass_superxbr(struct gl_shader_cache *sc, int id, int step, float tex_mul,
+void pass_superxbr(struct gl_shader_cache *sc, int step,
const struct superxbr_opts *conf,
struct gl_transform *transform);
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index ae1800821f..085bc825af 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -217,7 +217,6 @@ struct gl_video {
struct fbotex blend_subs_fbo;
struct fbotex output_fbo;
struct fbosurface surfaces[FBOSURFACES_MAX];
- struct fbotex prescale_fbo[MAX_PRESCALE_PASSES];
int surface_idx;
int surface_now;
@@ -602,9 +601,6 @@ static void uninit_rendering(struct gl_video *p)
fbotex_uninit(&p->indirect_fbo);
fbotex_uninit(&p->blend_subs_fbo);
- for (int pass = 0; pass < MAX_PRESCALE_PASSES; pass++)
- fbotex_uninit(&p->prescale_fbo[pass]);
-
for (int n = 0; n < FBOSURFACES_MAX; n++)
fbotex_uninit(&p->surfaces[n].fbotex);
@@ -910,9 +906,11 @@ static void pass_prepare_src_tex(struct gl_video *p)
char texture_name[32];
char texture_size[32];
+ char texture_rot[32];
char pixel_size[32];
snprintf(texture_name, sizeof(texture_name), "texture%d", n);
snprintf(texture_size, sizeof(texture_size), "texture_size%d", n);
+ snprintf(texture_rot, sizeof(texture_rot), "texture_rot%d", n);
snprintf(pixel_size, sizeof(pixel_size), "pixel_size%d", n);
if (s->use_integer) {
@@ -926,6 +924,7 @@ static void pass_prepare_src_tex(struct gl_video *p)
f[1] = s->tex_h;
}
gl_sc_uniform_vec2(sc, texture_size, f);
+ gl_sc_uniform_mat2(sc, texture_rot, true, (float *)s->transform.m);
gl_sc_uniform_vec2(sc, pixel_size, (GLfloat[]){1.0f / f[0],
1.0f / f[1]});
@@ -1045,12 +1044,29 @@ static void uninit_scaler(struct gl_video *p, struct scaler *scaler)
scaler->initialized = false;
}
-static void hook_prelude(struct gl_video *p, const char *name, int id)
+static void hook_prelude(struct gl_video *p, const char *name, int id,
+ struct img_tex tex)
{
- GLSLHF("#define %s texture%d\n", name, id);
+ GLSLHF("#define %s_raw texture%d\n", name, id);
GLSLHF("#define %s_pos texcoord%d\n", name, id);
GLSLHF("#define %s_size texture_size%d\n", name, id);
+ GLSLHF("#define %s_rot texture_rot%d\n", name, id);
GLSLHF("#define %s_pt pixel_size%d\n", name, id);
+
+ // Set up the sampling functions
+ GLSLHF("#define %s_tex(pos) (%f * vec4(texture(%s_raw, pos)).%s)\n",
+ name, tex.multiplier, name, tex.swizzle[0] ? tex.swizzle : "rgba");
+
+ // Since the extra matrix multiplication impacts performance,
+ // skip it unless the texture was actually rotated
+ if (gl_transform_eq(tex.transform, identity_trans)) {
+ GLSLHF("#define %s_texOff(off) %s_tex(%s_pos + %s_pt * vec2(off))\n",
+ name, name, name, name);
+ } else {
+ GLSLHF("#define %s_texOff(off) "
+ "%s_tex(%s_pos + %s_rot * vec2(off)/%s_size)\n",
+ name, name, name, name, name);
+ }
}
static bool saved_tex_find(struct gl_video *p, const char *name,
@@ -1116,8 +1132,8 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
// This is a special name that means "currently hooked texture"
if (strcmp(bind_name, "HOOKED") == 0) {
int id = pass_bind(p, tex);
- hook_prelude(p, "HOOKED", id);
- hook_prelude(p, name, id);
+ hook_prelude(p, "HOOKED", id, tex);
+ hook_prelude(p, name, id, tex);
continue;
}
@@ -1130,7 +1146,7 @@ static struct img_tex pass_hook(struct gl_video *p, const char *name,
return tex;
}
- hook_prelude(p, bind_name, pass_bind(p, bind_tex));
+ hook_prelude(p, bind_name, pass_bind(p, bind_tex), bind_tex);
}
// Run the actual hook. This generates a series of GLSL shader
@@ -1502,33 +1518,6 @@ static void upload_nnedi3_weights(struct gl_video *p)
}
}
-// Applies a single pass of the prescaler, and accumulates the offset in
-// pass_transform.
-static void pass_prescale_luma_step(struct gl_video *p, struct img_tex tex,
- struct gl_transform *step_transform,
- int step)
-{
- int id = pass_bind(p, tex);
- int planes = tex.components;
-
- switch(p->opts.prescale_luma) {
- case 1:
- assert(planes == 1);
- pass_superxbr(p->sc, id, step, tex.multiplier,
- p->opts.superxbr_opts, step_transform);
- break;
- case 2:
- upload_nnedi3_weights(p);
- pass_nnedi3(p->gl, p->sc, planes, id, step, tex.multiplier,
- p->opts.nnedi3_opts, step_transform, tex.gl_target);
- break;
- default:
- abort();
- }
-
- skip_unused(p, planes);
-}
-
// Returns true if two img_texs are semantically equivalent (same metadata)
static bool img_tex_equiv(struct img_tex a, struct img_tex b)
{
@@ -1569,33 +1558,22 @@ static void pass_add_hooks(struct gl_video *p, struct tex_hook hook,
static void deband_hook(struct gl_video *p, struct img_tex tex,
struct gl_transform *trans, void *priv)
{
- // We could use the hook binding mechanism here but the existing code
- // already assumes we just know an ID so just do this for simplicity
- int id = pass_bind(p, tex);
- pass_sample_deband(p->sc, p->opts.deband_opts, id, tex.multiplier,
- tex.gl_target, &p->lfg);
- skip_unused(p, tex.components);
+ pass_sample_deband(p->sc, p->opts.deband_opts, &p->lfg);
}
-static void prescale_hook(struct gl_video *p, struct img_tex tex,
+static void superxbr_hook(struct gl_video *p, struct img_tex tex,
struct gl_transform *trans, void *priv)
{
- struct gl_transform step_trans = identity_trans;
- pass_prescale_luma_step(p, tex, &step_trans, 0);
- gl_transform_trans(step_trans, trans);
-
- // We render out an FBO *inside* this hook, which is normally quite
- // unusual but here it allows us to work around the lack of real closures.
- // Unfortunately it means we need to duplicate some work to compute the
- // new FBO size
- struct fbotex *fbo = priv;
- int w = tex.w * (int)step_trans.m[0][0],
- h = tex.h * (int)step_trans.m[1][1];
- finish_pass_fbo(p, fbo, w, h, 0);
- tex = img_tex_fbo(fbo, tex.type, tex.components);
+ int step = (uintptr_t)priv;
+ pass_superxbr(p->sc, step, p->opts.superxbr_opts, trans);
+}
- pass_prescale_luma_step(p, tex, &step_trans, 1);
- gl_transform_trans(step_trans, trans);
+static void nnedi3_hook(struct gl_video *p, struct img_tex tex,
+ struct gl_transform *trans, void *priv)
+{
+ int step = (uintptr_t)priv;
+ upload_nnedi3_weights(p);
+ pass_nnedi3(p->gl, p->sc, step, p->opts.nnedi3_opts, trans);
}
static void unsharp_hook(struct gl_video *p, struct img_tex tex,
@@ -1617,7 +1595,7 @@ static void user_hook_old(struct gl_video *p, struct img_tex tex,
load_shader(p, bstr0(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);
+ GLSLF("color = %s(HOOKED_raw, HOOKED_pos, HOOKED_size);\n", fn_name);
}
// Returns 1.0 on failure to at least create a legal FBO
@@ -1784,17 +1762,36 @@ static void pass_hook_user_shaders(struct gl_video *p, char **shaders)
static void gl_video_setup_hooks(struct gl_video *p)
{
if (p->opts.deband) {
- pass_add_hooks(p, (struct tex_hook) {.hook = deband_hook},
+ pass_add_hooks(p, (struct tex_hook) {.hook = deband_hook,
+ .bind_tex = {"HOOKED"}},
HOOKS("LUMA", "CHROMA", "RGB", "XYZ"));
}
int prescale_passes = get_prescale_passes(p);
- for (int i = 0; i < prescale_passes; i++) {
- pass_add_hook(p, (struct tex_hook) {
- .hook_tex = "LUMA",
- .hook = prescale_hook,
- .priv = &p->prescale_fbo[i],
- });
+ if (p->opts.prescale_luma == 1) { // superxbr
+ for (int i = 0; i < prescale_passes; i++) {
+ for (int step = 0; step < 2; step++) {
+ pass_add_hook(p, (struct tex_hook) {
+ .hook_tex = "LUMA",
+ .bind_tex = {"HOOKED"},
+ .hook = superxbr_hook,
+ .priv = (void *)(uintptr_t)step,
+ });
+ }
+ }
+ }
+
+ if (p->opts.prescale_luma == 2) { // nnedi3
+ for (int i = 0; i < prescale_passes; i++) {
+ for (int step = 0; step < 2; step++) {
+ pass_add_hook(p, (struct tex_hook) {
+ .hook_tex = "LUMA",
+ .bind_tex = {"HOOKED"},
+ .hook = nnedi3_hook,
+ .priv = (void *)(uintptr_t)step,
+ });
+ }
+ }
}
if (p->opts.unsharp != 0.0) {
diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c
index 8d3b1e0e40..8956ec37b9 100644
--- a/video/out/opengl/video_shaders.c
+++ b/video/out/opengl/video_shaders.c
@@ -290,7 +290,7 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
// Wide usage friendly PRNG, shamelessly stolen from a GLSL tricks forum post.
// Obtain random numbers by calling rand(h), followed by h = permute(h) to
-// update the state.
+// update the state. Assumes the texture was hooked.
static void prng_init(struct gl_shader_cache *sc, AVLFG *lfg)
{
GLSLH(float mod289(float x) { return x - floor(x / 289.0) * 289.0; })
@@ -298,7 +298,7 @@ static void prng_init(struct gl_shader_cache *sc, AVLFG *lfg)
GLSLH(float rand(float x) { return fract(x / 41.0); })
// Initialize the PRNG by hashing the position + a random uniform
- GLSL(vec3 _m = vec3(pos, random) + vec3(1.0);)
+ GLSL(vec3 _m = vec3(HOOKED_pos, random) + vec3(1.0);)
GLSL(float h = permute(permute(permute(_m.x)+_m.y)+_m.z);)
gl_sc_uniform_f(sc, "random", (double)av_lfg_get(lfg) / UINT32_MAX);
}
@@ -331,44 +331,40 @@ const struct m_sub_options deband_conf = {
.defaults = &deband_opts_def,
};
-// Stochastically sample a debanded result from a given texture
+// Stochastically sample a debanded result from a hooked texture.
void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
- int tex_num, float tex_mul, GLenum tex_target, AVLFG *lfg)
+ AVLFG *lfg)
{
- // Set up common variables and initialize the PRNG
+ // Initialize the PRNG
GLSLF("{\n");
- sampler_prelude(sc, tex_num);
prng_init(sc, lfg);
// Helper: Compute a stochastic approximation of the avg color around a
// pixel
- GLSLHF("vec4 average(%s tex, vec2 pos, vec2 pt, float range, inout float h) {",
- mp_sampler_type(tex_target));
+ GLSLHF("vec4 average(float range, inout float h) {\n");
// Compute a random rangle and distance
GLSLH(float dist = rand(h) * range; h = permute(h);)
GLSLH(float dir = rand(h) * 6.2831853; h = permute(h);)
-
- GLSLHF("pt *= dist;\n");
- GLSLH(vec2 o = vec2(cos(dir), sin(dir));)
+ GLSLH(vec2 o = dist * vec2(cos(dir), sin(dir));)
// Sample at quarter-turn intervals around the source pixel
GLSLH(vec4 ref[4];)
- GLSLH(ref[0] = texture(tex, pos + pt * vec2( o.x, o.y));)
- GLSLH(ref[1] = texture(tex, pos + pt * vec2(-o.y, o.x));)
- GLSLH(ref[2] = texture(tex, pos + pt * vec2(-o.x, -o.y));)
- GLSLH(ref[3] = texture(tex, pos + pt * vec2( o.y, -o.x));)
+ GLSLH(ref[0] = HOOKED_texOff(vec2( o.x, o.y));)
+ GLSLH(ref[1] = HOOKED_texOff(vec2(-o.y, o.x));)
+ GLSLH(ref[2] = HOOKED_texOff(vec2(-o.x, -o.y));)
+ GLSLH(ref[3] = HOOKED_texOff(vec2( o.y, -o.x));)
// Return the (normalized) average
- GLSLHF("return %f * (ref[0] + ref[1] + ref[2] + ref[3])/4.0;\n", tex_mul);
- GLSLH(})
+ GLSLH(return (ref[0] + ref[1] + ref[2] + ref[3])/4.0;)
+ GLSLHF("}\n");
// Sample the source pixel
- GLSLF("color = %f * texture(tex, pos);\n", tex_mul);
+ GLSL(color = HOOKED_tex(HOOKED_pos);)
GLSLF("vec4 avg, diff;\n");
for (int i = 1; i <= opts->iterations; i++) {
// Sample the average pixel and use it instead of the original if
// the difference is below the given threshold
- GLSLF("avg = average(tex, pos, pt, %f, h);\n", i * opts->range);
+ GLSLF("avg = average(%f, h);\n", i * opts->range);
GLSL(diff = abs(color - avg);)
GLSLF("color = mix(avg, color, greaterThan(diff, vec4(%f)));\n",
opts->threshold / (i * 16384.0));
@@ -383,20 +379,21 @@ void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
GLSLF("}\n");
}
+// Assumes the texture was hooked
void pass_sample_unsharp(struct gl_shader_cache *sc, float param) {
GLSLF("// unsharp\n");
GLSLF("{\n");
- GLSL(vec2 st1 = pt * 1.2;)
- GLSL(vec4 p = texture(tex, pos);)
- GLSL(vec4 sum1 = texture(tex, pos + st1 * vec2(+1, +1))
- + texture(tex, pos + st1 * vec2(+1, -1))
- + texture(tex, pos + st1 * vec2(-1, +1))
- + texture(tex, pos + st1 * vec2(-1, -1));)
- GLSL(vec2 st2 = pt * 1.5;)
- GLSL(vec4 sum2 = texture(tex, pos + st2 * vec2(+1, 0))
- + texture(tex, pos + st2 * vec2( 0, +1))
- + texture(tex, pos + st2 * vec2(-1, 0))
- + texture(tex, pos + st2 * vec2( 0, -1));)
+ GLSL(float st1 = 1.2;)
+ GLSL(vec4 p = HOOKED_tex(HOOKED_pos);)
+ GLSL(vec4 sum1 = HOOKED_texOff(st1 * vec2(+1, +1))
+ + HOOKED_texOff(st1 * vec2(+1, -1))
+ + HOOKED_texOff(st1 * vec2(-1, +1))
+ + HOOKED_texOff(st1 * vec2(-1, -1));)
+ GLSL(float st2 = 1.5;)
+ GLSL(vec4 sum2 = HOOKED_texOff(st2 * vec2(+1, 0))
+ + HOOKED_texOff(st2 * vec2( 0, +1))
+ + HOOKED_texOff(st2 * vec2(-1, 0))
+ + HOOKED_texOff(st2 * vec2( 0, -1));)
GLSL(vec4 t = p * 0.859375 + sum2 * -0.1171875 + sum1 * -0.09765625;)
GLSLF("color = p + t * %f;\n", param);
GLSLF("}\n");
diff --git a/video/out/opengl/video_shaders.h b/video/out/opengl/video_shaders.h
index bbfeebb576..1f4496fbab 100644
--- a/video/out/opengl/video_shaders.h
+++ b/video/out/opengl/video_shaders.h
@@ -38,8 +38,9 @@ void pass_sample_oversample(struct gl_shader_cache *sc, struct scaler *scaler,
void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc);
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);
+ AVLFG *lfg);
void pass_sample_unsharp(struct gl_shader_cache *sc, float param);