From 2d182fdea0a068cbbbe88b575963cbb480444f31 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sun, 18 Jan 2015 18:57:12 +0100 Subject: vo_opengl: implement naive anti-ringing This is not quite the same thing as madVR's antiringing algorithm, but it essentially does something similar. Porting madVR's approach to elliptic coordinates will take some amount of thought. --- DOCS/man/vo.rst | 17 +++++++++++++---- video/out/gl_video.c | 18 ++++++++++++++---- video/out/gl_video.h | 1 + video/out/gl_video_shaders.glsl | 23 +++++++++++++++++------ 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index ae7e377771..5e03361bf9 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -306,9 +306,10 @@ Available video output drivers are: ``ewa_lanczos`` Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The number of taps can - be controlled with ``lradius``. + be controlled with ``lradius``. Adding extra taps makes the filter + sharper but adds more ringing. - Adding extra taps makes the filter sharper but adds more ringing. + This filter supports antiringing (see ``lantiring``). ``mitchell`` Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with @@ -337,6 +338,14 @@ Available video output drivers are: ratio, the radius that actually being used might be different (most likely being increased a bit). + ``lantiring=`` + Set the antiringing strength. This tries to eliminate ringing, but can + introduce other artifacts in the process. Must be a float number + between 0.0 and 1.0. The default value of 0.0 disables antiringing + entirely. + + Note that this currently only affects ``ewa_lanczos``. + ``scaler-resizes-only`` Disable the scaler if the video image is not resized. In that case, ``bilinear`` is used instead whatever is set with ``lscale``. Bilinear @@ -434,10 +443,10 @@ Available video output drivers are: down by more than twice (or other factors, depending on image formats), and ``lscale`` did not use a separable scaler. - ``cparam1``, ``cparam2``, ``cradius`` + ``cparam1``, ``cparam2``, ``cradius``, ``cantiring`` Set filter parameters and radius for ``cscale``. - See ``lparam1``, ``lparam2`` and ``lradius``. + See ``lparam1``, ``lparam2``, ``lradius`` and ``lantiring``. ``fancy-downscaling`` When using convolution based filters, extend the filter size diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 7400ffba0f..ddccd3a3e5 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -105,6 +105,7 @@ struct scaler { int index; const char *name; float params[2]; + float antiring; struct filter_kernel *kernel; GLuint gl_lut; const char *lut_name; @@ -367,6 +368,8 @@ const struct m_sub_options gl_video_conf = { OPT_FLOAT("cparam2", scaler_params[1][1], 0), OPT_FLOATRANGE("lradius", scaler_radius[0], 0, 1.0, 16.0), OPT_FLOATRANGE("cradius", scaler_radius[1], 0, 1.0, 16.0), + OPT_FLOATRANGE("lantiring", scaler_antiring[0], 0, 0.0, 1.0), + OPT_FLOATRANGE("cantiring", scaler_antiring[1], 0, 0.0, 1.0), OPT_FLAG("scaler-resizes-only", scaler_resizes_only, 0), OPT_FLAG("fancy-downscaling", fancy_downscaling, 0), OPT_FLAG("sigmoid-upscaling", sigmoid_upscaling, 0), @@ -955,9 +958,9 @@ static void shader_setup_scaler(char **shader, struct scaler *scaler, int pass) char lut_fn[40]; if (scaler->kernel->polar) { int radius = (int)scaler->kernel->radius; - // SAMPLE_CONVOLUTION_POLAR_R(NAME, R, LUT) - APPENDF(shader, "SAMPLE_CONVOLUTION_POLAR_R(%s, %d, %s, WEIGHTS%d)\n", - name, radius, lut_tex, unit); + // SAMPLE_CONVOLUTION_POLAR_R(NAME, R, LUT, WEIGHTS_FN, ANTIRING) + APPENDF(shader, "SAMPLE_CONVOLUTION_POLAR_R(%s, %d, %s, WEIGHTS%d, %f)\n", + name, radius, lut_tex, unit, scaler->antiring); // Pre-compute unrolled weights matrix APPENDF(shader, "#define WEIGHTS%d(LUT) \\\n ", unit); @@ -971,7 +974,12 @@ static void shader_setup_scaler(char **shader, struct scaler *scaler, int pass) // Samples outside the radius are unnecessary if (d < radius) { - APPENDF(shader, "SAMPLE_POLAR(LUT, %f, %d, %d) \\\n ", + APPENDF(shader, "SAMPLE_POLAR_%s(LUT, %f, %d, %d) \\\n ", + // The center 4 coefficients are the primary + // contributors, used to clamp the result for + // anti-ringing + (x >= 0 && y >= 0 && x <= 1 && y <= 1) + ? "PRIMARY" : "HELPER", (double)radius, x, y); } } @@ -1316,6 +1324,8 @@ static void init_scaler(struct gl_video *p, struct scaler *scaler) scaler->kernel->params[n] = p->opts.scaler_params[scaler->index][n]; } + scaler->antiring = p->opts.scaler_antiring[scaler->index]; + if (scaler->kernel->radius < 0) { float radius = p->opts.scaler_radius[scaler->index]; if (!isnan(radius)) diff --git a/video/out/gl_video.h b/video/out/gl_video.h index b3c5d5abe5..980f237a15 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -33,6 +33,7 @@ struct gl_video_opts { char *dscaler; float scaler_params[2][2]; float scaler_radius[2]; + float scaler_antiring[2]; int indirect; float gamma; int srgb; diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl index fa9bfa2e95..d3cbbb7c41 100644 --- a/video/out/gl_video_shaders.glsl +++ b/video/out/gl_video_shaders.glsl @@ -188,6 +188,7 @@ uniform float dither_quantization; uniform float dither_center; uniform float filter_param1_l; uniform float filter_param1_c; +uniform float antiring_factor; uniform vec2 dither_size; in vec2 texcoord; @@ -298,21 +299,31 @@ float[6] weights6(sampler2D lookup, float f) { return res; \ } -#define SAMPLE_POLAR(LUT, R, X, Y) \ +#define SAMPLE_POLAR_HELPER(LUT, R, X, Y) \ w = texture1D(LUT, length(vec2(X, Y) - fcoord)/R).r; \ + c = texture(tex, base + pt * vec2(X, Y)); \ wsum += w; \ - res += w * texture(tex, base + pt * vec2(X, Y)); \ + res += w * c; \ -#define SAMPLE_CONVOLUTION_POLAR_R(NAME, R, LUT, WEIGHTS_FN) \ +#define SAMPLE_POLAR_PRIMARY(LUT, R, X, Y) \ + SAMPLE_POLAR_HELPER(LUT, R, X, Y) \ + lo = min(lo, c); \ + hi = max(hi, c); \ + +#define SAMPLE_CONVOLUTION_POLAR_R(NAME, R, LUT, WEIGHTS_FN, ANTIRING) \ vec4 NAME(VIDEO_SAMPLER tex, vec2 texsize, vec2 texcoord) { \ vec2 pt = vec2(1.0) / texsize; \ vec2 fcoord = fract(texcoord * texsize - vec2(0.5)); \ vec2 base = texcoord - fcoord * pt; \ - vec4 res = vec4(0); \ - float wsum = 0; \ + vec4 res = vec4(0.0); \ + vec4 lo = vec4(1.0); \ + vec4 hi = vec4(0.0); \ + float wsum = 0.0; \ float w; \ + vec4 c; \ WEIGHTS_FN(LUT); \ - return res / wsum; \ + res /= wsum; \ + return mix(res, clamp(res, lo, hi), ANTIRING); \ } #ifdef DEF_SCALER0 -- cgit v1.2.3