diff options
author | Niklas Haas <git@nand.wakku.to> | 2015-09-05 17:39:27 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2015-09-09 19:19:23 +0200 |
commit | 97363e176d180f4f1bbc1e67e3e513c493ce31ed (patch) | |
tree | 592e0d675e88e8cdf5ba61b9c43925caa1ede7d9 /video/out/opengl/video_shaders.c | |
parent | 95d5bee832f33721a228d19341e20b12149498ce (diff) | |
download | mpv-97363e176d180f4f1bbc1e67e3e513c493ce31ed.tar.bz2 mpv-97363e176d180f4f1bbc1e67e3e513c493ce31ed.tar.xz |
vo_opengl: implement debanding (and remove source-shader)
The removal of source-shader is a side effect, since this effectively
replaces it - and the video-reading code has been significantly
restructured to make more sense and be more readable.
This means users no longer have to constantly download and maintain a
separate deband.glsl installation alongside mpv, which was the only real
use case for source-shader that we found either way.
Diffstat (limited to 'video/out/opengl/video_shaders.c')
-rw-r--r-- | video/out/opengl/video_shaders.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c index 26d5636184..e517977b00 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -27,10 +27,13 @@ #define GLSL(x) gl_sc_add(sc, #x "\n"); #define GLSLF(...) gl_sc_addf(sc, __VA_ARGS__) +#define GLSLH(x) gl_sc_hadd(sc, #x "\n"); +#define GLSLHF(...) gl_sc_haddf(sc, __VA_ARGS__) // Set up shared/commonly used variables void sampler_prelude(struct gl_shader_cache *sc, int tex_num) { + GLSLF("#undef tex\n"); GLSLF("#define tex texture%d\n", tex_num); GLSLF("vec2 pos = texcoord%d;\n", tex_num); GLSLF("vec2 size = texture_size%d;\n", tex_num); @@ -337,3 +340,89 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) break; } } + +// 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. +static void prng_init(struct gl_shader_cache *sc, AVLFG *lfg) +{ + GLSLH(float mod289(float x) { return x - floor(x / 289.0) * 289.0; }) + GLSLH(float permute(float x) { return mod289((34.0*x + 1.0) * x); }) + 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(float h = permute(permute(permute(_m.x)+_m.y)+_m.z);) + gl_sc_uniform_f(sc, "random", (double)av_lfg_get(lfg) / UINT32_MAX); +} + +const struct deband_opts deband_opts_def = { + .iterations = 4, + .threshold = 64.0, + .range = 8.0, + .grain = 48.0, +}; + +#define OPT_BASE_STRUCT struct deband_opts +const struct m_sub_options deband_conf = { + .opts = (const m_option_t[]) { + OPT_INTRANGE("iterations", iterations, 0, 1, 16), + OPT_FLOATRANGE("threshold", threshold, 0, 0.0, 4096.0), + OPT_FLOATRANGE("range", range, 0, 1.0, 64.0), + OPT_FLOATRANGE("grain", grain, 0, 0.0, 4096.0), + {0} + }, + .size = sizeof(struct deband_opts), + .defaults = &deband_opts_def, +}; + +// Stochastically sample a debanded result from a given texture +void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts, + int tex_num, float tex_mul, float img_w, float img_h, + AVLFG *lfg) +{ + // Set up common variables and initialize the PRNG + GLSLF("// debanding (tex %d)\n", tex_num); + sampler_prelude(sc, tex_num); + prng_init(sc, lfg); + + // Helper: Compute a stochastic approximation of the avg color around a + // pixel + GLSLH(vec4 average(sampler2D tex, vec2 pos, float range, inout float h) {) + // 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("vec2 pt = dist / vec2(%f, %f);\n", img_w, img_h); + GLSLH(vec2 o = 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));) + + // Return the (normalized) average + GLSLHF("return %f * (ref[0] + ref[1] + ref[2] + ref[3])/4.0;\n", tex_mul); + GLSLH(}) + + // Sample the source pixel + GLSLF("vec4 color = %f * texture(tex, pos);\n", tex_mul); + 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, %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)); + } + + // Add some random noise to smooth out residual differences + GLSL(vec3 noise;) + GLSL(noise.x = rand(h); h = permute(h);) + GLSL(noise.y = rand(h); h = permute(h);) + GLSL(noise.z = rand(h); h = permute(h);) + GLSLF("color.xyz += %f * (noise - vec3(0.5));\n", opts->grain/8192.0); +} |